Replace vector of vector in RegexHighlighter with a single vector.

This commit is contained in:
Maxime Coste 2015-02-17 13:50:31 +00:00
parent 2f890f12c6
commit 59177c12f9

View File

@ -165,8 +165,6 @@ auto apply_face = [](const Face& face)
}; };
}; };
using FacesSpec = Vector<String, MemoryDomain::Highlight>;
static HighlighterAndId create_fill_highlighter(HighlighterParameters params) static HighlighterAndId create_fill_highlighter(HighlighterParameters params)
{ {
if (params.size() != 1) if (params.size() != 1)
@ -206,12 +204,15 @@ static bool overlaps(const BufferRange& lhs, const BufferRange& rhs)
: rhs.second > lhs.first; : rhs.second > lhs.first;
} }
using FacesSpec = Vector<std::pair<size_t, String>, MemoryDomain::Highlight>;
class RegexHighlighter : public Highlighter class RegexHighlighter : public Highlighter
{ {
public: public:
RegexHighlighter(Regex regex, FacesSpec faces) RegexHighlighter(Regex regex, FacesSpec faces)
: m_regex{std::move(regex)}, m_faces{std::move(faces)} : m_regex{std::move(regex)}, m_faces{std::move(faces)}
{ {
ensure_first_face_is_capture_0();
} }
void highlight(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer, BufferRange range) override void highlight(const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer, BufferRange range) override
@ -219,20 +220,24 @@ public:
if (flags != HighlightFlags::Highlight or not overlaps(display_buffer.range(), range)) if (flags != HighlightFlags::Highlight or not overlaps(display_buffer.range(), range))
return; return;
Vector<Optional<Face>> faces(m_faces.size()); Vector<Face> faces(m_faces.size());
auto& cache = update_cache_ifn(context.buffer(), display_buffer.range(), range); for (int f = 0; f < m_faces.size(); ++f)
for (auto& match : cache)
{ {
for (size_t n = 0; n < match.size(); ++n) if (not m_faces[f].second.empty())
{ faces[f] = get_face(m_faces[f].second);
if (n >= m_faces.size() or m_faces[n].empty())
continue;
if (not faces[n])
faces[n] = get_face(m_faces[n]);
highlight_range(display_buffer, match[n].first, match[n].second, true,
apply_face(*faces[n]));
} }
auto& matches = get_matches(context.buffer(), display_buffer.range(), range);
kak_assert(matches.size() % m_faces.size() == 0);
for (size_t m = 0; m < matches.size(); ++m)
{
auto& face = faces[m % faces.size()];
if (face == Face{})
continue;
highlight_range(display_buffer,
matches[m].first, matches[m].second,
true, apply_face(face));
} }
} }
@ -240,6 +245,7 @@ public:
{ {
m_regex = std::move(regex); m_regex = std::move(regex);
m_faces = std::move(faces); m_faces = std::move(faces);
ensure_first_face_is_capture_0();
++m_regex_version; ++m_regex_version;
} }
@ -260,9 +266,7 @@ public:
"' expected <capture>:<facespec>"); "' expected <capture>:<facespec>");
get_face(res[2].str()); // throw if wrong face spec get_face(res[2].str()); // throw if wrong face spec
int capture = str_to_int(res[1].str()); int capture = str_to_int(res[1].str());
if (capture >= faces.size()) faces.emplace_back(capture, res[2].str());
faces.resize(capture+1);
faces[capture] = res[2].str();
} }
String id = "hlregex'" + params[0] + "'"; String id = "hlregex'" + params[0] + "'";
@ -279,12 +283,13 @@ public:
} }
private: private:
// stores the range for each highlighted capture of each match
using MatchList = Vector<BufferRange, MemoryDomain::Highlight>;
struct Cache struct Cache
{ {
size_t m_timestamp = -1; size_t m_timestamp = -1;
size_t m_regex_version = -1; size_t m_regex_version = -1;
using MatchesList = Vector<Vector<BufferRange, MemoryDomain::Highlight>, MemoryDomain::Highlight>; using RangeAndMatches = std::pair<BufferRange, MatchList>;
using RangeAndMatches = std::pair<BufferRange, MatchesList>;
Vector<RangeAndMatches, MemoryDomain::Highlight> m_matches; Vector<RangeAndMatches, MemoryDomain::Highlight> m_matches;
}; };
BufferSideCache<Cache> m_cache; BufferSideCache<Cache> m_cache;
@ -294,24 +299,38 @@ private:
size_t m_regex_version = 0; size_t m_regex_version = 0;
void add_matches(const Buffer& buffer, Cache::MatchesList& match_list, void ensure_first_face_is_capture_0()
{
if (m_faces.empty())
return;
std::sort(m_faces.begin(), m_faces.end(),
[](const std::pair<size_t, String>& lhs,
const std::pair<size_t, String>& rhs)
{ return lhs.first < rhs.first; });
if (m_faces[0].first != 0)
m_faces.emplace(m_faces.begin(), 0, String{});
}
void add_matches(const Buffer& buffer, MatchList& matches,
BufferRange range) BufferRange range)
{ {
kak_assert(matches.size() % m_faces.size() == 0);
using RegexIt = RegexIterator<BufferIterator>; using RegexIt = RegexIterator<BufferIterator>;
RegexIt re_it{buffer.iterator_at(range.first), RegexIt re_it{buffer.iterator_at(range.first),
buffer.iterator_at(range.second), m_regex}; buffer.iterator_at(range.second), m_regex};
RegexIt re_end; RegexIt re_end;
for (; re_it != re_end; ++re_it) for (; re_it != re_end; ++re_it)
{ {
match_list.emplace_back(); for (size_t i = 0; i < m_faces.size(); ++i)
auto& match = match_list.back(); {
for (auto& sub : *re_it) auto& sub = (*re_it)[m_faces[i].first];
match.emplace_back(sub.first.coord(), sub.second.coord()); matches.emplace_back(sub.first.coord(), sub.second.coord());
}
} }
} }
Cache::MatchesList& update_cache_ifn(const Buffer& buffer, MatchList& get_matches(const Buffer& buffer, BufferRange display_range,
BufferRange display_range,
BufferRange buffer_range) BufferRange buffer_range)
{ {
Cache& cache = m_cache.get(buffer); Cache& cache = m_cache.get(buffer);
@ -349,21 +368,25 @@ private:
// greatly reduces regex parsing. To change if we encounter // greatly reduces regex parsing. To change if we encounter
// regex that do not work great with that. // regex that do not work great with that.
BufferRange& old_range = it->first; BufferRange& old_range = it->first;
Cache::MatchesList& matches = it->second; MatchList& matches = it->second;
auto first_end = matches.front()[0].second;
auto last_begin = matches.back()[0].first; // Thanks to the ensure_first_face_is_capture_0 method, we know
// these point to the first/last matches capture 0.
auto first_end = matches.begin()->second;
auto last_begin = (matches.end() - m_faces.size())->first;
bool remove_last = true; bool remove_last = true;
// add regex matches from new begin to old first match end // add regex matches from new begin to old first match end
if (range.first < old_range.first) if (range.first < old_range.first)
{ {
old_range.first = range.first; old_range.first = range.first;
Cache::MatchesList new_matches; MatchList new_matches;
add_matches(buffer, new_matches, {range.first, first_end}); add_matches(buffer, new_matches, {range.first, first_end});
matches.erase(matches.begin()); matches.erase(matches.begin(), matches.begin() + m_faces.size());
// matches.front() was matches.back() as well, so // first matches was last matches as well, so
// make sure we do not try to remove it again. // make sure we do not try to remove them again.
if (matches.empty()) if (matches.empty())
remove_last = false; remove_last = false;
@ -376,7 +399,7 @@ private:
{ {
old_range.second = range.second; old_range.second = range.second;
if (remove_last) if (remove_last)
matches.pop_back(); matches.erase(matches.end() - m_faces.size(), matches.end());
add_matches(buffer, matches, {last_begin, range.second}); add_matches(buffer, matches, {last_begin, range.second});
} }
} }
@ -435,7 +458,7 @@ 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");
auto get_face = [](const Context& context){ auto get_face = [](const Context& context){
return FacesSpec{ { "Search" } }; return FacesSpec{ { 0, "Search" } };
}; };
auto get_regex = [](const Context&){ auto get_regex = [](const Context&){
auto s = Context().main_sel_register_value("/"); auto s = Context().main_sel_register_value("/");
@ -458,7 +481,7 @@ HighlighterAndId create_regex_option_highlighter(HighlighterParameters params)
String facespec = params[1]; String facespec = params[1];
auto get_face = [=](const Context&){ auto get_face = [=](const Context&){
return FacesSpec{ { facespec } }; return FacesSpec{ { 0, facespec } };
}; };
String option_name = params[0]; String option_name = params[0];