diff --git a/kilo.c b/kilo.c index 9413594..2633caf 100644 --- a/kilo.c +++ b/kilo.c @@ -1,12 +1,38 @@ -#include #include +#include #include #include #include +#include #include #include #include +struct abuf { + char *p; + int len; +}; + +struct { + struct termios orig_termios; + int rows; + int cols; + int cx, cy; +} E = { .cx = 0, .cy = 0 }; + +enum keys { + ARROW_UP = 0x100 + 1, + ARROW_DOWN, + ARROW_LEFT, + ARROW_RIGHT +}; + +#define ABUF_INIT {NULL, 0} + +void ab_append(struct abuf *, const char *); +void ab_free(struct abuf *); +void ab_write(struct abuf *); + void enable_raw_mode(); void disable_raw_mode(); @@ -16,21 +42,14 @@ int read_cursor_position(int *, int *); void editor_init(); void editor_redraw_screen(); void editor_clear_screen(); -void editor_draw_rows(); +void editor_draw_rows(struct abuf *); void editor_process_key(); -char editor_read_key(); +int editor_read_key(); void die(const char *); #define CTRL_KEY(key) ((key) & 0x1f) -struct { - struct termios orig_termios; - int rows; - int cols; - bool raw; -} E = { .raw = false }; - int main() { editor_init(); @@ -54,8 +73,6 @@ void editor_init() { } void enable_raw_mode() { - if (E.raw) return; - if (tcgetattr(STDIN_FILENO, &E.orig_termios) == -1) die("tcgetattr"); atexit(disable_raw_mode); @@ -66,8 +83,6 @@ void enable_raw_mode() { raw.c_cc[VTIME] = 1; if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) die("tcsetattr"); - - E.raw = true; } void disable_raw_mode() { @@ -85,15 +100,16 @@ int get_window_size(int *rows, int *cols) { return 0; } else { if (write(STDOUT_FILENO, "\x1b[999C\x1b[999B", 12) != 12) return -1; + return read_cursor_position(rows, cols); } - + return -1; } int read_cursor_position(int *rows, int *cols) { char buf[32]; - unsigned int i = 0; + int i = 0; if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) return -1; @@ -101,22 +117,32 @@ int read_cursor_position(int *rows, int *cols) { if (read(STDIN_FILENO, buf, 1) != 1 && *buf != '[') return -1; do { - if (i == sizeof(buf)) return -1; + if (i == (int) sizeof(buf)) return -1; if (read(STDIN_FILENO, buf+i, 1) == 0) break; } while(buf[i++] != 'R'); buf[i-1] = '\0'; if (sscanf(buf, "%d;%d", rows, cols) != 2) return -1; - + return 0; } void editor_redraw_screen() { - editor_clear_screen(); + struct abuf ab = ABUF_INIT; - editor_draw_rows(); + ab_append(&ab, "\x1b[?25l"); + ab_append(&ab, "\x1b[H"); - write(STDOUT_FILENO, "\x1b[H", 3); + editor_draw_rows(&ab); + + char buf[32]; + snprintf(buf, sizeof(buf), "\x1b[%d;%dH", E.cy + 1, E.cx + 1); + ab_append(&ab, buf); + + ab_append(&ab, "\x1b[?25h"); + + ab_write(&ab); + ab_free(&ab); } void editor_clear_screen() { @@ -124,29 +150,71 @@ void editor_clear_screen() { write(STDOUT_FILENO, "\x1b[H", 3); } -void editor_draw_rows() { - for (int y = 0; y < E.rows - 1; y++) - write(STDOUT_FILENO, "~\r\n", 3); - write(STDOUT_FILENO, "~", 1); +void editor_draw_rows(struct abuf *ab) { + for (int y = 0; y < E.rows; y++) { + ab_append(ab, "~"); + + ab_append(ab, "\x1b[K"); + if (y < E.rows - 1) ab_append(ab, "\r\n"); + } } void editor_process_key() { - char c = editor_read_key(); + int c = editor_read_key(); + switch (c) { case CTRL_KEY('Q'): editor_clear_screen(); exit(0); break; + + case ARROW_LEFT: + if (E.cx > 0) E.cx--; + break; + case ARROW_DOWN: + if (E.cy < E.rows - 1) E.cy++; + break; + case ARROW_UP: + if (E.cy > 0) E.cy--; + break; + case ARROW_RIGHT: + if (E.cx < E.cols - 1) E.cx++; + break; default: printf("%d\r\n", c); break; } } -char editor_read_key() { +int editor_read_key() { char c; while (read(STDIN_FILENO, &c, 1) == 0); - return c; + + if (c == '\x1b') { + char buf[2]; + + if (read(STDIN_FILENO, buf+0, 1) != 1) return c; + if (read(STDIN_FILENO, buf+1, 1) != 1) return c; + + if (buf[0] == '[') { + switch (buf[1]) { + case 'A': + return ARROW_UP; + break; + case 'B': + return ARROW_DOWN; + break; + case 'C': + return ARROW_RIGHT; + break; + case 'D': + return ARROW_LEFT; + break; + } + } + } + + return (int) c; } void die(const char *s) { @@ -155,3 +223,20 @@ void die(const char *s) { perror(s); exit(1); } + +void ab_append(struct abuf *ab, const char *s) { + int len = strlen(s); + + ab->p = realloc(ab->p, ab->len + len); + memcpy(ab->p + ab->len, s, len); + + ab->len += len; +} + +void ab_write(struct abuf *ab) { + write(STDOUT_FILENO, ab->p, ab->len); +} + +void ab_free(struct abuf *ab) { + free(ab->p); +}