URI: 
       tImplement appending commands - 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 3d0707ecc637d39e0f853d036c592bbcbe7675f7
   DIR parent 335e5d61cc5d4876fb7240543fb55afb55f00cfb
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Fri,  5 Nov 2021 21:04:14 +0100
       
       Implement appending commands
       
       Diffstat:
         M buffer.c                            |      16 ++++++++++++++++
         M buffer.h                            |       2 +-
         M keys_basic.c                        |      49 +++++++++++++++++++++++++++++++
         M keys_basic_config.h                 |       8 ++++++++
       
       4 files changed, 74 insertions(+), 1 deletion(-)
       ---
   DIR diff --git a/buffer.c b/buffer.c
       t@@ -901,6 +901,22 @@ line_byte_to_char(ledit_line *line, int byte) {
                return c;
        }
        
       +int
       +ledit_buffer_next_cursor_pos(ledit_buffer *buffer, int line, int byte) {
       +        int nattrs;
       +        ledit_line *ll = ledit_buffer_get_line(buffer, line);
       +        int c = line_byte_to_char(ll, byte);
       +        int cur_byte = ledit_line_next_utf8(ll, byte);
       +        const PangoLogAttr *attrs =
       +            pango_layout_get_log_attrs_readonly(ll->layout, &nattrs);
       +        for (int i = c + 1; i < nattrs; i++) {
       +                if (attrs[i].is_cursor_position)
       +                        return cur_byte;
       +                cur_byte = ledit_line_next_utf8(ll, cur_byte);
       +        }
       +        return ll->len;
       +}
       +
        static int
        line_next_word(ledit_line *line, int byte, int char_index, int wrapped_line, int *char_ret, int *real_byte_ret) {
                int c, nattrs;
   DIR diff --git a/buffer.h b/buffer.h
       t@@ -57,7 +57,7 @@ void ledit_pos_to_x_softline(ledit_line *line, int pos, int *x_ret, int *softlin
        void ledit_x_softline_to_pos(ledit_line *line, int x, int softline, int *pos_ret);
        int ledit_line_next_utf8(ledit_line *line, int index);
        int ledit_line_prev_utf8(ledit_line *line, int index);
       -int ledit_line_byte_to_char(ledit_line *line, int byte);
       +int ledit_buffer_next_cursor_pos(ledit_buffer *buffer, int line, int byte);
        
        void ledit_buffer_next_word(ledit_buffer *buffer, int line, int byte, int num_repeat, int *line_ret, int *byte_ret, int *real_byte_ret);
        void ledit_buffer_next_word_end(ledit_buffer *buffer, int line, int byte, int num_repeat, int *line_ret, int *byte_ret, int *real_byte_ret);
   DIR diff --git a/keys_basic.c b/keys_basic.c
       t@@ -396,6 +396,55 @@ get_key_repeat(void) {
                return num;
        }
        
       +static struct action
       +append_line_above(ledit_buffer *buffer, char *text, int len) {
       +        int sli, x;
       +        /* do this here already so the mode group is the same for the newline insertion */
       +        enter_insert(buffer, text, len);
       +        ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line);
       +        pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &x);
       +        if (sli == 0) {
       +                insert_text(buffer, buffer->cur_line, 0, "\n", -1, buffer->cur_line, 0, 1);
       +        } else {
       +                PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, sli);
       +                insert_text(buffer, buffer->cur_line, sl->start_index, "\n\n", -1, buffer->cur_line + 1, 0, 1);
       +        }
       +        return (struct action){ACTION_NONE, NULL};
       +}
       +
       +static struct action
       +append_line_below(ledit_buffer *buffer, char *text, int len) {
       +        int sli, x;
       +        enter_insert(buffer, text, len);
       +        ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line);
       +        pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &x);
       +        PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, sli);
       +        if (sl->start_index + sl->length == ll->len) {
       +                insert_text(buffer, buffer->cur_line, ll->len, "\n", -1, buffer->cur_line + 1, 0, 1);
       +        } else {
       +                insert_text(buffer, buffer->cur_line, sl->start_index + sl->length, "\n\n", -1, buffer->cur_line + 1, 0, 1);
       +        }
       +        return (struct action){ACTION_NONE, NULL};
       +}
       +
       +static struct action
       +append_after_cursor(ledit_buffer *buffer, char *text, int len) {
       +        buffer->cur_index = ledit_buffer_next_cursor_pos(
       +            buffer, buffer->cur_line, buffer->cur_index
       +        );
       +        return enter_insert(buffer, text, len);
       +}
       +
       +static struct action
       +append_after_eol(ledit_buffer *buffer, char *text, int len) {
       +        int sli, x;
       +        ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line);
       +        pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &x);
       +        PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, sli);
       +        buffer->cur_index = sl->start_index + sl->length;
       +        return enter_insert(buffer, text, len);
       +}
       +
        /* FIXME: allow motion callback! */
        static struct action
        move_to_line(ledit_buffer *buffer, char *text, int len) {
   DIR diff --git a/keys_basic_config.h b/keys_basic_config.h
       t@@ -76,6 +76,10 @@ static struct action next_bigword(ledit_buffer *buffer, char *text, int len);
        static struct action next_bigword_end(ledit_buffer *buffer, char *text, int len);
        static struct action prev_word(ledit_buffer *buffer, char *text, int len);
        static struct action prev_bigword(ledit_buffer *buffer, char *text, int len);
       +static struct action append_after_eol(ledit_buffer *buffer, char *text, int len);
       +static struct action append_after_cursor(ledit_buffer *buffer, char *text, int len);
       +static struct action append_line_above(ledit_buffer *buffer, char *text, int len);
       +static struct action append_line_below(ledit_buffer *buffer, char *text, int len);
        
        /* FIXME: maybe sort these and use binary search
           -> but that would mess with the catch-all keys */
       t@@ -143,6 +147,10 @@ static struct key keys_en[] = {
                {"G",  0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &move_to_line},
                {"p",  0, 0, NORMAL, KEY_ANY, KEY_ANY, &paste_normal},
                {"P",  0, 0, NORMAL, KEY_ANY, KEY_ANY, &paste_normal_backwards},
       +        {"A",  0, 0, NORMAL, KEY_ANY, KEY_ANY, &append_after_eol},
       +        {"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},
                {"", 0, 0, INSERT, KEY_ANY, KEY_ANY, &insert_mode_insert_text}