@@ -31,6 +31,7 @@ import dotty.tools.dotc.util.{SourceFile, SourcePosition}
31
31
import dotty .tools .dotc .{CompilationUnit , Driver }
32
32
import dotty .tools .dotc .config .CompilerCommand
33
33
import dotty .tools .io .*
34
+ import dotty .tools .repl .Rendering .showUser
34
35
import dotty .tools .runner .ScalaClassLoader .*
35
36
import org .jline .reader .*
36
37
@@ -149,11 +150,36 @@ class ReplDriver(settings: Array[String],
149
150
150
151
/** Blockingly read a line, getting back a parse result */
151
152
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
+ }
153
166
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()
155
181
}
156
- given Context = state.context
182
+
157
183
try {
158
184
val line = terminal.readLine(completer)
159
185
ParseResult (line)
@@ -230,23 +256,10 @@ class ReplDriver(settings: Array[String],
230
256
label
231
257
232
258
/** 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 ] =
247
260
if expr.startsWith(" :" ) then
248
261
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 () )
250
263
}
251
264
else
252
265
given state : State = newRun(state0)
@@ -259,8 +272,7 @@ class ReplDriver(settings: Array[String],
259
272
unit.tpdTree = tpdTree
260
273
given Context = state.context.fresh.setCompilationUnit(unit)
261
274
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
264
276
}
265
277
.getOrElse(Nil )
266
278
end completions
0 commit comments