Skip to content

Commit 5e2c869

Browse files
committed
feat(repl): autocomplete repl commands
This adds in completion for the available commands in the repl just like there is for Scala 2. For example you can do `:@@` which will give you back all the commands.
1 parent 6dc591a commit 5e2c869

File tree

3 files changed

+36
-16
lines changed

3 files changed

+36
-16
lines changed

compiler/src/dotty/tools/repl/ParseResult.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ object ParseResult {
127127
stats
128128
}
129129

130-
private val commands: List[(String, String => ParseResult)] = List(
130+
private[repl] val commands: List[(String, String => ParseResult)] = List(
131131
Quit.command -> (_ => Quit),
132132
Quit.alias -> (_ => Quit),
133133
Help.command -> (_ => Help),

compiler/src/dotty/tools/repl/ReplDriver.scala

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ class ReplDriver(settings: Array[String],
205205
label
206206

207207
/** Extract possible completions at the index of `cursor` in `expr` */
208-
protected final def completions(cursor: Int, expr: String, state0: State): List[Candidate] = {
208+
protected final def completions(cursor: Int, expr: String, state0: State): List[Candidate] =
209209
def makeCandidate(label: String) = {
210210

211211
new Candidate(
@@ -218,20 +218,24 @@ class ReplDriver(settings: Array[String],
218218
/* complete = */ false // if true adds space when completing
219219
)
220220
}
221-
implicit val state = newRun(state0)
222-
compiler
223-
.typeCheck(expr, errorsAllowed = true)
224-
.map { tree =>
225-
val file = SourceFile.virtual("<completions>", expr, maybeIncomplete = true)
226-
val unit = CompilationUnit(file)(using state.context)
227-
unit.tpdTree = tree
228-
given Context = state.context.fresh.setCompilationUnit(unit)
229-
val srcPos = SourcePosition(file, Span(cursor))
230-
val (_, completions) = Completion.completions(srcPos)
231-
completions.map(_.label).distinct.map(makeCandidate)
232-
}
233-
.getOrElse(Nil)
234-
}
221+
222+
if expr.startsWith(":") then
223+
ParseResult.commands.map(command => makeCandidate(command._1))
224+
else
225+
given state: State = newRun(state0)
226+
compiler
227+
.typeCheck(expr, errorsAllowed = true)
228+
.map { tree =>
229+
val file = SourceFile.virtual("<completions>", expr, maybeIncomplete = true)
230+
val unit = CompilationUnit(file)(using state.context)
231+
unit.tpdTree = tree
232+
given Context = state.context.fresh.setCompilationUnit(unit)
233+
val srcPos = SourcePosition(file, Span(cursor))
234+
val (_, completions) = Completion.completions(srcPos)
235+
completions.map(_.label).distinct.map(makeCandidate)
236+
}
237+
.getOrElse(Nil)
238+
end completions
235239

236240
private def interpret(res: ParseResult)(implicit state: State): State = {
237241
res match {

compiler/test/dotty/tools/repl/TabcompleteTests.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,4 +191,20 @@ class TabcompleteTests extends ReplTest {
191191
|Foo.`bac"""stripMargin))
192192
}
193193

194+
@Test def commands = initially {
195+
assertEquals(
196+
List(
197+
":doc",
198+
":exit",
199+
":help",
200+
":imports",
201+
":load",
202+
":quit",
203+
":reset",
204+
":settings",
205+
":type"
206+
),
207+
tabComplete(":")
208+
)
209+
}
194210
}

0 commit comments

Comments
 (0)