Selection lost when reload action is involved
Checklist
- [x] I have read through the manual page (
man fzf) - [x] I have searched through the existing issues
- [x] For bug reports, I have checked if the bug is reproducible in the latest version of fzf
Output of fzf --version
0.65.1 (e5cd7f0a)
OS
- [ ] Linux
- [x] macOS
- [ ] Windows
- [ ] Etc.
Shell
- [ ] bash
- [x] zsh
- [ ] fish
Problem / Steps to reproduce
Hello, I have a problem with losing all selections on reload followed by any selecting action (select-all, toggle,…).
printf "%s\n" 1 2 3 | bin/fzf --multi --bind 'esc:reload(printf "%s\n" 1 2 3)+select-all'
- The selections happen - they just flicker and disappear.
- Tried it also with reload-sync with the same result.
- Same result with older version 0.56.3 (add1aec).
- I noticed that when I add any action after reload(-sync) it's executed immediately (it doesn't wait for reload to finish). I'm pretty sure this is expected but how can I ensure that some actions are invoked only after the list is complete?
- Tried using experimental state JSON to only output select-all from transform when "reading" is false but it got stuck on true despite "progress" being 100.
I've always wondered about the order of the execution of actions. It's not always clear which actions are blocking and which are not, and sometimes I'm not sure if they execute in order or concurrently.
For your immediate issue, I found this to work (but is not ideal):
printf "%s\n" 1 2 3 | fzf --multi --bind 'esc:reload(printf "%s\n" 1 2 3)+bg-transform(sleep 0.01; echo select-all)'
Everything is synchronous (blocking), except for reload, because loading of the input list is inherently asynchronous. This is also true for reload-sync. The "sync" part means that it replaces the list at once after the reload process is complete, it doesn't block fzf during the process.
To deal with the asynchronous nature of loading, you can bind actions to the load event:
printf "%s\n" 1 2 3 | fzf --multi --bind 'esc:reload(printf "%s\n" 1 2 3),load:select-all'
But load also fires on the initial input, so you may need a way to suppress it until the next reload. This is one way to do it using unbind and rebind:
printf "%s\n" 1 2 3 | fzf --multi --bind 'start:unbind(load),esc:rebind(load)+reload(printf "%s\n" 1 2 3),load:select-all'
I know this is not the most straightforward or ergonomic way to implement things, but it is how it is. I'm open to suggestions. Some ideas.
- Implement a truly synchronous version of
ggthat blocks everything until the command is complete and fzf finished consuming the output (this is probably my least favorite). - Add
reloadevent to complement theloadevent. - ...
See also:
- https://github.com/junegunn/fzf/issues/2441
- https://github.com/junegunn/fzf/issues/4409