Skip to content

Only apply highlights to visible portion of buffer#5434

Open
bscuron wants to merge 1 commit intomawww:masterfrom
bscuron:highlight_fix
Open

Only apply highlights to visible portion of buffer#5434
bscuron wants to merge 1 commit intomawww:masterfrom
bscuron:highlight_fix

Conversation

@bscuron
Copy link
Contributor

@bscuron bscuron commented Jan 11, 2026

cat src/*.cc src/*.hh > test.cc
perf record ./src/kak test.cc

Before: 81.36% Kakoune::RegionsHighlighter::MatchAdder::add(Kakoune::Range<Kakoune::LineCount>)
After: 0.36% Kakoune::RegionsHighlighter::MatchAdder::add(Kakoune::Range<Kakoune::LineCount>)

This noticeably improves performance in larger files.

All tests still pass.

@Screwtapello
Copy link
Contributor

Is there a correctness issue where jumping into the middle of a region causes it to be highlighted incorrectly? For example, if a file has a /* */ comment block that's several screens long, and you jump into the middle of it (so that the /* is off the top of the screen), does the text still get highlighted like it was a comment?

@bscuron
Copy link
Contributor Author

bscuron commented Jan 11, 2026

Is there a correctness issue where jumping into the middle of a region causes it to be highlighted incorrectly? For example, if a file has a /* */ comment block that's several screens long, and you jump into the middle of it (so that the /* is off the top of the screen), does the text still get highlighted like it was a comment?

Ah it does not correctly apply a highlight in this case. It looks like vim handles this in a few different ways: syntax synchronizing. Of those ways, this simplest would be to scan the previous n lines when applying highlights.

@mawww
Copy link
Owner

mawww commented Jan 12, 2026

Regions are by design applied to the whole buffer, in order to be fully correct. We do a few compromises in order to make them fast, most notably not allowing region start/end to span multiple lines. What you measure here is the initial work that needs to be done to get all matches, but after that regions are updated incrementally based off changes made to the buffer and should be fast enough. Have you noticed performance issue past the first display of the large buffer ? Or only on load time ?

@bscuron
Copy link
Contributor Author

bscuron commented Jan 13, 2026

Regions are by design applied to the whole buffer, in order to be fully correct. We do a few compromises in order to make them fast, most notably not allowing region start/end to span multiple lines. What you measure here is the initial work that needs to be done to get all matches, but after that regions are updated incrementally based off changes made to the buffer and should be fast enough. Have you noticed performance issue past the first display of the large buffer ? Or only on load time ?

There seems to be some sort of performance impact even past initial load. For example, when opening a large file, creating a selection for each character 'e' and typing some text.

Currently, each selection enters MatchAdder.add and is also evaluated by the regex_vm. The difference can be seen by:

  1. Applying this patch to the master branch:
diff --git a/src/highlighters.cc b/src/highlighters.cc
index d77b27db..1af7ce14 100644
--- a/src/highlighters.cc
+++ b/src/highlighters.cc
@@ -2216,6 +2216,12 @@ private:
 
         void add(LineRange range)
         {
+
+            FILE *fp = fopen("test.txt", "a");
+            fprintf(fp, "%zu\n", (size_t)range.begin);
+            fprintf(fp, "%zu\n", (size_t)range.end);
+            fclose(fp);
+
             for (auto line = range.begin; line < range.end; ++line)
             {
                 const StringView l = m_buffer[line];
  1. Opening a large file cat src/*.cc src/*.hh > test.cc
  2. Adding many selections
  3. Making an edit
  4. Rename test.txt
  5. Run same steps on this branch

The output txt file for the master branch contains all selection ranges. The output txt file for this branch contains only the visible ranges.

Another note: after running the test on the master branch, delete the txt file without closing kak. Create many selections again and make an edit. The selection ranges are there again. It looks like each selection range would be reevaluated on each keystroke across the whole buffer.

@krobelus
Copy link
Contributor

yes, whenever a line is changed, any cached highlighting is invalidated.
It's possible that this can be made smarter but it's rarely relevant in practice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants