From 3326e9ef49175574997a1f3ebd1c5b52b7c28548 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 15 Sep 2022 19:45:47 +0530 Subject: [PATCH] Move code to walk with symlinks to the utils module --- tools/completion/files.go | 83 +++------------------------------------ tools/utils/paths.go | 76 +++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 78 deletions(-) diff --git a/tools/completion/files.go b/tools/completion/files.go index cb437ef89..ee48ba136 100644 --- a/tools/completion/files.go +++ b/tools/completion/files.go @@ -5,92 +5,17 @@ package completion import ( "fmt" "io/fs" - "kitty/tools/utils" "os" "path/filepath" "strings" "golang.org/x/sys/unix" + + "kitty/tools/utils" ) var _ = fmt.Print -type CompleteFilesCallback func(completion_candidate, abspath string, d fs.DirEntry) error -type Walk_callback func(path, abspath string, d fs.DirEntry, err error) error - -func transform_symlink(path string) string { - if q, err := filepath.EvalSymlinks(path); err == nil { - return q - } - return path -} - -func needs_symlink_recurse(path string, d fs.DirEntry) bool { - if d.Type()&os.ModeSymlink == os.ModeSymlink { - if s, serr := os.Stat(path); serr == nil && s.IsDir() { - return true - } - } - return false -} - -type transformed_walker struct { - seen map[string]bool - real_callback Walk_callback - transform_func func(string) string - needs_recurse_func func(string, fs.DirEntry) bool -} - -var sep = string(os.PathSeparator) - -func (self *transformed_walker) walk(dirpath string) error { - resolved_path := self.transform_func(dirpath) - if self.seen[resolved_path] { - return nil - } - self.seen[resolved_path] = true - - c := func(path string, d fs.DirEntry, err error) error { - if err != nil { - // Happens if ReadDir on d failed, skip it in that case - return fs.SkipDir - } - rpath, err := filepath.Rel(resolved_path, path) - if err != nil { - return err - } - // we cant use filepath.Join here as it calls Clean() which can alter dirpath if it contains .. or . etc. - path_based_on_original_dir := dirpath - if !strings.HasSuffix(dirpath, sep) { - path_based_on_original_dir += sep - } - path_based_on_original_dir += rpath - if self.needs_recurse_func(path, d) { - err = self.walk(path_based_on_original_dir) - } else { - err = self.real_callback(path_based_on_original_dir, path, d, err) - } - return err - } - - return filepath.WalkDir(resolved_path, c) -} - -// Walk, recursing into symlinks that point to directories. Ignores directories -// that could not be read. -func WalkWithSymlink(dirpath string, callback Walk_callback, transformers ...func(string) string) error { - - transform := func(path string) string { - for _, t := range transformers { - path = t(path) - } - return transform_symlink(path) - } - sw := transformed_walker{ - seen: make(map[string]bool), real_callback: callback, transform_func: transform, needs_recurse_func: needs_symlink_recurse} - return sw.walk(dirpath) -} - func absolutize_path(path string) string { path = utils.Expanduser(path) q, err := filepath.Abs(path) @@ -100,6 +25,8 @@ func absolutize_path(path string) string { return path } +type CompleteFilesCallback func(completion_candidate, abspath string, d fs.DirEntry) error + func complete_files(prefix string, callback CompleteFilesCallback) error { abspath := absolutize_path(prefix) base := prefix @@ -107,7 +34,7 @@ func complete_files(prefix string, callback CompleteFilesCallback) error { base = filepath.Dir(prefix) } num := 0 - WalkWithSymlink(base, func(path, abspath string, d fs.DirEntry, err error) error { + utils.WalkWithSymlink(base, func(path, abspath string, d fs.DirEntry, err error) error { if err != nil { return fs.SkipDir } diff --git a/tools/utils/paths.go b/tools/utils/paths.go index 0e9746ea8..d54dfc1bf 100644 --- a/tools/utils/paths.go +++ b/tools/utils/paths.go @@ -3,6 +3,7 @@ package utils import ( + "io/fs" "os" "os/user" "path/filepath" @@ -87,3 +88,78 @@ func ConfigDir() string { return config_dir } + +type Walk_callback func(path, abspath string, d fs.DirEntry, err error) error + +func transform_symlink(path string) string { + if q, err := filepath.EvalSymlinks(path); err == nil { + return q + } + return path +} + +func needs_symlink_recurse(path string, d fs.DirEntry) bool { + if d.Type()&os.ModeSymlink == os.ModeSymlink { + if s, serr := os.Stat(path); serr == nil && s.IsDir() { + return true + } + } + return false +} + +type transformed_walker struct { + seen map[string]bool + real_callback Walk_callback + transform_func func(string) string + needs_recurse_func func(string, fs.DirEntry) bool +} + +var sep = string(os.PathSeparator) + +func (self *transformed_walker) walk(dirpath string) error { + resolved_path := self.transform_func(dirpath) + if self.seen[resolved_path] { + return nil + } + self.seen[resolved_path] = true + + c := func(path string, d fs.DirEntry, err error) error { + if err != nil { + // Happens if ReadDir on d failed, skip it in that case + return fs.SkipDir + } + rpath, err := filepath.Rel(resolved_path, path) + if err != nil { + return err + } + // we cant use filepath.Join here as it calls Clean() which can alter dirpath if it contains .. or . etc. + path_based_on_original_dir := dirpath + if !strings.HasSuffix(dirpath, sep) { + path_based_on_original_dir += sep + } + path_based_on_original_dir += rpath + if self.needs_recurse_func(path, d) { + err = self.walk(path_based_on_original_dir) + } else { + err = self.real_callback(path_based_on_original_dir, path, d, err) + } + return err + } + + return filepath.WalkDir(resolved_path, c) +} + +// Walk, recursing into symlinks that point to directories. Ignores directories +// that could not be read. +func WalkWithSymlink(dirpath string, callback Walk_callback, transformers ...func(string) string) error { + + transform := func(path string) string { + for _, t := range transformers { + path = t(path) + } + return transform_symlink(path) + } + sw := transformed_walker{ + seen: make(map[string]bool), real_callback: callback, transform_func: transform, needs_recurse_func: needs_symlink_recurse} + return sw.walk(dirpath) +}