From 1ba780057e80fcc1205f6ef0d885425e44b6d10d Mon Sep 17 00:00:00 2001 From: Peter Ebden Date: Wed, 6 Dec 2017 15:20:10 +0000 Subject: [PATCH 1/3] Add filepath as an equivalent to filename which completes into subdirectories. I have some cases where this was the behaviour I wanted; obviously users can implement this themselves but it seems pretty generally useful (probably as much so as Filename?). --- completion.go | 16 ++++++++++++++++ completion_test.go | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/completion.go b/completion.go index 7a7a08b..4e4b002 100644 --- a/completion.go +++ b/completion.go @@ -2,6 +2,7 @@ package flags import ( "fmt" + "os" "path/filepath" "reflect" "sort" @@ -48,6 +49,9 @@ type completion struct { // Filename is a string alias which provides filename completion. type Filename string +// Filepath is a string alias which provides completion for file paths into subdirectories. +type Filepath string + func completionsWithoutDescriptions(items []string) []Completion { ret := make([]Completion, len(items)) @@ -65,6 +69,18 @@ func (f *Filename) Complete(match string) []Completion { return completionsWithoutDescriptions(ret) } +// Complete returns a list of existing files with the given prefix. +// If it completes to a single directory, the contents of that directory are interrogated. +func (f *Filepath) Complete(match string) []Completion { + ret, _ := filepath.Glob(match + "*") + if len(ret) == 1 { + if info, err := os.Stat(ret[0]); err == nil && info.IsDir() { + ret, _ = filepath.Glob(ret[0] + "/*") + } + } + return completionsWithoutDescriptions(ret) +} + func (c *completion) skipPositional(s *parseState, n int) { if n >= len(s.positional) { s.positional = nil diff --git a/completion_test.go b/completion_test.go index 26f70e4..9bcf40b 100644 --- a/completion_test.go +++ b/completion_test.go @@ -63,6 +63,7 @@ var completionTestOptions struct { RemoveCommand struct { Other bool `short:"o"` File Filename `short:"f" long:"filename"` + Dir Filepath `short:"d" long:"dir"` } `command:"rm" description:"remove an item"` RenameCommand struct { @@ -84,6 +85,13 @@ func init() { completionTestFilename := []string{filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion_test.go")} + completionTestFilepath := []string{ + filepath.Join(completionTestSourcedir, "examples/add.go"), + filepath.Join(completionTestSourcedir, "examples/bash-completion"), + filepath.Join(completionTestSourcedir, "examples/main.go"), + filepath.Join(completionTestSourcedir, "examples/rm.go"), + } + completionTests = []completionTest{ { // Short names @@ -227,6 +235,20 @@ func init() { false, }, + { + // Flag filepath file + []string{"rm", "-d", path.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + + { + // Flag filepath dir + []string{"rm", "-d", path.Join(completionTestSourcedir, "examples")}, + completionTestFilepath, + false, + }, + { // Custom completed []string{"rename", "-c", "hello un"}, From 919b882502014d3846d5d24bdb263a9a9497cadf Mon Sep 17 00:00:00 2001 From: Peter Ebden Date: Sat, 28 Apr 2018 08:25:31 +0100 Subject: [PATCH 2/3] Add it to Filename instead --- completion.go | 10 ---------- completion_test.go | 16 ++++------------ 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/completion.go b/completion.go index 4e4b002..59bd61c 100644 --- a/completion.go +++ b/completion.go @@ -49,9 +49,6 @@ type completion struct { // Filename is a string alias which provides filename completion. type Filename string -// Filepath is a string alias which provides completion for file paths into subdirectories. -type Filepath string - func completionsWithoutDescriptions(items []string) []Completion { ret := make([]Completion, len(items)) @@ -65,13 +62,6 @@ func completionsWithoutDescriptions(items []string) []Completion { // Complete returns a list of existing files with the given // prefix. func (f *Filename) Complete(match string) []Completion { - ret, _ := filepath.Glob(match + "*") - return completionsWithoutDescriptions(ret) -} - -// Complete returns a list of existing files with the given prefix. -// If it completes to a single directory, the contents of that directory are interrogated. -func (f *Filepath) Complete(match string) []Completion { ret, _ := filepath.Glob(match + "*") if len(ret) == 1 { if info, err := os.Stat(ret[0]); err == nil && info.IsDir() { diff --git a/completion_test.go b/completion_test.go index 9bcf40b..dba5458 100644 --- a/completion_test.go +++ b/completion_test.go @@ -63,7 +63,6 @@ var completionTestOptions struct { RemoveCommand struct { Other bool `short:"o"` File Filename `short:"f" long:"filename"` - Dir Filepath `short:"d" long:"dir"` } `command:"rm" description:"remove an item"` RenameCommand struct { @@ -85,7 +84,7 @@ func init() { completionTestFilename := []string{filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion_test.go")} - completionTestFilepath := []string{ + completionTestSubdir := []string{ filepath.Join(completionTestSourcedir, "examples/add.go"), filepath.Join(completionTestSourcedir, "examples/bash-completion"), filepath.Join(completionTestSourcedir, "examples/main.go"), @@ -236,16 +235,9 @@ func init() { }, { - // Flag filepath file - []string{"rm", "-d", path.Join(completionTestSourcedir, "completion")}, - completionTestFilename, - false, - }, - - { - // Flag filepath dir - []string{"rm", "-d", path.Join(completionTestSourcedir, "examples")}, - completionTestFilepath, + // Subdirectory + []string{"rm", "--filename", path.Join(completionTestSourcedir, "examples")}, + completionTestSubdir, false, }, From fe2106393318e27f95efc9d54a567a79b9e73ded Mon Sep 17 00:00:00 2001 From: Jesse van den Kieboom Date: Sun, 23 Sep 2018 08:42:30 +0200 Subject: [PATCH 3/3] Recurse completion of single directory down --- completion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/completion.go b/completion.go index 59bd61c..26700cc 100644 --- a/completion.go +++ b/completion.go @@ -65,7 +65,7 @@ func (f *Filename) Complete(match string) []Completion { ret, _ := filepath.Glob(match + "*") if len(ret) == 1 { if info, err := os.Stat(ret[0]); err == nil && info.IsDir() { - ret, _ = filepath.Glob(ret[0] + "/*") + return f.Complete(ret[0] + "/") } } return completionsWithoutDescriptions(ret)