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