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