Use menu behavior for completing builtins where appropriate
This allows to select completions without pressing Tab. There are two different obvious ways to add the menu bit. 1. When creating the "Completions" object, pass the Completions::Flags::Menu parameter. 2. If there is a completer function like "complete_scope", wrap it, e.g. "menu(complete_scope)". I have settled on always using 2 if there is a completer function and 1 otherwise. The advantage of 2 over 1 is that it allows to use the completer function in a context where we don't want the menu behavior (e.g. "complete-command"). --- Now the only* completion type where we usually don't use menu behavior is file completion. Unfortunately, menu behavior has poor interaction with directories' trailing slashes. Consider this (contrived) example: define-command ls -docstring "list directory contents" -params .. %{ echo -- %sh{ls "$@"} } complete-command -menu ls file Run ":ls kakoun<ret>". The prompt expands to ":ls kakoune/" before executing. Next, run ":<c-p>". This recalls ":ls kakoune/" and immediately selects the first completion, so on validation, the command will be ":ls kakoune/colors/", which is weird. [*] Also, expansions like %val{bufname} also don't use menu behavior. It wouldn't add value since validation doesn't add a closing delimiter. I have an experimental patch that adds closing delimiters automatically but I'm not sure if that's the right direction.
This commit is contained in:
parent
0b5dcf062f
commit
031de6d28c
|
@ -972,7 +972,7 @@ const CommandDesc arrange_buffers_cmd = {
|
||||||
CommandHelper{},
|
CommandHelper{},
|
||||||
[](const Context& context, CompletionFlags flags, CommandParameters params, size_t, ByteCount cursor_pos)
|
[](const Context& context, CompletionFlags flags, CommandParameters params, size_t, ByteCount cursor_pos)
|
||||||
{
|
{
|
||||||
return complete_buffer_name<false>(context, flags, params.back(), cursor_pos);
|
return menu(complete_buffer_name<false>)(context, flags, params.back(), cursor_pos);
|
||||||
},
|
},
|
||||||
[](const ParametersParser& parser, Context&, const ShellContext&)
|
[](const ParametersParser& parser, Context&, const ShellContext&)
|
||||||
{
|
{
|
||||||
|
@ -1094,7 +1094,7 @@ const CommandDesc add_hook_cmd = {
|
||||||
},
|
},
|
||||||
CommandFlags::None,
|
CommandFlags::None,
|
||||||
CommandHelper{},
|
CommandHelper{},
|
||||||
make_completer(menu(complete_scope),complete_hooks, complete_nothing,
|
make_completer(menu(complete_scope), menu(complete_hooks), complete_nothing,
|
||||||
[](const Context& context, CompletionFlags flags,
|
[](const Context& context, CompletionFlags flags,
|
||||||
StringView prefix, ByteCount cursor_pos)
|
StringView prefix, ByteCount cursor_pos)
|
||||||
{ return CommandManager::instance().complete(
|
{ return CommandManager::instance().complete(
|
||||||
|
@ -1138,7 +1138,8 @@ const CommandDesc remove_hook_cmd = {
|
||||||
{
|
{
|
||||||
if (auto scope = get_scope_ifp(params[0], context))
|
if (auto scope = get_scope_ifp(params[0], context))
|
||||||
return { 0_byte, params[0].length(),
|
return { 0_byte, params[0].length(),
|
||||||
scope->hooks().complete_hook_group(params[1], pos_in_token) };
|
scope->hooks().complete_hook_group(params[1], pos_in_token),
|
||||||
|
Completions::Flags::Menu };
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
|
@ -1478,7 +1479,7 @@ const CommandDesc debug_cmd = {
|
||||||
StringView prefix, ByteCount cursor_pos) -> Completions {
|
StringView prefix, ByteCount cursor_pos) -> Completions {
|
||||||
auto c = {"info", "buffers", "options", "memory", "shared-strings",
|
auto c = {"info", "buffers", "options", "memory", "shared-strings",
|
||||||
"profile-hash-maps", "faces", "mappings", "regex", "registers"};
|
"profile-hash-maps", "faces", "mappings", "regex", "registers"};
|
||||||
return { 0_byte, cursor_pos, complete(prefix, cursor_pos, c) };
|
return { 0_byte, cursor_pos, complete(prefix, cursor_pos, c), Completions::Flags::Menu };
|
||||||
}),
|
}),
|
||||||
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
||||||
{
|
{
|
||||||
|
@ -1682,7 +1683,8 @@ const CommandDesc set_option_cmd = {
|
||||||
return menu(complete_scope_including_current)(context, flags, params[0], pos_in_token);
|
return menu(complete_scope_including_current)(context, flags, params[0], pos_in_token);
|
||||||
else if (token_to_complete == 1)
|
else if (token_to_complete == 1)
|
||||||
return { 0_byte, params[1].length(),
|
return { 0_byte, params[1].length(),
|
||||||
GlobalScope::instance().option_registry().complete_option_name(params[1], pos_in_token) };
|
GlobalScope::instance().option_registry().complete_option_name(params[1], pos_in_token),
|
||||||
|
Completions::Flags::Menu };
|
||||||
else if (token_to_complete == 2 and params[2].empty() and
|
else if (token_to_complete == 2 and params[2].empty() and
|
||||||
GlobalScope::instance().option_registry().option_exists(params[1]))
|
GlobalScope::instance().option_registry().option_exists(params[1]))
|
||||||
{
|
{
|
||||||
|
@ -1718,7 +1720,8 @@ Completions complete_option(const Context& context, CompletionFlags flags,
|
||||||
return menu(complete_scope_no_global)(context, flags, params[0], pos_in_token);
|
return menu(complete_scope_no_global)(context, flags, params[0], pos_in_token);
|
||||||
else if (token_to_complete == 1)
|
else if (token_to_complete == 1)
|
||||||
return { 0_byte, params[1].length(),
|
return { 0_byte, params[1].length(),
|
||||||
GlobalScope::instance().option_registry().complete_option_name(params[1], pos_in_token) };
|
GlobalScope::instance().option_registry().complete_option_name(params[1], pos_in_token),
|
||||||
|
Completions::Flags::Menu };
|
||||||
return Completions{};
|
return Completions{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1786,7 +1789,7 @@ const CommandDesc declare_option_cmd = {
|
||||||
[](const Context& context, CompletionFlags flags,
|
[](const Context& context, CompletionFlags flags,
|
||||||
StringView prefix, ByteCount cursor_pos) -> Completions {
|
StringView prefix, ByteCount cursor_pos) -> Completions {
|
||||||
auto c = {"int", "bool", "str", "regex", "int-list", "str-list", "completions", "line-specs", "range-specs", "str-to-str-map"};
|
auto c = {"int", "bool", "str", "regex", "int-list", "str-list", "completions", "line-specs", "range-specs", "str-to-str-map"};
|
||||||
return { 0_byte, cursor_pos, complete(prefix, cursor_pos, c) };
|
return { 0_byte, cursor_pos, complete(prefix, cursor_pos, c), Completions::Flags::Menu };
|
||||||
}),
|
}),
|
||||||
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
||||||
{
|
{
|
||||||
|
@ -1839,7 +1842,8 @@ static Completions map_key_completer(const Context& context, CompletionFlags fla
|
||||||
{
|
{
|
||||||
auto& user_modes = get_scope(params[0], context).keymaps().user_modes();
|
auto& user_modes = get_scope(params[0], context).keymaps().user_modes();
|
||||||
return { 0_byte, params[1].length(),
|
return { 0_byte, params[1].length(),
|
||||||
complete(params[1], pos_in_token, concatenated(modes, user_modes)) };
|
complete(params[1], pos_in_token, concatenated(modes, user_modes)),
|
||||||
|
Completions::Flags::Menu };
|
||||||
}
|
}
|
||||||
if (unmap and token_to_complete == 2)
|
if (unmap and token_to_complete == 2)
|
||||||
{
|
{
|
||||||
|
@ -1850,7 +1854,8 @@ static Completions map_key_completer(const Context& context, CompletionFlags fla
|
||||||
return { 0_byte, params[2].length(),
|
return { 0_byte, params[2].length(),
|
||||||
complete(params[2], pos_in_token,
|
complete(params[2], pos_in_token,
|
||||||
keys | transform([](Key k) { return key_to_str(k); })
|
keys | transform([](Key k) { return key_to_str(k); })
|
||||||
| gather<Vector<String>>()) };
|
| gather<Vector<String>>()),
|
||||||
|
Completions::Flags::Menu };
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -2465,7 +2470,7 @@ const CommandDesc unset_face_cmd = {
|
||||||
double_params,
|
double_params,
|
||||||
CommandFlags::None,
|
CommandFlags::None,
|
||||||
face_doc_helper,
|
face_doc_helper,
|
||||||
make_completer(menu(complete_scope), complete_face),
|
make_completer(menu(complete_scope), menu(complete_face)),
|
||||||
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
||||||
{
|
{
|
||||||
get_scope(parser[0], context).faces().remove_face(parser[1]);
|
get_scope(parser[0], context).faces().remove_face(parser[1]);
|
||||||
|
@ -2653,7 +2658,8 @@ const CommandDesc enter_user_mode_cmd = {
|
||||||
if (token_to_complete == 0)
|
if (token_to_complete == 0)
|
||||||
{
|
{
|
||||||
return { 0_byte, params[0].length(),
|
return { 0_byte, params[0].length(),
|
||||||
complete(params[0], pos_in_token, context.keymaps().user_modes()) };
|
complete(params[0], pos_in_token, context.keymaps().user_modes()),
|
||||||
|
Completions::Flags::Menu };
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
|
@ -2698,10 +2704,10 @@ const CommandDesc require_module_cmd = {
|
||||||
single_param,
|
single_param,
|
||||||
CommandFlags::None,
|
CommandFlags::None,
|
||||||
CommandHelper{},
|
CommandHelper{},
|
||||||
make_completer(
|
make_completer(menu(
|
||||||
[](const Context&, CompletionFlags, StringView prefix, ByteCount cursor_pos) {
|
[](const Context&, CompletionFlags, StringView prefix, ByteCount cursor_pos) {
|
||||||
return CommandManager::instance().complete_module_name(prefix.substr(0, cursor_pos));
|
return CommandManager::instance().complete_module_name(prefix.substr(0, cursor_pos));
|
||||||
}),
|
})),
|
||||||
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
||||||
{
|
{
|
||||||
CommandManager::instance().load_module(parser[0], context);
|
CommandManager::instance().load_module(parser[0], context);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user