mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 08:52:50 +08:00
Positioned Progress Tasks - Before or After Other Tasks (#1250)
This commit is contained in:
parent
5acd83a3ef
commit
d921ac6f02
@ -14,7 +14,16 @@ public sealed class ProgressContext
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether or not all started tasks have completed.
|
/// Gets a value indicating whether or not all started tasks have completed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsFinished => _tasks.Where(x => x.IsStarted).All(task => task.IsFinished);
|
public bool IsFinished
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_taskLock)
|
||||||
|
{
|
||||||
|
return _tasks.Where(x => x.IsStarted).All(task => task.IsFinished);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal ProgressContext(IAnsiConsole console, ProgressRenderer renderer)
|
internal ProgressContext(IAnsiConsole console, ProgressRenderer renderer)
|
||||||
{
|
{
|
||||||
@ -33,11 +42,68 @@ public sealed class ProgressContext
|
|||||||
/// <returns>The newly created task.</returns>
|
/// <returns>The newly created task.</returns>
|
||||||
public ProgressTask AddTask(string description, bool autoStart = true, double maxValue = 100)
|
public ProgressTask AddTask(string description, bool autoStart = true, double maxValue = 100)
|
||||||
{
|
{
|
||||||
return AddTask(description, new ProgressTaskSettings
|
lock (_taskLock)
|
||||||
{
|
{
|
||||||
AutoStart = autoStart,
|
var settings = new ProgressTaskSettings { AutoStart = autoStart, MaxValue = maxValue, };
|
||||||
MaxValue = maxValue,
|
|
||||||
});
|
return AddTaskAtInternal(description, settings, _tasks.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a task.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="description">The task description.</param>
|
||||||
|
/// <param name="index">The index at which the task should be inserted.</param>
|
||||||
|
/// <param name="autoStart">Whether or not the task should start immediately.</param>
|
||||||
|
/// <param name="maxValue">The task's max value.</param>
|
||||||
|
/// <returns>The newly created task.</returns>
|
||||||
|
public ProgressTask AddTaskAt(string description, int index, bool autoStart = true, double maxValue = 100)
|
||||||
|
{
|
||||||
|
lock (_taskLock)
|
||||||
|
{
|
||||||
|
var settings = new ProgressTaskSettings { AutoStart = autoStart, MaxValue = maxValue, };
|
||||||
|
|
||||||
|
return AddTaskAtInternal(description, settings, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a task before the reference task.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="description">The task description.</param>
|
||||||
|
/// <param name="referenceProgressTask">The reference task to add before.</param>
|
||||||
|
/// <param name="autoStart">Whether or not the task should start immediately.</param>
|
||||||
|
/// <param name="maxValue">The task's max value.</param>
|
||||||
|
/// <returns>The newly created task.</returns>
|
||||||
|
public ProgressTask AddTaskBefore(string description, ProgressTask referenceProgressTask, bool autoStart = true, double maxValue = 100)
|
||||||
|
{
|
||||||
|
lock (_taskLock)
|
||||||
|
{
|
||||||
|
var settings = new ProgressTaskSettings { AutoStart = autoStart, MaxValue = maxValue, };
|
||||||
|
var indexOfReference = _tasks.IndexOf(referenceProgressTask);
|
||||||
|
|
||||||
|
return AddTaskAtInternal(description, settings, indexOfReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a task after the reference task.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="description">The task description.</param>
|
||||||
|
/// <param name="referenceProgressTask">The reference task to add after.</param>
|
||||||
|
/// <param name="autoStart">Whether or not the task should start immediately.</param>
|
||||||
|
/// <param name="maxValue">The task's max value.</param>
|
||||||
|
/// <returns>The newly created task.</returns>
|
||||||
|
public ProgressTask AddTaskAfter(string description, ProgressTask referenceProgressTask, bool autoStart = true, double maxValue = 100)
|
||||||
|
{
|
||||||
|
lock (_taskLock)
|
||||||
|
{
|
||||||
|
var settings = new ProgressTaskSettings { AutoStart = autoStart, MaxValue = maxValue, };
|
||||||
|
var indexOfReference = _tasks.IndexOf(referenceProgressTask);
|
||||||
|
|
||||||
|
return AddTaskAtInternal(description, settings, indexOfReference + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -48,18 +114,58 @@ public sealed class ProgressContext
|
|||||||
/// <returns>The newly created task.</returns>
|
/// <returns>The newly created task.</returns>
|
||||||
public ProgressTask AddTask(string description, ProgressTaskSettings settings)
|
public ProgressTask AddTask(string description, ProgressTaskSettings settings)
|
||||||
{
|
{
|
||||||
if (settings is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(settings));
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_taskLock)
|
lock (_taskLock)
|
||||||
{
|
{
|
||||||
var task = new ProgressTask(_taskId++, description, settings.MaxValue, settings.AutoStart);
|
return AddTaskAtInternal(description, settings, _tasks.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_tasks.Add(task);
|
/// <summary>
|
||||||
|
/// Adds a task at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="description">The task description.</param>
|
||||||
|
/// <param name="settings">The task settings.</param>
|
||||||
|
/// <param name="index">The index at which the task should be inserted.</param>
|
||||||
|
/// <returns>The newly created task.</returns>
|
||||||
|
public ProgressTask AddTaskAt(string description, ProgressTaskSettings settings, int index)
|
||||||
|
{
|
||||||
|
lock (_taskLock)
|
||||||
|
{
|
||||||
|
return AddTaskAtInternal(description, settings, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return task;
|
/// <summary>
|
||||||
|
/// Adds a task before the reference task.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="description">The task description.</param>
|
||||||
|
/// <param name="settings">The task settings.</param>
|
||||||
|
/// <param name="referenceProgressTask">The reference task to add before.</param>
|
||||||
|
/// <returns>The newly created task.</returns>
|
||||||
|
public ProgressTask AddTaskBefore(string description, ProgressTaskSettings settings, ProgressTask referenceProgressTask)
|
||||||
|
{
|
||||||
|
lock (_taskLock)
|
||||||
|
{
|
||||||
|
var indexOfReference = _tasks.IndexOf(referenceProgressTask);
|
||||||
|
|
||||||
|
return AddTaskAtInternal(description, settings, indexOfReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a task after the reference task.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="description">The task description.</param>
|
||||||
|
/// <param name="settings">The task settings.</param>
|
||||||
|
/// <param name="referenceProgressTask">The reference task to add after.</param>
|
||||||
|
/// <returns>The newly created task.</returns>
|
||||||
|
public ProgressTask AddTaskAfter(string description, ProgressTaskSettings settings, ProgressTask referenceProgressTask)
|
||||||
|
{
|
||||||
|
lock (_taskLock)
|
||||||
|
{
|
||||||
|
var indexOfReference = _tasks.IndexOf(referenceProgressTask);
|
||||||
|
|
||||||
|
return AddTaskAtInternal(description, settings, indexOfReference + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +178,20 @@ public sealed class ProgressContext
|
|||||||
_console.Write(new ControlCode(string.Empty));
|
_console.Write(new ControlCode(string.Empty));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ProgressTask AddTaskAtInternal(string description, ProgressTaskSettings settings, int position)
|
||||||
|
{
|
||||||
|
if (settings is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(settings));
|
||||||
|
}
|
||||||
|
|
||||||
|
var task = new ProgressTask(_taskId++, description, settings.MaxValue, settings.AutoStart);
|
||||||
|
|
||||||
|
_tasks.Insert(position, task);
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
internal IReadOnlyList<ProgressTask> GetTasks()
|
internal IReadOnlyList<ProgressTask> GetTasks()
|
||||||
{
|
{
|
||||||
lock (_taskLock)
|
lock (_taskLock)
|
||||||
|
@ -263,4 +263,82 @@ public sealed class ProgressTests
|
|||||||
// Then
|
// Then
|
||||||
task.RemainingTime.ShouldBe(TimeSpan.MaxValue);
|
task.RemainingTime.ShouldBe(TimeSpan.MaxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Should_Render_Tasks_Added_Before_And_After_Correctly()
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
var console = new TestConsole()
|
||||||
|
.Width(10)
|
||||||
|
.Interactive()
|
||||||
|
.EmitAnsiSequences();
|
||||||
|
|
||||||
|
var progress = new Progress(console)
|
||||||
|
.Columns(new TaskDescriptionColumn())
|
||||||
|
.AutoRefresh(false)
|
||||||
|
.AutoClear(true);
|
||||||
|
|
||||||
|
// When
|
||||||
|
progress.Start(ctx =>
|
||||||
|
{
|
||||||
|
var foo1 = ctx.AddTask("foo1");
|
||||||
|
var foo2 = ctx.AddTask("foo2");
|
||||||
|
var foo3 = ctx.AddTask("foo3");
|
||||||
|
|
||||||
|
var afterFoo1 = ctx.AddTaskAfter("afterFoo1", foo1);
|
||||||
|
var beforeFoo3 = ctx.AddTaskBefore("beforeFoo3", foo3);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Then
|
||||||
|
console.Output.SplitLines().Select(x => x.Trim()).ToArray()
|
||||||
|
.ShouldBeEquivalentTo(new[]
|
||||||
|
{
|
||||||
|
"[?25l",
|
||||||
|
"foo1",
|
||||||
|
"afterFoo1",
|
||||||
|
"foo2",
|
||||||
|
"beforeFoo3",
|
||||||
|
"foo3",
|
||||||
|
"[2K[1A[2K[1A[2K[1A[2K[1A[2K[1A[2K[1A[2K[?25h",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Should_Render_Tasks_At_Specified_Indexes_Correctly()
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
var console = new TestConsole()
|
||||||
|
.Width(10)
|
||||||
|
.Interactive()
|
||||||
|
.EmitAnsiSequences();
|
||||||
|
|
||||||
|
var progress = new Progress(console)
|
||||||
|
.Columns(new TaskDescriptionColumn())
|
||||||
|
.AutoRefresh(false)
|
||||||
|
.AutoClear(true);
|
||||||
|
|
||||||
|
// When
|
||||||
|
progress.Start(ctx =>
|
||||||
|
{
|
||||||
|
var foo1 = ctx.AddTask("foo1");
|
||||||
|
var foo2 = ctx.AddTask("foo2");
|
||||||
|
var foo3 = ctx.AddTask("foo3");
|
||||||
|
|
||||||
|
var afterFoo1 = ctx.AddTaskAt("afterFoo1", 1);
|
||||||
|
var beforeFoo3 = ctx.AddTaskAt("beforeFoo3", 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Then
|
||||||
|
console.Output.SplitLines().Select(x => x.Trim()).ToArray()
|
||||||
|
.ShouldBeEquivalentTo(new[]
|
||||||
|
{
|
||||||
|
"[?25l",
|
||||||
|
"foo1",
|
||||||
|
"afterFoo1",
|
||||||
|
"foo2",
|
||||||
|
"beforeFoo3",
|
||||||
|
"foo3",
|
||||||
|
"[2K[1A[2K[1A[2K[1A[2K[1A[2K[1A[2K[1A[2K[?25h",
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user