mirror of
				https://github.com/Tyrrrz/CliFx.git
				synced 2025-10-25 15:19:17 +00:00 
			
		
		
		
	Change ICommandHelpTextRenderer
This commit is contained in:
		| @@ -79,7 +79,8 @@ namespace CliFx | ||||
|                     } | ||||
|  | ||||
|                     // Show help | ||||
|                     _commandHelpTextRenderer.RenderHelpText(_applicationMetadata, availableCommandSchemas, parentCommandSchema); | ||||
|                     var helpTextSource = new HelpTextSource(_applicationMetadata, availableCommandSchemas, parentCommandSchema); | ||||
|                     _commandHelpTextRenderer.RenderHelpText(_console, helpTextSource); | ||||
|  | ||||
|                     return isError ? -1 : 0; | ||||
|                 } | ||||
| @@ -95,7 +96,8 @@ namespace CliFx | ||||
|                 // Show help if it was requested | ||||
|                 if (commandInput.IsHelpRequested()) | ||||
|                 { | ||||
|                     _commandHelpTextRenderer.RenderHelpText(_applicationMetadata, availableCommandSchemas, matchingCommandSchema); | ||||
|                     var helpTextSource = new HelpTextSource(_applicationMetadata, availableCommandSchemas, matchingCommandSchema); | ||||
|                     _commandHelpTextRenderer.RenderHelpText(_console, helpTextSource); | ||||
|  | ||||
|                     return 0; | ||||
|                 } | ||||
|   | ||||
| @@ -83,7 +83,7 @@ namespace CliFx | ||||
|  | ||||
|             return new CliApplication(metadata, commandTypes, | ||||
|                 console, new CommandInputParser(), new CommandSchemaResolver(), | ||||
|                 commandFactory, new CommandInitializer(), new CommandHelpTextRenderer(console)); | ||||
|                 commandFactory, new CommandInitializer(), new CommandHelpTextRenderer()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										22
									
								
								CliFx/Models/HelpTextSource.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								CliFx/Models/HelpTextSource.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace CliFx.Models | ||||
| { | ||||
|     public class HelpTextSource | ||||
|     { | ||||
|         public ApplicationMetadata ApplicationMetadata { get; } | ||||
|  | ||||
|         public IReadOnlyList<CommandSchema> AvailableCommandSchemas { get; } | ||||
|  | ||||
|         public CommandSchema TargetCommandSchema { get; } | ||||
|  | ||||
|         public HelpTextSource(ApplicationMetadata applicationMetadata, | ||||
|             IReadOnlyList<CommandSchema> availableCommandSchemas, | ||||
|             CommandSchema targetCommandSchema) | ||||
|         { | ||||
|             ApplicationMetadata = applicationMetadata; | ||||
|             AvailableCommandSchemas = availableCommandSchemas; | ||||
|             TargetCommandSchema = targetCommandSchema; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -8,249 +8,260 @@ namespace CliFx.Services | ||||
| { | ||||
|     public partial class CommandHelpTextRenderer : ICommandHelpTextRenderer | ||||
|     { | ||||
|         private readonly IConsole _console; | ||||
|         public void RenderHelpText(IConsole console, HelpTextSource source) => new Impl(console, source).RenderHelpText(); | ||||
|     } | ||||
|  | ||||
|         private bool _isEmpty = true; | ||||
|         private int _position; | ||||
|  | ||||
|         public CommandHelpTextRenderer(IConsole console) | ||||
|     public partial class CommandHelpTextRenderer | ||||
|     { | ||||
|         private class Impl | ||||
|         { | ||||
|             _console = console; | ||||
|         } | ||||
|             private readonly IConsole _console; | ||||
|             private readonly HelpTextSource _source; | ||||
|  | ||||
|         private void Render(string text) | ||||
|         { | ||||
|             _console.Output.Write(text); | ||||
|             private bool _isEmpty = true; | ||||
|             private int _position; | ||||
|  | ||||
|             _isEmpty = false; | ||||
|             _position += text.Length; | ||||
|         } | ||||
|  | ||||
|         private void RenderNewLine() | ||||
|         { | ||||
|             _console.Output.WriteLine(); | ||||
|  | ||||
|             _isEmpty = false; | ||||
|             _position = 0; | ||||
|         } | ||||
|  | ||||
|         private void RenderIndent(int spaces = 2) => Render(' '.Repeat(spaces)); | ||||
|  | ||||
|         private void RenderColumnIndent(int spaces = 20, int margin = 2) | ||||
|         { | ||||
|             if (_position + margin >= spaces) | ||||
|             public Impl(IConsole console, HelpTextSource source) | ||||
|             { | ||||
|                 RenderNewLine(); | ||||
|                 RenderIndent(spaces); | ||||
|                 _console = console; | ||||
|                 _source = source; | ||||
|             } | ||||
|             else | ||||
|  | ||||
|             private void Render(string text) | ||||
|             { | ||||
|                 RenderIndent(spaces - _position); | ||||
|                 _console.Output.Write(text); | ||||
|  | ||||
|                 _isEmpty = false; | ||||
|                 _position += text.Length; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private void Render(string text, ConsoleColor foregroundColor) => | ||||
|             _console.WithForegroundColor(foregroundColor, () => Render(text)); | ||||
|  | ||||
|         private void Render(string text, ConsoleColor foregroundColor, ConsoleColor backgroundColor) => | ||||
|             _console.WithColors(foregroundColor, backgroundColor, () => Render(text)); | ||||
|  | ||||
|         private void RenderHeader(string text) | ||||
|         { | ||||
|             Render(text, ConsoleColor.Black, ConsoleColor.DarkGray); | ||||
|             RenderNewLine(); | ||||
|         } | ||||
|  | ||||
|         private void RenderApplicationInfo(ApplicationMetadata applicationMetadata, CommandSchema commandSchema) | ||||
|         { | ||||
|             if (!commandSchema.IsDefault()) | ||||
|                 return; | ||||
|  | ||||
|             // Margin | ||||
|             if (!_isEmpty) | ||||
|                 RenderNewLine(); | ||||
|  | ||||
|             // Title and version | ||||
|             Render($"{applicationMetadata.Title} v{applicationMetadata.VersionText}", ConsoleColor.Yellow); | ||||
|             RenderNewLine(); | ||||
|         } | ||||
|  | ||||
|         private void RenderDescription(CommandSchema commandSchema) | ||||
|         { | ||||
|             if (commandSchema.Description.IsNullOrWhiteSpace()) | ||||
|                 return; | ||||
|  | ||||
|             // Margin | ||||
|             if (!_isEmpty) | ||||
|                 RenderNewLine(); | ||||
|  | ||||
|             // Header | ||||
|             RenderHeader("Description"); | ||||
|  | ||||
|             // Description | ||||
|             RenderIndent(); | ||||
|             Render(commandSchema.Description); | ||||
|             RenderNewLine(); | ||||
|         } | ||||
|  | ||||
|         private void RenderUsage(ApplicationMetadata applicationMetadata, CommandSchema commandSchema, | ||||
|             IReadOnlyList<CommandSchema> childCommandSchemas) | ||||
|         { | ||||
|             // Margin | ||||
|             if (!_isEmpty) | ||||
|                 RenderNewLine(); | ||||
|  | ||||
|             // Header | ||||
|             RenderHeader("Usage"); | ||||
|  | ||||
|             // Exe name | ||||
|             RenderIndent(); | ||||
|             Render(applicationMetadata.ExecutableName); | ||||
|  | ||||
|             // Command name | ||||
|             if (!commandSchema.IsDefault()) | ||||
|             private void RenderNewLine() | ||||
|             { | ||||
|                 _console.Output.WriteLine(); | ||||
|  | ||||
|                 _isEmpty = false; | ||||
|                 _position = 0; | ||||
|             } | ||||
|  | ||||
|             private void RenderIndent(int spaces = 2) => Render(' '.Repeat(spaces)); | ||||
|  | ||||
|             private void RenderColumnIndent(int spaces = 20, int margin = 2) | ||||
|             { | ||||
|                 if (_position + margin >= spaces) | ||||
|                 { | ||||
|                     RenderNewLine(); | ||||
|                     RenderIndent(spaces); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     RenderIndent(spaces - _position); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             private void Render(string text, ConsoleColor foregroundColor) => | ||||
|                 _console.WithForegroundColor(foregroundColor, () => Render(text)); | ||||
|  | ||||
|             private void Render(string text, ConsoleColor foregroundColor, ConsoleColor backgroundColor) => | ||||
|                 _console.WithColors(foregroundColor, backgroundColor, () => Render(text)); | ||||
|  | ||||
|             private void RenderHeader(string text) | ||||
|             { | ||||
|                 Render(text, ConsoleColor.Black, ConsoleColor.DarkGray); | ||||
|                 RenderNewLine(); | ||||
|             } | ||||
|  | ||||
|             private void RenderApplicationInfo() | ||||
|             { | ||||
|                 if (!_source.TargetCommandSchema.IsDefault()) | ||||
|                     return; | ||||
|  | ||||
|                 // Margin | ||||
|                 if (!_isEmpty) | ||||
|                     RenderNewLine(); | ||||
|  | ||||
|                 // Title | ||||
|                 Render(_source.ApplicationMetadata.Title, ConsoleColor.Yellow); | ||||
|                 Render(" "); | ||||
|                 Render(commandSchema.Name, ConsoleColor.Cyan); | ||||
|                 Render(_source.ApplicationMetadata.VersionText, ConsoleColor.Yellow); | ||||
|                 RenderNewLine(); | ||||
|             } | ||||
|  | ||||
|             // Child command | ||||
|             if (childCommandSchemas.Any()) | ||||
|             private void RenderDescription() | ||||
|             { | ||||
|                 if (_source.TargetCommandSchema.Description.IsNullOrWhiteSpace()) | ||||
|                     return; | ||||
|  | ||||
|                 // Margin | ||||
|                 if (!_isEmpty) | ||||
|                     RenderNewLine(); | ||||
|  | ||||
|                 // Header | ||||
|                 RenderHeader("Description"); | ||||
|  | ||||
|                 // Description | ||||
|                 RenderIndent(); | ||||
|                 Render(_source.TargetCommandSchema.Description); | ||||
|                 RenderNewLine(); | ||||
|             } | ||||
|  | ||||
|             private void RenderUsage() | ||||
|             { | ||||
|                 // Margin | ||||
|                 if (!_isEmpty) | ||||
|                     RenderNewLine(); | ||||
|  | ||||
|                 // Header | ||||
|                 RenderHeader("Usage"); | ||||
|  | ||||
|                 // Exe name | ||||
|                 RenderIndent(); | ||||
|                 Render(_source.ApplicationMetadata.ExecutableName); | ||||
|  | ||||
|                 // Command name | ||||
|                 if (!_source.TargetCommandSchema.IsDefault()) | ||||
|                 { | ||||
|                     Render(" "); | ||||
|                     Render(_source.TargetCommandSchema.Name, ConsoleColor.Cyan); | ||||
|                 } | ||||
|  | ||||
|                 // Child command | ||||
|                 if (GetChildCommandSchemas(_source.AvailableCommandSchemas, _source.TargetCommandSchema).Any()) | ||||
|                 { | ||||
|                     Render(" "); | ||||
|                     Render("[command]", ConsoleColor.Cyan); | ||||
|                 } | ||||
|  | ||||
|                 // Options | ||||
|                 Render(" "); | ||||
|                 Render("[options]", ConsoleColor.White); | ||||
|                 RenderNewLine(); | ||||
|             } | ||||
|  | ||||
|             private void RenderOptions() | ||||
|             { | ||||
|                 var options = new List<CommandOptionSchema>(); | ||||
|                 options.AddRange(_source.TargetCommandSchema.Options); | ||||
|  | ||||
|                 options.Add(new CommandOptionSchema(null, "help", 'h', null, false, "Shows help text.")); | ||||
|  | ||||
|                 if (_source.TargetCommandSchema.IsDefault()) | ||||
|                     options.Add(new CommandOptionSchema(null, "version", null, null, false, "Shows application version.")); | ||||
|  | ||||
|                 // Margin | ||||
|                 if (!_isEmpty) | ||||
|                     RenderNewLine(); | ||||
|  | ||||
|                 // Header | ||||
|                 RenderHeader("Options"); | ||||
|  | ||||
|                 // Options | ||||
|                 foreach (var option in options) | ||||
|                 { | ||||
|                     RenderIndent(); | ||||
|  | ||||
|                     // Short name | ||||
|                     if (option.ShortName != null) | ||||
|                     { | ||||
|                         Render($"-{option.ShortName}", ConsoleColor.White); | ||||
|                     } | ||||
|  | ||||
|                     // Delimiter | ||||
|                     if (!option.Name.IsNullOrWhiteSpace() && option.ShortName != null) | ||||
|                     { | ||||
|                         Render("|"); | ||||
|                     } | ||||
|  | ||||
|                     // Name | ||||
|                     if (!option.Name.IsNullOrWhiteSpace()) | ||||
|                     { | ||||
|                         Render($"--{option.Name}", ConsoleColor.White); | ||||
|                     } | ||||
|  | ||||
|                     // Description | ||||
|                     if (!option.Description.IsNullOrWhiteSpace()) | ||||
|                     { | ||||
|                         RenderColumnIndent(); | ||||
|                         Render(option.Description); | ||||
|                     } | ||||
|  | ||||
|                     RenderNewLine(); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             private void RenderChildCommands() | ||||
|             { | ||||
|                 var childCommandSchemas = GetChildCommandSchemas(_source.AvailableCommandSchemas, _source.TargetCommandSchema).ToArray(); | ||||
|  | ||||
|                 if (!childCommandSchemas.Any()) | ||||
|                     return; | ||||
|  | ||||
|                 // Margin | ||||
|                 if (!_isEmpty) | ||||
|                     RenderNewLine(); | ||||
|  | ||||
|                 // Header | ||||
|                 RenderHeader("Commands"); | ||||
|  | ||||
|                 // Child commands | ||||
|                 foreach (var childCommandSchema in childCommandSchemas) | ||||
|                 { | ||||
|                     var relativeCommandName = GetRelativeCommandName(childCommandSchema, _source.TargetCommandSchema); | ||||
|  | ||||
|                     // Name | ||||
|                     RenderIndent(); | ||||
|                     Render(relativeCommandName, ConsoleColor.Cyan); | ||||
|  | ||||
|                     // Description | ||||
|                     if (!childCommandSchema.Description.IsNullOrWhiteSpace()) | ||||
|                     { | ||||
|                         RenderColumnIndent(); | ||||
|                         Render(childCommandSchema.Description); | ||||
|                     } | ||||
|  | ||||
|                     RenderNewLine(); | ||||
|                 } | ||||
|  | ||||
|                 // Margin | ||||
|                 RenderNewLine(); | ||||
|  | ||||
|                 // Child command help tip | ||||
|                 Render("You can run `"); | ||||
|                 Render(_source.ApplicationMetadata.ExecutableName); | ||||
|  | ||||
|                 if (!_source.TargetCommandSchema.IsDefault()) | ||||
|                 { | ||||
|                     Render(" "); | ||||
|                     Render(_source.TargetCommandSchema.Name, ConsoleColor.Cyan); | ||||
|                 } | ||||
|  | ||||
|                 Render(" "); | ||||
|                 Render("[command]", ConsoleColor.Cyan); | ||||
|             } | ||||
|  | ||||
|             // Options | ||||
|             Render(" "); | ||||
|             Render("[options]", ConsoleColor.White); | ||||
|             RenderNewLine(); | ||||
|         } | ||||
|  | ||||
|         private void RenderOptions(CommandSchema commandSchema) | ||||
|         { | ||||
|             var options = new List<CommandOptionSchema>(); | ||||
|             options.AddRange(commandSchema.Options); | ||||
|  | ||||
|             options.Add(new CommandOptionSchema(null, "help", 'h', null, false, "Shows help text.")); | ||||
|  | ||||
|             if (commandSchema.IsDefault()) | ||||
|                 options.Add(new CommandOptionSchema(null, "version", null, null, false, "Shows application version.")); | ||||
|  | ||||
|             // Margin | ||||
|             if (!_isEmpty) | ||||
|                 RenderNewLine(); | ||||
|  | ||||
|             // Header | ||||
|             RenderHeader("Options"); | ||||
|  | ||||
|             // Options | ||||
|             foreach (var option in options) | ||||
|             { | ||||
|                 RenderIndent(); | ||||
|  | ||||
|                 // Short name | ||||
|                 if (option.ShortName != null) | ||||
|                 { | ||||
|                     Render($"-{option.ShortName}", ConsoleColor.White); | ||||
|                 } | ||||
|  | ||||
|                 // Delimiter | ||||
|                 if (!option.Name.IsNullOrWhiteSpace() && option.ShortName != null) | ||||
|                 { | ||||
|                     Render("|"); | ||||
|                 } | ||||
|  | ||||
|                 // Name | ||||
|                 if (!option.Name.IsNullOrWhiteSpace()) | ||||
|                 { | ||||
|                     Render($"--{option.Name}", ConsoleColor.White); | ||||
|                 } | ||||
|  | ||||
|                 // Description | ||||
|                 if (!option.Description.IsNullOrWhiteSpace()) | ||||
|                 { | ||||
|                     RenderColumnIndent(); | ||||
|                     Render(option.Description); | ||||
|                 } | ||||
|  | ||||
|                 RenderNewLine(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private void RenderChildCommands(ApplicationMetadata applicationMetadata, CommandSchema commandSchema, | ||||
|             IReadOnlyList<CommandSchema> childCommandSchemas) | ||||
|         { | ||||
|             if (!childCommandSchemas.Any()) | ||||
|                 return; | ||||
|  | ||||
|             // Margin | ||||
|             if (!_isEmpty) | ||||
|                 RenderNewLine(); | ||||
|  | ||||
|             // Header | ||||
|             RenderHeader("Commands"); | ||||
|  | ||||
|             // Child commands | ||||
|             foreach (var childCommandSchema in childCommandSchemas) | ||||
|             { | ||||
|                 var relativeCommandName = GetRelativeCommandName(childCommandSchema, commandSchema); | ||||
|  | ||||
|                 // Name | ||||
|                 RenderIndent(); | ||||
|                 Render(relativeCommandName, ConsoleColor.Cyan); | ||||
|  | ||||
|                 // Description | ||||
|                 if (!childCommandSchema.Description.IsNullOrWhiteSpace()) | ||||
|                 { | ||||
|                     RenderColumnIndent(); | ||||
|                     Render(childCommandSchema.Description); | ||||
|                 } | ||||
|  | ||||
|                 RenderNewLine(); | ||||
|             } | ||||
|  | ||||
|             // Margin | ||||
|             RenderNewLine(); | ||||
|  | ||||
|             // Child command help tip | ||||
|             Render("You can run `"); | ||||
|             Render(applicationMetadata.ExecutableName); | ||||
|  | ||||
|             if (!commandSchema.IsDefault()) | ||||
|             { | ||||
|                 Render(" "); | ||||
|                 Render(commandSchema.Name, ConsoleColor.Cyan); | ||||
|                 Render("--help", ConsoleColor.White); | ||||
|  | ||||
|                 Render("` to show help on a specific command."); | ||||
|  | ||||
|                 RenderNewLine(); | ||||
|             } | ||||
|  | ||||
|             Render(" "); | ||||
|             Render("[command]", ConsoleColor.Cyan); | ||||
|  | ||||
|             Render(" "); | ||||
|             Render("--help", ConsoleColor.White); | ||||
|  | ||||
|             Render("` to show help on a specific command."); | ||||
|  | ||||
|             RenderNewLine(); | ||||
|         } | ||||
|  | ||||
|         public void RenderHelpText(ApplicationMetadata applicationMetadata, | ||||
|             IReadOnlyList<CommandSchema> availableCommandSchemas, CommandSchema matchingCommandSchema) | ||||
|         { | ||||
|             var childCommandSchemas = availableCommandSchemas | ||||
|                 .Where(c => availableCommandSchemas.FindParent(c.Name) == matchingCommandSchema) | ||||
|                 .ToArray(); | ||||
|  | ||||
|             RenderApplicationInfo(applicationMetadata, matchingCommandSchema); | ||||
|             RenderDescription(matchingCommandSchema); | ||||
|             RenderUsage(applicationMetadata, matchingCommandSchema, childCommandSchemas); | ||||
|             RenderOptions(matchingCommandSchema); | ||||
|             RenderChildCommands(applicationMetadata, matchingCommandSchema, childCommandSchemas); | ||||
|             public void RenderHelpText() | ||||
|             { | ||||
|                 RenderApplicationInfo(); | ||||
|                 RenderDescription(); | ||||
|                 RenderUsage(); | ||||
|                 RenderOptions(); | ||||
|                 RenderChildCommands(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public partial class CommandHelpTextRenderer | ||||
|     { | ||||
|         private static IEnumerable<CommandSchema> GetChildCommandSchemas(IReadOnlyList<CommandSchema> availableCommandSchemas, | ||||
|             CommandSchema parentCommandSchema) => | ||||
|             availableCommandSchemas.Where(c => availableCommandSchemas.FindParent(c.Name) == parentCommandSchema); | ||||
|  | ||||
|         private static string GetRelativeCommandName(CommandSchema commandSchema, CommandSchema parentCommandSchema) => | ||||
|             parentCommandSchema.Name.IsNullOrWhiteSpace() | ||||
|                 ? commandSchema.Name | ||||
|   | ||||
| @@ -1,11 +1,9 @@ | ||||
| using System.Collections.Generic; | ||||
| using CliFx.Models; | ||||
| using CliFx.Models; | ||||
|  | ||||
| namespace CliFx.Services | ||||
| { | ||||
|     public interface ICommandHelpTextRenderer | ||||
|     { | ||||
|         void RenderHelpText(ApplicationMetadata applicationMetadata, | ||||
|             IReadOnlyList<CommandSchema> availableCommandSchemas, CommandSchema matchingCommandSchema); | ||||
|         void RenderHelpText(IConsole console, HelpTextSource source); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user