Skip to content

Commit ed464b0

Browse files
committed
Add annotations highlight
- Highlight is based on MemberDef with annotations present - move scanner highlighter before parser so that annotation @inline wholdn't be highlighted as keyword - annotations are highlighted when full member definition is available
1 parent 65634a9 commit ed464b0

File tree

2 files changed

+48
-24
lines changed

2 files changed

+48
-24
lines changed

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

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -370,17 +370,12 @@ object SyntaxHighlighting {
370370
override def doReport(m: MessageContainer)(implicit ctx: Context): Unit = ()
371371
}
372372

373-
private val ignoredKwds = Set(nme.ARROWkw, nme.EQ, nme.EQL, nme.COLONkw)
374-
375373
def highlight(in: String)(ctx0: Context): String = {
376374
import dotty.tools.dotc.ast.untpd._
377375

378376
implicit val ctx: Context = ctx0.fresh.setReporter(new NoReporter)
379377

380378
val source = new SourceFile("<highlighting>", in.toCharArray)
381-
val parser = new Parser(source)
382-
val trees = parser.blockStatSeq()
383-
384379
val colorAt = Array.fill(in.length)(NoColor)
385380

386381
def highlightRange(from: Int, to: Int, color: String) = {
@@ -395,18 +390,39 @@ object SyntaxHighlighting {
395390
def highlightPosition(pos: Position, color: String) =
396391
if (pos.exists) highlightRange(pos.start, pos.end, color)
397392

393+
val scanner = new Scanner(source)
394+
395+
while (scanner.token != EOF) {
396+
val isKwd = alphaKeywords.contains(scanner.token)
397+
val offsetStart = scanner.offset
398+
399+
if (scanner.token == IDENTIFIER && scanner.name == nme.???) {
400+
highlightRange(scanner.offset, scanner.offset + scanner.name.length, Console.RED_B)
401+
}
402+
scanner.nextToken()
403+
404+
if (isKwd) {
405+
val offsetEnd = scanner.lastOffset
406+
highlightPosition(Position(offsetStart, offsetEnd), KeywordColor)
407+
}
408+
}
409+
398410
val treeHighlighter = new UntypedTreeTraverser {
399411
def traverse(tree: Tree)(implicit ctx: Context): Unit = {
400412
tree match {
401-
case id: Ident if id.isType =>
413+
case id : Ident if id.isType =>
402414
highlightPosition(id.pos, TypeColor)
403415
case tpe : TypeDef =>
416+
for (annotation <- tpe.rawMods.annotations)
417+
highlightPosition(annotation.pos, AnnotationColor)
404418
highlightPosition(tpe.namePos, TypeColor)
405419
case _ : TypTree =>
406420
highlightPosition(tree.pos, TypeColor)
407421
case mod: ModuleDef =>
408422
highlightPosition(mod.namePos, TypeColor)
409423
case v : ValOrDefDef =>
424+
for (annotation <- v.rawMods.annotations)
425+
highlightPosition(annotation.pos, AnnotationColor)
410426
highlightPosition(v.namePos, ValDefColor)
411427
highlightPosition(v.tpt.pos, TypeColor)
412428
case _ : Literal =>
@@ -417,26 +433,12 @@ object SyntaxHighlighting {
417433
}
418434
}
419435

436+
val parser = new Parser(source)
437+
val trees = parser.blockStatSeq()
438+
420439
for (tree <- trees)
421440
treeHighlighter.traverse(tree)
422441

423-
val scanner = new Scanner(source)
424-
425-
while (scanner.token != EOF) {
426-
val isKwd = isKeyword(scanner.token) && !ignoredKwds.contains(scanner.name)
427-
val offsetStart = scanner.offset
428-
429-
if (scanner.token == IDENTIFIER && scanner.name == nme.???) {
430-
highlightRange(scanner.offset, scanner.offset + scanner.name.length, Console.RED_B)
431-
}
432-
scanner.nextToken()
433-
434-
if (isKwd) {
435-
val offsetEnd = scanner.lastOffset
436-
highlightPosition(Position(offsetStart, offsetEnd), KeywordColor)
437-
}
438-
}
439-
440442
val sb = new mutable.StringBuilder()
441443

442444
for (idx <- colorAt.indices) {

compiler/test/dotty/tools/dotc/printing/SyntaxHighlightingTests.scala

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,33 @@ class SyntaxHighlightingTests extends DottyTest {
5050
def strings = {
5151
// For some reason we currently use literal color for string
5252
test("\"Hello\"", "<L|\"Hello\">")
53+
test("s\"Hello\"", "s<L|\"Hello\">")
54+
// test("s\"Hello $name\"", "s<L|\"Hello <V|$name<L|\">")
55+
test("raw\"Hello\"", "raw<L|\"Hello\">")
56+
test("s\"\"\"Hello\"\"\"", "s<L|\"\"\"Hello\"\"\">")
5357
}
5458

5559
@Test
5660
def annotations = {
57-
test("@tailrec", "<T|@tailrec>")
61+
val source =
62+
"""
63+
|@deprecated
64+
|class Foo {
65+
| @inline val bar = 42
66+
|}
67+
""".stripMargin
68+
69+
val expected =
70+
"""
71+
|<T|@deprecated>
72+
|<K|class> <T|Foo> {
73+
| <T|@inline> <K|val> <V|bar> = <L|42>
74+
|}
75+
""".stripMargin
76+
77+
test(source, expected)
78+
79+
test("@deprecated class Foo", "<T|@deprecated> <K|class> <T|Foo>")
5880
}
5981

6082
@Test

0 commit comments

Comments
 (0)