diff --git a/.gitignore b/.gitignore index 6d9567d..2b9f023 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ build/ kilo -.ccls-cache -.nvim.lua +.cache compile_commands.json diff --git a/Makefile b/Makefile index 1127dab..25695b3 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,9 @@ OBJS := $(SRCS:src/%.c=build/%.o) DEPS := $(OBJS:%.o=%.d) WARNING_FLAGS := -Wall -Wextra -INCLUDE_FLAGS := -I headers +INCLUDE_FLAGS := -I include +CC := clang CFLAGS := $(WARNING_FLAGS) $(INCLUDE_FLAGS) -MMD -MP -std=c99 kilo: $(OBJS) diff --git a/include/kilo.h b/include/kilo.h new file mode 100644 index 0000000..8258e02 --- /dev/null +++ b/include/kilo.h @@ -0,0 +1,46 @@ +#ifndef KILO_H +#define KILO_H + +#include +#include +#include +#include + +struct editor_state { + char *filename; + int cx, cy; + int rx; + int screenrows, screencols; + int row_off, col_off; + bool running; + + struct EROW *rows; + int n_rows; + + char message[256]; + time_t message_time; + + struct termios orig_termios; +}; +extern struct editor_state E; + +typedef uint16_t KEY; + +void die(const char *); + +enum KEYS { + TAB = 9, + HOME = 0x100, + DEL, + PG_UP, + PG_DOWN, + END, + ARROW_UP, + ARROW_DOWN, + ARROW_LEFT, + ARROW_RIGHT, + NOP +}; + + +#endif // KILO_H diff --git a/include/terminal.h b/include/terminal.h new file mode 100644 index 0000000..b971ce1 --- /dev/null +++ b/include/terminal.h @@ -0,0 +1,17 @@ +#ifndef TERMINAL_H +#define TERMINAL_H + +#include + +#include "kilo.h" + +int term_enable_raw(void); +void term_disable_raw(void); +int term_clear(void); +int term_cursor_hidden(bool); +int term_get_win_size(int *, int *); +int term_get_cursor_pos(int *, int *); +int term_set_cursor_pos(int, int); +KEY term_read_key(void); + +#endif // TERMINAL_H diff --git a/src/kilo.c b/src/kilo.c index d35a69c..3d96179 100644 --- a/src/kilo.c +++ b/src/kilo.c @@ -4,16 +4,14 @@ #define KILO_TAB_STOP 4 #include -#include -#include #include #include #include -#include -#include -#include #include +#include "kilo.h" +#include "terminal.h" + #define CTRL_KEY(key) ((key) & 0x1f) #define MAX(a,b) (((a)>(b))?(a):(b)) @@ -31,38 +29,7 @@ struct EROW { int n_rchars; }; -struct { - char *filename; - int cx, cy; - int rx; - int screenrows, screencols; - int row_off, col_off; - bool running; - - struct EROW *rows; - int n_rows; - - char message[256]; - time_t message_time; - - struct termios orig_termios; -} E; - -enum KEYS { - TAB = 9, - HOME = 0x100, - DEL, - PG_UP, - PG_DOWN, - END, - ARROW_UP, - ARROW_DOWN, - ARROW_LEFT, - ARROW_RIGHT, - NOP -}; - -typedef uint16_t KEY; +struct editor_state E; /*****************************************************************************/ @@ -88,17 +55,6 @@ int sb_get_size(struct string_buf *); void sb_append(struct string_buf *, const char *, int); void sb_free(struct string_buf *); -int term_enable_raw(void); -void term_disable_raw(void); -int term_clear(void); -int term_cursor_hidden(bool); -int term_get_win_size(int *, int *); -int term_get_cursor_pos(int *, int *); -int term_set_cursor_pos(int, int); -KEY term_read_key(void); - -void die(const char *); - /*****************************************************************************/ int main(int argc, char **argv) { @@ -446,132 +402,6 @@ void sb_free(struct string_buf *sb) { /*****************************************************************************/ -int term_enable_raw(void) { - if (tcgetattr(STDIN_FILENO, &E.orig_termios) == -1) return -1; - atexit(term_disable_raw); - - struct termios raw = E.orig_termios; - cfmakeraw(&raw); - - raw.c_cc[VMIN] = 0; - raw.c_cc[VTIME] = 10; - - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) return -1; - - return 0; -} - -void term_disable_raw(void) { - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &E.orig_termios) == -1) - die ("term_disable_raw"); -} - -int term_clear(void) { - if (write(STDOUT_FILENO, "\x1b[2J", 4) != 4) return -1; - if (write(STDOUT_FILENO, "\x1b[H", 3) != 3) return -1; - return 0; - -} - -int term_cursor_hidden(bool hidden) { - if (write(STDOUT_FILENO, (hidden ? "\x1b[?25l" : "\x1b[?25h"), 6) != 6) - return -1; - - return 0; -} - -int term_get_win_size(int *row, int *col) { - struct winsize ws; - - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0) { - *row = ws.ws_row; - *col = ws.ws_col; - - return 0; - } else { - if (write(STDOUT_FILENO, "\x1b[999C\x1b[999B", 12) != 12) return -1; - - return term_get_cursor_pos(row, col); - } -} - -int term_get_cursor_pos(int *row, int *col) { - char buf[16]; - - if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) return -1; - - for (int i = 0; i < (int) sizeof(buf); i++) { - if (read(STDIN_FILENO, buf+i, 1) == 0 || buf[i] == 'R') { - buf[i] = '\0'; - break; - } - } - - if (sscanf(buf, "\x1b[%d;%d", row, col) == EOF) - return -1; - - return 0; -} - -int term_set_cursor_pos(int row, int col) { - char buf[16]; - - int len = snprintf(buf, sizeof(buf), "\x1b[%d;%dH", row, col); - len = (len >= (int) sizeof(buf) ? (int) sizeof(buf) - 1 : len); - - if ((int) write(STDOUT_FILENO, buf, len) != len) return -1; - return 0; -} - -KEY term_read_key(void) { - char c; - while (read(STDIN_FILENO, &c, 1) == 0); - - if (c == '\x1b') { - char buf[8] = { '\0' }; - - for (int i = 0; i < (int) sizeof(buf); i++) { - if (read(STDIN_FILENO, buf+i, 1) == 0) break; - - char escape_char; - if (sscanf(buf, "[%c~", &escape_char) != EOF) { - switch (escape_char) { - case 'A': return ARROW_UP; - case 'B': return ARROW_DOWN; - case 'C': return ARROW_RIGHT; - case 'D': return ARROW_LEFT; - case 'H': return HOME; - case 'F': return END; - } - } - - int escape_int; - if (sscanf(buf, "[%d~", &escape_int) != EOF) { - switch (escape_int) { - case 1: - case 7: - return HOME; - case 3: - return DEL; - case 4: - case 8: - return END; - case 5: - return PG_UP; - case 6: - return PG_DOWN; - } - } - } - - return NOP; - } - - return (KEY) c; -} - -/*****************************************************************************/ - void die(const char *s) { term_clear(); diff --git a/src/terminal.c b/src/terminal.c new file mode 100644 index 0000000..22a6696 --- /dev/null +++ b/src/terminal.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include + +#include "kilo.h" +#include "terminal.h" + +int term_enable_raw(void) { + if (tcgetattr(STDIN_FILENO, &E.orig_termios) == -1) + return -1; + + struct termios raw = E.orig_termios; + raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + raw.c_oflag &= ~(OPOST); + raw.c_cflag |= (CS8); + raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + raw.c_cc[VMIN] = 0; + raw.c_cc[VTIME] = 1; + + atexit(term_disable_raw); + return tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); +} + +void term_disable_raw(void) { + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &E.orig_termios) == -1) + die ("term_disable_raw"); +} + +int term_clear(void) { + if (write(STDOUT_FILENO, "\x1b[2J", 4) != 4) return -1; + if (write(STDOUT_FILENO, "\x1b[H", 3) != 3) return -1; + return 0; + +} + +int term_cursor_hidden(bool hidden) { + if (write(STDOUT_FILENO, (hidden ? "\x1b[?25l" : "\x1b[?25h"), 6) != 6) + return -1; + + return 0; +} + +int term_get_win_size(int *row, int *col) { + struct winsize ws; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0) { + *row = ws.ws_row; + *col = ws.ws_col; + + return 0; + } else { + if (write(STDOUT_FILENO, "\x1b[999C\x1b[999B", 12) != 12) return -1; + + return term_get_cursor_pos(row, col); + } +} + +int term_get_cursor_pos(int *row, int *col) { + char buf[16]; + + if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) return -1; + + for (int i = 0; i < (int) sizeof(buf); i++) { + if (read(STDIN_FILENO, buf+i, 1) == 0 || buf[i] == 'R') { + buf[i] = '\0'; + break; + } + } + + if (sscanf(buf, "\x1b[%d;%d", row, col) == EOF) + return -1; + + return 0; +} + +int term_set_cursor_pos(int row, int col) { + char buf[16]; + + int len = snprintf(buf, sizeof(buf), "\x1b[%d;%dH", row, col); + len = (len >= (int) sizeof(buf) ? (int) sizeof(buf) - 1 : len); + + if ((int) write(STDOUT_FILENO, buf, len) != len) return -1; + return 0; +} + +KEY term_read_key(void) { + char c; + while (read(STDIN_FILENO, &c, 1) == 0); + + if (c == '\x1b') { + char buf[8] = { '\0' }; + + for (int i = 0; i < (int) sizeof(buf); i++) { + if (read(STDIN_FILENO, buf+i, 1) == 0) break; + + char escape_char; + if (sscanf(buf, "[%c~", &escape_char) != EOF) { + switch (escape_char) { + case 'A': return ARROW_UP; + case 'B': return ARROW_DOWN; + case 'C': return ARROW_RIGHT; + case 'D': return ARROW_LEFT; + case 'H': return HOME; + case 'F': return END; + } + } + + int escape_int; + if (sscanf(buf, "[%d~", &escape_int) != EOF) { + switch (escape_int) { + case 1: + case 7: + return HOME; + case 3: + return DEL; + case 4: + case 8: + return END; + case 5: + return PG_UP; + case 6: + return PG_DOWN; + } + } + } + + return NOP; + } + + return (KEY) c; +} +