@@ -4411,35 +4411,72 @@ func (t *Terminal) Loop() error {
44114411 t .input = append (append (t .input [:t .cx ], t .yanked ... ), suffix ... )
44124412 t .cx += len (t .yanked )
44134413 case actPageUp , actPageDown , actHalfPageUp , actHalfPageDown :
4414+ // Calculate the number of lines to move
44144415 maxItems := t .maxItems ()
44154416 linesToMove := maxItems - 1
44164417 if a .t == actHalfPageUp || a .t == actHalfPageDown {
44174418 linesToMove = maxItems / 2
44184419 }
4420+ // Move at least one line even in a very short window
4421+ linesToMove = util .Max (1 , linesToMove )
44194422
4423+ // Determine the direction of the movement
44204424 direction := - 1
44214425 if a .t == actPageUp || a .t == actHalfPageUp {
44224426 direction = 1
44234427 }
44244428
4425- moved := false
4426- for linesToMove > 0 {
4427- currentItem := t .currentItem ()
4428- if currentItem == nil {
4429- break
4430- }
4429+ // In non-default layout, items are listed from top to bottom
4430+ if t .layout != layoutDefault {
4431+ direction *= - 1
4432+ }
44314433
4432- itemLines , _ := t .numItemLines (currentItem , maxItems )
4433- linesToMove -= itemLines
4434- if moved && linesToMove < 0 {
4435- break
4434+ // We can simply add the number of lines to the current position in
4435+ // single-line mode
4436+ if ! t .canSpanMultiLines () {
4437+ t .vset (t .cy + direction * linesToMove )
4438+ req (reqList )
4439+ break
4440+ }
4441+
4442+ // But in multi-line mode, we need to carefully limit the amount of
4443+ // vertical movement so that items are not skipped. In order to do
4444+ // this, we calculate the minimum or maximum offset based on the
4445+ // direction of the movement and the number of lines of the items
4446+ // around the current scroll offset.
4447+ var minOffset , maxOffset , lineSum int
4448+ if direction > 0 {
4449+ maxOffset = t .offset
4450+ for ; maxOffset < t .merger .Length (); maxOffset ++ {
4451+ itemLines , _ := t .numItemLines (t .merger .Get (maxOffset ).item , maxItems )
4452+ lineSum += itemLines
4453+ if lineSum >= maxItems {
4454+ break
4455+ }
44364456 }
4457+ } else {
4458+ minOffset = t .offset
4459+ for ; minOffset >= 0 && minOffset < t .merger .Length (); minOffset -- {
4460+ itemLines , _ := t .numItemLines (t .merger .Get (minOffset ).item , maxItems )
4461+ lineSum += itemLines
4462+ if lineSum >= maxItems {
4463+ if lineSum > maxItems {
4464+ minOffset ++
4465+ }
4466+ break
4467+ }
4468+ }
4469+ }
4470+
4471+ for ; linesToMove > 0 ; linesToMove -- {
44374472 cy := t .cy
4438- t .vmove (direction , false )
4439- if cy == t .cy {
4473+ t .vset (cy + direction )
4474+ t .constrain ()
4475+ if cy == t .cy ||
4476+ direction > 0 && t .offset >= maxOffset ||
4477+ direction < 0 && t .offset <= minOffset {
44404478 break
44414479 }
4442- moved = true
44434480 }
44444481 req (reqList )
44454482 case actOffsetUp , actOffsetDown :
0 commit comments