From 4ee88d1f4917d3355380e8f32800e4f143731e13 Mon Sep 17 00:00:00 2001 From: Vui Lam Date: Sun, 5 May 2024 22:51:23 -0700 Subject: [PATCH] Align example lines with rest of usage output Now that multi-line Example values do not need explicit indent to have them shown left-aligned in usage, update usage to ensure there is at least a designated amount of indent for each non-empty line, so as to match up with the rest of the usage sections. Also correct for some specific situations where the explicit indent of subsequent lines is still present in the Example value by making the output for such value left aligned as well. Signed-off-by: Vui Lam --- plugin/usage.go | 52 +++++++++++++++-- plugin/usage_test.go | 129 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 167 insertions(+), 14 deletions(-) diff --git a/plugin/usage.go b/plugin/usage.go index 6c638543..91269457 100644 --- a/plugin/usage.go +++ b/plugin/usage.go @@ -276,6 +276,52 @@ func aliasesWithMappedName(cmd *cobra.Command) string { return strings.Join(append([]string{cmdName}, cmd.Aliases...), ", ") } +// ensure that the example string is left indented by the designated amount +func alignExampleForUsage(exampleString string) string { + var result string + + // always indent single line by designated amount + if !strings.Contains(strings.TrimSpace(exampleString), "\n") { + result = indentStr + strings.TrimLeft(exampleString, " ") + return result + } + + var hasUnexpectedIndent bool + lines := strings.Split(exampleString, "\n") + numLines := len(lines) + + for i := 1; i < numLines; i++ { + if lines[i] == "" { + continue + } + if strings.HasPrefix(lines[i], indentStr) && !strings.HasPrefix(lines[i], indentStr+" ") { + continue + } + hasUnexpectedIndent = true + break + } + + if !hasUnexpectedIndent { + // A special case identified where all or all-but-first lines are + // indented exactly by 2 spaces. Opinionatedly, we treat this as + // attempts to address past indentation quirks, and hence will ensure + // all lines are uniformly indented instead. + result = indentStr + strings.TrimLeft(exampleString, " ") + } else { + // Otherwise we just indent all non-empty lines (include lines with + // leading spaces) by the same extra amount. + for _, l := range lines { + if l != "" { + l = indentStr + l + } + result = result + l + "\n" + } + result = strings.TrimSuffix(result, "\n") + } + + return result +} + func printHelp(cmd *cobra.Command) string { var output strings.Builder target := types.StringToTarget(cmd.Annotations["target"]) @@ -289,11 +335,7 @@ func printHelp(cmd *cobra.Command) string { if cmd.HasExample() { output.WriteString("\n" + component.Bold(examplesStr) + "\n") - - // matches cobra default help template's behavior of not indenting the - // Example value, which has the added benefit of ensuring multiline - // .Example values are aligned - output.WriteString(cmd.Example + "\n") + output.WriteString(alignExampleForUsage(cmd.Example) + "\n") } if cmd.HasAvailableSubCommands() { diff --git a/plugin/usage_test.go b/plugin/usage_test.go index 7c008b23..6ca98ac8 100644 --- a/plugin/usage_test.go +++ b/plugin/usage_test.go @@ -179,7 +179,7 @@ Aliases: test, t Examples: -sample example usage of the test command + sample example usage of the test command Available Commands: fetch Fetch the plugin tests @@ -240,7 +240,7 @@ Aliases: test, t Examples: -sample example usage of the test command + sample example usage of the test command Available Commands: fetch Fetch the plugin tests @@ -301,7 +301,7 @@ Aliases: test, t Examples: -sample example usage of the test command + sample example usage of the test command Available Commands: fetch Fetch the plugin tests @@ -357,7 +357,7 @@ Usage: tanzu test fetch [flags] Examples: -sample example usage of the fetch command + sample example usage of the fetch command Flags: -h, --help help for fetch @@ -415,7 +415,7 @@ Usage: tanzu fetch [flags] Examples: -sample example usage of the fetch command + sample example usage of the fetch command Flags: -h, --help help for fetch @@ -469,7 +469,7 @@ Usage: tanzu kubernetes test fetch [flags] Examples: -sample example usage of the fetch command + sample example usage of the fetch command Flags: -h, --help help for fetch @@ -521,7 +521,7 @@ Usage: tanzu mission-control test fetch [flags] Examples: -sample example usage of the fetch command + sample example usage of the fetch command Flags: -h, --help help for fetch @@ -584,8 +584,8 @@ Aliases: pu, psh Examples: -sample example usage of the push command -more sample example usage of the push command + sample example usage of the push command + more sample example usage of the push command Available Commands: more Push more @@ -658,3 +658,114 @@ Global Flags: assert.Equal(t, expected, got) } + +func TestExampleIndent(t *testing.T) { + tests := []struct { + test string + input string + // add leading newline to align expected output for improved readability + expectedOutputWithLeadingNewline string + }{ + { + test: "single line - no indent", + input: "first line", + expectedOutputWithLeadingNewline: ` + first line`, + }, + { + test: "single line - with indent", + input: " first line", + expectedOutputWithLeadingNewline: ` + first line`, + }, + { + test: "single line - with irregular indent", + input: " first line", + expectedOutputWithLeadingNewline: ` + first line`, + }, + { + test: "single line - with newline", + input: "first line\n", + expectedOutputWithLeadingNewline: ` + first line +`, + }, + { + test: "single line - with newlines", + input: "first line\n\n\n", + expectedOutputWithLeadingNewline: ` + first line + + +`, + }, + { + test: "multi line - no pre-indents", + input: "first line\nsecond line\nthird line", + expectedOutputWithLeadingNewline: ` + first line + second line + third line`, + }, + { + test: "multi line - with pre-indents of all lines", + input: " first line\n second line\n third line", + expectedOutputWithLeadingNewline: ` + first line + second line + third line`, + }, + { + test: "multi line - with pre-indents of subsequent lines and newlines", + input: "first line\n\n second line\n third line\n\n\n", + expectedOutputWithLeadingNewline: ` + first line + + second line + third line + + +`, + }, + + // when example lines have unrecognized indentation amounts + // no special handling other than shift all lines by same indent + { + test: "multi line - lines having unexpected indent amounts - a", + input: "first line\n second line\n third line", + expectedOutputWithLeadingNewline: ` + first line + second line + third line`, + }, + { + test: "multi line - lines having unexpected indent amounts - b", + input: "first line\n para one\n next\n more indent\n another", + expectedOutputWithLeadingNewline: ` + first line + para one + next + more indent + another`, + }, + { + test: "multi line - lines having unexpected indent amounts and newlines", + input: "first line\n\n second line\n third line\n\n", + expectedOutputWithLeadingNewline: ` + first line + + second line + third line + +`, + }, + } + for _, spec := range tests { + t.Run(spec.test, func(t *testing.T) { + assert := assert.New(t) + result := alignExampleForUsage(spec.input) + assert.Equal(spec.expectedOutputWithLeadingNewline, "\n"+result) + }) + } +}