Created
March 26, 2020 16:41
-
-
Save cdiggins/102164183f6a3ad166c225a924abc47a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using Vim.Logger; | |
namespace Vim.DotNetUtilities | |
{ | |
/// <summary> | |
/// This interface is different from the IProgress<T> class in the system library | |
/// https://docs.microsoft.com/en-us/dotnet/api/system.iprogress-1?view=netframework-4.8 | |
/// It was designed to simplify the use case of percentage reporting where the number of steps | |
/// is known in advance, and each step simply advances the counter by "1", and the percentage | |
/// can be reported easily. The goal is for the progress reporting to just have to | |
/// call an "Update()" extension method multiple times with no values and have it "just" work. | |
/// More sophisticated scenarios are possible, if the current status can be completed precisely. | |
/// This implements IDisposable so that cancelation and completion can properly clean up resources, | |
/// and communicates that the progress is over. | |
/// </summary> | |
public interface IProgress : IDisposable | |
{ | |
float Total { get; } | |
float Current { get; } | |
void Update(float current, string message); | |
} | |
public static class ProgressExtensions | |
{ | |
public static void NextStep(this IProgress progress, string message = "", float stepSize = 1f) | |
{ | |
progress.Update(progress.Current + stepSize, message); | |
} | |
public static void Complete(this IProgress progress, string message = "") | |
{ | |
progress.Update(progress.Total, message); | |
progress.Dispose(); | |
} | |
public static void Cancel(this IProgress progress, string message = "") | |
{ | |
progress.Update(progress.Current, message); | |
progress.Dispose(); | |
} | |
public static IProgress SubProgress(this IProgress progress, float total, string message, float parentStepSize = 1) | |
{ | |
if (progress == null) return null; | |
var r = new SubProgress(progress, total, parentStepSize); | |
r.NextStep(message, 0f); | |
return r; | |
} | |
} | |
public sealed class IndeterminateProgress : IProgress | |
{ | |
public float Total => 1f; | |
public float Current => 1f; | |
public Action<string> OnUpdate { get; } | |
public Action OnComplete { get; } | |
public IndeterminateProgress(Action<string> update, Action completed = null) | |
=> (OnUpdate, OnComplete) = (update, completed); | |
public void Dispose() | |
=> OnComplete?.Invoke(); | |
public void Update(float current, string message) | |
=> OnUpdate?.Invoke(message); | |
} | |
public class StdProgress : IProgress | |
{ | |
public float Total { get; set; } | |
public float Current { get; set; } | |
public Action<StdProgress> Action { get; set; } | |
public string LastMessage { get; set; } | |
public long LastTime { get; set; } | |
public Stopwatch Stopwatch { get; } = new Stopwatch(); | |
public float LastProgressPercentage { get; set; } | |
public float ProgressPercentage => Current / Total; | |
public StdProgress(float total = 1f, Action<StdProgress> action = null) | |
{ | |
Stopwatch.Start(); | |
Total = total; | |
Action = action; | |
} | |
public virtual void Update(float current, string message) | |
{ | |
LastTime = Stopwatch.ElapsedMilliseconds; | |
LastMessage = message; | |
Current = current; | |
// Only update every 1% of the time. More often is too much | |
if (ProgressPercentage - LastProgressPercentage >= 0.01f) | |
{ | |
LastProgressPercentage = ProgressPercentage; | |
Action?.Invoke(this); | |
} | |
} | |
public void Dispose() | |
{ } | |
} | |
public class StdLoggingProgress : StdProgress | |
{ | |
public ILogger Logger; | |
public StdLoggingProgress(float total, ILogger logger = null) | |
: base(total) | |
{ | |
Logger = logger ?? new StdLogger(); | |
Action = (progress) => Logger.Log(progress.LastMessage); | |
} | |
} | |
public sealed class SubProgress : IProgress | |
{ | |
public float Total { get; set; } | |
public float Current { get; set; } | |
public IProgress Parent { get; } | |
public float ParentCurrent { get; set; } | |
public float ParentStepSize { get; set; } | |
public SubProgress(IProgress parent, float total, float parentStepSize = 1) | |
{ | |
Parent = parent; | |
Total = total; | |
ParentCurrent = parent.Current; | |
ParentStepSize = parentStepSize; | |
} | |
public void Update(float current, string message) | |
{ | |
Current = current; | |
Parent.Update(ParentCurrent + (Current / Total) * ParentStepSize, message); | |
} | |
public void Dispose() | |
{ | |
Parent.Dispose(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment