1 /******************************************************************************* 2 3 Utilities used internally by the config parser. 4 5 Compile this library with `-debug=ConfigFillerDebug` to get verbose output. 6 This can be achieved with `debugVersions` in dub, or by depending on the 7 `debug` configuration provided by `dub.json`. 8 9 Copyright: 10 Copyright (c) 2019-2022 BOSAGORA Foundation 11 All rights reserved. 12 13 License: 14 MIT License. See LICENSE for details. 15 16 *******************************************************************************/ 17 18 module configy.Utils; 19 20 import std.format; 21 22 /// Type of sink used by the `toString` 23 package alias SinkType = void delegate (in char[]) @safe; 24 25 /******************************************************************************* 26 27 Debugging utility for config filler 28 29 Since this module does a lot of meta-programming, some things can easily 30 go wrong. For example, a condition being false might happen because it is 31 genuinely false or because the condition is buggy. 32 33 To make figuring out if a config is properly parsed or not, a little utility 34 (config-dumper) exists, which will provide a verbose output of what the 35 config filler does. To do this, `config-dumper` is compiled with 36 the below `debug` version. 37 38 *******************************************************************************/ 39 40 debug (ConfigFillerDebug) 41 { 42 /// A thin wrapper around `stderr.writefln` with indentation 43 package void dbgWrite (Args...) (string fmt, Args args) 44 { 45 import std.stdio; 46 stderr.write(IndentChars[0 .. indent >= IndentChars.length ? $ : indent]); 47 stderr.writefln(fmt, args); 48 } 49 50 /// Log a value that is to be returned 51 /// The value will be the first argument and painted yellow 52 package T dbgWriteRet (T, Args...) (auto ref T return_, string fmt, Args args) 53 { 54 dbgWrite(fmt, return_.paint(Yellow), args); 55 return return_; 56 } 57 58 /// The current indentation 59 package size_t indent; 60 61 /// Helper for indentation (who needs more than 16 levels of indent?) 62 private immutable IndentChars = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; 63 } 64 else 65 { 66 /// No-op 67 package void dbgWrite (Args...) (string fmt, lazy Args args) {} 68 69 /// Ditto 70 package T dbgWriteRet (T, Args...) (auto ref T return_, string fmt, lazy Args args) 71 { 72 return return_; 73 } 74 } 75 76 /// Thin wrapper to simplify colorization 77 package struct Colored (T) 78 { 79 /// Color used 80 private string color; 81 82 /// Value to print 83 private T value; 84 85 /// Hook for `formattedWrite` 86 public void toString (scope SinkType sink) 87 { 88 static if (is(typeof(T.init.length) : size_t)) 89 if (this.value.length == 0) return; 90 91 formattedWrite(sink, "%s%s%s", this.color, this.value, Reset); 92 } 93 } 94 95 /// Ditto 96 package Colored!T paint (T) (T arg, string color) 97 { 98 return Colored!T(color, arg); 99 } 100 101 /// Paint `arg` in color `ifTrue` if `cond` evaluates to `true`, use color `ifFalse` otherwise 102 package Colored!T paintIf (T) (T arg, bool cond, string ifTrue, string ifFalse) 103 { 104 return Colored!T(cond ? ifTrue : ifFalse, arg); 105 } 106 107 /// Paint a boolean in green if `true`, red otherwise, unless `reverse` is set to `true`, 108 /// in which case the colors are swapped 109 package Colored!bool paintBool (bool value, bool reverse = false) 110 { 111 return value.paintIf(reverse ^ value, Green, Red); 112 } 113 114 /// Reset the foreground color used 115 package immutable Reset = "\u001b[0m"; 116 /// Set the foreground color to red, used for `false`, missing, errors, etc... 117 package immutable Red = "\u001b[31m"; 118 /// Set the foreground color to red, used for warnings and other things 119 /// that should draw attention but do not pose an immediate issue 120 package immutable Yellow = "\u001b[33m"; 121 /// Set the foreground color to green, used for `true`, present, etc... 122 package immutable Green = "\u001b[32m"; 123 /// Set the foreground color to green, used field names / path 124 package immutable Cyan = "\u001b[36m";