diff --git a/internal/editor/chunked_buffer.go b/internal/editor/chunked_buffer.go index 5b5e15e..e327483 100644 --- a/internal/editor/chunked_buffer.go +++ b/internal/editor/chunked_buffer.go @@ -452,10 +452,12 @@ func (cb *ChunkedBuffer) VisibleByteRange(scrollOffset ui.Dp, byteOffset int, vi // released). That is the root cause of the ~1GB "Unknown" memory on large // files. // - // Word wrap does not require a separate path: each real line produces at - // least one visual line, so shaping viewportHeight/lineHeight real lines - // always yields at least as many visual lines as fit in the viewport. The - // extra wrapped lines are simply clipped by the renderer. + // Word wrap does not require a separate path: the viewport top and bottom + // are each expressed in VISUAL-line space and mapped to the logical lines + // that contain them (WrapIndex.LineForVisual). Because each logical line + // produces at least one visual line, that logical range always covers the + // viewport; the fetch is viewport-bounded no matter how many wraps lie + // above it, and any spill past the bottom edge is clipped by the renderer. lineH := lineHeight if lineH <= 0 { lineH = EffectiveLineHeight() @@ -564,10 +566,18 @@ func (cb *ChunkedBuffer) visibleByteRangePrecise(scrollOffset ui.Dp, viewportHei // (the legacy no-wrap behavior). v0, _ := scrollDecompose(scrollOffset, lineHeight) startLine = int(v0) + endLine := int(math.Ceil(float64(scrollOffset+viewportHeight) / float64(lineHeight))) if w := cb.WrapIndex; w != nil { startLine = w.LineForVisual(int32(v0)) + // endLine is still in VISUAL space: it is the visual line at the + // viewport bottom, so map it to the logical line that contains it, + // exactly like the top. Using the raw visual number as a logical + // index over-fetched the window by every wrapped line above the + // viewport — an over-fetch that grows without bound with scroll + // depth, so shaping/drawing (and therefore scroll responsiveness) + // degraded the further down the file you were. + endLine = w.LineForVisual(int32(endLine)) } - endLine := int(math.Ceil(float64(scrollOffset+viewportHeight) / float64(lineHeight))) if startLine < 0 { startLine = 0