mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-14 16:02: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>
|
||||
/// Gets a value indicating whether or not all started tasks have completed.
|
||||
/// </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)
|
||||
{
|
||||
@ -33,11 +42,68 @@ public sealed class ProgressContext
|
||||
/// <returns>The newly created task.</returns>
|
||||
public ProgressTask AddTask(string description, bool autoStart = true, double maxValue = 100)
|
||||
{
|
||||
return AddTask(description, new ProgressTaskSettings
|
||||
lock (_taskLock)
|
||||
{
|
||||
AutoStart = autoStart,
|
||||
MaxValue = maxValue,
|
||||
});
|
||||
var settings = new ProgressTaskSettings { AutoStart = autoStart, 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>
|
||||
@ -48,18 +114,58 @@ public sealed class ProgressContext
|
||||
/// <returns>The newly created task.</returns>
|
||||
public ProgressTask AddTask(string description, ProgressTaskSettings settings)
|
||||
{
|
||||
if (settings is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(settings));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
lock (_taskLock)
|
||||
@ -79,4 +199,4 @@ public sealed class ProgressContext
|
||||
return new List<ProgressTask>(_tasks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -263,4 +263,82 @@ public sealed class ProgressTests
|
||||
// Then
|
||||
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