diff --git a/src/highlighters.cc b/src/highlighters.cc index 594c6b0e..3fe8ad11 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -2210,11 +2210,57 @@ private: m_regexes.insert({key, Regex{str, flags}}); } - void add_matches(const Buffer& buffer, LineRange range, Cache& cache) const + class MatchAdder { - for (auto& [key, regex] : m_regexes) - cache.matches[key]; + public: + MatchAdder(RegionsHighlighter& region, const Buffer& buffer, Cache& cache) : m_buffer(buffer) + { + for (auto& [key, regex] : region.m_regexes) + cache.matches[key]; + for (auto& [key, regex] : region.m_regexes) + m_matchers.push_back(Matcher{cache.matches.get(key), regex}); + } + ~MatchAdder() + { + // Move new matches into position. + for (auto& [matches, regex, pivot, vm] : m_matchers) + std::inplace_merge(matches.begin(), matches.begin() + pivot, matches.end(), + [](const auto& lhs, const auto& rhs) { return lhs.line < rhs.line; }); + } + + void add(LineRange range) + { + for (auto line = range.begin; line < range.end; ++line) + { + const StringView l = m_buffer[line]; + const auto flags = RegexExecFlags::NotEndOfLine; // buffer line already ends with \n + + for (auto& [matches, regex, pivot, vm] : m_matchers) + { + auto extra_flags = RegexExecFlags::None; + auto pos = l.begin(); + while (vm.exec(pos, l.end(), l.begin(), l.end(), flags | extra_flags)) + { + ConstArrayView captures = vm.captures(); + const bool with_capture = regex.mark_count() > 0 and captures[2] != nullptr and + captures[1] - captures[0] < std::numeric_limits::max(); + matches.push_back({ + line, + (int)(captures[0] - l.begin()), + (int)(captures[1] - l.begin()), + (uint16_t)(with_capture ? captures[2] - captures[0] : 0), + (uint16_t)(with_capture ? captures[3] - captures[2] : 0) + }); + pos = captures[1]; + + extra_flags = (captures[0] == captures[1]) ? RegexExecFlags::NotInitialNull : RegexExecFlags::None; + } + } + } + } + + private: struct Matcher { RegexMatchList& matches; @@ -2222,48 +2268,10 @@ private: size_t pivot = matches.size(); ThreadedRegexVM vm{*regex.impl()}; }; - Vector matchers; - for (auto& [key, regex] : m_regexes) - matchers.push_back(Matcher{cache.matches.get(key), regex}); - for (auto line = range.begin; line < range.end; ++line) - { - const StringView l = buffer[line]; - const auto flags = RegexExecFlags::NotEndOfLine; // buffer line already ends with \n - - for (auto& [matches, regex, pivot, vm] : matchers) - { - auto extra_flags = RegexExecFlags::None; - auto pos = l.begin(); - while (vm.exec(pos, l.end(), l.begin(), l.end(), flags | extra_flags)) - { - ConstArrayView captures = vm.captures(); - const bool with_capture = regex.mark_count() > 0 and captures[2] != nullptr and - captures[1] - captures[0] < std::numeric_limits::max(); - matches.push_back({ - line, - (int)(captures[0] - l.begin()), - (int)(captures[1] - l.begin()), - (uint16_t)(with_capture ? captures[2] - captures[0] : 0), - (uint16_t)(with_capture ? captures[3] - captures[2] : 0) - }); - pos = captures[1]; - - extra_flags = (captures[0] == captures[1]) ? RegexExecFlags::NotInitialNull : RegexExecFlags::None; - } - } - } - - for (auto& [matches, regex, pivot, vm] : matchers) - { - auto pos = std::lower_bound(matches.begin(), matches.begin() + pivot, range.begin, - [](const RegexMatch& m, LineCount l) { return m.line < l; }); - kak_assert(pos == matches.begin() + pivot or pos->line >= range.end); // We should not have had matches for range - - // Move new matches into position. - std::rotate(pos, matches.begin() + pivot, matches.end()); - } - } + const Buffer& m_buffer; + Vector m_matchers; + }; void update_changed_lines(const Buffer& buffer, ConstArrayView modifs, Cache& cache) { @@ -2299,7 +2307,6 @@ private: } } - bool update_matches(Cache& cache, const Buffer& buffer, LineRange range) { const size_t buffer_timestamp = buffer.timestamp(); @@ -2315,7 +2322,7 @@ private: add_regex(region->m_recurse, region->match_capture()); } - add_matches(buffer, range, cache); + MatchAdder{*this, buffer, cache}.add(range); cache.ranges.reset(range); cache.buffer_timestamp = buffer_timestamp; cache.regions_timestamp = m_regions_timestamp; @@ -2333,10 +2340,11 @@ private: modified = true; } - cache.ranges.add_range(range, [&, this](const LineRange& range) { + MatchAdder matches{*this, buffer, cache}; + cache.ranges.add_range(range, [&](const LineRange& range) { if (range.begin == range.end) return; - add_matches(buffer, range, cache); + matches.add(range); modified = true; }); return modified; diff --git a/src/line_modification.cc b/src/line_modification.cc index 8551e394..f63bc6ea 100644 --- a/src/line_modification.cc +++ b/src/line_modification.cc @@ -147,26 +147,27 @@ void LineRangeSet::update(ConstArrayView modifs) void LineRangeSet::add_range(LineRange range, FunctionRef on_new_range) { - auto it = std::lower_bound(begin(), end(), range.begin, - [](LineRange range, LineCount line) { return range.end < line; }); - if (it == end() or it->begin > range.end) + auto insert_at = std::lower_bound(begin(), end(), range.begin, + [](LineRange range, LineCount line) { return range.end < line; }); + if (insert_at == end() or insert_at->begin > range.end) on_new_range(range); else { auto pos = range.begin; - while (it != end() and it->begin <= range.end) + auto it = insert_at; + for (; it != end() and it->begin <= range.end; ++it) { if (pos < it->begin) on_new_range({pos, it->begin}); range = LineRange{std::min(range.begin, it->begin), std::max(range.end, it->end)}; pos = it->end; - it = erase(it); } + insert_at = erase(insert_at, it); if (pos < range.end) on_new_range({pos, range.end}); } - insert(it, range); + insert(insert_at, range); } void LineRangeSet::remove_range(LineRange range)