Skip to content

Commit 71f3aca

Browse files
authored
Merge pull request #4648 from dotty-staging/topic/tasty-doc-ide
Show docs in the IDE
2 parents 8a50365 + b47cc1f commit 71f3aca

File tree

5 files changed

+58
-32
lines changed

5 files changed

+58
-32
lines changed

compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class InteractiveDriver(val settings: List[String]) extends Driver {
3131
override def sourcesRequired = false
3232

3333
private val myInitCtx: Context = {
34-
val rootCtx = initCtx.fresh.addMode(Mode.ReadPositions).addMode(Mode.Interactive)
34+
val rootCtx = initCtx.fresh.addMode(Mode.ReadPositions).addMode(Mode.Interactive).addMode(Mode.ReadComments)
3535
rootCtx.setSetting(rootCtx.settings.YretainTrees, true)
3636
val ctx = setup(settings.toArray, rootCtx)._2
3737
ctx.initialize()(ctx)

language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala

+20-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import scala.io.Codec
1919
import dotc._
2020
import ast.{Trees, tpd}
2121
import core._, core.Decorators.{sourcePos => _, _}
22-
import Contexts._, Flags._, Names._, NameOps._, Symbols._, SymDenotations._, Trees._, Types._
22+
import Comments._, Contexts._, Flags._, Names._, NameOps._, Symbols._, SymDenotations._, Trees._, Types._
2323
import classpath.ClassPathEntries
2424
import reporting._, reporting.diagnostic.MessageContainer
2525
import util._
@@ -340,13 +340,16 @@ class DottyLanguageServer extends LanguageServer
340340
implicit val ctx = driver.currentCtx
341341

342342
val pos = sourcePosition(driver, uri, params.getPosition)
343-
val tp = Interactive.enclosingType(driver.openedTrees(uri), pos)
343+
val trees = driver.openedTrees(uri)
344+
val tp = Interactive.enclosingType(trees, pos)
344345
val tpw = tp.widenTermRefExpr
345346

346347
if (tpw == NoType) new Hover
347348
else {
348-
val str = tpw.show.toString
349-
new Hover(List(JEither.forLeft(str)).asJava, null)
349+
val symbol = Interactive.enclosingSourceSymbol(trees, pos)
350+
val docComment = ctx.docCtx.flatMap(_.docstring(symbol))
351+
val markedStrings = docMarkedStrings(docComment, tpw.show.toString)
352+
new Hover(markedStrings.map(JEither.forRight(_)).asJava, null)
350353
}
351354
}
352355

@@ -463,6 +466,19 @@ object DottyLanguageServer {
463466
item
464467
}
465468

469+
private def docMarkedStrings(comment: Option[Comment], typeInfo: String): List[lsp4j.MarkedString] = {
470+
471+
val docHover = comment.map { comment =>
472+
new lsp4j.MarkedString("scala", comment.raw)
473+
}
474+
475+
val typeInfoHover = new lsp4j.MarkedString()
476+
typeInfoHover.setValue(typeInfo)
477+
478+
typeInfoHover :: docHover.toList
479+
}
480+
481+
466482
/** Create an lsp4j.SymbolInfo from a Symbol and a SourcePosition */
467483
def symbolInfo(sym: Symbol, pos: SourcePosition)(implicit ctx: Context): lsp4j.SymbolInformation = {
468484
def symbolKind(sym: Symbol)(implicit ctx: Context): lsp4j.SymbolKind = {

language-server/test/dotty/tools/languageserver/HoverTest.scala

+27-20
Original file line numberDiff line numberDiff line change
@@ -7,53 +7,60 @@ import dotty.tools.languageserver.util.Code._
77
class HoverTest {
88

99
@Test def hoverOnWhiteSpace0: Unit =
10-
code"$m1 $m2".withSource.hover(m1 to m2, "")
10+
code"$m1 $m2".withSource.hover(m1 to m2, Nil)
11+
12+
@Test def hoverOnClassShowsDoc: Unit = {
13+
code"""$m1 /** foo */ ${m2}class Foo $m3 $m4""".withSource
14+
.hover(m1 to m2, Nil)
15+
.hover(m2 to m3, List("Foo", "/** foo */"))
16+
.hover(m3 to m4, Nil)
17+
}
1118

1219
@Test def hoverOnClass0: Unit = {
1320
code"""$m1 ${m2}class Foo $m3 $m4""".withSource
14-
.hover(m1 to m2, "")
15-
.hover(m2 to m3, "Foo")
16-
.hover(m3 to m4, "")
21+
.hover(m1 to m2, Nil)
22+
.hover(m2 to m3, "Foo" :: Nil)
23+
.hover(m3 to m4, Nil)
1724
}
1825

1926
@Test def hoverOnClass1: Unit = {
2027
code"""$m1 ${m2}class Foo { } $m3 $m4""".withSource
21-
.hover(m1 to m2, "")
22-
.hover(m2 to m3, "Foo")
23-
.hover(m3 to m4, "")
28+
.hover(m1 to m2, Nil)
29+
.hover(m2 to m3, "Foo" :: Nil)
30+
.hover(m3 to m4, Nil)
2431
}
2532

2633
@Test def hoverOnValDef0: Unit = {
2734
code"""class Foo {
2835
| ${m1}val x = ${m2}8$m3; ${m4}x$m5
2936
|}""".withSource
30-
.hover(m1 to m2, "Int")
31-
.hover(m2 to m3, "Int(8)")
32-
.hover(m4 to m5, "Int")
37+
.hover(m1 to m2, "Int" :: Nil)
38+
.hover(m2 to m3, "Int(8)" :: Nil)
39+
.hover(m4 to m5, "Int" :: Nil)
3340
}
3441

3542
@Test def hoverOnValDef1: Unit = {
3643
code"""class Foo {
3744
| ${m1}final val x = 8$m2; ${m3}x$m4
3845
|}""".withSource
39-
.hover(m1 to m2, "Int(8)")
40-
.hover(m3 to m4, "Int(8)")
46+
.hover(m1 to m2, "Int(8)" :: Nil)
47+
.hover(m3 to m4, "Int(8)" :: Nil)
4148
}
4249

4350
@Test def hoverOnDefDef0: Unit = {
4451
code"""class Foo {
4552
| ${m1}def x = ${m2}8$m3; ${m4}x$m5
4653
|}""".withSource
47-
.hover(m1 to m2, "Int")
48-
.hover(m2 to m3, "Int(8)")
49-
.hover(m4 to m5, "Int")
54+
.hover(m1 to m2, "Int" :: Nil)
55+
.hover(m2 to m3, "Int(8)" :: Nil)
56+
.hover(m4 to m5, "Int" :: Nil)
5057
}
5158

5259
@Test def hoverMissingRef0: Unit = {
5360
code"""class Foo {
5461
| ${m1}x$m2
5562
|}""".withSource
56-
.hover(m1 to m2, "<error not found: x>")
63+
.hover(m1 to m2, "<error not found: x>" :: Nil)
5764
}
5865

5966
@Test def hoverFun0: Unit = {
@@ -65,10 +72,10 @@ class HoverTest {
6572
| ${m5}y($m6)$m7
6673
|}
6774
""".withSource
68-
.hover(m1 to m2, "String(\"abc\")")
69-
.hover(m3 to m4, "String")
70-
.hover(m5 to m6, "(): Int")
71-
.hover(m6 to m7, "Int")
75+
.hover(m1 to m2, "String(\"abc\")" :: Nil)
76+
.hover(m3 to m4, "String" :: Nil)
77+
.hover(m5 to m6, "(): Int" :: Nil)
78+
.hover(m6 to m7, "Int" :: Nil)
7279
}
7380

7481
}

language-server/test/dotty/tools/languageserver/util/CodeTester.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ class CodeTester(sources: List[SourceWithPositions], actions: List[Action]) {
2525
* Perform a hover over `range`, verifies that result matches `expected`.
2626
*
2727
* @param range The range over which to hover.
28-
* @param expected The expected result.
28+
* @param expected The expected results.
2929
*
3030
* @see dotty.tools.languageserver.util.actions.CodeHover
3131
*/
32-
def hover(range: CodeRange, expected: String): this.type =
32+
def hover(range: CodeRange, expected: List[String]): this.type =
3333
doAction(new CodeHover(range, expected))
3434

3535
/**

language-server/test/dotty/tools/languageserver/util/actions/CodeHover.scala

+8-5
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,27 @@ import dotty.tools.languageserver.util.{CodeRange, PositionContext}
55

66
import org.junit.Assert.{assertEquals, assertNull, assertTrue}
77

8+
import scala.collection.JavaConverters._
9+
810
/**
911
* An action requesting for the info shown when `range` is hovered.
1012
* This action corresponds to the `textDocument/hover` method of the Language Server Protocol.
1113
*
1214
* @param range The range of positions that should be hovered.
1315
* @param expected The expected result.
1416
*/
15-
class CodeHover(override val range: CodeRange, expected: String) extends ActionOnRange {
17+
class CodeHover(override val range: CodeRange, expected: List[String]) extends ActionOnRange {
1618

1719
override def onMarker(marker: CodeMarker): Exec[Unit] = {
1820
val result = server.hover(marker.toTextDocumentPositionParams).get()
1921
assertNull(result.getRange)
2022
if (expected.isEmpty) assertNull(result.getContents)
2123
else {
22-
assertEquals(1, result.getContents.size)
23-
val content = result.getContents.get(0)
24-
assertTrue(content.isLeft)
25-
assertEquals(expected, content.getLeft)
24+
assertEquals(expected.size, result.getContents.size)
25+
expected.zip(result.getContents.asScala).foreach { case (expected, actual) =>
26+
assertTrue(actual.isRight)
27+
assertEquals(expected, actual.getRight.getValue)
28+
}
2629
}
2730
}
2831

0 commit comments

Comments
 (0)