summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--args.go6
-rw-r--r--predict_files.go30
-rw-r--r--predict_test.go104
-rw-r--r--tests/dir/bar (renamed from tests/dir/x)0
-rw-r--r--tests/dir/foo0
5 files changed, 85 insertions, 55 deletions
diff --git a/args.go b/args.go
index 6d4fea6..0d2b94d 100644
--- a/args.go
+++ b/args.go
@@ -3,15 +3,15 @@ package complete
// Args describes command line arguments
type Args struct {
// All lists of all arguments in command line (not including the command itself)
- All []string
+ All []string
// Completed lists of all completed arguments in command line,
// If the last one is still being typed - no space after it,
// it won't appear in this list of arguments.
- Completed []string
+ Completed []string
// Last argument in command line, the one being typed, if the last
// character in the command line is a space, this argument will be empty,
// otherwise this would be the last word.
- Last string
+ Last string
// LastCompleted is the last argument that was fully typed.
// If the last character in the command line is space, this would be the
// last word, otherwise, it would be the word before that.
diff --git a/predict_files.go b/predict_files.go
index 8ad5368..fe70c97 100644
--- a/predict_files.go
+++ b/predict_files.go
@@ -25,9 +25,35 @@ func PredictFiles(pattern string) Predictor {
}
func files(pattern string, allowFiles bool) PredictFunc {
+
+ // search for files according to arguments,
+ // if only one directory has matched the result, search recursively into
+ // this directory to give more results.
return func(a Args) (prediction []string) {
- prediction = predictFiles(a.Last, pattern, allowFiles)
- return
+ last := a.Last
+ for {
+
+ prediction = predictFiles(last, pattern, allowFiles)
+
+ // if the number of prediction is not 1, we either have many results or
+ // have no results, so we return it.
+ if len(prediction) != 1 {
+ return
+ }
+
+ // if the result is only one item, we might want to recursively check
+ // for more accurate results.
+ if prediction[0] == last { // avoid loop forever
+ return
+ }
+
+ // only try deeper, if the one item is a directory
+ if stat, err := os.Stat(prediction[0]); err != nil || !stat.IsDir() {
+ return
+ }
+
+ last = prediction[0]
+ }
}
}
diff --git a/predict_test.go b/predict_test.go
index ebe8aa1..5e3e5d4 100644
--- a/predict_test.go
+++ b/predict_test.go
@@ -11,10 +11,10 @@ func TestPredicate(t *testing.T) {
initTests()
tests := []struct {
- name string
- p Predictor
- arg string
- want []string
+ name string
+ p Predictor
+ argList []string
+ want []string
}{
{
name: "set",
@@ -22,10 +22,10 @@ func TestPredicate(t *testing.T) {
want: []string{"a", "b", "c"},
},
{
- name: "set with does",
- p: PredictSet("./..", "./x"),
- arg: "./.",
- want: []string{"./.."},
+ name: "set with does",
+ p: PredictSet("./..", "./x"),
+ argList: []string{"./.", "./.."},
+ want: []string{"./.."},
},
{
name: "set/empty",
@@ -63,67 +63,71 @@ func TestPredicate(t *testing.T) {
want: []string{"./", "./dir/", "./a.txt", "./b.txt", "./c.txt", "./.dot.txt"},
},
{
- name: "files/txt",
- p: PredictFiles("*.txt"),
- arg: "./dir/",
- want: []string{"./dir/"},
- },
- {
- name: "files/x",
- p: PredictFiles("x"),
- arg: "./dir/",
- want: []string{"./dir/", "./dir/x"},
+ name: "files/txt",
+ p: PredictFiles("*.txt"),
+ argList: []string{"./dir/"},
+ want: []string{"./dir/"},
},
{
- name: "files/*",
- p: PredictFiles("x*"),
- arg: "./dir/",
- want: []string{"./dir/", "./dir/x"},
+ name: "complete files inside dir if it is the only match",
+ p: PredictFiles("foo"),
+ argList: []string{"./dir/", "./d"},
+ want: []string{"./dir/", "./dir/foo"},
},
{
- name: "files/md",
- p: PredictFiles("*.md"),
- want: []string{"./", "./dir/", "./readme.md"},
+ name: "complete files inside dir when argList includes file name",
+ p: PredictFiles("*"),
+ argList: []string{"./dir/f", "./dir/foo"},
+ want: []string{"./dir/foo"},
},
{
- name: "dirs",
- p: PredictDirs("*"),
- arg: "./dir/",
- want: []string{"./dir/"},
+ name: "files/md",
+ p: PredictFiles("*.md"),
+ argList: []string{"", ".", "./"},
+ want: []string{"./", "./dir/", "./readme.md"},
},
{
- name: "dirs and files",
- p: PredictFiles("*"),
- arg: "./dir",
- want: []string{"./dir/", "./dir/x"},
+ name: "dirs",
+ p: PredictDirs("*"),
+ argList: []string{"./dir/", "./di", "di", "dir", "dir/"},
+ want: []string{"./dir/"},
},
{
- name: "dirs",
- p: PredictDirs("*"),
- want: []string{"./", "./dir/"},
+ name: "predict anything in dir",
+ p: PredictFiles("*"),
+ argList: []string{"./dir", "dir", "./dir/", "./di"},
+ want: []string{"./dir/", "./dir/foo", "./dir/bar"},
},
{
- name: "subdir",
- p: PredictFiles("*"),
- arg: "./dir/",
- want: []string{"./dir/", "./dir/x"},
+ name: "root directories",
+ p: PredictDirs("*"),
+ argList: []string{"", ".", "./"},
+ want: []string{"./", "./dir/"},
},
}
for _, tt := range tests {
- t.Run(tt.name+"?arg='"+tt.arg+"'", func(t *testing.T) {
- matches := tt.p.Predict(newArgs(strings.Split(tt.arg, " ")))
+ // no args in argList, means an empty argument
+ if len(tt.argList) == 0 {
+ tt.argList = append(tt.argList, "")
+ }
+
+ for _, arg := range tt.argList {
+ t.Run(tt.name+"?arg='"+arg+"'", func(t *testing.T) {
+
+ matches := tt.p.Predict(newArgs(strings.Split(arg, " ")))
- sort.Strings(matches)
- sort.Strings(tt.want)
+ sort.Strings(matches)
+ sort.Strings(tt.want)
- got := strings.Join(matches, ",")
- want := strings.Join(tt.want, ",")
+ got := strings.Join(matches, ",")
+ want := strings.Join(tt.want, ",")
- if got != want {
- t.Errorf("failed %s\ngot = %s\nwant: %s", t.Name(), got, want)
- }
- })
+ if got != want {
+ t.Errorf("failed %s\ngot = %s\nwant: %s", t.Name(), got, want)
+ }
+ })
+ }
}
}
diff --git a/tests/dir/x b/tests/dir/bar
index e69de29..e69de29 100644
--- a/tests/dir/x
+++ b/tests/dir/bar
diff --git a/tests/dir/foo b/tests/dir/foo
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/dir/foo