Console.WriteLine with Wordwrap
May 17th, 2005

Here’s a class I wrote that will write with wordwrap to standard out in a .NET console app. There are a few other nifty options.


    using System;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Text.RegularExpressions;
    
    namespace McKinley
    {
        public sealed class Out
        {
            [StructLayout(LayoutKind.Sequential)]
            private struct COORD
            {
                public short X;
                public short Y;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            private struct CONSOLE_SCREEN_BUFFER_INFO
            {
                public COORD dwSize;
                public COORD dwCursorPosition;
                public short  wAttributes;
                public SMALL_RECT srWindow;
                public COORD dwMaximumWindowSize;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            private struct SMALL_RECT
            {
                public short Left;
                public short Top;
                public short Right;
                public short Bottom;
            }
    
            private const int STD_OUTPUT_HANDLE = -11;
    
            [DllImport("kernel32.dll")]
            private static extern IntPtr GetConsoleWindow();
    
            [DllImport("kernel32.dll")]
            private static extern bool GetConsoleScreenBufferInfo(IntPtr hConsoleOutput,
                out CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);
    
            [DllImport("kernel32.dll")]
            private static extern IntPtr GetStdHandle(int nStdHandle);
    
            private static CONSOLE_SCREEN_BUFFER_INFO StdOutInfo()
            {
                IntPtr hOut = GetStdHandle(STD_OUTPUT_HANDLE);
                if(hOut != IntPtr.Zero)
                {
                     CONSOLE_SCREEN_BUFFER_INFO info;
                     if(GetConsoleScreenBufferInfo(hOut, out info))
                     {
                         return info;
                     }
                }
                return new CONSOLE_SCREEN_BUFFER_INFO();
            }
    
            private static Point GetCursorPosition()
            {
                CONSOLE_SCREEN_BUFFER_INFO info = StdOutInfo();
                return new Point(info.dwCursorPosition.X, info.dwCursorPosition.Y);
            }
    
            private static Point GetConsoleWindowSize()
            {
                CONSOLE_SCREEN_BUFFER_INFO info = StdOutInfo();
                return new Point(info.dwSize.X, info.dwSize.Y);
            }
    
            /// <summary>
            /// Writes <paramref name="val" /> to standard output with word wrap.
            /// Each line is indented by <paramref name="indent" /> characters,
            /// and is prefixed by the string specified by <paramref name="prefix"/>.
            /// </summary>
            public static void WordWrap(string val, int indent, string prefix)
            {
                int max = (GetConsoleWindowSize()).X;
                string pad = new string(' ', indent)+prefix;
    
                Regex r = new Regex(@"([\w\.]*(\s)?)");
                Match words = r.Match(val);
    
                int count = (GetCursorPosition()).X;
                if(count == 0)
                {
                     Console.Write(pad);
                }
                else
                {
                     Console.Write(prefix);
                }
                count = (GetCursorPosition()).X;
                while(words.Success)
                {
                     string word = words.Value;
                     count += word.Length;
                     if(count >= max-1)
                     {
                         Console.WriteLine();
                         Console.Write(pad);
                         count = word.Length + pad.Length;
                     }
                     Console.Write(word);
                     words = words.NextMatch();
                }
            }
    
            /// <summary>
            /// Writes <paramref name="val"/> to the standard output
            /// with word wrap. Each line is indented by
            /// <paramref name="indent"/> characters.
            /// </summary>
            public static void WordWrap(string val, int indent)
            {
                WordWrap(val, indent, string.Empty);
            }
    
            /// <summary>
            /// Writes <paramref name="val"/> to the standard output
            /// with word wrap.
            /// </summary>
            public static void WordWrap(string val)
            {
                WordWrap(val,0);
            }
    
            private Out() { }
        }
    }