From 0b08f0dea076bcc66a2ffe7006e7392d30500f53 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Fri, 6 Mar 2026 19:21:22 +0900 Subject: [PATCH] Fix preview follow/scroll with long wrapped lines Fixes bugs reported in https://github.com/junegunn/fzf/pull/4703: * Clamp followOffset return value to avoid going past the end of lines * Account for t.previewed.filled when determining scrollability --- src/terminal.go | 6 +++--- test/test_preview.rb | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/terminal.go b/src/terminal.go index 50390de4..59dbb71e 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -4223,7 +4223,7 @@ func (t *Terminal) followOffset() int { for i := len(body) - 1; i >= 0; i-- { h := t.previewLineHeight(body[i], maxWidth) if visualLines+h > height { - return headerLines + i + 1 + return min(len(lines)-1, headerLines+i+1) } visualLines += h } @@ -4521,7 +4521,7 @@ Loop: } } - t.previewer.scrollable = t.previewer.scrollable || t.pwindow.Y() == height-1 && t.pwindow.X() == t.pwindow.Width() + t.previewer.scrollable = t.previewer.scrollable || t.pwindow.Y() == height-1 && t.pwindow.X() == t.pwindow.Width() || t.previewed.filled if fillRet == tui.FillNextLine { continue } else if fillRet == tui.FillSuspend { @@ -4544,7 +4544,7 @@ Loop: } lineNo++ } - t.previewer.scrollable = t.previewer.scrollable || index < len(lines)-1 + t.previewer.scrollable = t.previewer.scrollable || t.previewed.filled || index < len(lines)-1 t.previewed.image = image t.previewed.wireframe = wireframe } diff --git a/test/test_preview.rb b/test/test_preview.rb index 616074c3..68f3e117 100644 --- a/test/test_preview.rb +++ b/test/test_preview.rb @@ -393,6 +393,20 @@ class TestPreview < TestInteractive end end + def test_preview_follow_wrap_long_line + tmux.send_keys %(seq 1 | #{FZF} --preview "seq 2; yes yes | head -10000 | tr '\n' ' '" --preview-window follow,wrap --bind up:preview-up,down:preview-down), :Enter + tmux.until do |lines| + assert_equal 1, lines.match_count + assert lines.any_include?('3/3 │') + end + tmux.send_keys :Up + tmux.until { |lines| assert lines.any_include?('2/3 │') } + tmux.send_keys :Up + tmux.until { |lines| assert lines.any_include?('1/3 │') } + tmux.send_keys :Down + tmux.until { |lines| assert lines.any_include?('2/3 │') } + end + def test_close tmux.send_keys "seq 100 | #{FZF} --preview 'echo foo' --bind ctrl-c:close", :Enter tmux.until { |lines| assert_equal 100, lines.match_count }