|
|
|
|
@@ -27,6 +27,9 @@
|
|
|
|
|
|
|
|
|
|
struct edit_line {
|
|
|
|
|
struct list_node_link lines_link;
|
|
|
|
|
struct list_node_link select_link;
|
|
|
|
|
size_t select_start;
|
|
|
|
|
size_t select_end;
|
|
|
|
|
struct gapbuffer gb;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -35,6 +38,18 @@ struct cursor {
|
|
|
|
|
size_t line;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define EDIT_MODE_NORMAL 0
|
|
|
|
|
#define EDIT_MODE_COMAMND 1
|
|
|
|
|
|
|
|
|
|
static const char* string_modes[] = {
|
|
|
|
|
[EDIT_MODE_NORMAL] = "Normal",
|
|
|
|
|
[EDIT_MODE_COMAMND] = "Command",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct edit_select {
|
|
|
|
|
struct list_node_link* lines;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct editor {
|
|
|
|
|
struct list_node_link* lines;
|
|
|
|
|
struct edit_line* current_line;
|
|
|
|
|
@@ -42,6 +57,8 @@ struct editor {
|
|
|
|
|
size_t col_offset;
|
|
|
|
|
size_t row_offset;
|
|
|
|
|
size_t total_lines;
|
|
|
|
|
struct edit_select select;
|
|
|
|
|
int mode;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct editor editor;
|
|
|
|
|
@@ -98,6 +115,8 @@ static size_t count_digits (size_t n) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void edit_start (const char* file_path, const char* text) {
|
|
|
|
|
mprintf (ANSIQ_SCR_SAVE);
|
|
|
|
|
|
|
|
|
|
prepare_lines (text);
|
|
|
|
|
struct arena temp_arena;
|
|
|
|
|
memset (&temp_arena, 0, sizeof (temp_arena));
|
|
|
|
|
@@ -105,7 +124,7 @@ void edit_start (const char* file_path, const char* text) {
|
|
|
|
|
|
|
|
|
|
terminal_dimensions (&cols, &rows);
|
|
|
|
|
|
|
|
|
|
mprintf (ANSIQ_SCR_CLR_ALL ANSIQ_CUR_INVISIBLE);
|
|
|
|
|
mprintf (ANSIQ_CUR_INVISIBLE);
|
|
|
|
|
|
|
|
|
|
bool edit_run = true;
|
|
|
|
|
|
|
|
|
|
@@ -207,8 +226,9 @@ void edit_start (const char* file_path, const char* text) {
|
|
|
|
|
bbptr += w;
|
|
|
|
|
bb_remaining -= w;
|
|
|
|
|
|
|
|
|
|
w = snprintf (bbptr, bb_remaining, " Editing %s; line %zu col %zu" ANSIQ_GR_RESET, file_path,
|
|
|
|
|
editor.cursor.line + 1, editor.cursor.col + 1);
|
|
|
|
|
w = snprintf (bbptr, bb_remaining, " Editing %s; line %zu col %zu; Mode: %s" ANSIQ_GR_RESET,
|
|
|
|
|
file_path, editor.cursor.line + 1, editor.cursor.col + 1,
|
|
|
|
|
string_modes[editor.mode]);
|
|
|
|
|
bbptr += w;
|
|
|
|
|
bb_remaining -= w;
|
|
|
|
|
|
|
|
|
|
@@ -225,50 +245,58 @@ void edit_start (const char* file_path, const char* text) {
|
|
|
|
|
|
|
|
|
|
switch (ch) {
|
|
|
|
|
case '\b':
|
|
|
|
|
if (editor.cursor.col > 0) {
|
|
|
|
|
gapbuffer_move (&editor.current_line->gb, editor.cursor.col);
|
|
|
|
|
editor.cursor.col--;
|
|
|
|
|
gapbuffer_backspace (&editor.current_line->gb);
|
|
|
|
|
if (editor.mode == EDIT_MODE_NORMAL) {
|
|
|
|
|
if (editor.cursor.col > 0) {
|
|
|
|
|
gapbuffer_move (&editor.current_line->gb, editor.cursor.col);
|
|
|
|
|
editor.cursor.col--;
|
|
|
|
|
gapbuffer_backspace (&editor.current_line->gb);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case '\t':
|
|
|
|
|
gapbuffer_move (&editor.current_line->gb, editor.cursor.col);
|
|
|
|
|
for (size_t i = 0; i < sizeof (TAB_INSERT) - 1; i++)
|
|
|
|
|
gapbuffer_insert (&wrealloc, NULL, &editor.current_line->gb, TAB_INSERT[i]);
|
|
|
|
|
if (editor.mode == EDIT_MODE_NORMAL) {
|
|
|
|
|
gapbuffer_move (&editor.current_line->gb, editor.cursor.col);
|
|
|
|
|
for (size_t i = 0; i < sizeof (TAB_INSERT) - 1; i++)
|
|
|
|
|
gapbuffer_insert (&wrealloc, NULL, &editor.current_line->gb, TAB_INSERT[i]);
|
|
|
|
|
|
|
|
|
|
editor.cursor.col += sizeof (TAB_INSERT) - 1;
|
|
|
|
|
editor.cursor.col += sizeof (TAB_INSERT) - 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case '\n': {
|
|
|
|
|
gapbuffer_move (&editor.current_line->gb, editor.cursor.col);
|
|
|
|
|
if (editor.mode == EDIT_MODE_NORMAL) {
|
|
|
|
|
gapbuffer_move (&editor.current_line->gb, editor.cursor.col);
|
|
|
|
|
|
|
|
|
|
struct edit_line* new_line = malloc (sizeof (*new_line));
|
|
|
|
|
memset (new_line, 0, sizeof (*new_line));
|
|
|
|
|
struct edit_line* new_line = malloc (sizeof (*new_line));
|
|
|
|
|
memset (new_line, 0, sizeof (*new_line));
|
|
|
|
|
|
|
|
|
|
char* tail = gapbuffer_string_at (&warena_malloc, &temp_arena, &editor.current_line->gb,
|
|
|
|
|
editor.cursor.col);
|
|
|
|
|
size_t tail_size = strlen (tail);
|
|
|
|
|
size_t init_cap = tail_size > 0 ? tail_size : 32;
|
|
|
|
|
char* tail = gapbuffer_string_at (&warena_malloc, &temp_arena, &editor.current_line->gb,
|
|
|
|
|
editor.cursor.col);
|
|
|
|
|
size_t tail_size = strlen (tail);
|
|
|
|
|
size_t init_cap = tail_size > 0 ? tail_size : 32;
|
|
|
|
|
|
|
|
|
|
gapbuffer_init (&wmalloc, NULL, &new_line->gb, init_cap);
|
|
|
|
|
gapbuffer_init (&wmalloc, NULL, &new_line->gb, init_cap);
|
|
|
|
|
|
|
|
|
|
if (tail_size > 0) {
|
|
|
|
|
memcpy (new_line->gb.buffer,
|
|
|
|
|
editor.current_line->gb.buffer + editor.current_line->gb.gap_end, tail_size);
|
|
|
|
|
new_line->gb.gap_start = tail_size;
|
|
|
|
|
if (tail_size > 0) {
|
|
|
|
|
memcpy (new_line->gb.buffer,
|
|
|
|
|
editor.current_line->gb.buffer + editor.current_line->gb.gap_end, tail_size);
|
|
|
|
|
new_line->gb.gap_start = tail_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
editor.current_line->gb.gap_end = editor.current_line->gb.size;
|
|
|
|
|
|
|
|
|
|
list_insert_after (editor.lines, &editor.current_line->lines_link, &new_line->lines_link);
|
|
|
|
|
|
|
|
|
|
editor.cursor.col = 0;
|
|
|
|
|
editor.cursor.line++;
|
|
|
|
|
editor.current_line = new_line;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
editor.current_line->gb.gap_end = editor.current_line->gb.size;
|
|
|
|
|
|
|
|
|
|
list_insert_after (editor.lines, &editor.current_line->lines_link, &new_line->lines_link);
|
|
|
|
|
|
|
|
|
|
editor.cursor.col = 0;
|
|
|
|
|
editor.cursor.line++;
|
|
|
|
|
editor.current_line = new_line;
|
|
|
|
|
} break;
|
|
|
|
|
case KB_DELETE:
|
|
|
|
|
if (editor.cursor.col < gapbuffer_length (&editor.current_line->gb)) {
|
|
|
|
|
gapbuffer_move (&editor.current_line->gb, editor.cursor.col);
|
|
|
|
|
editor.current_line->gb.gap_end++;
|
|
|
|
|
if (editor.mode == EDIT_MODE_NORMAL) {
|
|
|
|
|
if (editor.cursor.col < gapbuffer_length (&editor.current_line->gb)) {
|
|
|
|
|
gapbuffer_move (&editor.current_line->gb, editor.cursor.col);
|
|
|
|
|
editor.current_line->gb.gap_end++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case KB_LEFT:
|
|
|
|
|
@@ -305,14 +333,28 @@ void edit_start (const char* file_path, const char* text) {
|
|
|
|
|
case KB_END:
|
|
|
|
|
editor.cursor.col = gapbuffer_length (&editor.current_line->gb);
|
|
|
|
|
break;
|
|
|
|
|
case KB_CTRL ('Q'):
|
|
|
|
|
edit_run = false;
|
|
|
|
|
case KB_ESCAPE:
|
|
|
|
|
editor.mode = EDIT_MODE_NORMAL;
|
|
|
|
|
break;
|
|
|
|
|
case KB_CTRL ('X'):
|
|
|
|
|
editor.mode = EDIT_MODE_COMAMND;
|
|
|
|
|
default:
|
|
|
|
|
if (isprint (ch)) {
|
|
|
|
|
gapbuffer_move (&editor.current_line->gb, editor.cursor.col);
|
|
|
|
|
gapbuffer_insert (&wrealloc, NULL, &editor.current_line->gb, ch);
|
|
|
|
|
editor.cursor.col++;
|
|
|
|
|
if (editor.mode == EDIT_MODE_COMAMND) {
|
|
|
|
|
switch (ch) {
|
|
|
|
|
case 'q':
|
|
|
|
|
edit_run = false;
|
|
|
|
|
editor.mode = EDIT_MODE_NORMAL;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
editor.mode = EDIT_MODE_NORMAL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else if (editor.mode == EDIT_MODE_NORMAL) {
|
|
|
|
|
gapbuffer_move (&editor.current_line->gb, editor.cursor.col);
|
|
|
|
|
gapbuffer_insert (&wrealloc, NULL, &editor.current_line->gb, ch);
|
|
|
|
|
editor.cursor.col++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@@ -333,4 +375,5 @@ void edit_start (const char* file_path, const char* text) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset (&editor, 0, sizeof (editor));
|
|
|
|
|
mprintf (ANSIQ_SCR_RESTORE);
|
|
|
|
|
}
|
|
|
|
|
|