Invalidate cache when RegionsHighlighter subregions are modified
This commit is contained in:
parent
6d320328b0
commit
1574748d4e
|
@ -1811,6 +1811,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
m_regions.insert({std::move(name), std::move(region_hl)});
|
m_regions.insert({std::move(name), std::move(region_hl)});
|
||||||
|
++m_regions_timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Completions complete_child(StringView path, ByteCount cursor_pos, bool group) const override
|
Completions complete_child(StringView path, ByteCount cursor_pos, bool group) const override
|
||||||
|
@ -1864,6 +1865,109 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct Region
|
||||||
|
{
|
||||||
|
BufferCoord begin;
|
||||||
|
BufferCoord end;
|
||||||
|
StringView region;
|
||||||
|
};
|
||||||
|
using RegionList = Vector<Region, MemoryDomain::Highlight>;
|
||||||
|
|
||||||
|
struct Cache
|
||||||
|
{
|
||||||
|
size_t timestamp = 0;
|
||||||
|
size_t regions_timestamp = 0;
|
||||||
|
Vector<RegionMatches, MemoryDomain::Highlight> matches;
|
||||||
|
HashMap<BufferRange, RegionList, MemoryDomain::Highlight> regions;
|
||||||
|
};
|
||||||
|
|
||||||
|
using RegionAndMatch = std::pair<size_t, RegexMatchList::const_iterator>;
|
||||||
|
|
||||||
|
// find the begin closest to pos in all matches
|
||||||
|
RegionAndMatch find_next_begin(const Cache& cache, BufferCoord pos) const
|
||||||
|
{
|
||||||
|
RegionAndMatch res{0, cache.matches[0].find_next_begin(pos)};
|
||||||
|
for (size_t i = 1; i < cache.matches.size(); ++i)
|
||||||
|
{
|
||||||
|
const auto& matches = cache.matches[i];
|
||||||
|
auto it = matches.find_next_begin(pos);
|
||||||
|
if (it != matches.begin_matches.end() and
|
||||||
|
(res.second == cache.matches[res.first].begin_matches.end() or
|
||||||
|
it->begin_coord() < res.second->begin_coord()))
|
||||||
|
res = RegionAndMatch{i, it};
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RegionList& get_regions_for_range(const Buffer& buffer, BufferRange range)
|
||||||
|
{
|
||||||
|
Cache& cache = m_cache.get(buffer);
|
||||||
|
const size_t buf_timestamp = buffer.timestamp();
|
||||||
|
if (cache.timestamp != buf_timestamp or cache.regions_timestamp != m_regions_timestamp)
|
||||||
|
{
|
||||||
|
if (cache.timestamp == 0 or cache.regions_timestamp != m_regions_timestamp)
|
||||||
|
{
|
||||||
|
cache.matches.resize(m_regions.size());
|
||||||
|
for (size_t i = 0; i < m_regions.size(); ++i)
|
||||||
|
cache.matches[i] = m_regions.item(i).value->find_matches(buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto modifs = compute_line_modifications(buffer, cache.timestamp);
|
||||||
|
for (size_t i = 0; i < m_regions.size(); ++i)
|
||||||
|
m_regions.item(i).value->update_matches(buffer, modifs, cache.matches[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.regions.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = cache.regions.find(range);
|
||||||
|
if (it != cache.regions.end())
|
||||||
|
return it->value;
|
||||||
|
|
||||||
|
RegionList& regions = cache.regions[range];
|
||||||
|
|
||||||
|
for (auto begin = find_next_begin(cache, range.begin),
|
||||||
|
end = RegionAndMatch{ 0, cache.matches[0].begin_matches.end() };
|
||||||
|
begin != end; )
|
||||||
|
{
|
||||||
|
const RegionMatches& matches = cache.matches[begin.first];
|
||||||
|
auto& region = m_regions.item(begin.first);
|
||||||
|
auto beg_it = begin.second;
|
||||||
|
auto end_it = matches.find_matching_end(beg_it->end_coord(),
|
||||||
|
region.value->match_capture() ? beg_it->capture : Optional<StringView>{});
|
||||||
|
|
||||||
|
if (end_it == matches.end_matches.end() or end_it->end_coord() >= range.end)
|
||||||
|
{
|
||||||
|
regions.push_back({ {beg_it->line, beg_it->begin},
|
||||||
|
range.end,
|
||||||
|
region.key });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
regions.push_back({ beg_it->begin_coord(),
|
||||||
|
end_it->end_coord(),
|
||||||
|
region.key });
|
||||||
|
auto end_coord = end_it->end_coord();
|
||||||
|
|
||||||
|
// With empty begin and end matches (for example if the regexes
|
||||||
|
// are /"\K/ and /(?=")/), that case can happen, and would
|
||||||
|
// result in an infinite loop.
|
||||||
|
if (end_coord == beg_it->begin_coord())
|
||||||
|
{
|
||||||
|
kak_assert(beg_it->begin_coord() == beg_it->end_coord() and
|
||||||
|
end_it->begin_coord() == end_it->end_coord());
|
||||||
|
++end_coord.column;
|
||||||
|
}
|
||||||
|
begin = find_next_begin(cache, end_coord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cache.timestamp = buf_timestamp;
|
||||||
|
cache.regions_timestamp = m_regions_timestamp;
|
||||||
|
return regions;
|
||||||
|
}
|
||||||
|
|
||||||
struct RegionHighlighter : public Highlighter
|
struct RegionHighlighter : public Highlighter
|
||||||
{
|
{
|
||||||
RegionHighlighter(std::unique_ptr<Highlighter>&& delegate,
|
RegionHighlighter(std::unique_ptr<Highlighter>&& delegate,
|
||||||
|
@ -1958,107 +2062,8 @@ private:
|
||||||
HashMap<String, std::unique_ptr<RegionHighlighter>, MemoryDomain::Highlight> m_regions;
|
HashMap<String, std::unique_ptr<RegionHighlighter>, MemoryDomain::Highlight> m_regions;
|
||||||
String m_default_region;
|
String m_default_region;
|
||||||
|
|
||||||
struct Region
|
size_t m_regions_timestamp = 0;
|
||||||
{
|
|
||||||
BufferCoord begin;
|
|
||||||
BufferCoord end;
|
|
||||||
StringView region;
|
|
||||||
};
|
|
||||||
using RegionList = Vector<Region, MemoryDomain::Highlight>;
|
|
||||||
|
|
||||||
struct Cache
|
|
||||||
{
|
|
||||||
size_t timestamp = 0;
|
|
||||||
Vector<RegionMatches, MemoryDomain::Highlight> matches;
|
|
||||||
HashMap<BufferRange, RegionList, MemoryDomain::Highlight> regions;
|
|
||||||
};
|
|
||||||
BufferSideCache<Cache> m_cache;
|
BufferSideCache<Cache> m_cache;
|
||||||
|
|
||||||
using RegionAndMatch = std::pair<size_t, RegexMatchList::const_iterator>;
|
|
||||||
|
|
||||||
// find the begin closest to pos in all matches
|
|
||||||
RegionAndMatch find_next_begin(const Cache& cache, BufferCoord pos) const
|
|
||||||
{
|
|
||||||
RegionAndMatch res{0, cache.matches[0].find_next_begin(pos)};
|
|
||||||
for (size_t i = 1; i < cache.matches.size(); ++i)
|
|
||||||
{
|
|
||||||
const auto& matches = cache.matches[i];
|
|
||||||
auto it = matches.find_next_begin(pos);
|
|
||||||
if (it != matches.begin_matches.end() and
|
|
||||||
(res.second == cache.matches[res.first].begin_matches.end() or
|
|
||||||
it->begin_coord() < res.second->begin_coord()))
|
|
||||||
res = RegionAndMatch{i, it};
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RegionList& get_regions_for_range(const Buffer& buffer, BufferRange range)
|
|
||||||
{
|
|
||||||
Cache& cache = m_cache.get(buffer);
|
|
||||||
const size_t buf_timestamp = buffer.timestamp();
|
|
||||||
if (cache.timestamp != buf_timestamp)
|
|
||||||
{
|
|
||||||
if (cache.timestamp == 0)
|
|
||||||
{
|
|
||||||
cache.matches.resize(m_regions.size());
|
|
||||||
for (size_t i = 0; i < m_regions.size(); ++i)
|
|
||||||
cache.matches[i] = m_regions.item(i).value->find_matches(buffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto modifs = compute_line_modifications(buffer, cache.timestamp);
|
|
||||||
for (size_t i = 0; i < m_regions.size(); ++i)
|
|
||||||
m_regions.item(i).value->update_matches(buffer, modifs, cache.matches[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
cache.regions.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto it = cache.regions.find(range);
|
|
||||||
if (it != cache.regions.end())
|
|
||||||
return it->value;
|
|
||||||
|
|
||||||
RegionList& regions = cache.regions[range];
|
|
||||||
|
|
||||||
for (auto begin = find_next_begin(cache, range.begin),
|
|
||||||
end = RegionAndMatch{ 0, cache.matches[0].begin_matches.end() };
|
|
||||||
begin != end; )
|
|
||||||
{
|
|
||||||
const RegionMatches& matches = cache.matches[begin.first];
|
|
||||||
auto& region = m_regions.item(begin.first);
|
|
||||||
auto beg_it = begin.second;
|
|
||||||
auto end_it = matches.find_matching_end(beg_it->end_coord(),
|
|
||||||
region.value->match_capture() ? beg_it->capture : Optional<StringView>{});
|
|
||||||
|
|
||||||
if (end_it == matches.end_matches.end() or end_it->end_coord() >= range.end)
|
|
||||||
{
|
|
||||||
regions.push_back({ {beg_it->line, beg_it->begin},
|
|
||||||
range.end,
|
|
||||||
region.key });
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
regions.push_back({ beg_it->begin_coord(),
|
|
||||||
end_it->end_coord(),
|
|
||||||
region.key });
|
|
||||||
auto end_coord = end_it->end_coord();
|
|
||||||
|
|
||||||
// With empty begin and end matches (for example if the regexes
|
|
||||||
// are /"\K/ and /(?=")/), that case can happen, and would
|
|
||||||
// result in an infinite loop.
|
|
||||||
if (end_coord == beg_it->begin_coord())
|
|
||||||
{
|
|
||||||
kak_assert(beg_it->begin_coord() == beg_it->end_coord() and
|
|
||||||
end_it->begin_coord() == end_it->end_coord());
|
|
||||||
++end_coord.column;
|
|
||||||
}
|
|
||||||
begin = find_next_begin(cache, end_coord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cache.timestamp = buf_timestamp;
|
|
||||||
return regions;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void setup_builtin_highlighters(HighlighterGroup& group)
|
void setup_builtin_highlighters(HighlighterGroup& group)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user