@@ -41,9 +41,9 @@ final class TokenVisitor: SyntaxRewriter {
41
41
42
42
list. append (
43
43
" <span class=' \( className) ' " +
44
- " data-title=' \( " \( escapeHTML ( " \( node. trimmed) " ) ) " . replacingOccurrences ( of : " \n " , with : " ↲ " ) ) ' " +
45
- " data-content=' \( escapeHTML ( content) ) ' " +
46
- " data-type=' \( escapeHTML ( type) ) ' " +
44
+ " data-title=' \( " \( node. trimmed) " . htmlEscaped ( ) . displayInvisibles ( ) ) ' " +
45
+ " data-content=' \( content. htmlEscaped ( ) . substituteInvisibles ( ) ) ' " +
46
+ " data-type=' \( type. htmlEscaped ( ) ) ' " +
47
47
#"data-range='{"startRow": \#( start. line) ,"startColumn": \#( start. column) ,"endRow": \#( end. line) ,"endColumn": \#( end. column) }'>"#
48
48
)
49
49
@@ -142,7 +142,12 @@ final class TokenVisitor: SyntaxRewriter {
142
142
}
143
143
144
144
override func visit( _ token: TokenSyntax ) -> TokenSyntax {
145
- current. text = escapeHTML ( token. text)
145
+ current. text = token
146
+ . text
147
+ . htmlEscaped ( )
148
+ . substituteInvisibles ( )
149
+ . replacingOccurrences ( of: " " , with: " ␣ " )
150
+ . replacingOccurrences ( of: " <br/> " , with: " ↲<br/> " )
146
151
current. token = Token ( kind: " \( token. tokenKind) " , leadingTrivia: " " , trailingTrivia: " " )
147
152
148
153
token. leadingTrivia. forEach { ( piece) in
@@ -183,18 +188,21 @@ final class TokenVisitor: SyntaxRewriter {
183
188
let end = sourceRange. end
184
189
let text = token. presence == . present ? token. text : " "
185
190
list. append (
186
- " <span class='token \( escapeHTML ( kind) ) ' " +
187
- " data-title=' \( escapeHTML ( " \( token. trimmed) " ) ) ' " +
188
- " data-content=' \( escapeHTML ( " \( token. tokenKind) " ) ) ' " +
191
+ " <span class='token \( kind. htmlEscaped ( ) ) ' " +
192
+ " data-title=' \( " \( token. trimmed) " . htmlEscaped ( ) . displayInvisibles ( ) ) ' " +
193
+ " data-content=' \( " \( token. tokenKind) " . htmlEscaped ( ) . substituteInvisibles ( ) ) ' " +
189
194
" data-type='Token' " +
190
195
#"data-range='{"startRow": \#( start. line) ,"startColumn": \#( start. column) ,"endRow": \#( end. line) ,"endColumn": \#( end. column) }'>"# +
191
- " \( escapeHTML ( text) ) </span> "
196
+ " \( text. htmlEscaped ( ) . substituteInvisibles ( ) ) </span> "
192
197
)
193
198
}
194
199
195
200
private func processTriviaPiece( _ piece: TriviaPiece ) -> String {
196
201
func wrapWithSpanTag( class c: String , text: String ) -> String {
197
- " <span class=' \( escapeHTML ( c) ) ' data-title=' \( escapeHTML ( " \( piece) " ) ) ' data-content=' \( escapeHTML ( c) ) ' data-type='Trivia'> \( escapeHTML ( text) ) </span> "
202
+ " <span class=' \( c. htmlEscaped ( ) ) ' " +
203
+ " data-title=' \( " \( piece) " . htmlEscaped ( ) . displayInvisibles ( ) ) ' " +
204
+ " data-content=' \( c. htmlEscaped ( ) . substituteInvisibles ( ) ) ' " +
205
+ " data-type='Trivia'> \( text. htmlEscaped ( ) . substituteInvisibles ( ) ) </span> "
198
206
}
199
207
200
208
var trivia = " "
@@ -206,7 +214,7 @@ final class TokenVisitor: SyntaxRewriter {
206
214
case . verticalTabs, . formfeeds:
207
215
break
208
216
case . newlines( let count) , . carriageReturns( let count) , . carriageReturnLineFeeds( let count) :
209
- trivia += String ( repeating: " <br> " , count: count)
217
+ trivia += String ( repeating: " <br/ > " , count: count)
210
218
case . lineComment( let text) :
211
219
trivia += wrapWithSpanTag ( class: " lineComment " , text: text)
212
220
case . blockComment( let text) :
@@ -230,24 +238,35 @@ final class TokenVisitor: SyntaxRewriter {
230
238
private func replaceSymbols( text: String ) -> String {
231
239
text
232
240
. replacingOccurrences ( of: " " , with: " ␣ " )
233
- . replacingOccurrences ( of: " <br> " , with: " ↲<br> " )
234
-
241
+ . replacingOccurrences ( of: " <br/> " , with: " ↲<br/> " )
235
242
}
236
243
}
237
244
238
- func escapeHTML( _ string: String ) -> String {
239
- var newString = string
240
- let specialCharacters = [
241
- ( " & " , " & " ) ,
242
- ( " < " , " < " ) ,
243
- ( " > " , " > " ) ,
244
- ( " \" " , " " " ) ,
245
- ( " ' " , " ' " ) ,
246
- ] ;
247
- for (unescaped, escaped) in specialCharacters {
248
- newString = newString. replacingOccurrences ( of: unescaped, with: escaped, options: . literal, range: nil )
245
+ private extension String {
246
+ func htmlEscaped( ) -> String {
247
+ var string = self
248
+ let specialCharacters = [
249
+ ( " & " , " & " ) ,
250
+ ( " < " , " < " ) ,
251
+ ( " > " , " > " ) ,
252
+ ( " \" " , " " " ) ,
253
+ ( " ' " , " ' " ) ,
254
+ ] ;
255
+ for (unescaped, escaped) in specialCharacters {
256
+ string = string. replacingOccurrences ( of: unescaped, with: escaped, options: . literal, range: nil )
257
+ }
258
+ return string
259
+ }
260
+
261
+ func substituteInvisibles( ) -> String {
262
+ self
263
+ . replacingOccurrences ( of: " " , with: " " )
264
+ . replacingOccurrences ( of: " \n " , with: " <br/> " )
265
+ }
266
+
267
+ func displayInvisibles( ) -> String {
268
+ self
269
+ . replacingOccurrences ( of: " " , with: " ␣ " )
270
+ . replacingOccurrences ( of: " \n " , with: " ↲ " )
249
271
}
250
- return newString
251
- . replacingOccurrences ( of: " " , with: " " )
252
- . replacingOccurrences ( of: " \n " , with: " <br> " )
253
272
}
0 commit comments