mirror of
				https://github.com/nsnail/spectre.console.git
				synced 2025-11-01 01:25:27 +08:00 
			
		
		
		
	Positioned Progress Tasks - Before or After Other Tasks (#1250)
This commit is contained in:
		| @@ -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", | ||||
|             }); | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Tom Longhurst
					Tom Longhurst