Refactor highlighter command completions

This commit is contained in:
Maxime Coste 2014-06-15 16:04:38 +01:00
parent e0cd8ad93c
commit 205e8b2889
6 changed files with 191 additions and 85 deletions

View File

@ -350,39 +350,70 @@ const CommandDesc namebuf_cmd = {
} }
}; };
template<typename GetRootGroup> Completions complete_highlighter_group(const Context& context,
CommandCompleter group_rm_completer(GetRootGroup get_root_group) StringView arg, ByteCount pos_in_token)
{ {
return [=](const Context& context, CompletionFlags flags, const bool shared = not arg.empty() and arg[0] == '/';
CommandParameters params, size_t token_to_complete, if (shared)
ByteCount pos_in_token) -> Completions { {
auto& root_group = get_root_group(context); auto& group = DefinedHighlighters::instance();
const String& arg = params[token_to_complete]; return offset_pos(group.complete_group_id(arg.substr(1_byte), pos_in_token-1), 1);
if (token_to_complete == 1 and params[0] == "-group") }
return { 0_byte, arg.length(), root_group.complete_group_id(arg, pos_in_token) }; else
else if (token_to_complete == 2 and params[0] == "-group") {
return { 0_byte, arg.length(), root_group.get_group(params[1], '/').complete_id(arg, pos_in_token) }; auto& group = context.window().highlighters();
return { 0_byte, arg.length(), root_group.complete_id(arg, pos_in_token) }; return group.complete_group_id(arg, pos_in_token);
}; }
} }
template<typename FactoryRegistry, typename GetRootGroup> Completions rm_highlighter_completer(
CommandCompleter group_add_completer(GetRootGroup get_root_group) const Context& context, CompletionFlags flags, CommandParameters params,
size_t token_to_complete, ByteCount pos_in_token)
{ {
return [=](const Context& context, CompletionFlags flags, const String& arg = params[token_to_complete];
CommandParameters params, size_t token_to_complete, if (token_to_complete == 0 and not arg.empty() and arg.front() == '/')
ByteCount pos_in_token) -> Completions { {
auto& root_group = get_root_group(context); auto& group = DefinedHighlighters::instance();
const String& arg = params[token_to_complete]; return offset_pos(group.complete_id(arg.substr(1_byte), pos_in_token-1), 1);
if (token_to_complete == 1 and params[0] == "-group") }
return { 0_byte, arg.length(), root_group.complete_group_id(arg, pos_in_token) }; else if (token_to_complete == 0)
else if (token_to_complete == 0 or (token_to_complete == 2 and params[0] == "-group")) return context.window().highlighters().complete_id(arg, pos_in_token);
return { 0_byte, arg.length(), FactoryRegistry::instance().complete_name(arg, pos_in_token) }; return {};
return Completions{};
};
} }
HighlighterGroup& get_highlighters(const Context& c) { return c.window().highlighters(); } Completions add_highlighter_completer(
const Context& context, CompletionFlags flags, CommandParameters params,
size_t token_to_complete, ByteCount pos_in_token)
{
StringView arg = params[token_to_complete];
if (token_to_complete == 1 and params[0] == "-group")
return complete_highlighter_group(context, params[1], pos_in_token);
else if (token_to_complete == 0 or (token_to_complete == 2 and params[0] == "-group"))
return { 0_byte, arg.length(), HighlighterRegistry::instance().complete_name(arg, pos_in_token) };
return Completions{};
}
HighlighterGroup& get_highlighter_group(const Context& context, StringView path)
{
if (path.empty())
throw runtime_error("group path should not be empty");
HighlighterGroup* group = nullptr;
if (path[0] == '/')
{
group = &DefinedHighlighters::instance();
path = path.substr(1_byte);
}
else
group = &context.window().highlighters();
if (path.back() == '/')
path = path.substr(0_byte, path.length() - 1);
if (not path.empty())
return group->get_group(path);
return *group;
}
const CommandDesc add_highlighter_cmd = { const CommandDesc add_highlighter_cmd = {
"addhl", "addhl",
@ -393,7 +424,7 @@ const CommandDesc add_highlighter_cmd = {
SwitchMap{ { "group", { true, "specify the group in which to put the highlighter" } } }, SwitchMap{ { "group", { true, "specify the group in which to put the highlighter" } } },
ParameterDesc::Flags::SwitchesOnlyAtStart, 1 }, ParameterDesc::Flags::SwitchesOnlyAtStart, 1 },
CommandFlags::None, CommandFlags::None,
group_add_completer<HighlighterRegistry>(get_highlighters), add_highlighter_completer,
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
HighlighterRegistry& registry = HighlighterRegistry::instance(); HighlighterRegistry& registry = HighlighterRegistry::instance();
@ -404,48 +435,32 @@ const CommandDesc add_highlighter_cmd = {
for (; begin != parser.end(); ++begin) for (; begin != parser.end(); ++begin)
highlighter_params.push_back(*begin); highlighter_params.push_back(*begin);
HighlighterGroup* group = nullptr; auto& group = (parser.has_option("group")) ?
if (parser.has_option("group")) get_highlighter_group(context, parser.option_value("group"))
{ : context.window().highlighters();
StringView path = parser.option_value("group"); group.append(registry[name](highlighter_params));
if (path.empty())
throw runtime_error("group param should not be empty");
if (path[0] == '/')
{
group = &DefinedHighlighters::instance();
path = path.substr(1_byte);
}
else
group = &context.window().highlighters();
if (not path.empty())
group = &group->get_group(path, '/');
}
else
group = &context.window().highlighters();
group->append(registry[name](highlighter_params));
} }
}; };
const CommandDesc rm_highlighter_cmd = { const CommandDesc rm_highlighter_cmd = {
"rmhl", "rmhl",
"rh", "rh",
"rmhl <switches> <name>: remove highlighter <name> from current window", "rmhl <path>: remove highlighter <name>",
ParameterDesc{ ParameterDesc{
SwitchMap{ { "group", { true, "remove highlighter from given group" } } }, SwitchMap{},
ParameterDesc::Flags::None, 1, 1 ParameterDesc::Flags::None, 1, 1
}, },
CommandFlags::None, CommandFlags::None,
group_rm_completer(get_highlighters), rm_highlighter_completer,
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
HighlighterGroup& window_hl = context.window().highlighters(); StringView path = parser[0];
HighlighterGroup& group = parser.has_option("group") ? auto sep_it = find(reversed(path), '/');
window_hl.get_group(parser.option_value("group"), '/') auto& group = sep_it != path.rend() ?
: window_hl; get_highlighter_group(context, {path.begin(), sep_it.base()-1})
: context.window().highlighters();
group.remove(parser[0]); group.remove({sep_it.base(), path.end()});
} }
}; };

View File

@ -47,5 +47,11 @@ inline Completions complete_nothing(const Context& context, CompletionFlags,
Completions shell_complete(const Context& context, CompletionFlags, Completions shell_complete(const Context& context, CompletionFlags,
StringView, ByteCount cursor_pos); StringView, ByteCount cursor_pos);
inline Completions offset_pos(Completions completion, ByteCount offset)
{
return { completion.start + offset, completion.end + offset,
std::move(completion.candidates) };
}
} }
#endif // completion_hh_INCLUDED #endif // completion_hh_INCLUDED

View File

@ -3,6 +3,9 @@
namespace Kakoune namespace Kakoune
{ {
static constexpr Codepoint path_separator = '/';
void HighlighterGroup::operator()(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer) const void HighlighterGroup::operator()(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer) const
{ {
for (auto& hl : m_highlighters) for (auto& hl : m_highlighters)
@ -21,9 +24,9 @@ void HighlighterGroup::remove(StringView id)
m_highlighters.remove(id); m_highlighters.remove(id);
} }
HighlighterGroup& HighlighterGroup::get_group(StringView path, Codepoint path_separator) HighlighterGroup& HighlighterGroup::get_group(StringView path)
{ {
auto sep_it = std::find(path.begin(), path.end(), path_separator); auto sep_it = find(path, path_separator);
StringView id(path.begin(), sep_it); StringView id(path.begin(), sep_it);
auto it = m_highlighters.find(id); auto it = m_highlighters.find(id);
if (it == m_highlighters.end()) if (it == m_highlighters.end())
@ -31,22 +34,22 @@ HighlighterGroup& HighlighterGroup::get_group(StringView path, Codepoint path_se
if (auto* group = it->second.target<HighlighterGroup>()) if (auto* group = it->second.target<HighlighterGroup>())
{ {
if (sep_it != path.end()) if (sep_it != path.end())
return group->get_group({sep_it+1, path.end()}, path_separator); return group->get_group({sep_it+1, path.end()});
return *group; return *group;
} }
else if (auto* hier_group = it->second.target<HierachicalHighlighter>()) else if (auto* hier_group = it->second.target<HierachicalHighlighter>())
{ {
if (sep_it == path.end()) if (sep_it == path.end())
throw group_not_found("not a leaf group: "_str + id); throw group_not_found("not a leaf group: "_str + id);
return hier_group->get_group({sep_it+1, path.end()}, path_separator); return hier_group->get_group({sep_it+1, path.end()});
} }
else else
throw group_not_found("not a group: "_str + id); throw group_not_found("not a group: "_str + id);
} }
HighlighterFunc HighlighterGroup::get_highlighter(StringView path, Codepoint path_separator) const HighlighterFunc HighlighterGroup::get_highlighter(StringView path) const
{ {
auto sep_it = std::find(path.begin(), path.end(), path_separator); auto sep_it = find(path, path_separator);
StringView id(path.begin(), sep_it); StringView id(path.begin(), sep_it);
auto it = m_highlighters.find(id); auto it = m_highlighters.find(id);
if (it == m_highlighters.end()) if (it == m_highlighters.end())
@ -54,50 +57,117 @@ HighlighterFunc HighlighterGroup::get_highlighter(StringView path, Codepoint pat
if (sep_it == path.end()) if (sep_it == path.end())
return HighlighterFunc{std::ref(it->second)}; return HighlighterFunc{std::ref(it->second)};
else if (auto* group = it->second.target<HighlighterGroup>()) else if (auto* group = it->second.target<HighlighterGroup>())
return group->get_highlighter({sep_it+1, path.end()}, path_separator); return group->get_highlighter({sep_it+1, path.end()});
else if (auto* hier_group = it->second.target<HierachicalHighlighter>()) else if (auto* hier_group = it->second.target<HierachicalHighlighter>())
return hier_group->get_highlighter({sep_it+1, path.end()}, path_separator); return hier_group->get_highlighter({sep_it+1, path.end()});
else else
throw group_not_found("not a group: "_str + id); throw group_not_found("not a group: "_str + id);
} }
CandidateList HighlighterGroup::complete_id(StringView prefix, ByteCount cursor_pos) const Completions HighlighterGroup::complete_id(StringView path, ByteCount cursor_pos) const
{ {
return m_highlighters.complete_id(prefix, cursor_pos); auto sep_it = find(path, path_separator);
StringView id(path.begin(), sep_it);
if (sep_it == path.end())
return { 0_byte, id.length(), m_highlighters.complete_id(id, cursor_pos) };
auto it = m_highlighters.find(id);
if (it != m_highlighters.end())
{
const ByteCount offset = (int)(sep_it + 1 - path.begin());
cursor_pos -= offset;
if (auto* group = it->second.target<HighlighterGroup>())
return offset_pos(group->complete_id({sep_it+1, path.end()}, cursor_pos), offset);
if (auto* hier_group = it->second.target<HierachicalHighlighter>())
return offset_pos(hier_group->complete_id({sep_it+1, path.end()}, cursor_pos), offset);
}
return {};
} }
CandidateList HighlighterGroup::complete_group_id(StringView prefix, ByteCount cursor_pos) const Completions HighlighterGroup::complete_group_id(StringView path, ByteCount cursor_pos) const
{ {
return m_highlighters.complete_id_if( auto sep_it = find(path, path_separator);
prefix, cursor_pos, [](const HighlighterAndId& func) { StringView id(path.begin(), sep_it);
return func.second.template target<HighlighterGroup>() != nullptr; if (sep_it == path.end())
}); return { 0_byte, path.length(), m_highlighters.complete_id_if(
path, cursor_pos, [](const HighlighterAndId& func) {
return func.second.template target<HighlighterGroup>() or
func.second.template target<HierachicalHighlighter>();
}) };
auto it = m_highlighters.find(id);
if (it != m_highlighters.end())
{
const ByteCount offset = (int)(sep_it + 1 - path.begin());
cursor_pos -= offset;
if (auto* group = it->second.target<HighlighterGroup>())
return offset_pos(group->complete_group_id({sep_it+1, path.end()}, cursor_pos), offset);
if (auto* hier_group = it->second.target<HierachicalHighlighter>())
return offset_pos(hier_group->complete_group_id({sep_it+1, path.end()}, cursor_pos), offset);
}
return {};
} }
HighlighterGroup& HierachicalHighlighter::get_group(StringView path, Codepoint path_separator) HighlighterGroup& HierachicalHighlighter::get_group(StringView path)
{ {
auto sep_it = std::find(path.begin(), path.end(), path_separator); auto sep_it = find(path, path_separator);
StringView id(path.begin(), sep_it); StringView id(path.begin(), sep_it);
auto it = m_groups.find(id); auto it = m_groups.find(id);
if (it == m_groups.end()) if (it == m_groups.end())
throw group_not_found("no such id: "_str + id); throw group_not_found("no such id: "_str + id);
if (sep_it != path.end()) if (sep_it != path.end())
return it->second.get_group(StringView(sep_it+1, path.end()), path_separator); return it->second.get_group(StringView(sep_it+1, path.end()));
else else
return it->second; return it->second;
} }
HighlighterFunc HierachicalHighlighter::get_highlighter(StringView path, Codepoint path_separator) const HighlighterFunc HierachicalHighlighter::get_highlighter(StringView path) const
{ {
auto sep_it = std::find(path.begin(), path.end(), path_separator); auto sep_it = find(path, path_separator);
StringView id(path.begin(), sep_it); StringView id(path.begin(), sep_it);
auto it = m_groups.find(id); auto it = m_groups.find(id);
if (it == m_groups.end()) if (it == m_groups.end())
throw group_not_found("no such id: "_str + id); throw group_not_found("no such id: "_str + id);
if (sep_it != path.end()) if (sep_it != path.end())
return it->second.get_highlighter(StringView(sep_it+1, path.end()), path_separator); return it->second.get_highlighter(StringView(sep_it+1, path.end()));
else else
return HighlighterFunc(std::ref(it->second)); return HighlighterFunc(std::ref(it->second));
} }
Completions HierachicalHighlighter::complete_id(StringView path, ByteCount cursor_pos) const
{
auto sep_it = find(path, path_separator);
StringView id(path.begin(), sep_it);
auto it = m_groups.find(id);
if (sep_it == path.end())
return { 0_byte, id.length(), m_groups.complete_id(id, cursor_pos) };
if (it != m_groups.end())
{
const ByteCount offset = (int)(sep_it + 1 - path.begin());
return offset_pos(
it->second.complete_id({sep_it+1, path.end()},
cursor_pos - offset), offset);
}
return {};
}
Completions HierachicalHighlighter::complete_group_id(StringView path, ByteCount cursor_pos) const
{
auto sep_it = find(path, path_separator);
StringView id(path.begin(), sep_it);
auto it = m_groups.find(id);
if (sep_it == path.end())
return { 0_byte, id.length(), m_groups.complete_id(id, cursor_pos) };
if (it != m_groups.end())
{
const ByteCount offset = (int)(sep_it + 1- path.begin());
return offset_pos(
it->second.complete_group_id({sep_it+1, path.end()},
cursor_pos - offset), offset);
}
return {};
}
} }

View File

@ -24,11 +24,11 @@ public:
void append(HighlighterAndId&& hl); void append(HighlighterAndId&& hl);
void remove(StringView id); void remove(StringView id);
HighlighterGroup& get_group(StringView path, Codepoint path_separator = 0); HighlighterGroup& get_group(StringView path);
HighlighterFunc get_highlighter(StringView path, Codepoint path_separator = 0) const; HighlighterFunc get_highlighter(StringView path) const;
CandidateList complete_id(StringView prefix, ByteCount cursor_pos) const; Completions complete_id(StringView path, ByteCount cursor_pos) const;
CandidateList complete_group_id(StringView prefix, ByteCount cursor_pos) const; Completions complete_group_id(StringView path, ByteCount cursor_pos) const;
private: private:
id_map<HighlighterFunc> m_highlighters; id_map<HighlighterFunc> m_highlighters;
@ -53,8 +53,11 @@ public:
m_callback(m_groups, context, flags, display_buffer); m_callback(m_groups, context, flags, display_buffer);
} }
HighlighterGroup& get_group(StringView path, Codepoint path_separator = 0); HighlighterGroup& get_group(StringView path);
HighlighterFunc get_highlighter(StringView path, Codepoint path_separator = 0) const; HighlighterFunc get_highlighter(StringView path) const;
Completions complete_id(StringView path, ByteCount cursor_pos) const;
Completions complete_group_id(StringView path, ByteCount cursor_pos) const;
protected: protected:
Callback m_callback; Callback m_callback;

View File

@ -660,7 +660,7 @@ HighlighterAndId reference_factory(HighlighterParameters params)
{ {
try try
{ {
DefinedHighlighters::instance().get_highlighter(name, '/')(context, flags, display_buffer); DefinedHighlighters::instance().get_highlighter(name)(context, flags, display_buffer);
} }
catch (group_not_found&) catch (group_not_found&)
{ {

View File

@ -151,6 +151,18 @@ struct ReversedContainer
decltype(container.rend()) end() { return container.rend(); } decltype(container.rend()) end() { return container.rend(); }
}; };
template<typename Container>
auto begin(ReversedContainer<Container>& c) -> decltype(c.begin())
{
return c.begin();
}
template<typename Container>
auto end(ReversedContainer<Container>& c) -> decltype(c.end())
{
return c.end();
}
template<typename Container> template<typename Container>
ReversedContainer<Container> reversed(Container&& container) ReversedContainer<Container> reversed(Container&& container)
{ {