1 /* 2 * hunt-console eases the creation of beautiful and testable command line interfaces. 3 * 4 * Copyright (C) 2018-2019, HuntLabs 5 * 6 * Website: https://www.huntlabs.net 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.console.formatter.DefaultOutputFormatterStyle; 13 14 import std.string; 15 import std.conv; 16 17 import hunt.console.error.InvalidArgumentException; 18 import hunt.console.util.StringUtils; 19 20 import hunt.collection.Map; 21 import hunt.collection.HashMap; 22 import hunt.collection.List; 23 import hunt.collection.ArrayList; 24 import hunt.console.formatter.OutputFormatterStyle; 25 import hunt.console.formatter.OutputFormatterOption; 26 import hunt.logging; 27 28 class DefaultOutputFormatterStyle : OutputFormatterStyle 29 { 30 private static Map!(string, OutputFormatterOption) availableForegroundColors; 31 private static Map!(string, OutputFormatterOption) availableBackgroundColors; 32 private static Map!(string, OutputFormatterOption) availableOptions; 33 34 static this() { 35 availableForegroundColors = new HashMap!(string, OutputFormatterOption)(); 36 availableBackgroundColors = new HashMap!(string, OutputFormatterOption)(); 37 availableOptions = new HashMap!(string, OutputFormatterOption)(); 38 availableForegroundColors.put("black", new OutputFormatterOption(30, 39)); 39 availableForegroundColors.put("red", new OutputFormatterOption(31, 39)); 40 availableForegroundColors.put("green", new OutputFormatterOption(32, 39)); 41 availableForegroundColors.put("yellow", new OutputFormatterOption(33, 39)); 42 availableForegroundColors.put("blue", new OutputFormatterOption(34, 39)); 43 availableForegroundColors.put("magenta", new OutputFormatterOption(35, 39)); 44 availableForegroundColors.put("cyan", new OutputFormatterOption(36, 39)); 45 availableForegroundColors.put("white", new OutputFormatterOption(37, 39)); 46 47 availableBackgroundColors.put("black", new OutputFormatterOption(40, 49)); 48 availableBackgroundColors.put("red", new OutputFormatterOption(41, 49)); 49 availableBackgroundColors.put("green", new OutputFormatterOption(41, 49)); 50 availableBackgroundColors.put("yellow", new OutputFormatterOption(43, 49)); 51 availableBackgroundColors.put("blue", new OutputFormatterOption(44, 49)); 52 availableBackgroundColors.put("magenta", new OutputFormatterOption(45, 49)); 53 availableBackgroundColors.put("cyan", new OutputFormatterOption(46, 49)); 54 availableBackgroundColors.put("white", new OutputFormatterOption(47, 49)); 55 56 availableOptions.put("bold", new OutputFormatterOption(1, 22)); 57 availableOptions.put("underscore", new OutputFormatterOption(4, 24)); 58 availableOptions.put("blink", new OutputFormatterOption(5, 25)); 59 availableOptions.put("reverse", new OutputFormatterOption(7, 27)); 60 availableOptions.put("conceal", new OutputFormatterOption(8, 28)); 61 } 62 63 private OutputFormatterOption foreground; 64 private OutputFormatterOption background; 65 private List!(OutputFormatterOption) options ; 66 67 public this() 68 { 69 this(null, null, null); 70 } 71 72 public this(string foreground) 73 { 74 this(foreground, null, null); 75 } 76 77 public this(string foreground, string background) 78 { 79 this(foreground, background, null); 80 } 81 82 public this(string foreground, string background, string[] opts...) 83 { 84 this.options = new ArrayList!OutputFormatterOption(); 85 if (foreground !is null) { 86 setForeground(foreground); 87 } 88 if (background !is null) { 89 setBackground(background); 90 } 91 // logInfo("---infos : ",opts); 92 if (opts !is null && opts.length > 0) { 93 setOptions(opts); 94 } 95 } 96 97 override public void setForeground(string color) 98 { 99 if (color is null) { 100 foreground = null; 101 return; 102 } 103 104 if (!availableForegroundColors.containsKey(color)) { 105 string[] keys; 106 foreach(string k,_; availableForegroundColors) { 107 keys ~= k; 108 } 109 throw new InvalidArgumentException(format( 110 "Invalid foreground color specified: '%s'. Expected one of (%s)", 111 color, 112 StringUtils.join(keys, ", ") 113 )); 114 } 115 116 foreground = availableForegroundColors.get(color); 117 } 118 119 override public void setBackground(string color) 120 { 121 if (color is null) { 122 background = null; 123 return; 124 } 125 126 if (!availableBackgroundColors.containsKey(color)) { 127 string[] keys; 128 foreach(string k,_; availableBackgroundColors) { 129 keys ~= k; 130 } 131 throw new InvalidArgumentException(format( 132 "Invalid background color specified: '%s'. Expected one of (%s)", 133 color, 134 StringUtils.join(keys, ", ") 135 )); 136 } 137 138 background = availableBackgroundColors.get(color); 139 } 140 141 override public void setOption(string option) 142 { 143 if (!availableOptions.containsKey(option)) { 144 string[] keys; 145 foreach(string k,_; availableOptions) { 146 keys ~= k; 147 } 148 throw new InvalidArgumentException(format("Invalid option specified: '%s'. Expected one of (%s)", 149 option, StringUtils.join(keys, ","))); 150 } 151 152 if (!options.contains(availableOptions.get(option))) { 153 options.add(availableOptions.get(option)); 154 } 155 } 156 157 override public void unsetOption(string option) 158 { 159 if (!availableOptions.containsKey(option)) { 160 string[] keys; 161 foreach(string k,_; availableOptions) { 162 keys ~= k; 163 } 164 throw new InvalidArgumentException(format("Invalid option specified: '%s'. Expected one of (%s)", 165 option, StringUtils.join(keys, ","))); 166 } 167 168 if (options.contains(availableOptions.get(option))) { 169 options.remove(availableOptions.get(option)); 170 } 171 } 172 173 override public void setOptions(string[] options...) 174 { 175 this.options = new ArrayList!OutputFormatterOption(); 176 177 foreach (string option ; options) { 178 if(option.length == 0) 179 continue; 180 setOption(option); 181 } 182 } 183 184 override public string apply(string text) 185 { 186 List!(string) setCodes = new ArrayList!string(); 187 List!(string) unsetCodes = new ArrayList!string(); 188 189 if (foreground !is null) { 190 setCodes.add(to!string(foreground.getSet())); 191 unsetCodes.add(to!string(foreground.getUnset())); 192 } 193 if (background !is null) { 194 setCodes.add(to!string(background.getSet())); 195 unsetCodes.add(to!string(background.getUnset())); 196 } 197 198 foreach (OutputFormatterOption option ; options) { 199 setCodes.add(to!string(option.getSet())); 200 unsetCodes.add(to!string(option.getUnset())); 201 } 202 203 if (setCodes.size() == 0) { 204 return text; 205 } 206 string[] codes; 207 foreach(value; setCodes) { 208 codes ~= value; 209 } 210 string[] uncodes; 211 foreach(value; unsetCodes) { 212 uncodes ~= value; 213 } 214 return format( 215 "\033[%sm%s\033[%sm", 216 StringUtils.join(codes, ";"), 217 text, 218 StringUtils.join(uncodes, ";") 219 ); 220 } 221 222 override public bool opEquals(Object o) 223 { 224 if (this is o) return true; 225 if (!(cast(DefaultOutputFormatterStyle)o !is null)) return false; 226 227 DefaultOutputFormatterStyle that = cast(DefaultOutputFormatterStyle) o; 228 229 if (background !is null ? !(background == that.background) : that.background !is null) return false; 230 if (foreground !is null ? !(foreground == that.foreground) : that.foreground !is null) return false; 231 if (options !is null ? !(options == that.options) : that.options !is null) return false; 232 233 return true; 234 } 235 236 override public size_t toHash() @trusted nothrow 237 { 238 int result = foreground !is null ? cast(int)(foreground.toHash()) : 0; 239 result = 31 * result + (background !is null ? cast(int)(background.toHash()) : 0); 240 result = 31 * result + (options !is null ? cast(int)(options.toHash()) : 0); 241 return result; 242 } 243 }