fix: performance issues with textarea - #1024
Open
andrinoff wants to merge 1 commit into
Open
Conversation
Signed-off-by: drew <me@andrinoff.com>
Member
Author
2026-07-31.14-49-07.mp4The first part showed matcha integrated with these changes. The second one is pre-compiled with the upstream bubbles. The performance is WAY better and it is usable now (the previous one took 10 seconds of scrolling to do nothing), but it is still quite slow, i'll try to look into it further, possibly missed something |
andrinoff
marked this pull request as ready for review
August 1, 2026 18:25
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CONTRIBUTING.md.What?
Replaces the textarea's hash-keyed wrap memoization with a per-row wrap cache, and makes rendering window-bound instead of buffer-bound.
The new
wrapCacheholds one entry per logical row with that row's soft-wrapped lines, plus an offsets table mapping each row to the visual line it starts at. Entries are validated by comparing the cached source slice against the live one (length plus backing pointer), so any edit that replaces a row's contents is detected for free; edits that mutate a row in place (transpose, case changes, insert) invalidate explicitly. Structural edits (splitLine,mergeLineAbove/Below, multi-line paste) shift the cache withinsert/remove, so untouched rows below the cursor are never re-wrapped.viewLines()replacesview(). It renders only the visual lines inside the viewport window and hands the viewport a[]stringthroughSetContentLinesinstead of a joined blob. Off-screen lines stay empty and the viewport still scrolls over the full content.visualLineOffsets,rowForVisualLine,totalVisualLines, andcursorLineNumbernow read the offset table by binary search instead of walking and re-wrapping every row.wrap()tracks the current row width as it goes rather than re-measuring the accumulated line per word.Also deletes
internal/memoizationWhy?
The old cache was keyed by
sha256(string(runes) + width), so every lookup hashed the full line content, andcursorLineNumber,totalVisualLines, andvieweach walked all rows on every keystroke. Rendering built the entire buffer as one string regardless of what was visible. Cost was O(content) rather than O(viewport), so a textarea holding a large document became unusable.Measured on a 60-column, 20-line-tall textarea, old to new: at 100 lines, view goes 2.41 ms to 0.61 ms and keystroke-plus-view 5.13 ms to 1.15 ms; at 1,000 lines, 41.2 ms to 1.00 ms and 85.6 ms to 1.17 ms; at 10,000 lines, 241.8 ms to 0.56 ms and 671.0 ms to 1.14 ms. Render cost is now flat in content size.
SetValueis unchanged at 2.6 to 2.9 ms, since the initial wrap is still cold there.Fixes CHARM-1891
Fixes #1023