mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-22 05:33:45 -04:00
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:
parent
43f293f22e
commit
f3e6941c9a
8 changed files with 90 additions and 25 deletions
|
|
@ -47,6 +47,10 @@
|
||||||
font is used (https://codeberg.org/dnkl/foot/issues/169).
|
font is used (https://codeberg.org/dnkl/foot/issues/169).
|
||||||
* Drag & drop support; text, files and URLs can now be dropped in a
|
* Drag & drop support; text, files and URLs can now be dropped in a
|
||||||
foot terminal window (https://codeberg.org/dnkl/foot/issues/175).
|
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
|
### Changed
|
||||||
|
|
|
||||||
|
|
@ -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
|
: Same as <kbd>ctrl</kbd>+<kbd>w</kbd>, except that the only word
|
||||||
separating characters are whitespace characters.
|
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>
|
<kbd>escape</kbd>, <kbd>ctrl</kbd>+<kbd>g</kbd>
|
||||||
: Cancel the search
|
: Cancel the search
|
||||||
|
|
||||||
|
|
|
||||||
6
config.c
6
config.c
|
|
@ -108,6 +108,8 @@ static const char *const search_binding_action_map[] = {
|
||||||
[BIND_ACTION_SEARCH_DELETE_NEXT_WORD] = "delete-next-word",
|
[BIND_ACTION_SEARCH_DELETE_NEXT_WORD] = "delete-next-word",
|
||||||
[BIND_ACTION_SEARCH_EXTEND_WORD] = "extend-to-word-boundary",
|
[BIND_ACTION_SEARCH_EXTEND_WORD] = "extend-to-word-boundary",
|
||||||
[BIND_ACTION_SEARCH_EXTEND_WORD_WS] = "extend-to-next-whitespace",
|
[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,
|
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 none = {0};
|
||||||
const struct config_key_modifiers alt = {.alt = true};
|
const struct config_key_modifiers alt = {.alt = true};
|
||||||
const struct config_key_modifiers ctrl = {.ctrl = 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};
|
const struct config_key_modifiers ctrl_shift = {.ctrl = true, .shift = true};
|
||||||
|
|
||||||
add_binding(BIND_ACTION_SEARCH_CANCEL, ctrl, XKB_KEY_g);
|
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_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, ctrl, XKB_KEY_w);
|
||||||
add_binding(BIND_ACTION_SEARCH_EXTEND_WORD_WS, ctrl_shift, 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
|
#undef add_binding
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
Same as *ctrl*+*w*, except that the only word separating
|
||||||
characters are whitespace characters.
|
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*
|
*escape*, *ctrl*+*g*
|
||||||
Cancel the search
|
Cancel the search
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
Extend the current selection to the next whitespace. Default:
|
||||||
_Control+Shift+W_.
|
_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
|
# SECTION: mouse-bindings
|
||||||
|
|
||||||
|
|
|
||||||
2
foot.ini
2
foot.ini
|
|
@ -102,6 +102,8 @@
|
||||||
# delete-next-word=Mod1+d Control+Delete
|
# delete-next-word=Mod1+d Control+Delete
|
||||||
# extend-to-word-boundary=Control+w
|
# extend-to-word-boundary=Control+w
|
||||||
# extend-to-next-whitespace=Control+Shift+W
|
# extend-to-next-whitespace=Control+Shift+W
|
||||||
|
# clipboard-paste=Control+v Control+y
|
||||||
|
# primary-paste=Shift+Insert
|
||||||
|
|
||||||
[mouse-bindings]
|
[mouse-bindings]
|
||||||
# primary-paste=BTN_MIDDLE
|
# primary-paste=BTN_MIDDLE
|
||||||
|
|
|
||||||
82
search.c
82
search.c
|
|
@ -332,6 +332,35 @@ search_find_next(struct terminal *term)
|
||||||
#undef ROW_DEC
|
#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
|
static void
|
||||||
search_match_to_end_of_word(struct terminal *term, bool spaces_only)
|
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;
|
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
|
static bool
|
||||||
execute_binding(struct seat *seat, struct terminal *term,
|
execute_binding(struct seat *seat, struct terminal *term,
|
||||||
enum bind_action_search action, uint32_t serial)
|
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);
|
search_match_to_end_of_word(term, true);
|
||||||
return false;
|
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:
|
case BIND_ACTION_SEARCH_COUNT:
|
||||||
assert(false);
|
assert(false);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -666,31 +722,7 @@ search_input(struct seat *seat, struct terminal *term, uint32_t key,
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const char *src = (const char *)buf;
|
add_chars(term, (const char *)buf, 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", 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';
|
|
||||||
|
|
||||||
update_search:
|
update_search:
|
||||||
LOG_DBG("search: buffer: %ls", term->search.buf);
|
LOG_DBG("search: buffer: %ls", term->search.buf);
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,8 @@ enum bind_action_search {
|
||||||
BIND_ACTION_SEARCH_DELETE_NEXT_WORD,
|
BIND_ACTION_SEARCH_DELETE_NEXT_WORD,
|
||||||
BIND_ACTION_SEARCH_EXTEND_WORD,
|
BIND_ACTION_SEARCH_EXTEND_WORD,
|
||||||
BIND_ACTION_SEARCH_EXTEND_WORD_WS,
|
BIND_ACTION_SEARCH_EXTEND_WORD_WS,
|
||||||
|
BIND_ACTION_SEARCH_CLIPBOARD_PASTE,
|
||||||
|
BIND_ACTION_SEARCH_PRIMARY_PASTE,
|
||||||
BIND_ACTION_SEARCH_COUNT,
|
BIND_ACTION_SEARCH_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue