From f1b8fe152766d633183d3d8a7b23d9da41bc729b Mon Sep 17 00:00:00 2001 From: Bittrance Date: Mon, 28 Apr 2025 18:18:36 +0200 Subject: [PATCH 1/2] Simpler top-level context detection for fish completions. Previously, completions checked against all levels of subcommands. This change has it look only for top-level commands, which must necessarily be present before their children. It also adds hidden top-level commands to the list. --- fish.go | 21 ++++++++++++--------- testdata/expected-fish-full.fish | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/fish.go b/fish.go index b1086ebc9e..4407fceb9b 100644 --- a/fish.go +++ b/fish.go @@ -30,16 +30,15 @@ func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error { if err != nil { return err } - allCommands := []string{} // Add global flags - completions := cmd.prepareFishFlags(cmd.VisibleFlags(), allCommands) + completions := cmd.prepareFishFlags(cmd.VisibleFlags(), []string{}) // Add help flag if !cmd.HideHelp { completions = append( completions, - cmd.prepareFishFlags([]Flag{HelpFlag}, allCommands)..., + cmd.prepareFishFlags([]Flag{HelpFlag}, []string{})..., ) } @@ -47,24 +46,29 @@ func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error { if !cmd.HideVersion { completions = append( completions, - cmd.prepareFishFlags([]Flag{VersionFlag}, allCommands)..., + cmd.prepareFishFlags([]Flag{VersionFlag}, []string{})..., ) } // Add commands and their flags completions = append( completions, - cmd.prepareFishCommands(cmd.VisibleCommands(), &allCommands, []string{})..., + cmd.prepareFishCommands(cmd.VisibleCommands(), []string{})..., ) + toplevelCommandNames := []string{} + for _, child := range cmd.Commands { + toplevelCommandNames = append(toplevelCommandNames, child.Names()...) + } + return t.ExecuteTemplate(w, name, &fishCommandCompletionTemplate{ Command: cmd, Completions: completions, - AllCommands: allCommands, + AllCommands: toplevelCommandNames, }) } -func (cmd *Command) prepareFishCommands(commands []*Command, allCommands *[]string, previousCommands []string) []string { +func (cmd *Command) prepareFishCommands(commands []*Command, previousCommands []string) []string { completions := []string{} for _, command := range commands { var completion strings.Builder @@ -88,7 +92,6 @@ func (cmd *Command) prepareFishCommands(commands []*Command, allCommands *[]stri ) } - *allCommands = append(*allCommands, command.Names()...) completions = append(completions, completion.String()) completions = append( completions, @@ -100,7 +103,7 @@ func (cmd *Command) prepareFishCommands(commands []*Command, allCommands *[]stri completions = append( completions, cmd.prepareFishCommands( - command.Commands, allCommands, command.Names(), + command.Commands, command.Names(), )..., ) } diff --git a/testdata/expected-fish-full.fish b/testdata/expected-fish-full.fish index f586c66fda..25329b4636 100644 --- a/testdata/expected-fish-full.fish +++ b/testdata/expected-fish-full.fish @@ -2,7 +2,7 @@ function __fish_greet_no_subcommand --description 'Test if there has been any subcommand yet' for i in (commandline -opc) - if contains -- $i config c sub-config s ss info i in some-command usage u sub-usage su + if contains -- $i config c info i in some-command hidden-command usage u return 1 end end From 55db2a0b66d452738e508415083263196b792ce2 Mon Sep 17 00:00:00 2001 From: Bittrance Date: Mon, 28 Apr 2025 21:50:54 +0200 Subject: [PATCH 2/2] Fish completions need not add their own help commands. --- fish.go | 24 ------------------------ testdata/expected-fish-full.fish | 8 -------- 2 files changed, 32 deletions(-) diff --git a/fish.go b/fish.go index 4407fceb9b..8d7af2797a 100644 --- a/fish.go +++ b/fish.go @@ -34,22 +34,6 @@ func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error { // Add global flags completions := cmd.prepareFishFlags(cmd.VisibleFlags(), []string{}) - // Add help flag - if !cmd.HideHelp { - completions = append( - completions, - cmd.prepareFishFlags([]Flag{HelpFlag}, []string{})..., - ) - } - - // Add version flag - if !cmd.HideVersion { - completions = append( - completions, - cmd.prepareFishFlags([]Flag{VersionFlag}, []string{})..., - ) - } - // Add commands and their flags completions = append( completions, @@ -84,14 +68,6 @@ func (cmd *Command) prepareFishCommands(commands []*Command, previousCommands [] " -d '%s'", escapeSingleQuotes(command.Usage)) } - - if !command.HideHelp { - completions = append( - completions, - cmd.prepareFishFlags([]Flag{HelpFlag}, command.Names())..., - ) - } - completions = append(completions, completion.String()) completions = append( completions, diff --git a/testdata/expected-fish-full.fish b/testdata/expected-fish-full.fish index 25329b4636..42aee6d188 100644 --- a/testdata/expected-fish-full.fish +++ b/testdata/expected-fish-full.fish @@ -14,24 +14,16 @@ complete -c greet -n '__fish_greet_no_subcommand' -f -l flag -s fl -s f -r complete -c greet -n '__fish_greet_no_subcommand' -f -l another-flag -s b -d 'another usage text' complete -c greet -n '__fish_greet_no_subcommand' -l logfile -r complete -c greet -n '__fish_greet_no_subcommand' -l foofile -r -complete -c greet -n '__fish_greet_no_subcommand' -f -l help -s h -d 'show help' -complete -c greet -n '__fish_greet_no_subcommand' -f -l version -s v -d 'print the version' -complete -c greet -n '__fish_seen_subcommand_from config c' -f -l help -s h -d 'show help' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'config c' -d 'another usage test' complete -c greet -n '__fish_seen_subcommand_from config c' -l flag -s fl -s f -r complete -c greet -n '__fish_seen_subcommand_from config c' -f -l another-flag -s b -d 'another usage text' -complete -c greet -n '__fish_seen_subcommand_from sub-config s ss' -f -l help -s h -d 'show help' complete -x -c greet -n '__fish_seen_subcommand_from config c; and not __fish_seen_subcommand_from sub-config s ss' -a 'sub-config s ss' -d 'another usage test' complete -c greet -n '__fish_seen_subcommand_from sub-config s ss' -f -l sub-flag -s sub-fl -s s -r complete -c greet -n '__fish_seen_subcommand_from sub-config s ss' -f -l sub-command-flag -s s -d 'some usage text' -complete -c greet -n '__fish_seen_subcommand_from info i in' -f -l help -s h -d 'show help' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'info i in' -d 'retrieve generic information' -complete -c greet -n '__fish_seen_subcommand_from some-command' -f -l help -s h -d 'show help' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'some-command' -complete -c greet -n '__fish_seen_subcommand_from usage u' -f -l help -s h -d 'show help' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'usage u' -d 'standard usage text' complete -c greet -n '__fish_seen_subcommand_from usage u' -l flag -s fl -s f -r complete -c greet -n '__fish_seen_subcommand_from usage u' -f -l another-flag -s b -d 'another usage text' -complete -c greet -n '__fish_seen_subcommand_from sub-usage su' -f -l help -s h -d 'show help' complete -x -c greet -n '__fish_seen_subcommand_from usage u; and not __fish_seen_subcommand_from sub-usage su' -a 'sub-usage su' -d 'standard usage text' complete -c greet -n '__fish_seen_subcommand_from sub-usage su' -f -l sub-command-flag -s s -d 'some usage text'