@@ -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
@@ -148,11 +149,36 @@ class ReplDriver(settings: Array[String],
148149
149150 /** Blockingly read a line, getting back a parse result */
150151 def readLine ()(using state : State ): ParseResult = {
151- val completer : Completer = { (_, line, candidates) =>
152+ given Context = state.context
153+ val completer : Completer = { (lineReader, line, candidates) =>
154+ def makeCandidate (label : String ) = {
155+ new Candidate (
156+ /* value = */ label,
157+ /* displ = */ stripBackTicks(label), // displayed value
158+ /* group = */ null , // can be used to group completions together
159+ /* descr = */ null , // TODO use for documentation?
160+ /* suffix = */ null ,
161+ /* key = */ null ,
162+ /* complete = */ false // if true adds space when completing
163+ )
164+ }
152165 val comps = completions(line.cursor, line.line, state)
153- candidates.addAll(comps.asJava)
166+ candidates.addAll(comps.map(_.label).distinct.map(makeCandidate).asJava)
167+ val lineWord = line.word()
168+ comps.filter(c => c.label == lineWord && c.symbols.nonEmpty) match
169+ case Nil =>
170+ case exachMatches =>
171+ val terminal = lineReader.nn.getTerminal
172+ lineReader.callWidget(LineReader .CLEAR )
173+ terminal.writer.println()
174+ exachMatches.foreach: exact =>
175+ exact.symbols.foreach: sym =>
176+ terminal.writer.println(SyntaxHighlighting .highlight(sym.showUser))
177+ lineReader.callWidget(LineReader .REDRAW_LINE )
178+ lineReader.callWidget(LineReader .REDISPLAY )
179+ terminal.flush()
154180 }
155- given Context = state.context
181+
156182 try {
157183 val line = terminal.readLine(completer)
158184 ParseResult (line)
@@ -229,23 +255,10 @@ class ReplDriver(settings: Array[String],
229255 label
230256
231257 /** Extract possible completions at the index of `cursor` in `expr` */
232- protected final def completions (cursor : Int , expr : String , state0 : State ): List [Candidate ] =
233- def makeCandidate (label : String ) = {
234-
235- new Candidate (
236- /* value = */ label,
237- /* displ = */ stripBackTicks(label), // displayed value
238- /* group = */ null , // can be used to group completions together
239- /* descr = */ null , // TODO use for documentation?
240- /* suffix = */ null ,
241- /* key = */ null ,
242- /* complete = */ false // if true adds space when completing
243- )
244- }
245-
258+ protected final def completions (cursor : Int , expr : String , state0 : State ): List [Completion ] =
246259 if expr.startsWith(" :" ) then
247260 ParseResult .commands.collect {
248- case command if command._1.startsWith(expr) => makeCandidate (command._1)
261+ case command if command._1.startsWith(expr) => Completion (command._1, " " , List () )
249262 }
250263 else
251264 given state : State = newRun(state0)
@@ -258,8 +271,7 @@ class ReplDriver(settings: Array[String],
258271 unit.tpdTree = tpdTree
259272 given Context = state.context.fresh.setCompilationUnit(unit)
260273 val srcPos = SourcePosition (file, Span (cursor))
261- val completions = try Completion .completions(srcPos)._2 catch case NonFatal (_) => Nil
262- completions.map(_.label).distinct.map(makeCandidate)
274+ try Completion .completions(srcPos)._2 catch case NonFatal (_) => Nil
263275 }
264276 .getOrElse(Nil )
265277 end completions
0 commit comments