@@ -21,7 +21,7 @@ mod stupid;
2121mod templates;
2222mod wrap;
2323
24- use std:: { ffi:: OsString , io:: Write , path:: PathBuf } ;
24+ use std:: { ffi:: OsString , fmt :: Write as _ , io:: Write as _ , path:: PathBuf } ;
2525
2626use anyhow:: { anyhow, Context , Result } ;
2727use bstr:: ByteSlice ;
@@ -312,10 +312,70 @@ fn full_app_help(
312312 }
313313 } ;
314314
315+ // By default clap renders subcommands as a single list which is hard to read given the number
316+ // of existing subcommands. We group the commands by their categories and create several
317+ // shorter lists which are easier to read.
318+ let command = {
319+ let command = get_full_command ( & aliases, color_choice) ;
320+ let heading_style = command. get_styles ( ) . get_header ( ) . render ( ) ;
321+ let heading_style_reset = command. get_styles ( ) . get_header ( ) . render_reset ( ) ;
322+ let mut subcommands_by_category = String :: new ( ) ;
323+
324+ use cmd:: CommandCategory :: * ;
325+ const GROUPS : [ ( cmd:: CommandCategory , & str ) ; 7 ] = [
326+ ( PatchInspection , "Patch inspection commands:" ) ,
327+ ( PatchManipulation , "Patch manipulation commands:" ) ,
328+ ( StackInspection , "Stack inspection commands:" ) ,
329+ ( StackManipulation , "Stack manipulation commands:" ) ,
330+ ( Administration , "Administration commands:" ) ,
331+ ( Alias , "Aliases:" ) ,
332+ ( Help , "Help:" ) ,
333+ ] ;
334+
335+ // Render each subcommand list individually with a custom template and by hiding other
336+ // subcommands.
337+ for ( group_category, group_heading) in GROUPS {
338+ let mut command = command. clone ( ) . help_template ( format ! (
339+ "{heading_style}{group_heading}{heading_style_reset}\n {{subcommands}}"
340+ ) ) ;
341+
342+ for stgit_command in cmd:: STGIT_COMMANDS {
343+ command = command. mut_subcommand ( stgit_command. name , |subcommand| {
344+ subcommand. hide ( stgit_command. category != group_category)
345+ } ) ;
346+ }
347+
348+ for alias_name in aliases. keys ( ) {
349+ command = command. mut_subcommand ( alias_name, |subcommand| {
350+ subcommand. hide ( group_category != Alias )
351+ } ) ;
352+ }
353+
354+ command = command. disable_help_subcommand ( group_category != Help ) ;
355+
356+ write ! (
357+ subcommands_by_category,
358+ "\n {}" ,
359+ command. render_help( ) . ansi( )
360+ )
361+ . expect ( "failed to render help" ) ;
362+ }
363+
364+ // Render the full help by injecting the subcommand groups into the template.
365+ command. help_template ( format ! (
366+ "\
367+ {{before-help}}{{about-with-newline}}
368+ {{usage-heading}} {{usage}}
369+ {subcommands_by_category}
370+ {heading_style}Options:{heading_style_reset}
371+ {{options}}{{after-help}}"
372+ ) )
373+ } ;
374+
315375 // full_app_help should only be called once it has been determined that the command
316376 // line does not have a viable subcommand or alias. Thus this get_matches_from()
317377 // call should print an appropriate help message and terminate the process.
318- let err = get_full_command ( & aliases , color_choice )
378+ let err = command
319379 . try_get_matches_from ( argv)
320380 . expect_err ( "command line should not have viable matches" ) ;
321381 err. print ( ) . expect ( "failed to print clap error" ) ;
0 commit comments