From 9f9c1e11e2cbdb8e70a11ff2c5840e02880255ac Mon Sep 17 00:00:00 2001 From: Piotr Kocia Date: Sat, 5 Apr 2025 00:28:59 +0200 Subject: [PATCH] implement paste --- config.c | 7 ++ ime.c | 5 +- key-binding.h | 2 + vimode.c | 226 ++++++++++++++++++++++++++------------------------ 4 files changed, 130 insertions(+), 110 deletions(-) diff --git a/config.c b/config.c index 5096d706..4ce619e4 100644 --- a/config.c +++ b/config.c @@ -201,6 +201,8 @@ static const char *const vimode_search_binding_action_map[] = { [BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_CHAR] = "vimode-search-delete-prev", [BIND_ACTION_VIMODE_SEARCH_LEFT] = "vimode-search-left", [BIND_ACTION_VIMODE_SEARCH_RIGHT] = "vimode-search-right", + [BIND_ACTION_VIMODE_SEARCH_CLIPBOARD_PASTE] = "vimode-search-clipboard-paste", + [BIND_ACTION_VIMODE_SEARCH_PRIMARY_PASTE] = "vimode-search-primary-paste", }; static const char *const url_binding_action_map[] = { @@ -3339,6 +3341,11 @@ add_default_vimode_search_bindings(struct config *conf) {BIND_ACTION_VIMODE_SEARCH_LEFT, m("none"), {{XKB_KEY_leftarrow}}}, {BIND_ACTION_VIMODE_SEARCH_RIGHT, m(XKB_MOD_NAME_CTRL), {{XKB_KEY_l}}}, {BIND_ACTION_VIMODE_SEARCH_RIGHT, m("none"), {{XKB_KEY_rightarrow}}}, + {BIND_ACTION_VIMODE_SEARCH_CLIPBOARD_PASTE, m(XKB_MOD_NAME_CTRL), {{XKB_KEY_p}}}, + {BIND_ACTION_VIMODE_SEARCH_CLIPBOARD_PASTE, m(XKB_MOD_NAME_CTRL), {{XKB_KEY_v}}}, + {BIND_ACTION_VIMODE_SEARCH_CLIPBOARD_PASTE, m(XKB_MOD_NAME_CTRL "+" XKB_MOD_NAME_SHIFT), {{XKB_KEY_v}}}, + {BIND_ACTION_VIMODE_SEARCH_CLIPBOARD_PASTE, m("none"), {{XKB_KEY_XF86Paste}}}, + {BIND_ACTION_VIMODE_SEARCH_PRIMARY_PASTE, m(XKB_MOD_NAME_SHIFT), {{XKB_KEY_Insert}}}, }; conf->bindings.vimode_search.count = ALEN(bindings); diff --git a/ime.c b/ime.c index 56711254..61825d3c 100644 --- a/ime.c +++ b/ime.c @@ -198,10 +198,9 @@ done(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, size_t len = strlen(text); if (term != NULL) { - if (term->vimode.searching) { + if (term->vimode.searching) vimode_search_add_chars(term, text, len); - render_refresh_vimode_search_box(term); - } else + else term_to_slave(term, text, len); } ime_reset_pending_commit(seat); diff --git a/key-binding.h b/key-binding.h index 0cf731fe..d2838342 100644 --- a/key-binding.h +++ b/key-binding.h @@ -105,6 +105,8 @@ enum bind_action_vimode_search { BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_CHAR, BIND_ACTION_VIMODE_SEARCH_LEFT, BIND_ACTION_VIMODE_SEARCH_RIGHT, + BIND_ACTION_VIMODE_SEARCH_CLIPBOARD_PASTE, + BIND_ACTION_VIMODE_SEARCH_PRIMARY_PASTE, BIND_ACTION_VIMODE_SEARCH_COUNT, }; diff --git a/vimode.c b/vimode.c index b9a950e7..fcd9b3b0 100644 --- a/vimode.c +++ b/vimode.c @@ -142,6 +142,56 @@ static void center_view_on_cursor(struct terminal *const term) } } +// move_cursor_delta +// +// Moves the cursor within the scrollback by the vector delta. If the +// cursor goes outside the view bounds, the view is scrolled. +// +// Parameters: +// delta - the number of rows/columns to move by. Negative values move +// up/left, positive down/right. +// +static void move_cursor_delta(struct terminal *const term, + struct coord const delta) +{ + damage_cursor_cell(term); + struct coord cursor = cursor_to_view_relative(term, term->vimode.cursor); + cursor.row += delta.row; + cursor.col += delta.col; + + if (cursor.row < 0) { + int const overflow = -cursor.row; + cmd_scrollback_up(term, overflow); + cursor.row = 0; + } else if (cursor.row >= term->rows) { + int const overflow = cursor.row - term->rows + 1; + cmd_scrollback_down(term, overflow); + cursor.row = term->rows - 1; + } + + if (cursor.col < 0) { + cursor.col = 0; + } else if (cursor.col >= term->cols) { + cursor.col = term->cols - 1; + } + + term->vimode.cursor = cursor_from_view_relative(term, cursor); + LOG_DBG("CURSOR MOVED (%d, %d) [delta=(%d, %d)]", term->vimode.cursor.row, + term->vimode.cursor.col, delta.row, delta.col); + damage_cursor_cell(term); + render_refresh(term); +} + +static void move_cursor_vertical(struct terminal *const term, int const count) +{ + move_cursor_delta(term, (struct coord){.row = count, .col = 0}); +} + +static void move_cursor_horizontal(struct terminal *const term, int const count) +{ + move_cursor_delta(term, (struct coord){.row = 0, .col = count}); +} + static void update_selection(struct terminal *const term) { enum vi_mode const mode = term->vimode.mode; @@ -527,7 +577,7 @@ static bool find_next(struct terminal *term, char32_t const *const buf, * rest of the search buffer matches. */ - LOG_DBG("search: initial match at row=%d, col=%d", match_start_row, + LOG_DBG("search: initial match at (%d, %d)", match_start_row, match_start_col); int match_end_row = match_start_row; @@ -733,12 +783,47 @@ struct range search_matches_next(struct search_match_iterator *iter) return match; } -static void add_wchars(struct terminal *term, char32_t *src, size_t count) +static void on_search_string_updated(struct terminal *const term) { + LOG_DBG("SEARCH UPDATED [%ls]", (const wchar_t *)term->vimode.search.buf); + struct range match; + // TODO (kociap): when several consecutive searches succeed, the + // cursor is not moved to its original position in-between + // searches. + bool const matched = find_next_from_cursor( + term, term->vimode.search.buf, term->vimode.search.len, + term->vimode.search.direction, &match); + if (matched > 0) { + term->vimode.search.match = match.start; + term->vimode.search.match_len = term->vimode.search.len; + struct coord const delta = + delta_cursor_in_abs_coord(term, term->vimode.search.match); + move_cursor_delta(term, delta); + center_view_on_cursor(term); + update_selection(term); + } else { + restore_pre_search_state(term); + } + update_highlights(term); + render_refresh_vimode_search_box(term); +} + +static void add_chars_to_search(struct terminal *term, char const *buffer, + size_t const length) +{ + size_t count = mbsntoc32(NULL, buffer, length, 0); + if (count == (size_t)-1) { + LOG_ERRNO("failed to convert %.*s to Unicode", (int)length, buffer); + return; + } + + char32_t c32s[count + 1]; + mbsntoc32(c32s, buffer, length, count); + /* Strip non-printable characters */ for (size_t i = 0, j = 0, orig_count = count; i < orig_count; i++) { - if (isc32print(src[i])) - src[j++] = src[i]; + if (isc32print(c32s[i])) + c32s[j++] = c32s[i]; else count--; } @@ -753,7 +838,7 @@ static void add_wchars(struct terminal *term, char32_t *src, size_t count) (term->vimode.search.len - term->vimode.search.cursor) * sizeof(char32_t)); - memcpy(&term->vimode.search.buf[term->vimode.search.cursor], src, + memcpy(&term->vimode.search.buf[term->vimode.search.cursor], c32s, count * sizeof(char32_t)); term->vimode.search.len += count; @@ -764,15 +849,8 @@ static void add_wchars(struct terminal *term, char32_t *src, size_t count) void vimode_search_add_chars(struct terminal *term, const char *src, size_t count) { - size_t chars = mbsntoc32(NULL, src, count, 0); - if (chars == (size_t)-1) { - LOG_ERRNO("failed to convert %.*s to Unicode", (int)count, src); - return; - } - - char32_t c32s[chars + 1]; - mbsntoc32(c32s, src, count, chars); - add_wchars(term, c32s, chars); + add_chars_to_search(term, src, count); + on_search_string_updated(term); } void vimode_view_down(struct terminal *const term, int const delta) @@ -788,56 +866,6 @@ void vimode_view_down(struct terminal *const term, int const delta) update_highlights(term); } -// move_cursor_delta -// -// Moves the cursor within the scrollback by the vector delta. If the -// cursor goes outside the view bounds, the view is scrolled. -// -// Parameters: -// delta - the number of rows/columns to move by. Negative values move -// up/left, positive down/right. -// -static void move_cursor_delta(struct terminal *const term, - struct coord const delta) -{ - damage_cursor_cell(term); - struct coord cursor = cursor_to_view_relative(term, term->vimode.cursor); - cursor.row += delta.row; - cursor.col += delta.col; - - if (cursor.row < 0) { - int const overflow = -cursor.row; - cmd_scrollback_up(term, overflow); - cursor.row = 0; - } else if (cursor.row >= term->rows) { - int const overflow = cursor.row - term->rows + 1; - cmd_scrollback_down(term, overflow); - cursor.row = term->rows - 1; - } - - if (cursor.col < 0) { - cursor.col = 0; - } else if (cursor.col >= term->cols) { - cursor.col = term->cols - 1; - } - - term->vimode.cursor = cursor_from_view_relative(term, cursor); - LOG_DBG("CURSOR MOVED (%d, %d) [delta=(%d, %d)]", term->vimode.cursor.row, - term->vimode.cursor.col, delta.row, delta.col); - damage_cursor_cell(term); - render_refresh(term); -} - -static void move_cursor_vertical(struct terminal *const term, int const count) -{ - move_cursor_delta(term, (struct coord){.row = count, .col = 0}); -} - -static void move_cursor_horizontal(struct terminal *const term, int const count) -{ - move_cursor_delta(term, (struct coord){.row = 0, .col = count}); -} - enum c32_class { CLASS_BLANK, CLASS_PUNCTUATION, @@ -1396,6 +1424,18 @@ static void execute_vimode_binding(struct seat *seat, struct terminal *term, } } +static void from_clipboard_cb(char *text, size_t size, void *user) +{ + struct terminal *term = user; + add_chars_to_search(term, text, size); +} + +static void from_clipboard_done(void *user) +{ + struct terminal *term = user; + on_search_string_updated(term); +} + static void execute_vimode_search_binding(struct seat *seat, struct terminal *const term, const struct key_binding *binding, @@ -1438,7 +1478,6 @@ static void execute_vimode_search_binding(struct seat *seat, search->cursor -= 1; search->len -= 1; search->buf[search->len] = U'\0'; - render_refresh_vimode_search_box(term); *search_string_changed = true; } break; @@ -1446,34 +1485,28 @@ static void execute_vimode_search_binding(struct seat *seat, case BIND_ACTION_VIMODE_SEARCH_LEFT: if (search->cursor > 0) { search->cursor -= 1; - render_refresh_vimode_search_box(term); } break; case BIND_ACTION_VIMODE_SEARCH_RIGHT: if (search->cursor < search->len) { search->cursor += 1; - render_refresh_vimode_search_box(term); } break; - // case BIND_ACTION_SEARCH_CLIPBOARD_PASTE: - // text_from_clipboard(seat, term, &from_clipboard_cb, - // &from_clipboard_done, - // term); - // *update_search_result = *redraw = true; - // return true; - // - // case BIND_ACTION_SEARCH_PRIMARY_PASTE: - // text_from_primary(seat, term, &from_clipboard_cb, - // &from_clipboard_done, - // term); - // *update_search_result = *redraw = true; - // return true; - // - // case BIND_ACTION_SEARCH_UNICODE_INPUT: - // unicode_mode_activate(term); - // return true; + case BIND_ACTION_VIMODE_SEARCH_CLIPBOARD_PASTE: + text_from_clipboard(seat, term, &from_clipboard_cb, + &from_clipboard_done, term); + break; + + case BIND_ACTION_VIMODE_SEARCH_PRIMARY_PASTE: + text_from_primary(seat, term, &from_clipboard_cb, &from_clipboard_done, + term); + break; + + // case BIND_ACTION_VIMODE_SEARCH_UNICODE_INPUT: + // unicode_mode_activate(term); + // break; case BIND_ACTION_VIMODE_COUNT: BUG("Invalid action type"); @@ -1579,34 +1612,13 @@ void vimode_input(struct seat *seat, struct terminal *term, } if (count > 0) { - vimode_search_add_chars(term, (const char *)buf, count); - render_refresh_vimode_search_box(term); + add_chars_to_search(term, (const char *)buf, count); search_string_updated = true; } } if (search_string_updated) { - LOG_DBG("SEARCH UPDATED [%ls]", - (const wchar_t *)term->vimode.search.buf); - struct range match; - // TODO (kociap): when several consecutive searches succeed, the - // cursor is not moved to its original position in-between - // searches. - bool const matched = find_next_from_cursor( - term, term->vimode.search.buf, term->vimode.search.len, - term->vimode.search.direction, &match); - if (matched > 0) { - term->vimode.search.match = match.start; - term->vimode.search.match_len = term->vimode.search.len; - struct coord const delta = - delta_cursor_in_abs_coord(term, term->vimode.search.match); - move_cursor_delta(term, delta); - center_view_on_cursor(term); - update_selection(term); - } else { - restore_pre_search_state(term); - } - update_highlights(term); + on_search_string_updated(term); } } }