using System; using System.Collections.Generic; using System.Threading.Tasks; using Spectre.Console.Internal; using Spectre.Console.Rendering; namespace Spectre.Console { /// /// Represents a task list. /// public sealed class Progress { private readonly IAnsiConsole _console; /// /// Gets or sets a value indicating whether or not task list should auto refresh. /// Defaults to true. /// public bool AutoRefresh { get; set; } = true; /// /// Gets or sets a value indicating whether or not the task list should /// be cleared once it completes. /// Defaults to false. /// public bool AutoClear { get; set; } /// /// Gets or sets the refresh rate if AutoRefresh is enabled. /// Defaults to 10 times/second. /// public TimeSpan RefreshRate { get; set; } = TimeSpan.FromMilliseconds(100); internal List Columns { get; } internal ProgressRenderer? FallbackRenderer { get; set; } /// /// Initializes a new instance of the class. /// /// The console to render to. public Progress(IAnsiConsole console) { _console = console ?? throw new ArgumentNullException(nameof(console)); // Initialize with default columns Columns = new List { new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn(), }; } /// /// Starts the progress task list. /// /// The action to execute. public void Start(Action action) { var task = StartAsync(ctx => { action(ctx); return Task.CompletedTask; }); task.GetAwaiter().GetResult(); } /// /// Starts the progress task list and returns a result. /// /// The result type. /// he action to execute. /// The result. public T Start(Func func) { var task = StartAsync(ctx => Task.FromResult(func(ctx))); return task.GetAwaiter().GetResult(); } /// /// Starts the progress task list. /// /// The action to execute. /// A representing the asynchronous operation. public async Task StartAsync(Func action) { if (action is null) { throw new ArgumentNullException(nameof(action)); } _ = await StartAsync(async progressContext => { await action(progressContext).ConfigureAwait(false); return default; }).ConfigureAwait(false); } /// /// Starts the progress task list and returns a result. /// /// The action to execute. /// The result type of task. /// A representing the asynchronous operation. public async Task StartAsync(Func> action) { if (action is null) { throw new ArgumentNullException(nameof(action)); } var renderer = CreateRenderer(); renderer.Started(); T result; try { using (new RenderHookScope(_console, renderer)) { var context = new ProgressContext(_console, renderer); if (AutoRefresh) { using (var thread = new ProgressRefreshThread(context, renderer.RefreshRate)) { result = await action(context).ConfigureAwait(false); } } else { result = await action(context).ConfigureAwait(false); } context.Refresh(); } } finally { renderer.Completed(AutoClear); } return result; } private ProgressRenderer CreateRenderer() { var caps = _console.Capabilities; var interactive = caps.SupportsInteraction && caps.SupportsAnsi; if (interactive) { var columns = new List(Columns); return new DefaultProgressRenderer(_console, columns, RefreshRate); } else { return FallbackRenderer ?? new FallbackProgressRenderer(); } } } }