URI: 
       tMake marks work with selections and motion callbacks - ledit - Text editor (WIP)
  HTML git clone git://lumidify.org/ledit.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/ledit.git (encrypted, but very slow)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 91a730677ac95f922d6e5bca531f9cf0811e0fd6
   DIR parent 61c47698d180e2e9e81df98c5ac9d7304594a95b
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Thu, 11 Nov 2021 00:02:36 +0100
       
       Make marks work with selections and motion callbacks
       
       Diffstat:
         M buffer.c                            |      43 ++++++++++++++++++++++++++++++
         M buffer.h                            |      13 +++++++++++++
         M keys_basic.c                        |      74 +++++++++++++++++++++++++++++--
         M keys_basic_config.h                 |       4 ++--
         M keys_command.c                      |      80 +------------------------------
         M keys_command.h                      |       4 +---
         M keys_command_config.h               |       6 +-----
       
       7 files changed, 131 insertions(+), 93 deletions(-)
       ---
   DIR diff --git a/buffer.c b/buffer.c
       t@@ -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) {
       t@@ -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);
        
       t@@ -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);
        }
        
   DIR diff --git a/buffer.h b/buffer.h
       t@@ -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. */
       t@@ -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);
       t@@ -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);
   DIR diff --git a/keys_basic.c b/keys_basic.c
       t@@ -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
       t@@ -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? */
   DIR diff --git a/keys_basic_config.h b/keys_basic_config.h
       t@@ -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},
   DIR diff --git a/keys_command.c b/keys_command.c
       t@@ -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
   DIR diff --git a/keys_command.h b/keys_command.h
       t@@ -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 */
   DIR diff --git a/keys_command_config.h b/keys_command_config.h
       t@@ -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 */
       t@@ -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[] = {