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 private StyledString addPair(int before, int after) 47 { 48 befores ~= before; 49 afters ~= after; 50 return this; 51 } 52 53 StyledString setForeground(int color) { 54 return addPair(color, 0); 55 } 56 StyledString setBackground(int color) { 57 return addPair(color + 10, 0); 58 } 59 StyledString addStyle(int style) { 60 return addPair(style, style+20); 61 } 62 string toString() 63 { 64 import std.algorithm; 65 66 auto prefix = befores.map!(a => "\033[%dm".format(a)).join(""); 67 auto suffix = afters.map!(a => "\033[%dm".format(a)).join(""); 68 return "%s%s%s".format(prefix, s, suffix); 69 } 70 } 71 72 @("styledstring") unittest 73 { 74 import unit_threaded; 75 import std.stdio; 76 import std.traits; 77 78 foreach (immutable color; [EnumMembers!AnsiColor]) 79 { 80 auto colorName = "%s".format(color); 81 writeln(StyledString(colorName).setForeground(color)); 82 } 83 foreach (immutable color; [EnumMembers!AnsiColor]) 84 { 85 auto colorName = "bg%s".format(color); 86 writeln(StyledString(colorName).setBackground(color)); 87 } 88 foreach (immutable style; [EnumMembers!Style]) 89 { 90 auto styleName = "%s".format(style); 91 writeln(StyledString(styleName).addStyle(style)); 92 } 93 } 94 95 auto colorMixin(T)() 96 { 97 import std.traits; 98 99 string res = ""; 100 foreach (immutable color; [EnumMembers!T]) 101 { 102 auto t = typeof(T.init).stringof; 103 auto c = "%s".format(color); 104 res ~= "auto %1$s(string s) { return StyledString(s).setForeground(%2$s.%1$s); }\n".format(c, 105 t); 106 res ~= "auto %1$s(StyledString s) { return s.setForeground(%2$s.%1$s); }\n".format(c, t); 107 string name = c[0 .. 1].toUpper ~ c[1 .. $]; 108 res ~= "auto on%3$s(string s) { return StyledString(s).setBackground(%2$s.%1$s); }\n".format(c, 109 t, name); 110 res ~= "auto on%3$s(StyledString s) { return s.setBackground(%2$s.%1$s); }\n".format(c, 111 t, name); 112 } 113 return res; 114 } 115 116 auto styleMixin(T)() 117 { 118 import std.traits; 119 120 string res = ""; 121 foreach (immutable style; [EnumMembers!T]) 122 { 123 auto t = typeof(T.init).stringof; 124 auto s = "%s".format(style); 125 res ~= "auto %1$s(string s) { return StyledString(s).addStyle(%2$s.%1$s); }\n".format(s, 126 t); 127 res ~= "auto %1$s(StyledString s) { return s.addStyle(%2$s.%1$s); }\n".format(s, 128 t); 129 } 130 return res; 131 } 132 133 mixin(colorMixin!AnsiColor); 134 mixin(styleMixin!Style); 135 136 @("api") unittest 137 { 138 import std.stdio; 139 140 writeln("red".red.onGreen); 141 writeln("red".red.onYellow.bold.underlined); 142 }