Esempio n. 1
0
        public void RenderHelpText_Test(HelpTextSource source,
                                        IReadOnlyList <string> expectedSubstrings)
        {
            // Arrange
            using var stdout = new StringWriter();

            var console  = new VirtualConsole(stdout);
            var renderer = new HelpTextRenderer();

            // Act
            renderer.RenderHelpText(console, source);

            // Assert
            stdout.ToString().Should().ContainAll(expectedSubstrings);
        }
Esempio n. 2
0
        private int?HandleHelpOption(CommandInput commandInput,
                                     IReadOnlyList <CommandSchema> availableCommandSchemas, CommandSchema targetCommandSchema)
        {
            // Help should be rendered if it was requested, or when executing a command which isn't defined
            var shouldRenderHelp = commandInput.IsHelpOptionSpecified() || targetCommandSchema == null;

            // If shouldn't render help, pass execution to the next handler
            if (!shouldRenderHelp)
            {
                return(null);
            }

            // Keep track whether there was an error in the input
            var isError = false;

            // If target command isn't defined, find its contextual replacement
            if (targetCommandSchema == null)
            {
                // If command was specified, inform the user that it's not defined
                if (commandInput.IsCommandSpecified())
                {
                    _console.WithForegroundColor(ConsoleColor.Red,
                                                 () => _console.Error.WriteLine($"Specified command [{commandInput.CommandName}] is not defined."));

                    isError = true;
                }

                // Replace target command with closest parent of specified command
                targetCommandSchema = availableCommandSchemas.FindParent(commandInput.CommandName);

                // If there's no parent, replace with stub default command
                if (targetCommandSchema == null)
                {
                    targetCommandSchema     = CommandSchema.StubDefaultCommand;
                    availableCommandSchemas = availableCommandSchemas.Concat(CommandSchema.StubDefaultCommand).ToArray();
                }
            }

            // Build help text source
            var helpTextSource = new HelpTextSource(_metadata, availableCommandSchemas, targetCommandSchema);

            // Render help text
            _helpTextRenderer.RenderHelpText(_console, helpTextSource);

            // Short-circuit with appropriate exit code
            return(isError ? -1 : 0);
        }
Esempio n. 3
0
        private int?HandleHelpOption(CommandInput commandInput,
                                     IReadOnlyList <CommandSchema> availableCommandSchemas, CommandCandidate?commandCandidate)
        {
            // Help should be rendered if it was requested, or when executing a command which isn't defined
            var shouldRenderHelp = commandInput.IsHelpOptionSpecified() || commandCandidate == null;

            // If shouldn't render help, pass execution to the next handler
            if (!shouldRenderHelp)
            {
                return(null);
            }

            // Keep track whether there was an error in the input
            var isError = false;

            // Report error if no command matched the arguments
            if (commandCandidate is null)
            {
                // If a command was specified, inform the user that the command is not defined
                if (commandInput.HasArguments())
                {
                    _console.WithForegroundColor(ConsoleColor.Red,
                                                 () => _console.Error.WriteLine($"No command could be matched for input [{string.Join(" ", commandInput.Arguments)}]"));
                    isError = true;
                }

                commandCandidate = new CommandCandidate(CommandSchema.StubDefaultCommand, new string[0], commandInput);
            }

            // Build help text source
            var helpTextSource = new HelpTextSource(_metadata, availableCommandSchemas, commandCandidate.Schema);

            // Render help text
            _helpTextRenderer.RenderHelpText(_console, helpTextSource);

            // Short-circuit with appropriate exit code
            return(isError ? -1 : 0);
        }
Esempio n. 4
0
        /// <inheritdoc />
        public void RenderHelpText(IConsole console, HelpTextSource source)
        {
            // Track position
            var column = 0;
            var row    = 0;

            // Get built-in option schemas (help and version)
            var builtInOptionSchemas = new List <CommandOptionSchema> {
                CommandOptionSchema.HelpOption
            };

            if (source.TargetCommandSchema.IsDefault())
            {
                builtInOptionSchemas.Add(CommandOptionSchema.VersionOption);
            }

            // Get child command schemas
            var childCommandSchemas = source.AvailableCommandSchemas
                                      .Where(c => source.AvailableCommandSchemas.FindParent(c.Name) == source.TargetCommandSchema)
                                      .ToArray();

            // Define helper functions

            bool IsEmpty() => column == 0 && row == 0;

            void Render(string text)
            {
                console.Output.Write(text);

                column += text.Length;
            }

            void RenderNewLine()
            {
                console.Output.WriteLine();

                column = 0;
                row++;
            }

            void RenderMargin(int lines = 1)
            {
                if (!IsEmpty())
                {
                    for (var i = 0; i < lines; i++)
                    {
                        RenderNewLine();
                    }
                }
            }

            void RenderIndent(int spaces = 2)
            {
                Render(' '.Repeat(spaces));
            }

            void RenderColumnIndent(int spaces = 20, int margin = 2)
            {
                if (column + margin >= spaces)
                {
                    RenderNewLine();
                    RenderIndent(spaces);
                }
                else
                {
                    RenderIndent(spaces - column);
                }
            }

            void RenderWithColor(string text, ConsoleColor foregroundColor)
            {
                console.WithForegroundColor(foregroundColor, () => Render(text));
            }

            void RenderWithColors(string text, ConsoleColor foregroundColor, ConsoleColor backgroundColor)
            {
                console.WithColors(foregroundColor, backgroundColor, () => Render(text));
            }

            void RenderHeader(string text)
            {
                RenderWithColors(text, ConsoleColor.Black, ConsoleColor.DarkGray);
                RenderNewLine();
            }

            void RenderApplicationInfo()
            {
                if (!source.TargetCommandSchema.IsDefault())
                {
                    return;
                }

                // Title and version
                RenderWithColor(source.ApplicationMetadata.Title, ConsoleColor.Yellow);
                Render(" ");
                RenderWithColor(source.ApplicationMetadata.VersionText, ConsoleColor.Yellow);
                RenderNewLine();

                // Description
                if (!string.IsNullOrWhiteSpace(source.ApplicationMetadata.Description))
                {
                    Render(source.ApplicationMetadata.Description !);
                    RenderNewLine();
                }
            }

            void RenderDescription()
            {
                if (string.IsNullOrWhiteSpace(source.TargetCommandSchema.Description))
                {
                    return;
                }

                // Margin
                RenderMargin();

                // Header
                RenderHeader("Description");

                // Description
                RenderIndent();
                Render(source.TargetCommandSchema.Description !);
                RenderNewLine();
            }

            void RenderUsage()
            {
                // Margin
                RenderMargin();

                // Header
                RenderHeader("Usage");

                // Exe name
                RenderIndent();
                Render(source.ApplicationMetadata.ExecutableName);

                // Command name
                if (!string.IsNullOrWhiteSpace(source.TargetCommandSchema.Name))
                {
                    Render(" ");
                    RenderWithColor(source.TargetCommandSchema.Name !, ConsoleColor.Cyan);
                }

                // Child command
                if (childCommandSchemas.Any())
                {
                    Render(" ");
                    RenderWithColor("[command]", ConsoleColor.Cyan);
                }

                // Arguments
                foreach (var argumentSchema in source.TargetCommandSchema.Arguments)
                {
                    Render(" ");
                    if (!argumentSchema.IsRequired)
                    {
                        Render("[");
                    }

                    Render($"<{argumentSchema.DisplayName}>");

                    if (!argumentSchema.IsRequired)
                    {
                        Render("]");
                    }
                }

                // Options
                Render(" ");
                RenderWithColor("[options]", ConsoleColor.White);
                RenderNewLine();
            }

            void RenderArguments()
            {
                // Do not render anything if the command has no arguments
                if (source.TargetCommandSchema.Arguments.Count == 0)
                {
                    return;
                }

                // Margin
                RenderMargin();

                // Header
                RenderHeader("Arguments");

                // Order arguments
                var orderedArgumentSchemas = source.TargetCommandSchema.Arguments
                                             .Ordered()
                                             .ToArray();

                // Arguments
                foreach (var argumentSchema in orderedArgumentSchemas)
                {
                    // Is required
                    if (argumentSchema.IsRequired)
                    {
                        RenderWithColor("* ", ConsoleColor.Red);
                    }
                    else
                    {
                        RenderIndent();
                    }

                    // Short name
                    RenderWithColor($"{argumentSchema.DisplayName}", ConsoleColor.White);

                    // Description
                    if (!string.IsNullOrWhiteSpace(argumentSchema.Description))
                    {
                        RenderColumnIndent();
                        Render(argumentSchema.Description !);
                    }

                    RenderNewLine();
                }
            }

            void RenderOptions()
            {
                // Margin
                RenderMargin();

                // Header
                RenderHeader("Options");

                // Order options and append built-in options
                var allOptionSchemas = source.TargetCommandSchema.Options
                                       .OrderByDescending(o => o.IsRequired)
                                       .Concat(builtInOptionSchemas)
                                       .ToArray();

                // Options
                foreach (var optionSchema in allOptionSchemas)
                {
                    // Is required
                    if (optionSchema.IsRequired)
                    {
                        RenderWithColor("* ", ConsoleColor.Red);
                    }
                    else
                    {
                        RenderIndent();
                    }

                    // Short name
                    if (optionSchema.ShortName != null)
                    {
                        RenderWithColor($"-{optionSchema.ShortName}", ConsoleColor.White);
                    }

                    // Delimiter
                    if (!string.IsNullOrWhiteSpace(optionSchema.Name) && optionSchema.ShortName != null)
                    {
                        Render("|");
                    }

                    // Name
                    if (!string.IsNullOrWhiteSpace(optionSchema.Name))
                    {
                        RenderWithColor($"--{optionSchema.Name}", ConsoleColor.White);
                    }

                    // Description
                    if (!string.IsNullOrWhiteSpace(optionSchema.Description))
                    {
                        RenderColumnIndent();
                        Render(optionSchema.Description !);
                    }

                    RenderNewLine();
                }
            }

            void RenderChildCommands()
            {
                if (!childCommandSchemas.Any())
                {
                    return;
                }

                // Margin
                RenderMargin();

                // Header
                RenderHeader("Commands");

                // Child commands
                foreach (var childCommandSchema in childCommandSchemas)
                {
                    var relativeCommandName = GetRelativeCommandName(childCommandSchema, source.TargetCommandSchema) !;

                    // Name
                    RenderIndent();
                    RenderWithColor(relativeCommandName, ConsoleColor.Cyan);

                    // Description
                    if (!string.IsNullOrWhiteSpace(childCommandSchema.Description))
                    {
                        RenderColumnIndent();
                        Render(childCommandSchema.Description !);
                    }

                    RenderNewLine();
                }

                // Margin
                RenderMargin();

                // Child command help tip
                Render("You can run `");
                Render(source.ApplicationMetadata.ExecutableName);

                if (!string.IsNullOrWhiteSpace(source.TargetCommandSchema.Name))
                {
                    Render(" ");
                    RenderWithColor(source.TargetCommandSchema.Name, ConsoleColor.Cyan);
                }

                Render(" ");
                RenderWithColor("[command]", ConsoleColor.Cyan);

                Render(" ");
                RenderWithColor("--help", ConsoleColor.White);

                Render("` to show help on a specific command.");

                RenderNewLine();
            }

            // Reset color just in case
            console.ResetColor();

            // Render everything
            RenderApplicationInfo();
            RenderDescription();
            RenderUsage();
            RenderArguments();
            RenderOptions();
            RenderChildCommands();
        }