Skip to content

Commit be2e6b4

Browse files
slothspotallanrenucci
authored andcommitted
Introduce Parser and Scanner based highlighter
1 parent 8b6b965 commit be2e6b4

File tree

2 files changed

+94
-3
lines changed

2 files changed

+94
-3
lines changed

compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,20 @@ package dotty.tools
22
package dotc
33
package printing
44

5-
import parsing.Tokens._
5+
import dotty.tools.dotc.core.Contexts.Context
6+
import dotty.tools.dotc.core.StdNames._
7+
import dotty.tools.dotc.parsing.Parsers.Parser
8+
import dotty.tools.dotc.parsing.Scanners.Scanner
9+
import dotty.tools.dotc.parsing.Tokens._
10+
import dotty.tools.dotc.reporting.Reporter
11+
import dotty.tools.dotc.reporting.diagnostic.MessageContainer
12+
import dotty.tools.dotc.util.Positions.Position
13+
614
import scala.annotation.switch
715
import scala.collection.mutable.StringBuilder
8-
import util.Chars
16+
import util.{Chars, SourceFile}
17+
18+
import scala.collection.mutable
919

1020
/** This object provides functions for syntax highlighting in the REPL */
1121
object SyntaxHighlighting {
@@ -354,4 +364,85 @@ object SyntaxHighlighting {
354364

355365
newBuf.toIterable
356366
}
367+
368+
private class NoReporter extends Reporter {
369+
override def doReport(m: MessageContainer)(implicit ctx: Context): Unit = ()
370+
}
371+
372+
def highlight(in: String)(ctx0: Context): String = {
373+
import dotty.tools.dotc.ast.untpd._
374+
375+
implicit val ctx: Context = ctx0.fresh.setReporter(new NoReporter)
376+
377+
val sf = new SourceFile("<highlighting>", in.toCharArray)
378+
val p = new Parser(sf)
379+
val s = new Scanner(sf)
380+
val trees = p.blockStatSeq()
381+
382+
val outputH = Array.fill(in.length)(NoColor)
383+
384+
def highlightRange(p: Position, color: String): Unit = {
385+
if(p.exists) {
386+
for {
387+
i <- p.start until math.min(p.end, outputH.length)
388+
} outputH(i) = color
389+
}
390+
}
391+
392+
val treeTraverser = new UntypedTreeTraverser {
393+
def traverse(tree: Tree)(implicit ctx: Context): Unit = {
394+
tree match {
395+
case tpe : TypeDef =>
396+
highlightRange(tpe.namePos, TypeColor)
397+
case _ : TypTree =>
398+
highlightRange(tree.pos, TypeColor)
399+
case mod: ModuleDef =>
400+
highlightRange(mod.namePos, TypeColor)
401+
case v : ValOrDefDef =>
402+
highlightRange(v.namePos, ValDefColor)
403+
highlightRange(v.tpt.pos, TypeColor)
404+
case _ : Literal =>
405+
highlightRange(tree.pos, LiteralColor)
406+
case _ =>
407+
}
408+
traverseChildren(tree)
409+
}
410+
}
411+
412+
for {
413+
t <- trees
414+
} {
415+
treeTraverser.traverse(t)
416+
}
417+
418+
val sb = new mutable.StringBuilder()
419+
420+
while(s.token != EOF) {
421+
val isKwd = isKeyword(s.token)
422+
val offsetStart = s.offset
423+
424+
425+
if(s.token == IDENTIFIER && s.name == nme.???) {
426+
highlightRange(Position(s.offset, s.offset + s.name.length), Console.RED_B)
427+
}
428+
s.nextToken()
429+
430+
if(isKwd) {
431+
val offsetEnd = s.lastOffset
432+
highlightRange(Position(offsetStart, offsetEnd), KeywordColor)
433+
}
434+
}
435+
436+
for {
437+
idx <- outputH.indices
438+
} {
439+
if(idx == 0 || outputH(idx-1) != outputH(idx)){
440+
sb.append(outputH(idx))
441+
}
442+
sb.append(in(idx))
443+
}
444+
sb.append(NoColor)
445+
446+
sb.mkString
447+
}
357448
}

compiler/src/dotty/tools/repl/AmmoniteReader.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ private[repl] class AmmoniteReader(out: OutputStream,
105105

106106
def displayTransform(buffer: Vector[Char], cursor: Int): (Ansi.Str, Int) = {
107107
val coloredBuffer =
108-
SyntaxHighlighting(buffer)
108+
SyntaxHighlighting.highlight(buffer.mkString)(ctx)
109109

110110
val ansiBuffer = Ansi.Str.parse(coloredBuffer.toVector)
111111
val (newBuffer, cursorOffset) = SelectionFilter.mangleBuffer(

0 commit comments

Comments
 (0)