Closed flobernd closed 5 months ago
Everything written to the console using an IAnsiConsole will already automatically be put above the progress.
Hi @patriksvensson, thanks for the reply. That's not exactly what I'm trying to achieve 🙂 I need something like this:
|= Reticulating splines ---------------------------------------- 63% 00:06:181 -
52438428
1870133191
1511040860
494825954
1900287500
1576363183
934959048
1910108725
1465638547
1366240317
|= Folding space ---------------------------------------- 21% 00:06:179 -
52438428
1870133191
1511040860
494825954
1900287500
1576363183
934959048
1910108725
1465638547
1366240317
This is useful to have output of a task near (in this case below) the corresponding progress bar to allow the user to quickly determine which output belongs to which concurrently running task.
Utilizing the new RenderHook
property, I managed to create a sample application that demonstrates the desired behavior. It's just hacked together, so please don't take too close of a look at the code style. The rows
output is shared for both tasks in this example which of course should not be the case in production.
internal static class Program
{
private static async Task Main()
{
var ri = 0;
var rows = Enumerable.Repeat<IRenderable>(new Text(""), 11).ToArray();
var progress = AnsiConsole.Progress()
.AutoRefresh(true)
.AutoClear(false)
.HideCompleted(false)
.Columns(
new TaskDescriptionColumn(),
new ProgressBarColumn(),
new PercentageColumn(),
new ElapsedTimeMilliColumn(),
new SpinnerColumn()
);
progress.RefreshRate = TimeSpan.FromMilliseconds(50);
progress.RenderHook = RenderHook;
IRenderable RenderHook(IRenderable renderable, IReadOnlyList<ProgressTask> tasks)
{
if (renderable is not Grid layout)
{
return renderable;
}
if (layout.Rows[0][0] is not Grid grid)
{
return renderable;
}
var result = new List<IRenderable>();
var i = 0;
foreach (var row in grid.Rows)
{
var g = new Grid();
foreach (var column in grid.Columns)
{
g.AddColumn(column);
}
g.AddRow([.. row]);
result.Add(g);
if (ri != 0 && !tasks[i].IsFinished)
{
result.Add(new Rows(rows[..(ri + 1)]));
}
++i;
}
var l = new Grid { Expand = true };
l.AddColumn();
l.AddRow(new Rows(result));
return l;
}
AnsiConsole.Clear();
AnsiConsole.MarkupLine("[blue]Elasticsearch.NET[/] Client Generator");
AnsiConsole.WriteLine();
progress
.Start(ctx =>
{
// Define tasks
var task1 = ctx.AddTask("[green]|= Reticulating splines[/]");
var task2 = ctx.AddTask("[green]|= Folding space[/]");
while (!ctx.IsFinished)
{
// Simulate some work
Task.Delay(50).Wait();
// Increment
task1.Increment(1.5);
task2.Increment(0.5);
if (ri == 10)
{
for (var i = 1; i < 10; ++i)
{
rows[i - 1] = rows[i];
}
ri = 9;
}
rows[ri++] = new Text($"{new Random((int)DateTime.Now.Ticks).Next()}");
}
ctx.Refresh();
});
// Fixme: Empty lines between the last progress bar and "test"
AnsiConsole.WriteLine("test");
}
}
I would as well offer to create a PR, if this functionality is something you would consider adding 🙂
Since this is a very niche thing, and nothing that we're really planning the progress bars to support, I think this would make an excellent addition as a external Spectre.Console extension.
Hi @patriksvensson, no problem. This will however result in a lot of duplicate code I'm afraid.
Closing this feature request as not planned.
Is your feature request related to a problem? Please describe.
I would like to display live log output individually for each progress task - similar to what Docker does when building an image.
Describe the solution you'd like
ProgressTask
should provide aWriteLine
method that allows to output log strings to the console. These log strings should be displayed below the progress bar. The log area for each progress task should have a (configurable) fixed height of e.g. 10 lines. After exceeding the maximum, text should start to scroll out of the screen.As an alternative,
ProgressTask
could contain aRows
component which would allow the user to dynamically add- or remove lines while the task is running.Please upvote :+1: this issue if you are interested in it.