fzf icon indicating copy to clipboard operation
fzf copied to clipboard

In most cases, the bash completion script of fzf will continue to run find even if confirmation is pressed in the fzf search interface

Open A4-Tacks opened this issue 2 years ago • 6 comments

  • [x] I have read through the manual page (man fzf)
  • [x] I have the latest version of fzf
  • [ ] I have searched through the existing issues

Info

  • OS
    • [x] Linux
    • [ ] Mac OS X
    • [ ] Windows
    • [ ] Etc.
  • Shell
    • [x] bash
    • [ ] zsh
    • [ ] fish

Problem / Steps to reproduce

lrne@localhost[/home/lrne/]                                                                             [000] 10:34:52
    $ cd /
# <Alt-c>
lrne@localhost[/]                                                                                       [000] 10:34:53
# <Ctrl-c><Ctrl-c>
      ^C
lrne@localhost[/]                                                                                       [130] 10:35:03
# cd **<Tab>
# <Ctrl-c><Ctrl-c>
sed: 无法将 44 个项目写入 stdout:断开的管道
    $ cd usr/local/etc/tmoe-linux/proot_proc/^C
lrne@localhost[/]                                                                                       [130] 10:35:13
# cd <Ctrl-t>

# <Ctrl-c><Ctrl-c>
lrne@localhost[/]                                                                                       [130] 10:35:26
    $

A4-Tacks avatar May 05 '23 02:05 A4-Tacks

I think I see the same issue.

My homedir has 48318 subdirectories (and the homedir itself). A find on those is more or less fast:

$ time find . -type d > /dev/null 

real	0m0,357s
user	0m0,079s
sys	0m0,272s

but when doing fzf’s Alt-C, and despite immediately selecting a result, it takes considerably longer.

I've looked at the spwaned find process with btop and the elapsed time until it terminates (and until bash’s prompt returns) is 36 s**!!!** Interestingly, the cut process terminates somewhat earlier (after around 26s or so).

@junegunn, any ideas?

calestyo avatar Sep 23 '23 20:09 calestyo

A simple reproducer for this is:

longcmd()
{
   cat /usr/share/dict/british-english
   sleep 1000
}

with

$ longcmd | fzf

Even after a selection has been made fzf doesn't quit. I guess that's the same why it hangs with Alt-C.

calestyo avatar Sep 23 '23 23:09 calestyo

Related: https://github.com/junegunn/fzf/issues/398#issuecomment-152370884

find command can detect SIGPIPE (the receiving process is gone) and terminate itself, but the situation can only be detected when it produces an output. So if it's not printing anything for a while, the termination can be delayed.

while true; do
  echo hello
  sleep 5
  echo goodbye
done | fzf --bind start:abort

A common workaround is to replace the pipe with a process substitution.

(echo wait; sleep 1000) | fzf --bind focus:accept

fzf --bind focus:accept < <(echo wait; sleep 1000)

But sleep process will still run in the background, so it's not ideal either.

junegunn avatar Sep 24 '23 04:09 junegunn

A find on those is more or less fast:

$ time find . -type d > /dev/null 

real	0m0,357s
user	0m0,079s
sys	0m0,272s

but when doing fzf’s Alt-C, and despite immediately selecting a result, it takes considerably longer.

This is a different situation than the one I mentioned above? Not sure what's going on. Is the situation different if you remove cut from the command?

junegunn avatar Sep 24 '23 04:09 junegunn

I think I may have found the reason for both. Plus some off-topic stuff (depending on what you think about all that, I shall put it in a separate issue).

  1. My find, that took much less time, didn’t use -L… whereas fzf’s does.
    Plus in some test directories for some other project I'm working on, I had a symlink to /, thereby creating a loop (which interestingly, find didn’t seem to notice - no idea why, because it does detect it in simple test cases).

I vaguely remember to have seen some other issues, where people asked for removing -L but IIRC, you wanted to keep it.

I anyway wanted to ask whether the keybindings could be made more friendly towards customisation (especially the key-combinations themselves). Especially Ctrl-T is IMO what quite some people use for new tab (e.g. on a GUI Terminal):

  • One way of doing so would be to split out the functions (like __fzf_history__()) into a separate file, that's sourced by the current key bindings script (like key-bindings.bash) with the actual binding definitions (like bind -m …). That way, it would be easier for people to override the bindings and still source the functions from a file that's automatically updated as the fzf package is.
  • Another way would be to add a new config variable that allows to set the key-combinations (like \C-t). One could make it that a binding isn't set up at all, if the key-combination is the empty string, which would easily allow to selectively disable some of them.

This, together will the following, could allow for far greater configurability, and also provide an easy way for people to use the find e.g. with/without -L or to have it run on / rather than ..

All the functions that use FZF_* env vars, i.e. __fzf_select__(), __fzf_cd__(), etc., could be changed, to first look at positional parameters for these config options (i.e. what's used as cmd and opts).
This would allow to rather easily set up variations like in:

bind -m emacs-standard -x '"\C-t": fzf-file-widget "<find command with -L on .>"'
bind -m emacs-standard -x '"\C-f": fzf-file-widget "<find command with -P on .>"'
bind -m emacs-standard -x '"\C-h": fzf-file-widget "<find command with -L on />"'
bind -m emacs-standard -x '"\C-n": fzf-file-widget "<find command with -P on />"'

plus it would avoid having to clutter up the environment with variables.
One could in principle even provide command generator helpers, e.g. functions that take some parameters (like follow_symlinks (true/false), start_point (.//), prune_fs (bash array), prune_dirs (bash array), prun_path (bash array)) and spit out a find (for use in the bind) command that does just as the user wishes).
Such a helper command for the current Alt-C could allow for easy selection of whether the user wants to have history numbers printed, or whether --exact should be used.

Once the key-combinations are customisable, it might also make sense to align the names of options like FZF_CTRL_T_COMMAND to something that actually tells what it is about, e.g. FZF_SELECT_FILE_COMMAND. CTRL_T doesn't really give the information.
It should be easy to tell people how they need to replace the env var names - and if really really needed (though I'd recommend against that), one could simply use the old variables as fall back.
Or maybe they wouldn't be needed anymore at all.

  1. Another factor was, that somewhere below /run/ gvfs had mounted some NFS and SMB shares, for which listing was painfully slow.

Maybe it would be beneficial to exclude network filesystems per default? I mean usually, the guys serving such filesystems are anyway not too happy about people recursively stating through them. ;-)

Debian's plocate package contains a IMO quite well maintained list of fs-types, directory and file names that are excluded from searching: /etc/updatedb.conf:

PRUNE_BIND_MOUNTS="yes"
# PRUNENAMES=".git .bzr .hg .svn"
PRUNEPATHS="/tmp /var/spool /media /var/lib/os-prober /var/lib/ceph /home/.ecryptfs /var/lib/schroot"
PRUNEFS="NFS afs autofs binfmt_misc ceph cgroup cgroup2 cifs coda configfs curlftpfs debugfs devfs devpts devtmpfs ecryptfs ftpfs fuse.ceph fuse.cryfs fuse.encfs fuse.glusterfs fuse.gocryptfs fuse.gvfsd-fuse fuse.mfs fuse.rclone fuse.rozofs fuse.sshfs fusectl fusesmb hugetlbfs iso9660 lustre lustre_lite mfs mqueue ncpfs nfs nfs4 ocfs ocfs2 proc pstore rpc_pipefs securityfs shfs smbfs sysfs tmpfs tracefs udev udf usbfs"

Not all of that may make sense for fzf. E.g. udf, iso9660 and tmpfs could be kept, not sure about ecryptfs (it often is on top of some remote fs, though).
You already exclude things like proc and sysfs per default, though I'm actually wondering, whether these should be included (I guess scanning them would be fast)?

Also I guess, we cannot really mimic the behaviour of PRUNE_BIND_MOUNTS (and -xdev would perpahps not be a good defaul choice).

But It may make sense to prune directories with the names from PRUNENAMES, above.

The find command helper functions I've mentioned above, could e.g. have a user friendly parameter, that allows to add any remote filesystem to the pruned one, making it easy for a user to just switch that on/off, instead of having to maintain a list.

calestyo avatar Sep 24 '23 13:09 calestyo

Okay I just found out why find didn't detect the loop - it wasn't really loops, but multiple links leading to / and in there, multiple links (/run/ and /var/run) lead to the gvfs mountpoint and that was terribly slow.

However, still don't understand why find wasn't killed then by SIGPIPE, cause when it goes through the slow SMB mount, it does print files, like one every second or so, and when fzf has already made a selection by then, shouldn't find get terminated then?

calestyo avatar Sep 24 '23 13:09 calestyo