diff --git a/custom_completions_test.go b/custom_completions_test.go index 66b3e6384..276b8a77b 100644 --- a/custom_completions_test.go +++ b/custom_completions_test.go @@ -1407,39 +1407,6 @@ func TestCompleteCmdInBashScript(t *testing.T) { check(t, output, ShellCompNoDescRequestCmd) } -func TestCompleteNoDesCmdInFishScript(t *testing.T) { - rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} - child := &Command{ - Use: "child", - ValidArgsFunction: validArgsFunc, - Run: emptyRun, - } - rootCmd.AddCommand(child) - - buf := new(bytes.Buffer) - rootCmd.GenFishCompletion(buf, false) - output := buf.String() - - check(t, output, ShellCompNoDescRequestCmd) -} - -func TestCompleteCmdInFishScript(t *testing.T) { - rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} - child := &Command{ - Use: "child", - ValidArgsFunction: validArgsFunc, - Run: emptyRun, - } - rootCmd.AddCommand(child) - - buf := new(bytes.Buffer) - rootCmd.GenFishCompletion(buf, true) - output := buf.String() - - check(t, output, ShellCompRequestCmd) - checkOmit(t, output, ShellCompNoDescRequestCmd) -} - func TestCompleteNoDesCmdInZshScript(t *testing.T) { rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} child := &Command{ diff --git a/fish_completions.go b/fish_completions.go index 52b89c6e3..66a6357cb 100644 --- a/fish_completions.go +++ b/fish_completions.go @@ -5,9 +5,15 @@ import ( "fmt" "io" "os" + "strings" ) func genFishComp(buf *bytes.Buffer, name string, includeDesc bool) { + // Variables should not contain a '-' or ':' character + nameForVar := name + nameForVar = strings.Replace(nameForVar, "-", "_", -1) + nameForVar = strings.Replace(nameForVar, ":", "_", -1) + compCmd := ShellCompRequestCmd if !includeDesc { compCmd = ShellCompNoDescRequestCmd @@ -38,12 +44,12 @@ function __%[1]s_perform_completion __%[1]s_debug "emptyArg: $emptyArg" if not type -q "$args[1]" - # This can happen when "complete --do-complete %[1]s" is called when running this script. + # This can happen when "complete --do-complete %[2]s" is called when running this script. __%[1]s_debug "Cannot find $args[1]. No completions." return end - set requestComp "$args[1] %[2]s $args[2..-1] $emptyArg" + set requestComp "$args[1] %[3]s $args[2..-1] $emptyArg" __%[1]s_debug "Calling $requestComp" set results (eval $requestComp 2> /dev/null) @@ -99,11 +105,11 @@ function __%[1]s_prepare_completions __%[1]s_debug "Completions are: $__%[1]s_comp_results" __%[1]s_debug "Directive is: $directive" - set shellCompDirectiveError %[3]d - set shellCompDirectiveNoSpace %[4]d - set shellCompDirectiveNoFileComp %[5]d - set shellCompDirectiveFilterFileExt %[6]d - set shellCompDirectiveFilterDirs %[7]d + set shellCompDirectiveError %[4]d + set shellCompDirectiveNoSpace %[5]d + set shellCompDirectiveNoFileComp %[6]d + set shellCompDirectiveFilterFileExt %[7]d + set shellCompDirectiveFilterDirs %[8]d if test -z "$directive" set directive 0 @@ -158,24 +164,24 @@ end # so we can properly delete any completions provided by another script. # The space after the the program name is essential to trigger completion for the program # and not completion of the program name itself. -complete --do-complete "%[1]s " &> /dev/null +complete --do-complete "%[2]s " &> /dev/null # Remove any pre-existing completions for the program since we will be handling all of them. -complete -c %[1]s -e +complete -c %[2]s -e # The order in which the below two lines are defined is very important so that __%[1]s_prepare_completions # is called first. It is __%[1]s_prepare_completions that sets up the __%[1]s_comp_do_file_comp variable. # # This completion will be run second as complete commands are added FILO. # It triggers file completion choices when __%[1]s_comp_do_file_comp is set. -complete -c %[1]s -n 'set --query __%[1]s_comp_do_file_comp' +complete -c %[2]s -n 'set --query __%[1]s_comp_do_file_comp' # This completion will be run first as complete commands are added FILO. -# The call to __%[1]s_prepare_completions will setup both __%[1]s_comp_results abd __%[1]s_comp_do_file_comp. +# The call to __%[1]s_prepare_completions will setup both __%[1]s_comp_results and __%[1]s_comp_do_file_comp. # It provides the program's completion choices. -complete -c %[1]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results' +complete -c %[2]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results' -`, name, compCmd, +`, nameForVar, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs)) } diff --git a/fish_completions_test.go b/fish_completions_test.go new file mode 100644 index 000000000..532b6055a --- /dev/null +++ b/fish_completions_test.go @@ -0,0 +1,69 @@ +package cobra + +import ( + "bytes" + "testing" +) + +func TestCompleteNoDesCmdInFishScript(t *testing.T) { + rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} + child := &Command{ + Use: "child", + ValidArgsFunction: validArgsFunc, + Run: emptyRun, + } + rootCmd.AddCommand(child) + + buf := new(bytes.Buffer) + rootCmd.GenFishCompletion(buf, false) + output := buf.String() + + check(t, output, ShellCompNoDescRequestCmd) +} + +func TestCompleteCmdInFishScript(t *testing.T) { + rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} + child := &Command{ + Use: "child", + ValidArgsFunction: validArgsFunc, + Run: emptyRun, + } + rootCmd.AddCommand(child) + + buf := new(bytes.Buffer) + rootCmd.GenFishCompletion(buf, true) + output := buf.String() + + check(t, output, ShellCompRequestCmd) + checkOmit(t, output, ShellCompNoDescRequestCmd) +} + +func TestProgWithDash(t *testing.T) { + rootCmd := &Command{Use: "root-dash", Args: NoArgs, Run: emptyRun} + buf := new(bytes.Buffer) + rootCmd.GenFishCompletion(buf, false) + output := buf.String() + + // Functions name should have replace the '-' + check(t, output, "__root_dash_perform_completion") + checkOmit(t, output, "__root-dash_perform_completion") + + // The command name should not have replaced the '-' + check(t, output, "-c root-dash") + checkOmit(t, output, "-c root_dash") +} + +func TestProgWithColon(t *testing.T) { + rootCmd := &Command{Use: "root:colon", Args: NoArgs, Run: emptyRun} + buf := new(bytes.Buffer) + rootCmd.GenFishCompletion(buf, false) + output := buf.String() + + // Functions name should have replace the ':' + check(t, output, "__root_colon_perform_completion") + checkOmit(t, output, "__root:colon_perform_completion") + + // The command name should not have replaced the ':' + check(t, output, "-c root:colon") + checkOmit(t, output, "-c root_colon") +}