Showing Progress in a Console Windows

Recently I needed to show some progress indicator on some long running console application.  I recall the good old days of my college days with console based SMTP clients such as elm and pine… as I recall these clients showed progress via a simple ASCII spiner.    

I was impressed with how simple this is to do with .NET Framework 2.0.. I started off writing the usage code I wanted to enable, then built a simple class that meet those requirements.. I highly recommend this process especially for more complex designs.
Here is the client code: 

        static void Main(string[] args)
            ConsoleSpiner spin 
= new ConsoleSpiner()


And here is the class I came up with. 

    public class ConsoleSpiner
int counter
public void 
(counter % 4
case 0: Console.Write(“/”)
; break;
1: Console.Write(“-“)
; break;
2: Console.Write(“\\”)
; break;
3: Console.Write(“-“)
; break;
            Console.SetCursorPosition(Console.CursorLeft – 
1, Console.CursorTop)

PS – does anyone still use elm\pine?  Are their clients that work with exchange?  Also, I was always told that pine was an acronym for “Pine Is Not Elm”, but accounting to the official site it is not. 

Comments (27)

  1. > I was always told that pine was an

    > acronym for “Pine Is Not Elm”,

    That’s one of those nasty chicken and egg things that can lead to nasty, recursive stack-overflow 😉


    Pine is not Elm

    (Pine is not Elm) is not Elm

    (Pine is not Elm (Pine is not Elm) is not Elm) is not Elm


  2. David Smith says:

    WOW! Look at that spinner spin!

  3. Slim Shady says:

    I’m not buying this one Brad.

    You need to make time the spinner based on milliseconds since last turn… you can’t just turn it on every call. It’s like an old videogame running as fast as it can instead of using the clock to make sure it runs at the same speed on any CPU.

    I would fix it for you but I am too busy.

  4. LarryOsterman says:

    Pine is still used (and developed) at the UW.

    It’s still the premier IMAP client out there (it does IMAP better than all the others IMHO).

    It’s a bit klunky but it DOES show what the protocol can do.

  5. LarryOsterman says:

    Btw, from the project history:

    With Pine 3.90, significant new functionality has been added, notably aggregate operations for manipulating groups of messages at once, the first (alpha) release of PC-Pine for the Winsock network interface standard, and greatly improved Usenet (News) support. One of the early interpretations of the name "Pine" was "Pine Is No-longer Elm"; today a "Program for Internet News and Email" seems more apropos. Laurence Lundblade (Pine author emeritus) has more insight into the issue of what "Pine" really stands for.

    So Pine DOES stand for "Pine is not Elm". Just like FINE is "FINE is not Emacs" etc.

  6. edn says:


    Any reason to use a switch() statement when a string/char array would allow you to easily change the animation to anything you want while also allowing you to reduce that statement to a single line?

    string [] frame = new string [] = {

    "/", "-", "\", "-" };

    Console.WriteLine (frame[counter % animFrame.Length]);

    Console.SetCursorPosition(Console.CursorLeft – frame[counter % animFrame.Length].Length, Console.CursorTop);


  7. I have a question about your style. I used to initialize every variable on the declaration. Every single one. Until the day I adopted FXCop and it suggested not initializing a variable to its default value. Can you elaborate on this rule?

    Btw, my version (also since college days) is a little more ‘ANSI’, I would use ‘Console.Write("b");’ instead of SetCursorPosition-fancy-thing 🙂


  8. S says:

    BTW I thing the characters |/- make a better spinner than /–.

  9. Andreas Haeber says:

    I used pine last session at a university 🙂 Don’t know if it works with Exchange, I assume they used some *NIX-mailserver there.

  10. For the record, running this code in the debugger causes an IOException to be thrown…maybe due to VS trapping the output of the app in its own console?

  11. BradA says:

    Judah, sorry about the exception you are seeing… This is actually a result of a “feature” of VS called Quick Console which is intended to replace the system console allowing for a better developer experience dealing with console output. Unfortunately, Quick Console doesn’t support many console features (such as SetCursorPosition, ConsoleColor, etc). Regrettably, it fails in a difficult to understand way… you get an IOException which could lead developers to believe it is a bug in their code when it is really a bug.. ahh, I mean feature of VS.

    As such, it is my advice that you turn off this “feature” on all console applications… Luckily it is pretty easy to do:

    Tools->Options->Debugging->General – “Redirect all console output to Quick Console window”

  12. Matt says:


    Small spelling correction: "Spiner" should be "spinner"

    Personally, I prefer my spinning characters to be: |, /, -, , |, /, -, . It’s a bit smoother 🙂


  13. mihailik says:

    This Whidbey SetCursorPosition stuff is not implemented in .NET 1.x.

    To make progress version-independent I use "r" char. Pseudo-code:

    Console.Write("rWorking: " + <indicator> );

  14. mihailik says:

    And the most clean and user-friendly case is:

    DateTime nextDump = DateTime.Now;

    for( … )


    // working

    if( DateTime.Now>=nextDump )


    Console.Write("rFormatting: "+percent+"%…");

    nextDump = DateTime.Now.AddSecond(0.2);



    Spinner is not great, user likes to see what amount of work done. Also, you should not update console too fast, because it is exceptionally slow operation.

  15. Jeremy Wiebe says:

    "I started off writing the usage code I wanted to enable, then built a simple class that meet those requirements."…. or if you are into the latest buzzwords it’s called Test Driven Development. 🙂

  16. Greg Ennis says:

    "Tools->Options->Debugging->General – Redirect all console output to Quick Console window"

    I don’t have this option. Is this only available in VS 2005?

  17. BradA says:

    Yes, Quick Console is a VS2005 feature…

  18. mihailik says:

    It would be better to disable QuickConsole by default, for better backward compatibility.

    When I start with new Console Project in VS2005 I often in doubt, where my WriteLines gone?

    At least VS team should apply white-on-black colors to this tool window to make it visually equals to standalone console.

  19. William says:

    Thanks Brad. I did this once, but used the Title bar to show the spinner. Then the status does not get mixed up with other ouput and you don’t need to use position or backspace, etc. You could also use "|" bars to show a console-progress bar deal. Cheers.

  20. RichB says:

    People use Mutt nowadays and only corporations use Exchange, everyone else uses IMAP for server-side email systems.

    Novell’s Evolution mail client can connect to Exchange, but it’s a GUI application.

  21. danielfe says:

    Nice spinner 🙂

    I blogged about this a while back, but to your question on Pine clients, Andrew Troelsen wrote a C# "Pine" client for an article on Programming Outlook 2003 using C#.

  22. vBogey says:

    I can only hope no one else will consider this approach usefull.

  23. says:

    I read Brad Abrams post on Showing Progress in a Console Window. I did not like the way he implemented…

  24. RGabo says:

    Brad, why do you do a counter = 0 in the constructor?

    I have no problem with explicitly declaring the default constructor (you talked about that in your guidelines 😉 but a managed System.Int32 is always 0 when the object is constructed.

    So what’s the deal? 🙂

  25. BradA says:

    RBabo — You are right, not really needed, but the cost is almost zero as well and I wanted it for explicit documentation.. that is make sure the reader understands explicity how I am using this field..