implement paste

This commit is contained in:
Piotr Kocia 2025-04-05 00:28:59 +02:00
parent c1eee29fbe
commit 9f9c1e11e2
4 changed files with 130 additions and 110 deletions

View file

@ -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);

5
ime.c
View file

@ -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);

View file

@ -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,
};

226
vimode.c
View file

@ -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);
}
}
}