diff --git a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala index 4b0235572..a963582f4 100644 --- a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala +++ b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala @@ -74,13 +74,13 @@ object LineReader { parser: Parser[_], terminal: Terminal, ): LineReader = { - val term = JLine3(terminal) // We may want to consider insourcing LineReader.java from jline. We don't otherwise // 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 { 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 { Option(mask.map(reader.readLine(prompt, _)).getOrElse(reader.readLine(prompt))) } catch { diff --git a/main-command/src/main/scala/sbt/internal/ui/UITask.scala b/main-command/src/main/scala/sbt/internal/ui/UITask.scala index 8fd4d4177..f47def3a6 100644 --- a/main-command/src/main/scala/sbt/internal/ui/UITask.scala +++ b/main-command/src/main/scala/sbt/internal/ui/UITask.scala @@ -59,7 +59,7 @@ private[sbt] object UITask { def readLine(): Either[String, String] = try { val clear = terminal.ansi(ClearPromptLine, "") - @tailrec def impl(): Either[String, String] = { + val res = { val thread = Thread.currentThread if (thread.isInterrupted || closed.get) throw interrupted val reader = LineReader.createReader(history(state), parser, terminal) @@ -76,16 +76,17 @@ private[sbt] object UITask { case None => Left(TerminateAction) case Some(s: String) => 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 => Right(cmd) } } } - val res = impl() terminal.setPrompt(Prompt.Pending) res - } catch { case e: InterruptedException => Right("") } + } catch { case e: InterruptedException => Left("") } override def close(): Unit = closed.set(true) } } diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index 505c913c2..b2d077a4c 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -446,7 +446,7 @@ private[sbt] final class CommandExchange { case null => case mt: FastTrackTask => mt.task match { - case `attach` => mt.channel.prompt(ConsolePromptEvent(lastState.get)) + case `attach` | "" => mt.channel.prompt(ConsolePromptEvent(lastState.get)) case `Cancel` => Option(currentExecRef.get).foreach(cancel) mt.channel.prompt(ConsolePromptEvent(lastState.get))