mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 08:52:50 +08:00
154 lines
4.5 KiB
C#
154 lines
4.5 KiB
C#
namespace Spectre.Console.Cli;
|
|
|
|
/// <summary>
|
|
/// The entry point for a command line application.
|
|
/// </summary>
|
|
public sealed class CommandApp : ICommandApp
|
|
{
|
|
private readonly Configurator _configurator;
|
|
private readonly CommandExecutor _executor;
|
|
private bool _executed;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="CommandApp"/> class.
|
|
/// </summary>
|
|
/// <param name="registrar">The registrar.</param>
|
|
public CommandApp(ITypeRegistrar? registrar = null)
|
|
{
|
|
registrar ??= new DefaultTypeRegistrar();
|
|
|
|
_configurator = new Configurator(registrar);
|
|
_executor = new CommandExecutor(registrar);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Configures the command line application.
|
|
/// </summary>
|
|
/// <param name="configuration">The configuration.</param>
|
|
public void Configure(Action<IConfigurator> configuration)
|
|
{
|
|
if (configuration == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(configuration));
|
|
}
|
|
|
|
configuration(_configurator);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the default command.
|
|
/// </summary>
|
|
/// <typeparam name="TCommand">The command type.</typeparam>
|
|
public void SetDefaultCommand<TCommand>()
|
|
where TCommand : class, ICommand
|
|
{
|
|
GetConfigurator().SetDefaultCommand<TCommand>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Runs the command line application with specified arguments.
|
|
/// </summary>
|
|
/// <param name="args">The arguments.</param>
|
|
/// <returns>The exit code from the executed command.</returns>
|
|
public int Run(IEnumerable<string> args)
|
|
{
|
|
return RunAsync(args).GetAwaiter().GetResult();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Runs the command line application with specified arguments.
|
|
/// </summary>
|
|
/// <param name="args">The arguments.</param>
|
|
/// <returns>The exit code from the executed command.</returns>
|
|
public async Task<int> RunAsync(IEnumerable<string> args)
|
|
{
|
|
try
|
|
{
|
|
if (!_executed)
|
|
{
|
|
// Add built-in (hidden) commands.
|
|
_configurator.AddBranch(CliConstants.Commands.Branch, cli =>
|
|
{
|
|
cli.HideBranch();
|
|
cli.AddCommand<VersionCommand>(CliConstants.Commands.Version);
|
|
cli.AddCommand<XmlDocCommand>(CliConstants.Commands.XmlDoc);
|
|
cli.AddCommand<ExplainCommand>(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<IRenderable?>? GetRenderableErrorMessage(Exception ex, bool convert = true)
|
|
{
|
|
if (ex is CommandAppException renderable && renderable.Pretty != null)
|
|
{
|
|
return new List<IRenderable?> { renderable.Pretty };
|
|
}
|
|
|
|
if (convert)
|
|
{
|
|
var converted = new List<IRenderable?>
|
|
{
|
|
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;
|
|
}
|
|
} |