@@ -11,9 +11,7 @@ import dotty.tools.dotc.reporting.Reporter
11
11
import dotty .tools .dotc .reporting .diagnostic .MessageContainer
12
12
import dotty .tools .dotc .util .Positions .Position
13
13
14
- import scala .annotation .switch
15
- import scala .collection .mutable .StringBuilder
16
- import util .{Chars , SourceFile }
14
+ import util .SourceFile
17
15
18
16
import scala .collection .mutable
19
17
@@ -30,346 +28,6 @@ object SyntaxHighlighting {
30
28
val TypeColor = Console .MAGENTA
31
29
val AnnotationColor = Console .MAGENTA
32
30
33
- private def none (str : String ) = str
34
- private def keyword (str : String ) = KeywordColor + str + NoColor
35
- private def typeDef (str : String ) = TypeColor + str + NoColor
36
- private def literal (str : String ) = LiteralColor + str + NoColor
37
- private def valDef (str : String ) = ValDefColor + str + NoColor
38
- private def operator (str : String ) = TypeColor + str + NoColor
39
- private def annotation (str : String ) =
40
- if (str.trim == " @" ) str else { AnnotationColor + str + NoColor }
41
- private val tripleQs = Console .RED_B + " ???" + NoColor
42
-
43
- private val keywords : Seq [String ] = for {
44
- index <- IF to ERASED // All alpha keywords
45
- } yield tokenString(index)
46
-
47
- private val interpolationPrefixes =
48
- 'A' :: 'B' :: 'C' :: 'D' :: 'E' :: 'F' :: 'G' :: 'H' :: 'I' :: 'J' :: 'K' ::
49
- 'L' :: 'M' :: 'N' :: 'O' :: 'P' :: 'Q' :: 'R' :: 'S' :: 'T' :: 'U' :: 'V' ::
50
- 'W' :: 'X' :: 'Y' :: 'Z' :: '$' :: '_' :: 'a' :: 'b' :: 'c' :: 'd' :: 'e' ::
51
- 'f' :: 'g' :: 'h' :: 'i' :: 'j' :: 'k' :: 'l' :: 'm' :: 'n' :: 'o' :: 'p' ::
52
- 'q' :: 'r' :: 's' :: 't' :: 'u' :: 'v' :: 'w' :: 'x' :: 'y' :: 'z' :: Nil
53
-
54
- private val typeEnders =
55
- '{' :: '}' :: ')' :: '(' :: '[' :: ']' :: '=' :: ' ' :: ',' :: '.' :: '|' ::
56
- '&' :: '\n ' :: Nil
57
-
58
- def apply (chars : Iterable [Char ])(implicit ctx : Context ): Iterable [Char ] = {
59
- if (ctx.settings.color.value != " never" ) highlight(chars)
60
- else chars
61
- }
62
-
63
- def highlight (chars : Iterable [Char ]): Iterable [Char ] = {
64
- var prev : Char = 0
65
- var remaining = chars.toStream
66
- val newBuf = new StringBuilder
67
- var lastValDefToken = " "
68
-
69
- @ forceInline def keywordStart =
70
- prev == 0 || prev == ' ' || prev == '{' || prev == '(' ||
71
- prev == '\n ' || prev == '[' || prev == ',' || prev == ':' ||
72
- prev == '|' || prev == '&' || prev.isDigit
73
-
74
- @ forceInline def numberStart (c : Char ) =
75
- c.isDigit && (! prev.isLetter || prev == '.' || prev == ' ' || prev == '(' || prev == '\u0000 ' )
76
-
77
- def takeChar (): Char = takeChars(1 ).head
78
- def takeChars (x : Int ): Seq [Char ] = {
79
- val taken = remaining.take(x)
80
- remaining = remaining.drop(x)
81
- taken
82
- }
83
-
84
- while (remaining.nonEmpty) {
85
- val n = takeChar()
86
- if (interpolationPrefixes.contains(n)) {
87
- // Interpolation prefixes are a superset of the keyword start chars
88
- val (prefix, after) = remaining.span(interpolationPrefixes.contains)
89
- if (after.startsWith(" \" " )) {
90
- newBuf += n ++= prefix
91
- prev = prefix.lastOption.getOrElse(n)
92
- if (remaining.nonEmpty) takeChars(prefix.length + 1 ) // drop 1 for appendLiteral
93
- appendString('"' , after.startsWith(" \"\"\" " ), true )
94
- } else {
95
- if (n.isUpper && (keywordStart || prev == '.' )) {
96
- appendWhile(n, ! typeEnders.contains(_), typeDef)
97
- } else if (keywordStart) {
98
- append(n, keywords.contains(_), { kw =>
99
- if (kw == " new" ) typeDef(kw) else keyword(kw)
100
- })
101
- } else {
102
- newBuf += n
103
- prev = n
104
- }
105
- }
106
- } else {
107
- (n : @ switch) match {
108
- case '/' =>
109
- if (remaining.nonEmpty) {
110
- remaining.head match {
111
- case '/' =>
112
- takeChar()
113
- eolComment()
114
- case '*' =>
115
- takeChar()
116
- blockComment()
117
- case x =>
118
- newBuf += '/'
119
- }
120
- } else newBuf += '/'
121
- case '=' =>
122
- append('=' , _ == " =>" , operator)
123
- case '<' =>
124
- append('<' , { x => x == " <-" || x == " <:" || x == " <%" }, operator)
125
- case '>' =>
126
- append('>' , { x => x == " >:" }, operator)
127
- case '#' =>
128
- if (prev != ' ' && prev != '.' ) newBuf append operator(" #" )
129
- else newBuf += n
130
- prev = '#'
131
- case '@' =>
132
- appendWhile('@' , ! typeEnders.contains(_), annotation)
133
- case '\" ' =>
134
- appendString('\" ' , multiline = remaining.take(2 ).mkString == " \"\" " , false )
135
- case '\' ' =>
136
- appendSingleQuote('\' ' )
137
- case '`' =>
138
- appendTo('`' , _ == '`' , none)
139
- case _ => {
140
- if (n == '?' && remaining.take(2 ).mkString == " ??" ) {
141
- takeChars(2 )
142
- newBuf append tripleQs
143
- prev = '?'
144
- }
145
- else if (n.isUpper && keywordStart)
146
- appendWhile(n, ! typeEnders.contains(_), typeDef)
147
- else if (numberStart(n)) {
148
- def isNumber (c : Char ): Boolean =
149
- c.isDigit || c == '\u0000 ' || (c == '.' && remaining.nonEmpty && remaining.head.isDigit)
150
- appendWhile(n, isNumber, literal)
151
- } else
152
- newBuf += n; prev = n
153
- }
154
- }
155
- }
156
- }
157
-
158
- def eolComment () = {
159
- newBuf append (CommentColor + " //" )
160
- var curr = '/'
161
- while (curr != '\n ' && remaining.nonEmpty) {
162
- curr = takeChar()
163
- newBuf += curr
164
- }
165
- prev = curr
166
- newBuf append NoColor
167
- }
168
-
169
- def blockComment () = {
170
- newBuf append (CommentColor + " /*" )
171
- var curr = '*'
172
- var open = 1
173
- while (open > 0 && remaining.nonEmpty) {
174
- curr = takeChar()
175
- if (curr == '@' ) {
176
- appendWhile('@' , ! typeEnders.contains(_), annotation)
177
- newBuf append CommentColor
178
- }
179
- else newBuf += curr
180
-
181
- if (curr == '*' && remaining.nonEmpty) {
182
- curr = takeChar()
183
- newBuf += curr
184
- if (curr == '/' ) open -= 1
185
- } else if (curr == '/' && remaining.nonEmpty) {
186
- curr = takeChar()
187
- newBuf += curr
188
- if (curr == '*' ) open += 1
189
- }
190
-
191
- if (Chars .isLineBreakChar(curr)) {
192
- newBuf append CommentColor
193
- }
194
- }
195
- prev = curr
196
- newBuf append NoColor
197
- }
198
-
199
- def appendString (delim : Char , multiline : Boolean = false , inInterpolation : Boolean ) = {
200
- var curr : Char = 0
201
- var continue = true
202
- var closing = 0
203
- newBuf append (LiteralColor + delim)
204
-
205
- def shouldInterpolate =
206
- inInterpolation && curr == '$' && prev != '$' && remaining.nonEmpty
207
-
208
- def interpolate () = {
209
- val next = takeChar()
210
- if (next == '$' ) {
211
- newBuf += curr
212
- newBuf += next
213
- prev = '$'
214
- } else if (next == '{' ) {
215
- var open = 1 // keep track of open blocks
216
- newBuf append (ValDefColor + curr)
217
- newBuf += next
218
- while (remaining.nonEmpty && open > 0 ) {
219
- var c = takeChar()
220
- newBuf += c
221
- if (c == '}' ) open -= 1
222
- else if (c == '{' ) open += 1
223
- }
224
- newBuf append LiteralColor
225
- } else {
226
- newBuf append (ValDefColor + curr)
227
- newBuf += next
228
- var c : Char = 'a'
229
- while (c.isLetterOrDigit && remaining.nonEmpty) {
230
- c = takeChar()
231
- if (c != '"' ) newBuf += c
232
- }
233
- newBuf append LiteralColor
234
- if (c == '"' ) {
235
- newBuf += c
236
- continue = false
237
- }
238
- }
239
- closing = 0
240
- }
241
-
242
- while (continue && remaining.nonEmpty) {
243
- curr = takeChar()
244
- if (curr == '\\ ' && remaining.nonEmpty) {
245
- val next = takeChar()
246
- newBuf append (KeywordColor + curr)
247
- if (next == 'u' ) {
248
- val code = " u" + takeChars(4 ).mkString
249
- newBuf append code
250
- } else newBuf += next
251
- newBuf append LiteralColor
252
- closing = 0
253
- } else if (shouldInterpolate) {
254
- interpolate()
255
- } else if (curr == delim && multiline) {
256
- closing += 1
257
- if (closing == 3 ) continue = false
258
- newBuf += curr
259
- } else if (curr == delim) {
260
- continue = false
261
- newBuf += curr
262
- } else {
263
- newBuf += curr
264
- closing = 0
265
- }
266
-
267
- if (Chars .isLineBreakChar(curr)) {
268
- newBuf append LiteralColor
269
- }
270
- }
271
- newBuf append NoColor
272
- prev = curr
273
- }
274
-
275
- def appendSingleQuote (delim : Char ) = remaining.take(3 ) match {
276
- case chr #:: '\' ' #:: _ => // single character
277
- newBuf append LiteralColor
278
- newBuf appendAll s " ' $chr' "
279
- newBuf append NoColor
280
- takeChars(2 )
281
- prev = '\' '
282
- case '\\ ' #:: chr #:: '\' ' #:: _ => // escaped character
283
- newBuf append LiteralColor
284
- newBuf appendAll s " ' \\ $chr' "
285
- newBuf append NoColor
286
- takeChars(3 )
287
- prev = '\' '
288
- case _ => appendWhile(delim, ! typeEnders.contains(_), literal)
289
- }
290
-
291
- def append (c : Char , shouldHL : String => Boolean , highlight : String => String ) = {
292
- var curr : Char = 0
293
- val sb = new StringBuilder (s " $c" )
294
-
295
- def delim (c : Char ) = (c : @ switch) match {
296
- case ' ' => true
297
- case '\n ' => true
298
- case '(' => true
299
- case ')' => true
300
- case '[' => true
301
- case ']' => true
302
- case ':' => true
303
- case '@' => true
304
- case ',' => true
305
- case '.' => true
306
- case _ => false
307
- }
308
-
309
- val valDefStarterTokens = " var" :: " val" :: " def" :: " case" :: Nil
310
-
311
- /** lastValDefToken is used to check whether we want to show something
312
- * in valDef color or not. There are only a few cases when lastValDefToken
313
- * should be updated, that way we can avoid stopping coloring too early.
314
- * eg.: case A(x, y, z) => ???
315
- * Without this function only x would be colored.
316
- */
317
- def updateLastToken (currentToken : String ): String =
318
- (lastValDefToken, currentToken) match {
319
- case _ if valDefStarterTokens.contains(currentToken) => currentToken
320
- case ((" val" | " var" ), " =" ) => currentToken
321
- case (" case" , (" =>" | " class" | " object" )) => currentToken
322
- case (" def" , _) => currentToken
323
- case _ => lastValDefToken
324
- }
325
-
326
- while (remaining.nonEmpty && ! delim(curr)) {
327
- curr = takeChar()
328
- if (! delim(curr)) sb += curr
329
- }
330
-
331
- val str = sb.toString
332
- val toAdd =
333
- if (shouldHL(str))
334
- highlight(str)
335
- else if (valDefStarterTokens.contains(lastValDefToken) && ! List (" =" , " =>" ).contains(str))
336
- valDef(str)
337
- else str
338
- val suffix = if (delim(curr)) s " $curr" else " "
339
- newBuf append (toAdd + suffix)
340
- lastValDefToken = updateLastToken(str)
341
- prev = curr
342
- }
343
-
344
- def appendWhile (c : Char , pred : Char => Boolean , highlight : String => String ) = {
345
- var curr : Char = 0
346
- val sb = new StringBuilder (s " $c" )
347
- while (remaining.nonEmpty && pred(curr)) {
348
- curr = takeChar()
349
- if (pred(curr)) sb += curr
350
- }
351
-
352
- val str = sb.toString
353
- val suffix = if (! pred(curr)) s " $curr" else " "
354
- newBuf append (highlight(str) + suffix)
355
- prev = curr
356
- }
357
-
358
- def appendTo (c : Char , pred : Char => Boolean , highlight : String => String ) = {
359
- var curr : Char = 0
360
- val sb = new StringBuilder (s " $c" )
361
- while (remaining.nonEmpty && ! pred(curr)) {
362
- curr = takeChar()
363
- sb += curr
364
- }
365
-
366
- newBuf append highlight(sb.toString)
367
- prev = curr
368
- }
369
-
370
- newBuf.toIterable
371
- }
372
-
373
31
private class NoReporter extends Reporter {
374
32
override def doReport (m : MessageContainer )(implicit ctx : Context ): Unit = ()
375
33
}
0 commit comments