@@ -12,12 +12,13 @@ import (
12
12
)
13
13
14
14
const (
15
- requiredArg = "<%v>"
16
- optionalArg = "[<%v>]"
17
- variadicArg = "%v..."
18
- shortFlag = "-%v"
19
- longFlag = "--%v"
20
- optionType = "(%v)"
15
+ terminalWidth = 80
16
+ requiredArg = "<%v>"
17
+ optionalArg = "[<%v>]"
18
+ variadicArg = "%v..."
19
+ shortFlag = "-%v"
20
+ longFlag = "--%v"
21
+ optionType = "(%v)"
21
22
22
23
whitespace = "\r \n \t "
23
24
@@ -165,22 +166,24 @@ func LongHelp(rootName string, root *cmds.Command, path []string, out io.Writer)
165
166
MoreHelp : (cmd != root ),
166
167
}
167
168
169
+ width := terminalWidth - len (indentStr )
170
+
168
171
if len (cmd .Helptext .LongDescription ) > 0 {
169
172
fields .Description = cmd .Helptext .LongDescription
170
173
}
171
174
172
175
// autogen fields that are empty
173
176
if len (fields .Arguments ) == 0 {
174
- fields .Arguments = strings .Join (argumentText (cmd ), "\n " )
177
+ fields .Arguments = strings .Join (argumentText (width , cmd ), "\n " )
175
178
}
176
179
if len (fields .Options ) == 0 {
177
- fields .Options = strings .Join (optionText (cmd ), "\n " )
180
+ fields .Options = strings .Join (optionText (width , cmd ), "\n " )
178
181
}
179
182
if len (fields .Subcommands ) == 0 {
180
183
fields .Subcommands = strings .Join (subcommandText (cmd , rootName , path ), "\n " )
181
184
}
182
185
if len (fields .Synopsis ) == 0 {
183
- fields .Synopsis = generateSynopsis (cmd , pathStr )
186
+ fields .Synopsis = generateSynopsis (width , cmd , pathStr )
184
187
}
185
188
186
189
// trim the extra newlines (see TrimNewlines doc)
@@ -221,12 +224,14 @@ func ShortHelp(rootName string, root *cmds.Command, path []string, out io.Writer
221
224
MoreHelp : (cmd != root ),
222
225
}
223
226
227
+ width := terminalWidth - len (indentStr )
228
+
224
229
// autogen fields that are empty
225
230
if len (fields .Subcommands ) == 0 {
226
231
fields .Subcommands = strings .Join (subcommandText (cmd , rootName , path ), "\n " )
227
232
}
228
233
if len (fields .Synopsis ) == 0 {
229
- fields .Synopsis = generateSynopsis (cmd , pathStr )
234
+ fields .Synopsis = generateSynopsis (width , cmd , pathStr )
230
235
}
231
236
232
237
// trim the extra newlines (see TrimNewlines doc)
@@ -238,8 +243,17 @@ func ShortHelp(rootName string, root *cmds.Command, path []string, out io.Writer
238
243
return shortHelpTemplate .Execute (out , fields )
239
244
}
240
245
241
- func generateSynopsis (cmd * cmds.Command , path string ) string {
246
+ func generateSynopsis (width int , cmd * cmds.Command , path string ) string {
242
247
res := path
248
+ currentLineLength := len (res )
249
+ appendText := func (text string ) {
250
+ if currentLineLength + len (text )+ 1 > width {
251
+ res += "\n " + strings .Repeat (" " , len (path ))
252
+ currentLineLength = len (path )
253
+ }
254
+ currentLineLength += len (text ) + 1
255
+ res += " " + text
256
+ }
243
257
for _ , opt := range cmd .Options {
244
258
valopt , ok := cmd .Helptext .SynopsisOptionsValues [opt .Name ()]
245
259
if ! ok {
@@ -267,10 +281,10 @@ func generateSynopsis(cmd *cmds.Command, path string) string {
267
281
}
268
282
}
269
283
}
270
- res = fmt . Sprintf ( "%s [%s]" , res , sopt )
284
+ appendText ( "[" + sopt + "]" )
271
285
}
272
286
if len (cmd .Arguments ) > 0 {
273
- res = fmt . Sprintf ( "%s [--]", res )
287
+ appendText ( " [--]" )
274
288
}
275
289
for _ , arg := range cmd .Arguments {
276
290
sarg := fmt .Sprintf ("<%s>" , arg .Name )
@@ -281,25 +295,53 @@ func generateSynopsis(cmd *cmds.Command, path string) string {
281
295
if ! arg .Required {
282
296
sarg = fmt .Sprintf ("[%s]" , sarg )
283
297
}
284
- res = fmt . Sprintf ( "%s %s" , res , sarg )
298
+ appendText ( sarg )
285
299
}
286
300
return strings .Trim (res , " " )
287
301
}
288
302
289
- func argumentText (cmd * cmds.Command ) []string {
303
+ func argumentText (width int , cmd * cmds.Command ) []string {
290
304
lines := make ([]string , len (cmd .Arguments ))
291
305
292
306
for i , arg := range cmd .Arguments {
293
307
lines [i ] = argUsageText (arg )
294
308
}
295
309
lines = align (lines )
296
310
for i , arg := range cmd .Arguments {
297
- lines [i ] += " - " + arg .Description
311
+ lines [i ] += " - "
312
+ lines [i ] = appendWrapped (lines [i ], arg .Description , width )
298
313
}
299
314
300
315
return lines
301
316
}
302
317
318
+ func appendWrapped (prefix , text string , width int ) string {
319
+ offset := len (prefix )
320
+ bWidth := width - offset
321
+
322
+ text = strings .Trim (text , whitespace )
323
+ // Let the terminal handle wrapping if it's to small. Otherwise
324
+ // we get really small lines.
325
+ if bWidth < 40 {
326
+ prefix += text
327
+ return prefix
328
+ }
329
+
330
+ for len (text ) > bWidth {
331
+ idx := strings .LastIndexAny (text [:bWidth ], whitespace )
332
+ if idx < 0 {
333
+ idx = strings .IndexAny (text , whitespace )
334
+ }
335
+ if idx < 0 {
336
+ break
337
+ }
338
+ prefix += text [:idx ] + "\n " + strings .Repeat (" " , offset )
339
+ text = strings .TrimLeft (text [idx :], whitespace )
340
+ }
341
+ prefix += text
342
+ return prefix
343
+ }
344
+
303
345
func optionFlag (flag string ) string {
304
346
if len (flag ) == 1 {
305
347
return fmt .Sprintf (shortFlag , flag )
@@ -308,7 +350,7 @@ func optionFlag(flag string) string {
308
350
}
309
351
}
310
352
311
- func optionText (cmd ... * cmds.Command ) []string {
353
+ func optionText (width int , cmd ... * cmds.Command ) []string {
312
354
// get a slice of the options we want to list out
313
355
options := make ([]cmds.Option , 0 )
314
356
for _ , c := range cmd {
@@ -336,7 +378,8 @@ func optionText(cmd ...*cmds.Command) []string {
336
378
337
379
// add option descriptions to output
338
380
for i , opt := range options {
339
- lines [i ] += " - " + opt .Description ()
381
+ lines [i ] += " - "
382
+ lines [i ] = appendWrapped (lines [i ], opt .Description (), width )
340
383
}
341
384
342
385
return lines
0 commit comments