junegunn / fzf

:cherry_blossom: A command-line fuzzy finder
https://junegunn.github.io/fzf/
MIT License
61.81k stars 2.35k forks source link

`--walker-skip symlink-to-dir` not skipped #3858

Closed junegunn closed 3 weeks ago

junegunn commented 3 weeks ago

Checklist

Output of fzf --version

0.53.0

OS

Shell

Problem / Steps to reproduce

Related: #3857

mkdir -p /tmp/foo/bar/baz
cd /tmp/foo
ln -s bar bar2
find -L *
  # bar
  # bar/baz
  # bar2
  # bar2/baz

unset FZF_DEFAULT_OPTS FZF_DEFAULT_COMMAND

# Same result as find
fzf --walker file,dir,follow -f '' | sort
  # bar
  # bar/baz
  # bar2
  # bar2/baz

# bar2 is not skipped, because it's not a directory but a symlink to a directory
fzf --walker file,dir,follow --walker-skip bar2 -f '' | sort
  # bar
  # bar/baz
  # bar2
  # bar2/baz
diff --git a/src/reader.go b/src/reader.go
index 528f370..7728ed3 100644
--- a/src/reader.go
+++ b/src/reader.go
@@ -4,6 +4,7 @@ import (
    "bytes"
    "context"
    "io"
+   "io/fs"
    "os"
    "os/exec"
    "path/filepath"
@@ -222,6 +223,16 @@ func (r *Reader) readFromStdin() bool {
    return true
 }

+func isSymlinkToDir(path string, de os.DirEntry) bool {
+   if de.Type()&fs.ModeSymlink == 0 {
+       return false
+   }
+   if s, err := os.Stat(path); err == nil {
+       return s.Mode()&fs.ModeDir > 0
+   }
+   return false
+}
+
 func (r *Reader) readFiles(root string, opts walkerOpts, ignores []string) bool {
    r.killed = false
    conf := fastwalk.Config{Follow: opts.follow}
@@ -232,7 +243,7 @@ func (r *Reader) readFiles(root string, opts walkerOpts, ignores []string) bool
        path = filepath.Clean(path)
        if path != "." {
            isDir := de.IsDir()
-           if isDir {
+           if isDir || opts.follow && isSymlinkToDir(path, de) {
                base := filepath.Base(path)
                if !opts.hidden && base[0] == '.' {
                    return filepath.SkipDir