tImplement pasting (well, sort of) - 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 271d268ba17415be9808bb1da36389036b4eb95d | |
parent e5841801447358ed8f2f57e3dc0adc2873fb500e | |
Author: lumidify <[email protected]> | |
Date: Mon, 1 Nov 2021 13:17:15 +0100 | |
Implement pasting (well, sort of) | |
Diffstat: | |
M keys_basic.c | 121 ++++++++++++++++++++++++-----… | |
M keys_basic_config.h | 2 ++ | |
2 files changed, 97 insertions(+), 26 deletions(-) | |
--- | |
diff --git a/keys_basic.c b/keys_basic.c | |
t@@ -25,7 +25,8 @@ | |
#include "keys_command.h" | |
#include "keys_basic_config.h" | |
-/* this is supposed to be global for all buffers */ | |
+/* note: this is supposed to be global for all buffers */ | |
+int paste_buffer_line_based = 0; | |
static txtbuf *paste_buffer = NULL; | |
static int last_lines_scrolled = -1; | |
t@@ -91,7 +92,7 @@ static struct key_stack_elem *peek_key_stack(void); | |
static struct key_stack_elem *pop_key_stack(void); | |
void clear_key_stack(void); | |
-static void move_cursor_left_right(ledit_buffer *buffer, int dir); | |
+static void move_cursor_left_right(ledit_buffer *buffer, int dir, int allow_il… | |
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… | |
t@@ -99,6 +100,7 @@ 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 | |
); | |
+static void move_cursor_logically(ledit_buffer *buffer, int movement_dir, int … | |
/* FIXME: move to common */ | |
static void | |
t@@ -304,7 +306,7 @@ delete_range( | |
} | |
static void | |
-insert_text(ledit_buffer *buffer, int line, int index, char *text, int len, in… | |
+insert_text(ledit_buffer *buffer, int line, int index, char *text, int len, in… | |
if (len < 0) | |
len = strlen(text); | |
/* FIXME: this is kind of hacky... */ | |
t@@ -314,14 +316,22 @@ insert_text(ledit_buffer *buffer, int line, int index, c… | |
cur_range.byte1 = buffer->cur_index; | |
del_range.line1 = line; | |
del_range.byte1 = index; | |
+ int cur_line, cur_index; | |
ledit_buffer_insert_text_with_newlines( | |
buffer, line, index, text, len, | |
- &buffer->cur_line, &buffer->cur_index | |
+ &cur_line, &cur_index | |
); | |
- cur_range.line2 = buffer->cur_line; | |
- cur_range.byte2 = buffer->cur_index; | |
- del_range.line2 = buffer->cur_line; | |
- del_range.byte2 = buffer->cur_index; | |
+ /* this is mainly for pasting, where the new line and index | |
+ should not be at the end of the pasted text */ | |
+ if (new_line >= 0 && new_index >= 0) { | |
+ cur_range.line2 = buffer->cur_line = new_line; | |
+ cur_range.byte2 = buffer->cur_index = new_index; | |
+ } else { | |
+ cur_range.line2 = buffer->cur_line = cur_line; | |
+ cur_range.byte2 = buffer->cur_index = cur_index; | |
+ } | |
+ del_range.line2 = cur_line; | |
+ del_range.byte2 = cur_index; | |
ledit_push_undo_insert( | |
buffer->undo, &ins_buf, del_range, cur_range, start_group, buffer-… | |
); | |
t@@ -335,6 +345,7 @@ delete_selection(ledit_buffer *buffer) { | |
buffer->sel.line1, buffer->sel.byte1, | |
buffer->sel.line2, buffer->sel.byte2 | |
); | |
+ paste_buffer_line_based = 0; | |
/* FIXME: maybe just set this to the current cursor pos? */ | |
buffer->sel.line1 = buffer->sel.line2 = -1; | |
buffer->sel.byte1 = buffer->sel.byte2 = -1; | |
t@@ -629,8 +640,53 @@ key_d_cb(ledit_buffer *buffer, int line, int char_pos, en… | |
buffer->cur_line, buffer->cur_index, | |
line, char_pos | |
); | |
+ paste_buffer_line_based = line_based; | |
+ ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c… | |
+ finalize_repetition_stack(); | |
+} | |
+ | |
+/* FIXME: don't use the pango functions directly so normalize_and_set_pango_te… | |
+ always called properly */ | |
+static struct action | |
+paste_normal(ledit_buffer *buffer, char *text, int len) { | |
+ (void)text; | |
+ (void)len; | |
+ if (!paste_buffer) { | |
+ ledit_window_show_message(buffer->window, "Nothing to paste", … | |
+ discard_repetition_stack(); | |
+ return (struct action){ACTION_NONE, NULL}; | |
+ } | |
+ if (paste_buffer_line_based) { | |
+ int x, softline; | |
+ ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); | |
+ ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_lin… | |
+ pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0,… | |
+ PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layou… | |
+ insert_text( | |
+ buffer, buffer->cur_line, sl->start_index + sl->length, | |
+ "\n", -1, buffer->cur_line, buffer->cur_index, 1 | |
+ ); | |
+ /* remove trailing newline if it exists - this may be hacky */ | |
+ int text_len = paste_buffer->len; | |
+ if (paste_buffer->text[paste_buffer->len-1] == '\n') { | |
+ text_len--; | |
+ paste_buffer->text[paste_buffer->len-1] = '\0'; | |
+ } | |
+ insert_text( | |
+ buffer, buffer->cur_line + 1, 0, | |
+ paste_buffer->text, text_len, buffer->cur_line + 1, 0, 0 | |
+ ); | |
+ } else { | |
+ /* must allow illegal index so text can be pasted at end of li… | |
+ move_cursor_logically(buffer, 1, 1); | |
+ insert_text( | |
+ buffer, buffer->cur_line, buffer->cur_index, | |
+ paste_buffer->text, paste_buffer->len, buffer->cur_line, b… | |
+ ); | |
+ } | |
ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c… | |
finalize_repetition_stack(); | |
+ return (struct action){ACTION_NONE, NULL}; | |
} | |
static struct action | |
t@@ -794,7 +850,7 @@ delete_key(ledit_buffer *buffer, char *text, int len) { | |
} | |
static void | |
-move_cursor_left_right(ledit_buffer *buffer, int dir) { | |
+move_cursor_left_right(ledit_buffer *buffer, int dir, int allow_illegal_index)… | |
int num = 1; | |
struct key_stack_elem *e = pop_key_stack(); | |
if (e != NULL) { | |
t@@ -839,7 +895,9 @@ move_cursor_left_right(ledit_buffer *buffer, int dir) { | |
/* when in normal mode, the cursor cannot be at the very end | |
of the line because it's always covering a character */ | |
if (new_index >= cur_line->len) { | |
- if (buffer->common->mode == NORMAL && (e == NULL || e->motion_… | |
+ if (!allow_illegal_index && | |
+ buffer->common->mode == NORMAL && | |
+ (e == NULL || e->motion_cb == NULL)) { | |
new_index = last_index; | |
} else { | |
/* FIXME: I guess this is unnecessary */ | |
t@@ -868,7 +926,7 @@ static struct action | |
cursor_left(ledit_buffer *buffer, char *text, int len) { | |
(void)text; | |
(void)len; | |
- move_cursor_left_right(buffer, -1); | |
+ move_cursor_left_right(buffer, -1, 0); | |
return (struct action){ACTION_NONE, NULL}; | |
} | |
t@@ -876,7 +934,7 @@ static struct action | |
cursor_right(ledit_buffer *buffer, char *text, int len) { | |
(void)text; | |
(void)len; | |
- move_cursor_left_right(buffer, 1); | |
+ move_cursor_left_right(buffer, 1, 0); | |
return (struct action){ACTION_NONE, NULL}; | |
} | |
t@@ -887,7 +945,7 @@ return_key(ledit_buffer *buffer, char *text, int len) { | |
int start_group = 1; | |
if (delete_selection(buffer)) | |
start_group = 0; | |
- insert_text(buffer, buffer->cur_line, buffer->cur_index, "\n", -1, sta… | |
+ insert_text(buffer, buffer->cur_line, buffer->cur_index, "\n", -1, -1,… | |
/* FIXME: these aren't needed, right? This only works in insert mode | |
* anyways, so there's nothing to wipe */ | |
/* ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); | |
t@@ -954,6 +1012,28 @@ pango_layout_get_direction(PangoLayout *layout, int inde… | |
} | |
#endif | |
+static void | |
+move_cursor_logically(ledit_buffer *buffer, int movement_dir, int allow_illega… | |
+ PangoDirection dir = PANGO_DIRECTION_RTL; | |
+ int tmp_index = buffer->cur_index; | |
+ ledit_line *cur_line = ledit_buffer_get_line(buffer, buffer->cur_line); | |
+ if (buffer->cur_index >= cur_line->len) | |
+ tmp_index--; | |
+ if (tmp_index >= 0) | |
+ dir = pango_layout_get_direction(cur_line->layout, tmp_index); | |
+ if (dir == PANGO_DIRECTION_RTL || dir == PANGO_DIRECTION_WEAK_RTL) { | |
+ if (movement_dir < 0) | |
+ move_cursor_left_right(buffer, 1, allow_illegal_index); | |
+ else | |
+ move_cursor_left_right(buffer, -1, allow_illegal_index… | |
+ } else { | |
+ if (movement_dir < 0) | |
+ move_cursor_left_right(buffer, -1, allow_illegal_index… | |
+ else | |
+ move_cursor_left_right(buffer, 1, allow_illegal_index); | |
+ } | |
+} | |
+ | |
static struct action | |
escape_key(ledit_buffer *buffer, char *text, int len) { | |
(void)text; | |
t@@ -968,18 +1048,7 @@ escape_key(ledit_buffer *buffer, char *text, int len) { | |
} else { | |
ledit_buffer_set_mode(buffer, NORMAL); | |
clear_key_stack(); | |
- PangoDirection dir = PANGO_DIRECTION_RTL; | |
- int tmp_index = buffer->cur_index; | |
- ledit_line *cur_line = ledit_buffer_get_line(buffer, buffer->c… | |
- if (buffer->cur_index >= cur_line->len) | |
- tmp_index--; | |
- if (tmp_index >= 0) | |
- dir = pango_layout_get_direction(cur_line->layout, tmp… | |
- if (dir == PANGO_DIRECTION_RTL || dir == PANGO_DIRECTION_WEAK_… | |
- cursor_right(buffer, NULL, 0); | |
- } else { | |
- cursor_left(buffer, NULL, 0); | |
- } | |
+ move_cursor_logically(buffer, -1, 0); | |
if (buffer->sel.line1 != buffer->sel.line2) { | |
int min = buffer->sel.line1 < buffer->sel.line2 ? buff… | |
int max = buffer->sel.line1 > buffer->sel.line2 ? buff… | |
t@@ -1217,7 +1286,7 @@ redo(ledit_buffer *buffer, char *text, int len) { | |
static struct action | |
insert_mode_insert_text(ledit_buffer *buffer, char *text, int len) { | |
delete_selection(buffer); | |
- insert_text(buffer, buffer->cur_line, buffer->cur_index, text, len, 1); | |
+ insert_text(buffer, buffer->cur_line, buffer->cur_index, text, len, -1… | |
return (struct action){ACTION_NONE, NULL}; | |
} | |
diff --git a/keys_basic_config.h b/keys_basic_config.h | |
t@@ -64,6 +64,7 @@ static struct action scroll_with_cursor_down(ledit_buffer *b… | |
static struct action scroll_lines_up(ledit_buffer *buffer, char *text, int len… | |
static struct action scroll_lines_down(ledit_buffer *buffer, char *text, int l… | |
static struct action move_to_line(ledit_buffer *buffer, char *text, int len); | |
+static struct action paste_normal(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@@ -121,6 +122,7 @@ static struct key keys_en[] = { | |
{"d", ControlMask, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &scroll_lin… | |
{"u", ControlMask, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &scroll_lin… | |
{"G", 0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &move_to_line}, | |
+ {"p", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &paste_normal}, | |
{"", 0, 0, INSERT, KEY_ANY, KEY_ANY, &insert_mode_insert_text} | |
}; | |