Skip to content

Commit f4a6e9e

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 1b25f65 commit f4a6e9e

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
@@ -197,7 +197,7 @@ class ReplDriver(settings: Array[String],
197197
}
198198

199199
/** Extract possible completions at the index of `cursor` in `expr` */
200-
protected final def completions(cursor: Int, expr: String, state0: State): List[Candidate] = {
200+
protected final def completions(cursor: Int, expr: String, state0: State): List[Candidate] =
201201
def makeCandidate(label: String) = {
202202
new Candidate(
203203
/* value = */ label,
@@ -209,20 +209,24 @@ class ReplDriver(settings: Array[String],
209209
/* complete = */ false // if true adds space when completing
210210
)
211211
}
212-
implicit val state = newRun(state0)
213-
compiler
214-
.typeCheck(expr, errorsAllowed = true)
215-
.map { tree =>
216-
val file = SourceFile.virtual("<completions>", expr, maybeIncomplete = true)
217-
val unit = CompilationUnit(file)(using state.context)
218-
unit.tpdTree = tree
219-
given Context = state.context.fresh.setCompilationUnit(unit)
220-
val srcPos = SourcePosition(file, Span(cursor))
221-
val (_, completions) = Completion.completions(srcPos)
222-
completions.map(_.label).distinct.map(makeCandidate)
223-
}
224-
.getOrElse(Nil)
225-
}
212+
213+
if expr.startsWith(":") then
214+
ParseResult.commands.map(command => makeCandidate(command._1))
215+
else
216+
given state: State = newRun(state0)
217+
compiler
218+
.typeCheck(expr, errorsAllowed = true)
219+
.map { tree =>
220+
val file = SourceFile.virtual("<completions>", expr, maybeIncomplete = true)
221+
val unit = CompilationUnit(file)(using state.context)
222+
unit.tpdTree = tree
223+
given Context = state.context.fresh.setCompilationUnit(unit)
224+
val srcPos = SourcePosition(file, Span(cursor))
225+
val (_, completions) = Completion.completions(srcPos)
226+
completions.map(_.label).distinct.map(makeCandidate)
227+
}
228+
.getOrElse(Nil)
229+
end completions
226230

227231
private def interpret(res: ParseResult)(implicit state: State): State = {
228232
res match {

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,20 @@ class TabcompleteTests extends ReplTest {
131131
tabComplete("import quoted.* ; def fooImpl(using Quotes): Expr[Int] = { import quotes.reflect.* ; TypeRepr.of[Int].s"))
132132
}
133133

134+
@Test def commands = initially {
135+
assertEquals(
136+
List(
137+
":doc",
138+
":exit",
139+
":help",
140+
":imports",
141+
":load",
142+
":quit",
143+
":reset",
144+
":settings",
145+
":type"
146+
),
147+
tabComplete(":")
148+
)
149+
}
134150
}

0 commit comments

Comments
 (0)