@@ -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
@@ -148,11 +149,36 @@ class ReplDriver(settings: Array[String],
148
149
149
150
/** Blockingly read a line, getting back a parse result */
150
151
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
+ }
152
165
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()
154
180
}
155
- given Context = state.context
181
+
156
182
try {
157
183
val line = terminal.readLine(completer)
158
184
ParseResult (line)
@@ -229,23 +255,10 @@ class ReplDriver(settings: Array[String],
229
255
label
230
256
231
257
/** 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 ] =
246
259
if expr.startsWith(" :" ) then
247
260
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 () )
249
262
}
250
263
else
251
264
given state : State = newRun(state0)
@@ -258,8 +271,7 @@ class ReplDriver(settings: Array[String],
258
271
unit.tpdTree = tpdTree
259
272
given Context = state.context.fresh.setCompilationUnit(unit)
260
273
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
263
275
}
264
276
.getOrElse(Nil )
265
277
end completions
0 commit comments