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 <nobody@lumidify.org>
Date:   Wed, 10 Nov 2021 23:35:13 +0100

Implement J, I, and ^

Diffstat:
Mbuffer.c | 15+++++++++++++++
Mbuffer.h | 1+
Mkeys_basic.c | 108++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mkeys_basic_config.h | 6++++++
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},