diff --git a/CHANGELOG.md b/CHANGELOG.md index d7b5a9e..0d2a81a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,15 @@ CHANGELOG fzf --listen --sync --bind 'focus:transform-header:curl -s localhost:$FZF_PORT?limit=0 | jq .' ``` - Added `offset-middle` action to place the current item is in the middle of the screen +- fzf will not start the initial reader when `reload` or `reload-sync` is bound to `start` event. `fzf < /dev/null` or `: | fzf` are no longer required and extraneous `load` event will not fire due to the empty list. + ```sh + # Now this will work as expected. Previously, this would print an invalid header line. + # `fzf < /dev/null` or `: | fzf` would fix the problem, but then an extraneous + # `load` event would fire and the header would be prematurely updated. + fzf --header 'Loading ...' --header-lines 1 \ + --bind 'start:reload:sleep 1; ps -ef' \ + --bind 'load:change-header:Loaded!' + ``` - Fixed mouse support on Windows - Fixed crash when using `--tiebreak=end` with very long items - zsh 5.0 compatibility (thanks to @LangLangBart) diff --git a/src/constants.go b/src/constants.go index 980e158..29874b2 100644 --- a/src/constants.go +++ b/src/constants.go @@ -58,6 +58,7 @@ const ( const ( EvtReadNew util.EventType = iota EvtReadFin + EvtReadNone EvtSearchNew EvtSearchProgress EvtSearchFin diff --git a/src/core.go b/src/core.go index 87629b7..caada27 100644 --- a/src/core.go +++ b/src/core.go @@ -147,13 +147,20 @@ func Run(opts *Options) (int, error) { executor := util.NewExecutor(opts.WithShell) // Reader + reloadOnStart := opts.reloadOnStart() streamingFilter := opts.Filter != nil && !sort && !opts.Tac && !opts.Sync var reader *Reader if !streamingFilter { reader = NewReader(func(data []byte) bool { return chunkList.Push(data) }, eventBox, executor, opts.ReadZero, opts.Filter == nil) - go reader.ReadSource(opts.Input, opts.WalkerRoot, opts.WalkerOpts, opts.WalkerSkip) + + if reloadOnStart { + // reload or reload-sync action is bound to 'start' event, no need to start the reader + eventBox.Set(EvtReadNone, nil) + } else { + go reader.ReadSource(opts.Input, opts.WalkerRoot, opts.WalkerOpts, opts.WalkerSkip) + } } // Matcher @@ -227,7 +234,8 @@ func Run(opts *Options) (int, error) { } // Synchronous search - if opts.Sync { + sync := opts.Sync && !reloadOnStart + if sync { eventBox.Unwatch(EvtReadNew) eventBox.WaitFor(EvtReadFin) } @@ -247,7 +255,7 @@ func Run(opts *Options) (int, error) { if heightUnknown { maxFit, padHeight = terminal.MaxFitAndPad() } - deferred := opts.Select1 || opts.Exit0 || opts.Sync + deferred := opts.Select1 || opts.Exit0 || sync go terminal.Loop() if !deferred && !heightUnknown { // Start right away @@ -314,6 +322,9 @@ func Run(opts *Options) (int, error) { err = quitSignal.err stop = true return + case EvtReadNone: + reading = false + terminal.UpdateCount(0, false, nil) case EvtReadNew, EvtReadFin: if evt == EvtReadFin && nextCommand != nil { restart(*nextCommand, nextEnviron) diff --git a/src/options.go b/src/options.go index fdf5f8d..d9121c3 100644 --- a/src/options.go +++ b/src/options.go @@ -2945,3 +2945,18 @@ func ParseOptions(useDefaults bool, args []string) (*Options, error) { return opts, nil } + +func (opts *Options) reloadOnStart() bool { + // Not compatible with --filter + if opts.Filter != nil { + return false + } + if actions, prs := opts.Keymap[tui.Start.AsEvent()]; prs { + for _, action := range actions { + if action.t == actReload || action.t == actReloadSync { + return true + } + } + } + return false +} diff --git a/test/test_go.rb b/test/test_go.rb index fdef78f..4d72972 100755 --- a/test/test_go.rb +++ b/test/test_go.rb @@ -26,12 +26,12 @@ BASE = File.expand_path('..', __dir__) Dir.chdir(BASE) FZF = "FZF_DEFAULT_OPTS=\"--no-scrollbar --pointer \\> --marker \\>\" FZF_DEFAULT_COMMAND= #{BASE}/bin/fzf" -def wait +def wait(timeout = DEFAULT_TIMEOUT) since = Time.now begin yield or raise Minitest::Assertion, 'Assertion failure' rescue Minitest::Assertion - raise if Time.now - since > DEFAULT_TIMEOUT + raise if Time.now - since > timeout sleep(0.05) retry @@ -103,10 +103,10 @@ class Tmux go(%W[capture-pane -p -J -t #{win}]).map(&:rstrip).reverse.drop_while(&:empty?).reverse end - def until(refresh = false) + def until(refresh = false, timeout: DEFAULT_TIMEOUT) lines = nil begin - wait do + wait(timeout) do lines = capture class << lines def counts @@ -3356,6 +3356,14 @@ class TestGoFZF < TestBase BLOCK tmux.until { assert_block(block, _1) } end + + def test_start_on_reload + tmux.send_keys %[echo foo | #{FZF} --header Loading --header-lines 1 --bind 'start:reload:sleep 2; echo bar' --bind 'load:change-header:Loaded'], :Enter + tmux.until(timeout: 1) { |lines| assert_includes lines[-3], 'Loading' } + tmux.until(timeout: 1) { |lines| refute_includes lines[-4], 'foo' } + tmux.until { |lines| assert_includes lines[-3], 'Loaded' } + tmux.until { |lines| assert_includes lines[-4], 'bar' } + end end module TestShell