1 module colored; 2 3 import std.string; 4 5 enum AnsiColor { 6 black = 30, 7 red = 31, 8 green = 32, 9 yellow = 33, 10 blue = 34, 11 magenta = 35, 12 cyan = 36, 13 white = 37 14 } 15 16 struct StringWithForeground(T) { 17 string s; 18 T fg; 19 this(string s, T fg) { 20 this.s = s; 21 this.fg = fg; 22 } 23 string toString() { 24 return "\033[%dm%s\033[0m".format(fg, s); 25 } 26 } 27 28 struct StringWithBackground(T) { 29 string s; 30 T bg; 31 this(string s, T bg) { 32 this.s = s; 33 this.bg = bg; 34 } 35 string toString() { 36 return "\033[%dm%s\033[0m".format(bg+10, s); 37 } 38 } 39 40 struct StringWithBoth(T) { 41 string s; 42 T fg; 43 T bg; 44 this(string s, T fg, T bg) { 45 this.s = s; 46 this.fg = fg; 47 this.bg = bg; 48 } 49 string toString() { 50 return "\033[%dm\033[%dm%s\033[0m".format(fg, bg+10, s); 51 } 52 } 53 54 @("color structs") unittest { 55 import unit_threaded; 56 StringWithForeground!AnsiColor("fgTest", AnsiColor.red).toString.shouldEqual("\033[31mfgTest\033[0m"); 57 StringWithBackground!AnsiColor("bgTest", AnsiColor.red).toString.shouldEqual("\033[41mbgTest\033[0m"); 58 StringWithBoth!AnsiColor("bothTest", AnsiColor.red, AnsiColor.red).toString.shouldEqual("\033[31m\033[41mbothTest\033[0m"); 59 } 60 61 string asMixin(T)() { 62 import std.conv; 63 import std.traits; 64 string res = ""; 65 foreach (immutable ansiColor; [EnumMembers!T]) { 66 res ~= "auto %1$s(string s) { return StringWithForeground!%2$s(s, %2$s.%1$s); }\n".format(ansiColor, typeof(T.init).stringof); 67 res ~= "auto %1$s(StringWithBackground!%2$s s) { return StringWithBoth!%2$s(s.s, %2$s.%1$s, s.bg); }\n".format(ansiColor, typeof(T.init).stringof); 68 string n = ansiColor.to!string; 69 string name = n[0..1].toUpper ~ n[1..$]; 70 res ~= "auto on%3$s(string s) { return StringWithBackground!%2$s(s, %2$s.%1$s); }\n".format(ansiColor, typeof(T.init).stringof, name); 71 res ~= "auto on%3$s(StringWithForeground!%2$s s) { return StringWithBoth!%2$s(s.s, s.fg, %2$s.%1$s); }\n".format(ansiColor, typeof(T.init).stringof, name); 72 } 73 return res; 74 } 75 76 @("color mixins") unittest { 77 import unit_threaded; 78 enum TTT { 79 r = 1 80 } 81 asMixin!TTT.shouldEqual( 82 `auto r(string s) { return StringWithForeground!TTT(s, TTT.r); } 83 auto r(StringWithBackground!TTT s) { return StringWithBoth!TTT(s.s, TTT.r, s.bg); } 84 auto onR(string s) { return StringWithBackground!TTT(s, TTT.r); } 85 auto onR(StringWithForeground!TTT s) { return StringWithBoth!TTT(s.s, s.fg, TTT.r); } 86 `); 87 } 88 89 mixin(asMixin!AnsiColor);