@@ -109,6 +109,68 @@ static void printUsage(const char *progname) {
109109 return build;
110110}
111111
112+ static NSString *sanitizeForHTML (NSString *input) {
113+ NSMutableString *build = [NSMutableString string ];
114+ // thanks to https://www.w3.org/International/questions/qa-escapes#use
115+ NSDictionary <NSString *, NSString *> *replacementMap = @{
116+ @" <" : @" <" ,
117+ @" >" : @" >" ,
118+ @" &" : @" &" ,
119+ @" \" " : @" "" ,
120+ @" '" : @" '" ,
121+ };
122+ [input enumerateSubstringsInRange: NSMakeRange (0 , input.length) options: NSStringEnumerationByComposedCharacterSequences usingBlock: ^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
123+ [build appendString: (replacementMap[substring] ?: substring)];
124+ }];
125+ return build;
126+ }
127+
128+ static NSString *hljsHtmlForSemanticString (CDSemanticString *const semanticString) {
129+ NSMutableString *build = [NSMutableString string ];
130+ // https://highlightjs.readthedocs.io/en/latest/css-classes-reference.html
131+ [semanticString enumerateLongestEffectiveRangesUsingBlock: ^(NSString *string, CDSemanticType type) {
132+ NSString *htmlCls = nil ;
133+ switch (type) {
134+ case CDSemanticTypeComment:
135+ htmlCls = @" hljs-comment" ;
136+ break ;
137+ case CDSemanticTypeKeyword:
138+ htmlCls = @" hljs-keyword" ;
139+ break ;
140+ case CDSemanticTypeVariable:
141+ htmlCls = @" hljs-variable" ;
142+ break ;
143+ case CDSemanticTypeRecordName:
144+ htmlCls = @" hljs-type" ;
145+ break ;
146+ case CDSemanticTypeClass:
147+ // hljs-class is deprecated
148+ htmlCls = @" hljs-title class" ;
149+ break ;
150+ case CDSemanticTypeProtocol:
151+ // hljs does not officially define `hljs-title.protocol`
152+ // however `hljs-title` is still a class that themes should style
153+ htmlCls = @" hljs-title protocol" ;
154+ break ;
155+ case CDSemanticTypeNumeric:
156+ htmlCls = @" hljs-number" ;
157+ break ;
158+ default :
159+ break ;
160+ }
161+ if (htmlCls != nil ) {
162+ [build appendString: @" <span class=\" " ];
163+ [build appendString: htmlCls];
164+ [build appendString: @" \" >" ];
165+ }
166+ [build appendString: sanitizeForHTML (string)];
167+ if (htmlCls != nil ) {
168+ [build appendString: @" </span>" ];
169+ }
170+ }];
171+ return build;
172+ }
173+
112174static NSString *linesForSemanticStringColorMode (CDSemanticString *const semanticString, CDOutputColorMode const colorMode, BOOL const isOutputTTY) {
113175 BOOL shouldColor = NO ;
114176 switch (colorMode) {
0 commit comments