diff --git a/context.go b/context.go index 902eaa92c..f746d6e59 100644 --- a/context.go +++ b/context.go @@ -5,13 +5,12 @@ import ( "fmt" "os" "path/filepath" - "runtime" "strings" - "unicode" "github.com/rsteube/carapace/internal/common" "github.com/rsteube/carapace/internal/env" "github.com/rsteube/carapace/internal/shell/zsh" + "github.com/rsteube/carapace/pkg/util" "github.com/rsteube/carapace/third_party/github.com/drone/envsubst" "github.com/rsteube/carapace/third_party/golang.org/x/sys/execabs" ) @@ -122,24 +121,10 @@ func expandHome(s string) (string, error) { return s, nil } -// hasVolumePrefix checks if given path has a volume prefix (only for GOOS=windows) -func hasVolumePrefix(path string) bool { - switch { - case runtime.GOOS != "windows": - return false - case len(path) < 2: - return false - case unicode.IsLetter(rune(path[0])) && path[1] == ':': - return true - default: - return false - } -} - // Abs returns an absolute representation of path. func (c Context) Abs(path string) (string, error) { path = filepath.ToSlash(path) - if !strings.HasPrefix(path, "/") && !strings.HasPrefix(path, "~") && !hasVolumePrefix(path) { // path is relative + if !strings.HasPrefix(path, "/") && !strings.HasPrefix(path, "~") && !util.HasVolumePrefix(path) { // path is relative switch c.Dir { case "": path = "./" + path @@ -153,7 +138,7 @@ func (c Context) Abs(path string) (string, error) { return "", err } - if len(path) == 2 && hasVolumePrefix(path) { + if len(path) == 2 && util.HasVolumePrefix(path) { path += "/" // prevent `C:` -> `C:./current/working/directory` } result, err := filepath.Abs(path) diff --git a/internalActions.go b/internalActions.go index 35443c980..5b5c87456 100644 --- a/internalActions.go +++ b/internalActions.go @@ -9,12 +9,13 @@ import ( "github.com/rsteube/carapace/internal/common" "github.com/rsteube/carapace/internal/pflagfork" "github.com/rsteube/carapace/pkg/style" + "github.com/rsteube/carapace/pkg/util" "github.com/spf13/cobra" ) func actionPath(fileSuffixes []string, dirOnly bool) Action { return ActionCallback(func(c Context) Action { - if len(c.Value) == 2 && hasVolumePrefix(c.Value) { + if len(c.Value) == 2 && util.HasVolumePrefix(c.Value) { // TODO should be fixed in Abs or wherever this is happening return ActionValues(c.Value + "/") // prevent `C:` -> `C:.` } diff --git a/pkg/util/util.go b/pkg/util/util.go new file mode 100644 index 000000000..34910afc4 --- /dev/null +++ b/pkg/util/util.go @@ -0,0 +1,51 @@ +package util + +// TODO rename package update/optimize functions + +import ( + "errors" + "os" + "path/filepath" + "runtime" + "strings" + "unicode" +) + +// FindReverse traverses the filetree upwards to find given file/directory. +func FindReverse(path string, name string) (target string, err error) { + var absPath string + if absPath, err = filepath.Abs(path); err == nil { + target = absPath + "/" + name + if _, err = os.Stat(target); err != nil { + parent := filepath.Dir(absPath) + if parent != path { + return FindReverse(parent, name) + } else { + err = errors.New("could not find: " + name) + } + } + } + return +} + +// HasPathPrefix checks if given string has a path prefix. +func HasPathPrefix(s string) bool { + return strings.HasPrefix(s, ".") || + strings.HasPrefix(s, "/") || + strings.HasPrefix(s, "~") || + HasVolumePrefix(s) +} + +// HasVolumePrefix checks if given path has a volume prefix (only for GOOS=windows). +func HasVolumePrefix(s string) bool { + switch { + case runtime.GOOS != "windows": + return false + case len(s) < 2: + return false + case unicode.IsLetter(rune(s[0])) && s[1] == ':': + return true + default: + return false + } +}