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 c5fa1b6794a0e0dc9346571a34c85d40fdbb01b5
parent b113e1224270deb100329dec7cc42e05d8aead63
Author: lumidify <nobody@lumidify.org>
Date:   Wed, 10 Nov 2021 21:43:56 +0100

Clean up commands with motion callback

Diffstat:
Mkeys_basic.c | 308+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mkeys_basic_config.h | 4++--
2 files changed, 160 insertions(+), 152 deletions(-)

diff --git a/keys_basic.c b/keys_basic.c @@ -111,7 +111,7 @@ void clear_key_stack(void); static void move_cursor_left_right(ledit_buffer *buffer, int dir, int allow_illegal_index); static void move_cursor_up_down(ledit_buffer *buffer, int dir); static void push_num(int num); -static void key_d_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type); +static void delete_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type); static void yank_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type); static void get_new_line_softline( ledit_buffer *buffer, int cur_line, int cur_index, @@ -187,21 +187,74 @@ err_invalid_key(ledit_buffer *buffer) { return (struct action){ACTION_NONE, NULL}; } -/* FIXME: error if no motion cb and not number key */ +/* + * Get the number of times a command should be repeated and the motion + * callback, if there was one on the stack. + * Note that *cb_ret is set to NULL if a non-null address is given and + * there is no motion callback on the stack. + * An empty stack or a stack where the top element has a count of 0 + * leads to 0 being returned. + * In case of error, -1 is returned: + * - When the top or second element is not a number key but also does + * not comtain a motion callback. + * - When the stack is not empty after removing the top element and + * possibly a second one if the top one was a number key. + */ static int get_key_repeat_and_motion_cb(motion_callback *cb_ret) { int num = 1; struct key_stack_elem *e = pop_key_stack(); if (e != NULL) { if (e->key & KEY_NUMBER) { - num = e->count > 0 ? e->count : 1; + num = e->count; e = pop_key_stack(); + } else if (e->count == 0) { + num = 0; } if (e != NULL) num *= (e->count > 0 ? e->count : 1); + } else { + num = 0; } + if (e != NULL && !(e->key & KEY_NUMBER) && e->motion_cb == NULL) + num = -1; + else if (!key_stack_empty()) + num = -1; if (cb_ret != NULL && e != NULL && e->motion_cb != NULL) *cb_ret = e->motion_cb; + else if (cb_ret != NULL) + *cb_ret = NULL; + return num; +} + +/* + * Get the number of times a command should be repeated, or -1 if anything + * invalid was on the stack - this is for commands that just take a repeat + * count and nothing else (cursor movement keys are different because they + * can use other elements on the key stack too, for instance call a callback + * as is done for deletion. + * Note that an empty stack leads to 0 being returned even though most commands + * use 1 as repeat then so the caller can distinguish between empty stack and + * a repetition count of 1. + */ +static int +get_key_repeat(void) { + int num = 1; + struct key_stack_elem *e = pop_key_stack(); + if (e != NULL) { + if (e->key & KEY_NUMBER) { + num = e->count > 0 ? e->count : 1; + e = pop_key_stack(); + } + if (e != NULL) { + /* the key was not a number, or there was another + element under it on the stack -> error */ + num = -1; + } + } else { + num = 0; + } + clear_key_stack(); return num; } @@ -418,35 +471,6 @@ delete_selection(ledit_buffer *buffer) { return 0; } -/* get the number of times a command should be repeated, or -1 if anything - invalid was on the stack - this is for commands that just take a repeat - count and nothing else (cursor movement keys are different because they - can use other elements on the key stack too, for instance call a callback - as is done for deletion - Note that an empty stack leads to 0 being returned even though most commands - use 1 as repeat then so the caller can distinguish between empty stack and - a repetition count of 1 */ -static int -get_key_repeat(void) { - int num = 1; - struct key_stack_elem *e = pop_key_stack(); - if (e != NULL) { - if (e->key & KEY_NUMBER) { - num = e->count > 0 ? e->count : 1; - e = pop_key_stack(); - } - if (e != NULL) { - /* the key was not a number, or there was another - element under it on the stack -> error */ - num = -1; - } - } else { - num = 0; - } - clear_key_stack(); - return num; -} - static struct action delete_chars_forwards(ledit_buffer *buffer, char *text, int len) { (void)text; @@ -574,15 +598,18 @@ static struct action move_to_line(ledit_buffer *buffer, char *text, int len) { (void)text; (void)len; - int repeat = get_key_repeat(); + motion_callback cb = NULL; + int repeat = get_key_repeat_and_motion_cb(&cb); int line; if (repeat > 0) line = repeat > buffer->lines_num ? buffer->lines_num : repeat; else if (repeat == 0) line = buffer->lines_num; else - ledit_window_show_message(buffer->window, "Invalid key", -1); - if (repeat >= 0) { + return err_invalid_key(buffer); + if (cb != NULL) { + cb(buffer, line - 1, 0, KEY_MOTION_LINE); + } else { ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); buffer->cur_line = line - 1; buffer->cur_index = 0; @@ -597,8 +624,8 @@ move_to_line(ledit_buffer *buffer, char *text, int len) { ledit_buffer_scroll(buffer, ll->y_offset - text_h / 2); } ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_index); + discard_repetition_stack(); } - discard_repetition_stack(); return (struct action){ACTION_NONE, NULL}; } @@ -828,39 +855,31 @@ static struct action change(ledit_buffer *buffer, char *text, int len) { (void)text; (void)len; - int num = 0; - struct key_stack_elem *e = pop_key_stack(); - if (buffer->sel.line1 != buffer->sel.line2 || buffer->sel.byte1 != buffer->sel.byte2) { + motion_callback cb = NULL; + int num = get_key_repeat_and_motion_cb(&cb); + if (num == -1) + return err_invalid_key(buffer); + if (buffer->common->mode == VISUAL) { ledit_buffer_set_mode(buffer, INSERT); delete_selection(buffer); ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); clear_key_stack(); } else { - if (e != NULL) { - if (e->key & KEY_NUMBER) { - num = e->count; - e = pop_key_stack(); - } - if (e != NULL && e->motion_cb == &change_cb) { - int prevnum = e->count > 0 ? e->count : 1; - num = num > 0 ? num : 1; - int lines = num * prevnum; - int new_line, new_softline; - get_new_line_softline( - buffer, buffer->cur_line, buffer->cur_index, - lines - 1, &new_line, &new_softline - ); - ledit_line *ll = ledit_buffer_get_line(buffer, new_line); - PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layout, new_softline); - e->motion_cb(buffer, new_line, pl->start_index, KEY_MOTION_LINE); - clear_key_stack(); - } else if (e != NULL) { - /* FIXME: show message? */ - clear_key_stack(); - } - } - if (e == NULL) { - e = push_key_stack(); + if (cb == &change_cb) { + int lines = num > 0 ? num : 1; + int new_line, new_softline; + get_new_line_softline( + buffer, buffer->cur_line, buffer->cur_index, + lines - 1, &new_line, &new_softline + ); + ledit_line *ll = ledit_buffer_get_line(buffer, new_line); + PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layout, new_softline); + cb(buffer, new_line, pl->start_index, KEY_MOTION_LINE); + clear_key_stack(); + } else if (cb != NULL) { + return err_invalid_key(buffer); + } else { + struct key_stack_elem *e = push_key_stack(); e->key = KEY_MOTION; /* ? */ e->count = num; e->motion_cb = &change_cb; @@ -924,6 +943,8 @@ yank(ledit_buffer *buffer, char *text, int len) { } else { motion_callback cb = NULL; int num = get_key_repeat_and_motion_cb(&cb); + if (num == 0) + num = 1; if (cb == &yank_cb) { int new_line, new_softline; get_new_line_softline( @@ -1000,45 +1021,38 @@ yank_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type) { } static struct action -key_d(ledit_buffer *buffer, char *text, int len) { +delete(ledit_buffer *buffer, char *text, int len) { (void)text; (void)len; - int num = 0; + motion_callback cb = NULL; + int num = get_key_repeat_and_motion_cb(&cb); + if (num == -1) + return err_invalid_key(buffer); if (delete_selection(buffer)) { ledit_buffer_set_mode(buffer, 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); clear_key_stack(); } else { - struct key_stack_elem *e = pop_key_stack(); - if (e != NULL) { - if (e->key & KEY_NUMBER) { - num = e->count; - e = pop_key_stack(); - } - /* FIXME: checking equality of the function pointer may be a bit risky */ - if (e != NULL && e->motion_cb == &key_d_cb) { - int prevnum = e->count > 0 ? e->count : 1; - num = num > 0 ? num : 1; - int lines = num * prevnum; - int new_line, new_softline; - get_new_line_softline( - buffer, buffer->cur_line, buffer->cur_index, - lines - 1, &new_line, &new_softline - ); - ledit_line *ll = ledit_buffer_get_line(buffer, new_line); - PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layout, new_softline); - e->motion_cb(buffer, new_line, pl->start_index, KEY_MOTION_LINE); - clear_key_stack(); - } else if (e != NULL) { - clear_key_stack(); - } - } - if (e == NULL) { - e = push_key_stack(); + /* FIXME: checking equality of the function pointer may be a bit risky */ + if (cb == &delete_cb) { + int lines = num > 0 ? num : 1; + int new_line, new_softline; + get_new_line_softline( + buffer, buffer->cur_line, buffer->cur_index, + lines - 1, &new_line, &new_softline + ); + ledit_line *ll = ledit_buffer_get_line(buffer, new_line); + PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layout, new_softline); + cb(buffer, new_line, pl->start_index, KEY_MOTION_LINE); + clear_key_stack(); + } else if (cb != NULL) { + return err_invalid_key(buffer); + } else { + struct key_stack_elem *e = push_key_stack(); e->key = KEY_MOTION; /* ? */ e->count = num; - e->motion_cb = &key_d_cb; + e->motion_cb = &delete_cb; } } return (struct action){ACTION_NONE, NULL}; @@ -1046,7 +1060,7 @@ key_d(ledit_buffer *buffer, char *text, int len) { /* FIXME: should this get number of lines to remove or actual end line? */ static void -key_d_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type) { +delete_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type) { int line_based = type == KEY_MOTION_LINE ? 1 : 0; delete_range( buffer, line_based, 0, @@ -1314,16 +1328,12 @@ static struct action move_to_eol(ledit_buffer *buffer, char *text, int len) { (void)text; (void)len; - int num = 1; - struct key_stack_elem *e = pop_key_stack(); - if (e != NULL) { - if (e->key & KEY_NUMBER) { - num = e->count > 0 ? e->count : 1; - e = pop_key_stack(); - } - if (e != NULL) - num *= (e->count > 0 ? e->count : 1); - } + motion_callback cb; + int num = get_key_repeat_and_motion_cb(&cb); + if (num == -1) + return err_invalid_key(buffer); + if (num == 0) + num = 1; ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); int new_line, new_softline; get_new_line_softline( @@ -1333,13 +1343,17 @@ move_to_eol(ledit_buffer *buffer, char *text, int len) { ledit_line *ll = ledit_buffer_get_line(buffer, new_line); PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, new_softline); int end_index = sl->start_index + sl->length; - if (e != NULL && e->motion_cb != NULL) { - e->motion_cb(buffer, new_line, end_index, KEY_MOTION_CHAR); + if (cb != NULL) { + cb(buffer, new_line, end_index, KEY_MOTION_CHAR); } else { buffer->cur_line = new_line; buffer->cur_index = end_index; if (buffer->common->mode == VISUAL) { - ledit_buffer_set_selection(buffer, buffer->sel.line1, buffer->sel.byte1, new_line, end_index); + ledit_buffer_set_selection( + buffer, + buffer->sel.line1, buffer->sel.byte1, + new_line, end_index + ); } else { /* FIXME: this is weird because the cursor is actually on the next soft line, but the alternative has too many weird effects @@ -1358,24 +1372,20 @@ static struct action name(ledit_buffer *buffer, char *text, int len) { \ (void)text; \ (void)len; \ - int num = 1; \ - struct key_stack_elem *e = pop_key_stack(); \ - if (e != NULL) { \ - if (e->key & KEY_NUMBER) { \ - num = e->count > 0 ? e->count : 1; \ - e = pop_key_stack(); \ - } \ - if (e != NULL) \ - num *= (e->count > 0 ? e->count : 1); \ - } \ + motion_callback cb; \ + int num = get_key_repeat_and_motion_cb(&cb); \ + if (num == -1) \ + return err_invalid_key(buffer); \ + if (num == 0) \ + num = 1; \ int new_line, new_index, new_real_index; \ func( \ buffer, \ buffer->cur_line, buffer->cur_index, num, \ &new_line, &new_index, &new_real_index \ ); \ - if (e != NULL && e->motion_cb != NULL) { \ - e->motion_cb(buffer, new_line, new_real_index, KEY_MOTION_CHAR); \ + if (cb != NULL) { \ + cb(buffer, new_line, new_real_index, KEY_MOTION_CHAR); \ } else { \ if (buffer->common->mode == VISUAL) { \ ledit_buffer_set_selection( \ @@ -1411,16 +1421,12 @@ GEN_WORD_MOVEMENT(prev_bigword, ledit_buffer_prev_bigword) static void move_cursor_left_right(ledit_buffer *buffer, int dir, int allow_illegal_index) { - int num = 1; - struct key_stack_elem *e = pop_key_stack(); - if (e != NULL) { - if (e->key & KEY_NUMBER) { - num = e->count > 0 ? e->count : 1; - e = pop_key_stack(); - } - if (e != NULL) - num *= (e->count > 0 ? e->count : 1); - } + motion_callback cb; + int num = get_key_repeat_and_motion_cb(&cb); + if (num == -1) + (void)err_invalid_key(buffer); + if (num == 0) + num = 1; /* FIXME: trailing */ int trailing = 0, tmp_index; @@ -1456,16 +1462,15 @@ move_cursor_left_right(ledit_buffer *buffer, int dir, int allow_illegal_index) { of the line because it's always covering a character */ if (new_index >= cur_line->len) { if (!allow_illegal_index && - buffer->common->mode == NORMAL && - (e == NULL || e->motion_cb == NULL)) { + buffer->common->mode == NORMAL && cb == NULL) { new_index = last_index; } else { /* FIXME: I guess this is unnecessary */ new_index = cur_line->len; } } - if (e != NULL && e->motion_cb != NULL) { - e->motion_cb(buffer, buffer->cur_line, new_index, KEY_MOTION_CHAR); + if (cb != NULL) { + cb(buffer, buffer->cur_line, new_index, KEY_MOTION_CHAR); } else { buffer->cur_index = new_index; if (buffer->common->mode == VISUAL) { @@ -1578,21 +1583,17 @@ enter_insert(ledit_buffer *buffer, char *text, int len) { return (struct action){ACTION_NONE, NULL}; } -/* FIXME: Check if previous key allows motion command - or is this checked automatically before? */ +/* FIXME: Check if previous key allows motion command - or should this be checked automatically before? */ static void move_cursor_up_down(ledit_buffer *buffer, int dir) { int new_line, new_softline; - int num = 1; - struct key_stack_elem *e = pop_key_stack(); - if (e != NULL) { - if (e->key & KEY_NUMBER) { - num = e->count > 0 ? e->count : 1; - e = pop_key_stack(); - } - if (e != NULL) - num *= (e->count > 0 ? e->count : 1); - } + motion_callback cb; + int num = get_key_repeat_and_motion_cb(&cb); + if (num == -1) + (void)err_invalid_key(buffer); + if (num == 0) + num = 1; num *= dir; get_new_line_softline( @@ -1602,9 +1603,9 @@ move_cursor_up_down(ledit_buffer *buffer, int dir) { ledit_line *cur_lline = ledit_buffer_get_line(buffer, buffer->cur_line); ledit_line *new_lline = ledit_buffer_get_line(buffer, new_line); - if (e != NULL && e->motion_cb != NULL) { + if (cb != NULL) { PangoLayoutLine *pl = pango_layout_get_line_readonly(new_lline->layout, new_softline); - e->motion_cb(buffer, new_line, pl->start_index, KEY_MOTION_LINE); + cb(buffer, new_line, pl->start_index, KEY_MOTION_LINE); } else { int lineno, x; ledit_pos_to_x_softline(cur_lline, buffer->cur_index, &x, &lineno); @@ -1647,10 +1648,13 @@ static struct action cursor_to_beginning(ledit_buffer *buffer, char *text, int len) { (void)text; (void)len; - struct key_stack_elem *e = pop_key_stack(); - /* FIXME: error when no callback? */ - if (e != NULL && e->motion_cb != NULL) { - e->motion_cb(buffer, buffer->cur_line, 0, KEY_MOTION_CHAR); + motion_callback cb; + int num = get_key_repeat_and_motion_cb(&cb); + if (num == -1) + return err_invalid_key(buffer); + /* FIXME: should anything be done with num? */ + if (cb != NULL) { + cb(buffer, buffer->cur_line, 0, KEY_MOTION_CHAR); } else { buffer->cur_index = 0; if (buffer->common->mode == VISUAL) { @@ -1888,6 +1892,10 @@ static struct action name##_cb(ledit_buffer *buffer, char *text, int len) { \ motion_callback cb = NULL; \ int num = get_key_repeat_and_motion_cb(&cb); \ + if (num == -1) \ + return err_invalid_key(buffer); \ + if (num == 0) \ + num = 1; \ ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line); \ int new_index = buffer->cur_index; \ for (int i = 0; i < num; i++) { \ diff --git a/keys_basic_config.h b/keys_basic_config.h @@ -41,7 +41,7 @@ static struct action push_6(ledit_buffer *buffer, char *text, int len); static struct action push_7(ledit_buffer *buffer, char *text, int len); static struct action push_8(ledit_buffer *buffer, char *text, int len); static struct action push_9(ledit_buffer *buffer, char *text, int len); -static struct action key_d(ledit_buffer *buffer, char *text, int len); +static struct action delete(ledit_buffer *buffer, char *text, int len); static struct action enter_visual(ledit_buffer *buffer, char *text, int len); static struct action switch_selection_end(ledit_buffer *buffer, char *text, int len); static struct action clipcopy(ledit_buffer *buffer, char *text, int len); @@ -125,7 +125,7 @@ static struct key keys_en[] = { {"9", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_9}, {"x", 0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &delete_chars_forwards}, {"X", 0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &delete_chars_backwards}, - {"d", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &key_d}, + {"d", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &delete}, {"y", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &yank}, {"Y", 0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &yank_lines}, {"c", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &change},