ledit

Text editor (WIP)
git clone git://lumidify.org/ledit.git (fast, but not encrypted)
git clone https://lumidify.org/git/ledit.git (encrypted, but very slow)
Log | Files | Refs | README | LICENSE

commit 91a730677ac95f922d6e5bca531f9cf0811e0fd6
parent 61c47698d180e2e9e81df98c5ac9d7304594a95b
Author: lumidify <nobody@lumidify.org>
Date:   Thu, 11 Nov 2021 00:02:36 +0100

Make marks work with selections and motion callbacks

Diffstat:
Mbuffer.c | 43+++++++++++++++++++++++++++++++++++++++++++
Mbuffer.h | 13+++++++++++++
Mkeys_basic.c | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mkeys_basic_config.h | 4++--
Mkeys_command.c | 80+------------------------------------------------------------------------------
Mkeys_command.h | 4+---
Mkeys_command_config.h | 6+-----
7 files changed, 131 insertions(+), 93 deletions(-)

diff --git a/buffer.c b/buffer.c @@ -52,6 +52,47 @@ ledit_buffer_set_mode(ledit_buffer *buffer, enum ledit_mode mode) { ledit_change_mode_group(buffer->undo); } +static void +marklist_destroy(ledit_buffer_marklist *marklist) { + for (size_t i = 0; i < marklist->len; i++) { + free(marklist->marks[i].text); + } + free(marklist->marks); + free(marklist); +} + +void +ledit_buffer_insert_mark(ledit_buffer *buffer, char *mark, int len, int line, int byte) { + ledit_buffer_marklist *marklist = buffer->marklist; + for (size_t i = 0; i < marklist->len; i++) { + if (!strncmp(mark, marklist->marks[i].text, len)) { + marklist->marks[i].line = line; + marklist->marks[i].byte = byte; + return; + } + } + if (marklist->len == marklist->alloc) { + size_t new_alloc = marklist->alloc > 0 ? marklist->alloc * 2 : 4; + marklist->marks = ledit_realloc( + marklist->marks, new_alloc * sizeof(ledit_buffer_mark) + ); + marklist->alloc = new_alloc; + } + ledit_buffer_mark *m = &marklist->marks[marklist->len]; + m->text = ledit_strndup(mark, len); + m->line = line; + m->byte = byte; + marklist->len++; +} + +static ledit_buffer_marklist * +marklist_create(void) { + ledit_buffer_marklist *marklist = ledit_malloc(sizeof(ledit_buffer_marklist)); + marklist->len = marklist->alloc = 0; + marklist->marks = NULL; + return marklist; +} + ledit_buffer * ledit_buffer_create(ledit_common *common, ledit_theme *theme, ledit_window *window) { if (basic_attrs == NULL) { @@ -85,6 +126,7 @@ ledit_buffer_create(ledit_common *common, ledit_theme *theme, ledit_window *wind buffer->cache = ledit_cache_create(common); buffer->undo = ledit_undo_stack_create(); buffer->theme = theme; + buffer->marklist = marklist_create(); ledit_window_set_scroll_callback(window, &ledit_buffer_scroll_handler, buffer); ledit_window_set_button_callback(window, &ledit_buffer_button_handler, buffer); @@ -182,6 +224,7 @@ ledit_buffer_destroy(ledit_buffer *buffer) { free(buffer->lines); if (buffer->filename) free(buffer->filename); + marklist_destroy(buffer->marklist); free(buffer); } diff --git a/buffer.h b/buffer.h @@ -18,6 +18,17 @@ typedef struct { char h_dirty; /* whether height needs to be recalculated still */ } ledit_line; +typedef struct { + char *text; + int line; + int byte; +} ledit_buffer_mark; + +typedef struct { + size_t len, alloc; + ledit_buffer_mark *marks; +} ledit_buffer_marklist; + /* TODO: advisory lock on file? also check if modification date changed before writing */ struct ledit_buffer { ledit_common *common; /* common stuff, e.g. display, window, etc. */ @@ -39,6 +50,7 @@ struct ledit_buffer { ledit_cache *cache; ledit_undo_stack *undo; ledit_window *window; + ledit_buffer_marklist *marklist; }; ledit_buffer *ledit_buffer_create(ledit_common *common, ledit_theme *theme, ledit_window *window); @@ -159,3 +171,4 @@ void ledit_buffer_scroll_to_pos_bottom(ledit_buffer *buffer, int line, int byte) /* FIXME: just make generic sort range */ void ledit_buffer_sort_selection(int *line1, int *byte1, int *line2, int *byte2); int ledit_line_next_non_whitespace(ledit_line *line, int byte); +void ledit_buffer_insert_mark(ledit_buffer *buffer, char *mark, int len, int line, int byte); diff --git a/keys_basic.c b/keys_basic.c @@ -1836,14 +1836,80 @@ enter_searchedit_backward(ledit_buffer *buffer, char *text, int len) { return (struct action){ACTION_GRABKEY, &ledit_command_key_handler}; } +/* FIXME: differentiate between jumping to line and index like nvi */ +static struct action +mark_line_cb(ledit_buffer *buffer, char *text, int len) { + grab_char_cb = NULL; + ledit_buffer_insert_mark( + buffer, text, len, buffer->cur_line, buffer->cur_index + ); + return (struct action){ACTION_NONE, NULL}; +} + +/* FIXME: check that byte is actually in at grapheme boundary */ +static struct action +jump_to_mark_cb(ledit_buffer *buffer, char *text, int len) { + grab_char_cb = NULL; + ledit_buffer_marklist *marklist = buffer->marklist; + motion_callback cb; + int num = get_key_repeat_and_motion_cb(&cb); + if (num > 0) + return err_invalid_key(buffer); + int line = -1, index = -1; + for (size_t i = 0; i < marklist->len; i++) { + if (!strncmp(text, marklist->marks[i].text, len)) { + ledit_line *ll; + ledit_buffer_mark *m = &marklist->marks[i]; + if (m->line >= buffer->lines_num) { + line = buffer->lines_num - 1; + ll = ledit_buffer_get_line(buffer, line); + index = ll->len; + } else { + line = m->line; + ll = ledit_buffer_get_line(buffer, m->line); + if (m->byte >= ll->len) + index = ll->len; + else + index = m->byte; + } + break; + } + } + if (line == -1) + return err_invalid_key(buffer); + if (buffer->common->mode == VISUAL) { + ledit_buffer_set_selection( + buffer, buffer->sel.line1, buffer->sel.byte1, line, index + ); + buffer->cur_line = line; + buffer->cur_index = index; + } else { + if (cb) { + cb(buffer, line, index, KEY_MOTION_LINE); + } else { + ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); + buffer->cur_line = line; + buffer->cur_index = index; + buffer->cur_index = ledit_buffer_get_legal_normal_pos( + buffer, buffer->cur_line, buffer->cur_index + ); + ledit_buffer_set_line_cursor_attrs( + buffer, buffer->cur_line, buffer->cur_index + ); + discard_repetition_stack(); + } + } + return (struct action){ACTION_NONE, NULL}; +} + static struct action mark_line(ledit_buffer *buffer, char *text, int len) { (void)buffer; (void)text; (void)len; - ledit_command_set_type(CMD_MARKLINE); + grab_char_cb = &mark_line_cb; discard_repetition_stack(); - return (struct action){ACTION_GRABKEY, &ledit_command_key_handler}; + return (struct action){ACTION_NONE, NULL}; } static struct action @@ -1851,9 +1917,9 @@ jump_to_mark(ledit_buffer *buffer, char *text, int len) { (void)buffer; (void)text; (void)len; - ledit_command_set_type(CMD_JUMPTOMARK); + grab_char_cb = &jump_to_mark_cb; discard_repetition_stack(); - return (struct action){ACTION_GRABKEY, &ledit_command_key_handler}; + return (struct action){ACTION_NONE, NULL}; } /* FIXME: support visual mode, i.e. change selection to new place? */ diff --git a/keys_basic_config.h b/keys_basic_config.h @@ -169,8 +169,8 @@ static struct key keys_en[] = { {"a", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &append_after_cursor}, {"O", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &append_line_above}, {"o", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &append_line_below}, - {"m", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &mark_line}, - {"'", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &jump_to_mark}, + {"m", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &mark_line}, + {"'", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &jump_to_mark}, {"C", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &change_to_eol}, {"D", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &delete_to_eol}, {"r", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &replace}, diff --git a/keys_command.c b/keys_command.c @@ -30,87 +30,9 @@ /* this must first be set by caller before jumping to key handler */ static enum ledit_command_type cur_type; -struct mark { - char *text; - int line; - int byte; -}; - -/* FIXME: this should be part of buffer! */ -struct { - size_t len, alloc; - struct mark *marks; -} marklist = {0, 0, NULL}; - void command_key_cleanup(void) { - for (size_t i = 0; i < marklist.len; i++) { - free(marklist.marks[i].text); - } - free(marklist.marks); -} - -static void -insert_mark(char *mark, int len, int line, int byte) { - for (size_t i = 0; i < marklist.len; i++) { - if (!strncmp(mark, marklist.marks[i].text, len)) { - marklist.marks[i].line = line; - marklist.marks[i].byte = byte; - return; - } - } - if (marklist.len == marklist.alloc) { - size_t new_alloc = marklist.alloc > 0 ? marklist.alloc * 2 : 4; - marklist.marks = ledit_realloc( - marklist.marks, new_alloc * sizeof(struct mark) - ); - marklist.alloc = new_alloc; - } - struct mark *m = &marklist.marks[marklist.len]; - m->text = ledit_strndup(mark, len); - m->line = line; - m->byte = byte; - marklist.len++; -} - -/* FIXME: differentiate between jumping to line and index like nvi */ -static int -mark_line(ledit_buffer *buffer, char *key_text, int len) { - insert_mark(key_text, len, buffer->cur_line, buffer->cur_index); - return 0; -} - -/* FIXME: check that byte is actually in at grapheme boundary */ -/* FIXME: make this work with selections! */ -static int -jump_to_mark(ledit_buffer *buffer, char *key_text, int len) { - ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); - for (size_t i = 0; i < marklist.len; i++) { - if (!strncmp(key_text, marklist.marks[i].text, len)) { - ledit_line *ll; - struct mark *m = &marklist.marks[i]; - if (m->line >= buffer->lines_num) { - buffer->cur_line = buffer->lines_num - 1; - ll = ledit_buffer_get_line(buffer, buffer->cur_line); - buffer->cur_index = ll->len; - } else { - buffer->cur_line = m->line; - ll = ledit_buffer_get_line(buffer, m->line); - if (m->byte >= ll->len) - buffer->cur_index = ll->len; - else - buffer->cur_index = m->byte; - } - break; - } - } - if (buffer->common->mode == NORMAL) { - buffer->cur_index = ledit_buffer_get_legal_normal_pos( - buffer, buffer->cur_line, buffer->cur_index - ); - } - ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_index); - return 0; + /* nothing right now */ } void diff --git a/keys_command.h b/keys_command.h @@ -4,9 +4,7 @@ enum ledit_command_type { CMD_EDITSEARCHB, CMD_SEARCH, CMD_SEARCHB, - CMD_SUBSTITUTE, - CMD_MARKLINE, - CMD_JUMPTOMARK + CMD_SUBSTITUTE }; /* these are only here so they can also be used by keys_basic */ diff --git a/keys_command_config.h b/keys_command_config.h @@ -6,8 +6,6 @@ static int edit_insert_text(ledit_buffer *buffer, char *key_text, int len); static int edit_submit(ledit_buffer *buffer, char *key_text, int len); static int editsearch_submit(ledit_buffer *buffer, char *key_text, int len); static int editsearchb_submit(ledit_buffer *buffer, char *key_text, int len); -static int mark_line(ledit_buffer *buffer, char *key_text, int len); -static int jump_to_mark(ledit_buffer *buffer, char *key_text, int len); struct key { char *text; /* for keys that correspond with text */ @@ -28,9 +26,7 @@ static struct key keys_en[] = { {NULL, 0, XK_Return, CMD_EDITSEARCHB, &editsearchb_submit}, {"", 0, 0, CMD_EDIT, &edit_insert_text}, {"", 0, 0, CMD_EDITSEARCH, &edit_insert_text}, - {"", 0, 0, CMD_EDITSEARCHB, &edit_insert_text}, - {"", 0, 0, CMD_MARKLINE, &mark_line}, - {"", 0, 0, CMD_JUMPTOMARK, &jump_to_mark} + {"", 0, 0, CMD_EDITSEARCHB, &edit_insert_text} }; static struct key keys_de[] = {