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