commit 61c47698d180e2e9e81df98c5ac9d7304594a95b
parent c5fa1b6794a0e0dc9346571a34c85d40fdbb01b5
Author: lumidify <nobody@lumidify.org>
Date: Wed, 10 Nov 2021 23:35:13 +0100
Implement J, I, and ^
Diffstat:
4 files changed, 126 insertions(+), 4 deletions(-)
diff --git a/buffer.c b/buffer.c
@@ -1123,6 +1123,21 @@ line_next_bigword(ledit_line *line, int byte, int char_index, int wrapped_line,
return -1;
}
+int
+ledit_line_next_non_whitespace(ledit_line *line, int byte) {
+ int c, nattrs;
+ c = line_byte_to_char(line, byte);
+ int cur_byte = byte;
+ const PangoLogAttr *attrs =
+ pango_layout_get_log_attrs_readonly(line->layout, &nattrs);
+ for (; c < nattrs; c++) {
+ if (!attrs[c].is_white)
+ return cur_byte;
+ cur_byte = ledit_line_next_utf8(line, cur_byte);
+ }
+ return line->len;
+}
+
/* FIXME: document that word and bigword are a bit weird because word uses unicode semantics */
#define GEN_NEXT_WORD(name, func) \
diff --git a/buffer.h b/buffer.h
@@ -158,3 +158,4 @@ void ledit_buffer_scroll_to_pos_top(ledit_buffer *buffer, int line, int byte);
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);
diff --git a/keys_basic.c b/keys_basic.c
@@ -387,7 +387,8 @@ delete_range(
ledit_buffer *buffer,
int line_based, int selected,
int line_index1, int byte_index1,
- int line_index2, int byte_index2, int copy_to_buffer) {
+ int line_index2, int byte_index2,
+ int copy_to_buffer) {
(void)selected; /* FIXME */
if (copy_to_buffer && !paste_buffer)
paste_buffer = txtbuf_new();
@@ -1645,18 +1646,117 @@ cursor_up(ledit_buffer *buffer, char *text, int len) {
}
static struct action
+join_lines(ledit_buffer *buffer, char *text, int len) {
+ (void)text;
+ (void)len;
+ int num = get_key_repeat();
+ if (num == -1)
+ return err_invalid_key(buffer);
+ if (num == 0)
+ num = 1;
+ int start_group = 1;
+ ledit_line *ll1, *ll2;
+ int cur_line = buffer->cur_line;
+ /* FIXME: have a general tmp buf for everyone to use */
+ txtbuf *buf = txtbuf_new();
+ int oldlen;
+ ledit_range cur_range, del_range;
+ cur_range.line1 = cur_range.line2 = cur_line;
+ for (int i = 0; i < num; i++) {
+ if (cur_line == buffer->lines_num - 1)
+ break;
+ /* getting cur line again should be unnecessary, but
+ I'll just leave it in case I change the way lines
+ are stored later */
+ ll1 = ledit_buffer_get_line(buffer, cur_line);
+ oldlen = ll1->len;
+ ll2 = ledit_buffer_get_line(buffer, cur_line + 1);
+ /* FIXME: truncate whitespace to one space */
+ ledit_buffer_delete_range(
+ buffer, 0,
+ cur_line, ll1->len, cur_line + 1, 0,
+ NULL, NULL, &del_range, buf
+ );
+ cur_range.byte1 = buffer->cur_index;
+ cur_range.byte2 = buffer->cur_index =
+ ledit_buffer_get_legal_normal_pos(buffer, buffer->cur_line, oldlen);
+ ledit_push_undo_delete(
+ buffer->undo, buf, del_range, cur_range,
+ start_group, buffer->common->mode
+ );
+ start_group = 0;
+ }
+ ledit_buffer_set_line_cursor_attrs(
+ buffer, buffer->cur_line, buffer->cur_index
+ );
+ txtbuf_destroy(buf);
+ finalize_repetition_stack();
+ return (struct action){ACTION_NONE, NULL};
+}
+
+static struct action
+insert_at_beginning(ledit_buffer *buffer, char *text, int len) {
+ if (!key_stack_empty())
+ return err_invalid_key(buffer);
+ enter_insert(buffer, text, len);
+ int x, sli;
+ 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 *pl = pango_layout_get_line_readonly(ll->layout, sli);
+ push_undo_empty_insert(buffer, buffer->cur_line, buffer->cur_index, 1);
+ buffer->cur_index = pl->start_index;
+ ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ return (struct action){ACTION_NONE, NULL};
+}
+
+static struct action
+cursor_to_first_non_ws(ledit_buffer *buffer, char *text, int len) {
+ (void)text;
+ (void)len;
+ int x, sli;
+ motion_callback cb;
+ int num = get_key_repeat_and_motion_cb(&cb);
+ if (num != 0)
+ return err_invalid_key(buffer);
+ 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 *pl = pango_layout_get_line_readonly(ll->layout, sli);
+ int new_index = ledit_line_next_non_whitespace(ll, pl->start_index);
+ /* next non-whitespace might be on next softline */
+ if (new_index >= pl->start_index + pl->length) {
+ new_index = ledit_buffer_prev_cursor_pos(
+ buffer, buffer->cur_line, pl->start_index + pl->length, 1
+ );
+ }
+ if (cb != NULL) {
+ cb(buffer, buffer->cur_line, new_index, KEY_MOTION_CHAR);
+ } else {
+ buffer->cur_index = new_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
cursor_to_beginning(ledit_buffer *buffer, char *text, int len) {
(void)text;
(void)len;
+ int x, sli;
motion_callback cb;
int num = get_key_repeat_and_motion_cb(&cb);
- if (num == -1)
+ if (num != 0)
return err_invalid_key(buffer);
/* FIXME: should anything be done with num? */
+ 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 *pl = pango_layout_get_line_readonly(ll->layout, sli);
if (cb != NULL) {
- cb(buffer, buffer->cur_line, 0, KEY_MOTION_CHAR);
+ cb(buffer, buffer->cur_line, pl->start_index, KEY_MOTION_CHAR);
} else {
- buffer->cur_index = 0;
+ buffer->cur_index = pl->start_index;
if (buffer->common->mode == VISUAL) {
ledit_buffer_set_selection(
buffer,
diff --git a/keys_basic_config.h b/keys_basic_config.h
@@ -90,6 +90,9 @@ static struct action delete_chars_backwards(ledit_buffer *buffer, char *text, in
static struct action yank(ledit_buffer *buffer, char *text, int len);
static struct action yank_lines(ledit_buffer *buffer, char *text, int len);
static struct action replace(ledit_buffer *buffer, char *text, int len);
+static struct action cursor_to_first_non_ws(ledit_buffer *buffer, char *text, int len);
+static struct action join_lines(ledit_buffer *buffer, char *text, int len);
+static struct action insert_at_beginning(ledit_buffer *buffer, char *text, int len);
/* FIXME: maybe sort these and use binary search
-> but that would mess with the catch-all keys */
@@ -158,6 +161,8 @@ static struct key keys_en[] = {
{"b", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &prev_word},
{"B", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &prev_bigword},
{"G", 0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &move_to_line},
+ {"J", 0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &join_lines},
+ {"I", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &insert_at_beginning},
{"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},
@@ -169,6 +174,7 @@ static struct key keys_en[] = {
{"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},
+ {"^", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &cursor_to_first_non_ws},
{"t", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &find_next_char_forwards},
{"T", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &find_next_char_backwards},
{"f", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &find_char_forwards},