summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEyal Posener <[email protected]>2017-11-04 10:21:41 +0200
committerEyal Posener <[email protected]>2017-11-04 10:51:40 +0200
commit7ee9623f2b5d4685a91a51d0823275754b4d3a0a (patch)
treef45cd54539dd9a03cbb5314bb6a9c0891d013712
parent88e59760adaddb8276c9b15511302890690e2dae (diff)
Filter matches as a final stage
This simplifies the prediction logic writing, the predictor doesn't need to filter our according to line matching, instead it returns everything and the filtering is done at the end. This does not break current behavior.
-rw-r--r--command.go17
-rw-r--r--complete.go23
-rw-r--r--complete_test.go44
-rw-r--r--gocomplete/tests.go11
-rw-r--r--gocomplete/tests_test.go27
-rw-r--r--predict_set.go11
-rw-r--r--predict_test.go6
7 files changed, 56 insertions, 83 deletions
diff --git a/command.go b/command.go
index 6de48e9..82d37d5 100644
--- a/command.go
+++ b/command.go
@@ -1,7 +1,5 @@
package complete
-import "github.com/posener/complete/match"
-
// Command represents a command line
// It holds the data that enables auto completion of command line
// Command can also be a sub command.
@@ -25,9 +23,9 @@ type Command struct {
}
// Predict returns all possible predictions for args according to the command struct
-func (c *Command) Predict(a Args) (predictions []string) {
- predictions, _ = c.predict(a)
- return
+func (c *Command) Predict(a Args) []string {
+ options, _ := c.predict(a)
+ return options
}
// Commands is the type of Sub member, it maps a command name to a command struct
@@ -36,9 +34,7 @@ type Commands map[string]Command
// Predict completion of sub command names names according to command line arguments
func (c Commands) Predict(a Args) (prediction []string) {
for sub := range c {
- if match.Prefix(sub, a.Last) {
- prediction = append(prediction, sub)
- }
+ prediction = append(prediction, sub)
}
return
}
@@ -56,10 +52,7 @@ func (f Flags) Predict(a Args) (prediction []string) {
if flagHyphenStart && !lastHyphenStart {
continue
}
-
- if match.Prefix(flag, a.Last) {
- prediction = append(prediction, flag)
- }
+ prediction = append(prediction, flag)
}
return
}
diff --git a/complete.go b/complete.go
index 1df6617..3647c28 100644
--- a/complete.go
+++ b/complete.go
@@ -8,10 +8,12 @@ package complete
import (
"flag"
"fmt"
+ "io"
"os"
"strings"
"github.com/posener/complete/cmd"
+ "github.com/posener/complete/match"
)
const (
@@ -23,6 +25,7 @@ const (
type Complete struct {
Command Command
cmd.CLI
+ Out io.Writer
}
// New creates a new complete command.
@@ -34,6 +37,7 @@ func New(name string, command Command) *Complete {
return &Complete{
Command: command,
CLI: cmd.CLI{Name: name},
+ Out: os.Stdout,
}
}
@@ -59,13 +63,19 @@ func (c *Complete) Complete() bool {
return c.CLI.Run()
}
Log("Completing line: %s", line)
-
a := newArgs(line)
-
options := c.Command.Predict(a)
+ Log("Options: %s", options)
- Log("Completion: %s", options)
- output(options)
+ // filter only options that match the last argument
+ matches := []string{}
+ for _, option := range options {
+ if match.Prefix(option, a.Last) {
+ matches = append(matches, option)
+ }
+ }
+ Log("Matches: %s", matches)
+ c.output(matches)
return true
}
@@ -77,10 +87,9 @@ func getLine() ([]string, bool) {
return strings.Split(line, " "), true
}
-func output(options []string) {
- Log("")
+func (c *Complete) output(options []string) {
// stdout of program defines the complete options
for _, option := range options {
- fmt.Println(option)
+ fmt.Fprintln(c.Out, option)
}
}
diff --git a/complete_test.go b/complete_test.go
index ba4df4a..19bc688 100644
--- a/complete_test.go
+++ b/complete_test.go
@@ -1,8 +1,10 @@
package complete
import (
+ "bytes"
"os"
"sort"
+ "strings"
"testing"
)
@@ -34,6 +36,7 @@ func TestCompleter_Complete(t *testing.T) {
"-global1": PredictAnything,
},
}
+ cmp := New("cmd", c)
tests := []struct {
args string
@@ -175,18 +178,13 @@ func TestCompleter_Complete(t *testing.T) {
for _, tt := range tests {
t.Run(tt.args, func(t *testing.T) {
-
- tt.args = "cmd " + tt.args
- os.Setenv(envComplete, tt.args)
- line, _ := getLine()
-
- got := c.Predict(newArgs(line))
+ got := runComplete(cmp, tt.args)
sort.Strings(tt.want)
sort.Strings(got)
if !equalSlices(got, tt.want) {
- t.Errorf("failed '%s'\ngot = %s\nwant: %s", t.Name(), got, tt.want)
+ t.Errorf("failed '%s'\ngot: %s\nwant: %s", t.Name(), got, tt.want)
}
})
}
@@ -222,6 +220,8 @@ func TestCompleter_Complete_SharedPrefix(t *testing.T) {
},
}
+ cmp := New("cmd", c)
+
tests := []struct {
args string
want []string
@@ -258,12 +258,7 @@ func TestCompleter_Complete_SharedPrefix(t *testing.T) {
for _, tt := range tests {
t.Run(tt.args, func(t *testing.T) {
-
- tt.args = "cmd " + tt.args
- os.Setenv(envComplete, tt.args)
- line, _ := getLine()
-
- got := c.Predict(newArgs(line))
+ got := runComplete(cmp, tt.args)
sort.Strings(tt.want)
sort.Strings(got)
@@ -275,6 +270,29 @@ func TestCompleter_Complete_SharedPrefix(t *testing.T) {
}
}
+// runComplete runs the complete login for test purposes
+// it gets the complete struct and command line arguments and returns
+// the complete options
+func runComplete(c *Complete, args string) (completions []string) {
+ os.Setenv(envComplete, "cmd "+args)
+ b := bytes.NewBuffer(nil)
+ c.Out = b
+ c.Complete()
+ completions = parseOutput(b.String())
+ return
+}
+
+func parseOutput(output string) []string {
+ lines := strings.Split(output, "\n")
+ options := []string{}
+ for _, l := range lines {
+ if l != "" {
+ options = append(options, l)
+ }
+ }
+ return options
+}
+
func equalSlices(a, b []string) bool {
if len(a) != len(b) {
return false
diff --git a/gocomplete/tests.go b/gocomplete/tests.go
index a952dab..e755ae5 100644
--- a/gocomplete/tests.go
+++ b/gocomplete/tests.go
@@ -7,7 +7,6 @@ import (
"strings"
"github.com/posener/complete"
- "github.com/posener/complete/match"
)
var (
@@ -21,14 +20,8 @@ var (
// for test names use prefix of 'Test' or 'Example', and for benchmark
// test names use 'Benchmark'
func funcPredict(funcRegexp *regexp.Regexp) complete.Predictor {
- return complete.PredictFunc(func(a complete.Args) (prediction []string) {
- tests := funcNames(funcRegexp)
- for _, t := range tests {
- if match.Prefix(t, a.Last) {
- prediction = append(prediction, t)
- }
- }
- return
+ return complete.PredictFunc(func(a complete.Args) []string {
+ return funcNames(funcRegexp)
})
}
diff --git a/gocomplete/tests_test.go b/gocomplete/tests_test.go
index 6799157..150e2e2 100644
--- a/gocomplete/tests_test.go
+++ b/gocomplete/tests_test.go
@@ -23,37 +23,10 @@ func TestPredictions(t *testing.T) {
want: []string{"TestPredictions", "Example"},
},
{
- name: "predict tests not found",
- predictor: predictTest,
- last: "X",
- },
- {
name: "predict benchmark ok",
predictor: predictBenchmark,
want: []string{"BenchmarkFake"},
},
- {
- name: "predict benchmarks not found",
- predictor: predictBenchmark,
- last: "X",
- },
- {
- name: "predict local ok",
- predictor: complete.PredictFunc(predictPackages),
- last: ".",
- want: []string{"./"},
- },
- {
- name: "predict system ok",
- predictor: complete.PredictFunc(predictPackages),
- last: "github.com/posener/complete/goc",
- want: []string{"github.com/posener/complete/gocomplete/"},
- },
- {
- name: "predict packages not found",
- predictor: complete.PredictFunc(predictPackages),
- last: "X",
- },
}
for _, tt := range tests {
diff --git a/predict_set.go b/predict_set.go
index 8fc59d7..fa4a34a 100644
--- a/predict_set.go
+++ b/predict_set.go
@@ -1,7 +1,5 @@
package complete
-import "github.com/posener/complete/match"
-
// PredictSet expects specific set of terms, given in the options argument.
func PredictSet(options ...string) Predictor {
return predictSet(options)
@@ -9,11 +7,6 @@ func PredictSet(options ...string) Predictor {
type predictSet []string
-func (p predictSet) Predict(a Args) (prediction []string) {
- for _, m := range p {
- if match.Prefix(m, a.Last) {
- prediction = append(prediction, m)
- }
- }
- return
+func (p predictSet) Predict(a Args) []string {
+ return p
}
diff --git a/predict_test.go b/predict_test.go
index ac26e33..ba876d0 100644
--- a/predict_test.go
+++ b/predict_test.go
@@ -22,12 +22,6 @@ func TestPredicate(t *testing.T) {
want: []string{"a", "b", "c"},
},
{
- name: "set with does",
- p: PredictSet("./..", "./x"),
- argList: []string{"./.", "./.."},
- want: []string{"./.."},
- },
- {
name: "set/empty",
p: PredictSet(),
want: []string{},