Add reprompt fast track command

With the latest sbt snapshot, the ui would get stuck if the user entered
an empty command. They would be presented with an empty prompt and could
not input any commands. This was caused by the change in
d569abe70a that reset the prompt after a
line was read. I had tried to optimize line reading by ignoring empty
commands in UITask.readline so we wouldn't have to make a new thread.
This optimization wasn't really buying much since it only affects how
quickly the user is reprompted after entering an empty command. Unless a
user is spamming the <enter> key, they shouldn't notice a difference.
This commit is contained in:
Ethan Atkins 2020-08-10 11:02:02 -07:00
parent 31bea086aa
commit adc8d5ee6e
3 changed files with 9 additions and 8 deletions

View File

@ -74,13 +74,13 @@ object LineReader {
parser: Parser[_], parser: Parser[_],
terminal: Terminal, terminal: Terminal,
): LineReader = { ): LineReader = {
val term = JLine3(terminal)
// We may want to consider insourcing LineReader.java from jline. We don't otherwise // We may want to consider insourcing LineReader.java from jline. We don't otherwise
// directly need jline3 for sbt. // directly need jline3 for sbt.
val reader = LineReaderBuilder.builder().terminal(term).completer(completer(parser)).build()
historyPath.foreach(f => reader.setVariable(JLineReader.HISTORY_FILE, f))
new LineReader { new LineReader {
override def readLine(prompt: String, mask: Option[Char]): Option[String] = { override def readLine(prompt: String, mask: Option[Char]): Option[String] = {
val term = JLine3(terminal)
val reader = LineReaderBuilder.builder().terminal(term).completer(completer(parser)).build()
historyPath.foreach(f => reader.setVariable(JLineReader.HISTORY_FILE, f))
try terminal.withRawInput { try terminal.withRawInput {
Option(mask.map(reader.readLine(prompt, _)).getOrElse(reader.readLine(prompt))) Option(mask.map(reader.readLine(prompt, _)).getOrElse(reader.readLine(prompt)))
} catch { } catch {

View File

@ -59,7 +59,7 @@ private[sbt] object UITask {
def readLine(): Either[String, String] = def readLine(): Either[String, String] =
try { try {
val clear = terminal.ansi(ClearPromptLine, "") val clear = terminal.ansi(ClearPromptLine, "")
@tailrec def impl(): Either[String, String] = { val res = {
val thread = Thread.currentThread val thread = Thread.currentThread
if (thread.isInterrupted || closed.get) throw interrupted if (thread.isInterrupted || closed.get) throw interrupted
val reader = LineReader.createReader(history(state), parser, terminal) val reader = LineReader.createReader(history(state), parser, terminal)
@ -76,16 +76,17 @@ private[sbt] object UITask {
case None => Left(TerminateAction) case None => Left(TerminateAction)
case Some(s: String) => case Some(s: String) =>
s.trim() match { s.trim() match {
case "" => impl() // We need to put the empty string on the fast track queue so that we can
// reprompt the user if another command is running on the server.
case "" => Left("")
case cmd @ (`Shutdown` | `TerminateAction` | `Cancel`) => Left(cmd) case cmd @ (`Shutdown` | `TerminateAction` | `Cancel`) => Left(cmd)
case cmd => Right(cmd) case cmd => Right(cmd)
} }
} }
} }
val res = impl()
terminal.setPrompt(Prompt.Pending) terminal.setPrompt(Prompt.Pending)
res res
} catch { case e: InterruptedException => Right("") } } catch { case e: InterruptedException => Left("") }
override def close(): Unit = closed.set(true) override def close(): Unit = closed.set(true)
} }
} }

View File

@ -446,7 +446,7 @@ private[sbt] final class CommandExchange {
case null => case null =>
case mt: FastTrackTask => case mt: FastTrackTask =>
mt.task match { mt.task match {
case `attach` => mt.channel.prompt(ConsolePromptEvent(lastState.get)) case `attach` | "" => mt.channel.prompt(ConsolePromptEvent(lastState.get))
case `Cancel` => case `Cancel` =>
Option(currentExecRef.get).foreach(cancel) Option(currentExecRef.get).foreach(cancel)
mt.channel.prompt(ConsolePromptEvent(lastState.get)) mt.channel.prompt(ConsolePromptEvent(lastState.get))