Add View.BufferLineForViewLine to map a view line to its buffer line

The diff-line parser needs to walk the unwrapped diff buffer upward from a
clicked/selected row, but the row index it's handed is a view line index (which
counts wrapped lines). Expose the existing internal mapping (viewLines[y].linesY)
so callers can translate, with the same lock and stale-tail guard that
HyperLinkInLine uses against a concurrent shorter re-render.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Haller 2026-06-06 15:31:39 +02:00
parent c9c1fb6a0b
commit 165afd4652

View file

@ -1675,6 +1675,33 @@ func (v *View) HyperLinkInLine(y int, urlScheme string) (string, bool) {
return "", false
}
// BufferLineForViewLine maps a view line index (which counts wrapped lines) to
// the index of the corresponding line in the unwrapped internal buffer (as
// returned by BufferLines). Several view lines can map to the same buffer line
// when wrapping is on. Returns false if the view line is out of range.
func (v *View) BufferLineForViewLine(y int) (int, bool) {
// Take the lock so we don't race a concurrent re-render that is rebuilding
// the buffer.
v.writeMutex.Lock()
defer v.writeMutex.Unlock()
v.refreshViewLinesIfNeeded()
if y < 0 || y >= len(v.viewLines) {
return 0, false
}
// refreshViewLinesIfNeeded overwrites viewLines in place without truncating,
// so while a shorter re-render is loading, the tail of viewLines can still
// hold stale entries pointing past the (shrunk) v.lines. Guard against that.
linesY := v.viewLines[y].linesY
if linesY >= len(v.lines) {
return 0, false
}
return linesY, true
}
// indexFunc allows to split lines by words taking into account spaces
// and 0.
func indexFunc(r rune) bool {