From 0f3b356ebfe533d8135cf05f02fe1ff53cfe49b0 Mon Sep 17 00:00:00 2001 From: Johnny Richard Date: Tue, 26 Apr 2022 02:56:53 +0200 Subject: Add cursor movement --- .gitignore | 1 + Makefile | 4 +-- string_builder.c | 42 +++++++++++++++++++++++++++ string_builder.h | 31 ++++++++++++++++++++ ted.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++------- 5 files changed, 153 insertions(+), 13 deletions(-) create mode 100644 string_builder.c create mode 100644 string_builder.h diff --git a/.gitignore b/.gitignore index 8490248..a8cd213 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +*.o ted tags diff --git a/Makefile b/Makefile index 3968073..1f4421f 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,2 @@ -ted: ted.c - $(CC) ted.c -o ted -Wall -Wextra -pedantic -std=c11 +ted: ted.c string_builder.o + $(CC) ted.c string_builder.o -o ted -ggdb -Wall -Wextra -pedantic -std=c11 diff --git a/string_builder.c b/string_builder.c new file mode 100644 index 0000000..fa26e44 --- /dev/null +++ b/string_builder.c @@ -0,0 +1,42 @@ +/* + * Terminal Text Editor + * Copyright (C) 2022 Johnny Richard + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "string_builder.h" + +#include +#include + +void +string_builder_append(string_builder_t *sb, const char *s, int len) +{ + char *snew = realloc(sb->data, sb->len + len); + + if (snew == NULL) { + return; + } + + memcpy(&snew[sb->len], s, len); + sb->data = snew; + sb->len += len; +} + +void +string_builder_destroy(string_builder_t *sb) +{ + free(sb->data); +} + diff --git a/string_builder.h b/string_builder.h new file mode 100644 index 0000000..49cdf3a --- /dev/null +++ b/string_builder.h @@ -0,0 +1,31 @@ +/* + * Terminal Text Editor + * Copyright (C) 2022 Johnny Richard + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef STRING_BUILDER_H +#define STRING_BUILDER_H + +typedef struct string_builder { + char *data; + int len; +} string_builder_t; + +#define STRING_BUILDER_INIT { NULL, 0 } + +void string_builder_append(string_builder_t *sb, const char *s, int len); +void string_builder_destroy(string_builder_t *sb); + +#endif /* STRING_BUILDER_H */ diff --git a/ted.c b/ted.c index a01ac7e..e27ea94 100644 --- a/ted.c +++ b/ted.c @@ -21,13 +21,18 @@ #include #include #include +#include #include #include #include +#include "string_builder.h" + #define CTRL_KEY(k) ((k) & 0x1F) +#define TED_VERSION "0.0.1" typedef struct editor_config { + int cx, cy; int screen_rows; int screen_cols; struct termios orig_termios; @@ -40,8 +45,9 @@ 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_move_cursor(editor_config_t *ec, char key); +void editor_process_key(editor_config_t *ec); +void editor_draw_rows(editor_config_t *ec, string_builder_t *sb); void editor_clear_screen(); void editor_refresh_screen(editor_config_t *ec); void disable_raw_mode(); @@ -57,7 +63,7 @@ main() while (true) { editor_refresh_screen(&E); - editor_process_key(); + editor_process_key(&E); } return EXIT_SUCCESS; @@ -66,7 +72,9 @@ main() void editor_init(editor_config_t *ec) { - if (get_window_size(&ec->screen_rows, &ec->screen_rows) == -1) { + ec->cx = 0; + ec->cy = 0; + if (get_window_size(&ec->screen_rows, &ec->screen_cols) == -1) { die("get_window_size"); } } @@ -133,7 +141,26 @@ get_window_size(int *rows, int *cols) } void -editor_process_key() +editor_move_cursor(editor_config_t *ec, char key) +{ + switch (key) { + case 'h': + ec->cx--; + break; + case 'l': + ec->cx++; + break; + case 'k': + ec->cy--; + break; + case 'j': + ec->cy++; + break; + } +} + +void +editor_process_key(editor_config_t *ec) { char c = editor_read_key(); @@ -142,6 +169,12 @@ editor_process_key() editor_clear_screen(); exit(EXIT_SUCCESS); break; + case 'h': + case 'j': + case 'k': + case 'l': + editor_move_cursor(ec, c); + break; } } @@ -153,13 +186,34 @@ editor_clear_screen() } void -editor_draw_rows(editor_config_t *ec) +editor_draw_rows(editor_config_t *ec, string_builder_t *sb) { for (int y = 0; y < ec->screen_rows; ++y) { - write(STDOUT_FILENO, "~", 1); + if (y == ec->screen_rows / 3) { + char welcome[80]; + int welcomelen = snprintf(welcome, sizeof(welcome), "Ted editor --- version %s", TED_VERSION); + if (welcomelen > ec->screen_cols) { + welcomelen = ec->screen_cols; + } + + int padding = (ec->screen_cols - welcomelen) / 2; + if (padding) { + string_builder_append(sb, "~", 1); + padding--; + } + while (padding--) { + string_builder_append(sb, " ", 1); + } + + string_builder_append(sb, welcome, welcomelen); + } else { + string_builder_append(sb, "~", 1); + } + + string_builder_append(sb, "\x1b[K", 3); if (y < ec->screen_rows - 1) { - write(STDOUT_FILENO, "\r\n", 2); + string_builder_append(sb, "\r\n", 2); } } } @@ -167,9 +221,21 @@ editor_draw_rows(editor_config_t *ec) void editor_refresh_screen(editor_config_t *ec) { - editor_clear_screen(); - editor_draw_rows(ec); - write(STDOUT_FILENO, "\x1b[H", 3); + string_builder_t sb = STRING_BUILDER_INIT; + + string_builder_append(&sb, "\x1b[?25l", 6); + string_builder_append(&sb, "\x1b[H", 3); + + editor_draw_rows(ec, &sb); + + char buf[32]; + snprintf(buf, sizeof(buf), "\x1b[%d;%dH", ec->cy + 1, ec->cx + 1); + string_builder_append(&sb, buf, strlen(buf)); + + string_builder_append(&sb, "\x1b[?25h", 6); + + write(STDOUT_FILENO, sb.data, sb.len); + string_builder_destroy(&sb); } void -- cgit v1.2.3