Add docstring support for mappings, and use them in autoinfo

Fixes #105
Fixes #1100
Closes #1165
This commit is contained in:
Maxime Coste 2017-03-03 16:51:29 +00:00
parent 7d487e3b4c
commit e3cfde6d07
5 changed files with 130 additions and 53 deletions

View File

@ -1404,7 +1404,10 @@ const CommandDesc map_key_cmd = {
" view\n" " view\n"
" user\n" " user\n"
" object\n", " object\n",
ParameterDesc{{}, ParameterDesc::Flags::None, 4, 4}, ParameterDesc{
{ { "docstring", { true, "specify mapping description" } } },
ParameterDesc::Flags::None, 4, 4
},
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
map_key_completer, map_key_completer,
@ -1418,7 +1421,8 @@ const CommandDesc map_key_cmd = {
throw runtime_error("only a single key can be mapped"); throw runtime_error("only a single key can be mapped");
KeyList mapping = parse_keys(parser[3]); KeyList mapping = parse_keys(parser[3]);
keymaps.map_key(key[0], keymap_mode, std::move(mapping)); keymaps.map_key(key[0], keymap_mode, std::move(mapping),
parser.get_switch("docstring").value_or("").str());
} }
}; };
@ -1451,8 +1455,8 @@ const CommandDesc unmap_key_cmd = {
if (keymaps.is_mapped(key[0], keymap_mode) and if (keymaps.is_mapped(key[0], keymap_mode) and
(parser.positional_count() < 4 or (parser.positional_count() < 4 or
(keymaps.get_mapping(key[0], keymap_mode) == (keymaps.get_mapping(key[0], keymap_mode).keys ==
ConstArrayView<Key>{parse_keys(parser[3])}))) parse_keys(parser[3]))))
keymaps.unmap_key(key[0], keymap_mode); keymaps.unmap_key(key[0], keymap_mode);
} }
}; };

View File

@ -1453,7 +1453,7 @@ void InputHandler::handle_key(Key key)
not m_context.keymaps_disabled()) not m_context.keymaps_disabled())
{ {
ScopedSetBool disable_history{context().history_disabled()}; ScopedSetBool disable_history{context().history_disabled()};
for (auto& k : keymaps.get_mapping(key, keymap_mode)) for (auto& k : keymaps.get_mapping(key, keymap_mode).keys)
current_mode().handle_key(k); current_mode().handle_key(k);
} }
else else

View File

@ -3,12 +3,15 @@
#include "array_view.hh" #include "array_view.hh"
#include "assert.hh" #include "assert.hh"
#include <algorithm>
namespace Kakoune namespace Kakoune
{ {
void KeymapManager::map_key(Key key, KeymapMode mode, KeyList mapping) void KeymapManager::map_key(Key key, KeymapMode mode,
KeyList mapping, String docstring)
{ {
m_mapping[{key, mode}] = std::move(mapping); m_mapping[{key, mode}] = {std::move(mapping), std::move(docstring)};
} }
void KeymapManager::unmap_key(Key key, KeymapMode mode) void KeymapManager::unmap_key(Key key, KeymapMode mode)
@ -23,13 +26,29 @@ bool KeymapManager::is_mapped(Key key, KeymapMode mode) const
(m_parent and m_parent->is_mapped(key, mode)); (m_parent and m_parent->is_mapped(key, mode));
} }
ConstArrayView<Key> KeymapManager::get_mapping(Key key, KeymapMode mode) const const KeymapManager::KeyMapInfo&
KeymapManager::get_mapping(Key key, KeymapMode mode) const
{ {
auto it = m_mapping.find({key, mode}); auto it = m_mapping.find({key, mode});
if (it != m_mapping.end()) if (it != m_mapping.end())
return { it->second }; return it->second;
kak_assert(m_parent); kak_assert(m_parent);
return m_parent->get_mapping(key, mode); return m_parent->get_mapping(key, mode);
} }
KeymapManager::KeyList KeymapManager::get_mapped_keys(KeymapMode mode) const
{
KeyList res;
if (m_parent)
res = m_parent->get_mapped_keys(mode);
for (auto& map : m_mapping)
{
if (map.first.second == mode)
res.emplace_back(map.first.first);
}
std::sort(res.begin(), res.end());
res.erase(std::unique(res.begin(), res.end()), res.end());
return res;
}
} }

View File

@ -4,6 +4,7 @@
#include "array_view.hh" #include "array_view.hh"
#include "keys.hh" #include "keys.hh"
#include "hash.hh" #include "hash.hh"
#include "string.hh"
#include "unordered_map.hh" #include "unordered_map.hh"
#include "vector.hh" #include "vector.hh"
@ -29,11 +30,19 @@ public:
KeymapManager(KeymapManager& parent) : m_parent(&parent) {} KeymapManager(KeymapManager& parent) : m_parent(&parent) {}
using KeyList = Vector<Key, MemoryDomain::Mapping>; using KeyList = Vector<Key, MemoryDomain::Mapping>;
void map_key(Key key, KeymapMode mode, KeyList mapping); void map_key(Key key, KeymapMode mode, KeyList mapping, String docstring);
void unmap_key(Key key, KeymapMode mode); void unmap_key(Key key, KeymapMode mode);
bool is_mapped(Key key, KeymapMode mode) const; bool is_mapped(Key key, KeymapMode mode) const;
ConstArrayView<Key> get_mapping(Key key, KeymapMode mode) const; KeyList get_mapped_keys(KeymapMode mode) const;
struct KeyMapInfo
{
KeyList keys;
String docstring;
};
const KeyMapInfo& get_mapping(Key key, KeymapMode mode) const;
private: private:
KeymapManager() KeymapManager()
: m_parent(nullptr) {} : m_parent(nullptr) {}
@ -41,10 +50,8 @@ private:
friend class Scope; friend class Scope;
KeymapManager* m_parent; KeymapManager* m_parent;
using KeyAndMode = std::pair<Key, KeymapMode>; using KeyAndMode = std::pair<Key, KeymapMode>;
using Keymap = UnorderedMap<KeyAndMode, KeyList, MemoryDomain::Mapping>; UnorderedMap<KeyAndMode, KeyMapInfo, MemoryDomain::Mapping> m_mapping;
Keymap m_mapping;
}; };
} }

View File

@ -110,6 +110,49 @@ void repeat_last_select(Context& context, NormalParams)
context.repeat_last_select(); context.repeat_last_select();
} }
struct KeyInfo
{
ConstArrayView<Key> keys;
StringView docstring;
};
String build_autoinfo_for_mapping(Context& context, KeymapMode mode,
ConstArrayView<KeyInfo> built_ins)
{
auto& keymaps = context.keymaps();
Vector<std::pair<String, StringView>> descs;
for (auto& built_in : built_ins)
{
String keys = join(built_in.keys |
filter([&](Key k){ return not keymaps.is_mapped(k, mode); }) |
transform([](Key k) { return key_to_str(k); }),
',', false);
if (not keys.empty())
descs.emplace_back(std::move(keys), built_in.docstring);
}
for (auto& key : keymaps.get_mapped_keys(mode))
descs.emplace_back(key_to_str(key),
keymaps.get_mapping(key, mode).docstring);
auto max_len = 0_col;
for (auto& desc : descs)
{
auto len = desc.first.column_length();
if (len > max_len)
max_len = len;
}
String res;
for (auto& desc : descs)
res += format("{}:{}{}\n",
desc.first,
String{' ', max_len - desc.first.column_length() + 1},
desc.second);
return res;
}
template<SelectMode mode> template<SelectMode mode>
void goto_commands(Context& context, NormalParams params) void goto_commands(Context& context, NormalParams params)
{ {
@ -233,18 +276,19 @@ void goto_commands(Context& context, NormalParams params)
} }
} }
}, "goto", }, "goto",
"g,k: buffer top \n" build_autoinfo_for_mapping(context, KeymapMode::Goto,
"l: line end \n" {{{'g','k'},"buffer top"},
"h: line begin \n" {{'l'}, "line end"},
"i: line non blank start\n" {{'h'}, "line begin"},
"j: buffer bottom \n" {{'i'}, "line non blank start"},
"e: buffer end \n" {{'j'}, "buffer bottom"},
"t: window top \n" {{'e'}, "buffer end"},
"b: window bottom \n" {{'t'}, "window top"},
"c: window center \n" {{'b'}, "window bottom"},
"a: last buffer \n" {{'c'}, "window center"},
"f: file \n" {{'a'}, "last buffer"},
".: last buffer change \n"); {{'f'}, "file"},
{{'.'}, "last buffer change"}}));
} }
} }
@ -296,14 +340,15 @@ void view_commands(Context& context, NormalParams params)
break; break;
} }
}, "view", }, "view",
"v,c: center cursor (vertically)\n" build_autoinfo_for_mapping(context, KeymapMode::View,
"m: center cursor (horizontally)\n" {{{'v','c'}, "center cursor (vertically)"},
"t: cursor on top \n" {{'m'}, "center cursor (horizontally)"},
"b: cursor on bottom\n" {{'t'}, "cursor on top"},
"h: scroll left \n" {{'b'}, "cursor on bottom"},
"j: scroll down \n" {{'h'}, "scroll left"},
"k: scroll up \n" {{'j'}, "scroll down"},
"l: scroll right \n"); {{'k'}, "scroll up"},
{{'l'}, "scroll right"}}));
} }
void replace_with_char(Context& context, NormalParams) void replace_with_char(Context& context, NormalParams)
@ -1085,22 +1130,23 @@ void select_object(Context& context, NormalParams params)
utf8cp, utf8cp, count, flags)); utf8cp, utf8cp, count, flags));
} }
}, get_title(), }, get_title(),
"b,(,): parenthesis block\n" build_autoinfo_for_mapping(context, KeymapMode::Object,
"B,{,}: braces block \n" {{{'b','(',')'}, "parenthesis block"},
"r,[,]: brackets block \n" {{'B','{','}'}, "braces block"},
"a,<,>: angle block \n" {{'r','[',']'}, "brackets block"},
"\",Q: double quote string\n" {{'a','<','>'}, "angle block"},
"',q: single quote string\n" {{'"','Q'}, "double quote string"},
"`,g: grave quote string \n" {{'\'','q'}, "single quote string"},
"w: word \n" {{'`','g'}, "grave quote string"},
"W: WORD \n" {{'w'}, "word"},
"s: sentence \n" {{'W'}, "WORD"},
"p: paragraph \n" {{'s'}, "sentence"},
"␣: whitespaces \n" {{'p'}, "paragraph"},
"i: indent \n" {{' '}, "whitespaces"},
"u: argument \n" {{'i'}, "indent"},
"n: number \n" {{'u'}, "argument"},
":: custom object desc \n"); {{'n'}, "number"},
{{':'}, "custom object desc"}}));
} }
template<Direction direction, bool half = false> template<Direction direction, bool half = false>
@ -1588,15 +1634,16 @@ void exec_user_mappings(Context& context, NormalParams params)
if (not context.keymaps().is_mapped(key, KeymapMode::User)) if (not context.keymaps().is_mapped(key, KeymapMode::User))
return; return;
auto mapping = context.keymaps().get_mapping(key, KeymapMode::User); auto& mapping = context.keymaps().get_mapping(key, KeymapMode::User);
ScopedSetBool disable_keymaps(context.keymaps_disabled()); ScopedSetBool disable_keymaps(context.keymaps_disabled());
InputHandler::ScopedForceNormal force_normal{context.input_handler(), params}; InputHandler::ScopedForceNormal force_normal{context.input_handler(), params};
ScopedEdition edition(context); ScopedEdition edition(context);
for (auto& key : mapping) for (auto& key : mapping.keys)
context.input_handler().handle_key(key); context.input_handler().handle_key(key);
}, "user mapping", "enter user key"); }, "user mapping",
build_autoinfo_for_mapping(context, KeymapMode::User, {}));
} }
template<typename T> template<typename T>