A line of text, presumably with <tags>.
The base LogLevel to fall back to on </> tags.
Whether to expand tags or strip them.
The passed line but with any <tags> replaced with ANSI colour sequences. The original string is passed back if there was nothing to replace.
enum oldPattern = " %1$sYour private authorisation key is: %2$s%3$s%4$s It should be entered as %2$spass%4$s under %2$s[IRCBot]%4$s. "; immutable oldMessage = oldPattern.format(Tint.log, Tint.info, pass, Tint.off); enum newPattern = " <l>Your private authorisation key is: <i>%s</> It should be entered as <i>pass</> under <i>[IRCBot]</> "; immutable newMessage = newPattern .format(pass) .expandTags(LogLevel.off); enum patternWithColouredNickname = "No quotes for nickname <h>%s<h>."; immutable colouredMessage = patternWithColouredNickname .format(event.sender.nickname) .expandTags(LogLevel.off);
1 import kameloso.common : logger; 2 import std.conv : text, to; 3 import std.format : format; 4 5 { 6 immutable line = "This is a <l>log</> line."; 7 immutable replaced = line.expandTags(LogLevel.off, strip: false); 8 immutable expected = text("This is a ", logger.logtint, "log", logger.offtint, " line."); 9 assert((replaced == expected), replaced); 10 } 11 { 12 import std.conv : wtext; 13 14 immutable line = "This is a <l>log</> line."w; 15 immutable replaced = line.expandTags(LogLevel.off, strip: false); 16 immutable expected = wtext("This is a "w, logger.logtint, "log"w, logger.offtint, " line."w); 17 assert((replaced == expected), replaced.to!string); 18 } 19 { 20 import std.conv : dtext; 21 22 immutable line = "This is a <l>log</> line."d; 23 immutable replaced = line.expandTags(LogLevel.off, strip: false); 24 immutable expected = dtext("This is a "d, logger.logtint, "log"d, logger.offtint, " line."d); 25 assert((replaced == expected), replaced.to!string); 26 } 27 { 28 immutable line = `<i>info</>nothing<c>critical</>nothing\<w>not warning`; 29 immutable replaced = line.expandTags(LogLevel.off, strip: false); 30 immutable expected = text(logger.infotint, "info", logger.offtint, "nothing", 31 logger.criticaltint, "critical", logger.offtint, "nothing<w>not warning"); 32 assert((replaced == expected), replaced); 33 } 34 { 35 immutable line = "This is a line with no tags"; 36 immutable replaced = line.expandTags(LogLevel.off, strip: false); 37 assert(line is replaced); 38 } 39 { 40 immutable emptyLine = string.init; 41 immutable replaced = emptyLine.expandTags(LogLevel.off, strip: false); 42 assert(replaced is emptyLine); 43 } 44 { 45 immutable line = "hello<h>kameloso</>hello"; 46 immutable replaced = line.expandTags(LogLevel.off, strip: true); 47 immutable expected = "hellokamelosohello"; 48 assert((replaced == expected), replaced); 49 } 50 { 51 immutable line = "hello<h></>hello"; 52 immutable replaced = line.expandTags(LogLevel.off, strip: true); 53 immutable expected = "hellohello"; 54 assert((replaced == expected), replaced); 55 } 56 { 57 immutable line = `hello\<harbl>kameloso<h>hello</>hi`; 58 immutable replaced = line.expandTags(LogLevel.off, strip: true); 59 immutable expected = "hello<harbl>kamelosohellohi"; 60 assert((replaced == expected), replaced); 61 } 62 { 63 enum pattern = "Failed to fetch, replay and clear notes for " ~ 64 "<l>%s<e> on <l>%s<e>: <l>%s"; 65 immutable line = pattern.format("nickname", "<no channel>", "error"); 66 immutable replaced = line.expandTags(LogLevel.off, strip: false); 67 immutable expected = "Failed to fetch, replay and clear notes for " ~ 68 logger.logtint ~ "nickname" ~ logger.errortint ~ " on " ~ logger.logtint ~ 69 "<no channel>" ~ logger.errortint ~ ": " ~ logger.logtint ~ "error"; 70 assert((replaced == expected), replaced); 71 } 72 { 73 enum pattern = "Failed to fetch, replay and clear notes for " ~ 74 "<l>%s<e> on <l>%s<e>: <l>%s"; 75 immutable line = pattern.format("nickname", "<no channel>", "error"); 76 immutable replaced = line.expandTags(LogLevel.off, strip: true); 77 immutable expected = "Failed to fetch, replay and clear notes for " ~ 78 "nickname on <no channel>: error"; 79 assert((replaced == expected), replaced); 80 } 81 { 82 enum pattern = "Failed to fetch, replay and clear notes for " ~ 83 "<l>%s</> on <l>%s</>: <l>%s"; 84 immutable line = pattern.format("nickname", "<no channel>", "error"); 85 immutable replaced = line.expandTags(LogLevel.error, strip: false); 86 immutable expected = "Failed to fetch, replay and clear notes for " ~ 87 logger.logtint ~ "nickname" ~ logger.errortint ~ " on " ~ logger.logtint ~ 88 "<no channel>" ~ logger.errortint ~ ": " ~ logger.logtint ~ "error"; 89 assert((replaced == expected), replaced); 90 } 91 { 92 enum pattern = "Failed to fetch, replay and clear notes for " ~ 93 "<l>%s</> on <l>%s</>: <l>%s"; 94 immutable line = pattern.format("nickname", "<no channel>", "error"); 95 immutable replaced = line.expandTags(LogLevel.error, strip: true); 96 immutable expected = "Failed to fetch, replay and clear notes for " ~ 97 "nickname on <no channel>: error"; 98 assert((replaced == expected), replaced); 99 } 100 { 101 enum origPattern = "Could not apply <i>+%s<l> <i>%s<l> in <i>%s<l> " ~ 102 "because we are not an operator in the channel."; 103 enum newPattern = "Could not apply <i>+%s</> <i>%s</> in <i>%s</> " ~ 104 "because we are not an operator in the channel."; 105 immutable origLine = origPattern.format("o", "nickname", "#channel").expandTags(LogLevel.off, strip: false); 106 immutable newLine = newPattern.format("o", "nickname", "#channel").expandTags(LogLevel.all, strip: false); 107 assert((origLine == newLine), newLine); 108 } 109 110 version(Colours) 111 { 112 import kameloso.terminal.colours : colourByHash; 113 import kameloso.pods : CoreSettings; 114 115 CoreSettings brightSettings; 116 CoreSettings darkSettings; 117 brightSettings.brightTerminal = true; 118 119 { 120 immutable line = "hello<h>kameloso</>hello"; 121 immutable replaced = line.expandTags(LogLevel.off, strip: false); 122 immutable expected = text("hello", colourByHash("kameloso", 123 darkSettings), logger.offtint, "hello"); 124 assert((replaced == expected), replaced); 125 } 126 { 127 immutable line = `hello\<harbl>kameloso<h>hello</>hi`; 128 immutable replaced = line.expandTags(LogLevel.off, strip: false); 129 immutable expected = text("hello<harbl>kameloso", colourByHash("hello", 130 darkSettings), logger.offtint, "hi"); 131 assert((replaced == expected), replaced); 132 } 133 { 134 immutable line = "<l>%%APPDATA%%\\\\kameloso</>."; 135 immutable replaced = line.expandTags(LogLevel.off, strip: false); 136 immutable expected = logger.logtint ~ "%%APPDATA%%\\kameloso" ~ logger.offtint ~ "."; 137 assert((replaced == expected), replaced); 138 } 139 { 140 immutable line = "<l>herp\\</>herp\\\\herp\\\\<l>herp</>"; 141 immutable replaced = line.expandTags(LogLevel.off, strip: false); 142 immutable expected = logger.logtint ~ "herp</>herp\\herp\\" ~ logger.logtint ~ "herp" ~ logger.offtint; 143 assert((replaced == expected), replaced); 144 } 145 { 146 immutable line = "Added <h>hirrsteff</> as a blacklisted user in #garderoben"; 147 immutable replaced = line.expandTags(LogLevel.off, strip: false); 148 immutable expected = "Added " ~ 149 colourByHash("hirrsteff", brightSettings) ~ 150 logger.offtint ~ " as a blacklisted user in #garderoben"; 151 assert((replaced == expected), replaced); 152 } 153 }
String-replaces <tags> in a string with the results from calls to Tint. Also works with dstrings and wstrings.
<tags> are the lowercase first letter of all LogLevels; <l>, <t>, <i>, <w> <e>, <c> and <f>. <a> is not included.
</> equals the passed baseLevel and is used to terminate colour sequences, returning to a default.
Lastly, text between a <h> and a </> are replaced with the results from a call to colourByHash.
This should hopefully make highlighted strings more readable.