Skip to content

Commit

Permalink
improve docs
Browse files Browse the repository at this point in the history
  • Loading branch information
posener committed May 6, 2017
1 parent 9963a85 commit 703dd6e
Show file tree
Hide file tree
Showing 12 changed files with 230 additions and 64 deletions.
15 changes: 12 additions & 3 deletions cmd.go → cmd/cmd.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package complete
// Package cmd used for command line options for the complete tool
package cmd

import (
"errors"
Expand All @@ -7,10 +8,13 @@ import (
"os"
"strings"

"github.com/posener/complete/install"
"github.com/posener/complete/cmd/install"
)

func runCommandLine(cmd string) {
// Run is used when running complete in command line mode.
// this is used when the complete is not completing words, but to
// install it or uninstall it.
func Run(cmd string) {
c := parseFlags(cmd)
err := c.validate()
if err != nil {
Expand All @@ -34,6 +38,7 @@ func runCommandLine(cmd string) {
fmt.Println("Done!")
}

// prompt use for approval
func prompt(action, cmd string) bool {
fmt.Printf("%s bash completion for %s? ", action, cmd)
var answer string
Expand All @@ -47,13 +52,15 @@ func prompt(action, cmd string) bool {
}
}

// config for command line
type config struct {
install bool
uninstall bool
root bool
yes bool
}

// create a config from command line arguments
func parseFlags(cmd string) config {
var c config
flag.BoolVar(&c.install, "install", false,
Expand All @@ -69,6 +76,7 @@ func parseFlags(cmd string) config {
return c
}

// validate the config
func (c config) validate() error {
if c.install && c.uninstall {
return errors.New("Install and uninstall are exclusive")
Expand All @@ -79,6 +87,7 @@ func (c config) validate() error {
return nil
}

// action name according to the config values.
func (c config) action() string {
if c.install {
return "Install"
Expand Down
1 change: 0 additions & 1 deletion install/home.go → cmd/install/home.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ func isInFile(name string, lookFor string) bool {
}
prefix = prefix[:0]
}
return false
}

func uninstallToTemp(bashRCFileName, completeCmd string) (string, error) {
Expand Down
File renamed without changes.
File renamed without changes.
48 changes: 36 additions & 12 deletions command.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,40 @@
package complete

type Commands map[string]Command
// Command represents a command line
// It holds the data that enables auto completion of a given typed command line
// Command can also be a sub command.
type Command struct {
// Name is the name of command,
// IMPORTANT: For root command - it must be the same name as the program
// that the auto complete completes. So if the auto complete
// completes the 'go' command, Name must be equal to "go".
// It is optional for sub commands.
Name string

type Flags map[string]Predicate
// Sub is map of sub commands of the current command
// The key refer to the sub command name, and the value is it's
// Command descriptive struct.
Sub Commands

type Command struct {
Name string
Sub Commands
// Flags is a map of flags that the command accepts.
// The key is the flag name, and the value is it's prediction options.
Flags Flags
Args Predicate

// Args are extra arguments that the command accepts, those who are
// given without any flag before.
Args Predicate
}

// Commands is the type of Sub member, it maps a command name to a command struct
type Commands map[string]Command

// Flags is the type Flags of the Flags member, it maps a flag name to the flag
// prediction options.
type Flags map[string]Predicate

// options returns all available complete options for the given command
// args are all except the last command line arguments relevant to the command
func (c *Command) options(args []string) (options []Option, only bool) {
func (c *Command) options(args []string) (options []Matcher, only bool) {

// remove the first argument, which is the command name
args = args[1:]
Expand All @@ -37,7 +58,7 @@ func (c *Command) options(args []string) (options []Option, only bool) {

// add global available complete options
for flag := range c.Flags {
options = append(options, Arg(flag))
options = append(options, MatchPrefix(flag))
}

// add additional expected argument of the command
Expand All @@ -46,7 +67,9 @@ func (c *Command) options(args []string) (options []Option, only bool) {
return
}

func (c *Command) searchSub(args []string) (sub string, all []Option, only bool) {
// searchSub searches recursively within sub commands if the sub command appear
// in the on of the arguments.
func (c *Command) searchSub(args []string) (sub string, all []Matcher, only bool) {
for i, arg := range args {
if cmd, ok := c.Sub[arg]; ok {
sub = arg
Expand All @@ -57,10 +80,11 @@ func (c *Command) searchSub(args []string) (sub string, all []Option, only bool)
return "", nil, false
}

func (c *Command) subCommands() []Option {
subs := make([]Option, 0, len(c.Sub))
// suvCommands returns a list of matchers according to the sub command names
func (c *Command) subCommands() []Matcher {
subs := make([]Matcher, 0, len(c.Sub))
for sub := range c.Sub {
subs = append(subs, Arg(sub))
subs = append(subs, MatchPrefix(sub))
}
return subs
}
46 changes: 46 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package complete_test

import "github.com/posener/complete"

func main() {

// create a Command object, that represents the command we want
// to complete.
run := complete.Command{

// Name must be exactly as the binary that we want to complete
Name: "run",

// Sub defines a list of sub commands of the program,
// this is recursive, since every command is of type command also.
Sub: complete.Commands{

// add a build sub command
"build": complete.Command{

// define flags of the build sub command
Flags: complete.Flags{
// build sub command has a flag '-fast', which
// does not expects anything after it.
"-fast": complete.PredictNothing,
},
},
},

// define flags of the 'run' main command
Flags: complete.Flags{

// a flag '-h' which does not expects anything after it
"-h": complete.PredictNothing,

// a flag -o, which expects a file ending with .out after
// it, the tab completion will auto complete for files matching
// the given pattern.
"-o": complete.PredictFiles("*.out"),
},
}

// run the command completion, as part of the main() function.
// this triggers the autocompletion when needed.
complete.Run(run)
}
5 changes: 3 additions & 2 deletions gocomplete/complete.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package main is complete tool for the go command line
package main

import (
Expand All @@ -7,15 +8,15 @@ import (
var (
predictEllipsis = complete.PredictSet("./...")

goFilesOrPackages = complete.PredictFiles("**.go").
goFilesOrPackages = complete.PredictFiles("*.go").
Or(complete.PredictDirs).
Or(predictEllipsis)
)

func main() {
build := complete.Command{
Flags: complete.Flags{
"-o": complete.PredictFiles("**"),
"-o": complete.PredictFiles("*"),
"-i": complete.PredictNothing,

"-a": complete.PredictNothing,
Expand Down
6 changes: 3 additions & 3 deletions gocomplete/tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import (
)

func predictTest(testType string) complete.Predicate {
return func(last string) []complete.Option {
return func(last string) []complete.Matcher {
tests := testNames(testType)
options := make([]complete.Option, len(tests))
options := make([]complete.Matcher, len(tests))
for i := range tests {
options[i] = complete.Arg(tests[i])
options[i] = complete.MatchPrefix(tests[i])
}
return options
}
Expand Down
22 changes: 14 additions & 8 deletions option.go → match.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,34 @@ import (
"strings"
)

type Option interface {
// Matcher matches itself to a string
// it is used for comparing a given argument to the last typed
// word, and see if it is a possible auto complete option.
type Matcher interface {
String() string
Matches(prefix string) bool
Match(prefix string) bool
}

type Arg string
// MatchPrefix is a simple Matcher, if the word is it's prefix, there is a match
type MatchPrefix string

func (a Arg) String() string {
func (a MatchPrefix) String() string {
return string(a)
}

func (a Arg) Matches(prefix string) bool {
func (a MatchPrefix) Match(prefix string) bool {
return strings.HasPrefix(string(a), prefix)
}

type ArgFileName string
// MatchFileName is a file name Matcher, if the last word can prefix the
// MatchFileName path, there is a possible match
type MatchFileName string

func (a ArgFileName) String() string {
func (a MatchFileName) String() string {
return string(a)
}

func (a ArgFileName) Matches(prefix string) bool {
func (a MatchFileName) Match(prefix string) bool {
full, err := filepath.Abs(string(a))
if err != nil {
Log("failed getting abs path of %s: %s", a, err)
Expand Down
Loading

0 comments on commit 703dd6e

Please sign in to comment.