Repository: spf13/cobra (go)

Issue:
Completions do not suggest sub-commands if there are ValidArgs
When a command has both `ValidArgs` and sub-commands, the completion script only proposes the `ValidArgs`.  Cobra should do also propose non-hidden sub-commands in the completions list.

I cannot see a reason not to do this...

This was brought up in https://github.com/spf13/cobra/pull/1035#issuecomment-605511493

To illustrate, in the program below, the `rootCmd` specifies `ValidArgs` of `rs` and `ds`, but also has a sub-command `pod`.  The bash completion script will only propose the values of `ValidArgs` and not the sub-commands when both are present.  In this case `testprog [tab][tab]` will not suggest `pod` because there are `ValidArgs`.

Program to reproduce: 
```
package main

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
	ValidArgs: []string{/*"pod",*/ "rs", "ds"},
	Args:      cobra.ExactArgs(1),
	Use:       "testprog1",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("rootCmd called")
	},
}

var childCmd = &cobra.Command{
	Use: "pod",
	ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.BashCompDirective) {
		return []string{"these", "are", "custom", "completions"}, cobra.BashCompDirectiveDefault
	},
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("child called")
	},
}

var childCmd2 = &cobra.Command{
	Use: "svc",
	ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.BashCompDirective) {
		return []string{"second", "level"}, cobra.BashCompDirectiveDefault
	},
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("child called")
	},
}

var completionCmd = &cobra.Command{
	Use: "completion",
	Run: func(cmd *cobra.Command, args []string) {
		cmd.Root().GenBashCompletion(os.Stdout)
	},
}

func main() {
	rootCmd.AddCommand(childCmd)
	rootCmd.AddCommand(completionCmd)
	childCmd.AddCommand(childCmd2)
	rootCmd.Execute()
}
```

Pull request:
Make bash completion provide sub-command names even if ValidArgs present
Fixes #1076 

This PR makes bash completion also provide sub-command names when `ValidArgs` or `ValidArgsFunction` are specified.

Here are details about the completions given:

Cobra's **Bash** completion:
Original (before custom Go completions of PR #1035):
- `ValidArgs` XOR `sub-commands` (which means it gives `ValidArgs` and if there are none, then it gives `sub-commands`)

Current:
- `ValidArgs` XOR `ValidArgsFunction` XOR `sub-commands`

With this PR:
- (`ValidArgs` AND  `sub-commands`) XOR (`ValidArgsFunction` AND `sub-commands`)

For info, Cobra's **Zsh** completion does it yet another way:
- `sub-commands` XOR `ValidArgs`

Which which should align eventually.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..742d6d6
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,22 @@
+# Cobra Changelog
+
+## Pending
+* Fix man page doc generation - no auto generated tag when `cmd.DisableAutoGenTag = true` @jpmcb
+
+## v1.0.0
+Announcing v1.0.0 of Cobra. 🎉
+**Notable Changes**
+* Fish completion (including support for Go custom completion) @marckhouzam
+* API (urgent): Rename BashCompDirectives to ShellCompDirectives @marckhouzam
+* Remove/replace SetOutput on Command - deprecated @jpmcb
+* add support for autolabel stale PR @xchapter7x
+* Add Labeler Actions @xchapter7x
+* Custom completions coded in Go (instead of Bash) @marckhouzam
+* Partial Revert of #922 @jharshman
+* Add Makefile to project @jharshman
+* Correct documentation for InOrStdin @desponda
+* Apply formatting to templates @jharshman
+* Revert change so help is printed on stdout again @marckhouzam
+* Update md2man to v2.0.0 @pdf
+* update viper to v1.4.0 @umarcor
+* Update cmd/root.go example in README.md @jharshman
diff --git a/README.md b/README.md
index 9d79934..a932dd7 100644
--- a/README.md
+++ b/README.md
@@ -2,31 +2,9 @@
 
 Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files.
 
-Many of the most widely used Go projects are built using Cobra, such as:
-[Kubernetes](http://kubernetes.io/),
-[Hugo](http://gohugo.io),
-[rkt](https://github.com/coreos/rkt),
-[etcd](https://github.com/coreos/etcd),
-[Moby (former Docker)](https://github.com/moby/moby),
-[Docker (distribution)](https://github.com/docker/distribution),
-[OpenShift](https://www.openshift.com/),
-[Delve](https://github.com/derekparker/delve),
-[GopherJS](http://www.gopherjs.org/),
-[CockroachDB](http://www.cockroachlabs.com/),
-[Bleve](http://www.blevesearch.com/),
-[ProjectAtomic (enterprise)](http://www.projectatomic.io/),
-[Giant Swarm's gsctl](https://github.com/giantswarm/gsctl),
-[Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack),
-[rclone](http://rclone.org/),
-[nehm](https://github.com/bogem/nehm),
-[Pouch](https://github.com/alibaba/pouch),
-[Istio](https://istio.io),
-[Prototool](https://github.com/uber/prototool),
-[mattermost-server](https://github.com/mattermost/mattermost-server),
-[Gardener](https://github.com/gardener/gardenctl),
-[Linkerd](https://linkerd.io/),
-[Github CLI](https://github.com/cli/cli)
-etc.
+Cobra is used in many Go projects such as [Kubernetes](http://kubernetes.io/),
+[Hugo](https://gohugo.io), and [Github CLI](https://github.com/cli/cli) to
+name a few. [This list](./projects_using_cobra.md) contains a more extensive list of projects using Cobra.
 
 [![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra)
 [![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra)
@@ -740,11 +718,7 @@ Run 'kubectl help' for usage.
 
 ## Generating documentation for your command
 
-Cobra can generate documentation based on subcommands, flags, etc. in the following formats:
-
-- [Markdown](doc/md_docs.md)
-- [ReStructured Text](doc/rest_docs.md)
-- [Man Page](doc/man_docs.md)
+Cobra can generate documentation based on subcommands, flags, etc. Read more about it in the [docs generation documentation](doc/README.md).
 
 ## Generating bash completions
 
diff --git a/args.go b/args.go
index c4d820b..70e9b26 100644
--- a/args.go
+++ b/args.go
@@ -2,6 +2,7 @@ package cobra
 
 import (
 	"fmt"
+	"strings"
 )
 
 type PositionalArgs func(cmd *Command, args []string) error
@@ -34,8 +35,15 @@ func NoArgs(cmd *Command, args []string) error {
 // OnlyValidArgs returns an error if any args are not in the list of ValidArgs.
 func OnlyValidArgs(cmd *Command, args []string) error {
 	if len(cmd.ValidArgs) > 0 {
+		// Remove any description that may be included in ValidArgs.
+		// A description is following a tab character.
+		var validArgs []string
+		for _, v := range cmd.ValidArgs {
+			validArgs = append(validArgs, strings.Split(v, "\t")[0])
+		}
+
 		for _, v := range args {
-			if !stringInSlice(v, cmd.ValidArgs) {
+			if !stringInSlice(v, validArgs) {
 				return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0]))
 			}
 		}
diff --git a/bash_completions.go b/bash_completions.go
index b4098f4..d8341cc 100644
--- a/bash_completions.go
+++ b/bash_completions.go
@@ -181,10 +181,9 @@ __%[1]s_handle_reply()
     local completions
     completions=("${commands[@]}")
     if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then
-        completions=("${must_have_one_noun[@]}")
+        completions+=("${must_have_one_noun[@]}")
     elif [[ -n "${has_completion_function}" ]]; then
         # if a go completion function is provided, defer to that function
-        completions=()
         __%[1]s_handle_go_custom_completion
     fi
     if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then
@@ -344,7 +343,7 @@ __%[1]s_handle_word()
     __%[1]s_handle_word
 }
 
-`, name, ShellCompRequestCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp))
+`, name, ShellCompNoDescRequestCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp))
 }
 
 func writePostscript(buf *bytes.Buffer, name string) {
@@ -548,6 +547,9 @@ func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) {
 	buf.WriteString("    must_have_one_noun=()\n")
 	sort.Sort(sort.StringSlice(cmd.ValidArgs))
 	for _, value := range cmd.ValidArgs {
+		// Remove any description that may be included following a tab character.
+		// Descriptions are not supported by bash completion.
+		value = strings.Split(value, "\t")[0]
 		buf.WriteString(fmt.Sprintf("    must_have_one_noun+=(%q)\n", value))
 	}
 	if cmd.ValidArgsFunction != nil {
diff --git a/bash_completions.md b/bash_completions.md
index e1590e1..e61a3a6 100644
--- a/bash_completions.md
+++ b/bash_completions.md
@@ -115,6 +115,8 @@ in this example again instead of the replication controllers.
 
 In some cases it is not possible to provide a list of possible completions in advance.  Instead, the list of completions must be determined at execution-time.  Cobra provides two ways of defining such dynamic completion of nouns. Note that both these methods can be used along-side each other as long as they are not both used for the same command.
 
+**Note**: *Custom Completions written in Go* will automatically work for other shell-completion scripts (e.g., Fish shell), while *Custom Completions written in Bash* will only work for Bash shell-completion.  It is therefore recommended to use *Custom Completions written in Go*.
+
 #### 1. Custom completions of nouns written in Go
 
 In a similar fashion as for static completions, you can use the `ValidArgsFunction` field to provide a Go function that Cobra will execute when it needs the list of completion choices for the nouns of a command.  Note that either `ValidArgs` or `ValidArgsFunction` can be used for a single cobra command, but not both.
@@ -301,6 +303,8 @@ So while there are many other files in the CWD it only shows me subdirs and thos
 
 As for nouns, Cobra provides two ways of defining dynamic completion of flags.  Note that both these methods can be used along-side each other as long as they are not both used for the same flag.
 
+**Note**: *Custom Completions written in Go* will automatically work for other shell-completion scripts (e.g., Fish shell), while *Custom Completions written in Bash* will only work for Bash shell-completion.  It is therefore recommended to use *Custom Completions written in Go*.
+
 ## 1. Custom completions of flags written in Go
 
 To provide a Go function that Cobra will execute when it needs the list of completion choices for a flag, you must register the function in the following manner:
diff --git a/cobra/README.md b/cobra/README.md
index c360fda..0f718c2 100644
--- a/cobra/README.md
+++ b/cobra/README.md
@@ -88,12 +88,17 @@ author: Steve Francia <spf@spf13.com>
 license: MIT
 ```
 
+You can also use built-in licenses. For example, **GPLv2**, **GPLv3**, **LGPL**,
+**AGPL**, **MIT**, **2-Clause BSD** or **3-Clause BSD**.
+
 You can specify no license by setting `license` to `none` or you can specify
 a custom license:
 
 ```yaml
+author: Steve Francia <spf@spf13.com>
+year: 2020
 license:
-  header: This file is part of {{ .appName }}.
+  header: This file is part of CLI application foo.
   text: |
     {{ .copyright }}
 
@@ -102,5 +107,23 @@ license:
     master my life.
 ```
 
-You can also use built-in licenses. For example, **GPLv2**, **GPLv3**, **LGPL**,
-**AGPL**, **MIT**, **2-Clause BSD** or **3-Clause BSD**.
+In the above custom license configuration the `copyright` line in the License
+text is generated from the `author` and `year` properties. The content of the
+`LICENSE` file is
+
+```
+Copyright © 2020 Steve Francia <spf@spf13.com>
+
+This is my license. There are many like it, but this one is mine.
+My license is my best friend. It is my life. I must master it as I must
+master my life.
+```
+
+The `header` property is used as the license header files. No interpolation is
+done. This is the example of the go file header.
+```
+/*
+Copyright © 2020 Steve Francia <spf@spf13.com>
+This file is part of CLI application foo.
+*/
+```
diff --git a/cobra/cmd/init.go b/cobra/cmd/init.go
index dcf5ada..504a478 100644
--- a/cobra/cmd/init.go
+++ b/cobra/cmd/init.go
@@ -32,42 +32,17 @@ var (
 		Long: `Initialize (cobra init) will create a new application, with a license
 and the appropriate structure for a Cobra-based CLI application.
 
-  * If a name is provided, it will be created in the current directory;
+  * If a name is provided, a directory with that name will be created in the current directory;
   * If no name is provided, the current directory will be assumed;
-  * If a relative path is provided, it will be created inside $GOPATH
-    (e.g. github.com/spf13/hugo);
-  * If an absolute path is provided, it will be created;
-  * If the directory already exists but is empty, it will be used.
+`,
 
-Init will not use an existing directory with contents.`,
+		Run: func(_ *cobra.Command, args []string) {
 
-		Run: func(cmd *cobra.Command, args []string) {
-
-			wd, err := os.Getwd()
+			projectPath, err := initializeProject(args)
 			if err != nil {
 				er(err)
 			}
-
-			if len(args) > 0 {
-				if args[0] != "." {
-					wd = fmt.Sprintf("%s/%s", wd, args[0])
-				}
-			}
-
-			project := &Project{
-				AbsolutePath: wd,
-				PkgName:      pkgName,
-				Legal:        getLicense(),
-				Copyright:    copyrightLine(),
-				Viper:        viper.GetBool("useViper"),
-				AppName:      path.Base(pkgName),
-			}
-
-			if err := project.Create(); err != nil {
-				er(err)
-			}
-
-			fmt.Printf("Your Cobra applicaton is ready at\n%s\n", project.AbsolutePath)
+			fmt.Printf("Your Cobra application is ready at\n%s\n", projectPath)
 		},
 	}
 )
@@ -76,3 +51,31 @@ func init() {
 	initCmd.Flags().StringVar(&pkgName, "pkg-name", "", "fully qualified pkg name")
 	initCmd.MarkFlagRequired("pkg-name")
 }
+
+func initializeProject(args []string) (string, error) {
+	wd, err := os.Getwd()
+	if err != nil {
+		return "", err
+	}
+
+	if len(args) > 0 {
+		if args[0] != "." {
+			wd = fmt.Sprintf("%s/%s", wd, args[0])
+		}
+	}
+
+	project := &Project{
+		AbsolutePath: wd,
+		PkgName:      pkgName,
+		Legal:        getLicense(),
+		Copyright:    copyrightLine(),
+		Viper:        viper.GetBool("useViper"),
+		AppName:      path.Base(pkgName),
+	}
+
+	if err := project.Create(); err != nil {
+		return "", err
+	}
+
+	return project.AbsolutePath, nil
+}
diff --git a/custom_completions.go b/custom_completions.go
index 81f1bc3..ba57327 100644
--- a/custom_completions.go
+++ b/custom_completions.go
@@ -9,9 +9,14 @@ import (
 	"github.com/spf13/pflag"
 )
 
-// ShellCompRequestCmd is the name of the hidden command that is used to request
-// completion results from the program.  It is used by the shell completion script.
-const ShellCompRequestCmd = "__complete"
+const (
+	// ShellCompRequestCmd is the name of the hidden command that is used to request
+	// completion results from the program.  It is used by the shell completion scripts.
+	ShellCompRequestCmd = "__complete"
+	// ShellCompNoDescRequestCmd is the name of the hidden command that is used to request
+	// completion results without their description.  It is used by the shell completion scripts.
+	ShellCompNoDescRequestCmd = "__completeNoDesc"
+)
 
 // Global map of flag completion functions.
 var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){}
@@ -77,6 +82,7 @@ func (d ShellCompDirective) string() string {
 func (c *Command) initCompleteCmd(args []string) {
 	completeCmd := &Command{
 		Use:                   fmt.Sprintf("%s [command-line]", ShellCompRequestCmd),
+		Aliases:               []string{ShellCompNoDescRequestCmd},
 		DisableFlagsInUseLine: true,
 		Hidden:                true,
 		DisableFlagParsing:    true,
@@ -93,7 +99,12 @@ func (c *Command) initCompleteCmd(args []string) {
 				// 2- Even without completions, we need to print the directive
 			}
 
+			noDescriptions := (cmd.CalledAs() == ShellCompNoDescRequestCmd)
 			for _, comp := range completions {
+				if noDescriptions {
+					// Remove any description that may be included following a tab character.
+					comp = strings.Split(comp, "\t")[0]
+				}
 				// Print each possible completion to stdout for the completion script to consume.
 				fmt.Fprintln(finalCmd.OutOrStdout(), comp)
 			}
@@ -139,6 +150,27 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
 		return c, completions, ShellCompDirectiveDefault, fmt.Errorf("Unable to find a command for arguments: %v", trimmedArgs)
 	}
 
+	// When doing completion of a flag name, as soon as an argument starts with
+	// a '-' we know it is a flag.  We cannot use isFlagArg() here as it requires
+	// the flag to be complete
+	if len(toComplete) > 0 && toComplete[0] == '-' && !strings.Contains(toComplete, "=") {
+		// We are completing a flag name
+		finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) {
+			completions = append(completions, getFlagNameCompletions(flag, toComplete)...)
+		})
+		finalCmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) {
+			completions = append(completions, getFlagNameCompletions(flag, toComplete)...)
+		})
+
+		directive := ShellCompDirectiveDefault
+		if len(completions) > 0 {
+			if strings.HasSuffix(completions[0], "=") {
+				directive = ShellCompDirectiveNoSpace
+			}
+		}
+		return finalCmd, completions, directive, nil
+	}
+
 	var flag *pflag.Flag
 	if !finalCmd.DisableFlagParsing {
 		// We only do flag completion if we are allowed to parse flags
@@ -150,6 +182,33 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
 		}
 	}
 
+	if flag == nil {
+		// Complete subcommand names
+		for _, subCmd := range finalCmd.Commands() {
+			if subCmd.IsAvailableCommand() && strings.HasPrefix(subCmd.Name(), toComplete) {
+				completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
+			}
+		}
+
+		if len(finalCmd.ValidArgs) > 0 {
+			// Always complete ValidArgs, even if we are completing a subcommand name.
+			// This is for commands that have both subcommands and ValidArgs.
+			for _, validArg := range finalCmd.ValidArgs {
+				if strings.HasPrefix(validArg, toComplete) {
+					completions = append(completions, validArg)
+				}
+			}
+
+			// If there are ValidArgs specified (even if they don't match), we stop completion.
+			// Only one of ValidArgs or ValidArgsFunction can be used for a single command.
+			return finalCmd, completions, ShellCompDirectiveNoFileComp, nil
+		}
+
+		// Always let the logic continue so as to add any ValidArgsFunction completions,
+		// even if we already found sub-commands.
+		// This is for commands that have subcommands but also specify a ValidArgsFunction.
+	}
+
 	// Parse the flags and extract the arguments to prepare for calling the completion function
 	if err = finalCmd.ParseFlags(finalArgs); err != nil {
 		return finalCmd, completions, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error())
@@ -179,6 +238,32 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
 	return finalCmd, completions, directive, nil
 }
 
+func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string {
+	if nonCompletableFlag(flag) {
+		return []string{}
+	}
+
+	var completions []string
+	flagName := "--" + flag.Name
+	if strings.HasPrefix(flagName, toComplete) {
+		// Flag without the =
+		completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
+
+		if len(flag.NoOptDefVal) == 0 {
+			// Flag requires a value, so it can be suffixed with =
+			flagName += "="
+			completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
+		}
+	}
+
+	flagName = "-" + flag.Shorthand
+	if len(flag.Shorthand) > 0 && strings.HasPrefix(flagName, toComplete) {
+		completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
+	}
+
+	return completions
+}
+
 func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*pflag.Flag, []string, string, error) {
 	var flagName string
 	trimmedArgs := args
diff --git a/doc/README.md b/doc/README.md
new file mode 100644
index 0000000..6ea4eb6
--- /dev/null
+++ b/doc/README.md
@@ -0,0 +1,12 @@
+# Documentation generation
+
+- [Man page docs](./man_docs.md)
+- [Markdown docs](./md_docs.md)
+- [Rest docs](./rest_docs.md)
+- [Yaml docs](./yaml_docs.md)
+
+## Options
+### `DisableAutoGenTag`
+You may set `cmd.DisableAutoGenTag = true`
+to _entirely_ remove the auto generated string "Auto generated by spf13/cobra..."
+from any documentation source.
diff --git a/doc/man_docs.go b/doc/man_docs.go
index 8c7fba4..b29a677 100644
--- a/doc/man_docs.go
+++ b/doc/man_docs.go
@@ -105,7 +105,7 @@ func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error {
 	if header == nil {
 		header = &GenManHeader{}
 	}
-	if err := fillHeader(header, cmd.CommandPath()); err != nil {
+	if err := fillHeader(header, cmd.CommandPath(), cmd.DisableAutoGenTag); err != nil {
 		return err
 	}
 
@@ -114,7 +114,7 @@ func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error {
 	return err
 }
 
-func fillHeader(header *GenManHeader, name string) error {
+func fillHeader(header *GenManHeader, name string, disableAutoGen bool) error {
 	if header.Title == "" {
 		header.Title = strings.ToUpper(strings.Replace(name, " ", "\\-", -1))
 	}
@@ -133,7 +133,7 @@ func fillHeader(header *GenManHeader, name string) error {
 		header.Date = &now
 	}
 	header.date = (*header.Date).Format("Jan 2006")
-	if header.Source == "" {
+	if header.Source == "" && !disableAutoGen {
 		header.Source = "Auto generated by spf13/cobra"
 	}
 	return nil
diff --git a/fish_completions.go b/fish_completions.go
new file mode 100644
index 0000000..c83609c
--- /dev/null
+++ b/fish_completions.go
@@ -0,0 +1,172 @@
+package cobra
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+)
+
+func genFishComp(buf *bytes.Buffer, name string, includeDesc bool) {
+	compCmd := ShellCompRequestCmd
+	if !includeDesc {
+		compCmd = ShellCompNoDescRequestCmd
+	}
+	buf.WriteString(fmt.Sprintf("# fish completion for %-36s -*- shell-script -*-\n", name))
+	buf.WriteString(fmt.Sprintf(`
+function __%[1]s_debug
+    set file "$BASH_COMP_DEBUG_FILE"
+    if test -n "$file"
+        echo "$argv" >> $file
+    end
+end
+
+function __%[1]s_perform_completion
+    __%[1]s_debug "Starting __%[1]s_perform_completion with: $argv"
+
+    set args (string split -- " " "$argv")
+    set lastArg "$args[-1]"
+
+    __%[1]s_debug "args: $args"
+    __%[1]s_debug "last arg: $lastArg"
+
+    set emptyArg ""
+    if test -z "$lastArg"
+        __%[1]s_debug "Setting emptyArg"
+        set emptyArg \"\"
+    end
+    __%[1]s_debug "emptyArg: $emptyArg"
+
+    set requestComp "$args[1] %[2]s $args[2..-1] $emptyArg"
+    __%[1]s_debug "Calling $requestComp"
+
+    set results (eval $requestComp 2> /dev/null)
+    set comps $results[1..-2]
+    set directiveLine $results[-1]
+
+    # For Fish, when completing a flag with an = (e.g., <program> -n=<TAB>)
+    # completions must be prefixed with the flag
+    set flagPrefix (string match -r -- '-.*=' "$lastArg")
+
+    __%[1]s_debug "Comps: $comps"
+    __%[1]s_debug "DirectiveLine: $directiveLine"
+    __%[1]s_debug "flagPrefix: $flagPrefix"
+
+    for comp in $comps
+        printf "%%s%%s\n" "$flagPrefix" "$comp"
+    end
+
+    printf "%%s\n" "$directiveLine"
+end
+
+# This function does three things:
+# 1- Obtain the completions and store them in the global __%[1]s_comp_results
+# 2- Set the __%[1]s_comp_do_file_comp flag if file completion should be performed
+#    and unset it otherwise
+# 3- Return true if the completion results are not empty
+function __%[1]s_prepare_completions
+    # Start fresh
+    set --erase __%[1]s_comp_do_file_comp
+    set --erase __%[1]s_comp_results
+
+    # Check if the command-line is already provided.  This is useful for testing.
+    if not set --query __%[1]s_comp_commandLine
+        set __%[1]s_comp_commandLine (commandline)
+    end
+    __%[1]s_debug "commandLine is: $__%[1]s_comp_commandLine"
+
+    set results (__%[1]s_perform_completion "$__%[1]s_comp_commandLine")
+    set --erase __%[1]s_comp_commandLine
+    __%[1]s_debug "Completion results: $results"
+
+    if test -z "$results"
+        __%[1]s_debug "No completion, probably due to a failure"
+        # Might as well do file completion, in case it helps
+        set --global __%[1]s_comp_do_file_comp 1
+        return 0
+    end
+
+    set directive (string sub --start 2 $results[-1])
+    set --global __%[1]s_comp_results $results[1..-2]
+
+    __%[1]s_debug "Completions are: $__%[1]s_comp_results"
+    __%[1]s_debug "Directive is: $directive"
+
+    if test -z "$directive"
+        set directive 0
+    end
+
+    set compErr (math (math --scale 0 $directive / %[3]d) %% 2)
+    if test $compErr -eq 1
+        __%[1]s_debug "Received error directive: aborting."
+        # Might as well do file completion, in case it helps
+        set --global __%[1]s_comp_do_file_comp 1
+        return 0
+    end
+
+    set nospace (math (math --scale 0 $directive / %[4]d) %% 2)
+    set nofiles (math (math --scale 0 $directive / %[5]d) %% 2)
+
+    __%[1]s_debug "nospace: $nospace, nofiles: $nofiles"
+
+    # Important not to quote the variable for count to work
+    set numComps (count $__%[1]s_comp_results)
+    __%[1]s_debug "numComps: $numComps"
+
+    if test $numComps -eq 1; and test $nospace -ne 0
+        # To support the "nospace" directive we trick the shell
+        # by outputting an extra, longer completion.
+        __%[1]s_debug "Adding second completion to perform nospace directive"
+        set --append __%[1]s_comp_results $__%[1]s_comp_results[1].
+    end
+
+    if test $numComps -eq 0; and test $nofiles -eq 0
+        __%[1]s_debug "Requesting file completion"
+        set --global __%[1]s_comp_do_file_comp 1
+    end
+
+    # If we don't want file completion, we must return true even if there
+    # are no completions found.  This is because fish will perform the last
+    # completion command, even if its condition is false, if no other
+    # completion command was triggered
+    return (not set --query __%[1]s_comp_do_file_comp)
+end
+
+# Remove any pre-existing completions for the program since we will be handling all of them
+# TODO this cleanup is not sufficient.  Fish completions are only loaded once the user triggers
+# them, so the below deletion will not work as it is run too early.  What else can we do?
+complete -c %[1]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'
+
+# 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.
+# It provides the program's completion choices.
+complete -c %[1]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results'
+
+`, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp))
+}
+
+// GenFishCompletion generates fish completion file and writes to the passed writer.
+func (c *Command) GenFishCompletion(w io.Writer, includeDesc bool) error {
+	buf := new(bytes.Buffer)
+	genFishComp(buf, c.Name(), includeDesc)
+	_, err := buf.WriteTo(w)
+	return err
+}
+
+// GenFishCompletionFile generates fish completion file.
+func (c *Command) GenFishCompletionFile(filename string, includeDesc bool) error {
+	outFile, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer outFile.Close()
+
+	return c.GenFishCompletion(outFile, includeDesc)
+}
diff --git a/fish_completions.md b/fish_completions.md
new file mode 100644
index 0000000..6bfe5f8
--- /dev/null
+++ b/fish_completions.md
@@ -0,0 +1,7 @@
+## Generating Fish Completions for your own cobra.Command
+
+Cobra supports native Fish completions generated from the root `cobra.Command`.  You can use the `command.GenFishCompletion()` or `command.GenFishCompletionFile()` functions. You must provide these functions with a parameter indicating if the completions should be annotated with a description; Cobra will provide the description automatically based on usage information.  You can choose to make this option configurable by your users.
+
+### Limitations
+
+* Custom completions implemented using the `ValidArgsFunction` and `RegisterFlagCompletionFunc()` are supported automatically but the ones implemented in Bash scripting are not.
diff --git a/projects_using_cobra.md b/projects_using_cobra.md
new file mode 100644
index 0000000..aa79107
--- /dev/null
+++ b/projects_using_cobra.md
@@ -0,0 +1,26 @@
+## Projects using Cobra
+
+- [Bleve](http://www.blevesearch.com/)
+- [CockroachDB](http://www.cockroachlabs.com/)
+- [Delve](https://github.com/derekparker/delve)
+- [Docker (distribution)](https://github.com/docker/distribution)
+- [Gardener](https://github.com/gardener/gardenctl)
+- [Giant Swarm's gsctl](https://github.com/giantswarm/gsctl)
+- [Github CLI](https://github.com/cli/cli)
+- [GopherJS](http://www.gopherjs.org/)
+- [Helm](https://helm.sh)
+- [Hugo](https://gohugo.io)
+- [Istio](https://istio.io)
+- [Kubernetes](http://kubernetes.io/)
+- [Linkerd](https://linkerd.io/)
+- [Mattermost-server](https://github.com/mattermost/mattermost-server)
+- [Moby (former Docker)](https://github.com/moby/moby)
+- [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack)
+- [OpenShift](https://www.openshift.com/)
+- [Pouch](https://github.com/alibaba/pouch)
+- [ProjectAtomic (enterprise)](http://www.projectatomic.io/)
+- [Prototool](https://github.com/uber/prototool)
+- [Rclone](https://rclone.org/)
+- [etcd](https://github.com/coreos/etcd)
+- [nehm](https://github.com/bogem/nehm)
+- [rkt](https://github.com/coreos/rkt)


Test patch:
diff --git a/cobra/cmd/init_test.go b/cobra/cmd/init_test.go
index 8ee3910..c4b3f09 100644
--- a/cobra/cmd/init_test.go
+++ b/cobra/cmd/init_test.go
@@ -2,9 +2,12 @@ package cmd
 
 import (
 	"fmt"
+	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
+
+	"github.com/spf13/viper"
 )
 
 func getProject() *Project {
@@ -20,20 +23,72 @@ func getProject() *Project {
 }
 
 func TestGoldenInitCmd(t *testing.T) {
-	project := getProject()
-	defer os.RemoveAll(project.AbsolutePath)
 
-	if err := project.Create(); err != nil {
+	dir, err := ioutil.TempDir("", "cobra-init")
+	if err != nil {
 		t.Fatal(err)
 	}
+	defer os.RemoveAll(dir)
+
+	tests := []struct {
+		name      string
+		args      []string
+		pkgName   string
+		expectErr bool
+	}{
+		{
+			name:      "successfully creates a project with name",
+			args:      []string{"testproject"},
+			pkgName:   "github.com/spf13/testproject",
+			expectErr: false,
+		},
+		{
+			name:      "returns error when passing an absolute path for project",
+			args:      []string{dir},
+			pkgName:   "github.com/spf13/testproject",
+			expectErr: true,
+		},
+		{
+			name:      "returns error when passing an relative path for project",
+			args:      []string{"github.com/spf13/testproject"},
+			pkgName:   "github.com/spf13/testproject",
+			expectErr: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+
+			initCmd.Flags().Set("pkg-name", tt.pkgName)
+			viper.Set("useViper", true)
+			projectPath, err := initializeProject(tt.args)
+			defer func() {
+				if projectPath != "" {
+					os.RemoveAll(projectPath)
+				}
+			}()
+
+			if !tt.expectErr && err != nil {
+				t.Fatalf("did not expect an error, got %s", err)
+			}
+			if tt.expectErr {
+				if err == nil {
+					t.Fatal("expected an error but got none")
+				} else {
+					// got an expected error nothing more to do
+					return
+				}
+			}
 
-	expectedFiles := []string{"LICENSE", "main.go", "cmd/root.go"}
-	for _, f := range expectedFiles {
-		generatedFile := fmt.Sprintf("%s/%s", project.AbsolutePath, f)
-		goldenFile := fmt.Sprintf("testdata/%s.golden", filepath.Base(f))
-		err := compareFiles(generatedFile, goldenFile)
-		if err != nil {
-			t.Fatal(err)
-		}
+			expectedFiles := []string{"LICENSE", "main.go", "cmd/root.go"}
+			for _, f := range expectedFiles {
+				generatedFile := fmt.Sprintf("%s/%s", projectPath, f)
+				goldenFile := fmt.Sprintf("testdata/%s.golden", filepath.Base(f))
+				err := compareFiles(generatedFile, goldenFile)
+				if err != nil {
+					t.Fatal(err)
+				}
+			}
+		})
 	}
 }
diff --git a/custom_completions_test.go b/custom_completions_test.go
index ea6a6d9..8615483 100644
--- a/custom_completions_test.go
+++ b/custom_completions_test.go
@@ -12,7 +12,7 @@ func validArgsFunc(cmd *Command, args []string, toComplete string) ([]string, Sh
 	}
 
 	var completions []string
-	for _, comp := range []string{"one", "two"} {
+	for _, comp := range []string{"one\tThe first", "two\tThe second"} {
 		if strings.HasPrefix(comp, toComplete) {
 			completions = append(completions, comp)
 		}
@@ -26,7 +26,7 @@ func validArgsFunc2(cmd *Command, args []string, toComplete string) ([]string, S
 	}
 
 	var completions []string
-	for _, comp := range []string{"three", "four"} {
+	for _, comp := range []string{"three\tThe third", "four\tThe fourth"} {
 		if strings.HasPrefix(comp, toComplete) {
 			completions = append(completions, comp)
 		}
@@ -42,7 +42,7 @@ func TestValidArgsFuncSingleCmd(t *testing.T) {
 	}
 
 	// Test completing an empty string
-	output, err := executeCommand(rootCmd, ShellCompRequestCmd, "")
+	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -58,7 +58,7 @@ func TestValidArgsFuncSingleCmd(t *testing.T) {
 	}
 
 	// Check completing with a prefix
-	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "t")
+	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -86,7 +86,7 @@ func TestValidArgsFuncSingleCmdInvalidArg(t *testing.T) {
 	}
 
 	// Check completing with wrong number of args
-	output, err := executeCommand(rootCmd, ShellCompRequestCmd, "unexpectedArg", "t")
+	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "unexpectedArg", "t")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -115,7 +115,7 @@ func TestValidArgsFuncChildCmds(t *testing.T) {
 	rootCmd.AddCommand(child1Cmd, child2Cmd)
 
 	// Test completion of first sub-command with empty argument
-	output, err := executeCommand(rootCmd, ShellCompRequestCmd, "child1", "")
+	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -131,7 +131,7 @@ func TestValidArgsFuncChildCmds(t *testing.T) {
 	}
 
 	// Test completion of first sub-command with a prefix to complete
-	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child1", "t")
+	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "t")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -146,7 +146,7 @@ func TestValidArgsFuncChildCmds(t *testing.T) {
 	}
 
 	// Check completing with wrong number of args
-	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child1", "unexpectedArg", "t")
+	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "unexpectedArg", "t")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -160,7 +160,7 @@ func TestValidArgsFuncChildCmds(t *testing.T) {
 	}
 
 	// Test completion of second sub-command with empty argument
-	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "")
+	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -175,7 +175,7 @@ func TestValidArgsFuncChildCmds(t *testing.T) {
 		t.Errorf("expected: %q, got: %q", expected, output)
 	}
 
-	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "t")
+	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "t")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -190,7 +190,7 @@ func TestValidArgsFuncChildCmds(t *testing.T) {
 	}
 
 	// Check completing with wrong number of args
-	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "unexpectedArg", "t")
+	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "unexpectedArg", "t")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -215,7 +215,7 @@ func TestValidArgsFuncAliases(t *testing.T) {
 	rootCmd.AddCommand(child)
 
 	// Test completion of first sub-command with empty argument
-	output, err := executeCommand(rootCmd, ShellCompRequestCmd, "son", "")
+	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "son", "")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -231,7 +231,7 @@ func TestValidArgsFuncAliases(t *testing.T) {
 	}
 
 	// Test completion of first sub-command with a prefix to complete
-	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "daughter", "t")
+	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "daughter", "t")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -246,7 +246,7 @@ func TestValidArgsFuncAliases(t *testing.T) {
 	}
 
 	// Check completing with wrong number of args
-	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "son", "unexpectedArg", "t")
+	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "son", "unexpectedArg", "t")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -260,7 +260,7 @@ func TestValidArgsFuncAliases(t *testing.T) {
 	}
 }
 
-func TestValidArgsFuncInScript(t *testing.T) {
+func TestValidArgsFuncInBashScript(t *testing.T) {
 	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
 	child := &Command{
 		Use:               "child",
@@ -276,7 +276,7 @@ func TestValidArgsFuncInScript(t *testing.T) {
 	check(t, output, "has_completion_function=1")
 }
 
-func TestNoValidArgsFuncInScript(t *testing.T) {
+func TestNoValidArgsFuncInBashScript(t *testing.T) {
 	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
 	child := &Command{
 		Use: "child",
@@ -291,6 +291,55 @@ func TestNoValidArgsFuncInScript(t *testing.T) {
 	checkOmit(t, output, "has_completion_function=1")
 }
 
+func TestCompleteCmdInBashScript(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.GenBashCompletion(buf)
+	output := buf.String()
+
+	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 TestFlagCompletionInGo(t *testing.T) {
 	rootCmd := &Command{
 		Use: "root",
@@ -299,7 +348,7 @@ func TestFlagCompletionInGo(t *testing.T) {
 	rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot")
 	rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
 		completions := []string{}
-		for _, comp := range []string{"1", "2", "10"} {
+		for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} {
 			if strings.HasPrefix(comp, toComplete) {
 				completions = append(completions, comp)
 			}
@@ -309,7 +358,7 @@ func TestFlagCompletionInGo(t *testing.T) {
 	rootCmd.Flags().String("filename", "", "Enter a filename")
 	rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
 		completions := []string{}
-		for _, comp := range []string{"file.yaml", "myfile.json", "file.xml"} {
+		for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} {
 			if strings.HasPrefix(comp, toComplete) {
 				completions = append(completions, comp)
 			}
@@ -318,7 +367,7 @@ func TestFlagCompletionInGo(t *testing.T) {
 	})
 
 	// Test completing an empty string
-	output, err := executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "")
+	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--introot", "")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -335,7 +384,7 @@ func TestFlagCompletionInGo(t *testing.T) {
 	}
 
 	// Check completing with a prefix
-	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "1")
+	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--introot", "1")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -351,7 +400,7 @@ func TestFlagCompletionInGo(t *testing.T) {
 	}
 
 	// Test completing an empty string
-	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--filename", "")
+	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--filename", "")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -368,7 +417,7 @@ func TestFlagCompletionInGo(t *testing.T) {
 	}
 
 	// Check completing with a prefix
-	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--filename", "f")
+	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--filename", "f")
 	if err != nil {
 		t.Errorf("Unexpected error: %v", err)
 	}
@@ -383,3 +432,200 @@ func TestFlagCompletionInGo(t *testing.T) {
 		t.Errorf("expected: %q, got: %q", expected, output)
 	}
 }
+
+func TestValidArgsFuncChildCmdsWithDesc(t *testing.T) {
+	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
+	child1Cmd := &Command{
+		Use:               "child1",
+		ValidArgsFunction: validArgsFunc,
+		Run:               emptyRun,
+	}
+	child2Cmd := &Command{
+		Use:               "child2",
+		ValidArgsFunction: validArgsFunc2,
+		Run:               emptyRun,
+	}
+	rootCmd.AddCommand(child1Cmd, child2Cmd)
+
+	// Test completion of first sub-command with empty argument
+	output, err := executeCommand(rootCmd, ShellCompRequestCmd, "child1", "")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	expected := strings.Join([]string{
+		"one\tThe first",
+		"two\tThe second",
+		":0",
+		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
+
+	if output != expected {
+		t.Errorf("expected: %q, got: %q", expected, output)
+	}
+
+	// Test completion of first sub-command with a prefix to complete
+	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child1", "t")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	expected = strings.Join([]string{
+		"two\tThe second",
+		":0",
+		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
+
+	if output != expected {
+		t.Errorf("expected: %q, got: %q", expected, output)
+	}
+
+	// Check completing with wrong number of args
+	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child1", "unexpectedArg", "t")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	expected = strings.Join([]string{
+		":4",
+		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
+
+	if output != expected {
+		t.Errorf("expected: %q, got: %q", expected, output)
+	}
+
+	// Test completion of second sub-command with empty argument
+	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	expected = strings.Join([]string{
+		"three\tThe third",
+		"four\tThe fourth",
+		":0",
+		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
+
+	if output != expected {
+		t.Errorf("expected: %q, got: %q", expected, output)
+	}
+
+	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "t")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	expected = strings.Join([]string{
+		"three\tThe third",
+		":0",
+		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
+
+	if output != expected {
+		t.Errorf("expected: %q, got: %q", expected, output)
+	}
+
+	// Check completing with wrong number of args
+	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "unexpectedArg", "t")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	expected = strings.Join([]string{
+		":4",
+		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
+
+	if output != expected {
+		t.Errorf("expected: %q, got: %q", expected, output)
+	}
+}
+
+func TestFlagCompletionInGoWithDesc(t *testing.T) {
+	rootCmd := &Command{
+		Use: "root",
+		Run: emptyRun,
+	}
+	rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot")
+	rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
+		completions := []string{}
+		for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} {
+			if strings.HasPrefix(comp, toComplete) {
+				completions = append(completions, comp)
+			}
+		}
+		return completions, ShellCompDirectiveDefault
+	})
+	rootCmd.Flags().String("filename", "", "Enter a filename")
+	rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
+		completions := []string{}
+		for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} {
+			if strings.HasPrefix(comp, toComplete) {
+				completions = append(completions, comp)
+			}
+		}
+		return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp
+	})
+
+	// Test completing an empty string
+	output, err := executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	expected := strings.Join([]string{
+		"1\tThe first",
+		"2\tThe second",
+		"10\tThe tenth",
+		":0",
+		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
+
+	if output != expected {
+		t.Errorf("expected: %q, got: %q", expected, output)
+	}
+
+	// Check completing with a prefix
+	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "1")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	expected = strings.Join([]string{
+		"1\tThe first",
+		"10\tThe tenth",
+		":0",
+		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
+
+	if output != expected {
+		t.Errorf("expected: %q, got: %q", expected, output)
+	}
+
+	// Test completing an empty string
+	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--filename", "")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	expected = strings.Join([]string{
+		"file.yaml\tYAML format",
+		"myfile.json\tJSON format",
+		"file.xml\tXML format",
+		":6",
+		"Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n")
+
+	if output != expected {
+		t.Errorf("expected: %q, got: %q", expected, output)
+	}
+
+	// Check completing with a prefix
+	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--filename", "f")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	expected = strings.Join([]string{
+		"file.yaml\tYAML format",
+		"file.xml\tXML format",
+		":6",
+		"Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n")
+
+	if output != expected {
+		t.Errorf("expected: %q, got: %q", expected, output)
+	}
+}
diff --git a/doc/man_docs_test.go b/doc/man_docs_test.go
index 2c400f5..ee9b875 100644
--- a/doc/man_docs_test.go
+++ b/doc/man_docs_test.go
@@ -101,6 +101,8 @@ func TestGenManNoGenTag(t *testing.T) {
 
 	unexpected := translate("#HISTORY")
 	checkStringOmits(t, output, unexpected)
+	unexpected = translate("Auto generated by spf13/cobra")
+	checkStringOmits(t, output, unexpected)
 }
 
 func TestGenManSeeAlso(t *testing.T) {