mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
search/config: configurable key bindings for (scrollback) search mode
This commit is contained in:
parent
c1653c7237
commit
919f31ffcb
4 changed files with 213 additions and 9 deletions
|
|
@ -20,6 +20,7 @@
|
|||
controlled by the **scrollback-indicator-position** and
|
||||
**scrollback-indicator-format** options in `footrc`
|
||||
(https://codeberg.org/dnkl/foot/issues/42).
|
||||
* Key bindings in _scollback search_ mode are now configurable.
|
||||
|
||||
|
||||
### Deprecated
|
||||
|
|
|
|||
133
config.c
133
config.c
|
|
@ -48,7 +48,7 @@ static const uint32_t default_bright[] = {
|
|||
0xffffff,
|
||||
};
|
||||
|
||||
static const char *binding_action_map[] = {
|
||||
static const char *const binding_action_map[] = {
|
||||
[BIND_ACTION_NONE] = NULL,
|
||||
[BIND_ACTION_SCROLLBACK_UP] = "scrollback-up",
|
||||
[BIND_ACTION_SCROLLBACK_DOWN] = "scrollback-down",
|
||||
|
|
@ -70,6 +70,29 @@ static const char *binding_action_map[] = {
|
|||
static_assert(ALEN(binding_action_map) == BIND_ACTION_COUNT,
|
||||
"binding action map size mismatch");
|
||||
|
||||
static const char *const search_binding_action_map[] = {
|
||||
[BIND_ACTION_SEARCH_NONE] = NULL,
|
||||
[BIND_ACTION_SEARCH_CANCEL] = "cancel",
|
||||
[BIND_ACTION_SEARCH_COMMIT] = "commit",
|
||||
[BIND_ACTION_SEARCH_FIND_PREV] = "find-prev",
|
||||
[BIND_ACTION_SEARCH_FIND_NEXT] = "find-next",
|
||||
[BIND_ACTION_SEARCH_EDIT_LEFT] = "cursor-left",
|
||||
[BIND_ACTION_SEARCH_EDIT_LEFT_WORD] = "cursor-left-word",
|
||||
[BIND_ACTION_SEARCH_EDIT_RIGHT] = "cursor-right",
|
||||
[BIND_ACTION_SEARCH_EDIT_RIGHT_WORD] = "cursor-right-word",
|
||||
[BIND_ACTION_SEARCH_EDIT_HOME] = "cursor-home",
|
||||
[BIND_ACTION_SEARCH_EDIT_END] = "cursor-end",
|
||||
[BIND_ACTION_SEARCH_DELETE_PREV] = "delete-prev",
|
||||
[BIND_ACTION_SEARCH_DELETE_PREV_WORD] = "delete-prev-word",
|
||||
[BIND_ACTION_SEARCH_DELETE_NEXT] = "delete-next",
|
||||
[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",
|
||||
};
|
||||
|
||||
static_assert(ALEN(search_binding_action_map) == BIND_ACTION_SEARCH_COUNT,
|
||||
"search binding action map size mismatch");
|
||||
|
||||
static char *
|
||||
get_shell(void)
|
||||
{
|
||||
|
|
@ -523,6 +546,7 @@ parse_section_csd(const char *key, const char *value, struct config *conf,
|
|||
|
||||
static bool
|
||||
verify_key_combo(const struct config *conf, enum bind_action_normal action,
|
||||
const char *const binding_action_map[],
|
||||
const char *combo, const char *path, unsigned lineno)
|
||||
{
|
||||
tll_foreach(conf->bindings.key, it) {
|
||||
|
|
@ -602,7 +626,7 @@ parse_section_key_bindings(
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!verify_key_combo(conf, action, value, path, lineno)) {
|
||||
if (!verify_key_combo(conf, action, binding_action_map, value, path, lineno)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -641,6 +665,95 @@ parse_section_key_bindings(
|
|||
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_section_search_bindings(
|
||||
const char *key, const char *value, struct config *conf,
|
||||
const char *path, unsigned lineno)
|
||||
{
|
||||
#if 0
|
||||
const char *pipe_cmd = NULL;
|
||||
size_t pipe_len = 0;
|
||||
|
||||
if (value[0] == '[') {
|
||||
const char *pipe_cmd_end = strrchr(value, ']');
|
||||
if (pipe_cmd_end == NULL) {
|
||||
LOG_ERR("%s:%d: unclosed '['", path, lineno);
|
||||
return false;
|
||||
}
|
||||
|
||||
pipe_cmd = &value[1];
|
||||
pipe_len = pipe_cmd_end - pipe_cmd;
|
||||
|
||||
value = pipe_cmd_end + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (enum bind_action_search action = 0;
|
||||
action < BIND_ACTION_SEARCH_COUNT;
|
||||
action++)
|
||||
{
|
||||
if (search_binding_action_map[action] == NULL)
|
||||
continue;
|
||||
|
||||
if (strcmp(key, search_binding_action_map[action]) != 0)
|
||||
continue;
|
||||
|
||||
if (strcasecmp(value, "none") == 0) {
|
||||
tll_foreach(conf->bindings.search, it) {
|
||||
if (it->item.action == action) {
|
||||
free(it->item.key);
|
||||
// free(it->item.pipe_cmd);
|
||||
tll_remove(conf->bindings.search, it);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!verify_key_combo(conf, action, search_binding_action_map, value, path, lineno)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool already_added = false;
|
||||
tll_foreach(conf->bindings.search, it) {
|
||||
if (it->item.action == action
|
||||
#if 0
|
||||
&&
|
||||
((it->item.pipe_cmd == NULL && pipe_cmd == NULL) ||
|
||||
(it->item.pipe_cmd != NULL && pipe_cmd != NULL &&
|
||||
strncmp(it->item.pipe_cmd, pipe_cmd, pipe_len) == 0))
|
||||
#endif
|
||||
)
|
||||
{
|
||||
|
||||
free(it->item.key);
|
||||
// free(it->item.pipe_cmd);
|
||||
|
||||
it->item.key = strdup(value);
|
||||
#if 0
|
||||
it->item.pipe_cmd = pipe_cmd != NULL
|
||||
? strndup(pipe_cmd, pipe_len) : NULL;
|
||||
#endif
|
||||
already_added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!already_added) {
|
||||
struct config_key_binding_search binding = {
|
||||
.action = action,
|
||||
.key = strdup(value),
|
||||
// .pipe_cmd = pipe_cmd != NULL ? strndup(pipe_cmd, pipe_len) : NULL,
|
||||
};
|
||||
tll_push_back(conf->bindings.search, binding);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_ERR("%s:%u: invalid key: %s", path, lineno, key);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_section_mouse_bindings(
|
||||
const char *key, const char *value, struct config *conf,
|
||||
|
|
@ -785,6 +898,7 @@ parse_config_file(FILE *f, struct config *conf, const char *path)
|
|||
SECTION_CURSOR,
|
||||
SECTION_CSD,
|
||||
SECTION_KEY_BINDINGS,
|
||||
SECTION_SEARCH_BINDINGS,
|
||||
SECTION_MOUSE_BINDINGS,
|
||||
SECTION_TWEAK,
|
||||
SECTION_COUNT,
|
||||
|
|
@ -799,13 +913,14 @@ parse_config_file(FILE *f, struct config *conf, const char *path)
|
|||
parser_fun_t fun;
|
||||
const char *name;
|
||||
} section_info[] = {
|
||||
[SECTION_MAIN] = {&parse_section_main, "main"},
|
||||
[SECTION_COLORS] = {&parse_section_colors, "colors"},
|
||||
[SECTION_CURSOR] = {&parse_section_cursor, "cursor"},
|
||||
[SECTION_CSD] = {&parse_section_csd, "csd"},
|
||||
[SECTION_KEY_BINDINGS] = {&parse_section_key_bindings, "key-bindings"},
|
||||
[SECTION_MOUSE_BINDINGS] = {&parse_section_mouse_bindings, "mouse-bindings"},
|
||||
[SECTION_TWEAK] = {&parse_section_tweak, "tweak"},
|
||||
[SECTION_MAIN] = {&parse_section_main, "main"},
|
||||
[SECTION_COLORS] = {&parse_section_colors, "colors"},
|
||||
[SECTION_CURSOR] = {&parse_section_cursor, "cursor"},
|
||||
[SECTION_CSD] = {&parse_section_csd, "csd"},
|
||||
[SECTION_KEY_BINDINGS] = {&parse_section_key_bindings, "key-bindings"},
|
||||
[SECTION_SEARCH_BINDINGS] = {&parse_section_search_bindings, "search-bindings"},
|
||||
[SECTION_MOUSE_BINDINGS] = {&parse_section_mouse_bindings, "mouse-bindings"},
|
||||
[SECTION_TWEAK] = {&parse_section_tweak, "tweak"},
|
||||
};
|
||||
|
||||
static_assert(ALEN(section_info) == SECTION_COUNT, "section info array size mismatch");
|
||||
|
|
|
|||
|
|
@ -265,6 +265,76 @@ e.g. *search-start=none*.
|
|||
|
||||
Default: _not bound_
|
||||
|
||||
# SECTION: search-bindings
|
||||
|
||||
This section lets you override the default key bindings used in
|
||||
scrollback search mode. The syntax is exactly the same as the regular
|
||||
**key-bindings**.
|
||||
|
||||
*cancel*
|
||||
Aborts the search. The viewport is restored and the _primary
|
||||
selection_ is **not** updated. Default: _Control+g Escape_.
|
||||
|
||||
*commit*
|
||||
Exit search mode and copy current selection into the _primary
|
||||
selection_. Viewport is **not** restored. To copy the selection to
|
||||
the regular _clipboard_, use *Control+Shift+C*. Default: _Return_.
|
||||
|
||||
*find-prev*
|
||||
Search **backwards** in the scrollback history for the next
|
||||
match. Default: _Control+r_.
|
||||
|
||||
*find-next*
|
||||
Searchs **forwards** in the scrollback history for the next
|
||||
match. Default: _Control+s_.
|
||||
|
||||
*cursor-left*
|
||||
Moves the cursor in the search box one **character** to the
|
||||
left. Default: _Left Control+b_.
|
||||
|
||||
*cursor-left-word*
|
||||
Moves the cursor in the search box one **word** to the
|
||||
left. Default: _Control+Left Mod1+b_.
|
||||
|
||||
*cursor-right*
|
||||
Moves the cursor in the search box one **character** to the
|
||||
right. Default: _Right Control+f_.
|
||||
|
||||
*cursor-right-word*
|
||||
Moves the cursor in the search box one **word** to the
|
||||
right. Default: _Control+Left Mod1+b_.
|
||||
|
||||
*cursor-home*
|
||||
Moves the cursor in the search box to the beginning of the
|
||||
input. Default: _Home Control+a_.
|
||||
|
||||
*cursor-end*
|
||||
Moves the cursor in the search box to the end of the
|
||||
input. Default: _End Control+e_.
|
||||
|
||||
*delete-prev*
|
||||
Deletes the **character before** the cursor. Default: _BackSpace_.
|
||||
|
||||
*delete-prev-word*
|
||||
Deletes the **word before** the cursor. Default: _Mod1+BackSpace
|
||||
Control+BackSpace_.
|
||||
|
||||
*delete-next*
|
||||
Deletes the **character after** the cursor. Default: _Delete_.
|
||||
|
||||
*delete-next-word*
|
||||
Deletes the **word after** the cursor. Default: _Mod1+b
|
||||
Control+Delete_.
|
||||
|
||||
*extend-to-word-boundary*
|
||||
Extend current selection to the next word boundary. Default:
|
||||
_Control+w_.
|
||||
|
||||
*extend-to-next-whitespace*
|
||||
Extend the current selection to the next whitespace. Default:
|
||||
_Control+Shift+W_.
|
||||
|
||||
|
||||
# SECTION: mouse-bindings
|
||||
|
||||
This section lets you override the default mouse bindings.
|
||||
|
|
|
|||
18
footrc
18
footrc
|
|
@ -63,5 +63,23 @@
|
|||
# pipe-visible=[sh -c "xurls | bemenu | xargs -r firefox"] none
|
||||
# pipe-scrollback=[sh -c "xurls | bemenu | xargs -r firefox"] none
|
||||
|
||||
[search-bindings]
|
||||
# cancel=Control+g Escape
|
||||
# commit=Return
|
||||
# find-prev=Control+r
|
||||
# find-next=Control+s
|
||||
# cursor-left=Left Control+b
|
||||
# cursor-left-word=Control+Left Mod1+b
|
||||
# cursor-right=Right Control+f
|
||||
# cursor-right-word=Control+Right Mod1+f
|
||||
# cursor-home=Home Control+a
|
||||
# cursor-end=End Control+e
|
||||
# delete-prev=BackSpace
|
||||
# delete-prev-word=Mod1+BackSpace Control+BackSpace
|
||||
# delete-next=Delete
|
||||
# delete-next-word=Mod1+d Control+Delete
|
||||
# extend-to-word-boundary=Control+w
|
||||
# extend-to-next-whitespace=Control+Shift+W
|
||||
|
||||
[mouse-bindings]
|
||||
# primary-paste=BTN_MIDDLE
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue