1
- package dotty .tools
2
- package dotc
3
- package printing
1
+ package dotty .tools .dotc .printing
4
2
3
+ import dotty .tools .dotc .ast .untpd
5
4
import dotty .tools .dotc .core .Contexts .Context
6
5
import dotty .tools .dotc .core .StdNames ._
7
6
import dotty .tools .dotc .parsing .Parsers .Parser
@@ -10,14 +9,16 @@ import dotty.tools.dotc.parsing.Tokens._
10
9
import dotty .tools .dotc .reporting .Reporter
11
10
import dotty .tools .dotc .reporting .diagnostic .MessageContainer
12
11
import dotty .tools .dotc .util .Positions .Position
12
+ import dotty .tools .dotc .util .SourceFile
13
13
14
- import util .SourceFile
15
-
16
- import scala .collection .mutable
14
+ import java .util .Arrays
17
15
18
16
/** This object provides functions for syntax highlighting in the REPL */
19
17
object SyntaxHighlighting {
20
18
19
+ /** if true, log erroneous positions being highlighted */
20
+ private final val debug = false
21
+
21
22
// Keep in sync with SyntaxHighlightingTests
22
23
val NoColor = Console .RESET
23
24
val CommentColor = Console .BLUE
@@ -32,88 +33,89 @@ object SyntaxHighlighting {
32
33
override def doReport (m : MessageContainer )(implicit ctx : Context ): Unit = ()
33
34
}
34
35
35
- def highlight (in : String )(ctx0 : Context ): String = {
36
- import dotty .tools .dotc .ast .untpd ._
37
-
38
- implicit val ctx : Context = ctx0.fresh.setReporter(new NoReporter )
39
-
40
- val source = new SourceFile (" <highlighting>" , in.toCharArray)
41
- val colorAt = Array .fill(in.length)(NoColor )
42
-
43
- def highlightRange (from : Int , to : Int , color : String ) = {
44
- try {
45
- for (i <- from until to)
46
- colorAt(i) = color
47
- } catch {
48
- case _ : IndexOutOfBoundsException =>
49
- println(" Encountered tree with invalid position, please open an issue with the code snippet that caused the error" )
36
+ def highlight (in : String )(implicit ctx : Context ): String = {
37
+ def freshCtx = ctx.fresh.setReporter(new NoReporter )
38
+ if (in.isEmpty || ctx.settings.color.value == " never" ) in
39
+ else {
40
+ implicit val ctx = freshCtx
41
+ val source = new SourceFile (" <highlighting>" , in.toCharArray)
42
+ val colorAt = Array .fill(in.length)(NoColor )
43
+
44
+ def highlightRange (from : Int , to : Int , color : String ) =
45
+ Arrays .fill(colorAt.asInstanceOf [Array [AnyRef ]], from, to, color)
46
+
47
+ def highlightPosition (pos : Position , color : String ) = if (pos.exists) {
48
+ if (pos.start < 0 || pos.end > in.length) {
49
+ if (debug)
50
+ println(s " Trying to highlight erroneous position $pos. Input size: ${in.length}" )
51
+ }
52
+ else
53
+ highlightRange(pos.start, pos.end, color)
50
54
}
51
- }
52
- def highlightPosition (pos : Position , color : String ) =
53
- if (pos.exists) highlightRange(pos.start, pos.end, color)
54
-
55
- val scanner = new Scanner (source)
56
55
57
- while (scanner.token != EOF ) {
58
- val isKwd = alphaKeywords.contains(scanner.token)
59
- val offsetStart = scanner.offset
60
-
61
- if (scanner.token == IDENTIFIER && scanner.name == nme.??? ) {
62
- highlightRange(scanner.offset, scanner.offset + scanner.name.length, Console .RED_B )
56
+ val scanner = new Scanner (source)
57
+ while (scanner.token != EOF ) {
58
+ val start = scanner.offset
59
+ val token = scanner.token
60
+ val name = scanner.name
61
+ scanner.nextToken()
62
+ val end = scanner.lastOffset
63
+
64
+ if (alphaKeywords.contains(token))
65
+ highlightRange(start, end, KeywordColor )
66
+ else if (token == IDENTIFIER && name == nme.??? )
67
+ highlightRange(start, end, Console .RED_B )
63
68
}
64
- scanner.nextToken()
65
69
66
- if (isKwd) {
67
- val offsetEnd = scanner.lastOffset
68
- highlightPosition(Position (offsetStart, offsetEnd), KeywordColor )
69
- }
70
- }
70
+ val treeHighlighter = new untpd.UntypedTreeTraverser {
71
+ import untpd ._
71
72
72
- val treeHighlighter = new UntypedTreeTraverser {
73
- def traverse (tree : Tree )(implicit ctx : Context ): Unit = {
74
- tree match {
75
- case id : Ident if id.isType =>
76
- highlightPosition(id.pos, TypeColor )
77
- case tpe : TypeDef =>
78
- for (annotation <- tpe.rawMods.annotations)
79
- highlightPosition(annotation.pos, AnnotationColor )
80
- highlightPosition(tpe.namePos, TypeColor )
81
- case _ : TypTree =>
82
- highlightPosition(tree.pos, TypeColor )
83
- case mod : ModuleDef =>
84
- highlightPosition(mod.namePos, TypeColor )
85
- case v : ValOrDefDef =>
86
- for (annotation <- v.rawMods.annotations)
87
- highlightPosition(annotation.pos, AnnotationColor )
88
- highlightPosition(v.namePos, ValDefColor )
89
- highlightPosition(v.tpt.pos, TypeColor )
90
- case _ : Literal =>
91
- highlightPosition(tree.pos, LiteralColor )
92
- case _ =>
73
+ def ignored (tree : NameTree ) = {
74
+ val name = tree.name.toTermName
75
+ // trees named <error> and <init> have weird positions
76
+ name == nme.ERROR || name == nme.CONSTRUCTOR
93
77
}
94
- traverseChildren(tree)
95
- }
96
- }
97
78
98
- val parser = new Parser (source)
99
- val trees = parser.blockStatSeq()
79
+ def traverse (tree : Tree )(implicit ctx : Context ): Unit = {
80
+ tree match {
81
+ case tree : NameTree if ignored(tree) =>
82
+ ()
83
+ case tree : MemberDef /* ValOrDefDef | ModuleDef | TypeDef */ =>
84
+ for (annotation <- tree.rawMods.annotations)
85
+ highlightPosition(annotation.pos, AnnotationColor )
86
+ val color = if (tree.isInstanceOf [ValOrDefDef ]) ValDefColor else TypeColor
87
+ highlightPosition(tree.namePos, color)
88
+ case tree : Ident if tree.isType =>
89
+ highlightPosition(tree.pos, TypeColor )
90
+ case _ : TypTree =>
91
+ highlightPosition(tree.pos, TypeColor )
92
+ case _ : Literal =>
93
+ highlightPosition(tree.pos, LiteralColor )
94
+ case _ =>
95
+ }
96
+ traverseChildren(tree)
97
+ }
98
+ }
100
99
101
- for (tree <- trees)
102
- treeHighlighter.traverse(tree)
100
+ val parser = new Parser (source)
101
+ val trees = parser.blockStatSeq()
102
+ for (tree <- trees)
103
+ treeHighlighter.traverse(tree)
103
104
104
- val sb = new mutable. StringBuilder ()
105
+ val highlighted = new StringBuilder ()
105
106
106
- for (idx <- colorAt.indices) {
107
- if ( (idx == 0 && colorAt(idx) != NoColor )
108
- || (idx > 0 && colorAt(idx- 1 ) != colorAt(idx))) {
109
- sb.append(colorAt(idx))
107
+ for (idx <- colorAt.indices) {
108
+ val prev = if (idx == 0 ) NoColor else colorAt(idx - 1 )
109
+ val curr = colorAt(idx)
110
+ if (curr != prev)
111
+ highlighted.append(curr)
112
+ highlighted.append(in(idx))
110
113
}
111
- sb.append(in(idx))
112
- }
113
- if (colorAt.nonEmpty && colorAt.last != NoColor ) {
114
- sb.append(NoColor )
115
- }
116
114
117
- sb.toString
115
+ if (colorAt.last != NoColor )
116
+ highlighted.append(NoColor )
117
+
118
+ highlighted.toString
119
+ }
118
120
}
119
121
}
0 commit comments