@@ -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,38 @@ 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
- val comps = completions(line.cursor, line.line, state)
154
- candidates.addAll(comps.asJava)
155
- }
156
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
+ }
166
+ completions(line.cursor, line.line, state) match
167
+ case Left (cmds) => candidates.addAll(cmds.map(makeCandidate).asJava)
168
+ case Right (comps) =>
169
+ val lineWord = line.word()
170
+ candidates.addAll(comps.map(c => makeCandidate(c.label)).asJava)
171
+ comps.filter(_.label == lineWord) match
172
+ case Nil =>
173
+ case exachMatches =>
174
+ val terminal = lineReader.getTerminal
175
+ lineReader.callWidget(LineReader .CLEAR )
176
+ terminal.writer.println()
177
+ exachMatches.foreach: exact =>
178
+ exact.symbols.foreach: sym =>
179
+ terminal.writer.println(SyntaxHighlighting .highlight(sym.showUser))
180
+ lineReader.callWidget(LineReader .REDRAW_LINE )
181
+ lineReader.callWidget(LineReader .REDISPLAY )
182
+ terminal.flush()
183
+ }
184
+
157
185
try {
158
186
val line = terminal.readLine(completer)
159
187
ParseResult (line)
@@ -230,39 +258,26 @@ class ReplDriver(settings: Array[String],
230
258
label
231
259
232
260
/** 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
-
261
+ protected final def completions (cursor : Int , expr : String , state0 : State ): Either [List [String ], List [Completion ]] =
247
262
if expr.startsWith(" :" ) then
248
- ParseResult .commands.collect {
249
- case command if command._1.startsWith(expr) => makeCandidate( command._1)
250
- }
263
+ Left ( ParseResult .commands.collect {
264
+ case command if command._1.startsWith(expr) => command._1
265
+ })
251
266
else
252
267
given state : State = newRun(state0)
253
- compiler
254
- .typeCheck(expr, errorsAllowed = true )
255
- .map { (untpdTree, tpdTree) =>
256
- val file = SourceFile .virtual( " <completions> " , expr, maybeIncomplete = true )
257
- val unit = CompilationUnit (file)( using state.context )
258
- unit.untpdTree = untpdTree
259
- unit.tpdTree = tpdTree
260
- given Context = state.context.fresh.setCompilationUnit(unit)
261
- 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)
264
- }
265
- .getOrElse(Nil )
268
+ Right :
269
+ compiler
270
+ .typeCheck(expr, errorsAllowed = true )
271
+ .map { (untpdTree, tpdTree) =>
272
+ val file = SourceFile .virtual( " <completions> " , expr, maybeIncomplete = true )
273
+ val unit = CompilationUnit (file)( using state.context)
274
+ unit.untpdTree = untpdTree
275
+ unit.tpdTree = tpdTree
276
+ given Context = state.context.fresh.setCompilationUnit(unit )
277
+ val srcPos = SourcePosition (file, Span (cursor))
278
+ try Completion .completions(srcPos)._2 catch case NonFatal (_) => Nil
279
+ }
280
+ .getOrElse(Nil )
266
281
end completions
267
282
268
283
protected def interpret (res : ParseResult , quiet : Boolean = false )(using state : State ): State = {
0 commit comments