Skip to content

Instantly share code, notes, and snippets.

@halogenandtoast
Created August 28, 2014 15:56
Show Gist options
  • Select an option

  • Save halogenandtoast/1aa2abad82d70e0e8108 to your computer and use it in GitHub Desktop.

Select an option

Save halogenandtoast/1aa2abad82d70e0e8108 to your computer and use it in GitHub Desktop.
A crappy editor
#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