1010using System . Linq ;
1111using System . Text ;
1212using System . Threading . Tasks ;
13+ using McMaster . Extensions . CommandLineUtils . HelpText ;
1314
1415namespace McMaster . Extensions . CommandLineUtils
1516{
@@ -20,6 +21,7 @@ namespace McMaster.Extensions.CommandLineUtils
2021 public partial class CommandLineApplication
2122 {
2223 private IConsole _console ;
24+ private IHelpTextGenerator _helpTextGenerator ;
2325
2426 /// <summary>
2527 /// Initializes a new instance of <see cref="CommandLineApplication"/>.
@@ -45,6 +47,17 @@ public CommandLineApplication(IConsole console)
4547 /// <param name="workingDirectory">The current working directory.</param>
4648 /// <param name="throwOnUnexpectedArg">Initial value for <see cref="ThrowOnUnexpectedArgument"/>.</param>
4749 public CommandLineApplication ( IConsole console , string workingDirectory , bool throwOnUnexpectedArg )
50+ : this ( DefaultHelpTextGenerator . Singleton , console , workingDirectory , throwOnUnexpectedArg )
51+ { }
52+
53+ /// <summary>
54+ /// Initializes a new instance of <see cref="CommandLineApplication"/>.
55+ /// </summary>
56+ /// <param name="helpTextGenerator">The help text generator to use.</param>
57+ /// <param name="console">The console implementation to use.</param>
58+ /// <param name="workingDirectory">The current working directory.</param>
59+ /// <param name="throwOnUnexpectedArg">Initial value for <see cref="ThrowOnUnexpectedArgument"/>.</param>
60+ public CommandLineApplication ( IHelpTextGenerator helpTextGenerator , IConsole console , string workingDirectory , bool throwOnUnexpectedArg )
4861 {
4962 if ( console == null )
5063 {
@@ -62,13 +75,14 @@ public CommandLineApplication(IConsole console, string workingDirectory, bool th
6275 Arguments = new List < CommandArgument > ( ) ;
6376 Commands = new List < CommandLineApplication > ( ) ;
6477 RemainingArguments = new List < string > ( ) ;
78+ HelpTextGenerator = helpTextGenerator ;
6579 Invoke = ( ) => 0 ;
6680 ValidationErrorHandler = DefaultValidationErrorHandler ;
6781 SetConsole ( console ) ;
6882 }
6983
7084 private CommandLineApplication ( CommandLineApplication parent , string name , bool throwOnUnexpectedArg )
71- : this ( parent . _console , parent . WorkingDirectory , throwOnUnexpectedArg )
85+ : this ( parent . _helpTextGenerator , parent . _console , parent . WorkingDirectory , throwOnUnexpectedArg )
7286 {
7387 Name = name ;
7488 Parent = parent ;
@@ -81,6 +95,15 @@ private CommandLineApplication(CommandLineApplication parent, string name, bool
8195 /// </summary>
8296 public CommandLineApplication Parent { get ; set ; }
8397
98+ /// <summary>
99+ /// The help text generator to use.
100+ /// </summary>
101+ public IHelpTextGenerator HelpTextGenerator
102+ {
103+ get => _helpTextGenerator ;
104+ set => _helpTextGenerator = value ?? throw new ArgumentNullException ( nameof ( value ) ) ;
105+ }
106+
84107 /// <summary>
85108 /// The short name of the command. When this is a subcommand, it is the name of the word used to invoke the subcommand.
86109 /// </summary>
@@ -449,30 +472,29 @@ public void ShowHint()
449472 /// <summary>
450473 /// Show full help.
451474 /// </summary>
452- /// <param name="commandName">The subcommand for which to show help. Leave null to show for the current command.</param>
453- public void ShowHelp ( string commandName = null )
475+ public void ShowHelp ( )
454476 {
455477 for ( var cmd = this ; cmd != null ; cmd = cmd . Parent )
456478 {
457479 cmd . IsShowingInformation = true ;
458480 }
459481
460- Out . WriteLine ( GetHelpText ( commandName ) ) ;
482+ _helpTextGenerator . Generate ( this , Out ) ;
461483 }
462484
463485 /// <summary>
464- /// Produces help text describing command usage.
486+ /// This method has been marked as obsolete and will be removed in a future version.
487+ /// The recommended replacement is <see cref="ShowHelp()" />.
465488 /// </summary>
466- /// <param name="commandName"></param>
467- /// <returns></returns>
468- public virtual string GetHelpText ( string commandName = null )
489+ /// <param name="commandName">The subcommand for which to show help. Leave null to show for the current command.</param>
490+ [ Obsolete ( "This method has been marked as obsolete and will be removed in a future version." +
491+ "The recommended replacement is ShowHelp()" ) ]
492+ public void ShowHelp ( string commandName = null )
469493 {
470- var headerBuilder = new StringBuilder ( "Usage:" ) ;
471- for ( var cmd = this ; cmd != null ; cmd = cmd . Parent )
494+ if ( commandName == null )
472495 {
473- headerBuilder . Insert ( 6 , string . Format ( " {0}" , cmd . Name ) ) ;
496+ ShowHelp ( ) ;
474497 }
475-
476498 CommandLineApplication target ;
477499
478500 if ( commandName == null || string . Equals ( Name , commandName , StringComparison . OrdinalIgnoreCase ) )
@@ -483,94 +505,55 @@ public virtual string GetHelpText(string commandName = null)
483505 {
484506 target = Commands . SingleOrDefault ( cmd => string . Equals ( cmd . Name , commandName , StringComparison . OrdinalIgnoreCase ) ) ;
485507
486- if ( target != null )
487- {
488- headerBuilder . AppendFormat ( " {0}" , commandName ) ;
489- }
490- else
508+ if ( target == null )
491509 {
492510 // The command name is invalid so don't try to show help for something that doesn't exist
493511 target = this ;
494512 }
495-
496513 }
497514
498- var optionsBuilder = new StringBuilder ( ) ;
499- var commandsBuilder = new StringBuilder ( ) ;
500- var argumentsBuilder = new StringBuilder ( ) ;
515+ target . ShowHelp ( ) ;
516+ }
501517
502- var arguments = target . Arguments . Where ( a => a . ShowInHelpText ) . ToList ( ) ;
503- if ( arguments . Any ( ) )
504- {
505- headerBuilder . Append ( " [arguments]" ) ;
518+ /// <summary>
519+ /// Produces help text describing command usage.
520+ /// </summary>
521+ /// <returns>The help text.</returns>
522+ public virtual string GetHelpText ( )
523+ {
524+ var sb = new StringBuilder ( ) ;
525+ _helpTextGenerator . Generate ( this , new StringWriter ( sb ) ) ;
526+ return sb . ToString ( ) ;
527+ }
506528
507- argumentsBuilder . AppendLine ( ) ;
508- argumentsBuilder . AppendLine ( "Arguments:" ) ;
509- var maxArgLen = arguments . Max ( a => a . Name . Length ) ;
510- var outputFormat = string . Format ( " {{0, -{0}}}{{1}}" , maxArgLen + 2 ) ;
511- foreach ( var arg in arguments )
512- {
513- argumentsBuilder . AppendFormat ( outputFormat , arg . Name , arg . Description ) ;
514- argumentsBuilder . AppendLine ( ) ;
515- }
516- }
529+ /// <summary>
530+ /// This method has been marked as obsolete and will be removed in a future version.
531+ /// The recommended replacement is <see cref="GetHelpText()" />
532+ /// </summary>
533+ /// <param name="commandName"></param>
534+ /// <returns></returns>
535+ [ Obsolete ( "This method has been marked as obsolete and will be removed in a future version." +
536+ "The recommended replacement is GetHelpText()" ) ]
537+ public virtual string GetHelpText ( string commandName = null )
538+ {
539+ CommandLineApplication target ;
517540
518- var options = target . GetOptions ( ) . Where ( o => o . ShowInHelpText ) . ToList ( ) ;
519- if ( options . Any ( ) )
541+ if ( commandName == null || string . Equals ( Name , commandName , StringComparison . OrdinalIgnoreCase ) )
520542 {
521- headerBuilder . Append ( " [options]" ) ;
522-
523- optionsBuilder . AppendLine ( ) ;
524- optionsBuilder . AppendLine ( "Options:" ) ;
525- var maxOptLen = options . Max ( o => o . Template ? . Length ?? 0 ) ;
526- var outputFormat = string . Format ( " {{0, -{0}}}{{1}}" , maxOptLen + 2 ) ;
527- foreach ( var opt in options )
528- {
529- optionsBuilder . AppendFormat ( outputFormat , opt . Template , opt . Description ) ;
530- optionsBuilder . AppendLine ( ) ;
531- }
543+ target = this ;
532544 }
533-
534- var commands = target . Commands . Where ( c => c . ShowInHelpText ) . ToList ( ) ;
535- if ( commands . Any ( ) )
545+ else
536546 {
537- headerBuilder . Append ( " [command]" ) ;
538-
539- commandsBuilder . AppendLine ( ) ;
540- commandsBuilder . AppendLine ( "Commands:" ) ;
541- var maxCmdLen = commands . Max ( c => c . Name ? . Length ?? 0 ) ;
542- var outputFormat = string . Format ( " {{0, -{0}}}{{1}}" , maxCmdLen + 2 ) ;
543- foreach ( var cmd in commands . OrderBy ( c => c . Name ) )
544- {
545- commandsBuilder . AppendFormat ( outputFormat , cmd . Name , cmd . Description ) ;
546- commandsBuilder . AppendLine ( ) ;
547- }
547+ target = Commands . SingleOrDefault ( cmd => string . Equals ( cmd . Name , commandName , StringComparison . OrdinalIgnoreCase ) ) ;
548548
549- if ( OptionHelp ! = null )
549+ if ( target = = null )
550550 {
551- commandsBuilder . AppendLine ( ) ;
552- commandsBuilder . AppendFormat ( $ "Use \" { target . Name } [command] --{ OptionHelp . LongName } \" for more information about a command.") ;
553- commandsBuilder . AppendLine ( ) ;
551+ // The command name is invalid so don't try to show help for something that doesn't exist
552+ target = this ;
554553 }
555554 }
556555
557- if ( target . AllowArgumentSeparator )
558- {
559- headerBuilder . Append ( " [[--] <arg>...]" ) ;
560- }
561-
562- headerBuilder . AppendLine ( ) ;
563-
564- var nameAndVersion = new StringBuilder ( ) ;
565- nameAndVersion . AppendLine ( GetFullNameAndVersion ( ) ) ;
566- nameAndVersion . AppendLine ( ) ;
567-
568- return nameAndVersion . ToString ( )
569- + headerBuilder . ToString ( )
570- + argumentsBuilder . ToString ( )
571- + optionsBuilder . ToString ( )
572- + commandsBuilder . ToString ( )
573- + target . ExtendedHelpText ;
556+ return target . GetHelpText ( ) ;
574557 }
575558
576559 /// <summary>
0 commit comments