Change Predicate to be of function type

This commit is contained in:
Eyal Posener 2017-05-06 20:07:50 +03:00
parent dc4c327ae8
commit f46c5f8a28
4 changed files with 35 additions and 46 deletions

View File

@ -2,13 +2,13 @@ package complete
type Commands map[string]Command type Commands map[string]Command
type Flags map[string]*Predicate type Flags map[string]Predicate
type Command struct { type Command struct {
Name string Name string
Sub Commands Sub Commands
Flags Flags Flags Flags
Args *Predicate Args Predicate
} }
// options returns all available complete options for the given command // options returns all available complete options for the given command

View File

@ -11,16 +11,14 @@ import (
"github.com/posener/complete" "github.com/posener/complete"
) )
func predictTest(testType string) *complete.Predicate { func predictTest(testType string) complete.Predicate {
return &complete.Predicate{ return func(last string) []complete.Option {
Predictor: func(last string) []complete.Option { tests := testNames(testType)
tests := testNames(testType) options := make([]complete.Option, len(tests))
options := make([]complete.Option, len(tests)) for i := range tests {
for i := range tests { options[i] = complete.Arg(tests[i])
options[i] = complete.Arg(tests[i]) }
} return options
return options
},
} }
} }

View File

@ -6,53 +6,41 @@ import (
) )
// Predicate determines what terms can follow a command or a flag // Predicate determines what terms can follow a command or a flag
type Predicate struct { type Predicate func(last string) []Option
// Predictor is function that returns list of arguments that can
// come after the flag/command
Predictor func(last string) []Option
}
// Or unions two predicate struct, so that the result predicate // Or unions two predicate struct, so that the result predicate
// returns the union of their predication // returns the union of their predication
func (p *Predicate) Or(other *Predicate) *Predicate { func (p Predicate) Or(other Predicate) Predicate {
if p == nil || other == nil { if p == nil || other == nil {
return nil return nil
} }
return &Predicate{ return func(last string) []Option { return append(p.predict(last), other.predict(last)...) }
Predictor: func(last string) []Option { return append(p.predict(last), other.predict(last)...) },
}
} }
func (p *Predicate) predict(last string) []Option { func (p Predicate) predict(last string) []Option {
if p == nil || p.Predictor == nil { if p == nil {
return nil return nil
} }
return p.Predictor(last) return p(last)
} }
var ( var (
PredictNothing *Predicate = nil PredictNothing Predicate = nil
PredictAnything = &Predicate{}
PredictDirs = &Predicate{Predictor: dirs}
) )
func PredictSet(options ...string) *Predicate { func PredictAnything(last string) []Option { return nil }
return &Predicate{
Predictor: func(last string) []Option { func PredictSet(options ...string) Predicate {
ret := make([]Option, len(options)) return func(last string) []Option {
for i := range options { ret := make([]Option, len(options))
ret[i] = Arg(options[i]) for i := range options {
} ret[i] = Arg(options[i])
return ret }
}, return ret
} }
} }
func PredictFiles(pattern string) *Predicate { func PredictDirs(last string) (options []Option) {
return &Predicate{Predictor: glob(pattern)}
}
func dirs(last string) (options []Option) {
dir := dirFromLast(last) dir := dirFromLast(last)
return dirsAt(dir) return dirsAt(dir)
} }
@ -71,7 +59,7 @@ func dirsAt(path string) []Option {
return filesToOptions(dirs) return filesToOptions(dirs)
} }
func glob(pattern string) func(last string) []Option { func PredictFiles(pattern string) Predicate {
return func(last string) []Option { return func(last string) []Option {
dir := dirFromLast(last) dir := dirFromLast(last)
files, err := filepath.Glob(filepath.Join(dir, pattern)) files, err := filepath.Glob(filepath.Join(dir, pattern))

View File

@ -9,9 +9,12 @@ import (
func TestCompleter_Complete(t *testing.T) { func TestCompleter_Complete(t *testing.T) {
t.Parallel() t.Parallel()
// Set debug environment variable so logs will be printed
if testing.Verbose() { if testing.Verbose() {
os.Setenv(envDebug, "1") os.Setenv(envDebug, "1")
} }
// Change to tests directory for testing completion of files and directories
err := os.Chdir("./tests") err := os.Chdir("./tests")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -20,20 +23,20 @@ func TestCompleter_Complete(t *testing.T) {
c := Command{ c := Command{
Sub: map[string]Command{ Sub: map[string]Command{
"sub1": { "sub1": {
Flags: map[string]*Predicate{ Flags: map[string]Predicate{
"-flag1": PredictAnything, "-flag1": PredictAnything,
"-flag2": PredictNothing, "-flag2": PredictNothing,
}, },
}, },
"sub2": { "sub2": {
Flags: map[string]*Predicate{ Flags: map[string]Predicate{
"-flag2": PredictNothing, "-flag2": PredictNothing,
"-flag3": PredictSet("opt1", "opt2", "opt12"), "-flag3": PredictSet("opt1", "opt2", "opt12"),
}, },
Args: PredictDirs.Or(PredictFiles("*.md")), Args: Predicate(PredictDirs).Or(PredictFiles("*.md")),
}, },
}, },
Flags: map[string]*Predicate{ Flags: map[string]Predicate{
"-h": PredictNothing, "-h": PredictNothing,
"-global1": PredictAnything, "-global1": PredictAnything,
"-o": PredictFiles("*.txt"), "-o": PredictFiles("*.txt"),