Refactor RegionsHighlighters to define each region as a separate command
This commit is contained in:
parent
c9cdae4364
commit
b0ccf97b44
|
@ -136,17 +136,15 @@ evaluate-commands %sh{
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf %s\\n '
|
printf %s\\n '
|
||||||
add-highlighter shared/FT regions -default code -match-capture \
|
add-highlighter shared/FT regions
|
||||||
string %{MAYBEAT(?<!QUOTE)(?<!QUOTE\\)"} %{(?<!\\)(?:\\\\)*"} "" \
|
add-highlighter shared/FT/code default-region group
|
||||||
string %{R"([^(]*)\(} %{\)([^")]*)"} "" \
|
add-highlighter shared/FT/string region %{MAYBEAT(?<!QUOTE)(?<!QUOTE\\)"} %{(?<!\\)(?:\\\\)*"} "" fill string
|
||||||
comment /\* \*/ "" \
|
add-highlighter shared/FT/raw_string region %{R"([^(]*)\(} %{\)([^")]*)"} "" fill string
|
||||||
comment // $ "" \
|
add-highlighter shared/FT/comment region /\* \*/ "" fill comment
|
||||||
disabled ^\h*?#\h*if\h+(?:0|FALSE)\b "#\h*(?:else|elif|endif)" "#\h*if(?:def)?" \
|
add-highlighter shared/FT/line_comment region // $ "" fill comment
|
||||||
macro %{^\h*?\K#} %{(?<!\\)\n} ""
|
add-highlighter shared/FT/disabled region ^\h*?#\h*if\h+(?:0|FALSE)\b "#\h*(?:else|elif|endif)" "#\h*if(?:def)?" fill rgb:666666
|
||||||
|
add-highlighter shared/FT/macro region %{^\h*?\K#} %{(?<!\\)\n} "" group
|
||||||
|
|
||||||
add-highlighter shared/FT/string/fill fill string
|
|
||||||
add-highlighter shared/FT/comment/fill fill comment
|
|
||||||
add-highlighter shared/FT/disabled/fill fill rgb:666666
|
|
||||||
add-highlighter shared/FT/macro/fill fill meta
|
add-highlighter shared/FT/macro/fill fill meta
|
||||||
add-highlighter shared/FT/macro/include regex ^\h*#include\h+(\S*) 1:module
|
add-highlighter shared/FT/macro/include regex ^\h*#include\h+(\S*) 1:module
|
||||||
' | sed -e "s/FT/${ft}/g; s/QUOTE/'/g; s/MAYBEAT/${maybe_at}/;"
|
' | sed -e "s/FT/${ft}/g; s/QUOTE/'/g; s/MAYBEAT/${maybe_at}/;"
|
||||||
|
|
|
@ -11,18 +11,19 @@ hook global BufCreate (.*/)?(kakrc|.*.kak) %{
|
||||||
# Highlighters & Completion
|
# Highlighters & Completion
|
||||||
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||||
|
|
||||||
add-highlighter shared/kakrc regions -default code \
|
add-highlighter shared/kakrc regions
|
||||||
comment (^|\h)\K# $ '' \
|
add-highlighter shared/kakrc/code default-region group
|
||||||
double_string %{(^|\h)\K"} %{"(?!")} %{(?<!")("")+(?!")} \
|
add-highlighter shared/kakrc/comment region (^|\h)\K# $ '' fill comment
|
||||||
single_string %{(^|\h)\K'} %{'(?!')} %{(?<!')('')+(?!')} \
|
add-highlighter shared/kakrc/double_string region %{(^|\h)\K"} %{"(?!")} %{(?<!")("")+(?!")} group
|
||||||
shell '(^|\h)\K%?%sh\{' '\}' '\{' \
|
add-highlighter shared/kakrc/single_string region %{(^|\h)\K'} %{'(?!')} %{(?<!')('')+(?!')} group
|
||||||
shell '(^|\h)\K%?%sh\(' '\)' '\(' \
|
add-highlighter shared/kakrc/shell1 region '(^|\h)\K%?%sh\{' '\}' '\{' ref sh
|
||||||
shell '(^|\h)\K%?%sh\[' '\]' '\[' \
|
add-highlighter shared/kakrc/shell2 region '(^|\h)\K%?%sh\(' '\)' '\(' ref sh
|
||||||
shell '(^|\h)\K%?%sh<' '>' '<' \
|
add-highlighter shared/kakrc/shell3 region '(^|\h)\K%?%sh\[' '\]' '\[' ref sh
|
||||||
shell '(^|\h)\K-shell-(completion|candidates)\h+%\{' '\}' '\{' \
|
add-highlighter shared/kakrc/shell4 region '(^|\h)\K%?%sh<' '>' '<' ref sh
|
||||||
shell '(^|\h)\K-shell-(completion|candidates)\h+%\(' '\)' '\(' \
|
add-highlighter shared/kakrc/shell5 region '(^|\h)\K-shell-(completion|candidates)\h+%\{' '\}' '\{' ref sh
|
||||||
shell '(^|\h)\K-shell-(completion|candidates)\h+%\[' '\]' '\[' \
|
add-highlighter shared/kakrc/shell6 region '(^|\h)\K-shell-(completion|candidates)\h+%\(' '\)' '\(' ref sh
|
||||||
shell '(^|\h)\K-shell-(completion|candidates)\h+%<' '>' '<'
|
add-highlighter shared/kakrc/shell7 region '(^|\h)\K-shell-(completion|candidates)\h+%\[' '\]' '\[' ref sh
|
||||||
|
add-highlighter shared/kakrc/shell8 region '(^|\h)\K-shell-(completion|candidates)\h+%<' '>' '<' ref sh
|
||||||
|
|
||||||
evaluate-commands %sh{
|
evaluate-commands %sh{
|
||||||
# Grammar
|
# Grammar
|
||||||
|
@ -61,8 +62,6 @@ add-highlighter shared/kakrc/double_string/fill fill string
|
||||||
add-highlighter shared/kakrc/double_string/escape regex '""' 0:default+b
|
add-highlighter shared/kakrc/double_string/escape regex '""' 0:default+b
|
||||||
add-highlighter shared/kakrc/single_string/fill fill string
|
add-highlighter shared/kakrc/single_string/fill fill string
|
||||||
add-highlighter shared/kakrc/single_string/escape regex "''" 0:default+b
|
add-highlighter shared/kakrc/single_string/escape regex "''" 0:default+b
|
||||||
add-highlighter shared/kakrc/comment/fill fill comment
|
|
||||||
add-highlighter shared/kakrc/shell/sh ref sh
|
|
||||||
|
|
||||||
# Commands
|
# Commands
|
||||||
# ‾‾‾‾‾‾‾‾
|
# ‾‾‾‾‾‾‾‾
|
||||||
|
|
|
@ -2,32 +2,32 @@ hook global BufCreate .*\.(z|ba|c|k|mk)?sh(rc|_profile)? %{
|
||||||
set-option buffer filetype sh
|
set-option buffer filetype sh
|
||||||
}
|
}
|
||||||
|
|
||||||
add-highlighter shared/sh regions -default code -match-capture \
|
add-highlighter shared/sh regions
|
||||||
double_string %{(?<!\\)(?:\\\\)*\K"} %{(?<!\\)(?:\\\\)*"} '' \
|
add-highlighter shared/sh/code default-region group
|
||||||
single_string %{(?<!\\)(?:\\\\)*\K'} %{'} '' \
|
add-highlighter shared/sh/double_string region %{(?<!\\)(?:\\\\)*\K"} %{(?<!\\)(?:\\\\)*"} '' group
|
||||||
comment '(?<!\$)#' '$' '' \
|
add-highlighter shared/sh/single_string region %{(?<!\\)(?:\\\\)*\K'} %{'} '' fill string
|
||||||
heredoc '<<-?(\w+)' '^\t*(\w+)$' ''
|
add-highlighter shared/sh/comment region '(?<!\$)#' '$' '' fill comment
|
||||||
|
add-highlighter shared/sh/heredoc region -match-capture '<<-?(\w+)' '^\t*(\w+)$' '' fill string
|
||||||
|
|
||||||
add-highlighter shared/sh/double_string/fill fill string
|
add-highlighter shared/sh/double_string/fill fill string
|
||||||
add-highlighter shared/sh/single_string/fill fill string
|
|
||||||
add-highlighter shared/sh/comment/fill fill comment
|
|
||||||
add-highlighter shared/sh/heredoc/fill fill string
|
|
||||||
|
|
||||||
evaluate-commands %sh{
|
evaluate-commands %sh{
|
||||||
# Grammar
|
# Grammar
|
||||||
keywords="alias|bind|builtin|caller|case|cd|command|coproc|declare|do|done"
|
keywords="alias bind builtin caller case cd command coproc declare do done
|
||||||
keywords="${keywords}|echo|elif|else|enable|esac|exit|fi|for|function|help"
|
echo elif else enable esac exit fi for function help
|
||||||
keywords="${keywords}|if|in|let|local|logout|mapfile|printf|read|readarray"
|
if in let local logout mapfile printf read readarray
|
||||||
keywords="${keywords}|readonly|return|select|set|shift|source|test|then"
|
readonly return select set shift source test then
|
||||||
keywords="${keywords}|time|type|typeset|ulimit|unalias|until|while|break|continue"
|
time type typeset ulimit unalias until while break continue"
|
||||||
|
|
||||||
|
join() { printf "%s" "$1" | tr -s ' \n' "$2"; }
|
||||||
|
|
||||||
# Add the language's grammar to the static completion list
|
# Add the language's grammar to the static completion list
|
||||||
printf %s\\n "hook global WinSetOption filetype=sh %{
|
printf %s\\n "hook global WinSetOption filetype=sh %{
|
||||||
set-option window static_words ${keywords}
|
set-option window static_words $(join "${keywords}" ' ')
|
||||||
}" | tr '|' ' '
|
}"
|
||||||
|
|
||||||
# Highlight keywords
|
# Highlight keywords
|
||||||
printf %s "add-highlighter shared/sh/code/keywords regex \b(${keywords})\b 0:keyword"
|
printf %s "add-highlighter shared/sh/code/keywords regex \b($(join ${keywords} '|'))\b 0:keyword"
|
||||||
}
|
}
|
||||||
|
|
||||||
add-highlighter shared/sh/code/operators regex [\[\]\(\)&|]{1,2} 0:operator
|
add-highlighter shared/sh/code/operators regex [\[\]\(\)&|]{1,2} 0:operator
|
||||||
|
|
|
@ -1728,60 +1728,17 @@ struct RegionMatches
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RegionDesc
|
|
||||||
{
|
|
||||||
String m_name;
|
|
||||||
Regex m_begin;
|
|
||||||
Regex m_end;
|
|
||||||
Regex m_recurse;
|
|
||||||
bool m_match_capture;
|
|
||||||
|
|
||||||
RegionMatches find_matches(const Buffer& buffer) const
|
|
||||||
{
|
|
||||||
RegionMatches res;
|
|
||||||
Kakoune::find_matches(buffer, res.begin_matches, m_begin, m_match_capture);
|
|
||||||
Kakoune::find_matches(buffer, res.end_matches, m_end, m_match_capture);
|
|
||||||
if (not m_recurse.empty())
|
|
||||||
Kakoune::find_matches(buffer, res.recurse_matches, m_recurse, m_match_capture);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_matches(const Buffer& buffer,
|
|
||||||
ConstArrayView<LineModification> modifs,
|
|
||||||
RegionMatches& matches) const
|
|
||||||
{
|
|
||||||
Kakoune::update_matches(buffer, modifs, matches.begin_matches, m_begin, m_match_capture);
|
|
||||||
Kakoune::update_matches(buffer, modifs, matches.end_matches, m_end, m_match_capture);
|
|
||||||
if (not m_recurse.empty())
|
|
||||||
Kakoune::update_matches(buffer, modifs, matches.recurse_matches, m_recurse, m_match_capture);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RegionsHighlighter : public Highlighter
|
struct RegionsHighlighter : public Highlighter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using RegionDescList = Vector<RegionDesc, MemoryDomain::Highlight>;
|
RegionsHighlighter()
|
||||||
|
: Highlighter{HighlightPass::Colorize} {}
|
||||||
RegionsHighlighter(RegionDescList regions, String default_group)
|
|
||||||
: Highlighter{HighlightPass::Colorize},
|
|
||||||
m_regions{std::move(regions)},
|
|
||||||
m_default_group{std::move(default_group)}
|
|
||||||
{
|
|
||||||
if (m_regions.empty())
|
|
||||||
throw runtime_error("at least one region must be defined");
|
|
||||||
|
|
||||||
for (auto& region : m_regions)
|
|
||||||
{
|
|
||||||
m_groups.insert({region.m_name, HighlighterGroup{HighlightPass::Colorize}});
|
|
||||||
if (region.m_begin.empty() or region.m_end.empty())
|
|
||||||
throw runtime_error("invalid regex for region highlighter");
|
|
||||||
}
|
|
||||||
if (not m_default_group.empty())
|
|
||||||
m_groups.insert({m_default_group, HighlighterGroup{HighlightPass::Colorize}});
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_highlight(HighlightContext context, DisplayBuffer& display_buffer, BufferRange range) override
|
void do_highlight(HighlightContext context, DisplayBuffer& display_buffer, BufferRange range) override
|
||||||
{
|
{
|
||||||
|
if (m_regions.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
auto display_range = display_buffer.range();
|
auto display_range = display_buffer.range();
|
||||||
const auto& buffer = context.context.buffer();
|
const auto& buffer = context.context.buffer();
|
||||||
auto& regions = get_regions_for_range(buffer, range);
|
auto& regions = get_regions_for_range(buffer, range);
|
||||||
|
@ -1796,8 +1753,8 @@ public:
|
||||||
return c;
|
return c;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto default_group_it = m_groups.find(m_default_group);
|
auto default_region_it = m_regions.find(m_default_region);
|
||||||
const bool apply_default = default_group_it != m_groups.end();
|
const bool apply_default = default_region_it != m_regions.end();
|
||||||
|
|
||||||
auto last_begin = (begin == regions.begin()) ?
|
auto last_begin = (begin == regions.begin()) ?
|
||||||
BufferCoord{0,0} : (begin-1)->end;
|
BufferCoord{0,0} : (begin-1)->end;
|
||||||
|
@ -1807,20 +1764,20 @@ public:
|
||||||
if (apply_default and last_begin < begin->begin)
|
if (apply_default and last_begin < begin->begin)
|
||||||
apply_highlighter(context, display_buffer,
|
apply_highlighter(context, display_buffer,
|
||||||
correct(last_begin), correct(begin->begin),
|
correct(last_begin), correct(begin->begin),
|
||||||
default_group_it->value);
|
*default_region_it->value);
|
||||||
|
|
||||||
auto it = m_groups.find(begin->group);
|
auto it = m_regions.find(begin->region);
|
||||||
if (it == m_groups.end())
|
if (it == m_regions.end())
|
||||||
continue;
|
continue;
|
||||||
apply_highlighter(context, display_buffer,
|
apply_highlighter(context, display_buffer,
|
||||||
correct(begin->begin), correct(begin->end),
|
correct(begin->begin), correct(begin->end),
|
||||||
it->value);
|
*it->value);
|
||||||
last_begin = begin->end;
|
last_begin = begin->end;
|
||||||
}
|
}
|
||||||
if (apply_default and last_begin < display_range.end)
|
if (apply_default and last_begin < display_range.end)
|
||||||
apply_highlighter(context, display_buffer,
|
apply_highlighter(context, display_buffer,
|
||||||
correct(last_begin), range.end,
|
correct(last_begin), range.end,
|
||||||
default_group_it->value);
|
*default_region_it->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_children() const override { return true; }
|
bool has_children() const override { return true; }
|
||||||
|
@ -1829,13 +1786,31 @@ public:
|
||||||
{
|
{
|
||||||
auto sep_it = find(path, '/');
|
auto sep_it = find(path, '/');
|
||||||
StringView id(path.begin(), sep_it);
|
StringView id(path.begin(), sep_it);
|
||||||
auto it = m_groups.find(id);
|
auto it = m_regions.find(id);
|
||||||
if (it == m_groups.end())
|
if (it == m_regions.end())
|
||||||
throw child_not_found(format("no such id: {}", id));
|
throw child_not_found(format("no such id: {}", id));
|
||||||
if (sep_it == path.end())
|
if (sep_it == path.end())
|
||||||
return it->value;
|
return *it->value;
|
||||||
else
|
else
|
||||||
return it->value.get_child({sep_it+1, path.end()});
|
return it->value->get_child({sep_it+1, path.end()});
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_child(String name, std::unique_ptr<Highlighter>&& hl) override
|
||||||
|
{
|
||||||
|
if (not dynamic_cast<RegionHighlighter*>(hl.get()))
|
||||||
|
throw runtime_error{"only region highlighter can be added as child of a regions highlighter"};
|
||||||
|
if (m_regions.contains(name))
|
||||||
|
throw runtime_error{format("duplicate id: '{}'", name)};
|
||||||
|
|
||||||
|
std::unique_ptr<RegionHighlighter> region_hl{dynamic_cast<RegionHighlighter*>(hl.release())};
|
||||||
|
if (region_hl->is_default())
|
||||||
|
{
|
||||||
|
if (not m_default_region.empty())
|
||||||
|
throw runtime_error{"default region already defined"};
|
||||||
|
m_default_region = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_regions.insert({std::move(name), std::move(region_hl)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Completions complete_child(StringView path, ByteCount cursor_pos, bool group) const override
|
Completions complete_child(StringView path, ByteCount cursor_pos, bool group) const override
|
||||||
|
@ -1848,51 +1823,146 @@ public:
|
||||||
return offset_pos(hl.complete_child(path.substr(offset), cursor_pos - offset, group), offset);
|
return offset_pos(hl.complete_child(path.substr(offset), cursor_pos - offset, group), offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto container = m_groups | transform(&decltype(m_groups)::Item::key);
|
auto container = m_regions | transform(&decltype(m_regions)::Item::key);
|
||||||
return { 0, 0, complete(path, cursor_pos, container) };
|
return { 0, 0, complete(path, cursor_pos, container) };
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<Highlighter> create(HighlighterParameters params)
|
static std::unique_ptr<Highlighter> create(HighlighterParameters params)
|
||||||
|
{
|
||||||
|
if (not params.empty())
|
||||||
|
throw runtime_error{"unexpected parameters"};
|
||||||
|
return std::make_unique<RegionsHighlighter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Highlighter> create_region(HighlighterParameters params)
|
||||||
{
|
{
|
||||||
static const ParameterDesc param_desc{
|
static const ParameterDesc param_desc{
|
||||||
{ { "default", { true, "" } }, { "match-capture", { false, "" } } },
|
{ { "match-capture", { false, "" } } },
|
||||||
ParameterDesc::Flags::SwitchesOnlyAtStart, 5
|
ParameterDesc::Flags::SwitchesOnlyAtStart, 4
|
||||||
};
|
};
|
||||||
|
|
||||||
ParametersParser parser{params, param_desc};
|
ParametersParser parser{params, param_desc};
|
||||||
if ((parser.positional_count() % 4) != 0)
|
|
||||||
throw runtime_error("wrong parameter count, expected (<group name> <begin> <end> <recurse>)+");
|
|
||||||
|
|
||||||
const bool match_capture = (bool)parser.get_switch("match-capture");
|
const bool match_capture = (bool)parser.get_switch("match-capture");
|
||||||
RegionsHighlighter::RegionDescList regions;
|
if (parser[0].empty() or parser[1].empty())
|
||||||
for (size_t i = 0; i < parser.positional_count(); i += 4)
|
throw runtime_error("begin and end must not be empty");
|
||||||
{
|
|
||||||
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");
|
|
||||||
|
|
||||||
const RegexCompileFlags flags = match_capture ?
|
const RegexCompileFlags flags = match_capture ?
|
||||||
RegexCompileFlags::Optimize : RegexCompileFlags::NoSubs | RegexCompileFlags::Optimize;
|
RegexCompileFlags::Optimize : RegexCompileFlags::NoSubs | RegexCompileFlags::Optimize;
|
||||||
|
|
||||||
regions.push_back({ parser[i],
|
auto delegate = HighlighterRegistry::instance()[parser[3]].factory(parser.positionals_from(4));
|
||||||
Regex{parser[i+1], flags}, Regex{parser[i+2], flags},
|
return std::make_unique<RegionHighlighter>(std::move(delegate), Regex{parser[0], flags}, Regex{parser[1], flags}, parser[2].empty() ? Regex{} : Regex{parser[2], flags}, match_capture);
|
||||||
parser[i+3].empty() ? Regex{} : Regex{parser[i+3], flags},
|
|
||||||
match_capture });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto default_group = parser.get_switch("default").value_or(StringView{}).str();
|
static std::unique_ptr<Highlighter> create_default_region(HighlighterParameters params)
|
||||||
return std::make_unique<RegionsHighlighter>(std::move(regions), default_group);
|
{
|
||||||
|
static const ParameterDesc param_desc{ {}, ParameterDesc::Flags::SwitchesOnlyAtStart, 1 };
|
||||||
|
ParametersParser parser{params, param_desc};
|
||||||
|
|
||||||
|
auto delegate = HighlighterRegistry::instance()[parser[0]].factory(parser.positionals_from(1));
|
||||||
|
return std::make_unique<RegionHighlighter>(std::move(delegate));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const RegionDescList m_regions;
|
struct RegionHighlighter : public Highlighter
|
||||||
const String m_default_group;
|
{
|
||||||
HashMap<String, HighlighterGroup, MemoryDomain::Highlight> m_groups;
|
RegionHighlighter(std::unique_ptr<Highlighter>&& delegate,
|
||||||
|
Regex begin, Regex end, Regex recurse,
|
||||||
|
bool match_capture)
|
||||||
|
: Highlighter{delegate->passes()},
|
||||||
|
m_delegate{std::move(delegate)},
|
||||||
|
m_begin{std::move(begin)}, m_end{std::move(end)}, m_recurse{std::move(recurse)},
|
||||||
|
m_match_capture{match_capture}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RegionHighlighter(std::unique_ptr<Highlighter>&& delegate)
|
||||||
|
: Highlighter{delegate->passes()}, m_delegate{std::move(delegate)}, m_default{true}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_children() const override
|
||||||
|
{
|
||||||
|
return m_delegate->has_children();
|
||||||
|
}
|
||||||
|
|
||||||
|
Highlighter& get_child(StringView path) override
|
||||||
|
{
|
||||||
|
return m_delegate->get_child(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_child(String name, std::unique_ptr<Highlighter>&& hl) override
|
||||||
|
{
|
||||||
|
return m_delegate->add_child(name, std::move(hl));
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_child(StringView id) override
|
||||||
|
{
|
||||||
|
return m_delegate->remove_child(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Completions complete_child(StringView path, ByteCount cursor_pos, bool group) const override
|
||||||
|
{
|
||||||
|
return m_delegate->complete_child(path, cursor_pos, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_unique_ids(Vector<StringView>& unique_ids) const override
|
||||||
|
{
|
||||||
|
return m_delegate->fill_unique_ids(unique_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_highlight(HighlightContext context, DisplayBuffer& display_buffer, BufferRange range) override
|
||||||
|
{
|
||||||
|
return m_delegate->highlight(context, display_buffer, range);
|
||||||
|
}
|
||||||
|
|
||||||
|
RegionMatches find_matches(const Buffer& buffer) const
|
||||||
|
{
|
||||||
|
RegionMatches res;
|
||||||
|
if (m_default)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
Kakoune::find_matches(buffer, res.begin_matches, m_begin, m_match_capture);
|
||||||
|
Kakoune::find_matches(buffer, res.end_matches, m_end, m_match_capture);
|
||||||
|
if (not m_recurse.empty())
|
||||||
|
Kakoune::find_matches(buffer, res.recurse_matches, m_recurse, m_match_capture);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_matches(const Buffer& buffer,
|
||||||
|
ConstArrayView<LineModification> modifs,
|
||||||
|
RegionMatches& matches) const
|
||||||
|
{
|
||||||
|
if (m_default)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Kakoune::update_matches(buffer, modifs, matches.begin_matches, m_begin, m_match_capture);
|
||||||
|
Kakoune::update_matches(buffer, modifs, matches.end_matches, m_end, m_match_capture);
|
||||||
|
if (not m_recurse.empty())
|
||||||
|
Kakoune::update_matches(buffer, modifs, matches.recurse_matches, m_recurse, m_match_capture);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool match_capture() const { return m_match_capture; }
|
||||||
|
bool is_default() const { return m_default; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Highlighter> m_delegate;
|
||||||
|
|
||||||
|
Regex m_begin;
|
||||||
|
Regex m_end;
|
||||||
|
Regex m_recurse;
|
||||||
|
bool m_match_capture = false;
|
||||||
|
bool m_default = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
HashMap<String, std::unique_ptr<RegionHighlighter>, MemoryDomain::Highlight> m_regions;
|
||||||
|
String m_default_region;
|
||||||
|
|
||||||
struct Region
|
struct Region
|
||||||
{
|
{
|
||||||
BufferCoord begin;
|
BufferCoord begin;
|
||||||
BufferCoord end;
|
BufferCoord end;
|
||||||
StringView group;
|
StringView region;
|
||||||
};
|
};
|
||||||
using RegionList = Vector<Region, MemoryDomain::Highlight>;
|
using RegionList = Vector<Region, MemoryDomain::Highlight>;
|
||||||
|
|
||||||
|
@ -1932,13 +2002,13 @@ private:
|
||||||
{
|
{
|
||||||
cache.matches.resize(m_regions.size());
|
cache.matches.resize(m_regions.size());
|
||||||
for (size_t i = 0; i < m_regions.size(); ++i)
|
for (size_t i = 0; i < m_regions.size(); ++i)
|
||||||
cache.matches[i] = m_regions[i].find_matches(buffer);
|
cache.matches[i] = m_regions.item(i).value->find_matches(buffer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto modifs = compute_line_modifications(buffer, cache.timestamp);
|
auto modifs = compute_line_modifications(buffer, cache.timestamp);
|
||||||
for (size_t i = 0; i < m_regions.size(); ++i)
|
for (size_t i = 0; i < m_regions.size(); ++i)
|
||||||
m_regions[i].update_matches(buffer, modifs, cache.matches[i]);
|
m_regions.item(i).value->update_matches(buffer, modifs, cache.matches[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.regions.clear();
|
cache.regions.clear();
|
||||||
|
@ -1955,24 +2025,23 @@ private:
|
||||||
begin != end; )
|
begin != end; )
|
||||||
{
|
{
|
||||||
const RegionMatches& matches = cache.matches[begin.first];
|
const RegionMatches& matches = cache.matches[begin.first];
|
||||||
auto& region = m_regions[begin.first];
|
auto& region = m_regions.item(begin.first);
|
||||||
auto beg_it = begin.second;
|
auto beg_it = begin.second;
|
||||||
auto end_it = matches.find_matching_end(beg_it->end_coord(),
|
auto end_it = matches.find_matching_end(beg_it->end_coord(),
|
||||||
region.m_match_capture ? beg_it->capture
|
region.value->match_capture() ? beg_it->capture : Optional<StringView>{});
|
||||||
: Optional<StringView>{});
|
|
||||||
|
|
||||||
if (end_it == matches.end_matches.end() or end_it->end_coord() >= range.end)
|
if (end_it == matches.end_matches.end() or end_it->end_coord() >= range.end)
|
||||||
{
|
{
|
||||||
regions.push_back({ {beg_it->line, beg_it->begin},
|
regions.push_back({ {beg_it->line, beg_it->begin},
|
||||||
range.end,
|
range.end,
|
||||||
region.m_name });
|
region.key });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
regions.push_back({ beg_it->begin_coord(),
|
regions.push_back({ beg_it->begin_coord(),
|
||||||
end_it->end_coord(),
|
end_it->end_coord(),
|
||||||
region.m_name });
|
region.key });
|
||||||
auto end_coord = end_it->end_coord();
|
auto end_coord = end_it->end_coord();
|
||||||
|
|
||||||
// With empty begin and end matches (for example if the regexes
|
// With empty begin and end matches (for example if the regexes
|
||||||
|
@ -2034,8 +2103,8 @@ void register_highlighters()
|
||||||
registry.insert({
|
registry.insert({
|
||||||
"group",
|
"group",
|
||||||
{ create_highlighter_group,
|
{ create_highlighter_group,
|
||||||
"Parameters: [-passes <passes>] <group name>\n"
|
"Parameters: [-passes <passes>]\n"
|
||||||
"Creates a named group that can contain other highlighters,\n"
|
"Creates a group that can contain other highlighters,\n"
|
||||||
"<passes> is a flags(colorize|move|wrap) defaulting to colorize\n"
|
"<passes> is a flags(colorize|move|wrap) defaulting to colorize\n"
|
||||||
"which specify what kind of highlighters can be put in the group" } });
|
"which specify what kind of highlighters can be put in the group" } });
|
||||||
registry.insert({
|
registry.insert({
|
||||||
|
@ -2083,13 +2152,26 @@ void register_highlighters()
|
||||||
registry.insert({
|
registry.insert({
|
||||||
"regions",
|
"regions",
|
||||||
{ RegionsHighlighter::create,
|
{ RegionsHighlighter::create,
|
||||||
"Parameters: [-default <default group>] [-match-capture] <name> {<region name> <begin> <end> <recurse>}..."
|
"Parameters: None"
|
||||||
"Split the highlighting into regions defined by the <begin>, <end> and <recurse> regex\n"
|
"Holds child region highlighters and segments the buffer in ranges based on those regions\n"
|
||||||
"The region <region name> starts at <begin> match, end at <end> match that does not\n"
|
"definitions. The regions highlighter finds the next region to start by finding which\n"
|
||||||
"close a <recurse> match. In between region is the <default group>.\n"
|
"of its child region has the leftmost starting point from current position. In between\n"
|
||||||
"Highlighting a region is done by adding highlighters into the different <region name> subgroups.\n"
|
"regions, the default-region child highlighter is applied (if such a child exists)" } });
|
||||||
"If -match-capture is specified, then regions end/recurse matches must have the same \\1\n"
|
registry.insert({
|
||||||
"capture content as the begin to be considered"} });
|
"region",
|
||||||
|
{ RegionsHighlighter::create_region,
|
||||||
|
"Parameters: [-match-capture] <begin> <end> <recurse> <type> <params>...\n."
|
||||||
|
"Define a region for a regions highlighter, and apply the given delegate\n"
|
||||||
|
"highlighter as defined by <type> and eventual <params>...\n"
|
||||||
|
"The region starts at <begin> match and ends at the first <end> match that\n"
|
||||||
|
"does not close a <recurse> match.\n"
|
||||||
|
"If -match-capture is specified, then regions end/recurse matches must have\n"
|
||||||
|
"the same \\1 capture content as the begin match to be considered"} });
|
||||||
|
registry.insert({
|
||||||
|
"default-region",
|
||||||
|
{ RegionsHighlighter::create_default_region,
|
||||||
|
"Parameters: <delegate_type> <delegate_params>...\n"
|
||||||
|
"Define the default region of a regions highlighter" } });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user