@@ -31,6 +31,7 @@ import dotty.tools.dotc.util.{SourceFile, SourcePosition}
3131import dotty .tools .dotc .{CompilationUnit , Driver }
3232import dotty .tools .dotc .config .CompilerCommand
3333import dotty .tools .io .*
34+ import dotty .tools .repl .Rendering .showUser
3435import dotty .tools .runner .ScalaClassLoader .*
3536import org .jline .reader .*
3637
@@ -149,11 +150,36 @@ class ReplDriver(settings: Array[String],
149150
150151 /** Blockingly read a line, getting back a parse result */
151152 def readLine ()(using state : State ): ParseResult = {
152- val completer : Completer = { (_, line, candidates) =>
153+ given Context = state.context
154+ val completer : Completer = { (lineReader, line, candidates) =>
155+ def makeCandidate (label : String ) = {
156+ new Candidate (
157+ /* value = */ label,
158+ /* displ = */ stripBackTicks(label), // displayed value
159+ /* group = */ null , // can be used to group completions together
160+ /* descr = */ null , // TODO use for documentation?
161+ /* suffix = */ null ,
162+ /* key = */ null ,
163+ /* complete = */ false // if true adds space when completing
164+ )
165+ }
153166 val comps = completions(line.cursor, line.line, state)
154- candidates.addAll(comps.asJava)
167+ candidates.addAll(comps.map(_.label).distinct.map(makeCandidate).asJava)
168+ val lineWord = line.word()
169+ comps.filter(c => c.label == lineWord && c.symbols.nonEmpty) match
170+ case Nil =>
171+ case exachMatches =>
172+ val terminal = lineReader.nn.getTerminal
173+ lineReader.callWidget(LineReader .CLEAR )
174+ terminal.writer.println()
175+ exachMatches.foreach: exact =>
176+ exact.symbols.foreach: sym =>
177+ terminal.writer.println(SyntaxHighlighting .highlight(sym.showUser))
178+ lineReader.callWidget(LineReader .REDRAW_LINE )
179+ lineReader.callWidget(LineReader .REDISPLAY )
180+ terminal.flush()
155181 }
156- given Context = state.context
182+
157183 try {
158184 val line = terminal.readLine(completer)
159185 ParseResult (line)
@@ -230,23 +256,10 @@ class ReplDriver(settings: Array[String],
230256 label
231257
232258 /** Extract possible completions at the index of `cursor` in `expr` */
233- protected final def completions (cursor : Int , expr : String , state0 : State ): List [Candidate ] =
234- def makeCandidate (label : String ) = {
235-
236- new Candidate (
237- /* value = */ label,
238- /* displ = */ stripBackTicks(label), // displayed value
239- /* group = */ null , // can be used to group completions together
240- /* descr = */ null , // TODO use for documentation?
241- /* suffix = */ null ,
242- /* key = */ null ,
243- /* complete = */ false // if true adds space when completing
244- )
245- }
246-
259+ protected final def completions (cursor : Int , expr : String , state0 : State ): List [Completion ] =
247260 if expr.startsWith(" :" ) then
248261 ParseResult .commands.collect {
249- case command if command._1.startsWith(expr) => makeCandidate (command._1)
262+ case command if command._1.startsWith(expr) => Completion (command._1, " " , List () )
250263 }
251264 else
252265 given state : State = newRun(state0)
@@ -259,8 +272,7 @@ class ReplDriver(settings: Array[String],
259272 unit.tpdTree = tpdTree
260273 given Context = state.context.fresh.setCompilationUnit(unit)
261274 val srcPos = SourcePosition (file, Span (cursor))
262- val completions = try Completion .completions(srcPos)._2 catch case NonFatal (_) => Nil
263- completions.map(_.label).distinct.map(makeCandidate)
275+ try Completion .completions(srcPos)._2 catch case NonFatal (_) => Nil
264276 }
265277 .getOrElse(Nil )
266278 end completions
0 commit comments