Fix watch with metals sbt bsp implementation

I discovered that the metals bsp implementation worked very badly with
continuous builds. The problem was that metals is able to trigger a bsp
compile slightly before the continuous build would trigger. This would
cause the ui to get in a bad state. The worst case was that it would
actually cause sbt (or the thin client) to exit. A less catastrophic
issue was that it was possible for the wrong count to be printed by the
continuous message.

This commit fixes the issue by more carefully managing the prompt state
and only resetting the ui when the prompt is not in the Prompt.Watch
state.
This commit is contained in:
Ethan Atkins 2020-11-19 18:19:24 -08:00
parent 68933a628d
commit 600628e8e9
3 changed files with 16 additions and 8 deletions

View File

@ -990,12 +990,19 @@ object BuiltinCommands {
val exchange = StandardMain.exchange
exchange.channelForName(channel) match {
case Some(c) if ContinuousCommands.isInWatch(s0, c) =>
c.prompt(ConsolePromptEvent(s0))
if (c.terminal.prompt != Prompt.Watch) {
c.terminal.setPrompt(Prompt.Watch)
c.prompt(ConsolePromptEvent(s0))
} else if (c.terminal.isSupershellEnabled) {
c.terminal.printStream.print(ConsoleAppender.ClearScreenAfterCursor)
c.terminal.printStream.flush()
}
val s1 = exchange.run(s0)
val exec: Exec = getExec(s1, Duration.Inf)
val remaining: List[Exec] =
Exec(s"${ContinuousCommands.waitWatch} $channel", None) ::
Exec(FailureWall, None) :: s1.remainingCommands
Exec(FailureWall, None) :: Exec(s"${ContinuousCommands.waitWatch} $channel", None) ::
s1.remainingCommands
val newState = s1.copy(remainingCommands = exec +: remaining)
if (exec.commandLine.trim.isEmpty) newState
else newState.clearGlobalLog

View File

@ -226,9 +226,8 @@ object MainLoop {
// temporarily set the prompt to running during task evaluation
c.terminal.setPrompt(Prompt.Running)
(() => {
c.terminal.setPrompt(prevPrompt)
if (c.terminal.prompt != Prompt.Watch) c.terminal.setPrompt(prevPrompt)
ITerminal.set(prevTerminal)
c.terminal.setPrompt(prevPrompt)
c.terminal.flush()
}) -> progressState.put(Keys.terminalKey, Terminal(c.terminal))
case _ => (() => ()) -> progressState.put(Keys.terminalKey, Terminal(ITerminal.get))

View File

@ -1344,8 +1344,7 @@ private[sbt] object ContinuousCommands {
private[sbt] val postWatchCommand = watchCommand(postWatch) { (channel, state) =>
val cs = watchState(state, channel)
StandardMain.exchange.channelForName(channel).foreach { c =>
c.terminal.setPrompt(Prompt.Watch)
c.unprompt(ConsoleUnpromptEvent(Some(CommandSource(channel))))
c.terminal.setPrompt(Prompt.Pending)
}
val postState = state.get(watchStates) match {
case None => state
@ -1360,7 +1359,10 @@ private[sbt] object ContinuousCommands {
cs.callbacks.onExit()
StandardMain.exchange
.channelForName(channel)
.foreach(_.unprompt(ConsoleUnpromptEvent(Some(CommandSource(channel)))))
.foreach { c =>
c.terminal.setPrompt(Prompt.Pending)
c.unprompt(ConsoleUnpromptEvent(Some(CommandSource(channel))))
}
afterWatchState.get(watchStates) match {
case None => afterWatchState
case Some(w) => afterWatchState.put(watchStates, w - channel)