--- /dev/null
+/*\r
+ * Acess2 Text Editor\r
+ */\r
+#if !USE_LOCAL\r
+# include <acess/sys.h> // Needed for IOCtl\r
+#endif\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <stdint.h>\r
+#include <string.h>\r
+#include <signal.h>\r
+#include <unistd.h>\r
+#if USE_LOCAL\r
+# include <sys/ioctl.h>\r
+# include <termios.h>\r
+#else\r
+# include <acess/devices/terminal.h>\r
+#endif\r
+\r
+#define MAX_FILES_OPEN 1\r
+\r
+// === TYPES ===\r
+typedef struct\r
+{\r
+ const char *Filename;\r
+ char **LineBuffer;\r
+ int FileSize;\r
+ int LineCount;\r
+ \r
+ int FirstLine;\r
+ int CurrentLine; //!< Currently selected line\r
+ int CurrentPos; //!< Position in that line\r
+} tFile;\r
+\r
+// === PROTOTYPES ===\r
+void SigINT_Handler(int Signum);\r
+void ExitHandler(void);\r
+ int main(int argc, char *argv[]);\r
+ int OpenFile(tFile *Dest, const char *Path);\r
+void UpdateDisplayFull(void);\r
+void UpdateDisplayLine(int LineNum);\r
+void UpdateDisplayStatus(void);\r
+\r
+void CursorUp(tFile *File);\r
+void CursorDown(tFile *File);\r
+void CursorRight(tFile *File);\r
+void CursorLeft(tFile *File);\r
+\r
+void Term_SetPos(int Row, int Col);\r
+\r
+// === GLOBALS ===\r
+ int giProgramState = 0;\r
+tFile gaFiles[MAX_FILES_OPEN];\r
+tFile *gpCurrentFile;\r
+#if USE_LOCAL\r
+struct termios gOldTermios;\r
+#endif\r
+ int giTerminal_Width = 80;\r
+ int giTerminal_Height = 25;\r
+\r
+// === CODE ===\r
+void SigINT_Handler(int Signum)\r
+{\r
+ exit(55);\r
+}\r
+\r
+void ExitHandler(void)\r
+{\r
+ #if USE_LOCAL\r
+ tcsetattr(0, TCSANOW, &gOldTermios);\r
+ #endif\r
+ printf("\x1B[?1047l");\r
+}\r
+\r
+/**\r
+ * \fn int main(int argc, char *argv[])\r
+ * \brief Entrypoint\r
+ */\r
+int main(int argc, char *argv[])\r
+{\r
+ \r
+ if(argc < 2) {\r
+ printf("Usage: edit <file>\n");\r
+ return -1;\r
+ }\r
+\r
+ if( OpenFile(&gaFiles[0], argv[1]) ) {\r
+ return -1;\r
+ }\r
+ \r
+ signal(SIGINT, SigINT_Handler);\r
+ atexit(ExitHandler);\r
+\r
+ // Disable input buffering\r
+ #if USE_LOCAL\r
+ {\r
+ struct termios term;\r
+ tcgetattr(0, &gOldTermios);\r
+ term = gOldTermios;\r
+ term.c_lflag &= ~(ICANON|ECHO);\r
+ tcsetattr(0, TCSANOW, &term);\r
+ //setbuf(stdin, NULL);\r
+ }\r
+ #endif\r
+ \r
+ // Go to alternte screen buffer\r
+ printf("\x1B[?1047h");\r
+ \r
+ gpCurrentFile = &gaFiles[0];\r
+ \r
+ UpdateDisplayFull();\r
+ \r
+ giProgramState = 1;\r
+ \r
+ while(giProgramState)\r
+ {\r
+ char ch = 0;\r
+ \r
+ read(0, &ch, 1);\r
+ \r
+ if(ch == '\x1B')\r
+ {\r
+ read(0, &ch, 1);\r
+ switch(ch)\r
+ {\r
+ case 'A': CursorUp(gpCurrentFile); break;\r
+ case 'B': CursorDown(gpCurrentFile); break;\r
+ case 'C': CursorRight(gpCurrentFile); break;\r
+ case 'D': CursorLeft(gpCurrentFile); break;\r
+ \r
+ case '[':\r
+ read(0, &ch, 1);\r
+ switch(ch)\r
+ {\r
+ case 'A': CursorUp(gpCurrentFile); break;\r
+ case 'B': CursorDown(gpCurrentFile); break;\r
+ case 'C': CursorRight(gpCurrentFile); break;\r
+ case 'D': CursorLeft(gpCurrentFile); break;\r
+ default:\r
+ printf("ch (\\x1B[) = %x\r", ch);\r
+ fflush(stdout);\r
+ break;\r
+ }\r
+ break;\r
+ \r
+ default:\r
+ printf("ch (\\x1B) = %x\r", ch);\r
+ fflush(stdout);\r
+ break;\r
+ }\r
+ // TODO: Move\r
+ }\r
+ \r
+ switch(ch)\r
+ {\r
+ case 'q':\r
+ giProgramState = 0;\r
+ break;\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+int OpenFile(tFile *Dest, const char *Path)\r
+{\r
+ FILE *fp;\r
+ char *buffer;\r
+ int i, j;\r
+ int start;\r
+ \r
+ fp = fopen(Path, "r");\r
+ if(!fp) {\r
+ fprintf(stderr, "Unable to open %s\n", Path);\r
+ return -1;\r
+ }\r
+ \r
+ Dest->Filename = Path;\r
+ \r
+ fseek(fp, 0, SEEK_END);\r
+ Dest->FileSize = ftell(fp);\r
+ fseek(fp, 0, SEEK_SET);\r
+ \r
+ buffer = malloc(Dest->FileSize+1);\r
+ fread(buffer, Dest->FileSize, 1, fp);\r
+ fclose(fp);\r
+ buffer[Dest->FileSize] = '\0';\r
+ \r
+ Dest->LineCount = 1;\r
+ for( i = 0; i < Dest->FileSize; i ++ )\r
+ {\r
+ if( buffer[i] == '\n' )\r
+ Dest->LineCount ++;\r
+ }\r
+ \r
+ Dest->LineBuffer = malloc( Dest->LineCount * sizeof(char*) );\r
+ start = 0;\r
+ j = 0;\r
+ for( i = 0; i < Dest->FileSize; i ++ )\r
+ {\r
+ if( buffer[i] == '\n' )\r
+ {\r
+ buffer[i] = '\0';\r
+ Dest->LineBuffer[j] = strdup( &buffer[start] );\r
+ start = i+1;\r
+ j ++;\r
+ }\r
+ }\r
+ Dest->LineBuffer[j] = strdup( &buffer[start] );\r
+ \r
+ free(buffer);\r
+ \r
+ Dest->FirstLine = 0;\r
+ Dest->CurrentLine = 0;\r
+ Dest->CurrentPos = 0;\r
+ \r
+ return 0;\r
+}\r
+\r
+void ShowLine(tFile *File, int LineNum, int X, int Y, int W)\r
+{\r
+ int j, k;\r
+ char *line;\r
+ \r
+ line = File->LineBuffer[LineNum];\r
+ printf("%6i ", LineNum+1);\r
+ j = 8;\r
+ for( k = 0; j < W-1 && line[k]; j++, k++ )\r
+ {\r
+ switch( line[k] )\r
+ {\r
+ case '\t':\r
+ printf("\t");\r
+ j += 8;\r
+ j &= ~7;\r
+ break;\r
+ default:\r
+ if( line[k] < ' ' || line[k] >= 0x7F ) continue;\r
+ printf("%c", line[k]);\r
+ break;\r
+ }\r
+ }\r
+ \r
+ for( ; j < W-1; j++ )\r
+ printf(" ");\r
+ printf("\n");\r
+}\r
+\r
+void ShowFile(tFile *File, int X, int Y, int W, int H)\r
+{\r
+ int i;\r
+ Term_SetPos(Y, X);\r
+ \r
+ for( i = 0; i < H; i ++ )\r
+ {\r
+ if( File->FirstLine + i >= File->LineCount ) break;\r
+ ShowLine( File, File->FirstLine + i, X, Y + i, W );\r
+ }\r
+ for( ; i < H; i++ )\r
+ printf("\n");\r
+}\r
+\r
+void UpdateDisplayFull(void)\r
+{\r
+ #if USE_LOCAL\r
+ {\r
+ struct winsize ws;\r
+ ioctl(0, TIOCGWINSZ, &ws);\r
+ giTerminal_Width = ws.ws_col;\r
+ giTerminal_Height = ws.ws_row;\r
+ }\r
+ #else\r
+ giTerminal_Width = ioctl(1, TERM_IOCTL_WIDTH, NULL);\r
+ giTerminal_Height = ioctl(1, TERM_IOCTL_HEIGHT, NULL);\r
+ #endif\r
+ \r
+ printf("\x1B[2J");\r
+ \r
+ ShowFile(gpCurrentFile, 0, 0, giTerminal_Width, giTerminal_Height - 1);\r
+ \r
+ \r
+ // Status Line\r
+ UpdateDisplayStatus();\r
+ \r
+ Term_SetPos(\r
+ gpCurrentFile->CurrentLine-gpCurrentFile->FirstLine,\r
+ 8 + gpCurrentFile->CurrentPos\r
+ );\r
+ fflush(stdout);\r
+}\r
+\r
+void UpdateDisplayLine(int Line)\r
+{\r
+ ShowLine(\r
+ gpCurrentFile, Line,\r
+ 0, Line - gpCurrentFile->FirstLine,\r
+ giTerminal_Width );\r
+}\r
+\r
+void UpdateDisplayStatus(void)\r
+{\r
+ int lastLine = gpCurrentFile->FirstLine + giTerminal_Height - 1;\r
+ \r
+ if( lastLine > gpCurrentFile->LineCount )\r
+ lastLine = gpCurrentFile->LineCount;\r
+ \r
+ printf("--- Line %i/%i (showing %i to %i)",\r
+ gpCurrentFile->CurrentLine + 1, gpCurrentFile->LineCount,\r
+ gpCurrentFile->FirstLine, lastLine);\r
+}\r
+\r
+void CursorUp(tFile *File)\r
+{\r
+ if( File->CurrentLine > 0 )\r
+ {\r
+ File->CurrentLine --;\r
+ if( File->FirstLine > File->CurrentLine )\r
+ {\r
+ File->FirstLine = File->CurrentLine;\r
+ UpdateDisplayFull();\r
+ }\r
+ else\r
+ {\r
+ UpdateDisplayLine(File->CurrentLine + 1);\r
+ UpdateDisplayLine(File->CurrentLine);\r
+ UpdateDisplayStatus();\r
+ }\r
+ }\r
+}\r
+\r
+void CursorDown(tFile *File)\r
+{\r
+ if( File->CurrentLine+1 < File->LineCount )\r
+ {\r
+ File->CurrentLine ++;\r
+ if( File->FirstLine < File->CurrentLine - (giTerminal_Height-2) )\r
+ {\r
+ File->FirstLine = File->CurrentLine - (giTerminal_Height-2);\r
+ UpdateDisplayFull();\r
+ }\r
+ else\r
+ {\r
+ UpdateDisplayLine(File->CurrentLine - 1);\r
+ UpdateDisplayLine(File->CurrentLine);\r
+ UpdateDisplayStatus();\r
+ }\r
+ }\r
+}\r
+\r
+void CursorRight(tFile *File)\r
+{\r
+ if( File->CurrentPos > 0 )\r
+ {\r
+ File->CurrentPos --;\r
+ UpdateDisplayLine(File->CurrentLine);\r
+ UpdateDisplayStatus();\r
+ }\r
+}\r
+\r
+void CursorLeft(tFile *File)\r
+{\r
+ if( File->LineBuffer[File->CurrentLine][File->CurrentPos+1] )\r
+ {\r
+ File->CurrentPos --;\r
+ UpdateDisplayLine(File->CurrentLine);\r
+ UpdateDisplayStatus();\r
+ }\r
+}\r
+\r
+void Term_SetPos(int Row, int Col)\r
+{\r
+ printf("\x1B[%i;%iH", Row+1, Col+1); // Set cursor\r
+ fflush(stdout);\r
+}\r