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:
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},