diff --git a/kilo.c b/kilo.c index 83b0f92..9413594 100644 --- a/kilo.c +++ b/kilo.c @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -7,13 +9,16 @@ void enable_raw_mode(); void disable_raw_mode(); + int get_window_size(int *, int *); +int read_cursor_position(int *, int *); void editor_init(); void editor_redraw_screen(); void editor_clear_screen(); void editor_draw_rows(); void editor_process_key(); +char editor_read_key(); void die(const char *); @@ -23,11 +28,11 @@ struct { struct termios orig_termios; int rows; int cols; -} E; + bool raw; +} E = { .raw = false }; int main() { editor_init(); - enable_raw_mode(); while (1) { editor_redraw_screen(); @@ -37,14 +42,32 @@ int main() { return 0; } +void editor_init() { + if (!isatty(STDIN_FILENO)) { + printf("kilo only supports a terminal at standard in. Exiting."); + exit(1); + } + + enable_raw_mode(); + + if (get_window_size(&E.rows, &E.cols) == -1) die("get_window_size"); +} + void enable_raw_mode() { + if (E.raw) return; + if (tcgetattr(STDIN_FILENO, &E.orig_termios) == -1) die("tcgetattr"); atexit(disable_raw_mode); struct termios raw = E.orig_termios; cfmakeraw(&raw); + raw.c_cc[VMIN] = 0; + raw.c_cc[VTIME] = 1; + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) die("tcsetattr"); + + E.raw = true; } void disable_raw_mode() { @@ -55,23 +78,37 @@ void disable_raw_mode() { int get_window_size(int *rows, int *cols) { struct winsize ws; - if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0) { + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0) { *rows = ws.ws_row; *cols = ws.ws_col; return 0; + } else { + if (write(STDOUT_FILENO, "\x1b[999C\x1b[999B", 12) != 12) return -1; + return read_cursor_position(rows, cols); } - + return -1; } -void editor_init() { - if (!isatty(STDIN_FILENO)) { - printf("kilo only supports a terminal at standard in. Exiting."); - exit(1); - } +int read_cursor_position(int *rows, int *cols) { + char buf[32]; + unsigned int i = 0; - if (get_window_size(&E.rows, &E.cols) == -1) die("get_window_size"); + if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) return -1; + + if (read(STDIN_FILENO, buf, 1) != 1 && *buf != '\x1b') return -1; + if (read(STDIN_FILENO, buf, 1) != 1 && *buf != '[') return -1; + + do { + if (i == 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() { @@ -79,24 +116,22 @@ void editor_redraw_screen() { editor_draw_rows(); - write(STDIN_FILENO, "\x1b[H", 3); + write(STDOUT_FILENO, "\x1b[H", 3); } void editor_clear_screen() { - write(STDIN_FILENO, "\x1b[2J", 4); - write(STDIN_FILENO, "\x1b[H", 3); + write(STDOUT_FILENO, "\x1b[2J", 4); + write(STDOUT_FILENO, "\x1b[H", 3); } void editor_draw_rows() { for (int y = 0; y < E.rows - 1; y++) - write(STDIN_FILENO, "~\r\n", 3); - write(STDIN_FILENO, "~", 1); + write(STDOUT_FILENO, "~\r\n", 3); + write(STDOUT_FILENO, "~", 1); } void editor_process_key() { - char c; - read(STDIN_FILENO, &c, 1); - + char c = editor_read_key(); switch (c) { case CTRL_KEY('Q'): editor_clear_screen(); @@ -108,6 +143,12 @@ void editor_process_key() { } } +char editor_read_key() { + char c; + while (read(STDIN_FILENO, &c, 1) == 0); + return c; +} + void die(const char *s) { editor_clear_screen();