Refactor RegionsHighlighters to define each region as a separate command

This commit is contained in:
Maxime Coste 2018-06-28 19:50:23 +10:00
parent c9cdae4364
commit b0ccf97b44
4 changed files with 217 additions and 138 deletions

View File

@ -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}/;"

View File

@ -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
# ‾‾‾‾‾‾‾‾ # ‾‾‾‾‾‾‾‾

View File

@ -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

View File

@ -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" } });
} }
} }