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 lightGray = 37, 15 defaultColor = 39, 16 darkGray = 90, 17 lightRed = 91, 18 lightGreen = 92, 19 lightYellow = 93, 20 lightBlue = 94, 21 lightMagenta = 95, 22 lightCyan = 96, 23 white = 97 24 } 25 26 enum Style 27 { 28 bold = 1, 29 dim = 2, 30 underlined = 4, 31 blink = 5, 32 reverse = 7, 33 hidden = 8 34 } 35 36 struct StyledString 37 { 38 string s; 39 int[] befores; 40 int[] afters; 41 this(string s) 42 { 43 this.s = s; 44 } 45 46 StyledString addStyle(int before, int after) 47 { 48 befores ~= before; 49 afters ~= after; 50 return this; 51 } 52 53 string toString() 54 { 55 import std.algorithm; 56 57 auto prefix = befores.map!(a => "\033[%dm".format(a)).join(""); 58 auto suffix = afters.map!(a => "\033[%dm".format(a)).join(""); 59 return "%s%s%s".format(prefix, s, suffix); 60 } 61 } 62 63 @("styledstring") unittest 64 { 65 import unit_threaded; 66 import std.stdio; 67 import std.traits; 68 69 foreach (immutable color; [EnumMembers!AnsiColor]) 70 { 71 auto colorName = "%s".format(color); 72 writeln(StyledString(colorName).addStyle(color, 0)); 73 } 74 foreach (immutable color; [EnumMembers!AnsiColor]) 75 { 76 auto colorName = "bg%s".format(color); 77 writeln(StyledString(colorName).addStyle(color + 10, 0)); 78 } 79 foreach (immutable style; [EnumMembers!Style]) 80 { 81 auto styleName = "%s".format(style); 82 writeln(StyledString(styleName).addStyle(style, style + 20)); 83 } 84 85 writeln(StyledString("test").addStyle(AnsiColor.red, 0) 86 .addStyle(Style.underlined, Style.underlined + 20)); 87 } 88 89 auto colorMixin(T)() 90 { 91 import std.traits; 92 93 string res = ""; 94 foreach (immutable color; [EnumMembers!T]) 95 { 96 auto t = typeof(T.init).stringof; 97 auto c = "%s".format(color); 98 res ~= "auto %1$s(string s) { return StyledString(s).addStyle(%2$s.%1$s, 0); }\n".format(c, 99 t); 100 res ~= "auto %1$s(StyledString s) { return s.addStyle(%2$s.%1$s, 0); }\n".format(c, t); 101 string name = c[0 .. 1].toUpper ~ c[1 .. $]; 102 res ~= "auto on%3$s(string s) { return StyledString(s).addStyle(%2$s.%1$s+10, 0); }\n".format(c, 103 t, name); 104 res ~= "auto on%3$s(StyledString s) { return s.addStyle(%2$s.%1$s+10, 0); }\n".format(c, 105 t, name); 106 } 107 return res; 108 } 109 110 auto styleMixin(T)() 111 { 112 import std.traits; 113 114 string res = ""; 115 foreach (immutable style; [EnumMembers!T]) 116 { 117 auto t = typeof(T.init).stringof; 118 auto s = "%s".format(style); 119 res ~= "auto %1$s(string s) { return StyledString(s).addStyle(%2$s.%1$s, %2$s.%1$s+20); }\n".format(s, 120 t); 121 res ~= "auto %1$s(StyledString s) { return s.addStyle(%2$s.%1$s, %2$s.%1$s+20); }\n".format(s, 122 t); 123 } 124 return res; 125 } 126 127 mixin(colorMixin!AnsiColor); 128 mixin(styleMixin!Style); 129 130 @("api") unittest 131 { 132 import std.stdio; 133 134 writeln("red".red.onGreen); 135 writeln("red".red.onYellow.bold.underlined); 136 }