tImplement yanking - 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 <[email protected]> | |
Date: Wed, 10 Nov 2021 11:27:29 +0100 | |
Implement yanking | |
Diffstat: | |
M buffer.c | 10 +++++----- | |
M buffer.h | 2 ++ | |
M keys_basic.c | 118 ++++++++++++++++++++++++++---… | |
M keys_basic_config.h | 2 ++ | |
4 files changed, 110 insertions(+), 22 deletions(-) | |
--- | |
diff --git a/buffer.c b/buffer.c | |
t@@ -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… | |
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 b… | |
void | |
t@@ -704,6 +703,7 @@ ledit_buffer_delete_line_entry_base(ledit_buffer *buffer, … | |
/* 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]; | |
t@@ -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); | |
t@@ -1921,8 +1921,8 @@ ledit_buffer_set_selection(ledit_buffer *buffer, int lin… | |
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… | |
- sort_selection(&l1_new, &b1_new, &l2_new, &b2_new); | |
+ ledit_buffer_sort_selection(&buffer->sel.line1, &buffer->sel.b… | |
+ 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… | |
ledit_buffer_wipe_line_cursor_attrs(buffer, i); | |
diff --git a/buffer.h b/buffer.h | |
t@@ -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 byt… | |
+/* FIXME: just make generic sort range */ | |
+void ledit_buffer_sort_selection(int *line1, int *byte1, int *line2, int *byte… | |
diff --git a/keys_basic.c b/keys_basic.c | |
t@@ -9,6 +9,7 @@ | |
them reliably yet */ | |
#include <stdio.h> | |
#include <stdlib.h> | |
+#include <assert.h> | |
#include <X11/Xlib.h> | |
#include <X11/Xutil.h> | |
t@@ -111,6 +112,7 @@ static void move_cursor_left_right(ledit_buffer *buffer, i… | |
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_ty… | |
+static void yank_cb(ledit_buffer *buffer, int line, int char_pos, enum key_typ… | |
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 | |
t@@ -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; | |
t@@ -867,6 +887,87 @@ change_cb(ledit_buffer *buffer, int line, int char_pos, e… | |
} | |
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… | |
+ ); | |
+ ledit_buffer_copy_text_to_txtbuf( | |
+ buffer, paste_buffer, | |
+ buffer->sel.line1, buffer->sel.byte1, buffer->sel.line2, b… | |
+ ); | |
+ 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, b… | |
+ 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_lin… | |
+ PangoLayoutLine *pl = pango_layout_get_line_readonly(l… | |
+ 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 = cha… | |
+ 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->lay… | |
+ 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->lay… | |
+ assert(pl1 != NULL && pl2 != NULL); | |
+ ledit_buffer_copy_text_to_txtbuf( | |
+ buffer, paste_buffer, l1, pl1->start_index, l2, pl2->start… | |
+ ); | |
+ } 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; | |
t@@ -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 sta… | |
diff --git a/keys_basic_config.h b/keys_basic_config.h | |
t@@ -87,6 +87,7 @@ static struct action change_to_eol(ledit_buffer *buffer, cha… | |
static struct action delete_to_eol(ledit_buffer *buffer, char *text, int len); | |
static struct action delete_chars_forwards(ledit_buffer *buffer, char *text, i… | |
static struct action delete_chars_backwards(ledit_buffer *buffer, char *text, … | |
+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 */ | |
t@@ -123,6 +124,7 @@ static struct key keys_en[] = { | |
{"x", 0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &delete_chars_forward… | |
{"X", 0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &delete_chars_backwar… | |
{"d", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &ke… | |
+ {"y", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &ya… | |
{"c", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &ch… | |
{"v", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &enter_visual}, | |
{"o", 0, 0, VISUAL, KEY_ANY, KEY_ANY, &switch_selection_end}, |