1 /++ 2 + Copyright: Copyright © 2017, Christian Köstlin 3 + Authors: Christian Koestlin 4 + License: MIT 5 +/ 6 7 /// Simple coloring module for strings 8 module colored; 9 10 import std.string; 11 12 /// Available Colors 13 enum AnsiColor 14 { 15 black = 30, 16 red = 31, 17 green = 32, 18 yellow = 33, 19 blue = 34, 20 magenta = 35, 21 cyan = 36, 22 lightGray = 37, 23 defaultColor = 39, 24 darkGray = 90, 25 lightRed = 91, 26 lightGreen = 92, 27 lightYellow = 93, 28 lightBlue = 94, 29 lightMagenta = 95, 30 lightCyan = 96, 31 white = 97 32 } 33 34 /// Available Styles 35 enum Style 36 { 37 bold = 1, 38 dim = 2, 39 underlined = 4, 40 blink = 5, 41 reverse = 7, 42 hidden = 8 43 } 44 45 /// Internal structure to style a string 46 struct StyledString 47 { 48 private string s; 49 private int[] befores; 50 private int[] afters; 51 this(string s) 52 { 53 this.s = s; 54 } 55 56 private StyledString addPair(int before, int after) 57 { 58 befores ~= before; 59 afters ~= after; 60 return this; 61 } 62 63 StyledString setForeground(int color) 64 { 65 return addPair(color, 0); 66 } 67 68 StyledString setBackground(int color) 69 { 70 return addPair(color + 10, 0); 71 } 72 73 StyledString addStyle(int style) 74 { 75 return addPair(style, style + 20); 76 } 77 78 string toString() @safe 79 { 80 import std.algorithm; 81 82 auto prefix = befores.map!(a => "\033[%dm".format(a)).join(""); 83 auto suffix = afters.map!(a => "\033[%dm".format(a)).join(""); 84 return "%s%s%s".format(prefix, s, suffix); 85 } 86 } 87 88 @("styledstring") unittest 89 { 90 import unit_threaded; 91 import std.stdio; 92 import std.traits; 93 94 foreach (immutable color; [EnumMembers!AnsiColor]) 95 { 96 auto colorName = "%s".format(color); 97 writeln(StyledString(colorName).setForeground(color)); 98 } 99 foreach (immutable color; [EnumMembers!AnsiColor]) 100 { 101 auto colorName = "bg%s".format(color); 102 writeln(StyledString(colorName).setBackground(color)); 103 } 104 foreach (immutable style; [EnumMembers!Style]) 105 { 106 auto styleName = "%s".format(style); 107 writeln(StyledString(styleName).addStyle(style)); 108 } 109 } 110 111 auto colorMixin(T)() 112 { 113 import std.traits; 114 115 string res = ""; 116 foreach (immutable color; [EnumMembers!T]) 117 { 118 auto t = typeof(T.init).stringof; 119 auto c = "%s".format(color); 120 res ~= "auto %1$s(string s) { return StyledString(s).setForeground(%2$s.%1$s); }\n".format(c, 121 t); 122 res ~= "auto %1$s(StyledString s) { return s.setForeground(%2$s.%1$s); }\n".format(c, t); 123 string name = c[0 .. 1].toUpper ~ c[1 .. $]; 124 res ~= "auto on%3$s(string s) { return StyledString(s).setBackground(%2$s.%1$s); }\n".format(c, 125 t, name); 126 res ~= "auto on%3$s(StyledString s) { return s.setBackground(%2$s.%1$s); }\n".format(c, 127 t, name); 128 } 129 return res; 130 } 131 132 auto styleMixin(T)() 133 { 134 import std.traits; 135 136 string res = ""; 137 foreach (immutable style; [EnumMembers!T]) 138 { 139 auto t = typeof(T.init).stringof; 140 auto s = "%s".format(style); 141 res ~= "auto %1$s(string s) { return StyledString(s).addStyle(%2$s.%1$s); }\n".format(s, t); 142 res ~= "auto %1$s(StyledString s) { return s.addStyle(%2$s.%1$s); }\n".format(s, t); 143 } 144 return res; 145 } 146 147 mixin(colorMixin!AnsiColor); 148 mixin(styleMixin!Style); 149 150 @("api") unittest 151 { 152 import std.stdio; 153 154 "redOnGreen".red.onGreen.writeln; 155 "redOnYellowBoldUnderlined".red.onYellow.bold.underlined.writeln; 156 }