Add support for recursion in region highlighter
An optional parameter defines the recursion regex, that match potential closers. For example, %sh{ ... } blocks support nested { }, so defining \{ as the recurse regex make the region highlighter correctly match %sh{ ... { ... } ... } constructs
This commit is contained in:
parent
37d66b1e0b
commit
0a76fe3040
|
@ -17,7 +17,7 @@ addhl -def-group kakrc/single_string/content fill string
|
||||||
|
|
||||||
addhl -def-group kakrc regex (^|\h)\#[^\n]*\n 0:comment
|
addhl -def-group kakrc regex (^|\h)\#[^\n]*\n 0:comment
|
||||||
|
|
||||||
addhl -def-group kakrc region shell '%sh\{' '\}'
|
addhl -def-group kakrc region shell '%sh\{' '\}' '\{'
|
||||||
addhl -def-group kakrc/shell/content ref sh
|
addhl -def-group kakrc/shell/content ref sh
|
||||||
|
|
||||||
hook global WinSetOption filetype=kak %{ addhl ref kakrc }
|
hook global WinSetOption filetype=kak %{ addhl ref kakrc }
|
||||||
|
|
|
@ -670,10 +670,14 @@ HighlighterAndId reference_factory(HighlighterParameters params)
|
||||||
struct RegionHighlighter
|
struct RegionHighlighter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RegionHighlighter(Regex begin, Regex end)
|
RegionHighlighter(Regex begin, Regex end, Regex recurse = Regex{})
|
||||||
: m_begin(std::move(begin)),
|
: m_begin(std::move(begin)),
|
||||||
m_end(std::move(end))
|
m_end(std::move(end)),
|
||||||
{}
|
m_recurse(std::move(recurse))
|
||||||
|
{
|
||||||
|
if (m_begin.empty() or m_end.empty())
|
||||||
|
throw runtime_error("invalid regex for region highlighter");
|
||||||
|
}
|
||||||
|
|
||||||
void operator()(HierachicalHighlighter::GroupMap groups, const Context& context,
|
void operator()(HierachicalHighlighter::GroupMap groups, const Context& context,
|
||||||
HighlightFlags flags, DisplayBuffer& display_buffer)
|
HighlightFlags flags, DisplayBuffer& display_buffer)
|
||||||
|
@ -705,6 +709,7 @@ public:
|
||||||
private:
|
private:
|
||||||
Regex m_begin;
|
Regex m_begin;
|
||||||
Regex m_end;
|
Regex m_end;
|
||||||
|
Regex m_recurse;
|
||||||
|
|
||||||
struct Region
|
struct Region
|
||||||
{
|
{
|
||||||
|
@ -719,26 +724,18 @@ private:
|
||||||
LineCount line;
|
LineCount line;
|
||||||
ByteCount begin;
|
ByteCount begin;
|
||||||
ByteCount end;
|
ByteCount end;
|
||||||
|
|
||||||
|
ByteCoord begin_coord() const { return { line, begin }; }
|
||||||
|
ByteCoord end_coord() const { return { line, end }; }
|
||||||
};
|
};
|
||||||
using MatchList = std::vector<Match>;
|
using MatchList = std::vector<Match>;
|
||||||
|
|
||||||
static bool compare_matches_end(const Match& lhs, const Match& rhs)
|
|
||||||
{
|
|
||||||
return (lhs.line != rhs.line) ? lhs.line < rhs.line
|
|
||||||
: lhs.end < rhs.end;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool compare_matches_begin(const Match& lhs, const Match& rhs)
|
|
||||||
{
|
|
||||||
return (lhs.line != rhs.line) ? lhs.line < rhs.line
|
|
||||||
: lhs.begin < rhs.begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Cache
|
struct Cache
|
||||||
{
|
{
|
||||||
size_t timestamp = 0;
|
size_t timestamp = 0;
|
||||||
MatchList begin_matches;
|
MatchList begin_matches;
|
||||||
MatchList end_matches;
|
MatchList end_matches;
|
||||||
|
MatchList recurse_matches;
|
||||||
RegionList regions;
|
RegionList regions;
|
||||||
};
|
};
|
||||||
BufferSideCache<Cache> m_cache;
|
BufferSideCache<Cache> m_cache;
|
||||||
|
@ -754,30 +751,62 @@ private:
|
||||||
{
|
{
|
||||||
find_matches(buffer, cache.begin_matches, m_begin);
|
find_matches(buffer, cache.begin_matches, m_begin);
|
||||||
find_matches(buffer, cache.end_matches, m_end);
|
find_matches(buffer, cache.end_matches, m_end);
|
||||||
|
if (not m_recurse.empty())
|
||||||
|
find_matches(buffer, cache.recurse_matches, m_recurse);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto modifs = compute_line_modifications(buffer, cache.timestamp);
|
auto modifs = compute_line_modifications(buffer, cache.timestamp);
|
||||||
update_matches(buffer, modifs, cache.begin_matches, m_begin);
|
update_matches(buffer, modifs, cache.begin_matches, m_begin);
|
||||||
update_matches(buffer, modifs, cache.end_matches, m_end);
|
update_matches(buffer, modifs, cache.end_matches, m_end);
|
||||||
|
if (not m_recurse.empty())
|
||||||
|
update_matches(buffer, modifs, cache.recurse_matches, m_recurse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto compare_matches_end = [](const Match& lhs, const Match& rhs) {
|
||||||
|
return lhs.end_coord() < rhs.end_coord();
|
||||||
|
};
|
||||||
|
|
||||||
cache.regions.clear();
|
cache.regions.clear();
|
||||||
for (auto beg_it = cache.begin_matches.begin(), end_it = cache.end_matches.begin();
|
int recurse_level = 0;
|
||||||
|
auto ref_it = cache.begin_matches.begin();
|
||||||
|
for (auto beg_it = cache.begin_matches.begin(),
|
||||||
|
end_it = cache.end_matches.begin(),
|
||||||
|
rec_it = cache.recurse_matches.begin();
|
||||||
beg_it != cache.begin_matches.end(); )
|
beg_it != cache.begin_matches.end(); )
|
||||||
{
|
{
|
||||||
end_it = std::upper_bound(end_it, cache.end_matches.end(),
|
end_it = std::upper_bound(end_it, cache.end_matches.end(),
|
||||||
*beg_it, compare_matches_end);
|
*ref_it, compare_matches_end);
|
||||||
|
rec_it = std::upper_bound(rec_it, cache.recurse_matches.end(),
|
||||||
|
*ref_it, compare_matches_end);
|
||||||
|
|
||||||
if (end_it == cache.end_matches.end())
|
if (end_it == cache.end_matches.end())
|
||||||
{
|
{
|
||||||
cache.regions.push_back({ {beg_it->line, beg_it->begin},
|
cache.regions.push_back({ {beg_it->line, beg_it->begin},
|
||||||
buffer.end_coord() });
|
buffer.end_coord() });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cache.regions.push_back({ {beg_it->line, beg_it->begin},
|
|
||||||
{end_it->line, end_it->end} });
|
while (rec_it != cache.recurse_matches.end() and
|
||||||
|
rec_it->end_coord() < end_it->begin_coord())
|
||||||
|
{
|
||||||
|
++recurse_level;
|
||||||
|
++rec_it;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recurse_level == 0)
|
||||||
|
{
|
||||||
|
cache.regions.push_back({ beg_it->begin_coord(),
|
||||||
|
end_it->end_coord() });
|
||||||
beg_it = std::upper_bound(beg_it, cache.begin_matches.end(),
|
beg_it = std::upper_bound(beg_it, cache.begin_matches.end(),
|
||||||
*end_it, compare_matches_end);
|
*end_it, compare_matches_end);
|
||||||
|
ref_it = beg_it;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
--recurse_level;
|
||||||
|
ref_it = end_it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cache.timestamp = buf_timestamp;
|
cache.timestamp = buf_timestamp;
|
||||||
return cache.regions;
|
return cache.regions;
|
||||||
|
@ -821,9 +850,9 @@ private:
|
||||||
if (not erase)
|
if (not erase)
|
||||||
{
|
{
|
||||||
it->timestamp = buf_timestamp;
|
it->timestamp = buf_timestamp;
|
||||||
kak_assert(buffer.is_valid({it->line, it->begin}) or
|
kak_assert(buffer.is_valid(it->begin_coord()) or
|
||||||
buffer[it->line].length() == it->begin);
|
buffer[it->line].length() == it->begin);
|
||||||
kak_assert(buffer.is_valid({it->line, it->end}) or
|
kak_assert(buffer.is_valid(it->end_coord()) or
|
||||||
buffer[it->line].length() == it->end);
|
buffer[it->line].length() == it->end);
|
||||||
|
|
||||||
if (ins_pos != it)
|
if (ins_pos != it)
|
||||||
|
@ -851,7 +880,9 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::inplace_merge(matches.begin(), matches.begin() + pivot, matches.end(),
|
std::inplace_merge(matches.begin(), matches.begin() + pivot, matches.end(),
|
||||||
compare_matches_begin);
|
[](const Match& lhs, const Match& rhs) {
|
||||||
|
return lhs.begin_coord() < rhs.begin_coord();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -859,14 +890,19 @@ HighlighterAndId region_factory(HighlighterParameters params)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (params.size() != 3)
|
if (params.size() != 3 && params.size() != 4)
|
||||||
throw runtime_error("wrong parameter count");
|
throw runtime_error("wrong parameter count");
|
||||||
|
|
||||||
Regex begin{params[1], Regex::nosubs | Regex::optimize };
|
Regex begin{params[1], Regex::nosubs | Regex::optimize };
|
||||||
Regex end{params[2], Regex::nosubs | Regex::optimize };
|
Regex end{params[2], Regex::nosubs | Regex::optimize };
|
||||||
|
Regex recurse;
|
||||||
|
if (params.size() == 4)
|
||||||
|
recurse = Regex{params[3], Regex::nosubs | Regex::optimize };
|
||||||
|
|
||||||
return {params[0],
|
return {params[0],
|
||||||
HierachicalHighlighter(RegionHighlighter(std::move(begin),
|
HierachicalHighlighter(RegionHighlighter(std::move(begin),
|
||||||
std::move(end)),
|
std::move(end),
|
||||||
|
std::move(recurse)),
|
||||||
{ { "content", HighlighterGroup{} } })};
|
{ { "content", HighlighterGroup{} } })};
|
||||||
}
|
}
|
||||||
catch (boost::regex_error& err)
|
catch (boost::regex_error& err)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user