Add an unmap command to remove key mappings

This commit is contained in:
Maxime Coste 2016-09-19 09:10:41 +01:00
parent 44e9da3bee
commit 396b71ecc2
4 changed files with 93 additions and 17 deletions

View File

@ -1402,6 +1402,15 @@ a single key name and `keys` a list of keys.
`user` mode allows for user mapping behind the `,` key. Keys will be executed in `user` mode allows for user mapping behind the `,` key. Keys will be executed in
normal mode. normal mode.
Mappings can be removed with the unmap command
----------------------------------------
:unmap <scope> <mode> <key> [<expected>]
----------------------------------------
If `<expected>` is specified, unmapping will only proceed if the current
mapping matches the expected keys.
Defining Commands Defining Commands
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~

View File

@ -113,8 +113,17 @@ command *q!* has to be used).
define a new command (c.f. the 'Declaring new commands' section below) define a new command (c.f. the 'Declaring new commands' section below)
*map* <scope> <mode> <key> <keys>:: *map* <scope> <mode> <key> <keys>::
bind a combination of keys to another one (c.f. the 'commands' make *key* behave as if *keys* were typed. with *scope*
documentation page) being one of *global*, *buffer* or *window*, *mode* being
*insert*, *normal*, *prompt*, *menu* or *user*.
*user* mode allows for user mapping behind the *,* key. Keys
will be executed in normal mode.
*unmap* <scope> <mode> <key> [<expected>]::
remove the mapping of *key* in given *scope* and *mode*, if
expected is specified, only remove the mapping it if matches
the expected keys.
*hook* [-group <group>] <scope> <hook_name> <filtering_regex> <command>:: *hook* [-group <group>] <scope> <hook_name> <filtering_regex> <command>::
execute a command whenever an event is triggered (c.f. the 'hooks' execute a command whenever an event is triggered (c.f. the 'hooks'

View File

@ -73,6 +73,25 @@ private:
template<typename T> template<typename T>
using ConstArrayView = ArrayView<const T>; using ConstArrayView = ArrayView<const T>;
template<typename T>
bool operator==(ArrayView<T> lhs, ArrayView<T> rhs)
{
if (lhs.size() != rhs.size())
return false;
for (int i = 0; i < lhs.size(); ++i)
{
if (lhs[i] != rhs[i])
return false;
}
return true;
}
template<typename T>
bool operator!=(ArrayView<T> lhs, ArrayView<T> rhs)
{
return not (lhs == rhs);
}
} }
#endif // array_view_hh_INCLUDED #endif // array_view_hh_INCLUDED

View File

@ -1328,6 +1328,23 @@ KeymapMode parse_keymap_mode(const String& str)
throw runtime_error(format("unknown keymap mode '{}'", str)); throw runtime_error(format("unknown keymap mode '{}'", str));
} }
auto map_key_completer =
[](const Context& context, CompletionFlags flags,
CommandParameters params, size_t token_to_complete,
ByteCount pos_in_token) -> Completions
{
if (token_to_complete == 0)
return { 0_byte, params[0].length(),
complete(params[0], pos_in_token, scopes) };
if (token_to_complete == 1)
{
constexpr const char* modes[] = { "normal", "insert", "menu", "prompt", "goto", "view", "user", "object" };
return { 0_byte, params[1].length(),
complete(params[1], pos_in_token, modes) };
}
return {};
};
const CommandDesc map_key_cmd = { const CommandDesc map_key_cmd = {
"map", "map",
nullptr, nullptr,
@ -1344,21 +1361,7 @@ const CommandDesc map_key_cmd = {
ParameterDesc{{}, ParameterDesc::Flags::None, 4, 4}, ParameterDesc{{}, ParameterDesc::Flags::None, 4, 4},
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
[](const Context& context, CompletionFlags flags, map_key_completer,
CommandParameters params, size_t token_to_complete,
ByteCount pos_in_token) -> Completions
{
if (token_to_complete == 0)
return { 0_byte, params[0].length(),
complete(params[0], pos_in_token, scopes) };
if (token_to_complete == 1)
{
constexpr const char* modes[] = { "normal", "insert", "menu", "prompt", "goto", "view", "user", "object" };
return { 0_byte, params[1].length(),
complete(params[1], pos_in_token, modes) };
}
return {};
},
[](const ParametersParser& parser, Context& context, const ShellContext&) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
KeymapManager& keymaps = get_scope(parser[0], context).keymaps(); KeymapManager& keymaps = get_scope(parser[0], context).keymaps();
@ -1373,6 +1376,41 @@ const CommandDesc map_key_cmd = {
} }
}; };
const CommandDesc unmap_key_cmd = {
"unmap",
nullptr,
"unmap <scope> <mode> <key> [<expected-keys>]: unmap <key> from given mode in <scope>.\n"
"If <expected> is specified, remove the mapping only if its value is <expected>\n"
"<mode> can be:\n"
" normal\n"
" insert\n"
" menu\n"
" prompt\n"
" goto\n"
" view\n"
" user\n"
" object\n",
ParameterDesc{{}, ParameterDesc::Flags::None, 4, 4},
CommandFlags::None,
CommandHelper{},
map_key_completer,
[](const ParametersParser& parser, Context& context, const ShellContext&)
{
KeymapManager& keymaps = get_scope(parser[0], context).keymaps();
KeymapMode keymap_mode = parse_keymap_mode(parser[1]);
KeyList key = parse_keys(parser[2]);
if (key.size() != 1)
throw runtime_error("only a single key can be mapped");
if (keymaps.is_mapped(key[0], keymap_mode) and
(parser.positional_count() < 4 or
(keymaps.get_mapping(key[0], keymap_mode) ==
ConstArrayView<Key>{parse_keys(parser[3])})))
keymaps.unmap_key(key[0], keymap_mode);
}
};
const ParameterDesc context_wrap_params = { const ParameterDesc context_wrap_params = {
{ { "client", { true, "run in given client context" } }, { { "client", { true, "run in given client context" } },
{ "try-client", { true, "run in given client context if it exists, or else in the current one" } }, { "try-client", { true, "run in given client context if it exists, or else in the current one" } },
@ -2001,6 +2039,7 @@ void register_commands()
register_command(unset_option_cmd); register_command(unset_option_cmd);
register_command(declare_option_cmd); register_command(declare_option_cmd);
register_command(map_key_cmd); register_command(map_key_cmd);
register_command(unmap_key_cmd);
register_command(exec_string_cmd); register_command(exec_string_cmd);
register_command(eval_string_cmd); register_command(eval_string_cmd);
register_command(prompt_cmd); register_command(prompt_cmd);