diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 36468a72e9cb..27ceb207e1bc 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -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.* @@ -148,11 +149,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) @@ -229,23 +255,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) @@ -258,8 +271,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