Skip to content

Instantly share code, notes, and snippets.

@Tensorr
Forked from DanielSWolf/Program.cs
Created January 27, 2017 00:26
Show Gist options
  • Save Tensorr/c39bd9562ead0600eaedca554c36b0df to your computer and use it in GitHub Desktop.
Save Tensorr/c39bd9562ead0600eaedca554c36b0df to your computer and use it in GitHub Desktop.

Revisions

  1. @DanielSWolf DanielSWolf revised this gist Jul 25, 2015. No changes.
  2. @DanielSWolf DanielSWolf revised this gist Jul 25, 2015. No changes.
  3. @DanielSWolf DanielSWolf revised this gist Jul 25, 2015. No changes.
  4. @DanielSWolf DanielSWolf revised this gist Jul 2, 2015. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions Program.cs
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,6 @@
    static class Program {

    static void Main() {
    Thread.Sleep(5000);
    Console.Write("Performing some task... ");
    using (var progress = new ProgressBar()) {
    for (int i = 0; i <= 100; i++) {
    @@ -13,7 +12,6 @@ static void Main() {
    }
    }
    Console.WriteLine("Done.");
    Console.ReadLine();
    }

    }
  5. @DanielSWolf DanielSWolf created this gist Jul 2, 2015.
    19 changes: 19 additions & 0 deletions Program.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    using System;
    using System.Threading;

    static class Program {

    static void Main() {
    Thread.Sleep(5000);
    Console.Write("Performing some task... ");
    using (var progress = new ProgressBar()) {
    for (int i = 0; i <= 100; i++) {
    progress.Report((double) i / 100);
    Thread.Sleep(20);
    }
    }
    Console.WriteLine("Done.");
    Console.ReadLine();
    }

    }
    90 changes: 90 additions & 0 deletions ProgressBar.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,90 @@
    using System;
    using System.Text;
    using System.Threading;

    /// <summary>
    /// An ASCII progress bar
    /// </summary>
    public class ProgressBar : IDisposable, IProgress<double> {
    private const int blockCount = 10;
    private readonly TimeSpan animationInterval = TimeSpan.FromSeconds(1.0 / 8);
    private const string animation = @"|/-\";

    private readonly Timer timer;

    private double currentProgress = 0;
    private string currentText = string.Empty;
    private bool disposed = false;
    private int animationIndex = 0;

    public ProgressBar() {
    timer = new Timer(TimerHandler);

    // A progress bar is only for temporary display in a console window.
    // If the console output is redirected to a file, draw nothing.
    // Otherwise, we'll end up with a lot of garbage in the target file.
    if (!Console.IsOutputRedirected) {
    ResetTimer();
    }
    }

    public void Report(double value) {
    // Make sure value is in [0..1] range
    value = Math.Max(0, Math.Min(1, value));
    Interlocked.Exchange(ref currentProgress, value);
    }

    private void TimerHandler(object state) {
    lock (timer) {
    if (disposed) return;

    int progressBlockCount = (int) (currentProgress * blockCount);
    int percent = (int) (currentProgress * 100);
    string text = string.Format("[{0}{1}] {2,3}% {3}",
    new string('#', progressBlockCount), new string('-', blockCount - progressBlockCount),
    percent,
    animation[animationIndex++ % animation.Length]);
    UpdateText(text);

    ResetTimer();
    }
    }

    private void UpdateText(string text) {
    // Get length of common portion
    int commonPrefixLength = 0;
    int commonLength = Math.Min(currentText.Length, text.Length);
    while (commonPrefixLength < commonLength && text[commonPrefixLength] == currentText[commonPrefixLength]) {
    commonPrefixLength++;
    }

    // Backtrack to the first differing character
    StringBuilder outputBuilder = new StringBuilder();
    outputBuilder.Append('\b', currentText.Length - commonPrefixLength);

    // Output new suffix
    outputBuilder.Append(text.Substring(commonPrefixLength));

    // If the new text is shorter than the old one: delete overlapping characters
    int overlapCount = currentText.Length - text.Length;
    if (overlapCount > 0) {
    outputBuilder.Append(' ', overlapCount);
    outputBuilder.Append('\b', overlapCount);
    }

    Console.Write(outputBuilder);
    currentText = text;
    }

    private void ResetTimer() {
    timer.Change(animationInterval, TimeSpan.FromMilliseconds(-1));
    }

    public void Dispose() {
    lock (timer) {
    disposed = true;
    UpdateText(string.Empty);
    }
    }

    }