Refactor highlighters, use an interface with virtual methods
This commit is contained in:
parent
fc4142178f
commit
b2e90fe21e
|
@ -370,19 +370,19 @@ const CommandDesc namebuf_cmd = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Completions complete_highlighter_group(const Context& context,
|
Completions complete_highlighter(const Context& context,
|
||||||
StringView arg, ByteCount pos_in_token)
|
StringView arg, ByteCount pos_in_token, bool only_group)
|
||||||
{
|
{
|
||||||
const bool shared = not arg.empty() and arg[0] == '/';
|
const bool shared = not arg.empty() and arg[0] == '/';
|
||||||
if (shared)
|
if (shared)
|
||||||
{
|
{
|
||||||
auto& group = DefinedHighlighters::instance();
|
auto& group = DefinedHighlighters::instance();
|
||||||
return offset_pos(group.complete_group_id(arg.substr(1_byte), pos_in_token-1), 1);
|
return offset_pos(group.complete_child(arg.substr(1_byte), pos_in_token-1, only_group), 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto& group = context.window().highlighters();
|
auto& group = context.window().highlighters();
|
||||||
return group.complete_group_id(arg, pos_in_token);
|
return group.complete_child(arg, pos_in_token, only_group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,10 +394,10 @@ Completions rm_highlighter_completer(
|
||||||
if (token_to_complete == 0 and not arg.empty() and arg.front() == '/')
|
if (token_to_complete == 0 and not arg.empty() and arg.front() == '/')
|
||||||
{
|
{
|
||||||
auto& group = DefinedHighlighters::instance();
|
auto& group = DefinedHighlighters::instance();
|
||||||
return offset_pos(group.complete_id(arg.substr(1_byte), pos_in_token-1), 1);
|
return offset_pos(group.complete_child(arg.substr(1_byte), pos_in_token-1, false), 1);
|
||||||
}
|
}
|
||||||
else if (token_to_complete == 0)
|
else if (token_to_complete == 0)
|
||||||
return context.window().highlighters().complete_id(arg, pos_in_token);
|
return context.window().highlighters().complete_child(arg, pos_in_token, false);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,32 +407,32 @@ Completions add_highlighter_completer(
|
||||||
{
|
{
|
||||||
StringView arg = params[token_to_complete];
|
StringView arg = params[token_to_complete];
|
||||||
if (token_to_complete == 1 and params[0] == "-group")
|
if (token_to_complete == 1 and params[0] == "-group")
|
||||||
return complete_highlighter_group(context, params[1], pos_in_token);
|
return complete_highlighter(context, params[1], pos_in_token, true);
|
||||||
else if (token_to_complete == 0 or (token_to_complete == 2 and params[0] == "-group"))
|
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 { 0_byte, arg.length(), HighlighterRegistry::instance().complete_name(arg, pos_in_token) };
|
||||||
return Completions{};
|
return Completions{};
|
||||||
}
|
}
|
||||||
|
|
||||||
HighlighterGroup& get_highlighter_group(const Context& context, StringView path)
|
Highlighter& get_highlighter(const Context& context, StringView path)
|
||||||
{
|
{
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
throw runtime_error("group path should not be empty");
|
throw runtime_error("group path should not be empty");
|
||||||
|
|
||||||
HighlighterGroup* group = nullptr;
|
Highlighter* root = nullptr;
|
||||||
if (path[0] == '/')
|
if (path[0] == '/')
|
||||||
{
|
{
|
||||||
group = &DefinedHighlighters::instance();
|
root = &DefinedHighlighters::instance();
|
||||||
path = path.substr(1_byte);
|
path = path.substr(1_byte);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
group = &context.window().highlighters();
|
root = &context.window().highlighters();
|
||||||
|
|
||||||
if (path.back() == '/')
|
if (path.back() == '/')
|
||||||
path = path.substr(0_byte, path.length() - 1);
|
path = path.substr(0_byte, path.length() - 1);
|
||||||
|
|
||||||
if (not path.empty())
|
if (not path.empty())
|
||||||
return group->get_group(path);
|
return root->get_child(path);
|
||||||
return *group;
|
return *root;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CommandDesc add_highlighter_cmd = {
|
const CommandDesc add_highlighter_cmd = {
|
||||||
|
@ -456,9 +456,9 @@ const CommandDesc add_highlighter_cmd = {
|
||||||
highlighter_params.push_back(*begin);
|
highlighter_params.push_back(*begin);
|
||||||
|
|
||||||
auto& group = (parser.has_option("group")) ?
|
auto& group = (parser.has_option("group")) ?
|
||||||
get_highlighter_group(context, parser.option_value("group"))
|
get_highlighter(context, parser.option_value("group"))
|
||||||
: context.window().highlighters();
|
: context.window().highlighters();
|
||||||
group.append(registry[name](highlighter_params));
|
group.add_child(registry[name](highlighter_params));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -477,10 +477,10 @@ const CommandDesc rm_highlighter_cmd = {
|
||||||
StringView path = parser[0];
|
StringView path = parser[0];
|
||||||
auto sep_it = find(reversed(path), '/');
|
auto sep_it = find(reversed(path), '/');
|
||||||
auto& group = sep_it != path.rend() ?
|
auto& group = sep_it != path.rend() ?
|
||||||
get_highlighter_group(context, {path.begin(), sep_it.base()-1})
|
get_highlighter(context, {path.begin(), sep_it.base()-1})
|
||||||
: context.window().highlighters();
|
: context.window().highlighters();
|
||||||
|
|
||||||
group.remove({sep_it.base(), path.end()});
|
group.remove_child({sep_it.base(), path.end()});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,39 @@ enum class HighlightFlags
|
||||||
// color, adding information text (line numbering for example) or replacing
|
// color, adding information text (line numbering for example) or replacing
|
||||||
// buffer content (folding for example)
|
// buffer content (folding for example)
|
||||||
|
|
||||||
using HighlighterFunc = std::function<void (const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer)>;
|
struct Highlighter;
|
||||||
using HighlighterAndId = std::pair<String, HighlighterFunc>;
|
|
||||||
|
using HighlighterAndId = std::pair<String, std::unique_ptr<Highlighter>>;
|
||||||
|
|
||||||
|
struct Highlighter
|
||||||
|
{
|
||||||
|
virtual void highlight(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer) = 0;
|
||||||
|
|
||||||
|
virtual bool has_children() const { return false; }
|
||||||
|
virtual Highlighter& get_child(StringView path) { throw runtime_error("this highlighter do not hold children"); }
|
||||||
|
virtual void add_child(HighlighterAndId&& hl) { throw runtime_error("this highlighter do not hold children"); }
|
||||||
|
virtual void remove_child(StringView id) { throw runtime_error("this highlighter do not hold children"); }
|
||||||
|
virtual Completions complete_child(StringView path, ByteCount cursor_pos, bool group) const { throw runtime_error("this highlighter do not hold children"); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
struct SimpleHighlighter : public Highlighter
|
||||||
|
{
|
||||||
|
SimpleHighlighter(Func func) : m_func(std::move(func)) {}
|
||||||
|
virtual void highlight(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer) override
|
||||||
|
{
|
||||||
|
m_func(context, flags, display_buffer);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Func m_func;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::unique_ptr<SimpleHighlighter<T>> make_simple_highlighter(T func)
|
||||||
|
{
|
||||||
|
return make_unique<SimpleHighlighter<T>>(std::move(func));
|
||||||
|
}
|
||||||
|
|
||||||
using HighlighterParameters = memoryview<String>;
|
using HighlighterParameters = memoryview<String>;
|
||||||
using HighlighterFactory = std::function<HighlighterAndId (HighlighterParameters params)>;
|
using HighlighterFactory = std::function<HighlighterAndId (HighlighterParameters params)>;
|
||||||
|
|
||||||
|
|
|
@ -3,164 +3,54 @@
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
static constexpr Codepoint path_separator = '/';
|
void HighlighterGroup::highlight(const Context& context, HighlightFlags flags,
|
||||||
|
DisplayBuffer& display_buffer)
|
||||||
|
|
||||||
void HighlighterGroup::operator()(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer) const
|
|
||||||
{
|
{
|
||||||
for (auto& hl : m_highlighters)
|
for (auto& hl : m_highlighters)
|
||||||
hl.second(context, flags, display_buffer);
|
hl.second->highlight(context, flags, display_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HighlighterGroup::append(HighlighterAndId&& hl)
|
void HighlighterGroup::add_child(HighlighterAndId&& hl)
|
||||||
{
|
{
|
||||||
if (m_highlighters.contains(hl.first))
|
if (m_highlighters.contains(hl.first))
|
||||||
throw runtime_error("duplicate id: " + hl.first);
|
throw runtime_error("duplicate id: " + hl.first);
|
||||||
|
|
||||||
m_highlighters.append(std::move(hl));
|
m_highlighters.append(std::move(hl));
|
||||||
}
|
}
|
||||||
void HighlighterGroup::remove(StringView id)
|
|
||||||
|
void HighlighterGroup::remove_child(StringView id)
|
||||||
{
|
{
|
||||||
m_highlighters.remove(id);
|
m_highlighters.remove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
HighlighterGroup& HighlighterGroup::get_group(StringView path)
|
Highlighter& HighlighterGroup::get_child(StringView path)
|
||||||
{
|
{
|
||||||
auto sep_it = find(path, path_separator);
|
auto sep_it = find(path, '/');
|
||||||
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())
|
||||||
throw group_not_found("no such id: "_str + id);
|
throw child_not_found("no such id: "_str + id);
|
||||||
if (auto* group = it->second.target<HighlighterGroup>())
|
if (sep_it == path.end())
|
||||||
|
return *it->second;
|
||||||
|
else
|
||||||
|
return it->second->get_child({sep_it+1, path.end()});
|
||||||
|
}
|
||||||
|
|
||||||
|
Completions HighlighterGroup::complete_child(StringView path, ByteCount cursor_pos, bool group) const
|
||||||
{
|
{
|
||||||
|
auto sep_it = find(path, '/');
|
||||||
if (sep_it != path.end())
|
if (sep_it != path.end())
|
||||||
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())
|
ByteCount offset = sep_it+1 - path.begin();
|
||||||
throw group_not_found("not a leaf group: "_str + id);
|
Highlighter& hl = const_cast<HighlighterGroup*>(this)->get_child({path.begin(), sep_it});
|
||||||
return hier_group->get_group({sep_it+1, path.end()});
|
return offset_pos(hl.complete_child(path.substr(offset), cursor_pos - offset, group), offset);
|
||||||
}
|
|
||||||
else
|
|
||||||
throw group_not_found("not a group: "_str + id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HighlighterFunc HighlighterGroup::get_highlighter(StringView path) const
|
auto condition = [=](const HighlighterMap::value_type& hl)
|
||||||
{
|
{
|
||||||
auto sep_it = find(path, path_separator);
|
return not group || hl.second->has_children();
|
||||||
StringView id(path.begin(), sep_it);
|
};
|
||||||
auto it = m_highlighters.find(id);
|
return { 0, 0, m_highlighters.complete_id_if(path, cursor_pos, condition) };
|
||||||
if (it == m_highlighters.end())
|
|
||||||
throw group_not_found("no such id: "_str + id);
|
|
||||||
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()});
|
|
||||||
else if (auto* hier_group = it->second.target<HierachicalHighlighter>())
|
|
||||||
return hier_group->get_highlighter({sep_it+1, path.end()});
|
|
||||||
else
|
|
||||||
throw group_not_found("not a group: "_str + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<Completions (HighlighterGroup::*hg_complete)(StringView path, ByteCount cursor_pos) const,
|
|
||||||
Completions (HierachicalHighlighter::*hh_complete)(StringView path, ByteCount cursor_pos) const,
|
|
||||||
typename Condition>
|
|
||||||
Completions complete_impl(const id_map<HighlighterFunc>& highlighters, Condition condition,
|
|
||||||
StringView path, ByteCount cursor_pos)
|
|
||||||
{
|
|
||||||
auto sep_it = find(path, path_separator);
|
|
||||||
StringView id(path.begin(), sep_it);
|
|
||||||
if (sep_it == path.end())
|
|
||||||
return { 0_byte, path.length(), highlighters.complete_id_if(path, cursor_pos, condition) };
|
|
||||||
|
|
||||||
auto it = highlighters.find(id);
|
|
||||||
if (it != 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->*hg_complete)({sep_it+1, path.end()}, cursor_pos), offset);
|
|
||||||
if (auto* hier_group = it->second.target<HierachicalHighlighter>())
|
|
||||||
return offset_pos((hier_group->*hh_complete)({sep_it+1, path.end()}, cursor_pos), offset);
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Completions HighlighterGroup::complete_id(StringView path, ByteCount cursor_pos) const
|
|
||||||
{
|
|
||||||
return complete_impl<
|
|
||||||
&HighlighterGroup::complete_id,
|
|
||||||
&HierachicalHighlighter::complete_id
|
|
||||||
>(m_highlighters, [](const HighlighterAndId&) { return true; }, path, cursor_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
Completions HighlighterGroup::complete_group_id(StringView path, ByteCount cursor_pos) const
|
|
||||||
{
|
|
||||||
return complete_impl<
|
|
||||||
&HighlighterGroup::complete_group_id,
|
|
||||||
&HierachicalHighlighter::complete_group_id
|
|
||||||
>(m_highlighters, [](const HighlighterAndId& func) {
|
|
||||||
return func.second.target<HighlighterGroup>() or
|
|
||||||
func.second.target<HierachicalHighlighter>();
|
|
||||||
}, path, cursor_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
HighlighterGroup& HierachicalHighlighter::get_group(StringView path)
|
|
||||||
{
|
|
||||||
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()));
|
|
||||||
else
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
HighlighterFunc HierachicalHighlighter::get_highlighter(StringView path) const
|
|
||||||
{
|
|
||||||
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()));
|
|
||||||
else
|
|
||||||
return HighlighterFunc(std::ref(it->second));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<Completions (HighlighterGroup::*complete)(StringView path, ByteCount cursor_pos) const>
|
|
||||||
Completions complete_impl(const HierachicalHighlighter::GroupMap& groups,
|
|
||||||
StringView path, ByteCount cursor_pos)
|
|
||||||
{
|
|
||||||
auto sep_it = find(path, path_separator);
|
|
||||||
StringView id(path.begin(), sep_it);
|
|
||||||
auto it = groups.find(id);
|
|
||||||
if (sep_it == path.end())
|
|
||||||
return { 0_byte, id.length(), groups.complete_id(id, cursor_pos) };
|
|
||||||
|
|
||||||
if (it != groups.end())
|
|
||||||
{
|
|
||||||
const ByteCount offset = (int)(sep_it + 1- path.begin());
|
|
||||||
return offset_pos(
|
|
||||||
(it->second.*complete)({sep_it+1, path.end()},
|
|
||||||
cursor_pos - offset), offset);
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Completions HierachicalHighlighter::complete_id(StringView path, ByteCount cursor_pos) const
|
|
||||||
{
|
|
||||||
return complete_impl<&HighlighterGroup::complete_id>(m_groups, path, cursor_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
Completions HierachicalHighlighter::complete_group_id(StringView path, ByteCount cursor_pos) const
|
|
||||||
{
|
|
||||||
return complete_impl<&HighlighterGroup::complete_group_id>(m_groups, path, cursor_pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,59 +9,27 @@
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
struct group_not_found : public runtime_error
|
struct child_not_found : public runtime_error
|
||||||
{
|
{
|
||||||
using runtime_error::runtime_error;
|
using runtime_error::runtime_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HighlighterGroup
|
class HighlighterGroup : public Highlighter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void operator()(const Context& context,
|
void highlight(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer) override;
|
||||||
HighlightFlags flags,
|
|
||||||
DisplayBuffer& display_buffer) const;
|
|
||||||
|
|
||||||
void append(HighlighterAndId&& hl);
|
bool has_children() const { return true; }
|
||||||
void remove(StringView id);
|
void add_child(HighlighterAndId&& hl) override;
|
||||||
|
void remove_child(StringView id) override;
|
||||||
|
|
||||||
HighlighterGroup& get_group(StringView path);
|
Highlighter& get_child(StringView path) override;
|
||||||
HighlighterFunc get_highlighter(StringView path) const;
|
|
||||||
|
|
||||||
Completions complete_id(StringView path, ByteCount cursor_pos) const;
|
Completions complete_child(StringView path, ByteCount cursor_pos, bool group) const override;
|
||||||
Completions complete_group_id(StringView path, ByteCount cursor_pos) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
id_map<HighlighterFunc> m_highlighters;
|
using HighlighterMap = id_map<std::unique_ptr<Highlighter>>;
|
||||||
};
|
HighlighterMap m_highlighters;
|
||||||
|
|
||||||
class HierachicalHighlighter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using GroupMap = id_map<HighlighterGroup>;
|
|
||||||
using Callback = std::function<void (GroupMap& groups,
|
|
||||||
const Context& context,
|
|
||||||
HighlightFlags flags,
|
|
||||||
DisplayBuffer& display_buffer)>;
|
|
||||||
|
|
||||||
HierachicalHighlighter(Callback callback, GroupMap groups)
|
|
||||||
: m_callback(std::move(callback)), m_groups(std::move(groups)) {}
|
|
||||||
|
|
||||||
void operator()(const Context& context,
|
|
||||||
HighlightFlags flags,
|
|
||||||
DisplayBuffer& display_buffer)
|
|
||||||
{
|
|
||||||
m_callback(m_groups, context, flags, display_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
GroupMap m_groups;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DefinedHighlighters : public HighlighterGroup,
|
struct DefinedHighlighters : public HighlighterGroup,
|
||||||
|
|
|
@ -63,12 +63,11 @@ void highlight_range(DisplayBuffer& display_buffer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void apply_highlighter(const Context& context,
|
void apply_highlighter(const Context& context,
|
||||||
HighlightFlags flags,
|
HighlightFlags flags,
|
||||||
DisplayBuffer& display_buffer,
|
DisplayBuffer& display_buffer,
|
||||||
ByteCoord begin, ByteCoord end,
|
ByteCoord begin, ByteCoord end,
|
||||||
T&& highlighter)
|
Highlighter& highlighter)
|
||||||
{
|
{
|
||||||
using LineIterator = DisplayBuffer::LineList::iterator;
|
using LineIterator = DisplayBuffer::LineList::iterator;
|
||||||
LineIterator first_line;
|
LineIterator first_line;
|
||||||
|
@ -135,7 +134,7 @@ void apply_highlighter(const Context& context,
|
||||||
}
|
}
|
||||||
|
|
||||||
region_display.compute_range();
|
region_display.compute_range();
|
||||||
highlighter(context, flags, region_display);
|
highlighter.highlight(context, flags, region_display);
|
||||||
|
|
||||||
for (size_t i = 0; i < region_lines.size(); ++i)
|
for (size_t i = 0; i < region_lines.size(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -161,7 +160,7 @@ auto apply_face = [](const Face& face)
|
||||||
|
|
||||||
using FacesSpec = std::vector<String>;
|
using FacesSpec = std::vector<String>;
|
||||||
|
|
||||||
HighlighterAndId fill_factory(HighlighterParameters params)
|
static HighlighterAndId create_fill_highlighter(HighlighterParameters params)
|
||||||
{
|
{
|
||||||
if (params.size() != 1)
|
if (params.size() != 1)
|
||||||
throw runtime_error("wrong parameter count");
|
throw runtime_error("wrong parameter count");
|
||||||
|
@ -169,14 +168,14 @@ HighlighterAndId fill_factory(HighlighterParameters params)
|
||||||
const String& facespec = params[0];
|
const String& facespec = params[0];
|
||||||
get_face(facespec); // validate param
|
get_face(facespec); // validate param
|
||||||
|
|
||||||
auto fill = [facespec](const Context& context, HighlightFlags flags,
|
auto func = [=](const Context& context, HighlightFlags flags,
|
||||||
DisplayBuffer& display_buffer)
|
DisplayBuffer& display_buffer)
|
||||||
{
|
{
|
||||||
auto range = display_buffer.range();
|
auto range = display_buffer.range();
|
||||||
highlight_range(display_buffer, range.first, range.second, true,
|
highlight_range(display_buffer, range.first, range.second, true,
|
||||||
apply_face(get_face(facespec)));
|
apply_face(get_face(facespec)));
|
||||||
};
|
};
|
||||||
return HighlighterAndId("fill_" + params[0], fill);
|
return {"fill_" + facespec, make_simple_highlighter(std::move(func))};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -195,7 +194,7 @@ private:
|
||||||
ValueId m_id;
|
ValueId m_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RegexHighlighter
|
class RegexHighlighter : public Highlighter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RegexHighlighter(Regex regex, FacesSpec faces)
|
RegexHighlighter(Regex regex, FacesSpec faces)
|
||||||
|
@ -203,7 +202,7 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer)
|
void highlight(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer) override
|
||||||
{
|
{
|
||||||
if (flags != HighlightFlags::Highlight)
|
if (flags != HighlightFlags::Highlight)
|
||||||
return;
|
return;
|
||||||
|
@ -225,52 +224,14 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
void reset(Regex regex, FacesSpec faces)
|
||||||
struct Cache
|
|
||||||
{
|
{
|
||||||
std::pair<LineCount, LineCount> m_range;
|
m_regex = std::move(regex);
|
||||||
size_t m_timestamp = 0;
|
m_faces = std::move(faces);
|
||||||
std::vector<std::vector<std::pair<ByteCoord, ByteCoord>>> m_matches;
|
m_force_update = true;
|
||||||
};
|
|
||||||
BufferSideCache<Cache> m_cache;
|
|
||||||
|
|
||||||
Regex m_regex;
|
|
||||||
FacesSpec m_faces;
|
|
||||||
|
|
||||||
Cache& update_cache_ifn(const Buffer& buffer, const BufferRange& range)
|
|
||||||
{
|
|
||||||
Cache& cache = m_cache.get(buffer);
|
|
||||||
|
|
||||||
LineCount first_line = range.first.line;
|
|
||||||
LineCount last_line = std::min(buffer.line_count()-1, range.second.line);
|
|
||||||
|
|
||||||
if (buffer.timestamp() == cache.m_timestamp and
|
|
||||||
first_line >= cache.m_range.first and
|
|
||||||
last_line <= cache.m_range.second)
|
|
||||||
return cache;
|
|
||||||
|
|
||||||
cache.m_range.first = std::max(0_line, first_line - 10);
|
|
||||||
cache.m_range.second = std::min(buffer.line_count()-1, last_line+10);
|
|
||||||
cache.m_timestamp = buffer.timestamp();
|
|
||||||
|
|
||||||
cache.m_matches.clear();
|
|
||||||
|
|
||||||
using RegexIt = RegexIterator<BufferIterator>;
|
|
||||||
RegexIt re_it{buffer.iterator_at(cache.m_range.first),
|
|
||||||
buffer.iterator_at(cache.m_range.second+1), m_regex};
|
|
||||||
RegexIt re_end;
|
|
||||||
for (; re_it != re_end; ++re_it)
|
|
||||||
{
|
|
||||||
cache.m_matches.emplace_back();
|
|
||||||
auto& match = cache.m_matches.back();
|
|
||||||
for (auto& sub : *re_it)
|
|
||||||
match.emplace_back(sub.first.coord(), sub.second.coord());
|
|
||||||
}
|
}
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
HighlighterAndId highlight_regex_factory(HighlighterParameters params)
|
static HighlighterAndId create(HighlighterParameters params)
|
||||||
{
|
{
|
||||||
if (params.size() < 2)
|
if (params.size() < 2)
|
||||||
throw runtime_error("wrong parameter count");
|
throw runtime_error("wrong parameter count");
|
||||||
|
@ -296,8 +257,8 @@ HighlighterAndId highlight_regex_factory(HighlighterParameters params)
|
||||||
|
|
||||||
Regex ex{params[0].begin(), params[0].end(), Regex::optimize};
|
Regex ex{params[0].begin(), params[0].end(), Regex::optimize};
|
||||||
|
|
||||||
return HighlighterAndId(id, RegexHighlighter(std::move(ex),
|
return {id, make_unique<RegexHighlighter>(std::move(ex),
|
||||||
std::move(faces)));
|
std::move(faces))};
|
||||||
}
|
}
|
||||||
catch (RegexError& err)
|
catch (RegexError& err)
|
||||||
{
|
{
|
||||||
|
@ -305,8 +266,58 @@ HighlighterAndId highlight_regex_factory(HighlighterParameters params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Cache
|
||||||
|
{
|
||||||
|
std::pair<LineCount, LineCount> m_range;
|
||||||
|
size_t m_timestamp = 0;
|
||||||
|
std::vector<std::vector<std::pair<ByteCoord, ByteCoord>>> m_matches;
|
||||||
|
};
|
||||||
|
BufferSideCache<Cache> m_cache;
|
||||||
|
|
||||||
|
Regex m_regex;
|
||||||
|
FacesSpec m_faces;
|
||||||
|
|
||||||
|
bool m_force_update = false;
|
||||||
|
|
||||||
|
Cache& update_cache_ifn(const Buffer& buffer, const BufferRange& range)
|
||||||
|
{
|
||||||
|
Cache& cache = m_cache.get(buffer);
|
||||||
|
|
||||||
|
LineCount first_line = range.first.line;
|
||||||
|
LineCount last_line = std::min(buffer.line_count()-1, range.second.line);
|
||||||
|
|
||||||
|
if (not m_force_update and
|
||||||
|
buffer.timestamp() == cache.m_timestamp and
|
||||||
|
first_line >= cache.m_range.first and
|
||||||
|
last_line <= cache.m_range.second)
|
||||||
|
return cache;
|
||||||
|
|
||||||
|
m_force_update = false;
|
||||||
|
|
||||||
|
cache.m_range.first = std::max(0_line, first_line - 10);
|
||||||
|
cache.m_range.second = std::min(buffer.line_count()-1, last_line+10);
|
||||||
|
cache.m_timestamp = buffer.timestamp();
|
||||||
|
|
||||||
|
cache.m_matches.clear();
|
||||||
|
|
||||||
|
using RegexIt = RegexIterator<BufferIterator>;
|
||||||
|
RegexIt re_it{buffer.iterator_at(cache.m_range.first),
|
||||||
|
buffer.iterator_at(cache.m_range.second+1), m_regex};
|
||||||
|
RegexIt re_end;
|
||||||
|
for (; re_it != re_end; ++re_it)
|
||||||
|
{
|
||||||
|
cache.m_matches.emplace_back();
|
||||||
|
auto& match = cache.m_matches.back();
|
||||||
|
for (auto& sub : *re_it)
|
||||||
|
match.emplace_back(sub.first.coord(), sub.second.coord());
|
||||||
|
}
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename RegexGetter, typename FaceGetter>
|
template<typename RegexGetter, typename FaceGetter>
|
||||||
class DynamicRegexHighlighter
|
class DynamicRegexHighlighter : public Highlighter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DynamicRegexHighlighter(RegexGetter regex_getter, FaceGetter face_getter)
|
DynamicRegexHighlighter(RegexGetter regex_getter, FaceGetter face_getter)
|
||||||
|
@ -314,7 +325,7 @@ public:
|
||||||
m_face_getter(std::move(face_getter)),
|
m_face_getter(std::move(face_getter)),
|
||||||
m_highlighter(Regex(), FacesSpec{}) {}
|
m_highlighter(Regex(), FacesSpec{}) {}
|
||||||
|
|
||||||
void operator()(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer)
|
void highlight(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer)
|
||||||
{
|
{
|
||||||
if (flags != HighlightFlags::Highlight)
|
if (flags != HighlightFlags::Highlight)
|
||||||
return;
|
return;
|
||||||
|
@ -326,10 +337,10 @@ public:
|
||||||
m_last_regex = regex;
|
m_last_regex = regex;
|
||||||
m_last_face = face;
|
m_last_face = face;
|
||||||
if (not m_last_regex.empty())
|
if (not m_last_regex.empty())
|
||||||
m_highlighter= RegexHighlighter{m_last_regex, face};
|
m_highlighter.reset(m_last_regex, m_last_face);
|
||||||
}
|
}
|
||||||
if (not m_last_regex.empty() and not m_last_face.empty())
|
if (not m_last_regex.empty() and not m_last_face.empty())
|
||||||
m_highlighter(context, flags, display_buffer);
|
m_highlighter.highlight(context, flags, display_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -343,15 +354,15 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename RegexGetter, typename FaceGetter>
|
template<typename RegexGetter, typename FaceGetter>
|
||||||
DynamicRegexHighlighter<RegexGetter, FaceGetter>
|
std::unique_ptr<DynamicRegexHighlighter<RegexGetter, FaceGetter>>
|
||||||
make_dynamic_regex_highlighter(RegexGetter regex_getter, FaceGetter face_getter)
|
make_dynamic_regex_highlighter(RegexGetter regex_getter, FaceGetter face_getter)
|
||||||
{
|
{
|
||||||
return DynamicRegexHighlighter<RegexGetter, FaceGetter>(
|
return make_unique<DynamicRegexHighlighter<RegexGetter, FaceGetter>>(
|
||||||
std::move(regex_getter), std::move(face_getter));
|
std::move(regex_getter), std::move(face_getter));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HighlighterAndId highlight_search_factory(HighlighterParameters params)
|
HighlighterAndId create_search_highlighter(HighlighterParameters params)
|
||||||
{
|
{
|
||||||
if (params.size() != 0)
|
if (params.size() != 0)
|
||||||
throw runtime_error("wrong parameter count");
|
throw runtime_error("wrong parameter count");
|
||||||
|
@ -372,7 +383,7 @@ HighlighterAndId highlight_search_factory(HighlighterParameters params)
|
||||||
return {"hlsearch", make_dynamic_regex_highlighter(get_regex, get_face)};
|
return {"hlsearch", make_dynamic_regex_highlighter(get_regex, get_face)};
|
||||||
}
|
}
|
||||||
|
|
||||||
HighlighterAndId highlight_regex_option_factory(HighlighterParameters params)
|
HighlighterAndId create_regex_option_highlighter(HighlighterParameters params)
|
||||||
{
|
{
|
||||||
if (params.size() != 2)
|
if (params.size() != 2)
|
||||||
throw runtime_error("wrong parameter count");
|
throw runtime_error("wrong parameter count");
|
||||||
|
@ -392,19 +403,18 @@ HighlighterAndId highlight_regex_option_factory(HighlighterParameters params)
|
||||||
return {"hloption_" + option_name, make_dynamic_regex_highlighter(get_regex, get_face)};
|
return {"hloption_" + option_name, make_dynamic_regex_highlighter(get_regex, get_face)};
|
||||||
}
|
}
|
||||||
|
|
||||||
HighlighterAndId highlight_line_option_factory(HighlighterParameters params)
|
HighlighterAndId create_line_option_highlighter(HighlighterParameters params)
|
||||||
{
|
{
|
||||||
if (params.size() != 2)
|
if (params.size() != 2)
|
||||||
throw runtime_error("wrong parameter count");
|
throw runtime_error("wrong parameter count");
|
||||||
|
|
||||||
String facespec = params[1];
|
String facespec = params[1];
|
||||||
get_face(facespec); // validate facespec
|
|
||||||
|
|
||||||
String option_name = params[0];
|
String option_name = params[0];
|
||||||
// verify option type now
|
|
||||||
GlobalOptions::instance()[option_name].get<int>();
|
|
||||||
|
|
||||||
auto highlighter = [=](const Context& context, HighlightFlags flags,
|
get_face(facespec); // validate facespec
|
||||||
|
GlobalOptions::instance()[option_name].get<int>(); // verify option type now
|
||||||
|
|
||||||
|
auto func = [=](const Context& context, HighlightFlags flags,
|
||||||
DisplayBuffer& display_buffer)
|
DisplayBuffer& display_buffer)
|
||||||
{
|
{
|
||||||
int line = context.options()[option_name].get<int>();
|
int line = context.options()[option_name].get<int>();
|
||||||
|
@ -412,7 +422,7 @@ HighlighterAndId highlight_line_option_factory(HighlighterParameters params)
|
||||||
apply_face(get_face(facespec)));
|
apply_face(get_face(facespec)));
|
||||||
};
|
};
|
||||||
|
|
||||||
return {"hlline_" + option_name, std::move(highlighter)};
|
return {"hlline_" + params[0], make_simple_highlighter(std::move(func))};
|
||||||
}
|
}
|
||||||
|
|
||||||
void expand_tabulations(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer)
|
void expand_tabulations(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer)
|
||||||
|
@ -626,7 +636,7 @@ void expand_unprintable(const Context& context, HighlightFlags flags, DisplayBuf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HighlighterAndId flag_lines_factory(HighlighterParameters params)
|
HighlighterAndId create_flag_lines_highlighter(HighlighterParameters params)
|
||||||
{
|
{
|
||||||
if (params.size() != 2)
|
if (params.size() != 2)
|
||||||
throw runtime_error("wrong parameter count");
|
throw runtime_error("wrong parameter count");
|
||||||
|
@ -637,8 +647,8 @@ HighlighterAndId flag_lines_factory(HighlighterParameters params)
|
||||||
// throw if wrong option type
|
// throw if wrong option type
|
||||||
GlobalOptions::instance()[option_name].get<std::vector<LineAndFlag>>();
|
GlobalOptions::instance()[option_name].get<std::vector<LineAndFlag>>();
|
||||||
|
|
||||||
return {"hlflags_" + params[1],
|
auto func = [=](const Context& context, HighlightFlags flags,
|
||||||
[=](const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer)
|
DisplayBuffer& display_buffer)
|
||||||
{
|
{
|
||||||
auto& lines_opt = context.options()[option_name];
|
auto& lines_opt = context.options()[option_name];
|
||||||
auto& lines = lines_opt.get<std::vector<LineAndFlag>>();
|
auto& lines = lines_opt.get<std::vector<LineAndFlag>>();
|
||||||
|
@ -659,32 +669,20 @@ HighlighterAndId flag_lines_factory(HighlighterParameters params)
|
||||||
atom.face = { it != lines.end() ? std::get<1>(*it) : Colors::Default , bg };
|
atom.face = { it != lines.end() ? std::get<1>(*it) : Colors::Default , bg };
|
||||||
line.insert(line.begin(), std::move(atom));
|
line.insert(line.begin(), std::move(atom));
|
||||||
}
|
}
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<void (*highlighter_func)(const Context&, HighlightFlags, DisplayBuffer&)>
|
|
||||||
class SimpleHighlighterFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SimpleHighlighterFactory(const String& id) : m_id(id) {}
|
|
||||||
|
|
||||||
HighlighterAndId operator()(HighlighterParameters params) const
|
|
||||||
{
|
|
||||||
return HighlighterAndId(m_id, HighlighterFunc(highlighter_func));
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
String m_id;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
HighlighterAndId highlighter_group_factory(HighlighterParameters params)
|
return {"hlflags_" + params[1], make_simple_highlighter(func) };
|
||||||
|
}
|
||||||
|
|
||||||
|
HighlighterAndId create_highlighter_group(HighlighterParameters params)
|
||||||
{
|
{
|
||||||
if (params.size() != 1)
|
if (params.size() != 1)
|
||||||
throw runtime_error("wrong parameter count");
|
throw runtime_error("wrong parameter count");
|
||||||
|
|
||||||
return HighlighterAndId(params[0], HighlighterGroup());
|
return HighlighterAndId(params[0], make_unique<HighlighterGroup>());
|
||||||
}
|
}
|
||||||
|
|
||||||
HighlighterAndId reference_factory(HighlighterParameters params)
|
HighlighterAndId create_reference_highlighter(HighlighterParameters params)
|
||||||
{
|
{
|
||||||
if (params.size() != 1)
|
if (params.size() != 1)
|
||||||
throw runtime_error("wrong parameter count");
|
throw runtime_error("wrong parameter count");
|
||||||
|
@ -694,17 +692,18 @@ HighlighterAndId reference_factory(HighlighterParameters params)
|
||||||
// throw if not found
|
// throw if not found
|
||||||
//DefinedHighlighters::instance().get_group(name, '/');
|
//DefinedHighlighters::instance().get_group(name, '/');
|
||||||
|
|
||||||
return {name,
|
auto func = [=](const Context& context, HighlightFlags flags,
|
||||||
[name](const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer)
|
DisplayBuffer& display_buffer)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DefinedHighlighters::instance().get_highlighter(name)(context, flags, display_buffer);
|
DefinedHighlighters::instance().get_child(name).highlight(context, flags, display_buffer);
|
||||||
}
|
}
|
||||||
catch (group_not_found&)
|
catch (child_not_found&)
|
||||||
{
|
{}
|
||||||
}
|
};
|
||||||
}};
|
|
||||||
|
return {name, make_simple_highlighter(func)};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RegexMatch
|
struct RegexMatch
|
||||||
|
@ -868,7 +867,7 @@ struct RegionDesc
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RegionsHighlighter
|
struct RegionsHighlighter : public Highlighter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using NamedRegionDescList = std::vector<std::pair<String, RegionDesc>>;
|
using NamedRegionDescList = std::vector<std::pair<String, RegionDesc>>;
|
||||||
|
@ -880,12 +879,16 @@ public:
|
||||||
throw runtime_error("at least one region must be defined");
|
throw runtime_error("at least one region must be defined");
|
||||||
|
|
||||||
for (auto& region : m_regions)
|
for (auto& region : m_regions)
|
||||||
|
{
|
||||||
|
m_groups.append({region.first, HighlighterGroup{}});
|
||||||
if (region.second.m_begin.empty() or region.second.m_end.empty())
|
if (region.second.m_begin.empty() or region.second.m_end.empty())
|
||||||
throw runtime_error("invalid regex for region highlighter");
|
throw runtime_error("invalid regex for region highlighter");
|
||||||
}
|
}
|
||||||
|
if (not m_default_group.empty())
|
||||||
|
m_groups.append({m_default_group, HighlighterGroup{}});
|
||||||
|
}
|
||||||
|
|
||||||
void operator()(HierachicalHighlighter::GroupMap groups, const Context& context,
|
void highlight(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer)
|
||||||
HighlightFlags flags, DisplayBuffer& display_buffer)
|
|
||||||
{
|
{
|
||||||
if (flags != HighlightFlags::Highlight)
|
if (flags != HighlightFlags::Highlight)
|
||||||
return;
|
return;
|
||||||
|
@ -904,8 +907,8 @@ public:
|
||||||
return c;
|
return c;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto default_group_it = groups.find(m_default_group);
|
auto default_group_it = m_groups.find(m_default_group);
|
||||||
const bool apply_default = default_group_it != groups.end();
|
const bool apply_default = default_group_it != m_groups.end();
|
||||||
|
|
||||||
auto last_begin = range.first;
|
auto last_begin = range.first;
|
||||||
for (; begin != end; ++begin)
|
for (; begin != end; ++begin)
|
||||||
|
@ -915,8 +918,8 @@ public:
|
||||||
correct(last_begin), correct(begin->begin),
|
correct(last_begin), correct(begin->begin),
|
||||||
default_group_it->second);
|
default_group_it->second);
|
||||||
|
|
||||||
auto it = groups.find(begin->group);
|
auto it = m_groups.find(begin->group);
|
||||||
if (it == groups.end())
|
if (it == m_groups.end())
|
||||||
continue;
|
continue;
|
||||||
apply_highlighter(context, flags, display_buffer,
|
apply_highlighter(context, flags, display_buffer,
|
||||||
correct(begin->begin), correct(begin->end),
|
correct(begin->begin), correct(begin->end),
|
||||||
|
@ -929,9 +932,79 @@ public:
|
||||||
default_group_it->second);
|
default_group_it->second);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool has_children() const override { return true; }
|
||||||
|
|
||||||
|
Highlighter& get_child(StringView path) override
|
||||||
|
{
|
||||||
|
auto sep_it = find(path, '/');
|
||||||
|
StringView id(path.begin(), sep_it);
|
||||||
|
auto it = m_groups.find(id);
|
||||||
|
if (it == m_groups.end())
|
||||||
|
throw child_not_found("no such id: "_str + id);
|
||||||
|
if (sep_it == path.end())
|
||||||
|
return it->second;
|
||||||
|
else
|
||||||
|
return it->second.get_child({sep_it+1, path.end()});
|
||||||
|
}
|
||||||
|
|
||||||
|
Completions complete_child(StringView path, ByteCount cursor_pos, bool group) const override
|
||||||
|
{
|
||||||
|
auto sep_it = find(path, '/');
|
||||||
|
if (sep_it != path.end())
|
||||||
|
{
|
||||||
|
ByteCount offset = sep_it+1 - path.begin();
|
||||||
|
Highlighter& hl = const_cast<RegionsHighlighter*>(this)->get_child({path.begin(), sep_it});
|
||||||
|
return offset_pos(hl.complete_child(path.substr(offset), cursor_pos - offset, group), offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { 0, 0, m_groups.complete_id(path, cursor_pos) };
|
||||||
|
}
|
||||||
|
|
||||||
|
static HighlighterAndId create(HighlighterParameters params)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
static const ParameterDesc param_desc{
|
||||||
|
SwitchMap{ { "default", { true, "" } } },
|
||||||
|
ParameterDesc::Flags::SwitchesOnlyAtStart,
|
||||||
|
5};
|
||||||
|
|
||||||
|
ParametersParser parser{params, param_desc};
|
||||||
|
if ((parser.positional_count() % 4) != 1)
|
||||||
|
throw runtime_error("wrong parameter count, expect <id> (<group name> <begin> <end> <recurse>)+");
|
||||||
|
|
||||||
|
RegionsHighlighter::NamedRegionDescList regions;
|
||||||
|
for (size_t i = 1; i < parser.positional_count(); i += 4)
|
||||||
|
{
|
||||||
|
if (parser[i].empty() or parser[i+1].empty() or parser[i+2].empty())
|
||||||
|
throw runtime_error("group id, begin and end must not be empty");
|
||||||
|
|
||||||
|
Regex begin{parser[i+1], Regex::nosubs | Regex::optimize };
|
||||||
|
Regex end{parser[i+2], Regex::nosubs | Regex::optimize };
|
||||||
|
Regex recurse;
|
||||||
|
if (not parser[i+3].empty())
|
||||||
|
recurse = Regex{parser[i+3], Regex::nosubs | Regex::optimize };
|
||||||
|
|
||||||
|
regions.push_back({ parser[i], {std::move(begin), std::move(end), std::move(recurse)} });
|
||||||
|
}
|
||||||
|
String default_group;
|
||||||
|
if (parser.has_option("default"))
|
||||||
|
default_group = parser.option_value("default");
|
||||||
|
|
||||||
|
return {parser[0], make_unique<RegionsHighlighter>(std::move(regions),
|
||||||
|
std::move(default_group))};
|
||||||
|
}
|
||||||
|
catch (RegexError& err)
|
||||||
|
{
|
||||||
|
throw runtime_error(String("regex error: ") + err.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const NamedRegionDescList m_regions;
|
const NamedRegionDescList m_regions;
|
||||||
const String m_default_group;
|
const String m_default_group;
|
||||||
|
id_map<HighlighterGroup> m_groups;
|
||||||
|
|
||||||
struct Region
|
struct Region
|
||||||
{
|
{
|
||||||
|
@ -1029,68 +1102,31 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
HighlighterAndId regions_factory(HighlighterParameters params)
|
template<typename Func>
|
||||||
|
HighlighterFactory simple_factory(const String id, Func func)
|
||||||
{
|
{
|
||||||
try
|
return [=](HighlighterParameters params)
|
||||||
{
|
{
|
||||||
static const ParameterDesc param_desc{
|
return HighlighterAndId(id, make_simple_highlighter(func));
|
||||||
SwitchMap{ { "default", { true, "" } } },
|
};
|
||||||
ParameterDesc::Flags::SwitchesOnlyAtStart,
|
|
||||||
5};
|
|
||||||
|
|
||||||
ParametersParser parser{params, param_desc};
|
|
||||||
if ((parser.positional_count() % 4) != 1)
|
|
||||||
throw runtime_error("wrong parameter count, expect <id> (<group name> <begin> <end> <recurse>)+");
|
|
||||||
|
|
||||||
RegionsHighlighter::NamedRegionDescList regions;
|
|
||||||
id_map<HighlighterGroup> groups;
|
|
||||||
for (size_t i = 1; i < parser.positional_count(); i += 4)
|
|
||||||
{
|
|
||||||
if (parser[i].empty() or parser[i+1].empty() or parser[i+2].empty())
|
|
||||||
throw runtime_error("group id, begin and end must not be empty");
|
|
||||||
|
|
||||||
Regex begin{parser[i+1], Regex::nosubs | Regex::optimize };
|
|
||||||
Regex end{parser[i+2], Regex::nosubs | Regex::optimize };
|
|
||||||
Regex recurse;
|
|
||||||
if (not parser[i+3].empty())
|
|
||||||
recurse = Regex{parser[i+3], Regex::nosubs | Regex::optimize };
|
|
||||||
|
|
||||||
regions.push_back({ parser[i], {std::move(begin), std::move(end), std::move(recurse)} });
|
|
||||||
groups.append({ parser[i], HighlighterGroup{} });
|
|
||||||
}
|
|
||||||
String default_group;
|
|
||||||
if (parser.has_option("default"))
|
|
||||||
{
|
|
||||||
default_group = parser.option_value("default");
|
|
||||||
groups.append({ default_group, HighlighterGroup{} });
|
|
||||||
}
|
|
||||||
|
|
||||||
return {parser[0],
|
|
||||||
HierachicalHighlighter(
|
|
||||||
RegionsHighlighter(std::move(regions), std::move(default_group)), std::move(groups))};
|
|
||||||
}
|
|
||||||
catch (RegexError& err)
|
|
||||||
{
|
|
||||||
throw runtime_error(String("regex error: ") + err.what());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void register_highlighters()
|
void register_highlighters()
|
||||||
{
|
{
|
||||||
HighlighterRegistry& registry = HighlighterRegistry::instance();
|
HighlighterRegistry& registry = HighlighterRegistry::instance();
|
||||||
|
|
||||||
registry.register_func("number_lines", SimpleHighlighterFactory<show_line_numbers>("number_lines"));
|
registry.register_func("number_lines", simple_factory("number_lines", show_line_numbers));
|
||||||
registry.register_func("show_matching", SimpleHighlighterFactory<show_matching_char>("show_matching"));
|
registry.register_func("show_matching", simple_factory("show_matching", show_matching_char));
|
||||||
registry.register_func("show_whitespaces", SimpleHighlighterFactory<show_whitespaces>("show_whitespaces"));
|
registry.register_func("show_whitespaces", simple_factory("show_whitespaces", show_whitespaces));
|
||||||
registry.register_func("fill", fill_factory);
|
registry.register_func("fill", create_fill_highlighter);
|
||||||
registry.register_func("regex", highlight_regex_factory);
|
registry.register_func("regex", RegexHighlighter::create);
|
||||||
registry.register_func("regex_option", highlight_regex_option_factory);
|
registry.register_func("regex_option", create_regex_option_highlighter);
|
||||||
registry.register_func("search", highlight_search_factory);
|
registry.register_func("search", create_search_highlighter);
|
||||||
registry.register_func("group", highlighter_group_factory);
|
registry.register_func("group", create_highlighter_group);
|
||||||
registry.register_func("flag_lines", flag_lines_factory);
|
registry.register_func("flag_lines", create_flag_lines_highlighter);
|
||||||
registry.register_func("line_option", highlight_line_option_factory);
|
registry.register_func("line_option", create_line_option_highlighter);
|
||||||
registry.register_func("ref", reference_factory);
|
registry.register_func("ref", create_reference_highlighter);
|
||||||
registry.register_func("regions", regions_factory);
|
registry.register_func("regions", RegionsHighlighter::create);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,13 @@
|
||||||
|
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
std::unique_ptr<T> make_unique(Args&&... args)
|
||||||
|
{
|
||||||
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
// *** Singleton ***
|
// *** Singleton ***
|
||||||
//
|
//
|
||||||
// Singleton helper class, every singleton type T should inherit
|
// Singleton helper class, every singleton type T should inherit
|
||||||
|
|
|
@ -28,9 +28,9 @@ Window::Window(Buffer& buffer)
|
||||||
m_hooks.run_hook("WinCreate", buffer.name(), hook_handler.context());
|
m_hooks.run_hook("WinCreate", buffer.name(), hook_handler.context());
|
||||||
m_options.register_watcher(*this);
|
m_options.register_watcher(*this);
|
||||||
|
|
||||||
m_builtin_highlighters.append({"tabulations", expand_tabulations});
|
m_builtin_highlighters.add_child({"tabulations"_str, make_simple_highlighter(expand_tabulations)});
|
||||||
m_builtin_highlighters.append({"unprintable", expand_unprintable});
|
m_builtin_highlighters.add_child({"unprintable"_str, make_simple_highlighter(expand_unprintable)});
|
||||||
m_builtin_highlighters.append({"selections", highlight_selections});
|
m_builtin_highlighters.add_child({"selections"_str, make_simple_highlighter(highlight_selections)});
|
||||||
|
|
||||||
for (auto& option : m_options.flatten_options())
|
for (auto& option : m_options.flatten_options())
|
||||||
on_option_changed(*option);
|
on_option_changed(*option);
|
||||||
|
@ -82,8 +82,8 @@ void Window::update_display_buffer(const Context& context)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_display_buffer.compute_range();
|
m_display_buffer.compute_range();
|
||||||
m_highlighters(context, HighlightFlags::Highlight, m_display_buffer);
|
m_highlighters.highlight(context, HighlightFlags::Highlight, m_display_buffer);
|
||||||
m_builtin_highlighters(context, HighlightFlags::Highlight, m_display_buffer);
|
m_builtin_highlighters.highlight(context, HighlightFlags::Highlight, m_display_buffer);
|
||||||
|
|
||||||
// cut the start of the line before m_position.column
|
// cut the start of the line before m_position.column
|
||||||
for (auto& line : lines)
|
for (auto& line : lines)
|
||||||
|
@ -182,8 +182,8 @@ void Window::scroll_to_keep_selection_visible_ifn(const Context& context)
|
||||||
lines.emplace_back(AtomList{ {buffer(), cursor.line, cursor.line+1} });
|
lines.emplace_back(AtomList{ {buffer(), cursor.line, cursor.line+1} });
|
||||||
|
|
||||||
display_buffer.compute_range();
|
display_buffer.compute_range();
|
||||||
m_highlighters(context, HighlightFlags::MoveOnly, display_buffer);
|
m_highlighters.highlight(context, HighlightFlags::MoveOnly, display_buffer);
|
||||||
m_builtin_highlighters(context, HighlightFlags::MoveOnly, display_buffer);
|
m_builtin_highlighters.highlight(context, HighlightFlags::MoveOnly, display_buffer);
|
||||||
|
|
||||||
// now we can compute where the cursor is in display columns
|
// now we can compute where the cursor is in display columns
|
||||||
// (this is only valid if highlighting one line and multiple lines put
|
// (this is only valid if highlighting one line and multiple lines put
|
||||||
|
@ -266,8 +266,8 @@ ByteCoordAndTarget Window::offset_coord(ByteCoordAndTarget coord, LineCount offs
|
||||||
|
|
||||||
InputHandler hook_handler{{ *m_buffer, Selection{} } };
|
InputHandler hook_handler{{ *m_buffer, Selection{} } };
|
||||||
hook_handler.context().set_window(*this);
|
hook_handler.context().set_window(*this);
|
||||||
m_highlighters(hook_handler.context(), HighlightFlags::MoveOnly, display_buffer);
|
m_highlighters.highlight(hook_handler.context(), HighlightFlags::MoveOnly, display_buffer);
|
||||||
m_builtin_highlighters(hook_handler.context(), HighlightFlags::MoveOnly, display_buffer);
|
m_builtin_highlighters.highlight(hook_handler.context(), HighlightFlags::MoveOnly, display_buffer);
|
||||||
|
|
||||||
CharCount column = coord.target == -1 ? find_display_column(lines[0], buffer(), coord) : coord.target;
|
CharCount column = coord.target == -1 ? find_display_column(lines[0], buffer(), coord) : coord.target;
|
||||||
return { find_buffer_coord(lines[1], buffer(), column), column };
|
return { find_buffer_coord(lines[1], buffer(), column), column };
|
||||||
|
|
|
@ -36,7 +36,7 @@ public:
|
||||||
|
|
||||||
CharCoord display_position(ByteCoord coord);
|
CharCoord display_position(ByteCoord coord);
|
||||||
|
|
||||||
HighlighterGroup& highlighters() { return m_highlighters; }
|
Highlighter& highlighters() { return m_highlighters; }
|
||||||
|
|
||||||
OptionManager& options() { return m_options; }
|
OptionManager& options() { return m_options; }
|
||||||
const OptionManager& options() const { return m_options; }
|
const OptionManager& options() const { return m_options; }
|
||||||
|
|
Loading…
Reference in New Issue
Block a user