1 /** ANSI escape codes and sequences. 2 * 3 * See_Also: https://en.wikipedia.org/wiki/ANSI_escape_code 4 */ 5 module nxt.ansi_escape; 6 7 public import nxt.color : ColorRGB8; 8 9 @safe: 10 11 /** Visual attributes. 12 */ 13 struct Attrs 14 { 15 @safe: 16 immutable(SGR)[] sgrs; ///< Ordered set of SGR, typically initialized from `static immutable(SGR)[]`. 17 ColorRGB8 foregroundColor; ///< Foreground color. 18 ColorRGB8 backgroundColor; ///< Background color. 19 bool useForegroundColor; ///< Indicate if 'foregroundColor is to be used. 20 bool useBackgroundColor; ///< Indicate if 'backgroundColor is to be used. 21 22 void set(scope void delegate(scope const(char)[]) @safe sink) 23 { 24 setSGRs(sink, sgrs); 25 if (useForegroundColor) 26 { 27 setForegroundColorRGB8(sink, foregroundColor); 28 } 29 if (useBackgroundColor) 30 { 31 setBackgroundColorRGB8(sink, backgroundColor); 32 } 33 } 34 35 void reset(scope void delegate(scope const(char)[]) @safe sink) 36 { 37 resetSGRs(sink); 38 } 39 } 40 41 /** SGR (Select Graphic Rendition) sets display attributes. 42 * 43 * See_Also: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters 44 */ 45 enum SGR : uint 46 { 47 init = 0, ///< Default. 48 bold = 1, ///< Bold or increased intensity. 49 faint = 2, ///< Faint (decreased intensity) 50 italic = 3, ///< Italic. Not widely supported. Sometimes treated as inverse. 51 underline = 4, ///< Underline. 52 slowBlink = 5, ///< Slow blink. 53 rapidBlink = 6, ///< Rapid blink. 54 reverseVideo = 7, ///< Reversed video (swap). Swap foreground with background color. 55 hide = 8, ///< Conceal (Hide). Not widely supported. 56 crossedOut = 9, ///< Crossed-out. Characters legible, but marked for deletion. 57 primaryDefaultFont = 10, ///< Primary (default) font. 58 fraktur = 20, ///< Fraktur. Rarely supported 59 60 blackForegroundColor = 30, ///< Black foreground color. 61 redForegroundColor = 31, ///< Red foreground color. 62 greenForegroundColor = 32, ///< Green foreground color. 63 yellowForegroundColor = 33, ///< Yellow foreground color. 64 blueForegroundColor = 34, ///< Blue foreground color. 65 magentaForegroundColor = 35, ///< Magenta foreground color. 66 cyanForegroundColor = 36, ///< Cyan foreground color. 67 whiteForegroundColor = 37, ///< White foreground color. 68 69 defaultForegroundColor = 39, ///< Default foreground color. 70 71 lightBlackForegroundColor = 90, ///< Light black foreground color. 72 lightRedForegroundColor = 91, ///< Light red foreground color. 73 lightGreenForegroundColor = 92, ///< Light green foreground color. 74 lightYellowForegroundColor = 93, ///< Light yellow foreground color. 75 lightBlueForegroundColor = 94, ///< Light blue foreground color. 76 lightMagentaForegroundColor = 95, ///< Light magenta foreground color. 77 lightCyanForegroundColor = 96, ///< Light cyan foreground color. 78 lightWhiteForegroundColor = 97, ///< Light white foreground color. 79 80 defaultBackgroundColor = 49, ///< Default background color. 81 82 framed = 51, ///< Framed. 83 encircled = 52, ///< Encircled. 84 overlined = 53, ///< Overlined. 85 notFramedOrEncircled = 54, ///< Not framed or encircled. 86 notOverlined = 55, ///< Not overlined. 87 IdeogramUnderlineOrRightSideLine = 60, ///< Ideogram underline or right side line. 88 } 89 90 private void setSGR(scope void delegate(scope const(char)[]) @safe sink, 91 const SGR sgr) 92 { 93 final switch (sgr) 94 { 95 static foreach (member; __traits(allMembers, SGR)) 96 { 97 case __traits(getMember, SGR, member): 98 enum _ = cast(int)__traits(getMember, SGR, member); // avoids `std.conv.to` 99 sink(_.stringof); 100 return; 101 } 102 } 103 } 104 105 void setSGRs(scope void delegate(scope const(char)[]) @safe sink, 106 scope const SGR[] sgrs...) @safe 107 { 108 sink("\033["); 109 const n = sgrs.length; 110 foreach (const index, const sgr; sgrs) 111 { 112 setSGR(sink, sgr); // needs to be first 113 if (index != n - 1) // if not last 114 { 115 sink(";"); // separator 116 } 117 } 118 sink("m"); 119 } 120 121 void resetSGRs(scope void delegate(scope const(char)[]) @safe sink) 122 { 123 sink("\033[0m"); 124 } 125 126 void putWithSGRs(scope void delegate(scope const(char)[]) @safe sink, 127 scope const(char)[] text, 128 scope const SGR[] sgrs...) @safe 129 { 130 setSGRs(sink, sgrs); // set 131 sink(text); 132 resetSGRs(sink); // reset 133 } 134 135 /** Set foreground color to `rgb`. 136 * 137 * See_Also: https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit 138 */ 139 void setForegroundColorRGB8(scope void delegate(scope const(char)[]) @safe sink, 140 const ColorRGB8 rgb) @safe 141 { 142 sink("\033[38;2;"); 143 setColorRGB8Component(sink, rgb.redC); 144 sink(";"); 145 setColorRGB8Component(sink, rgb.greenC); 146 sink(";"); 147 setColorRGB8Component(sink, rgb.blueC); 148 sink("m"); 149 } 150 151 /** Set background color to `rgb`. 152 * 153 * See_Also: https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit 154 */ 155 void setBackgroundColorRGB8(scope void delegate(scope const(char)[]) @safe sink, 156 const ColorRGB8 rgb) @safe 157 { 158 sink("\033[48;2;"); 159 setColorRGB8Component(sink, rgb.redC); 160 sink(";"); 161 setColorRGB8Component(sink, rgb.greenC); 162 sink(";"); 163 setColorRGB8Component(sink, rgb.blueC); 164 sink("m"); 165 } 166 167 /** Set RGB 24-bit color component `component`. 168 * 169 * See_Also: https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit 170 */ 171 static private void setColorRGB8Component(scope void delegate(scope const(char)[]) @safe sink, 172 const ubyte component) @safe 173 { 174 final switch (component) 175 { 176 static foreach (value; 0 .. 256) 177 { 178 case value: 179 sink(value.stringof); // avoids `std.conv.to` 180 return; 181 } 182 } 183 } 184 185 version(none): 186 187 version(unittest) 188 class C 189 { 190 @safe: 191 @property void toString(scope void delegate(scope const(char)[]) @safe sink) const @trusted 192 { 193 putWithSGRs(sink, "XXX", SGR.yellowForegroundColor); 194 } 195 this() {} 196 } 197 198 @safe unittest 199 { 200 import std.stdio : writeln; 201 import std.conv : to; 202 auto c = new C(); 203 writeln(c.to!string); 204 }