From c4b57aaad8a48a1347a0404001fdcb13532c7620 Mon Sep 17 00:00:00 2001 From: Galen Abell Date: Tue, 30 Jul 2019 15:10:57 -0400 Subject: [PATCH] Add CompletePath method CompletePath takes an existing path and returns possible filesystem completions based on that path. --- commands/util.go | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/commands/util.go b/commands/util.go index e9fd205..81d2da6 100644 --- a/commands/util.go +++ b/commands/util.go @@ -1,12 +1,17 @@ package commands import ( + "fmt" "io" + "os" "os/exec" + "path/filepath" + "strings" "time" "git.sr.ht/~sircmpwn/aerc/widgets" "github.com/gdamore/tcell" + "github.com/mitchellh/go-homedir" ) // QuickTerm is an ephemeral terminal for running a single command and quiting. @@ -54,3 +59,89 @@ func QuickTerm(aerc *widgets.Aerc, args []string, stdin io.Reader) (*widgets.Ter return term, nil } + +// CompletePath provides filesystem completions given a starting path. +func CompletePath(path string) []string { + if path == "" { + // default to cwd + cwd, err := os.Getwd() + if err != nil { + return nil + } + path = cwd + } + + path, err := homedir.Expand(path) + if err != nil { + return nil + } + + // strip trailing slashes, etc. + path = filepath.Clean(path) + + if _, err := os.Stat(path); os.IsNotExist(err) { + // if the path doesn't exist, it is likely due to it being a partial path + // in this case, we want to return possible matches (ie /hom* should match + // /home) + matches, err := filepath.Glob(fmt.Sprintf("%s*", path)) + if err != nil { + return nil + } + + for i, m := range matches { + if isDir(m) { + matches[i] = m + "/" + } + } + + return matches + } + + files := listDir(path, false) + + for i, f := range files { + f = filepath.Join(path, f) + if isDir(f) { + f += "/" + } + + files[i] = f + } + + return files +} + +func isDir(path string) bool { + info, err := os.Stat(path) + if err != nil { + return false + } + + return info.IsDir() +} + +// return all filenames in a directory, optionally including hidden files +func listDir(path string, hidden bool) []string { + f, err := os.Open(path) + if err != nil { + return []string{} + } + + files, err := f.Readdirnames(-1) // read all dir names + if err != nil { + return []string{} + } + + if hidden { + return files + } + + var filtered []string + for _, g := range files { + if !strings.HasPrefix(g, ".") { + filtered = append(filtered, g) + } + } + + return filtered +}