Another attempt to fix (half-)page-up/down for multi-line items

Fix #4069
This commit is contained in:
Junegunn Choi 2024-11-08 20:18:42 +09:00
parent 4a85843bcf
commit 9c94f9c3d0
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627

View File

@ -4411,35 +4411,72 @@ func (t *Terminal) Loop() error {
t.input = append(append(t.input[:t.cx], t.yanked...), suffix...) t.input = append(append(t.input[:t.cx], t.yanked...), suffix...)
t.cx += len(t.yanked) t.cx += len(t.yanked)
case actPageUp, actPageDown, actHalfPageUp, actHalfPageDown: case actPageUp, actPageDown, actHalfPageUp, actHalfPageDown:
// Calculate the number of lines to move
maxItems := t.maxItems() maxItems := t.maxItems()
linesToMove := maxItems - 1 linesToMove := maxItems - 1
if a.t == actHalfPageUp || a.t == actHalfPageDown { if a.t == actHalfPageUp || a.t == actHalfPageDown {
linesToMove = maxItems / 2 linesToMove = maxItems / 2
} }
// Move at least one line even in a very short window
linesToMove = util.Max(1, linesToMove)
// Determine the direction of the movement
direction := -1 direction := -1
if a.t == actPageUp || a.t == actHalfPageUp { if a.t == actPageUp || a.t == actHalfPageUp {
direction = 1 direction = 1
} }
moved := false // In non-default layout, items are listed from top to bottom
for linesToMove > 0 { if t.layout != layoutDefault {
currentItem := t.currentItem() direction *= -1
if currentItem == nil { }
break
}
itemLines, _ := t.numItemLines(currentItem, maxItems) // We can simply add the number of lines to the current position in
linesToMove -= itemLines // single-line mode
if moved && linesToMove < 0 { if !t.canSpanMultiLines() {
break t.vset(t.cy + direction*linesToMove)
req(reqList)
break
}
// But in multi-line mode, we need to carefully limit the amount of
// vertical movement so that items are not skipped. In order to do
// this, we calculate the minimum or maximum offset based on the
// direction of the movement and the number of lines of the items
// around the current scroll offset.
var minOffset, maxOffset, lineSum int
if direction > 0 {
maxOffset = t.offset
for ; maxOffset < t.merger.Length(); maxOffset++ {
itemLines, _ := t.numItemLines(t.merger.Get(maxOffset).item, maxItems)
lineSum += itemLines
if lineSum >= maxItems {
break
}
} }
} else {
minOffset = t.offset
for ; minOffset >= 0 && minOffset < t.merger.Length(); minOffset-- {
itemLines, _ := t.numItemLines(t.merger.Get(minOffset).item, maxItems)
lineSum += itemLines
if lineSum >= maxItems {
if lineSum > maxItems {
minOffset++
}
break
}
}
}
for ; linesToMove > 0; linesToMove-- {
cy := t.cy cy := t.cy
t.vmove(direction, false) t.vset(cy + direction)
if cy == t.cy { t.constrain()
if cy == t.cy ||
direction > 0 && t.offset >= maxOffset ||
direction < 0 && t.offset <= minOffset {
break break
} }
moved = true
} }
req(reqList) req(reqList)
case actOffsetUp, actOffsetDown: case actOffsetUp, actOffsetDown: