summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--args.go38
-rw-r--r--command.go51
-rw-r--r--complete.go25
-rw-r--r--complete_test.go4
4 files changed, 66 insertions, 52 deletions
diff --git a/args.go b/args.go
new file mode 100644
index 0000000..bb45d1c
--- /dev/null
+++ b/args.go
@@ -0,0 +1,38 @@
+package complete
+
+type args struct {
+ all []string
+ completed []string
+ beingTyped string
+ lastCompleted string
+}
+
+func newArgs(line []string) args {
+ completed := removeLast(line)
+ return args{
+ all: line[1:],
+ completed: completed,
+ beingTyped: last(line),
+ lastCompleted: last(completed),
+ }
+}
+
+func (a args) from(i int) args {
+ a.all = a.all[i:]
+ a.completed = a.completed[i:]
+ return a
+}
+
+func removeLast(a []string) []string {
+ if len(a) > 0 {
+ return a[:len(a)-1]
+ }
+ return a
+}
+
+func last(args []string) (last string) {
+ if len(args) > 0 {
+ last = args[len(args)-1]
+ }
+ return
+}
diff --git a/command.go b/command.go
index f52d175..6e4a773 100644
--- a/command.go
+++ b/command.go
@@ -3,7 +3,7 @@ package complete
import "github.com/posener/complete/match"
// Command represents a command line
-// It holds the data that enables auto completion of a given typed command line
+// It holds the data that enables auto completion of command line
// Command can also be a sub command.
type Command struct {
// Sub is map of sub commands of the current command
@@ -12,7 +12,7 @@ type Command struct {
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.
+ // The key is the flag name, and the value is it's prediction predict.
Flags Flags
// Args are extra arguments that the command accepts, those who are
@@ -24,62 +24,52 @@ type 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.
+// prediction predict.
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 []match.Matcher, only bool) {
+// predict returns all available complete predict for the given command
+// all are all except the last command line arguments relevant to the command
+func (c *Command) predict(a args) (options []match.Matcher, only bool) {
- // remove the first argument, which is the command name
- args = args[1:]
- wordCurrent := last(args)
- wordCompleted := last(removeLast(args))
// if wordCompleted has something that needs to follow it,
// it is the most relevant completion
- if predicate, ok := c.Flags[wordCompleted]; ok && predicate != nil {
- Log("Predicting according to flag %s", wordCurrent)
- return predicate.predict(wordCurrent), true
+ if predicate, ok := c.Flags[a.lastCompleted]; ok && predicate != nil {
+ Log("Predicting according to flag %s", a.beingTyped)
+ return predicate.predict(a.beingTyped), true
}
- sub, options, only := c.searchSub(args)
+ sub, options, only := c.searchSub(a)
if only {
return
}
- // if no subcommand was entered in any of the args, add the
- // subcommands as complete options.
+ // if no sub command was found, return a list of the sub commands
if sub == "" {
options = append(options, c.subCommands()...)
}
- // add global available complete options
+ // add global available complete predict
for flag := range c.Flags {
options = append(options, match.Prefix(flag))
}
// add additional expected argument of the command
- options = append(options, c.Args.predict(wordCurrent)...)
+ options = append(options, c.Args.predict(a.beingTyped)...)
return
}
// 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 []match.Matcher, only bool) {
-
- // search for sub command in all arguments except the last one
- // because that one might not be completed yet
- searchArgs := removeLast(args)
-
- for i, arg := range searchArgs {
+func (c *Command) searchSub(a args) (sub string, all []match.Matcher, only bool) {
+ for i, arg := range a.completed {
if cmd, ok := c.Sub[arg]; ok {
sub = arg
- all, only = cmd.options(args[i:])
+ all, only = cmd.predict(a.from(i))
return
}
}
- return "", nil, false
+ return
}
// suvCommands returns a list of matchers according to the sub command names
@@ -90,10 +80,3 @@ func (c *Command) subCommands() []match.Matcher {
}
return subs
}
-
-func removeLast(a []string) []string {
- if len(a) > 0 {
- return a[:len(a)-1]
- }
- return a
-}
diff --git a/complete.go b/complete.go
index c91bf5f..2780e62 100644
--- a/complete.go
+++ b/complete.go
@@ -41,15 +41,17 @@ func New(name string, command Command) *Complete {
// returns success if the completion ran or if the cli matched
// any of the given flags, false otherwise
func (c *Complete) Run() bool {
- args, ok := getLine()
+ line, ok := getLine()
if !ok {
// make sure flags parsed,
// in case they were not added in the main program
return c.CLI.Run()
}
- Log("Completing args: %s", args)
+ Log("Completing line: %s", line)
- options := complete(c.Command, args)
+ a := newArgs(line)
+
+ options := complete(c.Command, a)
Log("Completion: %s", options)
output(options)
@@ -58,14 +60,12 @@ func (c *Complete) Run() bool {
// complete get a command an command line arguments and returns
// matching completion options
-func complete(c Command, args []string) (matching []string) {
- options, _ := c.options(args)
+func complete(c Command, a args) (matching []string) {
+ options, _ := c.predict(a)
- // choose only matching options
- l := last(args)
for _, option := range options {
- Log("option %T, %s -> %t", option, option, option.Match(l))
- if option.Match(l) {
+ Log("option %T, %s -> %t", option, option, option.Match(a.beingTyped))
+ if option.Match(a.beingTyped) {
matching = append(matching, option.String())
}
}
@@ -80,13 +80,6 @@ func getLine() ([]string, bool) {
return strings.Split(line, " "), true
}
-func last(args []string) (last string) {
- if len(args) > 0 {
- last = args[len(args)-1]
- }
- return
-}
-
func output(options []string) {
Log("")
// stdout of program defines the complete options
diff --git a/complete_test.go b/complete_test.go
index 282a2f6..0079c30 100644
--- a/complete_test.go
+++ b/complete_test.go
@@ -174,9 +174,9 @@ func TestCompleter_Complete(t *testing.T) {
tt.args = "cmd " + tt.args
os.Setenv(envComplete, tt.args)
- args, _ := getLine()
+ line, _ := getLine()
- got := complete(c, args)
+ got := complete(c, newArgs(line))
sort.Strings(tt.want)
sort.Strings(got)