Add additional args

add predition of directories
add ability for prediction union
This commit is contained in:
Eyal Posener 2017-05-05 23:07:18 +03:00
parent 04d16f6064
commit c8263230e1
9 changed files with 95 additions and 16 deletions

View File

@ -7,6 +7,7 @@ type Flags map[string]Predicate
type Command struct { type Command struct {
Sub Commands Sub Commands
Flags Flags Flags Flags
Args Predicate
} }
// options returns all available complete options for the given command // options returns all available complete options for the given command
@ -38,6 +39,11 @@ func (c *Command) options(args []string) (options []Option, only bool) {
options = append(options, Arg(flag)) options = append(options, Arg(flag))
} }
// add additional expected argument of the command
if c.Args.Expects {
options = append(options, c.Args.predict()...)
}
return return
} }

View File

@ -27,12 +27,13 @@ func TestCompleter_Complete(t *testing.T) {
"-flag2": PredictNothing, "-flag2": PredictNothing,
"-flag3": PredictNothing, "-flag3": PredictNothing,
}, },
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("./gocomplete/*.go"), "-o": PredictFiles("./tests/*.txt"),
}, },
}, },
} }
@ -45,6 +46,8 @@ func TestCompleter_Complete(t *testing.T) {
allGlobals = append(allGlobals, flag) allGlobals = append(allGlobals, flag)
} }
testTXTFiles := []string{"./tests/a.txt", "./tests/b.txt", "./tests/c.txt"}
tests := []struct { tests := []struct {
args string args string
want []string want []string
@ -83,7 +86,19 @@ func TestCompleter_Complete(t *testing.T) {
}, },
{ {
args: "sub2 ", args: "sub2 ",
want: []string{"-flag2", "-flag3", "-h", "-global1", "-o"}, want: []string{"./tests", "-flag2", "-flag3", "-h", "-global1", "-o"},
},
{
args: "sub2 tests",
want: []string{"./tests", "./tests/readme.md", "./tests/dir"},
},
{
args: "sub2 tests/re",
want: []string{"./tests/readme.md"},
},
{
args: "sub2 -flag2 ",
want: []string{"./tests", "-flag2", "-flag3", "-h", "-global1", "-o"},
}, },
{ {
args: "sub1 -fl", args: "sub1 -fl",
@ -119,15 +134,31 @@ func TestCompleter_Complete(t *testing.T) {
}, },
{ {
args: "-o ", args: "-o ",
want: []string{"./gocomplete/complete.go"}, want: []string{},
}, },
{ {
args: "-o goco", args: "-o ./tes",
want: []string{"./gocomplete/complete.go"}, want: []string{},
}, },
{ {
args: "-o ./goco", args: "-o tests/",
want: []string{"./gocomplete/complete.go"}, want: testTXTFiles,
},
{
args: "-o tests",
want: testTXTFiles,
},
{
args: "-o ./compl",
want: []string{},
},
{
args: "-o ./complete.go",
want: []string{},
},
{
args: "-o ./complete.go ",
want: allGlobals,
}, },
} }

View File

@ -10,6 +10,7 @@ var (
"-o": complete.PredictFiles("*"), "-o": complete.PredictFiles("*"),
"-i": complete.PredictNothing, "-i": complete.PredictNothing,
}, },
Args: complete.PredictFiles("**.go").Or(complete.PredictDirs("./")),
} }
test = complete.Command{ test = complete.Command{

View File

@ -35,5 +35,8 @@ func (a ArgFileName) Matches(prefix string) bool {
if err != nil { if err != nil {
logger("failed getting abs path of %s: %s", prefix, err) logger("failed getting abs path of %s: %s", prefix, err)
} }
return strings.HasPrefix(full, prefixFull)
// if the file has the prefix as prefix,
// but we don't want to show too many files, so, if it is in a deeper directory - omit it.
return strings.HasPrefix(full, prefixFull) && (full == prefixFull || !strings.Contains(full[len(prefixFull)+1:], "/"))
} }

View File

@ -16,11 +16,20 @@ type Predicate struct {
Predictor func() []Option Predictor func() []Option
} }
func (f *Predicate) predict() []Option { // Or unions two predicate struct, so that the result predicate
if f.Predictor == nil { // returns the union of their predication
func (p Predicate) Or(other Predicate) Predicate {
return Predicate{
Expects: p.Expects && other.Expects,
Predictor: func() []Option { return append(p.predict(), other.predict()...) },
}
}
func (p Predicate) predict() []Option {
if p.Predictor == nil {
return nil return nil
} }
return f.Predictor() return p.Predictor()
} }
var ( var (
@ -35,6 +44,28 @@ func PredictFiles(pattern string) Predicate {
} }
} }
func PredictDirs(path string) Predicate {
return Predicate{
Expects: true,
Predictor: dirs(path),
}
}
func dirs(path string) func() []Option {
return func() (options []Option) {
dirs := []string{}
filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
dirs = append(dirs, path)
}
return nil
})
if !filepath.IsAbs(path) {
filesToRel(dirs)
}
return filesToOptions(dirs)
}
}
func glob(pattern string) func() []Option { func glob(pattern string) func() []Option {
return func() []Option { return func() []Option {
files, err := filepath.Glob(pattern) files, err := filepath.Glob(pattern)
@ -44,11 +75,7 @@ func glob(pattern string) func() []Option {
if !filepath.IsAbs(pattern) { if !filepath.IsAbs(pattern) {
filesToRel(files) filesToRel(files)
} }
options := make([]Option, len(files)) return filesToOptions(files)
for i, f := range files {
options[i] = ArgFileName(f)
}
return options
} }
} }
func filesToRel(files []string) { func filesToRel(files []string) {
@ -69,3 +96,11 @@ func filesToRel(files []string) {
} }
return return
} }
func filesToOptions(files []string) []Option {
options := make([]Option, len(files))
for i, f := range files {
options[i] = ArgFileName(f)
}
return options
}

0
tests/a.txt Normal file
View File

0
tests/b.txt Normal file
View File

0
tests/c.txt Normal file
View File

3
tests/readme.md Normal file
View File

@ -0,0 +1,3 @@
# About this directory
This directory is for testing file completion purposes