summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2024-11-08 20:18:42 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2024-11-08 20:18:42 +0900
commit9c94f9c3d0b75d3d1e09f64837583c1f070fb38b (patch)
tree9091024375f71ad36b20b341805de9aa20009fe7 /src
parent4a85843bcf14490c75022b3f549b5467c31c7870 (diff)
downloadfzf-9c94f9c3d0b75d3d1e09f64837583c1f070fb38b.tar.gz
Another attempt to fix (half-)page-up/down for multi-line items
Fix #4069
Diffstat (limited to 'src')
-rw-r--r--src/terminal.go63
1 files changed, 50 insertions, 13 deletions
diff --git a/src/terminal.go b/src/terminal.go
index e747fbb3..dd3590c4 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -4411,35 +4411,72 @@ func (t *Terminal) Loop() error {
t.input = append(append(t.input[:t.cx], t.yanked...), suffix...)
t.cx += len(t.yanked)
case actPageUp, actPageDown, actHalfPageUp, actHalfPageDown:
+ // Calculate the number of lines to move
maxItems := t.maxItems()
linesToMove := maxItems - 1
if a.t == actHalfPageUp || a.t == actHalfPageDown {
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
if a.t == actPageUp || a.t == actHalfPageUp {
direction = 1
}
- moved := false
- for linesToMove > 0 {
- currentItem := t.currentItem()
- if currentItem == nil {
- break
- }
+ // In non-default layout, items are listed from top to bottom
+ if t.layout != layoutDefault {
+ direction *= -1
+ }
- itemLines, _ := t.numItemLines(currentItem, maxItems)
- linesToMove -= itemLines
- if moved && linesToMove < 0 {
- break
+ // We can simply add the number of lines to the current position in
+ // single-line mode
+ if !t.canSpanMultiLines() {
+ 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
- t.vmove(direction, false)
- if cy == t.cy {
+ t.vset(cy + direction)
+ t.constrain()
+ if cy == t.cy ||
+ direction > 0 && t.offset >= maxOffset ||
+ direction < 0 && t.offset <= minOffset {
break
}
- moved = true
}
req(reqList)
case actOffsetUp, actOffsetDown: