Skip to content

Commit 065a627

Browse files
majiayu000claude
andcommitted
fix: escape angle brackets in man page generation
Angle brackets in command usage, descriptions, and flag help text were being stripped during man page generation because md2man interprets them as HTML tags. This fix escapes < and > characters with backslashes so they are preserved in the rendered man page output. Fixes #2330 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: majiayu000 <1835304752@qq.com>
1 parent 61968e8 commit 065a627

File tree

2 files changed

+37
-4
lines changed

2 files changed

+37
-4
lines changed

doc/man_docs.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,14 @@ func fillHeader(header *GenManHeader, name string, disableAutoGen bool) error {
140140
return nil
141141
}
142142

143+
// escapeAngleBrackets escapes < and > characters to prevent md2man from
144+
// interpreting them as HTML tags. See https://github.com/spf13/cobra/issues/2330
145+
func escapeAngleBrackets(s string) string {
146+
s = strings.ReplaceAll(s, "<", `\<`)
147+
s = strings.ReplaceAll(s, ">", `\>`)
148+
return s
149+
}
150+
143151
func manPreamble(buf io.StringWriter, header *GenManHeader, cmd *cobra.Command, dashedName string) {
144152
description := cmd.Long
145153
if len(description) == 0 {
@@ -149,11 +157,11 @@ func manPreamble(buf io.StringWriter, header *GenManHeader, cmd *cobra.Command,
149157
cobra.WriteStringAndCheck(buf, fmt.Sprintf(`%% "%s" "%s" "%s" "%s" "%s"
150158
# NAME
151159
`, header.Title, header.Section, header.date, header.Source, header.Manual))
152-
cobra.WriteStringAndCheck(buf, fmt.Sprintf("%s \\- %s\n\n", dashedName, cmd.Short))
160+
cobra.WriteStringAndCheck(buf, fmt.Sprintf("%s \\- %s\n\n", dashedName, escapeAngleBrackets(cmd.Short)))
153161
cobra.WriteStringAndCheck(buf, "# SYNOPSIS\n")
154-
cobra.WriteStringAndCheck(buf, fmt.Sprintf("**%s**\n\n", cmd.UseLine()))
162+
cobra.WriteStringAndCheck(buf, fmt.Sprintf("**%s**\n\n", escapeAngleBrackets(cmd.UseLine())))
155163
cobra.WriteStringAndCheck(buf, "# DESCRIPTION\n")
156-
cobra.WriteStringAndCheck(buf, description+"\n\n")
164+
cobra.WriteStringAndCheck(buf, escapeAngleBrackets(description)+"\n\n")
157165
}
158166

159167
func manPrintFlags(buf io.StringWriter, flags *pflag.FlagSet) {
@@ -180,7 +188,7 @@ func manPrintFlags(buf io.StringWriter, flags *pflag.FlagSet) {
180188
format += "]"
181189
}
182190
format += "\n\t%s\n\n"
183-
cobra.WriteStringAndCheck(buf, fmt.Sprintf(format, flag.DefValue, flag.Usage))
191+
cobra.WriteStringAndCheck(buf, fmt.Sprintf(format, flag.DefValue, escapeAngleBrackets(flag.Usage)))
184192
})
185193
}
186194

doc/man_docs_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,31 @@ func assertNextLineEquals(scanner *bufio.Scanner, expectedLine string) error {
214214
return fmt.Errorf("hit EOF before finding %v", expectedLine)
215215
}
216216

217+
func TestGenManAngleBrackets(t *testing.T) {
218+
// Test that angle brackets are preserved in man page output.
219+
// See https://github.com/spf13/cobra/issues/2330
220+
cmd := &cobra.Command{
221+
Use: "cmd [<remote>:]<instance>",
222+
Short: "A command with <angle> brackets",
223+
Long: "This is a longer description with <placeholder> values.",
224+
Run: emptyRun,
225+
}
226+
cmd.Flags().StringP("config", "c", "", "Path to <config> file")
227+
228+
buf := new(bytes.Buffer)
229+
if err := GenMan(cmd, nil, buf); err != nil {
230+
t.Fatal(err)
231+
}
232+
output := buf.String()
233+
234+
// Verify angle brackets are preserved in the rendered man page
235+
checkStringContains(t, output, "<remote>")
236+
checkStringContains(t, output, "<instance>")
237+
checkStringContains(t, output, "<angle>")
238+
checkStringContains(t, output, "<placeholder>")
239+
checkStringContains(t, output, "<config>")
240+
}
241+
217242
func BenchmarkGenManToFile(b *testing.B) {
218243
file, err := os.CreateTemp("", "")
219244
if err != nil {

0 commit comments

Comments
 (0)