From f866add58f2dc11d0693da504a9293bd5fa2b615 Mon Sep 17 00:00:00 2001 From: Hadeed Ahmad Date: Sat, 2 Sep 2023 10:30:25 +0500 Subject: [PATCH] Begin work on text editing Along with lots of stuff I was too lazy to commit separately --- include/buffer.h | 1 + include/commands.h | 3 +- include/kilo.h | 2 + src/buffer.c | 16 ++++++++ src/commands.c | 95 ++++++++++++++++++++++++++++++++++------------ src/input.c | 14 ++++++- src/kilo.c | 3 +- src/terminal.c | 16 ++++++-- 8 files changed, 119 insertions(+), 31 deletions(-) diff --git a/include/buffer.h b/include/buffer.h index 14d4aa2..06ad1e7 100644 --- a/include/buffer.h +++ b/include/buffer.h @@ -20,6 +20,7 @@ void buffer_read_file(struct buffer *buffer, const char *filename); void buffer_append_row(struct buffer *buffer, const char *chars, int n_chars); void erow_update_rendering(struct erow *erow); +void erow_insert_char(struct erow *erow, int at, char c); int erow_cx_to_rx(struct erow *erow, int cx); int erow_rx_to_cx(struct erow *erow, int rx); diff --git a/include/commands.h b/include/commands.h index a08b6f5..03c1a08 100644 --- a/include/commands.h +++ b/include/commands.h @@ -3,6 +3,7 @@ #include "input.h" -void editor_move_cursor(KEY key); +void command_move_cursor(KEY key); +void command_insert_char(char c); #endif // COMMANDS_H diff --git a/include/kilo.h b/include/kilo.h index c63200a..169821c 100644 --- a/include/kilo.h +++ b/include/kilo.h @@ -20,4 +20,6 @@ struct editor_state { }; extern struct editor_state E; +void editor_set_message(const char *, ...); + #endif // KILO_H diff --git a/src/buffer.c b/src/buffer.c index 18f48fb..b9bdef3 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -64,6 +64,9 @@ void buffer_append_row(struct buffer *buffer, const char *chars, int n_chars) { memcpy(new_row->chars, chars, n_chars); new_row->n_chars = n_chars; + new_row->rchars = NULL; + new_row->n_rchars = 0; + erow_update_rendering(new_row); } @@ -116,6 +119,19 @@ void erow_update_rendering(struct erow *erow) { free(line_buffer); } +void erow_insert_char(struct erow *erow, int at, char c) { + if (at < 0) at = 0; + if (at > erow->n_chars) at = erow->n_chars; + + erow->chars = realloc(erow->chars, erow->n_chars + 1); + memmove(erow->chars + at + 1, erow->chars + at, erow->n_chars - at); + + erow->chars[at] = c; + erow->n_chars++; + + erow_update_rendering(erow); +} + int erow_cx_to_rx(struct erow *erow, int cx) { int rx = 0; diff --git a/src/commands.c b/src/commands.c index c6d07a0..2fc4f29 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1,33 +1,33 @@ #include #include "commands.h" +#include "input.h" #include "kilo.h" #include "buffer.h" -void editor_move_cursor(KEY key) { +static void cursor_adjust_viewport(void); +static void cursor_check_file_bounds(bool horizontal); +static void cursor_update_rx(bool horizontal); + +void command_move_cursor(KEY key) { struct erow *rows = E.current_buf->rows; int n_rows = E.current_buf->n_rows; - struct erow *current_row = (E.cy < n_rows ? rows + E.cy : NULL); + struct erow *current_row = (rows && E.cy < n_rows ? rows + E.cy : NULL); int max_x = (current_row ? current_row->n_chars : 0); switch (key) { case ARROW_LEFT: - if (E.cx > 0) E.cx--; - else if (E.cy > 0) E.cx = rows[--E.cy].n_chars; + E.cx--; break; case ARROW_DOWN: - if (E.cy < n_rows) E.cy++; + E.cy++; break; case ARROW_UP: - if (E.cy > 0) E.cy--; + E.cy--; break; case ARROW_RIGHT: - if (E.cx < max_x) E.cx++; - else if (E.cy < n_rows) { - E.cx = 0; - E.cy++; - } + E.cx++; break; case HOME: @@ -38,29 +38,76 @@ void editor_move_cursor(KEY key) { break; case PG_UP: - if ((E.cy -= E.screenrows) < 0) - E.cy = 0; + E.cy -= E.screenrows; break; case PG_DOWN: - if ((E.cy += E.screenrows) > n_rows) - E.cy = n_rows; + E.cy += E.screenrows; break; } - current_row = (E.cy < n_rows ? rows + E.cy : NULL); - max_x = (current_row ? current_row->n_chars : 0); + bool horizontal = (key == ARROW_LEFT || + key == ARROW_RIGHT || + key == HOME || + key == END); + + cursor_check_file_bounds(horizontal); + cursor_update_rx(horizontal); + cursor_adjust_viewport(); +} + +void command_insert_char(char c) { + if (E.cy == E.current_buf->n_rows) + buffer_append_row(E.current_buf, NULL, 0); + + erow_insert_char(E.current_buf->rows+E.cy, E.cx++, c); + E.rx = erow_cx_to_rx(E.current_buf->rows+E.cy, E.cx); +} + +static void cursor_check_file_bounds(bool horizontal) { + struct erow *rows = E.current_buf->rows; + int n_rows = E.current_buf->n_rows; + + struct erow *current_row = (rows && E.cy < n_rows ? rows + E.cy : NULL); + int max_x = (current_row ? current_row->n_chars : 0); + + if (E.cy < 0) + E.cy = 0; + + if (E.cy > n_rows) + E.cy = n_rows; + + if (E.cx < 0) { + if (E.cy > 0 && horizontal) E.cx = rows[--E.cy].n_chars; + else E.cx = 0; + } + + if (E.cx > max_x) { + if (E.cy < n_rows && horizontal) { + E.cx = 0; + E.cy++; + } else E.cx = max_x; + } +} + +static void cursor_update_rx(bool horizontal) { + struct erow *rows = E.current_buf->rows; + int n_rows = E.current_buf->n_rows; + + struct erow *current_row = (rows && E.cy < n_rows ? rows + E.cy : NULL); + int max_x = (current_row ? current_row->n_chars : 0); static int saved_rx = 0; - bool horizontal = (key == ARROW_LEFT || key == ARROW_RIGHT || - key == HOME || key == END); if (horizontal) saved_rx = erow_cx_to_rx(current_row, E.cx); - else E.cx = erow_rx_to_cx(current_row, saved_rx); + else { + E.cx = erow_rx_to_cx(current_row, saved_rx); + if (E.cx > max_x) + E.cx = max_x; + } - if (E.cx > max_x) - E.cx = max_x; - - E.rx = erow_cx_to_rx(&E.current_buf->rows[E.cy], E.cx); + E.rx = erow_cx_to_rx(rows + E.cy, E.cx); +} +static void cursor_adjust_viewport(void) { int max_row_off = E.cy; if (E.row_off > max_row_off) E.row_off = max_row_off; diff --git a/src/input.c b/src/input.c index 2f88de1..29fb2bc 100644 --- a/src/input.c +++ b/src/input.c @@ -3,6 +3,7 @@ #include "input.h" #include "terminal.h" #include "commands.h" +#include "utils.h" void input_process_key(void) { KEY c = terminal_read_key(); @@ -16,12 +17,23 @@ void input_process_key(void) { case END: case PG_UP: case PG_DOWN: - editor_move_cursor(c); + command_move_cursor(c); break; case CTRL_KEY('Q'): terminal_clear(); exit(0); break; + + case '\r': + break; + + case 127: + case DEL: + case CTRL_KEY('H'): + break; + + default: + command_insert_char(c); } } diff --git a/src/kilo.c b/src/kilo.c index d002726..c3e61bc 100644 --- a/src/kilo.c +++ b/src/kilo.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -11,7 +12,6 @@ #include "terminal.h" void editor_init(char *filename); -void editor_set_message(const char *, ...); struct editor_state E; @@ -46,6 +46,7 @@ void editor_init(char *filename) { buffer_read_file(E.current_buf, filename); editor_set_message("Welcome to kilo. Press CTRL-Q to quit."); + terminal_clear(); } void editor_set_message(const char *fmt, ...) { diff --git a/src/terminal.c b/src/terminal.c index 2a46376..21dc5e4 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -89,6 +89,7 @@ ERRCODE terminal_set_cursor_pos(int row, int col) { KEY terminal_read_key(void) { char c; + int n; while (read(STDIN_FILENO, &c, 1) == 0); if (c == '\x1b') { @@ -98,7 +99,11 @@ KEY terminal_read_key(void) { if (read(STDIN_FILENO, buf+i, 1) == 0) break; char escape_char; - if (sscanf(buf, "[%c~", &escape_char) != EOF) { + int escape_int; + + n = 0; + sscanf(buf, "[%c%n", &escape_char, &n); + if (n > 0) { switch (escape_char) { case 'A': return ARROW_UP; case 'B': return ARROW_DOWN; @@ -109,15 +114,18 @@ KEY terminal_read_key(void) { } } - if (sscanf(buf, "O%c", &escape_char) != EOF) { + n = 0; + sscanf(buf, "O%c%n", &escape_char, &n); + if (n > 0) { switch (escape_char) { case 'H': return HOME; case 'F': return END; } } - int escape_int; - if (sscanf(buf, "[%d~", &escape_int) != EOF) { + n = 0; + sscanf(buf, "[%d~%n", &escape_int, &n); + if (n > 0) { switch (escape_int) { case 1: case 7: