about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorGalen Abell <galen@galenabell.com>2019-07-30 15:10:57 -0400
committerDrew DeVault <sir@cmpwn.com>2019-08-02 09:22:39 -0400
commitc4b57aaad8a48a1347a0404001fdcb13532c7620 (patch)
tree4f276e2b6c0792f37649b37aaf5f015be62b33ae
parentb73fcaae32a0de7e070638620927d148064330f5 (diff)
downloadaerc-c4b57aaad8a48a1347a0404001fdcb13532c7620.tar.gz
Add CompletePath method
CompletePath takes an existing path and returns possible filesystem
completions based on that path.
-rw-r--r--commands/util.go91
1 files changed, 91 insertions, 0 deletions
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
+}