5 # include <acess/sys.h> // Needed for IOCtl
\r
14 # include <sys/ioctl.h>
\r
15 # include <termios.h>
\r
17 # include <acess/devices/terminal.h>
\r
20 #define MAX_FILES_OPEN 1
\r
25 const char *Filename;
\r
31 int CurrentLine; //!< Currently selected line
\r
32 int CurrentPos; //!< Position in that line
\r
35 // === PROTOTYPES ===
\r
36 void SigINT_Handler(int Signum);
\r
37 void ExitHandler(void);
\r
38 int main(int argc, char *argv[]);
\r
39 int OpenFile(tFile *Dest, const char *Path);
\r
40 void UpdateDisplayFull(void);
\r
41 void UpdateDisplayLine(int LineNum);
\r
42 void UpdateDisplayStatus(void);
\r
44 void CursorUp(tFile *File);
\r
45 void CursorDown(tFile *File);
\r
46 void CursorRight(tFile *File);
\r
47 void CursorLeft(tFile *File);
\r
49 void Term_SetPos(int Row, int Col);
\r
50 void Term_ScrollUp(int Count);
\r
53 int giProgramState = 0;
\r
54 tFile gaFiles[MAX_FILES_OPEN];
\r
55 tFile *gpCurrentFile;
\r
57 struct termios gOldTermios;
\r
59 int giTabSize = 8; // Someday this will be per-file (maybe)
\r
60 int giTerminal_Width = 80;
\r
61 int giTerminal_Height = 25;
\r
64 void SigINT_Handler(int Signum)
\r
69 void ExitHandler(void)
\r
72 tcsetattr(0, TCSANOW, &gOldTermios);
\r
74 printf("\x1B[?1047l");
\r
78 * \fn int main(int argc, char *argv[])
\r
81 int main(int argc, char *argv[])
\r
85 printf("Usage: edit <file>\n");
\r
89 if( OpenFile(&gaFiles[0], argv[1]) ) {
\r
93 signal(SIGINT, SigINT_Handler);
\r
94 atexit(ExitHandler);
\r
96 // Disable input buffering
\r
99 struct termios term;
\r
100 tcgetattr(0, &gOldTermios);
\r
101 term = gOldTermios;
\r
102 term.c_lflag &= ~(ICANON|ECHO);
\r
103 tcsetattr(0, TCSANOW, &term);
\r
104 //setbuf(stdin, NULL);
\r
108 // Go to alternte screen buffer
\r
109 printf("\x1B[?1047h");
\r
111 gpCurrentFile = &gaFiles[0];
\r
113 UpdateDisplayFull();
\r
115 giProgramState = 1;
\r
117 while(giProgramState)
\r
128 case 'A': CursorUp(gpCurrentFile); break;
\r
129 case 'B': CursorDown(gpCurrentFile); break;
\r
130 case 'C': CursorRight(gpCurrentFile); break;
\r
131 case 'D': CursorLeft(gpCurrentFile); break;
\r
137 case 'A': CursorUp(gpCurrentFile); break;
\r
138 case 'B': CursorDown(gpCurrentFile); break;
\r
139 case 'C': CursorRight(gpCurrentFile); break;
\r
140 case 'D': CursorLeft(gpCurrentFile); break;
\r
142 printf("ch (\\x1B[) = %x\r", ch);
\r
149 printf("ch (\\x1B) = %x\r", ch);
\r
159 giProgramState = 0;
\r
167 int OpenFile(tFile *Dest, const char *Path)
\r
174 fp = fopen(Path, "r");
\r
176 fprintf(stderr, "Unable to open %s\n", Path);
\r
180 Dest->Filename = Path;
\r
182 fseek(fp, 0, SEEK_END);
\r
183 Dest->FileSize = ftell(fp);
\r
184 fseek(fp, 0, SEEK_SET);
\r
186 buffer = malloc(Dest->FileSize+1);
\r
187 fread(buffer, Dest->FileSize, 1, fp);
\r
189 buffer[Dest->FileSize] = '\0';
\r
191 Dest->LineCount = 1;
\r
192 for( i = 0; i < Dest->FileSize; i ++ )
\r
194 if( buffer[i] == '\n' )
\r
195 Dest->LineCount ++;
\r
198 Dest->LineBuffer = malloc( Dest->LineCount * sizeof(char*) );
\r
201 for( i = 0; i < Dest->FileSize; i ++ )
\r
203 if( buffer[i] == '\n' )
\r
206 Dest->LineBuffer[j] = strdup( &buffer[start] );
\r
211 Dest->LineBuffer[j] = strdup( &buffer[start] );
\r
215 Dest->FirstLine = 0;
\r
216 Dest->CurrentLine = 0;
\r
217 Dest->CurrentPos = 0;
\r
222 void ShowLine(tFile *File, int LineNum, int X, int Y, int W)
\r
227 line = File->LineBuffer[LineNum];
\r
229 printf("\x1B[2K"); // Clear line
\r
230 printf("%6i ", LineNum+1);
\r
232 for( k = 0; j < W-1 && line[k]; j++, k++ )
\r
242 if( line[k] < ' ' || line[k] >= 0x7F ) continue;
\r
243 printf("%c", line[k]);
\r
248 for( ; j < W-1; j++ )
\r
253 void ShowFile(tFile *File, int X, int Y, int W, int H)
\r
258 for( i = 0; i < H; i ++ )
\r
260 if( File->FirstLine + i >= File->LineCount ) break;
\r
261 ShowLine( File, File->FirstLine + i, X, Y + i, W );
\r
263 for( ; i < H; i++ )
\r
267 void UpdateDisplayFull(void)
\r
272 ioctl(0, TIOCGWINSZ, &ws);
\r
273 giTerminal_Width = ws.ws_col;
\r
274 giTerminal_Height = ws.ws_row;
\r
277 giTerminal_Width = ioctl(1, TERM_IOCTL_WIDTH, NULL);
\r
278 giTerminal_Height = ioctl(1, TERM_IOCTL_HEIGHT, NULL);
\r
283 ShowFile(gpCurrentFile, 0, 0, giTerminal_Width, giTerminal_Height - 1);
\r
287 UpdateDisplayStatus();
\r
290 gpCurrentFile->CurrentLine-gpCurrentFile->FirstLine,
\r
291 8 + gpCurrentFile->CurrentPos
\r
296 void UpdateDisplayLine(int Line)
\r
299 gpCurrentFile, Line,
\r
300 0, Line - gpCurrentFile->FirstLine,
\r
301 giTerminal_Width );
\r
304 void UpdateDisplayStatus(void)
\r
306 int lastLine = gpCurrentFile->FirstLine + giTerminal_Height - 1;
\r
308 if( lastLine > gpCurrentFile->LineCount )
\r
309 lastLine = gpCurrentFile->LineCount;
\r
311 Term_SetPos( giTerminal_Height - 1, 0 );
\r
312 printf("--- Line %i/%i (showing %i to %i)",
\r
313 gpCurrentFile->CurrentLine + 1, gpCurrentFile->LineCount,
\r
314 gpCurrentFile->FirstLine + 1, lastLine);
\r
317 void UpdateCursorPosition(void)
\r
319 tFile *File = gpCurrentFile;
\r
323 // Determine the position (handling tab characters)
\r
325 tmp = File->LineBuffer[File->CurrentLine];
\r
326 for( i = 0; tmp[i] && i < File->CurrentPos; i ++ )
\r
330 case '\t': screen_x += giTabSize; break;
\r
331 default: screen_x ++; break;
\r
335 Term_SetPos( File->CurrentLine - File->FirstLine, 8 + screen_x);
\r
338 void CursorUp(tFile *File)
\r
340 if( File->CurrentLine <= 0 )
\r
343 File->CurrentLine --;
\r
344 if( File->FirstLine > File->CurrentLine )
\r
346 Term_ScrollUp(File->FirstLine - File->CurrentLine);
\r
347 File->FirstLine = File->CurrentLine;
\r
348 // UpdateDisplayLine(File->FirstLine + giTerminal_Height-2);
\r
349 UpdateDisplayLine(File->FirstLine);
\r
350 // UpdateDisplayFull();
\r
354 UpdateDisplayLine(File->CurrentLine + 1);
\r
355 UpdateDisplayLine(File->CurrentLine);
\r
357 UpdateDisplayStatus();
\r
359 UpdateCursorPosition();
\r
362 void CursorDown(tFile *File)
\r
366 if( File->CurrentLine + 1 >= File->LineCount )
\r
369 File->CurrentLine ++;
\r
370 // Check if scroll is needed
\r
371 threshold = File->CurrentLine - (giTerminal_Height-2);
\r
372 if( File->FirstLine < threshold )
\r
374 Term_ScrollUp( File->FirstLine - threshold );
\r
375 File->FirstLine = threshold;
\r
376 UpdateDisplayLine(File->FirstLine + giTerminal_Height-2);
\r
380 // Else, just update the previous and new lines (and status)
\r
381 UpdateDisplayLine(File->CurrentLine - 1);
\r
382 UpdateDisplayLine(File->CurrentLine);
\r
384 UpdateDisplayStatus();
\r
386 UpdateCursorPosition();
\r
389 void CursorLeft(tFile *File)
\r
391 if( File->CurrentPos > 0 )
\r
393 File->CurrentPos --;
\r
394 UpdateDisplayLine(File->CurrentLine);
\r
395 UpdateDisplayStatus();
\r
397 UpdateCursorPosition();
\r
400 void CursorRight(tFile *File)
\r
402 if( File->LineBuffer[File->CurrentLine][File->CurrentPos+1] )
\r
404 File->CurrentPos ++;
\r
405 UpdateDisplayLine(File->CurrentLine);
\r
406 UpdateDisplayStatus();
\r
408 UpdateCursorPosition();
\r
411 void Term_SetPos(int Row, int Col)
\r
413 printf("\x1B[%i;%iH", Row+1, Col+1); // Set cursor
\r
417 void Term_ScrollUp(int Count)
\r
420 // printf("\x1B[1;%ir", giTerminal_Height-1);
\r
422 printf("\x1B[%iM", -Count);
\r
424 printf("\x1B[%iL", Count);
\r