diff --git a/source/colorize/cwrite.d b/source/colorize/cwrite.d index 5550a29..3917e8a 100644 --- a/source/colorize/cwrite.d +++ b/source/colorize/cwrite.d @@ -25,7 +25,7 @@ void cwritef(T...)(T args) /// Coloured writefln. void cwritefln(T...)(T args) { - stdout.cwritefln(args); + stdout.cwritef(args, "\n"); } /// Coloured writeln. @@ -39,7 +39,7 @@ void cwriteln(T...)(T args) void cwritef(File f, Char, A...)(in Char[] fmt, A args) { auto s = format(fmt, args); - f.write(s); // TODO support colours + f.cwrite(s); } /// Coloured writef to a File. @@ -51,6 +51,15 @@ void cwrite(S...)(File f, S args) foreach(arg; args) s ~= to!string(arg); - f.write(s); + version(Windows) + { + auto winterm = WinTermEmulation(); + foreach(c ; s) + winterm.feed(c); + } + else + { + f.write(s); + } } diff --git a/source/colorize/winterm.d b/source/colorize/winterm.d index c0d76aa..e989045 100644 --- a/source/colorize/winterm.d +++ b/source/colorize/winterm.d @@ -17,17 +17,18 @@ version(Windows) struct WinTermEmulation { public: - this(bool workardound = true) nothrow + this(bool workardound = true) nothrow @nogc { - _console = GetStdHandle(STD_OUTPUT_HANDLE); - // saves console attributes + _console = GetStdHandle(STD_OUTPUT_HANDLE); _savedInitialColor = (0 != GetConsoleScreenBufferInfo(_console, &consoleInfo)); + _state = State.initial; } - ~this() + ~this() nothrow @nogc { + // Restore initial text attributes on release if (_savedInitialColor) { SetConsoleTextAttribute(_console, consoleInfo.wAttributes); @@ -35,15 +36,110 @@ version(Windows) } } - void feed(dchar d) nothrow + // Eat one character and update color state accordingly. Return true if this character should be displayed. + bool feed(dchar d) nothrow @nogc { + final switch(_state) with (State) + { + case initial: + if (d == '\x1B') + { + _state = escaped; + return false; + } + break; + case escaped: + if (d == '[') + { + _state = readingAttribute; + _currentAttr = 0; + return false; + } + break; + + + case readingAttribute: + if (d >= '0' && d <= '9') + { + _parsedAttr = _parsedAttr * 10 + (_parsedAttr - '0'); + return false; + } + else if (d == ';') + { + executeAttribute(_parsedAttr); + return false; + } + else if (d == 'm') + { + _state = State.initial; + return false; + } + break; + } + return true; } private: HANDLE _console; bool _savedInitialColor; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; + State _state; + WORD _currentAttr; + int _parsedAttr; + + enum State + { + initial, + escaped, + readingAttribute + } + + void executeAttribute(int attr) nothrow @nogc + { + switch (attr) + { + /+ case 0: + if (_savedInitialColor) + SetConsoleTextAttribute(_console, consoleInfo.wAttributes); + break; + + default: + + if (30 <= attr && attr <= 37) + } + + 0 Reset all attributes + 1 Bright + 2 Dim + 4 Underscore + 5 Blink + 7 Reverse + 8 Hidden + + Foreground Colours + 30 Black + 31 Red + 32 Green + 33 Yellow + 34 Blue + 35 Magenta + 36 Cyan + 37 White + + Background Colours + 40 Black + 41 Red + 42 Green + 43 Yellow + 44 Blue + 45 Magenta + 46 Cyan + 47 White ++/ + default: + } + } } }