search: add {clipboard,primary}-paste key bindings

These bindings copy from the clipboard or primary selection into the
search buffer.

Default bindings:

* clipboard-paste: ctrl+v, ctrl+y
* primary-paste: shift+insert
This commit is contained in:
Daniel Eklöf 2020-11-01 12:39:57 +01:00
parent 43f293f22e
commit f3e6941c9a
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
8 changed files with 90 additions and 25 deletions

View file

@ -47,6 +47,10 @@
font is used (https://codeberg.org/dnkl/foot/issues/169).
* Drag & drop support; text, files and URLs can now be dropped in a
foot terminal window (https://codeberg.org/dnkl/foot/issues/175).
* **clipboard-paste** and **primary-paste** scrollback search
bindings. By default, they are bound to `ctrl+v ctrl+y` and
`shift+insert` respectively, and lets you paste from the clipboard
or primary selection into the search buffer.
### Changed

View file

@ -162,6 +162,12 @@ These are the default shortcuts. See `man foot.ini` and the example
: Same as <kbd>ctrl</kbd>+<kbd>w</kbd>, except that the only word
separating characters are whitespace characters.
<kbd>ctrl</kbd>+<kbd>v</kbd>
: Paste from clipboard into the search buffer.
<kbd>shift</kbd>+<kbd>insert</kbd>
: Paste from primary selection into the search buffer.
<kbd>escape</kbd>, <kbd>ctrl</kbd>+<kbd>g</kbd>
: Cancel the search

View file

@ -108,6 +108,8 @@ static const char *const search_binding_action_map[] = {
[BIND_ACTION_SEARCH_DELETE_NEXT_WORD] = "delete-next-word",
[BIND_ACTION_SEARCH_EXTEND_WORD] = "extend-to-word-boundary",
[BIND_ACTION_SEARCH_EXTEND_WORD_WS] = "extend-to-next-whitespace",
[BIND_ACTION_SEARCH_CLIPBOARD_PASTE] = "clipboard-paste",
[BIND_ACTION_SEARCH_PRIMARY_PASTE] = "primary-paste",
};
static_assert(ALEN(search_binding_action_map) == BIND_ACTION_SEARCH_COUNT,
@ -1840,6 +1842,7 @@ add_default_search_bindings(struct config *conf)
const struct config_key_modifiers none = {0};
const struct config_key_modifiers alt = {.alt = true};
const struct config_key_modifiers ctrl = {.ctrl = true};
const struct config_key_modifiers shift = {.shift = true};
const struct config_key_modifiers ctrl_shift = {.ctrl = true, .shift = true};
add_binding(BIND_ACTION_SEARCH_CANCEL, ctrl, XKB_KEY_g);
@ -1867,6 +1870,9 @@ add_default_search_bindings(struct config *conf)
add_binding(BIND_ACTION_SEARCH_DELETE_NEXT_WORD, alt, XKB_KEY_d);
add_binding(BIND_ACTION_SEARCH_EXTEND_WORD, ctrl, XKB_KEY_w);
add_binding(BIND_ACTION_SEARCH_EXTEND_WORD_WS, ctrl_shift, XKB_KEY_W);
add_binding(BIND_ACTION_SEARCH_CLIPBOARD_PASTE, ctrl, XKB_KEY_v);
add_binding(BIND_ACTION_SEARCH_CLIPBOARD_PASTE, ctrl, XKB_KEY_y);
add_binding(BIND_ACTION_SEARCH_PRIMARY_PASTE, shift, XKB_KEY_Insert);
#undef add_binding
}

View file

@ -186,6 +186,12 @@ Note that these are just the defaults; they can be changed in
Same as *ctrl*+*w*, except that the only word separating
characters are whitespace characters.
*ctrl*+*v*, *ctrl*+*y*
Paste from clipboard into the searh buffer.
*shift*+*insert*
Paste from primary selection into the search buffer.
*escape*, *ctrl*+*g*
Cancel the search

View file

@ -452,6 +452,13 @@ scrollback search mode. The syntax is exactly the same as the regular
Extend the current selection to the next whitespace. Default:
_Control+Shift+W_.
*clipboard-paste*
Paste from the _clipboard_ into the search buffer. Default:
_Control+v Control+y_.
*primary-paste*
Paste from the _primary selection_ into the search
buffer. Default: _Shift+Insert_.
# SECTION: mouse-bindings

View file

@ -102,6 +102,8 @@
# delete-next-word=Mod1+d Control+Delete
# extend-to-word-boundary=Control+w
# extend-to-next-whitespace=Control+Shift+W
# clipboard-paste=Control+v Control+y
# primary-paste=Shift+Insert
[mouse-bindings]
# primary-paste=BTN_MIDDLE

View file

@ -332,6 +332,35 @@ search_find_next(struct terminal *term)
#undef ROW_DEC
}
static void
add_chars(struct terminal *term, const char *src, size_t count)
{
mbstate_t ps = {0};
size_t wchars = mbsnrtowcs(NULL, &src, count, 0, &ps);
if (wchars == -1) {
LOG_ERRNO("failed to convert %.*s to wchars", (int)count, src);
return;
}
if (!search_ensure_size(term, term->search.len + wchars))
return;
assert(term->search.len + wchars < term->search.sz);
memmove(&term->search.buf[term->search.cursor + wchars],
&term->search.buf[term->search.cursor],
(term->search.len - term->search.cursor) * sizeof(wchar_t));
memset(&ps, 0, sizeof(ps));
mbsnrtowcs(&term->search.buf[term->search.cursor], &src, count,
wchars, &ps);
term->search.len += wchars;
term->search.cursor += wchars;
term->search.buf[term->search.len] = L'\0';
}
static void
search_match_to_end_of_word(struct terminal *term, bool spaces_only)
{
@ -461,6 +490,23 @@ distance_prev_word(const struct terminal *term)
return term->search.cursor - cursor;
}
static void
from_clipboard_cb(char *text, size_t size, void *user)
{
struct terminal *term = user;
add_chars(term, text, size);
}
static void
from_clipboard_done(void *user)
{
struct terminal *term = user;
LOG_DBG("search: buffer: %ls", term->search.buf);
search_find_next(term);
render_refresh_search(term);
}
static bool
execute_binding(struct seat *seat, struct terminal *term,
enum bind_action_search action, uint32_t serial)
@ -609,6 +655,16 @@ execute_binding(struct seat *seat, struct terminal *term,
search_match_to_end_of_word(term, true);
return false;
case BIND_ACTION_SEARCH_CLIPBOARD_PASTE:
text_from_clipboard(
seat, term, &from_clipboard_cb, &from_clipboard_done, term);
return false;
case BIND_ACTION_SEARCH_PRIMARY_PASTE:
text_from_primary(
seat, term, &from_clipboard_cb, &from_clipboard_done, term);
return false;
case BIND_ACTION_SEARCH_COUNT:
assert(false);
return false;
@ -666,31 +722,7 @@ search_input(struct seat *seat, struct terminal *term, uint32_t key,
if (count == 0)
return;
const char *src = (const char *)buf;
mbstate_t ps = {0};
size_t wchars = mbsnrtowcs(NULL, &src, count, 0, &ps);
if (wchars == -1) {
LOG_ERRNO("failed to convert %.*s to wchars", count, buf);
return;
}
if (!search_ensure_size(term, term->search.len + wchars))
return;
assert(term->search.len + wchars < term->search.sz);
memmove(&term->search.buf[term->search.cursor + wchars],
&term->search.buf[term->search.cursor],
(term->search.len - term->search.cursor) * sizeof(wchar_t));
memset(&ps, 0, sizeof(ps));
mbsnrtowcs(&term->search.buf[term->search.cursor], &src, count,
wchars, &ps);
term->search.len += wchars;
term->search.cursor += wchars;
term->search.buf[term->search.len] = L'\0';
add_chars(term, (const char *)buf, count);
update_search:
LOG_DBG("search: buffer: %ls", term->search.buf);

View file

@ -93,6 +93,8 @@ enum bind_action_search {
BIND_ACTION_SEARCH_DELETE_NEXT_WORD,
BIND_ACTION_SEARCH_EXTEND_WORD,
BIND_ACTION_SEARCH_EXTEND_WORD_WS,
BIND_ACTION_SEARCH_CLIPBOARD_PASTE,
BIND_ACTION_SEARCH_PRIMARY_PASTE,
BIND_ACTION_SEARCH_COUNT,
};