add movement and deletion search keybinds

This commit is contained in:
Piotr Kocia 2025-04-05 02:40:06 +02:00
parent 7b3d7bf1f1
commit f41558fc80
3 changed files with 189 additions and 11 deletions

View file

@ -199,8 +199,17 @@ static const char *const vimode_search_binding_action_map[] = {
[BIND_ACTION_VIMODE_SEARCH_CANCEL] = "vimode-search-cancel",
[BIND_ACTION_VIMODE_SEARCH_CONFIRM] = "vimode-search-confirm",
[BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_CHAR] = "vimode-search-delete-prev",
[BIND_ACTION_VIMODE_SEARCH_DELETE_NEXT_CHAR] = "vimode-search-delete-next",
[BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_WORD] = "vimode-search-delete-prev-word",
[BIND_ACTION_VIMODE_SEARCH_DELETE_NEXT_WORD] = "vimode-search-delete-next-word",
[BIND_ACTION_VIMODE_SEARCH_DELETE_TO_START] = "vimode-search-delete-to-start",
[BIND_ACTION_VIMODE_SEARCH_DELETE_TO_END] = "vimode-search-delete-to-end",
[BIND_ACTION_VIMODE_SEARCH_LEFT] = "vimode-search-left",
[BIND_ACTION_VIMODE_SEARCH_RIGHT] = "vimode-search-right",
[BIND_ACTION_VIMODE_SEARCH_LEFT_WORD] = "vimode-search-left-word",
[BIND_ACTION_VIMODE_SEARCH_RIGHT_WORD] = "vimode-search-right-word",
[BIND_ACTION_VIMODE_SEARCH_LINE_START] = "vimode-search-line-start",
[BIND_ACTION_VIMODE_SEARCH_LINE_END] = "vimode-search-line-end",
[BIND_ACTION_VIMODE_SEARCH_UNICODE_INPUT] = "vimode-search-unicode-input",
[BIND_ACTION_VIMODE_SEARCH_CLIPBOARD_PASTE] = "vimode-search-clipboard-paste",
[BIND_ACTION_VIMODE_SEARCH_PRIMARY_PASTE] = "vimode-search-primary-paste",
@ -3338,10 +3347,21 @@ add_default_vimode_search_bindings(struct config *conf)
{BIND_ACTION_VIMODE_SEARCH_CANCEL, m("none"), {{XKB_KEY_Escape}}},
{BIND_ACTION_VIMODE_SEARCH_CANCEL, m(XKB_MOD_NAME_CTRL), {{XKB_KEY_c}}},
{BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_CHAR, m("none"), {{XKB_KEY_BackSpace}}},
{BIND_ACTION_VIMODE_SEARCH_DELETE_NEXT_CHAR, m("none"), {{XKB_KEY_Delete}}},
{BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_WORD, m(XKB_MOD_NAME_CTRL), {{XKB_KEY_BackSpace}}},
{BIND_ACTION_VIMODE_SEARCH_DELETE_NEXT_WORD, m(XKB_MOD_NAME_CTRL), {{XKB_KEY_Delete}}},
{BIND_ACTION_VIMODE_SEARCH_DELETE_TO_START, m(XKB_MOD_NAME_ALT), {{XKB_KEY_BackSpace}}},
{BIND_ACTION_VIMODE_SEARCH_DELETE_TO_END, m(XKB_MOD_NAME_ALT), {{XKB_KEY_Delete}}},
{BIND_ACTION_VIMODE_SEARCH_LEFT, m(XKB_MOD_NAME_CTRL), {{XKB_KEY_h}}},
{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_LEFT_WORD, m(XKB_MOD_NAME_CTRL), {{XKB_KEY_b}}},
{BIND_ACTION_VIMODE_SEARCH_RIGHT_WORD, m(XKB_MOD_NAME_CTRL), {{XKB_KEY_e}}},
{BIND_ACTION_VIMODE_SEARCH_LINE_START, m(XKB_MOD_NAME_CTRL), {{XKB_KEY_k}}},
{BIND_ACTION_VIMODE_SEARCH_LINE_START, m("none"), {{XKB_KEY_Home}}},
{BIND_ACTION_VIMODE_SEARCH_LINE_END, m(XKB_MOD_NAME_CTRL), {{XKB_KEY_j}}},
{BIND_ACTION_VIMODE_SEARCH_LINE_END, m("none"), {{XKB_KEY_End}}},
{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}}},

View file

@ -103,8 +103,17 @@ enum bind_action_vimode_search {
BIND_ACTION_VIMODE_SEARCH_CONFIRM,
BIND_ACTION_VIMODE_SEARCH_CANCEL,
BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_CHAR,
BIND_ACTION_VIMODE_SEARCH_DELETE_NEXT_CHAR,
BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_WORD,
BIND_ACTION_VIMODE_SEARCH_DELETE_NEXT_WORD,
BIND_ACTION_VIMODE_SEARCH_DELETE_TO_START,
BIND_ACTION_VIMODE_SEARCH_DELETE_TO_END,
BIND_ACTION_VIMODE_SEARCH_LEFT,
BIND_ACTION_VIMODE_SEARCH_RIGHT,
BIND_ACTION_VIMODE_SEARCH_LEFT_WORD,
BIND_ACTION_VIMODE_SEARCH_RIGHT_WORD,
BIND_ACTION_VIMODE_SEARCH_LINE_START,
BIND_ACTION_VIMODE_SEARCH_LINE_END,
BIND_ACTION_VIMODE_SEARCH_UNICODE_INPUT,
BIND_ACTION_VIMODE_SEARCH_CLIPBOARD_PASTE,
BIND_ACTION_VIMODE_SEARCH_PRIMARY_PASTE,

171
vimode.c
View file

@ -1437,6 +1437,100 @@ static void from_clipboard_done(void *user)
on_search_string_updated(term);
}
// Deletes characters from the search string backward from the cursor
// position. Deletes at most cursor characters.
// Returns true when any characters have been deleted.
//
static bool
delete_chars_from_search_backward(struct vimode_search *const search, int count)
{
if (search->cursor > 0) {
count = count < search->cursor ? count : search->cursor;
memmove(&search->buf[search->cursor - count],
&search->buf[search->cursor],
(search->len - search->cursor) * sizeof(char32_t));
search->cursor -= count;
search->len -= count;
search->buf[search->len] = U'\0';
return true;
}
return false;
}
// Deletes characters from the search string forward from the cursor
// position. Deletes at most length-cursor characters.
// Returns true when any characters have been deleted.
//
static bool delete_chars_from_search_forward(struct vimode_search *const search,
int count)
{
if (search->cursor < search->len) {
count = count < search->len - search->cursor
? count
: search->len - search->cursor;
memmove(&search->buf[search->cursor],
&search->buf[search->cursor + count],
(search->len - search->cursor - count) * sizeof(char32_t));
search->len -= count;
search->buf[search->len] = U'\0';
return true;
}
return false;
}
static int distance_back_word(struct vimode_search *const search)
{
int cursor = search->cursor;
if (cursor == 0) {
return 0;
}
cursor -= 1;
// Skip whitespace.
while (cursor > 0 && get_class(search->buf[cursor]) == CLASS_BLANK) {
cursor -= 1;
}
// Go back to the start of the word.
enum c32_class const current_class = get_class(search->buf[cursor]);
while (cursor >= 0 && get_class(search->buf[cursor]) == current_class) {
cursor -= 1;
}
// We overshot. Move forward one character.
cursor += 1;
return search->cursor - cursor;
}
static int distance_fwd_word(struct vimode_search *const search)
{
int cursor = search->cursor;
if (cursor == search->len) {
return 0;
}
enum c32_class const starting_class = get_class(search->buf[cursor]);
cursor += 1;
// Go forward to the end of the word.
if (starting_class != CLASS_BLANK) {
while (cursor < search->len &&
get_class(search->buf[cursor]) == starting_class) {
cursor += 1;
}
}
// Skip whitespace.
while (cursor < search->len &&
get_class(search->buf[cursor]) == CLASS_BLANK) {
cursor += 1;
}
return cursor - search->cursor;
}
static void execute_vimode_search_binding(struct seat *seat,
struct terminal *const term,
const struct key_binding *binding,
@ -1471,27 +1565,82 @@ static void execute_vimode_search_binding(struct seat *seat,
cancel_search(term, true);
break;
case BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_CHAR:
if (search->cursor > 0) {
memmove(&search->buf[search->cursor - 1],
&search->buf[search->cursor],
(search->len - search->cursor) * sizeof(char32_t));
search->cursor -= 1;
search->len -= 1;
search->buf[search->len] = U'\0';
*search_string_changed = true;
}
break;
case BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_CHAR: {
bool const deleted = delete_chars_from_search_backward(search, 1);
*search_string_changed = deleted;
} break;
case BIND_ACTION_VIMODE_SEARCH_DELETE_NEXT_CHAR: {
bool const deleted = delete_chars_from_search_forward(search, 1);
*search_string_changed = deleted;
} break;
case BIND_ACTION_VIMODE_SEARCH_DELETE_PREV_WORD: {
int const distance = distance_back_word(search);
bool const deleted =
delete_chars_from_search_backward(search, distance);
*search_string_changed = deleted;
} break;
case BIND_ACTION_VIMODE_SEARCH_DELETE_NEXT_WORD: {
int const distance = distance_fwd_word(search);
bool const deleted = delete_chars_from_search_forward(search, distance);
*search_string_changed = deleted;
} break;
case BIND_ACTION_VIMODE_SEARCH_DELETE_TO_START: {
bool const deleted =
delete_chars_from_search_backward(search, search->len);
*search_string_changed = deleted;
} break;
case BIND_ACTION_VIMODE_SEARCH_DELETE_TO_END: {
bool const deleted =
delete_chars_from_search_forward(search, search->len);
*search_string_changed = deleted;
} break;
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_VIMODE_SEARCH_LEFT_WORD:
if (search->cursor > 0) {
int const distance = distance_back_word(search);
search->cursor -= distance;
render_refresh_vimode_search_box(term);
}
break;
case BIND_ACTION_VIMODE_SEARCH_RIGHT_WORD:
if (search->cursor < search->len) {
int const distance = distance_fwd_word(search);
search->cursor += distance;
render_refresh_vimode_search_box(term);
}
break;
case BIND_ACTION_VIMODE_SEARCH_LINE_START:
if (search->cursor > 0) {
search->cursor = 0;
render_refresh_vimode_search_box(term);
}
break;
case BIND_ACTION_VIMODE_SEARCH_LINE_END:
if (search->cursor < search->len) {
search->cursor = search->len;
render_refresh_vimode_search_box(term);
}
break;