diff --git a/ce/edit.c b/ce/edit.c index ffd6946..2101863 100644 --- a/ce/edit.c +++ b/ce/edit.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,8 @@ struct editor { struct list_node_link* lines; struct edit_line* current_line; struct cursor cursor; + size_t col_offset; + size_t row_offset; }; static struct editor editor; @@ -58,34 +61,93 @@ static bool prepare_lines_cb (void* ctx, const char* start, size_t len) { static void prepare_lines (const char* text) { strtokenize (text, '\n', NULL, &prepare_lines_cb); } +static void update_horz_scroll (size_t screen_cols) { + if (editor.cursor.col < editor.col_offset) + editor.col_offset = editor.cursor.col; + + if (editor.cursor.col >= editor.col_offset + screen_cols) + editor.col_offset = editor.cursor.col - screen_cols + 1; +} + +static void update_vert_scroll (size_t screen_rows) { + if (editor.cursor.line < editor.row_offset) + editor.row_offset = editor.cursor.line; + + if (editor.cursor.line >= editor.row_offset + (screen_rows - 1)) + editor.row_offset = editor.cursor.line - (screen_rows - 1) + 1; +} + void edit_start (const char* text) { prepare_lines (text); struct arena temp_arena; + size_t cols, rows; + + terminal_dimensions (&cols, &rows); mprintf (ANSIQ_SCR_SAVE ANSIQ_SCR_CLR_ALL ANSIQ_CUR_INVISIBLE); for (;;) { + update_horz_scroll (cols); + update_vert_scroll (rows); + + int w; const size_t backbuffer_max = 128 * 1024; + size_t bb_remaining = backbuffer_max; char* backbuffer = arena_malloc (&temp_arena, backbuffer_max); memset (backbuffer, 0, backbuffer_max); + char* bbptr = backbuffer; - strncat (backbuffer, ANSIQ_CUR_HOME ANSIQ_SCR_CLR_ALL, backbuffer_max); + w = snprintf (bbptr, bb_remaining, ANSIQ_CUR_HOME); + bbptr += w; + bb_remaining -= w; + + size_t lines_drawn = 0; + size_t current_idx = 0; struct list_node_link *line_link, *tmp_line_link; list_foreach (editor.lines, line_link, tmp_line_link) { + if (current_idx < editor.row_offset) { + current_idx++; + continue; + } + + if (lines_drawn >= rows - 1) + break; + struct edit_line* line = list_entry (line_link, struct edit_line, lines_link); - strncat (backbuffer, ANSIQ_SCR_CLR_LINE, backbuffer_max); + w = snprintf (bbptr, bb_remaining, ANSIQ_SCR_CLR_LINE); + bbptr += w; + bb_remaining -= w; char* render = gapbuffer_get_string (&warena_malloc, &temp_arena, &line->gb); - strncat (backbuffer, render, backbuffer_max); - strncat (backbuffer, "\n", backbuffer_max); + size_t len = strlen (render); + + if (len > editor.col_offset) { + char* visible = render + editor.col_offset; + size_t visible_len = len - editor.col_offset; + + if (visible_len > cols) + visible_len = cols; + + w = snprintf (bbptr, bb_remaining, "%.*s", (int)visible_len, visible); + bbptr += w; + bb_remaining -= w; + } + + w = snprintf (bbptr, bb_remaining, ANSIQ_SCR_CLR2LEND "\n"); + bbptr += w; + bb_remaining -= w; + + lines_drawn++; + current_idx++; } - char tmp[128]; - snprintf (tmp, sizeof (tmp), ANSIQ_DYN_CUR_SET ANSIQ_CUR_VISIBLE, (int)editor.cursor.line + 1, - (int)editor.cursor.col + 1); - strncat (backbuffer, tmp, backbuffer_max); + w = snprintf (bbptr, bb_remaining, ANSIQ_DYN_CUR_SET ANSIQ_CUR_VISIBLE, + (int)(editor.cursor.line - editor.row_offset) + 1, + (int)(editor.cursor.col - editor.col_offset) + 1); + bbptr += w; + bb_remaining -= w; mail_send (e_pgid, backbuffer, strlen (backbuffer)); @@ -102,20 +164,37 @@ void edit_start (const char* text) { } break; case KB_DELETE: - if (editor.cursor.col < gapbuffer_length (&editor.current_line->gb)) { + if (editor.cursor.col < gapbuffer_length (&editor.current_line->gb)) editor.current_line->gb.gap_end++; - } break; case KB_LEFT: - if (editor.cursor.col > 0) { + if (editor.cursor.col > 0) editor.cursor.col--; - } break; case KB_RIGHT: - if (editor.cursor.col < gapbuffer_length (&editor.current_line->gb)) { + if (editor.cursor.col < gapbuffer_length (&editor.current_line->gb)) editor.cursor.col++; - } break; + case KB_UP: { + if (editor.cursor.line > 0) { + editor.cursor.line--; + editor.current_line = + list_entry (editor.current_line->lines_link.prev, struct edit_line, lines_link); + size_t len = gapbuffer_length (&editor.current_line->gb); + if (editor.cursor.col > len) + editor.cursor.col = len; + } + } break; + case KB_DOWN: { + if (editor.current_line->lines_link.next != NULL) { + editor.cursor.line++; + editor.current_line = + list_entry (editor.current_line->lines_link.next, struct edit_line, lines_link); + size_t len = gapbuffer_length (&editor.current_line->gb); + if (editor.cursor.col > len) + editor.cursor.col = len; + } + } break; default: if (isprint (ch)) { gapbuffer_insert (&wrealloc, NULL, &editor.current_line->gb, ch);