Skip to content

Commit

Permalink
Positioned Progress Tasks - Before or After Other Tasks
Browse files Browse the repository at this point in the history
  • Loading branch information
thomhurst committed Jun 29, 2023
1 parent e0ded71 commit 8e9e2f9
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 4 deletions.
105 changes: 101 additions & 4 deletions src/Spectre.Console/Live/Progress/ProgressContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -40,6 +49,40 @@ public ProgressTask AddTask(string description, bool autoStart = true, double ma
});
}

/// <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)
{
return AddTaskBefore(description, new ProgressTaskSettings
{
AutoStart = autoStart,
MaxValue = maxValue,
}, referenceProgressTask);
}

/// <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)
{
return AddTaskAfter(description, new ProgressTaskSettings
{
AutoStart = autoStart,
MaxValue = maxValue,
}, referenceProgressTask);
}

/// <summary>
/// Adds a task.
/// </summary>
Expand All @@ -55,11 +98,51 @@ public ProgressTask AddTask(string description, ProgressTaskSettings settings)

lock (_taskLock)
{
var task = new ProgressTask(_taskId++, description, settings.MaxValue, settings.AutoStart);
return AddTaskAt(description, settings, _tasks.Count);
}
}

/// <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)
{
if (settings is null)
{
throw new ArgumentNullException(nameof(settings));
}

lock (_taskLock)
{
var indexOfReference = _tasks.IndexOf(referenceProgressTask);

_tasks.Add(task);
return AddTaskAt(description, settings, indexOfReference);
}
}

return task;
/// <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 before</param>

Check failure on line 132 in src/Spectre.Console/Live/Progress/ProgressContext.cs

View workflow job for this annotation

GitHub Actions / Build (linux)

Documentation text should end with a period

Check failure on line 132 in src/Spectre.Console/Live/Progress/ProgressContext.cs

View workflow job for this annotation

GitHub Actions / Build (linux)

Documentation text should end with a period

Check failure on line 132 in src/Spectre.Console/Live/Progress/ProgressContext.cs

View workflow job for this annotation

GitHub Actions / Build (linux)

Documentation text should end with a period

Check failure on line 132 in src/Spectre.Console/Live/Progress/ProgressContext.cs

View workflow job for this annotation

GitHub Actions / Build (linux)

Documentation text should end with a period

Check failure on line 132 in src/Spectre.Console/Live/Progress/ProgressContext.cs

View workflow job for this annotation

GitHub Actions / Build (linux)

Documentation text should end with a period

Check failure on line 132 in src/Spectre.Console/Live/Progress/ProgressContext.cs

View workflow job for this annotation

GitHub Actions / Build (linux)

Documentation text should end with a period

Check failure on line 132 in src/Spectre.Console/Live/Progress/ProgressContext.cs

View workflow job for this annotation

GitHub Actions / Build (macOS)

Documentation text should end with a period

Check failure on line 132 in src/Spectre.Console/Live/Progress/ProgressContext.cs

View workflow job for this annotation

GitHub Actions / Build (macOS)

Documentation text should end with a period

Check failure on line 132 in src/Spectre.Console/Live/Progress/ProgressContext.cs

View workflow job for this annotation

GitHub Actions / Build (macOS)

Documentation text should end with a period

Check failure on line 132 in src/Spectre.Console/Live/Progress/ProgressContext.cs

View workflow job for this annotation

GitHub Actions / Build (macOS)

Documentation text should end with a period

Check failure on line 132 in src/Spectre.Console/Live/Progress/ProgressContext.cs

View workflow job for this annotation

GitHub Actions / Build (macOS)

Documentation text should end with a period

Check failure on line 132 in src/Spectre.Console/Live/Progress/ProgressContext.cs

View workflow job for this annotation

GitHub Actions / Build (macOS)

Documentation text should end with a period
/// <returns>The newly created task.</returns>
public ProgressTask AddTaskAfter(string description, ProgressTaskSettings settings, ProgressTask referenceProgressTask)
{
if (settings is null)
{
throw new ArgumentNullException(nameof(settings));
}

lock (_taskLock)
{
var indexOfReference = _tasks.IndexOf(referenceProgressTask);

return AddTaskAt(description, settings, indexOfReference + 1);
}
}

Expand All @@ -72,6 +155,20 @@ public void Refresh()
_console.Write(new ControlCode(string.Empty));
}

private ProgressTask AddTaskAt(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)
Expand Down
40 changes: 40 additions & 0 deletions test/Spectre.Console.Tests/Unit/Live/Progress/ProgressTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,44 @@ public void Should_Report_Max_Remaining_Time_For_Extremely_Small_Progress()
// 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[] { new ProgressBarColumn() })
.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
.NormalizeLineEndings()
.ShouldBe(
"[?25l" // Hide cursor
+ " \n" // Top padding
+ "━━━━━━━━━━\n" // Task
+ "━━━━━━━━━━\n" // Task
+ "━━━━━━━━━━\n" // Task
+ "━━━━━━━━━━\n" // Task
+ "━━━━━━━━━━\n" // Task
+ " " // Bottom padding
+ "[?25h"); // Clear + show cursor
}
}

0 comments on commit 8e9e2f9

Please sign in to comment.