1 module colored; 2 3 import std.string; 4 5 enum AnsiColor 6 { 7 black = 30, 8 red = 31, 9 green = 32, 10 yellow = 33, 11 blue = 34, 12 magenta = 35, 13 cyan = 36, 14 white = 37, 15 defaultColor = 39 16 } 17 18 struct StringWithForeground(T) 19 { 20 string s; 21 T fg; 22 this(string s, T fg) 23 { 24 this.s = s; 25 this.fg = fg; 26 } 27 28 string toString() 29 { 30 return "\033[%dm%s\033[0m".format(fg, s); 31 } 32 } 33 34 struct StringWithBackground(T) 35 { 36 string s; 37 T bg; 38 this(string s, T bg) 39 { 40 this.s = s; 41 this.bg = bg; 42 } 43 44 string toString() 45 { 46 return "\033[%dm%s\033[0m".format(bg + 10, s); 47 } 48 } 49 50 struct StringWithBoth(T) 51 { 52 string s; 53 T fg; 54 T bg; 55 this(string s, T fg, T bg) 56 { 57 this.s = s; 58 this.fg = fg; 59 this.bg = bg; 60 } 61 62 string toString() 63 { 64 return "\033[%dm\033[%dm%s\033[0m".format(fg, bg + 10, s); 65 } 66 } 67 68 @("color structs") unittest 69 { 70 import unit_threaded; 71 72 StringWithForeground!AnsiColor("fgTest", AnsiColor.red).toString.shouldEqual( 73 "\033[31mfgTest\033[0m"); 74 StringWithBackground!AnsiColor("bgTest", AnsiColor.red).toString.shouldEqual( 75 "\033[41mbgTest\033[0m"); 76 StringWithBoth!AnsiColor("bothTest", AnsiColor.red, AnsiColor.red).toString.shouldEqual( 77 "\033[31m\033[41mbothTest\033[0m"); 78 } 79 80 string asMixin(T)() 81 { 82 import std.conv; 83 import std.traits; 84 85 string res = ""; 86 foreach (immutable ansiColor; [EnumMembers!T]) 87 { 88 res ~= "auto %1$s(string s) { return StringWithForeground!%2$s(s, %2$s.%1$s); }\n".format(ansiColor, 89 typeof(T.init).stringof); 90 res ~= "auto %1$s(StringWithBackground!%2$s s) { return StringWithBoth!%2$s(s.s, %2$s.%1$s, s.bg); }\n".format( 91 ansiColor, typeof(T.init).stringof); 92 string n = ansiColor.to!string; 93 string name = n[0 .. 1].toUpper ~ n[1 .. $]; 94 res ~= "auto on%3$s(string s) { return StringWithBackground!%2$s(s, %2$s.%1$s); }\n".format(ansiColor, 95 typeof(T.init).stringof, name); 96 res ~= "auto on%3$s(StringWithForeground!%2$s s) { return StringWithBoth!%2$s(s.s, s.fg, %2$s.%1$s); }\n" 97 .format(ansiColor, typeof(T.init).stringof, name); 98 } 99 return res; 100 } 101 102 @("color mixins") unittest 103 { 104 import unit_threaded; 105 106 enum TTT 107 { 108 r = 1 109 } 110 111 asMixin!TTT.shouldEqual(`auto r(string s) { return StringWithForeground!TTT(s, TTT.r); } 112 auto r(StringWithBackground!TTT s) { return StringWithBoth!TTT(s.s, TTT.r, s.bg); } 113 auto onR(string s) { return StringWithBackground!TTT(s, TTT.r); } 114 auto onR(StringWithForeground!TTT s) { return StringWithBoth!TTT(s.s, s.fg, TTT.r); } 115 `); 116 } 117 118 mixin(asMixin!AnsiColor); 119 120 unittest 121 { 122 import std.stdio; 123 124 writeln("Hello World".black); 125 writeln("Hello World".red); 126 writeln("Hello World".green); 127 writeln("Hello World".yellow); 128 writeln("Hello World".blue); 129 writeln("Hello World".magenta); 130 writeln("Hello World".cyan); 131 writeln("Hello World".white); 132 writeln("Hello World".defaultColor); 133 }