summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2015-02-16 19:13:55 +0000
committerMaxime Coste <frrrwww@gmail.com>2015-02-16 19:13:55 +0000
commit8f6dab08d6b0782cf46ec192dbf6be797d9da7f5 (patch)
tree3e47d94ac533d42f057c587f222d05057daa1011 /src
parentce950ec9f7fa9cf2f65ee02430a7dc4edec3e172 (diff)
Try to limit the quantity of buffer reparsed by RegexHighlighter
Diffstat (limited to 'src')
-rw-r--r--src/highlighters.cc82
1 files changed, 61 insertions, 21 deletions
diff --git a/src/highlighters.cc b/src/highlighters.cc
index d3a7967b..9ac42b75 100644
--- a/src/highlighters.cc
+++ b/src/highlighters.cc
@@ -293,8 +293,25 @@ private:
bool m_force_update = false;
- Cache::MatchesList& update_cache_ifn(const Buffer& buffer, const BufferRange& display_range,
- const BufferRange& buffer_range)
+ void add_matches(const Buffer& buffer, Cache::MatchesList& match_list,
+ BufferRange range)
+ {
+ using RegexIt = RegexIterator<BufferIterator>;
+ RegexIt re_it{buffer.iterator_at(range.first),
+ buffer.iterator_at(range.second), m_regex};
+ RegexIt re_end;
+ for (; re_it != re_end; ++re_it)
+ {
+ match_list.emplace_back();
+ auto& match = match_list.back();
+ for (auto& sub : *re_it)
+ match.emplace_back(sub.first.coord(), sub.second.coord());
+ }
+ }
+
+ Cache::MatchesList& update_cache_ifn(const Buffer& buffer,
+ BufferRange display_range,
+ BufferRange buffer_range)
{
Cache& cache = m_cache.get(buffer);
auto& matches = cache.m_matches;
@@ -314,32 +331,55 @@ private:
[](const BufferRange& lhs, const Cache::RangeAndMatches& rhs)
{ return lhs.first < rhs.first.second; });
-
if (it == matches.end() or it->first.first > range.second)
+ {
it = matches.insert(it, Cache::RangeAndMatches{range, {}});
- else if (it->first.first <= range.first and it->first.second >= range.second)
- return it->second;
- else
+ add_matches(buffer, it->second, range);
+ }
+ else if (it->second.empty())
{
- range.first = std::min(range.first, it->first.first);
- range.second = std::max(range.second, it->first.second);
it->first = range;
- it->second.clear();
+ add_matches(buffer, it->second, range);
}
- auto& match_list = it->second;
-
- using RegexIt = RegexIterator<BufferIterator>;
- RegexIt re_it{buffer.iterator_at(range.first),
- buffer.iterator_at(range.second), m_regex};
- RegexIt re_end;
- for (; re_it != re_end; ++re_it)
+ else
{
- match_list.emplace_back();
- auto& match = match_list.back();
- for (auto& sub : *re_it)
- match.emplace_back(sub.first.coord(), sub.second.coord());
+ // Here we extend the matches, that is not strictly valid,
+ // but may work nicely with every reasonable regex, and
+ // greatly reduces regex parsing. To change if we encounter
+ // regex that do not work great with that.
+ BufferRange& old_range = it->first;
+ Cache::MatchesList& matches = it->second;
+ auto first_end = matches.front()[0].second;
+ auto last_begin = matches.back()[0].first;
+ bool remove_last = true;
+
+ // add regex matches from new begin to old first match end
+ if (range.first < old_range.first)
+ {
+ old_range.first = range.first;
+ Cache::MatchesList new_matches;
+ add_matches(buffer, new_matches, {range.first, first_end});
+ matches.erase(matches.begin());
+
+ // matches.front() was matches.back() as well, so
+ // make sure we do not try to remove it again.
+ if (matches.empty())
+ remove_last = false;
+
+ std::copy(std::make_move_iterator(new_matches.begin()),
+ std::make_move_iterator(new_matches.end()),
+ std::inserter(matches, matches.begin()));
+ }
+ // add regex matches from old last match begin to new end
+ if (old_range.second < range.second)
+ {
+ old_range.second = range.second;
+ if (remove_last)
+ matches.pop_back();
+ add_matches(buffer, matches, {last_begin, range.second});
+ }
}
- return match_list;
+ return it->second;
}
};