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 2e039562f045bbcb2a7b29bd39031f0597953460
parent 42118fa8413ad5bd8be9d6d9b54b3b233a68df5f
Author: lumidify <nobody@lumidify.org>
Date:   Wed, 10 Nov 2021 11:27:29 +0100

Implement yanking

Diffstat:
Mbuffer.c | 10+++++-----
Mbuffer.h | 2++
Mkeys_basic.c | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mkeys_basic_config.h | 2++
4 files changed, 110 insertions(+), 22 deletions(-)

diff --git a/buffer.c b/buffer.c @@ -43,7 +43,6 @@ static void init_line(ledit_buffer *buffer, ledit_line *line); static void delete_line_section_base(ledit_buffer *buffer, int line, int start, int length); static void normalize_and_set_pango_text(ledit_line *line); static void swap(int *a, int *b); -static void sort_selection(int *line1, int *byte1, int *line2, int *byte2); static void copy_selection_to_x_primary(ledit_buffer *buffer, int line1, int byte1, int line2, int byte2); void @@ -704,6 +703,7 @@ ledit_buffer_delete_line_entry_base(ledit_buffer *buffer, int index) { /* FIXME: use some sort of gap buffer (that would make this function slightly more useful...) */ +/* FIXME: error checking, assert? */ ledit_line * ledit_buffer_get_line(ledit_buffer *buffer, int index) { return &buffer->lines[index]; @@ -1886,8 +1886,8 @@ swap(int *a, int *b) { *b = tmp; } -static void -sort_selection(int *line1, int *byte1, int *line2, int *byte2) { +void +ledit_buffer_sort_selection(int *line1, int *byte1, int *line2, int *byte2) { if (*line1 > *line2) { swap(line1, line2); swap(byte1, byte2); @@ -1921,8 +1921,8 @@ ledit_buffer_set_selection(ledit_buffer *buffer, int line1, int byte1, int line2 if (buffer->sel.line1 >= 0) { int l1_new = line1, l2_new = line2; int b1_new = byte1, b2_new = byte2; - sort_selection(&buffer->sel.line1, &buffer->sel.byte1, &buffer->sel.line2, &buffer->sel.byte2); - sort_selection(&l1_new, &b1_new, &l2_new, &b2_new); + ledit_buffer_sort_selection(&buffer->sel.line1, &buffer->sel.byte1, &buffer->sel.line2, &buffer->sel.byte2); + ledit_buffer_sort_selection(&l1_new, &b1_new, &l2_new, &b2_new); if (buffer->sel.line1 > l2_new || buffer->sel.line2 < l1_new) { for (int i = buffer->sel.line1; i <= buffer->sel.line2; i++) { ledit_buffer_wipe_line_cursor_attrs(buffer, i); diff --git a/buffer.h b/buffer.h @@ -156,3 +156,5 @@ void ledit_buffer_resize_textview(ledit_buffer *buffer); void ledit_buffer_scroll(ledit_buffer *buffer, long new_offset); 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); diff --git a/keys_basic.c b/keys_basic.c @@ -9,6 +9,7 @@ them reliably yet */ #include <stdio.h> #include <stdlib.h> +#include <assert.h> #include <X11/Xlib.h> #include <X11/Xutil.h> @@ -111,6 +112,7 @@ static void move_cursor_left_right(ledit_buffer *buffer, int dir, int allow_ille 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 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, int movement, int *new_line_ret, int *new_softline_ret @@ -177,6 +179,24 @@ clear_key_stack(void) { key_stack.len = 0; } +/* FIXME: error if no motion cb and not 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; + e = pop_key_stack(); + } + if (e != NULL) + num *= (e->count > 0 ? e->count : 1); + } + if (cb_ret != NULL && e != NULL && e->motion_cb != NULL) + *cb_ret = e->motion_cb; + return num; +} + static struct repetition_stack_elem * push_repetition_stack(void) { struct repetition_stack_elem *e; @@ -867,6 +887,87 @@ change_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type) { } static struct action +yank(ledit_buffer *buffer, char *text, int len) { + (void)text; + (void)len; + if (!paste_buffer) + paste_buffer = txtbuf_new(); + if (buffer->common->mode == VISUAL) { + ledit_buffer_sort_selection( + &buffer->sel.line1, &buffer->sel.byte1, &buffer->sel.line2, &buffer->sel.byte2 + ); + ledit_buffer_copy_text_to_txtbuf( + buffer, paste_buffer, + buffer->sel.line1, buffer->sel.byte1, buffer->sel.line2, buffer->sel.byte2 + ); + paste_buffer_line_based = 0; + buffer->cur_line = buffer->sel.line1; + buffer->cur_index = buffer->sel.byte1; + ledit_buffer_set_selection(buffer, -1, -1, -1, -1); + 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 { + motion_callback cb = NULL; + int num = get_key_repeat_and_motion_cb(&cb); + if (cb == &yank_cb) { + int new_line, new_softline; + get_new_line_softline( + buffer, buffer->cur_line, buffer->cur_index, + num - 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) { + struct key_stack_elem *e = push_key_stack(); + e->key = KEY_MOTION; + e->count = num; + e->motion_cb = &yank_cb; + } else { + clear_key_stack(); + } + } + discard_repetition_stack(); + return (struct action){ACTION_NONE, NULL}; +} + +static void +yank_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type) { + int line_based = type == KEY_MOTION_LINE ? 1 : 0; + int l1 = buffer->cur_line, l2 = line, b1 = buffer->cur_index, b2 = char_pos; + if (!paste_buffer) + paste_buffer = txtbuf_new(); + if (l2 < l1 || (l1 == l2 && b2 < b1)) { + swap(&l1, &l2); + swap(&b1, &b2); + } + if (line_based) { + int x, sl1, sl2; + ledit_line *ll1 = ledit_buffer_get_line(buffer, l1); + pango_layout_index_to_line_x(ll1->layout, b1, 0, &sl1, &x); + PangoLayoutLine *pl1 = pango_layout_get_line_readonly(ll1->layout, sl1); + ledit_line *ll2 = ledit_buffer_get_line(buffer, l2); + pango_layout_index_to_line_x(ll2->layout, b2, 0, &sl2, &x); + PangoLayoutLine *pl2 = pango_layout_get_line_readonly(ll2->layout, sl2); + assert(pl1 != NULL && pl2 != NULL); + ledit_buffer_copy_text_to_txtbuf( + buffer, paste_buffer, l1, pl1->start_index, l2, pl2->start_index + pl2->length + ); + } else { + ledit_buffer_copy_text_to_txtbuf( + buffer, paste_buffer, l1, b1, l2, b2 + ); + } + paste_buffer_line_based = line_based; + discard_repetition_stack(); +} + +static struct action key_d(ledit_buffer *buffer, char *text, int len) { (void)text; (void)len; @@ -1700,23 +1801,6 @@ clippaste(ledit_buffer *buffer, char *text, int len) { return (struct action){ACTION_NONE, NULL}; } -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; - e = pop_key_stack(); - } - if (e != NULL) - num *= (e->count > 0 ? e->count : 1); - } - if (cb_ret != NULL && e != NULL && e->motion_cb != NULL) - *cb_ret = e->motion_cb; - return num; -} - /* FIXME: make sure the found position is valid cursor position? */ static int search_str_backwards(char *haystack, int hlen, char *needle, int nlen, int start_index) { diff --git a/keys_basic_config.h b/keys_basic_config.h @@ -87,6 +87,7 @@ static struct action change_to_eol(ledit_buffer *buffer, char *text, int len); static struct action delete_to_eol(ledit_buffer *buffer, char *text, int len); static struct action delete_chars_forwards(ledit_buffer *buffer, char *text, int len); static struct action delete_chars_backwards(ledit_buffer *buffer, char *text, int len); +static struct action yank(ledit_buffer *buffer, char *text, int len); /* FIXME: maybe sort these and use binary search -> but that would mess with the catch-all keys */ @@ -123,6 +124,7 @@ static struct key keys_en[] = { {"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}, + {"y", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &yank}, {"c", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &change}, {"v", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &enter_visual}, {"o", 0, 0, VISUAL, KEY_ANY, KEY_ANY, &switch_selection_end},