diff --git a/flag.go b/flag.go index e8cecc99..e4f03b9b 100644 --- a/flag.go +++ b/flag.go @@ -696,7 +696,9 @@ func UnquoteUsage(flag *Flag) (name string, usage string) { // Splits the string `s` on whitespace into an initial substring up to // `i` runes in length and the remainder. Will go `slop` over `i` if // that encompasses the entire string (which allows the caller to -// avoid short orphan words on the final line). +// avoid short orphan words on the final line). If the next word is +// wider than `i`, it is returned on its own and wrapping continues +// after it. func wrapN(i, slop int, s string) (string, string) { if i+slop > len(s) { return s, "" @@ -704,7 +706,13 @@ func wrapN(i, slop int, s string) (string, string) { w := strings.LastIndexAny(s[:i], " \t\n") if w <= 0 { - return s, "" + // No break in the first i bytes. Emit the over-wide word + // alone and keep wrapping whatever follows. + next := strings.IndexAny(s, " \t\n") + if next <= 0 { + return s, "" + } + return s[:next], s[next+1:] } nlPos := strings.LastIndex(s[:i], "\n") if nlPos > 0 && nlPos < w { diff --git a/printusage_test.go b/printusage_test.go index 076d13dd..ce12adf1 100644 --- a/printusage_test.go +++ b/printusage_test.go @@ -72,3 +72,19 @@ func TestPrintUsage_2(t *testing.T) { t.Errorf("Expected \n%s \nActual \n%s", expectedOutput2, res) } } + +// A word wider than the description column must sit on its own line. +// Wrapping has to resume for the words after it (#501). +func TestFlagUsagesWrappedContinuesAfterUnbreakableWord(t *testing.T) { + f := NewFlagSet("example", ContinueOnError) + f.String("mount", "", "a mount specification e.g. 'type=bind,source=/opt,destination=/hostopt'. The rest of this description is never wrapped.") + got := f.FlagUsagesWrapped(60) + want := ` --mount string a mount specification e.g. + 'type=bind,source=/opt,destination=/hostopt'. + The rest of this description is + never wrapped. +` + if got != want { + t.Errorf("FlagUsagesWrapped(60)\nwant:\n%q\ngot:\n%q", want, got) + } +}