tImplement J, I, and ^ - 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 61c47698d180e2e9e81df98c5ac9d7304594a95b | |
parent c5fa1b6794a0e0dc9346571a34c85d40fdbb01b5 | |
Author: lumidify <[email protected]> | |
Date: Wed, 10 Nov 2021 23:35:13 +0100 | |
Implement J, I, and ^ | |
Diffstat: | |
M buffer.c | 15 +++++++++++++++ | |
M buffer.h | 1 + | |
M keys_basic.c | 108 +++++++++++++++++++++++++++++… | |
M keys_basic_config.h | 6 ++++++ | |
4 files changed, 126 insertions(+), 4 deletions(-) | |
--- | |
diff --git a/buffer.c b/buffer.c | |
t@@ -1123,6 +1123,21 @@ line_next_bigword(ledit_line *line, int byte, int char_… | |
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 uni… | |
#define GEN_NEXT_WORD(name, func) … | |
diff --git a/buffer.h b/buffer.h | |
t@@ -158,3 +158,4 @@ void ledit_buffer_scroll_to_pos_top(ledit_buffer *buffer, … | |
void ledit_buffer_scroll_to_pos_bottom(ledit_buffer *buffer, int line, int byt… | |
/* FIXME: just make generic sort range */ | |
void ledit_buffer_sort_selection(int *line1, int *byte1, int *line2, int *byte… | |
+int ledit_line_next_non_whitespace(ledit_line *line, int byte); | |
diff --git a/keys_basic.c b/keys_basic.c | |
t@@ -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(); | |
t@@ -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… | |
+ 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, &… | |
+ 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, &… | |
+ 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, &… | |
+ 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 | |
t@@ -90,6 +90,9 @@ static struct action delete_chars_backwards(ledit_buffer *bu… | |
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, … | |
+static struct action join_lines(ledit_buffer *buffer, char *text, int len); | |
+static struct action insert_at_beginning(ledit_buffer *buffer, char *text, int… | |
/* FIXME: maybe sort these and use binary search | |
-> but that would mess with the catch-all keys */ | |
t@@ -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}, | |
t@@ -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_cha… | |
{"T", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &find_next_cha… | |
{"f", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBERALLOWED, &find_char_for… |