Repository: spf13/cobra
Pull request #126 (2015-08-09 05:26:18)

Add new BashCompSubdirsInDir annotation
This first `cd` to a specified directory, then
lists the subdirectories therein with `_filedir -d`.

This can be used by e.g. `hugo --theme=[Tab][Tab]`, which would
give a list of subdirectories under the `themes` directory.
See Pull Request spf13/hugo#1343 for more information.

anthonyfok: Thank you very much for the code review and feedback!
Indeed the use of `pushd` and `popd` is much more robust solution!
Thanks for the great tip!
I will make the changes and push it again right away.
eparis: should have said this already.  so sorry.  But can you please write something in bash_completions_test.go which at least trys to make sure the correct bash is getting written out?
eparis: (yes, I realize most of the tests are poor, but at least get a minimum of testing there)

Patch:
diff --git a/bash_completions.go b/bash_completions.go
index 3a421bc..82c4274 100644
--- a/bash_completions.go
+++ b/bash_completions.go
@@ -13,6 +13,7 @@ import (
 const (
 	BashCompFilenameExt     = "cobra_annotation_bash_completion_filename_extentions"
 	BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag"
+	BashCompSubdirsInDir    = "cobra_annotation_bash_completion_subdirs_in_dir"
 )
 
 func preamble(out *bytes.Buffer) {
@@ -100,6 +101,12 @@ __handle_filename_extension_flag()
     _filedir "@(${ext})"
 }
 
+__handle_subdirs_in_dir_flag()
+{
+    local dir="$1"
+    pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1
+}
+
 __handle_flag()
 {
     __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}"
@@ -226,6 +233,16 @@ func writeFlagHandler(name string, annotations map[string][]string, out *bytes.B
 				ext := "_filedir"
 				fmt.Fprintf(out, "    flags_completion+=(%q)\n", ext)
 			}
+		case BashCompSubdirsInDir:
+			fmt.Fprintf(out, "    flags_with_completion+=(%q)\n", name)
+
+			if len(value) == 1 {
+				ext := "__handle_subdirs_in_dir_flag " + value[0]
+				fmt.Fprintf(out, "    flags_completion+=(%q)\n", ext)
+			} else {
+				ext := "_filedir -d"
+				fmt.Fprintf(out, "    flags_completion+=(%q)\n", ext)
+			}
 		}
 	}
 }


Test patch:
diff --git a/bash_completions_test.go b/bash_completions_test.go
index acb6d81..a1f2b13 100644
--- a/bash_completions_test.go
+++ b/bash_completions_test.go
@@ -56,6 +56,11 @@ func TestBashCompletions(t *testing.T) {
 	c.Flags().StringVar(&flagvalExt, "filename-ext", "", "Enter a filename (extension limited)")
 	c.MarkFlagFilename("filename-ext")
 
+	// subdirectories in a given directory
+	var flagvalTheme string
+	c.Flags().StringVar(&flagvalTheme, "theme", "", "theme to use (located in /themes/THEMENAME/)")
+	c.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"})
+
 	out := new(bytes.Buffer)
 	c.GenBashCompletion(out)
 	str := out.String()
@@ -75,6 +80,8 @@ func TestBashCompletions(t *testing.T) {
 	check(t, str, `flags_completion+=("_filedir")`)
 	// check for filename extension flags
 	check(t, str, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`)
+	// check for subdirs_in_dir flags
+	check(t, str, `flags_completion+=("__handle_subdirs_in_dir_flag themes")`)
 
 	checkOmit(t, str, cmdDeprecated.Name())
 }