Use pointers to predicates

This commit is contained in:
Eyal Posener 2017-05-06 19:08:47 +03:00
parent 99ef98e3ba
commit 07b98cb912
5 changed files with 31 additions and 35 deletions

View File

@ -2,13 +2,13 @@ package complete
type Commands map[string]Command
type Flags map[string]Predicate
type Flags map[string]*Predicate
type Command struct {
Name string
Sub Commands
Flags Flags
Args Predicate
Args *Predicate
}
// options returns all available complete options for the given command
@ -20,7 +20,7 @@ func (c *Command) options(args []string) (options []Option, only bool) {
// if prev has something that needs to follow it,
// it is the most relevant completion
if predicate, ok := c.Flags[last(args)]; ok && !predicate.ExpectsNothing {
if predicate, ok := c.Flags[last(args)]; ok && predicate != nil {
return predicate.predict(), true
}
@ -41,9 +41,7 @@ func (c *Command) options(args []string) (options []Option, only bool) {
}
// add additional expected argument of the command
if !c.Args.ExpectsNothing {
options = append(options, c.Args.predict()...)
}
options = append(options, c.Args.predict()...)
return
}

View File

@ -4,13 +4,13 @@ import (
"github.com/posener/complete"
)
var predictEllipsis = complete.Predicate{
Predictor: func() []complete.Option { return []complete.Option{complete.Arg("./...")} },
}
var (
predictEllipsis = complete.PredictSet("./...")
var goFilesOrPackages = complete.PredictFiles("**.go").
Or(complete.PredictDirs("./")).
Or(predictEllipsis)
goFilesOrPackages = complete.PredictFiles("**.go").
Or(complete.PredictDirs("./")).
Or(predictEllipsis)
)
func main() {
build := complete.Command{

View File

@ -11,8 +11,8 @@ import (
"github.com/posener/complete"
)
func predictTest(testType string) complete.Predicate {
return complete.Predicate{
func predictTest(testType string) *complete.Predicate {
return &complete.Predicate{
Predictor: func() []complete.Option {
tests := testNames(testType)
options := make([]complete.Option, len(tests))

View File

@ -7,10 +7,6 @@ import (
// Predicate determines what terms can follow a command or a flag
type Predicate struct {
// ExpectsNothing determine if the predicate expects something after.
// flags/commands that do not expect any specific argument should
// leave it on false
ExpectsNothing bool
// Predictor is function that returns list of arguments that can
// come after the flag/command
Predictor func() []Option
@ -18,27 +14,29 @@ type Predicate struct {
// Or unions two predicate struct, so that the result predicate
// returns the union of their predication
func (p Predicate) Or(other Predicate) Predicate {
return Predicate{
ExpectsNothing: p.ExpectsNothing && other.ExpectsNothing,
Predictor: func() []Option { return append(p.predict(), other.predict()...) },
func (p *Predicate) Or(other *Predicate) *Predicate {
if p == nil || other == nil {
return nil
}
return &Predicate{
Predictor: func() []Option { return append(p.predict(), other.predict()...) },
}
}
func (p Predicate) predict() []Option {
if p.Predictor == nil {
func (p *Predicate) predict() []Option {
if p == nil || p.Predictor == nil {
return nil
}
return p.Predictor()
}
var (
PredictNothing = Predicate{ExpectsNothing: true}
PredictAnything = Predicate{}
PredictNothing *Predicate = nil
PredictAnything = &Predicate{}
)
func PredictSet(options ...string) Predicate {
return Predicate{
func PredictSet(options ...string) *Predicate {
return &Predicate{
Predictor: func() []Option {
ret := make([]Option, len(options))
for i := range options {
@ -49,12 +47,12 @@ func PredictSet(options ...string) Predicate {
}
}
func PredictFiles(pattern string) Predicate {
return Predicate{Predictor: glob(pattern)}
func PredictFiles(pattern string) *Predicate {
return &Predicate{Predictor: glob(pattern)}
}
func PredictDirs(path string) Predicate {
return Predicate{Predictor: dirs(path)}
func PredictDirs(path string) *Predicate {
return &Predicate{Predictor: dirs(path)}
}
func dirs(path string) func() []Option {

View File

@ -16,20 +16,20 @@ func TestCompleter_Complete(t *testing.T) {
c := Command{
Sub: map[string]Command{
"sub1": {
Flags: map[string]Predicate{
Flags: map[string]*Predicate{
"-flag1": PredictAnything,
"-flag2": PredictNothing,
},
},
"sub2": {
Flags: map[string]Predicate{
Flags: map[string]*Predicate{
"-flag2": PredictNothing,
"-flag3": PredictSet("opt1", "opt2", "opt12"),
},
Args: PredictDirs("./tests/").Or(PredictFiles("./tests/*.md")),
},
},
Flags: map[string]Predicate{
Flags: map[string]*Predicate{
"-h": PredictNothing,
"-global1": PredictAnything,
"-o": PredictFiles("./tests/*.txt"),