Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion autocomplete.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cli

import (
"github.com/posener/complete/cmd/install"
"github.com/posener/complete/v2/install"
)

// autocompleteInstaller is an interface to be implemented to perform the
Expand Down
30 changes: 16 additions & 14 deletions cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import (
"text/template"

"github.com/armon/go-radix"
"github.com/posener/complete"
"github.com/posener/complete/v2"
"github.com/posener/complete/v2/predict"
)

// CLI contains the state necessary to run subcommands and parse the
Expand Down Expand Up @@ -106,7 +107,7 @@ type CLI struct {
AutocompleteInstall string
AutocompleteUninstall string
AutocompleteNoDefaultFlags bool
AutocompleteGlobalFlags complete.Flags
AutocompleteGlobalFlags map[string]complete.Predictor
autocompleteInstaller autocompleteInstaller // For tests

// HelpFunc and HelpWriter are used to output help information, if
Expand All @@ -125,7 +126,7 @@ type CLI struct {
// Internal fields set automatically

once sync.Once
autocomplete *complete.Complete
autocomplete complete.Command
commandTree *radix.Tree
commandNested bool
commandHidden map[string]struct{}
Expand Down Expand Up @@ -173,9 +174,10 @@ func (c *CLI) Run() (int, error) {
// If this is a autocompletion request, satisfy it. This must be called
// first before anything else since its possible to be autocompleting
// -help or -version or other flags and we want to show completions
// and not actually write the help or version.
if c.Autocomplete && c.autocomplete.Complete() {
return 0, nil
// and not actually write the help or version. In case of completion
// flow, this function will perform os.Exit.
if c.Autocomplete {
complete.Complete(c.Name, &c.autocomplete)
}

// Just show the version and exit if instructed.
Expand Down Expand Up @@ -402,15 +404,15 @@ func (c *CLI) initAutocomplete() {
// they don't show up on every command.
if !c.AutocompleteNoDefaultFlags {
cmd.Flags = map[string]complete.Predictor{
"-" + c.AutocompleteInstall: complete.PredictNothing,
"-" + c.AutocompleteUninstall: complete.PredictNothing,
"-help": complete.PredictNothing,
"-version": complete.PredictNothing,
"-" + c.AutocompleteInstall: predict.Nothing,
"-" + c.AutocompleteUninstall: predict.Nothing,
"-help": predict.Nothing,
"-version": predict.Nothing,
}
}
cmd.GlobalFlags = c.AutocompleteGlobalFlags
cmd.Flags = c.AutocompleteGlobalFlags

c.autocomplete = complete.New(c.Name, cmd)
c.autocomplete = cmd
}

// initAutocompleteSub creates the complete.Command for a subcommand with
Expand Down Expand Up @@ -451,7 +453,7 @@ func (c *CLI) initAutocompleteSub(prefix string) complete.Command {
}

if cmd.Sub == nil {
cmd.Sub = complete.Commands(make(map[string]complete.Command))
cmd.Sub = make(map[string]*complete.Command)
}
subCmd := c.initAutocompleteSub(fullKey)

Expand All @@ -470,7 +472,7 @@ func (c *CLI) initAutocompleteSub(prefix string) complete.Command {
subCmd.Flags = c.AutocompleteFlags()
}

cmd.Sub[k] = subCmd
cmd.Sub[k] = &subCmd
return false
}

Expand Down
48 changes: 23 additions & 25 deletions cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ import (
"os"
"reflect"
"sort"
"strconv"
"strings"
"testing"

"github.com/posener/complete"
"github.com/posener/complete/v2"
"github.com/posener/complete/v2/predict"
)

// envComplete is the env var that the complete library sets to specify
// it should be calculating an auto-completion. This isn't exported so we
// reproduce it here. If it changes then we'll have to update this.
const envComplete = "COMP_LINE"
// envComplete and envPoint are the env vars that the complete library sets
// to specify it should be calculating an auto-completion. This isn't
// exported so we reproduce it here. If it changes then we'll have to update
// this.
const (
envComplete = "COMP_LINE"
envPoint = "COMP_POINT"
)

func TestCLIIsHelp(t *testing.T) {
testCases := []struct {
Expand Down Expand Up @@ -1244,7 +1250,7 @@ func TestCLIAutocomplete_rootGlobalFlags(t *testing.T) {

Autocomplete: true,
AutocompleteGlobalFlags: map[string]complete.Predictor{
"-tubes": complete.PredictNothing,
"-tubes": predict.Nothing,
},
}

Expand Down Expand Up @@ -1325,7 +1331,7 @@ func TestCLIAutocomplete_rootDisableDefaultFlags(t *testing.T) {
Autocomplete: true,
AutocompleteNoDefaultFlags: true,
AutocompleteGlobalFlags: map[string]complete.Predictor{
"-tubes": complete.PredictNothing,
"-tubes": predict.Nothing,
},
}
// Setup the autocomplete line
Expand Down Expand Up @@ -1384,20 +1390,19 @@ func TestCLIAutocomplete_rootDisableDefaultFlags(t *testing.T) {

func TestCLIAutocomplete_subcommandArgs(t *testing.T) {
cases := []struct {
Completed []string
Last string
Expected []string
Command string
Expected []string
}{
{[]string{"foo"}, "RE", []string{"README.md"}},
{[]string{"foo", "-go"}, "asdf", []string{"yo"}},
{"foo RE", []string{"README.md"}},
{"foo -go asdf", []string{"yo"}},
}

for _, tc := range cases {
t.Run(tc.Last, func(t *testing.T) {
t.Run(tc.Command, func(t *testing.T) {
command := new(MockCommandAutocomplete)
command.AutocompleteArgsValue = complete.PredictFiles("*")
command.AutocompleteArgsValue = predict.Files("*")
command.AutocompleteFlagsValue = map[string]complete.Predictor{
"-go": complete.PredictFunc(func(complete.Args) []string {
"-go": complete.PredictFunc(func(string) []string {
return []string{"yo"}
}),
}
Expand All @@ -1416,16 +1421,7 @@ func TestCLIAutocomplete_subcommandArgs(t *testing.T) {
cli.init()

// Test the autocompleter
actual := cli.autocomplete.Command.Predict(complete.Args{
Completed: tc.Completed,
Last: tc.Last,
LastCompleted: tc.Completed[len(tc.Completed)-1],
})
sort.Strings(actual)

if !reflect.DeepEqual(actual, tc.Expected) {
t.Fatalf("bad prediction: %#v", actual)
}
complete.Test(t, &cli.autocomplete, tc.Command, tc.Expected)
})
}
}
Expand Down Expand Up @@ -1489,6 +1485,7 @@ func TestCLISubcommand_nested(t *testing.T) {
func testAutocomplete(t *testing.T, input string) func() {
// This env var is used to trigger autocomplete
os.Setenv(envComplete, input)
os.Setenv(envPoint, strconv.Itoa(len(input)))

// Change stdout/stderr since the autocompleter writes directly to them.
oldStdout := os.Stdout
Expand All @@ -1505,6 +1502,7 @@ func testAutocomplete(t *testing.T, input string) func() {
return func() {
// Reset our env
os.Unsetenv(envComplete)
os.Unsetenv(envPoint)

// Reset stdout, stderr
os.Stdout = oldStdout
Expand Down
4 changes: 2 additions & 2 deletions command.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cli

import (
"github.com/posener/complete"
"github.com/posener/complete/v2"
)

const (
Expand Down Expand Up @@ -43,7 +43,7 @@ type CommandAutocomplete interface {
// AutocompleteFlags returns a mapping of supported flags and autocomplete
// options for this command. The map key for the Flags map should be the
// complete flag such as "-foo" or "--foo".
AutocompleteFlags() complete.Flags
AutocompleteFlags() map[string]complete.Predictor
}

// CommandHelpTemplate is an extension of Command that also has a function
Expand Down
6 changes: 3 additions & 3 deletions command_mock.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cli

import (
"github.com/posener/complete"
"github.com/posener/complete/v2"
)

// MockCommand is an implementation of Command that can be used for tests.
Expand Down Expand Up @@ -39,14 +39,14 @@ type MockCommandAutocomplete struct {

// Settable
AutocompleteArgsValue complete.Predictor
AutocompleteFlagsValue complete.Flags
AutocompleteFlagsValue map[string]complete.Predictor
}

func (c *MockCommandAutocomplete) AutocompleteArgs() complete.Predictor {
return c.AutocompleteArgsValue
}

func (c *MockCommandAutocomplete) AutocompleteFlags() complete.Flags {
func (c *MockCommandAutocomplete) AutocompleteFlags() map[string]complete.Predictor {
return c.AutocompleteFlagsValue
}

Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ require (
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310
github.com/bgentry/speakeasy v0.1.0
github.com/fatih/color v1.7.0
github.com/hashicorp/go-multierror v1.0.0 // indirect
github.com/mattn/go-colorable v0.0.9 // indirect
github.com/mattn/go-isatty v0.0.3
github.com/posener/complete v1.1.1
github.com/posener/complete/v2 v2.0.1-alpha.3
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc // indirect
)

go 1.13
19 changes: 13 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,28 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357 h1:Rem2+U35z1QtPQc6r+WolF7yXiefXqDKyk+lN2pE164=
github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v0.0.0-20180717150148-3d5d8f294aa0 h1:j30noezaCfvNLcdMYSvHLv81DxYRSt1grlpseG67vhU=
github.com/hashicorp/go-multierror v0.0.0-20180717150148-3d5d8f294aa0/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete/v2 v2.0.1-alpha.2 h1:y/9Kv6uzksN+fxY+qVBsJpRdyDNG+rEvJ2kiPQ73XVI=
github.com/posener/complete/v2 v2.0.1-alpha.2/go.mod h1:Q5Am7Oqn7AYZ/ZeyLMtB/4R3DYQi4atyOdgD8kP1mQw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc h1:MeuS1UDyZyFH++6vVy44PuufTeFF0d0nfI6XB87YGSk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=