Skip to content

Commit

Permalink
Repl - method signatures in autocomplete (scala#19917)
Browse files Browse the repository at this point in the history
Closes scala#17367 

This PR brings method signatures to repl completions, as in Scala 2 repl
(but with syntax highlighting).

After typing `List(1).max<TAB>`:

![image](https://github.com/scala/scala3/assets/24961583/0846e7b1-ff44-4e95-aaff-398069821b2f)
  • Loading branch information
Florian3k authored Mar 17, 2024
1 parent b782cbf commit b0ba045
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 21 deletions.
52 changes: 32 additions & 20 deletions compiler/src/dotty/tools/repl/ReplDriver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import dotty.tools.dotc.util.{SourceFile, SourcePosition}
import dotty.tools.dotc.{CompilationUnit, Driver}
import dotty.tools.dotc.config.CompilerCommand
import dotty.tools.io.*
import dotty.tools.repl.Rendering.showUser
import dotty.tools.runner.ScalaClassLoader.*
import org.jline.reader.*

Expand Down Expand Up @@ -149,11 +150,36 @@ class ReplDriver(settings: Array[String],

/** Blockingly read a line, getting back a parse result */
def readLine()(using state: State): ParseResult = {
val completer: Completer = { (_, line, candidates) =>
given Context = state.context
val completer: Completer = { (lineReader, line, candidates) =>
def makeCandidate(label: String) = {
new Candidate(
/* value = */ label,
/* displ = */ stripBackTicks(label), // displayed value
/* group = */ null, // can be used to group completions together
/* descr = */ null, // TODO use for documentation?
/* suffix = */ null,
/* key = */ null,
/* complete = */ false // if true adds space when completing
)
}
val comps = completions(line.cursor, line.line, state)
candidates.addAll(comps.asJava)
candidates.addAll(comps.map(_.label).distinct.map(makeCandidate).asJava)
val lineWord = line.word()
comps.filter(c => c.label == lineWord && c.symbols.nonEmpty) match
case Nil =>
case exachMatches =>
val terminal = lineReader.nn.getTerminal
lineReader.callWidget(LineReader.CLEAR)
terminal.writer.println()
exachMatches.foreach: exact =>
exact.symbols.foreach: sym =>
terminal.writer.println(SyntaxHighlighting.highlight(sym.showUser))
lineReader.callWidget(LineReader.REDRAW_LINE)
lineReader.callWidget(LineReader.REDISPLAY)
terminal.flush()
}
given Context = state.context

try {
val line = terminal.readLine(completer)
ParseResult(line)
Expand Down Expand Up @@ -230,23 +256,10 @@ class ReplDriver(settings: Array[String],
label

/** Extract possible completions at the index of `cursor` in `expr` */
protected final def completions(cursor: Int, expr: String, state0: State): List[Candidate] =
def makeCandidate(label: String) = {

new Candidate(
/* value = */ label,
/* displ = */ stripBackTicks(label), // displayed value
/* group = */ null, // can be used to group completions together
/* descr = */ null, // TODO use for documentation?
/* suffix = */ null,
/* key = */ null,
/* complete = */ false // if true adds space when completing
)
}

protected final def completions(cursor: Int, expr: String, state0: State): List[Completion] =
if expr.startsWith(":") then
ParseResult.commands.collect {
case command if command._1.startsWith(expr) => makeCandidate(command._1)
case command if command._1.startsWith(expr) => Completion(command._1, "", List())
}
else
given state: State = newRun(state0)
Expand All @@ -259,8 +272,7 @@ class ReplDriver(settings: Array[String],
unit.tpdTree = tpdTree
given Context = state.context.fresh.setCompilationUnit(unit)
val srcPos = SourcePosition(file, Span(cursor))
val completions = try Completion.completions(srcPos)._2 catch case NonFatal(_) => Nil
completions.map(_.label).distinct.map(makeCandidate)
try Completion.completions(srcPos)._2 catch case NonFatal(_) => Nil
}
.getOrElse(Nil)
end completions
Expand Down
2 changes: 1 addition & 1 deletion compiler/test/dotty/tools/repl/ReplTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ extends ReplDriver(options, new PrintStream(out, true, StandardCharsets.UTF_8.na

/** Returns the `(<instance completions>, <companion completions>)`*/
def tabComplete(src: String)(implicit state: State): List[String] =
completions(src.length, src, state).map(_.value).sorted
completions(src.length, src, state).map(_.label).sorted.distinct

extension [A](state: State)
infix def andThen(op: State ?=> A): A = op(using state)
Expand Down

0 comments on commit b0ba045

Please sign in to comment.