Roughly add all go commands
This commit is contained in:
parent
c8263230e1
commit
1af7c0b3b7
|
@ -19,7 +19,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.Expects {
|
if predicate, ok := c.Flags[last(args)]; ok && !predicate.ExpectsNothing {
|
||||||
return predicate.predict(), true
|
return predicate.predict(), true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,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.Expects {
|
if !c.Args.ExpectsNothing {
|
||||||
options = append(options, c.Args.predict()...)
|
options = append(options, c.Args.predict()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,11 @@ func New(c Command) *Completer {
|
||||||
|
|
||||||
func (c *Completer) Complete() {
|
func (c *Completer) Complete() {
|
||||||
args := getLine()
|
args := getLine()
|
||||||
logger("Completing args: %s", args)
|
Log("Completing args: %s", args)
|
||||||
|
|
||||||
options := c.complete(args)
|
options := c.complete(args)
|
||||||
|
|
||||||
logger("Completion: %s", options)
|
Log("Completion: %s", options)
|
||||||
output(options)
|
output(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,33 +4,187 @@ import (
|
||||||
"github.com/posener/complete"
|
"github.com/posener/complete"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var predictEllipsis = complete.Predicate{
|
||||||
build = complete.Command{
|
Predictor: func() []complete.Option { return []complete.Option{complete.Arg("./...")} },
|
||||||
|
}
|
||||||
|
|
||||||
|
var goFilesOrPackages = complete.PredictFiles("**.go").
|
||||||
|
Or(complete.PredictDirs("./")).
|
||||||
|
Or(predictEllipsis)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
build := complete.Command{
|
||||||
Flags: complete.Flags{
|
Flags: complete.Flags{
|
||||||
"-o": complete.PredictFiles("*"),
|
"-o": complete.PredictFiles("**"),
|
||||||
"-i": complete.PredictNothing,
|
"-i": complete.PredictNothing,
|
||||||
|
|
||||||
|
"-a": complete.PredictNothing,
|
||||||
|
"-n": complete.PredictNothing,
|
||||||
|
"-p": complete.PredictAnything,
|
||||||
|
"-race": complete.PredictNothing,
|
||||||
|
"-msan": complete.PredictNothing,
|
||||||
|
"-v": complete.PredictNothing,
|
||||||
|
"-work": complete.PredictNothing,
|
||||||
|
"-x": complete.PredictNothing,
|
||||||
|
"-asmflags": complete.PredictAnything,
|
||||||
|
"-buildmode": complete.PredictAnything,
|
||||||
|
"-compiler": complete.PredictAnything,
|
||||||
|
"-gccgoflags": complete.PredictAnything,
|
||||||
|
"-gcflags": complete.PredictAnything,
|
||||||
|
"-installsuffix": complete.PredictAnything,
|
||||||
|
"-ldflags": complete.PredictAnything,
|
||||||
|
"-linkshared": complete.PredictNothing,
|
||||||
|
"-pkgdir": complete.PredictDirs("./"),
|
||||||
|
"-tags": complete.PredictAnything,
|
||||||
|
"-toolexec": complete.PredictAnything,
|
||||||
},
|
},
|
||||||
Args: complete.PredictFiles("**.go").Or(complete.PredictDirs("./")),
|
Args: goFilesOrPackages,
|
||||||
}
|
}
|
||||||
|
|
||||||
test = complete.Command{
|
run := complete.Command{
|
||||||
Flags: complete.Flags{
|
Flags: complete.Flags{
|
||||||
"-run": complete.PredictAnything,
|
"-exec": complete.PredictAnything,
|
||||||
"-count": complete.PredictAnything,
|
|
||||||
},
|
},
|
||||||
|
Args: complete.PredictFiles("**.go"),
|
||||||
}
|
}
|
||||||
|
|
||||||
gogo = complete.Command{
|
test := complete.Command{
|
||||||
|
Flags: complete.Flags{
|
||||||
|
"-args": complete.PredictAnything,
|
||||||
|
"-c": complete.PredictNothing,
|
||||||
|
"-exec": complete.PredictAnything,
|
||||||
|
|
||||||
|
"-bench": predictTest("Benchmark"),
|
||||||
|
"-benchtime": complete.PredictAnything,
|
||||||
|
"-count": complete.PredictAnything,
|
||||||
|
"-cover": complete.PredictNothing,
|
||||||
|
"-covermode": complete.PredictSet([]string{"set", "count", "atomic"}),
|
||||||
|
"-coverpkg": complete.PredictDirs("./"),
|
||||||
|
"-cpu": complete.PredictAnything,
|
||||||
|
"-run": predictTest("test"),
|
||||||
|
"-short": complete.PredictNothing,
|
||||||
|
"-timeout": complete.PredictAnything,
|
||||||
|
|
||||||
|
"-benchmem": complete.PredictNothing,
|
||||||
|
"-blockprofile": complete.PredictFiles("**.out"),
|
||||||
|
"-blockprofilerate": complete.PredictAnything,
|
||||||
|
"-coverprofile": complete.PredictFiles("**.out"),
|
||||||
|
"-cpuprofile": complete.PredictFiles("**.out"),
|
||||||
|
"-memprofile": complete.PredictFiles("**.out"),
|
||||||
|
"-memprofilerate": complete.PredictAnything,
|
||||||
|
"-mutexprofile": complete.PredictFiles("**.out"),
|
||||||
|
"-mutexprofilefraction": complete.PredictAnything,
|
||||||
|
"-outputdir": complete.PredictDirs("./"),
|
||||||
|
"-trace": complete.PredictFiles("**.out"),
|
||||||
|
},
|
||||||
|
Args: goFilesOrPackages,
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt := complete.Command{
|
||||||
|
Flags: complete.Flags{
|
||||||
|
"-n": complete.PredictNothing,
|
||||||
|
"-x": complete.PredictNothing,
|
||||||
|
},
|
||||||
|
Args: goFilesOrPackages,
|
||||||
|
}
|
||||||
|
|
||||||
|
get := complete.Command{
|
||||||
|
Flags: complete.Flags{
|
||||||
|
"-d": complete.PredictNothing,
|
||||||
|
"-f": complete.PredictNothing,
|
||||||
|
"-fix": complete.PredictNothing,
|
||||||
|
"-insecure": complete.PredictNothing,
|
||||||
|
"-t": complete.PredictNothing,
|
||||||
|
"-u": complete.PredictNothing,
|
||||||
|
},
|
||||||
|
Args: goFilesOrPackages,
|
||||||
|
}
|
||||||
|
|
||||||
|
generate := complete.Command{
|
||||||
|
Flags: complete.Flags{
|
||||||
|
"-n": complete.PredictNothing,
|
||||||
|
"-x": complete.PredictNothing,
|
||||||
|
"-v": complete.PredictNothing,
|
||||||
|
"-run": complete.PredictAnything,
|
||||||
|
},
|
||||||
|
Args: goFilesOrPackages,
|
||||||
|
}
|
||||||
|
|
||||||
|
vet := complete.Command{
|
||||||
|
Flags: complete.Flags{
|
||||||
|
"-n": complete.PredictNothing,
|
||||||
|
"-x": complete.PredictNothing,
|
||||||
|
},
|
||||||
|
Args: complete.PredictDirs("./"),
|
||||||
|
}
|
||||||
|
|
||||||
|
list := complete.Command{
|
||||||
|
Flags: complete.Flags{
|
||||||
|
"-e": complete.PredictNothing,
|
||||||
|
"-f": complete.PredictAnything,
|
||||||
|
"-json": complete.PredictNothing,
|
||||||
|
},
|
||||||
|
Args: complete.PredictDirs("./"),
|
||||||
|
}
|
||||||
|
|
||||||
|
tool := complete.Command{
|
||||||
|
Flags: complete.Flags{
|
||||||
|
"-n": complete.PredictNothing,
|
||||||
|
},
|
||||||
|
Args: complete.PredictAnything,
|
||||||
|
}
|
||||||
|
|
||||||
|
clean := complete.Command{
|
||||||
|
Flags: complete.Flags{
|
||||||
|
"-i": complete.PredictNothing,
|
||||||
|
"-r": complete.PredictNothing,
|
||||||
|
"-n": complete.PredictNothing,
|
||||||
|
"-x": complete.PredictNothing,
|
||||||
|
},
|
||||||
|
Args: complete.PredictDirs("./"),
|
||||||
|
}
|
||||||
|
|
||||||
|
env := complete.Command{
|
||||||
|
Args: complete.PredictAnything,
|
||||||
|
}
|
||||||
|
|
||||||
|
bug := complete.Command{}
|
||||||
|
version := complete.Command{}
|
||||||
|
|
||||||
|
fix := complete.Command{
|
||||||
|
Args: complete.PredictDirs("./"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// commands that also accepts the build flags
|
||||||
|
for name, options := range build.Flags {
|
||||||
|
test.Flags[name] = options
|
||||||
|
run.Flags[name] = options
|
||||||
|
list.Flags[name] = options
|
||||||
|
vet.Flags[name] = options
|
||||||
|
}
|
||||||
|
|
||||||
|
gogo := complete.Command{
|
||||||
Sub: complete.Commands{
|
Sub: complete.Commands{
|
||||||
"build": build,
|
"build": build,
|
||||||
"test": test,
|
"install": build, // install and build have the same flags
|
||||||
|
"run": run,
|
||||||
|
"test": test,
|
||||||
|
"fmt": fmt,
|
||||||
|
"get": get,
|
||||||
|
"generate": generate,
|
||||||
|
"vet": vet,
|
||||||
|
"list": list,
|
||||||
|
"tool": tool,
|
||||||
|
"clean": clean,
|
||||||
|
"env": env,
|
||||||
|
"bug": bug,
|
||||||
|
"fix": fix,
|
||||||
|
"version": version,
|
||||||
},
|
},
|
||||||
Flags: complete.Flags{
|
Flags: complete.Flags{
|
||||||
"-h": complete.PredictNothing,
|
"-h": complete.PredictNothing,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
complete.New(gogo).Complete()
|
complete.New(gogo).Complete()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/ast"
|
||||||
|
"go/parser"
|
||||||
|
"go/token"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/posener/complete"
|
||||||
|
)
|
||||||
|
|
||||||
|
func predictTest(testType string) complete.Predicate {
|
||||||
|
return complete.Predicate{
|
||||||
|
Predictor: func() []complete.Option {
|
||||||
|
tests := testNames(testType)
|
||||||
|
options := make([]complete.Option, len(tests))
|
||||||
|
for i := range tests {
|
||||||
|
options[i] = complete.Arg(tests[i])
|
||||||
|
}
|
||||||
|
return options
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get all test names in current directory
|
||||||
|
func testNames(testType string) (tests []string) {
|
||||||
|
filepath.Walk("./", func(path string, info os.FileInfo, err error) error {
|
||||||
|
// if not a test file, skip
|
||||||
|
if !strings.HasSuffix(path, "_test.go") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// inspect test file and append all the test names
|
||||||
|
tests = append(tests, testsInFile(testType, path)...)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func testsInFile(testType, path string) (tests []string) {
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
f, err := parser.ParseFile(fset, path, nil, 0)
|
||||||
|
if err != nil {
|
||||||
|
complete.Log("Failed parsing %s: %s", path, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, d := range f.Decls {
|
||||||
|
if f, ok := d.(*ast.FuncDecl); ok {
|
||||||
|
name := f.Name.String()
|
||||||
|
if strings.HasPrefix(name, testType) {
|
||||||
|
tests = append(tests, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
7
log.go
7
log.go
|
@ -7,7 +7,12 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logger = getLogger()
|
// Log is used for debugging purposes
|
||||||
|
// since complete is running on tab completion, it is nice to
|
||||||
|
// have logs to the stderr (when writing your own completer)
|
||||||
|
// to write logs, set the COMP_DEBUG environment variable and
|
||||||
|
// use complete.Log in the complete program
|
||||||
|
var Log = getLogger()
|
||||||
|
|
||||||
func getLogger() func(format string, args ...interface{}) {
|
func getLogger() func(format string, args ...interface{}) {
|
||||||
var logfile io.Writer = ioutil.Discard
|
var logfile io.Writer = ioutil.Discard
|
||||||
|
|
|
@ -29,11 +29,11 @@ func (a ArgFileName) String() string {
|
||||||
func (a ArgFileName) Matches(prefix string) bool {
|
func (a ArgFileName) Matches(prefix string) bool {
|
||||||
full, err := filepath.Abs(string(a))
|
full, err := filepath.Abs(string(a))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger("failed getting abs path of %s: %s", a, err)
|
Log("failed getting abs path of %s: %s", a, err)
|
||||||
}
|
}
|
||||||
prefixFull, err := filepath.Abs(prefix)
|
prefixFull, err := filepath.Abs(prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger("failed getting abs path of %s: %s", prefix, err)
|
Log("failed getting abs path of %s: %s", prefix, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the file has the prefix as prefix,
|
// if the file has the prefix as prefix,
|
||||||
|
|
35
predicate.go
35
predicate.go
|
@ -7,10 +7,10 @@ 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 {
|
||||||
// Expects determine if the predicate expects something after.
|
// ExpectsNothing determine if the predicate expects something after.
|
||||||
// flags/commands that do not expect any specific argument should
|
// flags/commands that do not expect any specific argument should
|
||||||
// leave it on false
|
// leave it on false
|
||||||
Expects bool
|
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
|
||||||
|
@ -20,8 +20,8 @@ type Predicate struct {
|
||||||
// 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{
|
return Predicate{
|
||||||
Expects: p.Expects && other.Expects,
|
ExpectsNothing: p.ExpectsNothing && other.ExpectsNothing,
|
||||||
Predictor: func() []Option { return append(p.predict(), other.predict()...) },
|
Predictor: func() []Option { return append(p.predict(), other.predict()...) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,23 +33,30 @@ func (p Predicate) predict() []Option {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
PredictNothing = Predicate{Expects: false}
|
PredictNothing = Predicate{ExpectsNothing: true}
|
||||||
PredictAnything = Predicate{Expects: true}
|
PredictAnything = Predicate{}
|
||||||
)
|
)
|
||||||
|
|
||||||
func PredictFiles(pattern string) Predicate {
|
func PredictSet(options []string) Predicate {
|
||||||
return Predicate{
|
return Predicate{
|
||||||
Expects: true,
|
Predictor: func() []Option {
|
||||||
Predictor: glob(pattern),
|
ret := make([]Option, len(options))
|
||||||
|
for i := range options {
|
||||||
|
ret[i] = Arg(options[i])
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PredictFiles(pattern string) Predicate {
|
||||||
|
return Predicate{Predictor: glob(pattern)}
|
||||||
|
}
|
||||||
|
|
||||||
func PredictDirs(path string) Predicate {
|
func PredictDirs(path string) Predicate {
|
||||||
return Predicate{
|
return Predicate{Predictor: dirs(path)}
|
||||||
Expects: true,
|
|
||||||
Predictor: dirs(path),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func dirs(path string) func() []Option {
|
func dirs(path string) func() []Option {
|
||||||
return func() (options []Option) {
|
return func() (options []Option) {
|
||||||
dirs := []string{}
|
dirs := []string{}
|
||||||
|
@ -70,7 +77,7 @@ func glob(pattern string) func() []Option {
|
||||||
return func() []Option {
|
return func() []Option {
|
||||||
files, err := filepath.Glob(pattern)
|
files, err := filepath.Glob(pattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger("failed glob operation with pattern '%s': %s", pattern, err)
|
Log("failed glob operation with pattern '%s': %s", pattern, err)
|
||||||
}
|
}
|
||||||
if !filepath.IsAbs(pattern) {
|
if !filepath.IsAbs(pattern) {
|
||||||
filesToRel(files)
|
filesToRel(files)
|
||||||
|
|
Loading…
Reference in New Issue