Refactor highlighter command completions
This commit is contained in:
parent
e0cd8ad93c
commit
205e8b2889
129
src/commands.cc
129
src/commands.cc
|
@ -350,39 +350,70 @@ const CommandDesc namebuf_cmd = {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename GetRootGroup>
|
||||
CommandCompleter group_rm_completer(GetRootGroup get_root_group)
|
||||
Completions complete_highlighter_group(const Context& context,
|
||||
StringView arg, ByteCount pos_in_token)
|
||||
{
|
||||
return [=](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params, size_t token_to_complete,
|
||||
ByteCount pos_in_token) -> Completions {
|
||||
auto& root_group = get_root_group(context);
|
||||
const String& arg = params[token_to_complete];
|
||||
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 == 2 and params[0] == "-group")
|
||||
return { 0_byte, arg.length(), root_group.get_group(params[1], '/').complete_id(arg, pos_in_token) };
|
||||
return { 0_byte, arg.length(), root_group.complete_id(arg, pos_in_token) };
|
||||
};
|
||||
const bool shared = not arg.empty() and arg[0] == '/';
|
||||
if (shared)
|
||||
{
|
||||
auto& group = DefinedHighlighters::instance();
|
||||
return offset_pos(group.complete_group_id(arg.substr(1_byte), pos_in_token-1), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& group = context.window().highlighters();
|
||||
return group.complete_group_id(arg, pos_in_token);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FactoryRegistry, typename GetRootGroup>
|
||||
CommandCompleter group_add_completer(GetRootGroup get_root_group)
|
||||
Completions rm_highlighter_completer(
|
||||
const Context& context, CompletionFlags flags, CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token)
|
||||
{
|
||||
return [=](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params, size_t token_to_complete,
|
||||
ByteCount pos_in_token) -> Completions {
|
||||
auto& root_group = get_root_group(context);
|
||||
const String& arg = params[token_to_complete];
|
||||
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 or (token_to_complete == 2 and params[0] == "-group"))
|
||||
return { 0_byte, arg.length(), FactoryRegistry::instance().complete_name(arg, pos_in_token) };
|
||||
return Completions{};
|
||||
};
|
||||
const String& arg = params[token_to_complete];
|
||||
if (token_to_complete == 0 and not arg.empty() and arg.front() == '/')
|
||||
{
|
||||
auto& group = DefinedHighlighters::instance();
|
||||
return offset_pos(group.complete_id(arg.substr(1_byte), pos_in_token-1), 1);
|
||||
}
|
||||
else if (token_to_complete == 0)
|
||||
return context.window().highlighters().complete_id(arg, pos_in_token);
|
||||
return {};
|
||||
}
|
||||
|
||||
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 = {
|
||||
"addhl",
|
||||
|
@ -393,7 +424,7 @@ const CommandDesc add_highlighter_cmd = {
|
|||
SwitchMap{ { "group", { true, "specify the group in which to put the highlighter" } } },
|
||||
ParameterDesc::Flags::SwitchesOnlyAtStart, 1 },
|
||||
CommandFlags::None,
|
||||
group_add_completer<HighlighterRegistry>(get_highlighters),
|
||||
add_highlighter_completer,
|
||||
[](const ParametersParser& parser, Context& context)
|
||||
{
|
||||
HighlighterRegistry& registry = HighlighterRegistry::instance();
|
||||
|
@ -404,48 +435,32 @@ const CommandDesc add_highlighter_cmd = {
|
|||
for (; begin != parser.end(); ++begin)
|
||||
highlighter_params.push_back(*begin);
|
||||
|
||||
HighlighterGroup* group = nullptr;
|
||||
if (parser.has_option("group"))
|
||||
{
|
||||
StringView path = parser.option_value("group");
|
||||
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));
|
||||
auto& group = (parser.has_option("group")) ?
|
||||
get_highlighter_group(context, parser.option_value("group"))
|
||||
: context.window().highlighters();
|
||||
group.append(registry[name](highlighter_params));
|
||||
}
|
||||
};
|
||||
|
||||
const CommandDesc rm_highlighter_cmd = {
|
||||
"rmhl",
|
||||
"rh",
|
||||
"rmhl <switches> <name>: remove highlighter <name> from current window",
|
||||
"rmhl <path>: remove highlighter <name>",
|
||||
ParameterDesc{
|
||||
SwitchMap{ { "group", { true, "remove highlighter from given group" } } },
|
||||
SwitchMap{},
|
||||
ParameterDesc::Flags::None, 1, 1
|
||||
},
|
||||
CommandFlags::None,
|
||||
group_rm_completer(get_highlighters),
|
||||
rm_highlighter_completer,
|
||||
[](const ParametersParser& parser, Context& context)
|
||||
{
|
||||
HighlighterGroup& window_hl = context.window().highlighters();
|
||||
HighlighterGroup& group = parser.has_option("group") ?
|
||||
window_hl.get_group(parser.option_value("group"), '/')
|
||||
: window_hl;
|
||||
StringView path = parser[0];
|
||||
auto sep_it = find(reversed(path), '/');
|
||||
auto& group = sep_it != path.rend() ?
|
||||
get_highlighter_group(context, {path.begin(), sep_it.base()-1})
|
||||
: context.window().highlighters();
|
||||
|
||||
group.remove(parser[0]);
|
||||
group.remove({sep_it.base(), path.end()});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -47,5 +47,11 @@ inline Completions complete_nothing(const Context& context, CompletionFlags,
|
|||
Completions shell_complete(const Context& context, CompletionFlags,
|
||||
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
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
namespace Kakoune
|
||||
{
|
||||
|
||||
static constexpr Codepoint path_separator = '/';
|
||||
|
||||
|
||||
void HighlighterGroup::operator()(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer) const
|
||||
{
|
||||
for (auto& hl : m_highlighters)
|
||||
|
@ -21,9 +24,9 @@ void HighlighterGroup::remove(StringView 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);
|
||||
auto it = m_highlighters.find(id);
|
||||
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 (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;
|
||||
}
|
||||
else if (auto* hier_group = it->second.target<HierachicalHighlighter>())
|
||||
{
|
||||
if (sep_it == path.end())
|
||||
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
|
||||
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);
|
||||
auto it = m_highlighters.find(id);
|
||||
if (it == m_highlighters.end())
|
||||
|
@ -54,50 +57,117 @@ HighlighterFunc HighlighterGroup::get_highlighter(StringView path, Codepoint pat
|
|||
if (sep_it == path.end())
|
||||
return HighlighterFunc{std::ref(it->second)};
|
||||
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>())
|
||||
return hier_group->get_highlighter({sep_it+1, path.end()}, path_separator);
|
||||
return hier_group->get_highlighter({sep_it+1, path.end()});
|
||||
else
|
||||
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(
|
||||
prefix, cursor_pos, [](const HighlighterAndId& func) {
|
||||
return func.second.template target<HighlighterGroup>() != nullptr;
|
||||
});
|
||||
auto sep_it = find(path, path_separator);
|
||||
StringView id(path.begin(), sep_it);
|
||||
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);
|
||||
auto it = m_groups.find(id);
|
||||
if (it == m_groups.end())
|
||||
throw group_not_found("no such id: "_str + id);
|
||||
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
|
||||
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);
|
||||
auto it = m_groups.find(id);
|
||||
if (it == m_groups.end())
|
||||
throw group_not_found("no such id: "_str + id);
|
||||
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
|
||||
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 {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,11 +24,11 @@ public:
|
|||
void append(HighlighterAndId&& hl);
|
||||
void remove(StringView id);
|
||||
|
||||
HighlighterGroup& get_group(StringView path, Codepoint path_separator = 0);
|
||||
HighlighterFunc get_highlighter(StringView path, Codepoint path_separator = 0) const;
|
||||
HighlighterGroup& get_group(StringView path);
|
||||
HighlighterFunc get_highlighter(StringView path) const;
|
||||
|
||||
CandidateList complete_id(StringView prefix, ByteCount cursor_pos) const;
|
||||
CandidateList complete_group_id(StringView prefix, ByteCount cursor_pos) const;
|
||||
Completions complete_id(StringView path, ByteCount cursor_pos) const;
|
||||
Completions complete_group_id(StringView path, ByteCount cursor_pos) const;
|
||||
|
||||
private:
|
||||
id_map<HighlighterFunc> m_highlighters;
|
||||
|
@ -53,8 +53,11 @@ public:
|
|||
m_callback(m_groups, context, flags, display_buffer);
|
||||
}
|
||||
|
||||
HighlighterGroup& get_group(StringView path, Codepoint path_separator = 0);
|
||||
HighlighterFunc get_highlighter(StringView path, Codepoint path_separator = 0) const;
|
||||
HighlighterGroup& get_group(StringView path);
|
||||
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:
|
||||
Callback m_callback;
|
||||
|
|
|
@ -660,7 +660,7 @@ HighlighterAndId reference_factory(HighlighterParameters params)
|
|||
{
|
||||
try
|
||||
{
|
||||
DefinedHighlighters::instance().get_highlighter(name, '/')(context, flags, display_buffer);
|
||||
DefinedHighlighters::instance().get_highlighter(name)(context, flags, display_buffer);
|
||||
}
|
||||
catch (group_not_found&)
|
||||
{
|
||||
|
|
12
src/utils.hh
12
src/utils.hh
|
@ -151,6 +151,18 @@ struct ReversedContainer
|
|||
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>
|
||||
ReversedContainer<Container> reversed(Container&& container)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user