1- package dotty .tools
2- package dotc
3- package printing
1+ package dotty .tools .dotc .printing
42
3+ import dotty .tools .dotc .ast .untpd
54import dotty .tools .dotc .core .Contexts .Context
65import dotty .tools .dotc .core .StdNames ._
76import dotty .tools .dotc .parsing .Parsers .Parser
@@ -10,14 +9,16 @@ import dotty.tools.dotc.parsing.Tokens._
109import dotty .tools .dotc .reporting .Reporter
1110import dotty .tools .dotc .reporting .diagnostic .MessageContainer
1211import dotty .tools .dotc .util .Positions .Position
12+ import dotty .tools .dotc .util .SourceFile
1313
14- import util .SourceFile
15-
16- import scala .collection .mutable
14+ import java .util .Arrays
1715
1816/** This object provides functions for syntax highlighting in the REPL */
1917object SyntaxHighlighting {
2018
19+ /** if true, log erroneous positions being highlighted */
20+ private final val debug = false
21+
2122 // Keep in sync with SyntaxHighlightingTests
2223 val NoColor = Console .RESET
2324 val CommentColor = Console .BLUE
@@ -32,88 +33,89 @@ object SyntaxHighlighting {
3233 override def doReport (m : MessageContainer )(implicit ctx : Context ): Unit = ()
3334 }
3435
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)
5054 }
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)
5655
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 )
6368 }
64- scanner.nextToken()
6569
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 ._
7172
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
9377 }
94- traverseChildren(tree)
95- }
96- }
9778
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+ }
10099
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)
103104
104- val sb = new mutable. StringBuilder ()
105+ val highlighted = new StringBuilder ()
105106
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))
110113 }
111- sb.append(in(idx))
112- }
113- if (colorAt.nonEmpty && colorAt.last != NoColor ) {
114- sb.append(NoColor )
115- }
116114
117- sb.toString
115+ if (colorAt.last != NoColor )
116+ highlighted.append(NoColor )
117+
118+ highlighted.toString
119+ }
118120 }
119121}
0 commit comments