Skip to content
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
44 changes: 16 additions & 28 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ type App struct {
// Set when the app is run via RunAsSubcommand; the version flag belongs to
// the top-level app only
runningAsSubcommand bool
// An action to execute when the bash-completion flag is set
BashComplete BashCompleteFunc
// An action to execute before any subcommands are run, but after the context is ready
// If a non-nil error is returned, no subcommands are run
Before BeforeFunc
Expand Down Expand Up @@ -128,16 +126,15 @@ func compileTime() time.Time {
// Usage, Version and Action.
func NewApp() *App {
return &App{
Name: filepath.Base(os.Args[0]),
HelpName: filepath.Base(os.Args[0]),
Usage: "A new cli application",
UsageText: "",
Version: "0.0.0",
BashComplete: DefaultAppComplete,
Action: helpCommand.Action,
Compiled: compileTime(),
Writer: os.Stdout,
HelpWriter: os.Stdout,
Name: filepath.Base(os.Args[0]),
HelpName: filepath.Base(os.Args[0]),
Usage: "A new cli application",
UsageText: "",
Version: "0.0.0",
Action: helpCommand.Action,
Compiled: compileTime(),
Writer: os.Stdout,
HelpWriter: os.Stdout,
}
}

Expand Down Expand Up @@ -190,13 +187,13 @@ func (a *App) Setup() {
func (a *App) Run(arguments []string) (err error) {
a.Setup()

// handle the completion flag separately from the flagset since
// completion could be attempted after a flag, but before its value was put
// on the command line. this causes the flagset to interpret the completion
// flag name as the value of the flag before it which is undesirable
// note that we can only do this because the shell autocomplete function
// always appends the completion flag at the end of the command
shellComplete, arguments := checkShellCompleteFlag(a, arguments)
// Answer shell-completion requests: when completion is enabled and the
// process was spawned by the shell for completion (COMP_LINE is set),
// emit predictions and return without running the command.
if a.EnableBashCompletion && os.Getenv("COMP_LINE") != "" {
a.runShellCompletion()
return nil
}

// parse flags
flags := a.resolveFlags()
Expand All @@ -213,11 +210,6 @@ func (a *App) Run(arguments []string) (err error) {
fmt.Fprintln(a.Writer, nerr)
return nerr
}
context.shellComplete = shellComplete

if checkCompletions(context) {
return nil
}

if err != nil {
if onUsageError := a.resolveOnUsageError(); onUsageError != nil {
Expand Down Expand Up @@ -330,10 +322,6 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
return nerr
}

if checkCompletions(context) {
return nil
}

if err != nil {
if onUsageError := a.resolveOnUsageError(); onUsageError != nil {
err = onUsageError(context, err, true)
Expand Down
101 changes: 7 additions & 94 deletions app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"reflect"
"strings"
"testing"

"github.com/posener/complete"
)

var (
Expand All @@ -27,7 +29,7 @@ func init() {
}

type opCounts struct {
Total, BashComplete, OnUsageError, Before, CommandNotFound, Action, After, SubCommand int
Total, OnUsageError, Before, CommandNotFound, Action, After, SubCommand int
}

func ExampleApp_Run() {
Expand Down Expand Up @@ -228,43 +230,6 @@ func ExampleApp_Run_subcommandNoAction() {
// --help, -h show help
}

func ExampleApp_Run_bashComplete() {
// set args for examples sake
os.Args = []string{"greet", "--generate-bash-completion"}

app := NewApp()
app.Name = "greet"
app.EnableBashCompletion = true
app.Commands = []Command{
{
Name: "describeit",
Aliases: []string{"d"},
Usage: "use it to see a description",
Description: "This is how we describe describeit the function",
Action: func(c *Context) error {
fmt.Printf("i like to describe things")
return nil
},
}, {
Name: "next",
Usage: "next example",
Description: "more stuff to see when generating bash completion",
Action: func(c *Context) error {
fmt.Printf("the next example")
return nil
},
},
}

app.Run(os.Args)
// Output:
// describeit
// d
// next
// help
// h
}

func TestApp_Run(t *testing.T) {
s := ""

Expand Down Expand Up @@ -884,12 +849,6 @@ func TestApp_OrderOfOperations(t *testing.T) {
resetCounts := func() { counts = &opCounts{} }

app := NewApp()
app.EnableBashCompletion = true
app.BashComplete = func(c *Context) {
counts.Total++
counts.BashComplete = counts.Total
}

app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
counts.Total++
counts.OnUsageError = counts.Total
Expand Down Expand Up @@ -950,12 +909,6 @@ func TestApp_OrderOfOperations(t *testing.T) {

resetCounts()

_ = app.Run([]string{"command", "--generate-bash-completion"})
expect(t, counts.BashComplete, 1)
expect(t, counts.Total, 1)

resetCounts()

oldOnUsageError := app.OnUsageError
app.OnUsageError = nil
_ = app.Run([]string{"command", "--nope"})
Expand Down Expand Up @@ -1596,6 +1549,10 @@ func (c *customBoolFlag) Apply(set *flag.FlagSet) {
set.String(c.Nombre, c.Nombre, "")
}

func (c *customBoolFlag) GetCompleter() complete.Predictor {
return complete.PredictNothing
}

func TestCustomFlagsUnused(t *testing.T) {
app := NewApp()
app.Flags = []Flag{&customBoolFlag{"custom"}}
Expand Down Expand Up @@ -1650,47 +1607,3 @@ func TestHandleAction_WithUnknownPanic(t *testing.T) {
}
app.Action(NewContext(app, fs, nil))
}

func TestShellCompletionForIncompleteFlags(t *testing.T) {
app := NewApp()
app.Flags = []Flag{
IntFlag{
Name: "test-completion",
},
}
app.EnableBashCompletion = true
app.BashComplete = func(ctx *Context) {
for _, command := range ctx.App.Commands {
if command.Hidden {
continue
}

for _, name := range command.Names() {
fmt.Fprintln(ctx.App.Writer, name)
}
}

for _, flag := range ctx.App.Flags {
for _, name := range strings.Split(flag.GetName(), ",") {
if name == BashCompletionFlag.GetName() {
continue
}

switch name = strings.TrimSpace(name); len(name) {
case 0:
case 1:
fmt.Fprintln(ctx.App.Writer, "-"+name)
default:
fmt.Fprintln(ctx.App.Writer, "--"+name)
}
}
}
}
app.Action = func(ctx *Context) error {
return fmt.Errorf("should not get here")
}
err := app.Run([]string{"", "--test-completion", "--" + BashCompletionFlag.GetName()})
if err != nil {
t.Errorf("app should not return an error: %s", err)
}
}
16 changes: 0 additions & 16 deletions autocomplete/bash_autocomplete

This file was deleted.

5 changes: 0 additions & 5 deletions autocomplete/zsh_autocomplete

This file was deleted.

28 changes: 15 additions & 13 deletions cli.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
// Package cli provides a minimal framework for creating and organizing command line
// Go applications. cli is designed to be easy to understand and write, the most simple
// cli application can be written as follows:
// func main() {
// cli.NewApp().Run(os.Args)
// }
//
// func main() {
// cli.NewApp().Run(os.Args)
// }
//
// Of course this application does not do much, so let's make this an actual application:
// func main() {
// app := cli.NewApp()
// app.Name = "greet"
// app.Usage = "say a greeting"
// app.Action = func(c *cli.Context) error {
// println("Greetings")
// }
//
// app.Run(os.Args)
// }
// func main() {
// app := cli.NewApp()
// app.Name = "greet"
// app.Usage = "say a greeting"
// app.Action = func(c *cli.Context) error {
// println("Greetings")
// }
//
// app.Run(os.Args)
// }
package cli

//go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go
//go:generate python3 ./generate-flag-types.py cli -i flag-types.json -o flag_generated.go
16 changes: 5 additions & 11 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"slices"
"sort"
"strings"

"github.com/posener/complete"
)

// Command is a subcommand for a cli.App.
Expand All @@ -26,8 +28,9 @@ type Command struct {
ArgsUsage string
// The category the command is part of
Category string
// The function to call when checking for bash command completions
BashComplete BashCompleteFunc
// Completer predicts this command's positional arguments during shell
// completion.
Completer complete.Predictor
// An action to execute before any sub-subcommands are run, but after the context is ready
// If a non-nil error is returned, no sub-subcommands are run
Before BeforeFunc
Expand Down Expand Up @@ -187,9 +190,6 @@ func (c Command) Run(ctx *Context) (err error) {

context := NewContext(ctx.App, set, ctx)
context.Command = c
if checkCommandCompletions(context, c.Name) {
return nil
}

if err != nil {
if onUsageError := c.resolveOnUsageError(context); onUsageError != nil {
Expand Down Expand Up @@ -325,12 +325,6 @@ func (c Command) startApp(ctx *Context) error {

sort.Sort(app.categories)

// bash completion
app.EnableBashCompletion = ctx.App.EnableBashCompletion
if c.BashComplete != nil {
app.BashComplete = c.BashComplete
}

// set the actions
app.Before = c.resolveBefore(ctx)
app.After = c.resolveAfter(ctx)
Expand Down
Loading
Loading