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 import std.typecons : Flag, No, Yes; 5 6 { 7 immutable line = "This is a <l>log</> line."; 8 immutable replaced = line.expandTags(LogLevel.off, No.strip); 9 immutable expected = text("This is a ", logger.logtint, "log", logger.offtint, " line."); 10 assert((replaced == expected), replaced); 11 } 12 { 13 import std.conv : wtext; 14 15 immutable line = "This is a <l>log</> line."w; 16 immutable replaced = line.expandTags(LogLevel.off, No.strip); 17 immutable expected = wtext("This is a "w, logger.logtint, "log"w, logger.offtint, " line."w); 18 assert((replaced == expected), replaced.to!string); 19 } 20 { 21 import std.conv : dtext; 22 23 immutable line = "This is a <l>log</> line."d; 24 immutable replaced = line.expandTags(LogLevel.off, No.strip); 25 immutable expected = dtext("This is a "d, logger.logtint, "log"d, logger.offtint, " line."d); 26 assert((replaced == expected), replaced.to!string); 27 } 28 { 29 immutable line = `<i>info</>nothing<c>critical</>nothing\<w>not warning`; 30 immutable replaced = line.expandTags(LogLevel.off, No.strip); 31 immutable expected = text(logger.infotint, "info", logger.offtint, "nothing", 32 logger.criticaltint, "critical", logger.offtint, "nothing<w>not warning"); 33 assert((replaced == expected), replaced); 34 } 35 { 36 immutable line = "This is a line with no tags"; 37 immutable replaced = line.expandTags(LogLevel.off, No.strip); 38 assert(line is replaced); 39 } 40 { 41 immutable emptyLine = string.init; 42 immutable replaced = emptyLine.expandTags(LogLevel.off, No.strip); 43 assert(replaced is emptyLine); 44 } 45 { 46 immutable line = "hello<h>kameloso</>hello"; 47 immutable replaced = line.expandTags(LogLevel.off, Yes.strip); 48 immutable expected = "hellokamelosohello"; 49 assert((replaced == expected), replaced); 50 } 51 { 52 immutable line = "hello<h></>hello"; 53 immutable replaced = line.expandTags(LogLevel.off, Yes.strip); 54 immutable expected = "hellohello"; 55 assert((replaced == expected), replaced); 56 } 57 { 58 immutable line = `hello\<harbl>kameloso<h>hello</>hi`; 59 immutable replaced = line.expandTags(LogLevel.off, Yes.strip); 60 immutable expected = "hello<harbl>kamelosohellohi"; 61 assert((replaced == expected), replaced); 62 } 63 { 64 enum pattern = "Failed to fetch, replay and clear notes for " ~ 65 "<l>%s<e> on <l>%s<e>: <l>%s"; 66 immutable line = pattern.format("nickname", "<no channel>", "error"); 67 immutable replaced = line.expandTags(LogLevel.off, No.strip); 68 immutable expected = "Failed to fetch, replay and clear notes for " ~ 69 logger.logtint ~ "nickname" ~ logger.errortint ~ " on " ~ logger.logtint ~ 70 "<no channel>" ~ logger.errortint ~ ": " ~ logger.logtint ~ "error"; 71 assert((replaced == expected), replaced); 72 } 73 { 74 enum pattern = "Failed to fetch, replay and clear notes for " ~ 75 "<l>%s<e> on <l>%s<e>: <l>%s"; 76 immutable line = pattern.format("nickname", "<no channel>", "error"); 77 immutable replaced = line.expandTags(LogLevel.off, Yes.strip); 78 immutable expected = "Failed to fetch, replay and clear notes for " ~ 79 "nickname on <no channel>: error"; 80 assert((replaced == expected), replaced); 81 } 82 { 83 enum pattern = "Failed to fetch, replay and clear notes for " ~ 84 "<l>%s</> on <l>%s</>: <l>%s"; 85 immutable line = pattern.format("nickname", "<no channel>", "error"); 86 immutable replaced = line.expandTags(LogLevel.error, No.strip); 87 immutable expected = "Failed to fetch, replay and clear notes for " ~ 88 logger.logtint ~ "nickname" ~ logger.errortint ~ " on " ~ logger.logtint ~ 89 "<no channel>" ~ logger.errortint ~ ": " ~ logger.logtint ~ "error"; 90 assert((replaced == expected), replaced); 91 } 92 { 93 enum pattern = "Failed to fetch, replay and clear notes for " ~ 94 "<l>%s</> on <l>%s</>: <l>%s"; 95 immutable line = pattern.format("nickname", "<no channel>", "error"); 96 immutable replaced = line.expandTags(LogLevel.error, Yes.strip); 97 immutable expected = "Failed to fetch, replay and clear notes for " ~ 98 "nickname on <no channel>: error"; 99 assert((replaced == expected), replaced); 100 } 101 { 102 enum origPattern = "Could not apply <i>+%s<l> <i>%s<l> in <i>%s<l> " ~ 103 "because we are not an operator in the channel."; 104 enum newPattern = "Could not apply <i>+%s</> <i>%s</> in <i>%s</> " ~ 105 "because we are not an operator in the channel."; 106 immutable origLine = origPattern.format("o", "nickname", "#channel").expandTags(LogLevel.off, No.strip); 107 immutable newLine = newPattern.format("o", "nickname", "#channel").expandTags(LogLevel.all, No.strip); 108 assert((origLine == newLine), newLine); 109 } 110 111 version(Colours) 112 { 113 import kameloso.terminal.colours : colourByHash; 114 import kameloso.pods : CoreSettings; 115 116 CoreSettings brightSettings; 117 CoreSettings darkSettings; 118 brightSettings.brightTerminal = true; 119 120 { 121 immutable line = "hello<h>kameloso</>hello"; 122 immutable replaced = line.expandTags(LogLevel.off, No.strip); 123 immutable expected = text("hello", colourByHash("kameloso", 124 darkSettings), logger.offtint, "hello"); 125 assert((replaced == expected), replaced); 126 } 127 { 128 immutable line = `hello\<harbl>kameloso<h>hello</>hi`; 129 immutable replaced = line.expandTags(LogLevel.off, No.strip); 130 immutable expected = text("hello<harbl>kameloso", colourByHash("hello", 131 darkSettings), logger.offtint, "hi"); 132 assert((replaced == expected), replaced); 133 } 134 { 135 immutable line = "<l>%%APPDATA%%\\\\kameloso</>."; 136 immutable replaced = line.expandTags(LogLevel.off, No.strip); 137 immutable expected = logger.logtint ~ "%%APPDATA%%\\kameloso" ~ logger.offtint ~ "."; 138 assert((replaced == expected), replaced); 139 } 140 { 141 immutable line = "<l>herp\\</>herp\\\\herp\\\\<l>herp</>"; 142 immutable replaced = line.expandTags(LogLevel.off, No.strip); 143 immutable expected = logger.logtint ~ "herp</>herp\\herp\\" ~ logger.logtint ~ "herp" ~ logger.offtint; 144 assert((replaced == expected), replaced); 145 } 146 { 147 immutable line = "Added <h>hirrsteff</> as a blacklisted user in #garderoben"; 148 immutable replaced = line.expandTags(LogLevel.off, No.strip); 149 immutable expected = "Added " ~ 150 colourByHash("hirrsteff", brightSettings) ~ 151 logger.offtint ~ " as a blacklisted user in #garderoben"; 152 assert((replaced == expected), replaced); 153 } 154 }
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.