lib: Add cmdline.HideGlobalFlagsExcept() to clean up help.

Closes: veyron/release-issue#1905

---------- Example of new output ----------
$ vrpc
ERROR: vrpc: no command specified

Command vrpc sends and receives Vanadium remote procedure calls.

Usage:
vrpc <command>

The vrpc commands are:
signature   Describe the interfaces of a Vanadium server
call        Call a method of a Vanadium server
identify    Reveal blessings presented by a Vanadium server
help        Display help for commands or topics
Run "vrpc help [command]" for command usage.

Run "vrpc help -style=full" to show all global flags.
----------

This CL shortens the default cmdline usage output, so that you
have a chance at seeing the important parts before it scrolls off
the screen.  The main culprit for long output is our long list of
global flags.

By default, nothing has changed; all global flags are shown in
usage.  Calling cmdline.HideGlobalFlagsExcept() causes the
default behavior to hide global flags, except for the given
regexps.  This mechanism was chosen since it seems better to have
global flags shown if the developer doesn't do anything special,
but if they call the method it's easier to specify a whitelist
than a blacklist.

To show all global flags you use "help -style=full", or set the
envvar CMDLINE_STYLE=full for root commands with no subcommands.
When any global flags are hidden, the usage includes a line
desribing the exact command to run to get the full output.

The -style=godoc output always shows all global flags.

MultiPart: 2/3

Change-Id: I2699a200e11ab948b7a9739a287738288acb1b14
diff --git a/cmdline/cmdline.go b/cmdline/cmdline.go
index cc318be..ede3236 100644
--- a/cmdline/cmdline.go
+++ b/cmdline/cmdline.go
@@ -57,8 +57,11 @@
 	"io"
 	"io/ioutil"
 	"os"
+	"regexp"
 	"strconv"
 	"strings"
+	"unicode"
+	"unicode/utf8"
 
 	"v.io/x/lib/textutil"
 )
@@ -139,39 +142,44 @@
 type style int
 
 const (
-	styleDefault style = iota // Default style, good for cmdline output.
+	styleCompact style = iota // Default style, good for compact cmdline output.
+	styleFull                 // Similar to compact but shows global flags.
 	styleGoDoc                // Style good for godoc processing.
 )
 
 // String returns the human-readable representation of the style.
 func (s *style) String() string {
 	switch *s {
-	case styleDefault:
-		return "default"
+	case styleCompact:
+		return "compact"
+	case styleFull:
+		return "full"
 	case styleGoDoc:
 		return "godoc"
 	default:
-		panic(fmt.Errorf("Unhandled style %d", *s))
+		panic(fmt.Errorf("unhandled style %d", *s))
 	}
 }
 
 // Set implements the flag.Value interface method.
 func (s *style) Set(value string) error {
 	switch value {
-	case "default":
-		*s = styleDefault
+	case "compact":
+		*s = styleCompact
+	case "full":
+		*s = styleFull
 	case "godoc":
 		*s = styleGoDoc
 	default:
-		return fmt.Errorf("Unknown style %q", value)
+		return fmt.Errorf("unknown style %q", value)
 	}
 	return nil
 }
 
 // styleFromEnv returns the style value specified by the CMDLINE_STYLE
-// environment variable, falling back on the default style.
+// environment variable, falling back on styleCompact.
 func styleFromEnv() style {
-	style := styleDefault
+	style := styleCompact
 	style.Set(os.Getenv("CMDLINE_STYLE"))
 	return style
 }
@@ -223,7 +231,7 @@
 	fmt.Fprintln(w, cmd.Long)
 	fmt.Fprintln(w)
 	// Usage line.
-	hasFlags := numFlags(&cmd.Flags) > 0
+	hasFlags := numFlags(&cmd.Flags, nil, true) > 0
 	fmt.Fprintln(w, "Usage:")
 	path := cmd.namePath()
 	pathf := "   " + path
@@ -259,13 +267,13 @@
 		w.SetIndents(spaces(3), spaces(3+nameWidth+1))
 		for _, child := range cmd.Children {
 			// Don't repeatedly list default help command.
-			if !child.isDefaultHelp || firstCall {
+			if firstCall || !child.isDefaultHelp {
 				fmt.Fprintf(w, "%-[1]*[2]s %[3]s", nameWidth, child.Name, child.Short)
 				w.Flush()
 			}
 		}
 		w.SetIndents()
-		if firstCall {
+		if firstCall && style != styleGoDoc {
 			fmt.Fprintf(w, "Run \"%s help [command]\" for command usage.\n", path)
 		}
 	}
@@ -291,7 +299,7 @@
 			w.Flush()
 		}
 		w.SetIndents()
-		if firstCall {
+		if firstCall && style != styleGoDoc {
 			fmt.Fprintf(w, "Run \"%s help [topic]\" for topic details.\n", path)
 		}
 	}
@@ -299,13 +307,41 @@
 	if hasFlags {
 		fmt.Fprintln(w)
 		fmt.Fprintln(w, "The", path, "flags are:")
-		printFlags(w, &cmd.Flags, style)
+		printFlags(w, &cmd.Flags, style, nil, true)
 	}
 	// Global flags.
-	if numFlags(cmd.globalFlags) > 0 && firstCall {
-		fmt.Fprintln(w)
-		fmt.Fprintln(w, "The global flags are:")
-		printFlags(w, cmd.globalFlags, style)
+	hasCompact := numFlags(cmd.globalFlags, compactGlobalFlags, true) > 0
+	hasFull := numFlags(cmd.globalFlags, compactGlobalFlags, false) > 0
+	if firstCall {
+		if style == styleCompact {
+			if hasCompact {
+				fmt.Fprintln(w)
+				fmt.Fprintln(w, "The global flags are:")
+				printFlags(w, cmd.globalFlags, style, compactGlobalFlags, true)
+			}
+			if hasFull {
+				fmt.Fprintln(w)
+				fullhelp := fmt.Sprintf(`Run "%s help -style=full" to show all global flags.`, path)
+				if len(cmd.Children) == 0 {
+					if cmd.parent != nil {
+						fullhelp = fmt.Sprintf(`Run "%s help -style=full %s" to show all global flags.`, cmd.parent.namePath(), cmd.Name)
+					} else {
+						fullhelp = fmt.Sprintf(`Run "CMDLINE_STYLE=full %s -help" to show all global flags.`, path)
+					}
+				}
+				fmt.Fprintln(w, fullhelp)
+			}
+		} else {
+			if hasCompact || hasFull {
+				fmt.Fprintln(w)
+				fmt.Fprintln(w, "The global flags are:")
+				printFlags(w, cmd.globalFlags, style, compactGlobalFlags, true)
+				if hasCompact && hasFull {
+					fmt.Fprintln(w)
+				}
+				printFlags(w, cmd.globalFlags, style, compactGlobalFlags, false)
+			}
+		}
 	}
 }
 
@@ -318,15 +354,20 @@
 	return strings.Join(path, " ")
 }
 
-func numFlags(set *flag.FlagSet) (num int) {
-	set.VisitAll(func(*flag.Flag) {
-		num++
+func numFlags(set *flag.FlagSet, regexps []*regexp.Regexp, match bool) (num int) {
+	set.VisitAll(func(f *flag.Flag) {
+		if match == matchRegexps(regexps, f.Name) {
+			num++
+		}
 	})
 	return
 }
 
-func printFlags(w *textutil.LineWriter, set *flag.FlagSet, style style) {
+func printFlags(w *textutil.LineWriter, set *flag.FlagSet, style style, regexps []*regexp.Regexp, match bool) {
 	set.VisitAll(func(f *flag.Flag) {
+		if match != matchRegexps(regexps, f.Name) {
+			return
+		}
 		value := f.Value.String()
 		if style == styleGoDoc {
 			// When using styleGoDoc we use the default value, so that e.g. regular
@@ -344,6 +385,35 @@
 	return strings.Repeat(" ", count)
 }
 
+func matchRegexps(regexps []*regexp.Regexp, name string) bool {
+	// We distinguish nil regexps from empty regexps; the former means "all names
+	// match", while the latter means "no names match".
+	if regexps == nil {
+		return true
+	}
+	for _, r := range regexps {
+		if r.MatchString(name) {
+			return true
+		}
+	}
+	return false
+}
+
+var compactGlobalFlags []*regexp.Regexp
+
+// HideGlobalFlagsExcept hides global flags from the default compact-style usage
+// message, except for the given regexps.  Global flag names that match any of
+// the regexps will still be shown in the compact usage message.  Multiple calls
+// behave as if all regexps were provided in a single call.
+//
+// All global flags are always shown in non-compact style usage messages.
+func HideGlobalFlagsExcept(regexps ...*regexp.Regexp) {
+	compactGlobalFlags = append(compactGlobalFlags, regexps...)
+	if compactGlobalFlags == nil {
+		compactGlobalFlags = []*regexp.Regexp{}
+	}
+}
+
 // newDefaultHelp creates a new default help command.  We need to create new
 // instances since the parent for each help command is different.
 func newDefaultHelp() *Command {
@@ -358,11 +428,10 @@
 
 "help ..." recursively displays help for all commands and topics.
 
-The output is formatted to a target width in runes.  The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars.  By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
+Output is formatted to a target width in runes, determined by checking the
+CMDLINE_WIDTH environment variable, falling back on the terminal width, falling
+back on 80 chars.  By setting CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0
+the width is unlimited, and if x == 0 or is unset one of the fallbacks is used.
 `,
 		ArgsName: "[command/topic ...]",
 		ArgsLong: `
@@ -376,7 +445,13 @@
 		},
 		isDefaultHelp: true,
 	}
-	help.Flags.Var(&helpStyle, "style", `The formatting style for help output, either "default" or "godoc".`)
+	help.Flags.Var(&helpStyle, "style", `
+The formatting style for help output:
+   compact - Good for compact cmdline output.
+   full    - Good for cmdline output, shows all global flags.
+   godoc   - Good for godoc processing.
+Override the default by setting the CMDLINE_STYLE environment variable.
+`)
 	return help
 }
 
@@ -413,8 +488,7 @@
 func recursiveHelp(w *textutil.LineWriter, cmd *Command, style style, firstCall bool) {
 	if !firstCall {
 		lineBreak(w, style)
-		// Title-case required for godoc to recognize this as a section header.
-		header := strings.Title(cmd.namePath())
+		header := godocSectionHeader(cmd.namePath())
 		fmt.Fprintln(w, header)
 		fmt.Fprintln(w)
 	}
@@ -427,18 +501,27 @@
 	}
 	for _, topic := range cmd.Topics {
 		lineBreak(w, style)
-		// Title-case required for godoc to recognize this as a section header.
-		header := strings.Title(cmd.namePath()+" "+topic.Name) + " - help topic"
+		header := godocSectionHeader(cmd.namePath() + " " + topic.Name + " - help topic")
 		fmt.Fprintln(w, header)
 		fmt.Fprintln(w)
 		fmt.Fprintln(w, topic.Long)
 	}
 }
 
+func godocSectionHeader(s string) string {
+	// The first rune must be uppercase for godoc to recognize the string as a
+	// section header, which is linked to the table of contents.
+	if s == "" {
+		return ""
+	}
+	r, n := utf8.DecodeRuneInString(s)
+	return string(unicode.ToUpper(r)) + s[n:]
+}
+
 func lineBreak(w *textutil.LineWriter, style style) {
 	w.Flush()
 	switch style {
-	case styleDefault:
+	case styleCompact, styleFull:
 		width := w.Width()
 		if width < 0 {
 			// If the user has chosen an "unlimited" word-wrapping width, we still
diff --git a/cmdline/cmdline_test.go b/cmdline/cmdline_test.go
index 44922b7..8f621c3 100644
--- a/cmdline/cmdline_test.go
+++ b/cmdline/cmdline_test.go
@@ -56,6 +56,7 @@
 
 type testCase struct {
 	Args        []string
+	Envs        map[string]string
 	Err         error
 	Stdout      string
 	Stderr      string
@@ -83,10 +84,17 @@
 		flagExtra = false
 		flagTopLevelExtra = false
 		optNoNewline = false
+		origEnvs := make(map[string]string)
 
-		fmt.Fprintf(os.Stderr, "running test %v\n", test.Args)
+		fmt.Fprintf(os.Stderr, "running test %v %v\n", test.Args, test.Envs)
 		os.Args = append([]string{os.Args[0]}, test.Args...)
-		flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.PanicOnError)
+		flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
+		for k, v := range test.Envs {
+			origEnvs[k] = os.Getenv(k)
+			if err := os.Setenv(k, v); err != nil {
+				t.Fatalf("os.Setenv(%v, %v) failed: %v", k, v, err)
+			}
+		}
 
 		var globalFlag1 string
 		flag.StringVar(&globalFlag1, "global1", "", "global test flag 1")
@@ -99,13 +107,13 @@
 			flag.Parse()
 		}
 		if err := cmd.Execute(test.Args); err != test.Err {
-			t.Errorf("Ran with args %q\n GOT error:\n%q\nWANT error:\n%q", test.Args, err, test.Err)
+			t.Errorf("Ran with args %q envs %q\n GOT error:\n%q\nWANT error:\n%q", test.Args, test.Envs, err, test.Err)
 		}
 		if got, want := stripOutput(stdout.String()), test.Stdout; got != want {
-			t.Errorf("Ran with args %q\n GOT stdout:\n%q\nWANT stdout:\n%q", test.Args, got, want)
+			t.Errorf("Ran with args %q envs %q\n GOT stdout:\n%q\nWANT stdout:\n%q", test.Args, test.Envs, got, want)
 		}
 		if got, want := stripOutput(stderr.String()), test.Stderr; got != want {
-			t.Errorf("Ran with args %q\n GOT stderr:\n%q\nWANT stderr:\n%q", test.Args, got, want)
+			t.Errorf("Ran with args %q envs %q\n GOT stderr:\n%q\nWANT stderr:\n%q", test.Args, test.Envs, got, want)
 		}
 		if got, want := globalFlag1, test.GlobalFlag1; got != want {
 			t.Errorf("global1 flag got %q, want %q", got, want)
@@ -113,6 +121,12 @@
 		if got, want := *globalFlag2, test.GlobalFlag2; got != want {
 			t.Errorf("global2 flag got %q, want %q", got, want)
 		}
+
+		for k, v := range origEnvs {
+			if err := os.Setenv(k, v); err != nil {
+				t.Fatalf("os.Setenv(%v, %v) failed: %v", k, v, err)
+			}
+		}
 	}
 }
 
@@ -269,11 +283,10 @@
 
 "help ..." recursively displays help for all commands and topics.
 
-The output is formatted to a target width in runes.  The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars.  By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
+Output is formatted to a target width in runes, determined by checking the
+CMDLINE_WIDTH environment variable, falling back on the terminal width, falling
+back on 80 chars.  By setting CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0
+the width is unlimited, and if x == 0 or is unset one of the fallbacks is used.
 
 Usage:
    onecmd help [flags] [command/topic ...]
@@ -281,8 +294,12 @@
 [command/topic ...] optionally identifies a specific sub-command or help topic.
 
 The onecmd help flags are:
- -style=default
-   The formatting style for help output, either "default" or "godoc".
+ -style=compact
+   The formatting style for help output:
+      compact - Good for compact cmdline output.
+      full    - Good for cmdline output, shows all global flags.
+      godoc   - Good for godoc processing.
+   Override the default by setting the CMDLINE_STYLE environment variable.
 
 The global flags are:
  -global1=
@@ -309,7 +326,7 @@
  -global2=0
    global test flag 2
 ================================================================================
-Onecmd Echo
+Onecmd echo
 
 Echo prints any strings passed in to stdout.
 
@@ -318,7 +335,7 @@
 
 [strings] are arbitrary strings that will be echoed.
 ================================================================================
-Onecmd Help
+Onecmd help
 
 Help with no args displays the usage of the parent command.
 
@@ -326,11 +343,10 @@
 
 "help ..." recursively displays help for all commands and topics.
 
-The output is formatted to a target width in runes.  The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars.  By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
+Output is formatted to a target width in runes, determined by checking the
+CMDLINE_WIDTH environment variable, falling back on the terminal width, falling
+back on 80 chars.  By setting CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0
+the width is unlimited, and if x == 0 or is unset one of the fallbacks is used.
 
 Usage:
    onecmd help [flags] [command/topic ...]
@@ -338,8 +354,12 @@
 [command/topic ...] optionally identifies a specific sub-command or help topic.
 
 The onecmd help flags are:
- -style=default
-   The formatting style for help output, either "default" or "godoc".
+ -style=compact
+   The formatting style for help output:
+      compact - Good for compact cmdline output.
+      full    - Good for cmdline output, shows all global flags.
+      godoc   - Good for godoc processing.
+   Override the default by setting the CMDLINE_STYLE environment variable.
 `,
 		},
 		{
@@ -503,7 +523,7 @@
  -global2=0
    global test flag 2
 ================================================================================
-Multi Echo
+Multi echo
 
 Echo prints any strings passed in to stdout.
 
@@ -512,7 +532,7 @@
 
 [strings] are arbitrary strings that will be echoed.
 ================================================================================
-Multi Echoopt
+Multi echoopt
 
 Echoopt prints any args passed in to stdout.
 
@@ -525,7 +545,7 @@
  -n=false
    Do not output trailing newline
 ================================================================================
-Multi Help
+Multi help
 
 Help with no args displays the usage of the parent command.
 
@@ -533,11 +553,10 @@
 
 "help ..." recursively displays help for all commands and topics.
 
-The output is formatted to a target width in runes.  The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars.  By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
+Output is formatted to a target width in runes, determined by checking the
+CMDLINE_WIDTH environment variable, falling back on the terminal width, falling
+back on 80 chars.  By setting CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0
+the width is unlimited, and if x == 0 or is unset one of the fallbacks is used.
 
 Usage:
    multi help [flags] [command/topic ...]
@@ -545,8 +564,12 @@
 [command/topic ...] optionally identifies a specific sub-command or help topic.
 
 The multi help flags are:
- -style=default
-   The formatting style for help output, either "default" or "godoc".
+ -style=compact
+   The formatting style for help output:
+      compact - Good for compact cmdline output.
+      full    - Good for cmdline output, shows all global flags.
+      godoc   - Good for godoc processing.
+   Override the default by setting the CMDLINE_STYLE environment variable.
 `,
 		},
 		{
@@ -856,7 +879,7 @@
  -global2=0
    global test flag 2
 ================================================================================
-Toplevelprog Echoprog
+Toplevelprog echoprog
 
 Echoprog has two variants of echo.
 
@@ -874,7 +897,7 @@
  -extra=false
    Print an extra arg
 ================================================================================
-Toplevelprog Echoprog Echo
+Toplevelprog echoprog echo
 
 Echo prints any strings passed in to stdout.
 
@@ -883,7 +906,7 @@
 
 [strings] are arbitrary strings that will be echoed.
 ================================================================================
-Toplevelprog Echoprog Echoopt
+Toplevelprog echoprog echoopt
 
 Echoopt prints any args passed in to stdout.
 
@@ -896,11 +919,11 @@
  -n=false
    Do not output trailing newline
 ================================================================================
-Toplevelprog Echoprog Topic3 - help topic
+Toplevelprog echoprog topic3 - help topic
 
 Help topic 3 long.
 ================================================================================
-Toplevelprog Hello
+Toplevelprog hello
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -909,7 +932,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Toplevelprog Help
+Toplevelprog help
 
 Help with no args displays the usage of the parent command.
 
@@ -917,11 +940,10 @@
 
 "help ..." recursively displays help for all commands and topics.
 
-The output is formatted to a target width in runes.  The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars.  By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
+Output is formatted to a target width in runes, determined by checking the
+CMDLINE_WIDTH environment variable, falling back on the terminal width, falling
+back on 80 chars.  By setting CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0
+the width is unlimited, and if x == 0 or is unset one of the fallbacks is used.
 
 Usage:
    toplevelprog help [flags] [command/topic ...]
@@ -929,14 +951,18 @@
 [command/topic ...] optionally identifies a specific sub-command or help topic.
 
 The toplevelprog help flags are:
- -style=default
-   The formatting style for help output, either "default" or "godoc".
+ -style=compact
+   The formatting style for help output:
+      compact - Good for compact cmdline output.
+      full    - Good for cmdline output, shows all global flags.
+      godoc   - Good for godoc processing.
+   Override the default by setting the CMDLINE_STYLE environment variable.
 ================================================================================
-Toplevelprog Topic1 - help topic
+Toplevelprog topic1 - help topic
 
 Help topic 1 long.
 ================================================================================
-Toplevelprog Topic2 - help topic
+Toplevelprog topic2 - help topic
 
 Help topic 2 long.
 `,
@@ -1006,7 +1032,7 @@
  -global2=0
    global test flag 2
 ================================================================================
-Toplevelprog Echoprog Echo
+Toplevelprog echoprog echo
 
 Echo prints any strings passed in to stdout.
 
@@ -1015,7 +1041,7 @@
 
 [strings] are arbitrary strings that will be echoed.
 ================================================================================
-Toplevelprog Echoprog Echoopt
+Toplevelprog echoprog echoopt
 
 Echoopt prints any args passed in to stdout.
 
@@ -1028,7 +1054,7 @@
  -n=false
    Do not output trailing newline
 ================================================================================
-Toplevelprog Echoprog Help
+Toplevelprog echoprog help
 
 Help with no args displays the usage of the parent command.
 
@@ -1036,11 +1062,10 @@
 
 "help ..." recursively displays help for all commands and topics.
 
-The output is formatted to a target width in runes.  The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars.  By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
+Output is formatted to a target width in runes, determined by checking the
+CMDLINE_WIDTH environment variable, falling back on the terminal width, falling
+back on 80 chars.  By setting CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0
+the width is unlimited, and if x == 0 or is unset one of the fallbacks is used.
 
 Usage:
    toplevelprog echoprog help [flags] [command/topic ...]
@@ -1048,10 +1073,14 @@
 [command/topic ...] optionally identifies a specific sub-command or help topic.
 
 The toplevelprog echoprog help flags are:
- -style=default
-   The formatting style for help output, either "default" or "godoc".
+ -style=compact
+   The formatting style for help output:
+      compact - Good for compact cmdline output.
+      full    - Good for cmdline output, shows all global flags.
+      godoc   - Good for godoc processing.
+   Override the default by setting the CMDLINE_STYLE environment variable.
 ================================================================================
-Toplevelprog Echoprog Topic3 - help topic
+Toplevelprog echoprog topic3 - help topic
 
 Help topic 3 long.
 `,
@@ -1379,7 +1408,7 @@
  -global2=0
    global test flag 2
 ================================================================================
-Prog1 Hello11
+Prog1 hello11
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1388,7 +1417,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Hello12
+Prog1 hello12
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1397,7 +1426,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Prog2
+Prog1 prog2
 
 Prog2 has two variants of hello and a subprogram prog3.
 
@@ -1409,7 +1438,7 @@
    prog3       Set of hello commands
    hello22     Print strings on stdout preceded by "Hello"
 ================================================================================
-Prog1 Prog2 Hello21
+Prog1 prog2 hello21
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1418,7 +1447,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Prog2 Prog3
+Prog1 prog2 prog3
 
 Prog3 has two variants of hello.
 
@@ -1429,7 +1458,7 @@
    hello31     Print strings on stdout preceded by "Hello"
    hello32     Print strings on stdout preceded by "Hello"
 ================================================================================
-Prog1 Prog2 Prog3 Hello31
+Prog1 prog2 prog3 hello31
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1438,7 +1467,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Prog2 Prog3 Hello32
+Prog1 prog2 prog3 hello32
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1447,7 +1476,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Prog2 Hello22
+Prog1 prog2 hello22
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1456,7 +1485,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Help
+Prog1 help
 
 Help with no args displays the usage of the parent command.
 
@@ -1464,11 +1493,10 @@
 
 "help ..." recursively displays help for all commands and topics.
 
-The output is formatted to a target width in runes.  The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars.  By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
+Output is formatted to a target width in runes, determined by checking the
+CMDLINE_WIDTH environment variable, falling back on the terminal width, falling
+back on 80 chars.  By setting CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0
+the width is unlimited, and if x == 0 or is unset one of the fallbacks is used.
 
 Usage:
    prog1 help [flags] [command/topic ...]
@@ -1476,8 +1504,12 @@
 [command/topic ...] optionally identifies a specific sub-command or help topic.
 
 The prog1 help flags are:
- -style=default
-   The formatting style for help output, either "default" or "godoc".
+ -style=compact
+   The formatting style for help output:
+      compact - Good for compact cmdline output.
+      full    - Good for cmdline output, shows all global flags.
+      godoc   - Good for godoc processing.
+   Override the default by setting the CMDLINE_STYLE environment variable.
 `,
 		},
 		{
@@ -1500,7 +1532,7 @@
  -global2=0
    global test flag 2
 ================================================================================
-Prog1 Prog2 Hello21
+Prog1 prog2 hello21
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1509,7 +1541,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Prog2 Prog3
+Prog1 prog2 prog3
 
 Prog3 has two variants of hello.
 
@@ -1520,7 +1552,7 @@
    hello31     Print strings on stdout preceded by "Hello"
    hello32     Print strings on stdout preceded by "Hello"
 ================================================================================
-Prog1 Prog2 Prog3 Hello31
+Prog1 prog2 prog3 hello31
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1529,7 +1561,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Prog2 Prog3 Hello32
+Prog1 prog2 prog3 hello32
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1538,7 +1570,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Prog2 Hello22
+Prog1 prog2 hello22
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1547,7 +1579,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Prog2 Help
+Prog1 prog2 help
 
 Help with no args displays the usage of the parent command.
 
@@ -1555,11 +1587,10 @@
 
 "help ..." recursively displays help for all commands and topics.
 
-The output is formatted to a target width in runes.  The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars.  By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
+Output is formatted to a target width in runes, determined by checking the
+CMDLINE_WIDTH environment variable, falling back on the terminal width, falling
+back on 80 chars.  By setting CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0
+the width is unlimited, and if x == 0 or is unset one of the fallbacks is used.
 
 Usage:
    prog1 prog2 help [flags] [command/topic ...]
@@ -1567,8 +1598,12 @@
 [command/topic ...] optionally identifies a specific sub-command or help topic.
 
 The prog1 prog2 help flags are:
- -style=default
-   The formatting style for help output, either "default" or "godoc".
+ -style=compact
+   The formatting style for help output:
+      compact - Good for compact cmdline output.
+      full    - Good for cmdline output, shows all global flags.
+      godoc   - Good for godoc processing.
+   Override the default by setting the CMDLINE_STYLE environment variable.
 `,
 		},
 		{
@@ -1590,7 +1625,7 @@
  -global2=0
    global test flag 2
 ================================================================================
-Prog1 Prog2 Prog3 Hello31
+Prog1 prog2 prog3 hello31
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1599,7 +1634,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Prog2 Prog3 Hello32
+Prog1 prog2 prog3 hello32
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1608,7 +1643,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Prog2 Prog3 Help
+Prog1 prog2 prog3 help
 
 Help with no args displays the usage of the parent command.
 
@@ -1616,11 +1651,10 @@
 
 "help ..." recursively displays help for all commands and topics.
 
-The output is formatted to a target width in runes.  The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars.  By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
+Output is formatted to a target width in runes, determined by checking the
+CMDLINE_WIDTH environment variable, falling back on the terminal width, falling
+back on 80 chars.  By setting CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0
+the width is unlimited, and if x == 0 or is unset one of the fallbacks is used.
 
 Usage:
    prog1 prog2 prog3 help [flags] [command/topic ...]
@@ -1628,8 +1662,12 @@
 [command/topic ...] optionally identifies a specific sub-command or help topic.
 
 The prog1 prog2 prog3 help flags are:
- -style=default
-   The formatting style for help output, either "default" or "godoc".
+ -style=compact
+   The formatting style for help output:
+      compact - Good for compact cmdline output.
+      full    - Good for cmdline output, shows all global flags.
+      godoc   - Good for godoc processing.
+   Override the default by setting the CMDLINE_STYLE environment variable.
 `,
 		},
 		{
@@ -1651,7 +1689,7 @@
  -global2=0
    global test flag 2
 ================================================================================
-Prog1 Prog2 Prog3 Hello31
+Prog1 prog2 prog3 hello31
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1660,7 +1698,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Prog2 Prog3 Hello32
+Prog1 prog2 prog3 hello32
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1669,7 +1707,7 @@
 
 [strings] are arbitrary strings that will be printed.
 ================================================================================
-Prog1 Prog2 Prog3 Help
+Prog1 prog2 prog3 help
 
 Help with no args displays the usage of the parent command.
 
@@ -1677,11 +1715,10 @@
 
 "help ..." recursively displays help for all commands and topics.
 
-The output is formatted to a target width in runes.  The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars.  By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
+Output is formatted to a target width in runes, determined by checking the
+CMDLINE_WIDTH environment variable, falling back on the terminal width, falling
+back on 80 chars.  By setting CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0
+the width is unlimited, and if x == 0 or is unset one of the fallbacks is used.
 
 Usage:
    prog1 prog2 prog3 help [flags] [command/topic ...]
@@ -1689,8 +1726,12 @@
 [command/topic ...] optionally identifies a specific sub-command or help topic.
 
 The prog1 prog2 prog3 help flags are:
- -style=default
-   The formatting style for help output, either "default" or "godoc".
+ -style=compact
+   The formatting style for help output:
+      compact - Good for compact cmdline output.
+      full    - Good for cmdline output, shows all global flags.
+      godoc   - Good for godoc processing.
+   Override the default by setting the CMDLINE_STYLE environment variable.
 `,
 		},
 		{
@@ -1705,7 +1746,6 @@
    hello12     Print strings on stdout preceded by "Hello"
    prog2       Set of hello commands
    help        Display help for commands or topics
-Run "prog1 help [command]" for command usage.
 
 The global flags are:
  -global1=
@@ -1713,7 +1753,7 @@
  -global2=0
    global test flag 2
 
-Prog1 Hello11
+Prog1 hello11
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1722,7 +1762,7 @@
 
 [strings] are arbitrary strings that will be printed.
 
-Prog1 Hello12
+Prog1 hello12
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1731,7 +1771,7 @@
 
 [strings] are arbitrary strings that will be printed.
 
-Prog1 Prog2
+Prog1 prog2
 
 Prog2 has two variants of hello and a subprogram prog3.
 
@@ -1743,7 +1783,7 @@
    prog3       Set of hello commands
    hello22     Print strings on stdout preceded by "Hello"
 
-Prog1 Prog2 Hello21
+Prog1 prog2 hello21
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1752,7 +1792,7 @@
 
 [strings] are arbitrary strings that will be printed.
 
-Prog1 Prog2 Prog3
+Prog1 prog2 prog3
 
 Prog3 has two variants of hello.
 
@@ -1763,7 +1803,7 @@
    hello31     Print strings on stdout preceded by "Hello"
    hello32     Print strings on stdout preceded by "Hello"
 
-Prog1 Prog2 Prog3 Hello31
+Prog1 prog2 prog3 hello31
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1772,7 +1812,7 @@
 
 [strings] are arbitrary strings that will be printed.
 
-Prog1 Prog2 Prog3 Hello32
+Prog1 prog2 prog3 hello32
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1781,7 +1821,7 @@
 
 [strings] are arbitrary strings that will be printed.
 
-Prog1 Prog2 Hello22
+Prog1 prog2 hello22
 
 Hello prints any strings passed in to stdout preceded by "Hello".
 
@@ -1790,7 +1830,7 @@
 
 [strings] are arbitrary strings that will be printed.
 
-Prog1 Help
+Prog1 help
 
 Help with no args displays the usage of the parent command.
 
@@ -1798,11 +1838,10 @@
 
 "help ..." recursively displays help for all commands and topics.
 
-The output is formatted to a target width in runes.  The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars.  By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
+Output is formatted to a target width in runes, determined by checking the
+CMDLINE_WIDTH environment variable, falling back on the terminal width, falling
+back on 80 chars.  By setting CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0
+the width is unlimited, and if x == 0 or is unset one of the fallbacks is used.
 
 Usage:
    prog1 help [flags] [command/topic ...]
@@ -1810,8 +1849,12 @@
 [command/topic ...] optionally identifies a specific sub-command or help topic.
 
 The prog1 help flags are:
- -style=default
-   The formatting style for help output, either "default" or "godoc".
+ -style=compact
+   The formatting style for help output:
+      compact - Good for compact cmdline output.
+      full    - Good for cmdline output, shows all global flags.
+      godoc   - Good for godoc processing.
+   Override the default by setting the CMDLINE_STYLE environment variable.
 `,
 		},
 	}
@@ -1909,7 +1952,7 @@
  -global2=0
    global test flag 2
 ================================================================================
-Cmdargs Echo
+Cmdargs echo
 
 Echo prints any strings passed in to stdout.
 
@@ -1918,7 +1961,7 @@
 
 [strings] are arbitrary strings that will be echoed.
 ================================================================================
-Cmdargs Help
+Cmdargs help
 
 Help with no args displays the usage of the parent command.
 
@@ -1926,11 +1969,10 @@
 
 "help ..." recursively displays help for all commands and topics.
 
-The output is formatted to a target width in runes.  The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars.  By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
+Output is formatted to a target width in runes, determined by checking the
+CMDLINE_WIDTH environment variable, falling back on the terminal width, falling
+back on 80 chars.  By setting CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0
+the width is unlimited, and if x == 0 or is unset one of the fallbacks is used.
 
 Usage:
    cmdargs help [flags] [command/topic ...]
@@ -1938,8 +1980,12 @@
 [command/topic ...] optionally identifies a specific sub-command or help topic.
 
 The cmdargs help flags are:
- -style=default
-   The formatting style for help output, either "default" or "godoc".
+ -style=compact
+   The formatting style for help output:
+      compact - Good for compact cmdline output.
+      full    - Good for cmdline output, shows all global flags.
+      godoc   - Good for godoc processing.
+   Override the default by setting the CMDLINE_STYLE environment variable.
 `,
 		},
 		{
@@ -2101,7 +2147,7 @@
  -global2=0
    global test flag 2
 ================================================================================
-Cmdrun Echo
+Cmdrun echo
 
 Echo prints any strings passed in to stdout.
 
@@ -2110,7 +2156,7 @@
 
 [strings] are arbitrary strings that will be echoed.
 ================================================================================
-Cmdrun Help
+Cmdrun help
 
 Help with no args displays the usage of the parent command.
 
@@ -2118,11 +2164,10 @@
 
 "help ..." recursively displays help for all commands and topics.
 
-The output is formatted to a target width in runes.  The target width is
-determined by checking the environment variable CMDLINE_WIDTH, falling back on
-the terminal width from the OS, falling back on 80 chars.  By setting
-CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0 the width is unlimited, and
-if x == 0 or is unset one of the fallbacks is used.
+Output is formatted to a target width in runes, determined by checking the
+CMDLINE_WIDTH environment variable, falling back on the terminal width, falling
+back on 80 chars.  By setting CMDLINE_WIDTH=x, if x > 0 the width is x, if x < 0
+the width is unlimited, and if x == 0 or is unset one of the fallbacks is used.
 
 Usage:
    cmdrun help [flags] [command/topic ...]
@@ -2130,8 +2175,12 @@
 [command/topic ...] optionally identifies a specific sub-command or help topic.
 
 The cmdrun help flags are:
- -style=default
-   The formatting style for help output, either "default" or "godoc".
+ -style=compact
+   The formatting style for help output:
+      compact - Good for compact cmdline output.
+      full    - Good for cmdline output, shows all global flags.
+      godoc   - Good for godoc processing.
+   Override the default by setting the CMDLINE_STYLE environment variable.
 `,
 		},
 		{
@@ -2188,7 +2237,7 @@
 	runTestCases(t, prog, tests)
 }
 
-func TestLongCommandsHelp(t *testing.T) {
+func TestLongCommands(t *testing.T) {
 	cmdLong := &Command{
 		Name:  "thisisaverylongcommand",
 		Short: "the short description of the very long command is very long, and will have to be wrapped",
@@ -2247,3 +2296,135 @@
 	}
 	runTestCases(t, prog, tests)
 }
+
+func TestHideGlobalFlags(t *testing.T) {
+	HideGlobalFlagsExcept(regexp.MustCompile(`^global2$`))
+	cmdChild := &Command{
+		Name:  "child",
+		Short: "description of child command.",
+		Long:  "blah blah blah",
+		Run:   runEcho,
+	}
+	prog := &Command{
+		Name:     "program",
+		Short:    "Test hiding global flags.",
+		Long:     "Test hiding global flags.",
+		Children: []*Command{cmdChild},
+	}
+	var tests = []testCase{
+		{
+			Args: []string{"help"},
+			Stdout: `Test hiding global flags.
+
+Usage:
+   program <command>
+
+The program commands are:
+   child       description of child command.
+   help        Display help for commands or topics
+Run "program help [command]" for command usage.
+
+The global flags are:
+ -global2=0
+   global test flag 2
+
+Run "program help -style=full" to show all global flags.
+`,
+		},
+		{
+			Args: []string{"help", "child"},
+			Stdout: `blah blah blah
+
+Usage:
+   program child
+
+The global flags are:
+ -global2=0
+   global test flag 2
+
+Run "program help -style=full child" to show all global flags.
+`,
+		},
+		{
+			Args: []string{"help", "-style=full"},
+			Stdout: `Test hiding global flags.
+
+Usage:
+   program <command>
+
+The program commands are:
+   child       description of child command.
+   help        Display help for commands or topics
+Run "program help [command]" for command usage.
+
+The global flags are:
+ -global2=0
+   global test flag 2
+
+ -global1=
+   global test flag 1
+`,
+		},
+		{
+			Args: []string{"help", "-style=full", "child"},
+			Stdout: `blah blah blah
+
+Usage:
+   program child
+
+The global flags are:
+ -global2=0
+   global test flag 2
+
+ -global1=
+   global test flag 1
+`,
+		},
+	}
+	runTestCases(t, prog, tests)
+	compactGlobalFlags = nil
+}
+
+func TestHideGlobalFlagsRootNoChildren(t *testing.T) {
+	HideGlobalFlagsExcept(regexp.MustCompile(`^global2$`))
+	prog := &Command{
+		Name:  "program",
+		Short: "Test hiding global flags, root no children.",
+		Long:  "Test hiding global flags, root no children.",
+		Run:   runEcho,
+	}
+	var tests = []testCase{
+		{
+			Args: []string{"-help"},
+			Stdout: `Test hiding global flags, root no children.
+
+Usage:
+   program
+
+The global flags are:
+ -global2=0
+   global test flag 2
+
+Run "CMDLINE_STYLE=full program -help" to show all global flags.
+`,
+		},
+		{
+			Args: []string{"-help"},
+			Envs: map[string]string{"CMDLINE_STYLE": "full"},
+			Stdout: `Test hiding global flags, root no children.
+
+Usage:
+   program
+
+The global flags are:
+ -global2=0
+   global test flag 2
+
+ -global1=
+   global test flag 1
+`,
+		},
+	}
+	runTestCases(t, prog, tests)
+	compactGlobalFlags = nil
+}