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"
" user\n"
" object\n",
ParameterDesc{{}, ParameterDesc::Flags::None, 4, 4},
ParameterDesc{
{ { "docstring", { true, "specify mapping description" } } },
ParameterDesc::Flags::None, 4, 4
},
CommandFlags::None,
CommandHelper{},
map_key_completer,
@ -1418,7 +1421,8 @@ const CommandDesc map_key_cmd = {
throw runtime_error("only a single key can be mapped");
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
(parser.positional_count() < 4 or
(keymaps.get_mapping(key[0], keymap_mode) ==
ConstArrayView<Key>{parse_keys(parser[3])})))
(keymaps.get_mapping(key[0], keymap_mode).keys ==
parse_keys(parser[3]))))
keymaps.unmap_key(key[0], keymap_mode);
}
};

View File

@ -1453,7 +1453,7 @@ void InputHandler::handle_key(Key key)
not m_context.keymaps_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);
}
else

View File

@ -3,12 +3,15 @@
#include "array_view.hh"
#include "assert.hh"
#include <algorithm>
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)
@ -23,13 +26,29 @@ bool KeymapManager::is_mapped(Key key, KeymapMode mode) const
(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});
if (it != m_mapping.end())
return { it->second };
return it->second;
kak_assert(m_parent);
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 "keys.hh"
#include "hash.hh"
#include "string.hh"
#include "unordered_map.hh"
#include "vector.hh"
@ -29,11 +30,19 @@ public:
KeymapManager(KeymapManager& parent) : m_parent(&parent) {}
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);
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:
KeymapManager()
: m_parent(nullptr) {}
@ -41,10 +50,8 @@ private:
friend class Scope;
KeymapManager* m_parent;
using KeyAndMode = std::pair<Key, KeymapMode>;
using Keymap = UnorderedMap<KeyAndMode, KeyList, MemoryDomain::Mapping>;
Keymap m_mapping;
UnorderedMap<KeyAndMode, KeyMapInfo, MemoryDomain::Mapping> m_mapping;
};
}

View File

@ -110,6 +110,49 @@ void repeat_last_select(Context& context, NormalParams)
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>
void goto_commands(Context& context, NormalParams params)
{
@ -233,18 +276,19 @@ void goto_commands(Context& context, NormalParams params)
}
}
}, "goto",
"g,k: buffer top \n"
"l: line end \n"
"h: line begin \n"
"i: line non blank start\n"
"j: buffer bottom \n"
"e: buffer end \n"
"t: window top \n"
"b: window bottom \n"
"c: window center \n"
"a: last buffer \n"
"f: file \n"
".: last buffer change \n");
build_autoinfo_for_mapping(context, KeymapMode::Goto,
{{{'g','k'},"buffer top"},
{{'l'}, "line end"},
{{'h'}, "line begin"},
{{'i'}, "line non blank start"},
{{'j'}, "buffer bottom"},
{{'e'}, "buffer end"},
{{'t'}, "window top"},
{{'b'}, "window bottom"},
{{'c'}, "window center"},
{{'a'}, "last buffer"},
{{'f'}, "file"},
{{'.'}, "last buffer change"}}));
}
}
@ -296,14 +340,15 @@ void view_commands(Context& context, NormalParams params)
break;
}
}, "view",
"v,c: center cursor (vertically)\n"
"m: center cursor (horizontally)\n"
"t: cursor on top \n"
"b: cursor on bottom\n"
"h: scroll left \n"
"j: scroll down \n"
"k: scroll up \n"
"l: scroll right \n");
build_autoinfo_for_mapping(context, KeymapMode::View,
{{{'v','c'}, "center cursor (vertically)"},
{{'m'}, "center cursor (horizontally)"},
{{'t'}, "cursor on top"},
{{'b'}, "cursor on bottom"},
{{'h'}, "scroll left"},
{{'j'}, "scroll down"},
{{'k'}, "scroll up"},
{{'l'}, "scroll right"}}));
}
void replace_with_char(Context& context, NormalParams)
@ -1085,22 +1130,23 @@ void select_object(Context& context, NormalParams params)
utf8cp, utf8cp, count, flags));
}
}, get_title(),
"b,(,): parenthesis block\n"
"B,{,}: braces block \n"
"r,[,]: brackets block \n"
"a,<,>: angle block \n"
"\",Q: double quote string\n"
"',q: single quote string\n"
"`,g: grave quote string \n"
"w: word \n"
"W: WORD \n"
"s: sentence \n"
"p: paragraph \n"
"␣: whitespaces \n"
"i: indent \n"
"u: argument \n"
"n: number \n"
":: custom object desc \n");
build_autoinfo_for_mapping(context, KeymapMode::Object,
{{{'b','(',')'}, "parenthesis block"},
{{'B','{','}'}, "braces block"},
{{'r','[',']'}, "brackets block"},
{{'a','<','>'}, "angle block"},
{{'"','Q'}, "double quote string"},
{{'\'','q'}, "single quote string"},
{{'`','g'}, "grave quote string"},
{{'w'}, "word"},
{{'W'}, "WORD"},
{{'s'}, "sentence"},
{{'p'}, "paragraph"},
{{' '}, "whitespaces"},
{{'i'}, "indent"},
{{'u'}, "argument"},
{{'n'}, "number"},
{{':'}, "custom object desc"}}));
}
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))
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());
InputHandler::ScopedForceNormal force_normal{context.input_handler(), params};
ScopedEdition edition(context);
for (auto& key : mapping)
for (auto& key : mapping.keys)
context.input_handler().handle_key(key);
}, "user mapping", "enter user key");
}, "user mapping",
build_autoinfo_for_mapping(context, KeymapMode::User, {}));
}
template<typename T>