Created
August 28, 2014 15:56
-
-
Save halogenandtoast/1aa2abad82d70e0e8108 to your computer and use it in GitHub Desktop.
A crappy editor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <ncurses.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| enum mode { | |
| NORMAL, | |
| INSERT, | |
| COMMAND | |
| }; | |
| typedef struct line { | |
| int length; | |
| int max_length; | |
| char *string; | |
| } line_t; | |
| typedef struct document { | |
| char* filename; | |
| line_t** buffer; | |
| int lines_allocated; | |
| } document_t; | |
| void render_buffer(document_t* document, WINDOW *window) { | |
| int i; | |
| int width; | |
| int height; | |
| getmaxyx(window, height, width); | |
| for(i = 0; i < document->lines_allocated && i < height; i++) { | |
| wmove(window, i, 0); | |
| wprintw(window, document->buffer[i]->string); | |
| } | |
| wmove(window, 0, 0); | |
| } | |
| line_t* new_line_of_length(int length) { | |
| line_t* line = (line_t *)malloc(sizeof(line_t)); | |
| line->string = (char *)malloc(sizeof(char) * length); | |
| line->length = 0; | |
| line->max_length = length; | |
| return line; | |
| } | |
| line_t* new_line() { | |
| return new_line_of_length(100); | |
| } | |
| document_t* new_document() { | |
| document_t* document = (document_t *)malloc(sizeof(document_t)); | |
| document->buffer = (line_t **)calloc(100, sizeof(line_t *)); | |
| document->buffer[0] = new_line(); | |
| document->lines_allocated = 1; | |
| return document; | |
| } | |
| void free_document(document_t* document) { | |
| if(document->filename != NULL) { | |
| free(document->filename); | |
| } | |
| free(document->buffer); | |
| free(document); | |
| } | |
| char* insert_char(char* string, int pos, char c) { | |
| char *new = (char *)malloc(sizeof(char) * strlen(string) + 2); | |
| strncpy(new, string, pos); | |
| new[pos] = c; | |
| new[pos+1] = '\0'; | |
| strcat(new, string+pos); | |
| return new; | |
| } | |
| void load_file(document_t* document, char* filename) { | |
| int current_line = 0; | |
| char *line = NULL; | |
| size_t linecap = 0; | |
| ssize_t linelen; | |
| FILE* file; | |
| file = fopen(filename, "r"); | |
| document->filename = strdup(filename); | |
| if(file != NULL) { | |
| while((linelen = getline(&line, &linecap, file)) > 0) { | |
| if(current_line >= document->lines_allocated) { | |
| document->buffer[current_line] = new_line_of_length(100 + linelen); | |
| document->lines_allocated++; | |
| } else if(linelen > document->buffer[current_line]->max_length) { | |
| realloc(document->buffer[current_line]->string, sizeof(char) * (100 + linelen)); | |
| document->buffer[current_line]->max_length = 100 + linelen; | |
| } | |
| strcpy(document->buffer[current_line++]->string, line); | |
| } | |
| fclose(file); | |
| } | |
| } | |
| void write_file(document_t* document) { | |
| FILE* file; | |
| file = fopen(document->filename, "w"); | |
| for(int i = 0; i < document->lines_allocated; i++) { | |
| fprintf(file, "%s", document->buffer[i]->string); | |
| } | |
| fclose(file); | |
| } | |
| int main(int argc, char **argv) { | |
| int mode = NORMAL; | |
| int x = 0; | |
| int y = 0; | |
| int width; | |
| int height; | |
| int line_length; | |
| char cmd[2048]; | |
| int cmdpos = 0; | |
| document_t* document = new_document(); | |
| if(argc > 1) { | |
| load_file(document, argv[1]); | |
| } | |
| initscr(); | |
| refresh(); | |
| noecho(); | |
| raw(); | |
| getmaxyx(stdscr, height, width); | |
| WINDOW* details = newwin(1, width, height - 1, 0); | |
| WINDOW* mainwin = newwin(height - 1, width, 0, 0); | |
| wmove(mainwin, 0, 0); | |
| if(argc > 1) { | |
| render_buffer(document, mainwin); | |
| wrefresh(mainwin); | |
| } | |
| while(1) { | |
| char c = wgetch(mainwin); | |
| if(mode == NORMAL) { | |
| if(c == ':') { | |
| wprintw(details, ":"); | |
| wrefresh(details); | |
| cmdpos = 0; | |
| mode = COMMAND; | |
| } else if(c == 'i') { | |
| mode = INSERT; | |
| } else if(c == 'j') { | |
| wmove(mainwin, ++y, x); | |
| } else if(c == 'k') { | |
| wmove(mainwin, --y, x); | |
| } else if(c == 'l') { | |
| wmove(mainwin, y, ++x); | |
| } else if(c == 'h') { | |
| wmove(mainwin, y, --x); | |
| } | |
| } else if(mode == INSERT) { | |
| if(c == 27) { | |
| mode = NORMAL; | |
| } else if(c == 127) { | |
| line_length = document->buffer[y]->length; | |
| memmove(&document->buffer[y]->string[x-1], &document->buffer[y]->string[x], strlen(document->buffer[y]->string) - x); | |
| if(x == 0) { | |
| y -= 1; | |
| x = strlen(document->buffer[y]->string); | |
| } else { | |
| x -= 1; | |
| } | |
| wmove(mainwin, y, x); | |
| wdelch(mainwin); | |
| } else if(c == 10) { | |
| y += 1; | |
| x = 0; | |
| if(document->buffer[y] == NULL) { | |
| document->buffer[y] = new_line(); | |
| document->lines_allocated++; | |
| } | |
| wmove(mainwin, y, x); | |
| } else { | |
| document->buffer[y]->string = insert_char(document->buffer[y]->string, x, c); | |
| winsch(mainwin, c); | |
| wmove(mainwin, y, ++x); | |
| } | |
| wrefresh(mainwin); | |
| } else if(mode == COMMAND) { | |
| if(c == 10) { | |
| if(strcmp(cmd, "q") == 0) { | |
| break; | |
| } else if (strcmp(cmd, "wq") == 0) { | |
| write_file(document); | |
| break; | |
| } | |
| mode = NORMAL; | |
| wclear(details); | |
| cmdpos = 0; | |
| cmd[cmdpos] = '\0'; | |
| } else if(c == 127) { | |
| wmove(details, 0, cmdpos--); | |
| wdelch(details); | |
| cmd[cmdpos] = '\0'; | |
| } else if(c == 27) { | |
| mode = NORMAL; | |
| wclear(details); | |
| cmdpos = 0; | |
| cmd[cmdpos] = '\0'; | |
| } else { | |
| wprintw(details, "%c", c); | |
| cmd[cmdpos++] = c; | |
| cmd[cmdpos] = '\0'; | |
| } | |
| wrefresh(details); | |
| } | |
| } | |
| endwin(); | |
| free_document(document); | |
| return EXIT_SUCCESS; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment