search/config: configurable key bindings for (scrollback) search mode

This commit is contained in:
Daniel Eklöf 2020-07-29 17:27:01 +02:00
parent c1653c7237
commit 919f31ffcb
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
4 changed files with 213 additions and 9 deletions

View file

@ -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
View file

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

View file

@ -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
View file

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