From 2f249f6be2e49e57fd59ecd50f73e6a734c6bbb4 Mon Sep 17 00:00:00 2001 From: Johnny Richard Date: Mon, 25 Apr 2022 03:37:55 +0200 Subject: Enable terminal raw mode and draw editor --- .gitignore | 1 + ted.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 190 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8830688..8490248 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ ted +tags diff --git a/ted.c b/ted.c index 90f1213..a01ac7e 100644 --- a/ted.c +++ b/ted.c @@ -15,9 +15,197 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include +#include +#include +#include +#include #include +#include +#include +#include -int main() +#define CTRL_KEY(k) ((k) & 0x1F) + +typedef struct editor_config { + int screen_rows; + int screen_cols; + struct termios orig_termios; +} editor_config_t; + +editor_config_t E; + + +void editor_init(editor_config_t *ec); +char editor_read_key(); +int get_cursor_position(int *rows, int *cols); +int get_window_size(int *rows, int *cols); +void editor_process_key(); +void editor_draw_rows(editor_config_t *ec); +void editor_clear_screen(); +void editor_refresh_screen(editor_config_t *ec); +void disable_raw_mode(); +void enable_raw_mode(); +void die(const char *s); + +int +main() { + enable_raw_mode(); + + editor_init(&E); + + while (true) { + editor_refresh_screen(&E); + editor_process_key(); + } + return EXIT_SUCCESS; } + +void +editor_init(editor_config_t *ec) +{ + if (get_window_size(&ec->screen_rows, &ec->screen_rows) == -1) { + die("get_window_size"); + } +} + +char +editor_read_key() +{ + int nread; + char c; + while ((nread = read(STDIN_FILENO, &c, 1)) != 1) { + if (nread == -1 && errno != EAGAIN) { + die("read"); + } + } + return c; +} + +int +get_cursor_position(int *rows, int *cols) +{ + char buf[32]; + uint32_t i = 0; + + if (write(STDIN_FILENO, "\x1b[6n", 4) != 4) { + return -1; + } + + while (i < sizeof(buf) - 1) { + if (read(STDIN_FILENO, &buf[i], 1) != 1) { + break; + } + if (buf[i] == 'R') { + break; + } + i++; + } + buf[i] = '\0'; + + if (buf[0] != '\x1b' || buf[1] != '[') { + return -1; + } + if (sscanf(&buf[2], "%d;%d", rows, cols) != 2) { + return -1; + } + + return 0; +} + +int +get_window_size(int *rows, int *cols) +{ + struct winsize ws; + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { + if (write(STDIN_FILENO, "\x1b[999C\x1b[999B", 12) != 12) { + return -1; + } + return get_cursor_position(rows, cols); + } + + *cols = ws.ws_col; + *rows = ws.ws_row; + return 0; +} + +void +editor_process_key() +{ + char c = editor_read_key(); + + switch (c) { + case CTRL_KEY('q'): + editor_clear_screen(); + exit(EXIT_SUCCESS); + break; + } +} + +void +editor_clear_screen() +{ + write(STDOUT_FILENO, "\x1b[2J", 4); + write(STDOUT_FILENO, "\x1b[H", 3); +} + +void +editor_draw_rows(editor_config_t *ec) +{ + for (int y = 0; y < ec->screen_rows; ++y) { + write(STDOUT_FILENO, "~", 1); + + if (y < ec->screen_rows - 1) { + write(STDOUT_FILENO, "\r\n", 2); + } + } +} + +void +editor_refresh_screen(editor_config_t *ec) +{ + editor_clear_screen(); + editor_draw_rows(ec); + write(STDOUT_FILENO, "\x1b[H", 3); +} + +void +disable_raw_mode() +{ + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &E.orig_termios) == -1) { + die("tcsetattr"); + } +} + +void +enable_raw_mode() +{ + if (tcgetattr(STDIN_FILENO, &E.orig_termios) == -1) { + die("tcgetattr"); + } + + atexit(disable_raw_mode); + + 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; + + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) { + die("tcsetattr"); + } +} + +void +die(const char *s) +{ + editor_clear_screen(); + perror(s); + exit(EXIT_FAILURE); +} -- cgit v1.2.3