namespace Spectre.Console.Cli; /// /// The entry point for a command line application. /// public sealed class CommandApp : ICommandApp { private readonly Configurator _configurator; private readonly CommandExecutor _executor; private bool _executed; /// /// Initializes a new instance of the class. /// /// The registrar. public CommandApp(ITypeRegistrar? registrar = null) { registrar ??= new DefaultTypeRegistrar(); _configurator = new Configurator(registrar); _executor = new CommandExecutor(registrar); } /// /// Configures the command line application. /// /// The configuration. public void Configure(Action configuration) { if (configuration == null) { throw new ArgumentNullException(nameof(configuration)); } configuration(_configurator); } /// /// Sets the default command. /// /// The command type. public void SetDefaultCommand() where TCommand : class, ICommand { GetConfigurator().SetDefaultCommand(); } /// /// Runs the command line application with specified arguments. /// /// The arguments. /// The exit code from the executed command. public int Run(IEnumerable args) { return RunAsync(args).GetAwaiter().GetResult(); } /// /// Runs the command line application with specified arguments. /// /// The arguments. /// The exit code from the executed command. public async Task RunAsync(IEnumerable args) { try { if (!_executed) { // Add built-in (hidden) commands. _configurator.AddBranch(CliConstants.Commands.Branch, cli => { cli.HideBranch(); cli.AddCommand(CliConstants.Commands.Version); cli.AddCommand(CliConstants.Commands.XmlDoc); cli.AddCommand(CliConstants.Commands.Explain); }); _executed = true; } return await _executor .Execute(_configurator, args) .ConfigureAwait(false); } catch (Exception ex) { // Should we always propagate when debugging? if (Debugger.IsAttached && ex is CommandAppException appException && appException.AlwaysPropagateWhenDebugging) { throw; } if (_configurator.Settings.PropagateExceptions) { throw; } if (_configurator.Settings.ExceptionHandler != null) { return _configurator.Settings.ExceptionHandler(ex); } // Render the exception. var pretty = GetRenderableErrorMessage(ex); if (pretty != null) { _configurator.Settings.Console.SafeRender(pretty); } return -1; } } internal Configurator GetConfigurator() { return _configurator; } private static List? GetRenderableErrorMessage(Exception ex, bool convert = true) { if (ex is CommandAppException renderable && renderable.Pretty != null) { return new List { renderable.Pretty }; } if (convert) { var converted = new List { new Composer() .Text("[red]Error:[/]") .Space() .Text(ex.Message.EscapeMarkup()) .LineBreak(), }; // Got a renderable inner exception? if (ex.InnerException != null) { var innerRenderable = GetRenderableErrorMessage(ex.InnerException, convert: false); if (innerRenderable != null) { converted.AddRange(innerRenderable); } } return converted; } return null; } }