diff --git a/include/editor.h b/include/editor.h index a1992bc..32d37ef 100644 --- a/include/editor.h +++ b/include/editor.h @@ -2,5 +2,7 @@ #define EDITOR_H_ void insert_char(int c); +void insert_new_line(); +void del_char(); #endif diff --git a/include/row.h b/include/row.h new file mode 100644 index 0000000..8fa69b4 --- /dev/null +++ b/include/row.h @@ -0,0 +1,14 @@ +#ifndef ROW_H_ +#define ROW_H_ + +int row_cx_to_rx(row *row, int cx); +void update_row(row *row); +void insert_row(int at, char *s, size_t len); +void free_row(row *row); +void del_row(int at); +void row_insert_char(row *row, int at, int c); +void row_append_str(row *row, char *s, size_t len); +void row_del_char(row *row, int at); +char *rows_to_str(int *buflen); + +#endif diff --git a/include/vip.h b/include/vip.h index 87a3559..2ff95ce 100644 --- a/include/vip.h +++ b/include/vip.h @@ -7,6 +7,8 @@ /* CONFIG */ #define TAB_SIZE 4 +#define VERSION "0.0.1" + /* number of times of warning before quitting when there is modified text */ #define QUIT_CONFIRM 2 @@ -15,12 +17,15 @@ #define SURFACE_1_BG "\x1b[38;2;49;50;68m" #define BLACK_BG "\x1b[38;2;0;0;0m" #define BLACK_FG "\x1b[48;2;0;0;0m" -#define WHITE_FG "\x1b[48;2;255;255;255m" +#define WHITE_FG "\x1b[48;2;205;214;244m" #define BLUE_FG "\x1b[48;2;137;180;250m" #define BLUE_BG "\x1b[38;2;137;180;250m" #define GREEN_FG "\x1b[48;2;166;227;161m" -#define VERSION "0.0.1" + +#define NORMAL 0 +#define INSERT 1 +#define VISUAL 2 typedef struct row { int size; @@ -38,6 +43,7 @@ typedef struct editor { int rows; row *row; int dirty; + int mode; char *filename; char statusmsg[80]; time_t statusmsg_time; @@ -55,6 +61,7 @@ void abAppend(struct abuf *ab, const char *s, int len); void append_row(char *s, size_t len); void row_insert_char(row *row, int at, int c); +void row_del_char(row *row, int at); extern editor vip; diff --git a/src/editor.c b/src/editor.c index 199fa88..c6116b9 100644 --- a/src/editor.c +++ b/src/editor.c @@ -1,12 +1,46 @@ #include "vip.h" +#include "row.h" extern editor vip; void insert_char(int c) { if (vip.cy == vip.rows) { - append_row("", 0); + insert_row(vip.rows, "", 0); } row_insert_char(&vip.row[vip.cy], vip.cx, c); vip.cx++; } + +void insert_new_line() +{ + if (vip.cx == 0) { + insert_row(vip.cy, "", 0); + } else { + row *row = &vip.row[vip.cy]; + insert_row(vip.cy + 1, &row->chars[vip.cx], row->size - vip.cx); + row = &vip.row[vip.cy]; + row->size = vip.cx; + row->chars[row->size] = '\0'; + update_row(row); + } + vip.cy++; + vip.cx = 0; +} + +void del_char() +{ + if (vip.cy == vip.rows) return; + if (vip.cx == 0 && vip.cy == 0) return; + + row *row = &vip.row[vip.cy]; + if (vip.cx > 0) { + row_del_char(row, vip.cx - 1); + vip.cx--; + } else { + vip.cx = vip.row[vip.cy - 1].size; + row_append_str(&vip.row[vip.cy - 1], row->chars, row->size); + del_row(vip.cy); + vip.cy--; + } +} diff --git a/src/row.c b/src/row.c new file mode 100644 index 0000000..da4e5ac --- /dev/null +++ b/src/row.c @@ -0,0 +1,127 @@ +#include +#include +#include + +#include "vip.h" + +extern editor vip; + +int row_cx_to_rx(row *row, int cx) +{ + int rx = 0; + for (int j = 0; j < cx; j++) { + if (row->chars[j] == '\t') { + rx += (TAB_SIZE - 1) - (rx % TAB_SIZE); + } + rx++; + } + return rx; +} + +void update_row(row *row) +{ + int tabs = 0; + for (int j = 0; j < row->size; j++) + if (row->chars[j] == '\t') tabs++; + free(row->render); + row->render = malloc(row->size + tabs * (TAB_SIZE - 1) + 1); + int idx = 0; + for (int j = 0; j < row->size; j++) { + if (row->chars[j] == '\t') { + row->render[idx++] = ' '; + while (idx % TAB_SIZE != 0) { + row->render[idx++] = ' '; + } + } + else { + row->render[idx++] = row->chars[j]; + } + } + row->render[idx] = '\0'; + row->render_size = idx; +} + +void insert_row(int at, char *s, size_t len) +{ + if (at < 0 || at > vip.rows) return; + + vip.row = realloc(vip.row, sizeof(row) * (vip.rows + 1)); + memmove(&vip.row[at + 1], &vip.row[at], sizeof(row) * (vip.rows - at)); + + vip.row[at].size = len; + vip.row[at].chars = malloc(len + 1); + memcpy(vip.row[at].chars, s, len); + vip.row[at].chars[len] = '\0'; + + vip.row[at].render_size = 0; + vip.row[at].render = NULL; + update_row(&vip.row[at]); + + vip.rows++; + vip.dirty++; +} + +void free_row(row *row) +{ + free(row->render); + free(row->chars); +} + +void del_row(int at) +{ + if (at < 0 || at >= vip.rows) return; + free_row(&vip.row[at]); + memmove(&vip.row[at], &vip.row[at + 1], sizeof(row) * (vip.rows - at - 1)); + vip.rows--; + vip.dirty++; +} + +void row_insert_char(row *row, int at, int c) +{ + if (at < 0 || at > row->size) { + at = row->size; + } + row->chars = realloc(row->chars, row->size + 2); + memmove(&row->chars[at + 1], &row->chars[at], row->size - at + 1); + row->size++; + row->chars[at] = c; + update_row(row); + vip.dirty++; +} + +void row_append_str(row *row, char *s, size_t len) +{ + row->chars = realloc(row->chars, row->size + len + 1); + memcpy(&row->chars[row->size], s, len); + row->size += len; + row->chars[row->size] = '\0'; + update_row(row); + vip.dirty++; +} + +void row_del_char(row *row, int at) +{ + if (at < 0 || at >= row->size) return; + memmove(&row->chars[at], &row->chars[at + 1], row->size - at); + row->size--; + update_row(row); + vip.dirty++; +} + +char *rows_to_str(int *buflen) +{ + int total_len = 0; + for (int j = 0; j < vip.rows; j++) { + total_len += vip.row[j].size + 1; + } + *buflen = total_len; + char *buf = malloc(total_len); + char *p = buf; + for (int j = 0; j < vip.rows; j++) { + memcpy(p, vip.row[j].chars, vip.row[j].size); + p += vip.row[j].size; + *p = '\n'; + p++; + } + return buf; +} diff --git a/src/vip.c b/src/vip.c index 3f89a44..78ff7c7 100644 --- a/src/vip.c +++ b/src/vip.c @@ -13,6 +13,7 @@ #include "term.h" #include "bar.h" #include "editor.h" +#include "row.h" #define CTRL_KEY(k) ((k) & 0x1f) @@ -90,90 +91,6 @@ int read_key() } } -int row_cx_to_rx(row *row, int cx) -{ - int rx = 0; - for (int j = 0; j < cx; j++) { - if (row->chars[j] == '\t') { - rx += (TAB_SIZE - 1) - (rx % TAB_SIZE); - } - rx++; - } - return rx; -} - -void update_row(row *row) -{ - int tabs = 0; - for (int j = 0; j < row->size; j++) - if (row->chars[j] == '\t') tabs++; - free(row->render); - row->render = malloc(row->size + tabs * (TAB_SIZE - 1) + 1); - int idx = 0; - for (int j = 0; j < row->size; j++) { - if (row->chars[j] == '\t') { - row->render[idx++] = ' '; - while (idx % TAB_SIZE != 0) { - row->render[idx++] = ' '; - } - } - else { - row->render[idx++] = row->chars[j]; - } - } - row->render[idx] = '\0'; - row->render_size = idx; -} - -void append_row(char *s, size_t len) -{ - vip.row = realloc(vip.row, sizeof(row) * (vip.rows + 1)); - - int at = vip.rows; - vip.row[at].size = len; - vip.row[at].chars = malloc(len + 1); - memcpy(vip.row[at].chars, s, len); - vip.row[at].chars[len] = '\0'; - - vip.row[at].render_size = 0; - vip.row[at].render = NULL; - update_row(&vip.row[at]); - - vip.rows++; - vip.dirty++; -} - -void row_insert_char(row *row, int at, int c) -{ - if (at < 0 || at > row->size) { - at = row->size; - } - row->chars = realloc(row->chars, row->size + 2); - memmove(&row->chars[at + 1], &row->chars[at], row->size - at + 1); - row->size++; - row->chars[at] = c; - update_row(row); - vip.dirty++; -} - -char *rows_to_str(int *buflen) -{ - int total_len = 0; - for (int j = 0; j < vip.rows; j++) { - total_len += vip.row[j].size + 1; - } - *buflen = total_len; - char *buf = malloc(total_len); - char *p = buf; - for (int j = 0; j < vip.rows; j++) { - memcpy(p, vip.row[j].chars, vip.row[j].size); - p += vip.row[j].size; - *p = '\n'; - p++; - } - return buf; -} - void open_editor(char *filename) { free(vip.filename); @@ -190,7 +107,7 @@ void open_editor(char *filename) while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) { len--; } - append_row(line, len); + insert_row(vip.rows, line, len); } free(line); fclose(fp); @@ -345,11 +262,12 @@ void move_cursor(int key) void process_key() { - static int quit_times = QUIT_CONFIRM + static int quit_times = QUIT_CONFIRM; + int c = read_key(); switch (c) { case '\r': - /* TBC */ + insert_new_line(); break; case CTRL_KEY('q'): @@ -380,7 +298,9 @@ void process_key() case BACKSPACE: case CTRL_KEY('h'): case DEL_KEY: - /* TBC */ + if (c == DEL_KEY) + move_cursor(ARROW_RIGHT); + del_char(); break; case PAGE_UP: @@ -426,6 +346,7 @@ void init_editor() vip.rows = 0; vip.row = NULL; vip.dirty = 0; + vip.mode = NORMAL; vip.filename = NULL; vip.statusmsg[0] = '\0'; vip.statusmsg_time = 0;