diff --git a/kilo.c b/kilo.c index 7d17361..5fb5ade 100644 --- a/kilo.c +++ b/kilo.c @@ -1,11 +1,16 @@ /*** includes ***/ +#define _DEFAULT_SOURCE +#define _BSD_SOURCE +#define _GNU_SOURCE + #include #include #include #include #include #include +#include #include #include @@ -30,11 +35,20 @@ enum editorKey /*** data ***/ +typedef struct erow { + int size; + char *chars; +} erow; + struct editorConfig { int cx, cy; + int rowoff; // Row offset + int coloff; // Col offset int screenrows; int screencols; + int numrows; + erow *row; struct termios orig_termios; }; @@ -191,6 +205,37 @@ int getWindowSize(int *rows, int *cols) } } +/*** row operations ***/ + +void editorAppendRow(char *s, size_t len) { + E.row = realloc(E.row, sizeof(erow) * (E.numrows + 1)); + + int at = E.numrows; + E.row[at].size = len; + E.row[at].chars = malloc(len + 1); + memcpy(E.row[at].chars, s, len); + E.row[at].chars[len] = '\0'; + E.numrows++; +} + +/*** file i/o ***/ + +void editorOpen(char *filename) { + FILE *fp = fopen(filename, "r"); + if (!fp) die("fopen"); + + char *line = NULL; + size_t linecap = 0; + ssize_t linelen; + while ((linelen = getline(&line, &linecap, fp)) != -1) { + while (linelen > 0 && (line[linelen - 1] == '\n' || line[linelen - 1] == '\r')) + linelen--; + editorAppendRow(line, linelen); + } + free(line); + fclose(fp); +} + /*** append buffer ***/ struct abuf @@ -222,33 +267,56 @@ void abFree(struct abuf *ab) /*** output ***/ +void editorScroll() { + if (E.cy < E.rowoff) { + E.rowoff = E.cy; + } + if (E.cy >= E.rowoff + E.screenrows) { + E.rowoff = E.cy - E.screenrows + 1; + } + if (E.cx < E.coloff) { + E.coloff = E.cx; + } + if (E.cx >= E.coloff + E.screencols) { + E.coloff = E.cx - E.screencols + 1; + } +} + void editorDrawRows(struct abuf *ab) { int y; for (y = 0; y < E.screenrows; y++) { - if (y == E.screenrows / 3) - { - char welcome[80]; - int welcomelen = snprintf(welcome, sizeof(welcome), - "Kilo editor -- version %s", KILO_VERSION); - if (welcomelen > E.screencols) - welcomelen = E.screencols; - int padding = (E.screencols - welcomelen) / 2; - if (padding) + int filerow = y + E.rowoff; + if (filerow >= E.numrows) { + if (E.numrows == 0 && y == E.screenrows / 3) + { + char welcome[80]; + int welcomelen = snprintf(welcome, sizeof(welcome), + "Kilo editor -- version %s", KILO_VERSION); + if (welcomelen > E.screencols) + welcomelen = E.screencols; + int padding = (E.screencols - welcomelen) / 2; + if (padding) + { + abAppend(ab, "~", 1); + padding--; + } + while (padding--) + abAppend(ab, " ", 1); + abAppend(ab, welcome, welcomelen); + } + else { abAppend(ab, "~", 1); - padding--; } - while (padding--) - abAppend(ab, " ", 1); - abAppend(ab, welcome, welcomelen); - } - else - { - abAppend(ab, "~", 1); - } + } else { + int len = E.row[filerow].size - E.coloff; + if (len < 0) len = 0; + if (len > E.screencols) len = E.screencols; + abAppend(ab, &E.row[filerow].chars[E.coloff], len); + } abAppend(ab, "\x1b[K", 3); if (y < E.screenrows - 1) { @@ -259,6 +327,7 @@ void editorDrawRows(struct abuf *ab) void editorRefreshScreen() { + editorScroll(); struct abuf ab = ABUF_INIT; abAppend(&ab, "\x1b[?25l", 6); @@ -267,7 +336,7 @@ void editorRefreshScreen() editorDrawRows(&ab); char buf[32]; - snprintf(buf, sizeof(buf), "\x1b[%d;%dH", E.cy + 1, E.cx + 1); + snprintf(buf, sizeof(buf), "\x1b[%d;%dH", (E.cy - E.rowoff) + 1, (E.cx - E.coloff) + 1); abAppend(&ab, buf, strlen(buf)); abAppend(&ab, "\x1b[?25h", 6); @@ -279,6 +348,7 @@ void editorRefreshScreen() void editorMoveCursor(int key) { + erow *row = (E.cy >=E.numrows) ? NULL : &E.row[E.cy]; switch (key) { case ARROW_LEFT: @@ -288,10 +358,9 @@ void editorMoveCursor(int key) } break; case ARROW_RIGHT: - if (E.cx != E.screencols - 1) - { - E.cx++; - } + if (row && E.cx < row->size) { + E.cx++; + } break; case ARROW_UP: @@ -301,7 +370,7 @@ void editorMoveCursor(int key) } break; case ARROW_DOWN: - if (E.cy != E.screenrows - 1) + if (E.cy < E.numrows) { E.cy++; } @@ -353,14 +422,22 @@ void initEditor() { E.cx = 0; E.cy = 0; + E.rowoff = 0; + E.coloff = 0; + E.numrows = 0; + E.row = NULL; + if (getWindowSize(&E.screenrows, &E.screencols) == -1) die("getWindowSize"); } -int main() +int main(int argc, char *argv[]) { enableRawMode(); initEditor(); + if (argc >= 2) { + editorOpen(argv[1]); + } while (1) {