tClean up commands with motion callback - 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 <[email protected]> | |
Date: Wed, 10 Nov 2021 21:43:56 +0100 | |
Clean up commands with motion callback | |
Diffstat: | |
M keys_basic.c | 308 ++++++++++++++++-------------… | |
M keys_basic_config.h | 4 ++-- | |
2 files changed, 160 insertions(+), 152 deletions(-) | |
--- | |
diff --git a/keys_basic.c b/keys_basic.c | |
t@@ -111,7 +111,7 @@ void clear_key_stack(void); | |
static void move_cursor_left_right(ledit_buffer *buffer, int dir, int allow_il… | |
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_ty… | |
+static void delete_cb(ledit_buffer *buffer, int line, int char_pos, enum key_t… | |
static void yank_cb(ledit_buffer *buffer, int line, int char_pos, enum key_typ… | |
static void get_new_line_softline( | |
ledit_buffer *buffer, int cur_line, int cur_index, | |
t@@ -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; | |
} | |
t@@ -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; | |
t@@ -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; | |
t@@ -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, b… | |
+ discard_repetition_stack(); | |
} | |
- discard_repetition_stack(); | |
return (struct action){ACTION_NONE, NULL}; | |
} | |
t@@ -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 != buf… | |
+ 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_inde… | |
- lines - 1, &new_line, &new_softline | |
- ); | |
- ledit_line *ll = ledit_buffer_get_line(buffer,… | |
- PangoLayoutLine *pl = pango_layout_get_line_re… | |
- e->motion_cb(buffer, new_line, pl->start_index… | |
- 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_lin… | |
+ PangoLayoutLine *pl = pango_layout_get_line_readonly(l… | |
+ 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; | |
t@@ -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( | |
t@@ -1000,45 +1021,38 @@ yank_cb(ledit_buffer *buffer, int line, int char_pos, … | |
} | |
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, … | |
ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, b… | |
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 ma… | |
- 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_inde… | |
- lines - 1, &new_line, &new_softline | |
- ); | |
- ledit_line *ll = ledit_buffer_get_line(buffer,… | |
- PangoLayoutLine *pl = pango_layout_get_line_re… | |
- e->motion_cb(buffer, new_line, pl->start_index… | |
- 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 b… | |
+ 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_lin… | |
+ PangoLayoutLine *pl = pango_layout_get_line_readonly(l… | |
+ 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}; | |
t@@ -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, | |
t@@ -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( | |
t@@ -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_s… | |
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, … | |
+ 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… | |
next soft line, but the alternative has too many we… | |
t@@ -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( … | |
t@@ -1411,16 +1421,12 @@ GEN_WORD_MOVEMENT(prev_bigword, ledit_buffer_prev_bigw… | |
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; | |
t@@ -1456,16 +1462,15 @@ move_cursor_left_right(ledit_buffer *buffer, int dir, … | |
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_C… | |
+ if (cb != NULL) { | |
+ cb(buffer, buffer->cur_line, new_index, KEY_MOTION_CHAR); | |
} else { | |
buffer->cur_index = new_index; | |
if (buffer->common->mode == VISUAL) { | |
t@@ -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 aut… | |
+/* FIXME: Check if previous key allows motion command - or should this be chec… | |
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( | |
t@@ -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… | |
- e->motion_cb(buffer, new_line, pl->start_index, KEY_MOTION_LIN… | |
+ 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, &lin… | |
t@@ -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) { | |
t@@ -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 | |
t@@ -41,7 +41,7 @@ static struct action push_6(ledit_buffer *buffer, char *text… | |
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, in… | |
static struct action clipcopy(ledit_buffer *buffer, char *text, int len); | |
t@@ -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_forward… | |
{"X", 0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &delete_chars_backwar… | |
- {"d", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &ke… | |
+ {"d", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &de… | |
{"y", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &ya… | |
{"Y", 0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &yank_lines}, | |
{"c", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &ch… |