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 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
@ -20,7 +20,7 @@ func (c *Command) options(args []string) (options []Option, only bool) {
// if prev has something that needs to follow it, // if prev has something that needs to follow it,
// it is the most relevant completion // 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 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 // add additional expected argument of the command
if !c.Args.ExpectsNothing { options = append(options, c.Args.predict()...)
options = append(options, c.Args.predict()...)
}
return return
} }

View File

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

View File

@ -11,8 +11,8 @@ 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 &complete.Predicate{
Predictor: func() []complete.Option { Predictor: func() []complete.Option {
tests := testNames(testType) tests := testNames(testType)
options := make([]complete.Option, len(tests)) options := make([]complete.Option, len(tests))

View File

@ -7,10 +7,6 @@ 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 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 // Predictor is function that returns list of arguments that can
// come after the flag/command // come after the flag/command
Predictor func() []Option Predictor func() []Option
@ -18,27 +14,29 @@ type Predicate struct {
// 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 {
return Predicate{ if p == nil || other == nil {
ExpectsNothing: p.ExpectsNothing && other.ExpectsNothing, return nil
Predictor: func() []Option { return append(p.predict(), other.predict()...) }, }
return &Predicate{
Predictor: func() []Option { return append(p.predict(), other.predict()...) },
} }
} }
func (p Predicate) predict() []Option { func (p *Predicate) predict() []Option {
if p.Predictor == nil { if p == nil || p.Predictor == nil {
return nil return nil
} }
return p.Predictor() return p.Predictor()
} }
var ( var (
PredictNothing = Predicate{ExpectsNothing: true} PredictNothing *Predicate = nil
PredictAnything = Predicate{} PredictAnything = &Predicate{}
) )
func PredictSet(options ...string) Predicate { func PredictSet(options ...string) *Predicate {
return Predicate{ return &Predicate{
Predictor: func() []Option { Predictor: func() []Option {
ret := make([]Option, len(options)) ret := make([]Option, len(options))
for i := range options { for i := range options {
@ -49,12 +47,12 @@ func PredictSet(options ...string) Predicate {
} }
} }
func PredictFiles(pattern string) Predicate { func PredictFiles(pattern string) *Predicate {
return Predicate{Predictor: glob(pattern)} return &Predicate{Predictor: glob(pattern)}
} }
func PredictDirs(path string) Predicate { func PredictDirs(path string) *Predicate {
return Predicate{Predictor: dirs(path)} return &Predicate{Predictor: dirs(path)}
} }
func dirs(path string) func() []Option { func dirs(path string) func() []Option {

View File

@ -16,20 +16,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("./tests/").Or(PredictFiles("./tests/*.md")), Args: PredictDirs("./tests/").Or(PredictFiles("./tests/*.md")),
}, },
}, },
Flags: map[string]Predicate{ Flags: map[string]*Predicate{
"-h": PredictNothing, "-h": PredictNothing,
"-global1": PredictAnything, "-global1": PredictAnything,
"-o": PredictFiles("./tests/*.txt"), "-o": PredictFiles("./tests/*.txt"),