spectre.console
spectre.console copied to clipboard
Automatically stop ProgressTask when the underlying operation completes
Is your feature request related to a problem? Please describe.
Progress provides a method called StartAsync(...) that wraps an operation and exposes ProgressContext:
https://github.com/spectresystems/spectre.console/blob/b17eabaa1f67210da8992531d90382277bc116b8/src/Spectre.Console/Widgets/Progress/Progress.cs#L114-L156
Perhaps it would be nice to provide a similar method on ProgressContext itself. This would allow users to do the following:
await AnsiConsole.Progress().StartAsync(async progressContext =>
{
// Create the task and wrap an operation
await progressContext.StartAsync("My task", async progressTask =>
{
for (var i = 1; i <= 10; i++)
{
await Task.Delay(100);
progressTask.Value = 100 * (i / 10);
}
});
});
Under the hood, ProgressTask.StartAsync(...) should also have a try/finally block to automatically stop the task when the underlying operation completes (even if the operation doesn't report progress till the end). Currently, this has to be done manually by the user.
Additionally, if #314 is implemented, it would also make sense to handle catch clause and report the task as failed, in case the underlying operation throws an exception.
Describe alternatives you've considered
Another alternative would be to make ProgressTask implement IDisposable. That way disposing a task would mark is as complete and it would simplify the usage for the user:
await AnsiConsole.Progress().StartAsync(async progressContext =>
{
// Will dispose at the end, marking itself complete
using var progressTask = progressContext.AddTask("My task");
for (var i = 1; i <= 10; i++)
{
await Task.Delay(100);
progressTask.Value = 100 * (i / 10);
}
});
However, this would not allow to easily mark the task as failed based on exception (for #314).
Besides that, it would introduce inconsistency, as Progress already uses the delegate approach in Start(...)/StartAsync(....).