summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2016-09-19 09:10:41 +0100
committerMaxime Coste <frrrwww@gmail.com>2016-09-19 09:10:41 +0100
commit396b71ecc2dd1f092195b8ad404ce38c4c5d8144 (patch)
treeb42f0e93c79117b38db45b581ddc060ac306f1a3
parent44e9da3beed9e4b5e5bbf2a10a465c77d61c0a48 (diff)
Add an unmap command to remove key mappings
-rw-r--r--README.asciidoc9
-rw-r--r--doc/manpages/commands.asciidoc13
-rw-r--r--src/array_view.hh19
-rw-r--r--src/commands.cc69
4 files changed, 93 insertions, 17 deletions
diff --git a/README.asciidoc b/README.asciidoc
index db933813..abcfdfcb 100644
--- a/README.asciidoc
+++ b/README.asciidoc
@@ -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
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
~~~~~~~~~~~~~~~~~
diff --git a/doc/manpages/commands.asciidoc b/doc/manpages/commands.asciidoc
index 06356f87..c52491b8 100644
--- a/doc/manpages/commands.asciidoc
+++ b/doc/manpages/commands.asciidoc
@@ -113,8 +113,17 @@ command *q!* has to be used).
define a new command (c.f. the 'Declaring new commands' section below)
*map* <scope> <mode> <key> <keys>::
- bind a combination of keys to another one (c.f. the 'commands'
- documentation page)
+ make *key* behave as if *keys* were typed. with *scope*
+ 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>::
execute a command whenever an event is triggered (c.f. the 'hooks'
diff --git a/src/array_view.hh b/src/array_view.hh
index 02844f70..1366805a 100644
--- a/src/array_view.hh
+++ b/src/array_view.hh
@@ -73,6 +73,25 @@ private:
template<typename 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
diff --git a/src/commands.cc b/src/commands.cc
index c96a302b..61bb0ab1 100644
--- a/src/commands.cc
+++ b/src/commands.cc
@@ -1328,6 +1328,23 @@ KeymapMode parse_keymap_mode(const String& 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 = {
"map",
nullptr,
@@ -1344,21 +1361,7 @@ const CommandDesc map_key_cmd = {
ParameterDesc{{}, ParameterDesc::Flags::None, 4, 4},
CommandFlags::None,
CommandHelper{},
- [](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 {};
- },
+ map_key_completer,
[](const ParametersParser& parser, Context& context, const ShellContext&)
{
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 = {
{ { "client", { true, "run in given client context" } },
{ "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(declare_option_cmd);
register_command(map_key_cmd);
+ register_command(unmap_key_cmd);
register_command(exec_string_cmd);
register_command(eval_string_cmd);
register_command(prompt_cmd);