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