Dan McKinley
Math, Programming, and Minority Reports

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() { }
    }
}
Back home