1 //          Copyright Mario Kröplin 2013.
2 // Distributed under the Boost Software License, Version 1.0.
3 //    (See accompanying file LICENSE_1_0.txt or copy at
4 //          http://www.boost.org/LICENSE_1_0.txt)
5 
6 module dunit.color;
7 
8 import std.stdio;
9 
10 enum Color { red, green, yellow, onRed, onGreen, onYellow }
11 
12 version (Posix)
13 {
14     /**
15      * Writes the text in the given color, if possible.
16      */
17     public void writec(Color color, string text)
18     {
19         if (canUseColor())
20         {
21             const string CSI = "\x1B[";
22 
23             final switch (color) with (Color)
24             {
25                 case red:
26                     stdout.write(CSI, "37;31;1m");
27                     break;
28                 case green:
29                     stdout.write(CSI, "37;32;1m");
30                     break;
31                 case yellow:
32                     stdout.write(CSI, "37;33;1m");
33                     break;
34                 case onRed:
35                     stdout.write(CSI, "37;41;1m");
36                     break;
37                 case onGreen:
38                     stdout.write(CSI, "37;42;1m");
39                     break;
40                 case onYellow:
41                     stdout.write(CSI, "37;43;1m");
42                     break;
43             }
44             stdout.write(text);
45             stdout.write(CSI, "0m");
46             stdout.flush();
47         }
48         else
49         {
50             stdout.write(text);
51             stdout.flush();
52         }
53     }
54 
55     private static bool canUseColor()
56     {
57         static bool useColor = false;
58         static bool computed = false;
59 
60         if (!computed)
61         {
62             // disable colors if the output is written to a file or pipe instead of a tty
63             import core.sys.posix.unistd : isatty;
64 
65             useColor = isatty(stdout.fileno()) != 0;
66             computed = true;
67         }
68         return useColor;
69     }
70 }
71 
72 version (Windows)
73 {
74     /**
75      * Writes the text in the given color, if possible.
76      */
77     public void writec(Color color, string text)
78     {
79         if (canUseColor())
80         {
81             import core.sys.windows.windows;
82 
83             HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
84             CONSOLE_SCREEN_BUFFER_INFO info;
85 
86             GetConsoleScreenBufferInfo(handle, &info);
87             final switch (color) with (Color)
88             {
89                 case red:
90                     SetConsoleTextAttribute(handle,
91                             FOREGROUND_RED | FOREGROUND_INTENSITY);
92                     break;
93                 case green:
94                     SetConsoleTextAttribute(handle,
95                             FOREGROUND_GREEN | FOREGROUND_INTENSITY);
96                     break;
97                 case yellow:
98                     SetConsoleTextAttribute(handle,
99                             FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
100                     break;
101                 case onRed:
102                     SetConsoleTextAttribute(handle,
103                             BACKGROUND_RED | BACKGROUND_INTENSITY);
104                     break;
105                 case onGreen:
106                     SetConsoleTextAttribute(handle,
107                             BACKGROUND_GREEN | BACKGROUND_INTENSITY);
108                     break;
109                 case onYellow:
110                     SetConsoleTextAttribute(handle,
111                             BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY);
112                     break;
113             }
114             stdout.write(text);
115             stdout.flush();
116             SetConsoleTextAttribute(handle, info.wAttributes);
117         }
118         else
119         {
120             stdout.write(text);
121             stdout.flush();
122         }
123     }
124 
125     private static bool canUseColor()
126     {
127         static bool useColor = false;
128         static bool computed = false;
129 
130         if (!computed)
131         {
132             // disable colors if the results output is written to a file or pipe instead of a tty
133             import core.sys.windows.windows;
134 
135             CONSOLE_SCREEN_BUFFER_INFO info;
136 
137             useColor = GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info) > 0;
138             computed = true;
139         }
140         return useColor;
141     }
142 }