Unprompt channels during project load

In the situation where sbt was started in server mode and a client is
running a `~` command and a project reload is triggered by a change to
a build source, the console terminal looks like

sbt:foo>
[info] received remote command: ~compile
sbt:foo>
[info] welcome to sbt 1.4.0-SNAPSHOT (Azul Systems, Inc. Java 1.8.0_252)
sbt:foo>
[info] loading global plugins from ~/.sbt/1.0/plugins
sbt:foo>
[info] loading settings for project foo-build from metals.sbt ...
sbt:foo>
[info] loading project definition from
~/foo/project
sbt:foo>
[info] loading settings for project root from build.sbt ...
sbt:foo>
[info] loading settings for project macros from build.sbt ...
sbt:foo>
[info] loading settings for project main from build.sbt ...
sbt:foo>
[info] set current project to foo (in build file:~/foo)
sbt:foo>

This change fixes that by unprompting all channels during project
loading and reprompting them when it completes.
This commit is contained in:
Ethan Atkins 2020-07-09 08:52:24 -07:00
parent 30e4c02c9c
commit b1dcf031a5
6 changed files with 21 additions and 9 deletions

View File

@ -44,4 +44,5 @@ private[sbt] object Prompt {
private[sbt] case object Running extends NoPrompt
private[sbt] case object Batch extends NoPrompt
private[sbt] case object Watch extends NoPrompt
private[sbt] case object Loading extends NoPrompt
}

View File

@ -772,7 +772,7 @@ object Terminal {
case s if s.nonEmpty => currentLine.set(new ArrayBuffer[Byte])
case _ =>
}
progressState.reprint(TerminalImpl.this, rawPrintStream)
if (prompt != Prompt.Loading) progressState.reprint(TerminalImpl.this, rawPrintStream)
new ArrayBuffer[Byte]
} else buf += i
}

View File

@ -14,7 +14,7 @@ import java.util.concurrent.Executors
import sbt.State
import sbt.internal.util.{ ConsoleAppender, ProgressEvent, ProgressState, Util }
import sbt.internal.util.Prompt.{ AskUser, Running }
import sbt.internal.util.Prompt.{ AskUser, Loading, Running }
private[sbt] class UserThread(val channel: CommandChannel) extends AutoCloseable {
private[this] val uiThread = new AtomicReference[(UITask, Thread)]
@ -70,8 +70,9 @@ private[sbt] class UserThread(val channel: CommandChannel) extends AutoCloseable
}
val state = consolePromptEvent.state
terminal.prompt match {
case Running => terminal.setPrompt(AskUser(() => UITask.shellPrompt(terminal, state)))
case _ =>
case Loading | Running =>
terminal.setPrompt(AskUser(() => UITask.shellPrompt(terminal, state)))
case _ =>
}
onProgressEvent(ProgressEvent("Info", Vector(), None, None, None))
reset(state)

View File

@ -913,6 +913,8 @@ object BuiltinCommands {
}
def doLoadProject(s0: State, action: LoadAction.Value): State = {
StandardMain.exchange.unprompt(ConsoleUnpromptEvent(None), force = true)
StandardMain.exchange.channels.foreach(_.terminal.setPrompt(Prompt.Loading))
welcomeBanner(s0)
checkSBTVersionChanged(s0)
val (s1, base) = Project.loadAction(SessionVar.clear(s0), action)
@ -933,7 +935,9 @@ object BuiltinCommands {
SessionSettings.checkSession(session, s2)
val s3 = addCacheStoreFactoryFactory(Project.setProject(session, structure, s2))
val s4 = setupGlobalFileTreeRepository(s3)
CheckBuildSources.init(LintUnused.lintUnusedFunc(s4))
val s5 = CheckBuildSources.init(LintUnused.lintUnusedFunc(s4))
StandardMain.exchange.prompt(ConsolePromptEvent(s5))
s5
}
private val setupGlobalFileTreeRepository: State => State = { state =>
@ -977,9 +981,11 @@ object BuiltinCommands {
val exchange = StandardMain.exchange
if (exchange.channels.exists(ContinuousCommands.isInWatch)) {
val s1 = exchange.run(s0)
def needPrompt(c: CommandChannel) =
ContinuousCommands.isInWatch(c) && !ContinuousCommands.isPending(c)
exchange.channels.foreach {
case c if ContinuousCommands.isPending(c) =>
case c => c.prompt(ConsolePromptEvent(s1))
case c if needPrompt(c) => c.prompt(ConsolePromptEvent(s1))
case _ =>
}
val exec: Exec = getExec(s1, Duration.Inf)
val remaining: List[Exec] =

View File

@ -199,7 +199,7 @@ object MainLoop {
}
StandardMain.exchange.setState(progressState)
StandardMain.exchange.setExec(Some(exec))
StandardMain.exchange.unprompt(ConsoleUnpromptEvent(exec.source))
StandardMain.exchange.unprompt(ConsoleUnpromptEvent(exec.source), force = false)
val newState = Command.process(exec.commandLine, progressState)
if (exec.execId.fold(true)(!_.startsWith(networkExecPrefix)) &&
!exec.commandLine.startsWith(networkExecPrefix)) {

View File

@ -350,7 +350,11 @@ private[sbt] final class CommandExchange {
case c => c.prompt(event)
}
}
def unprompt(event: ConsoleUnpromptEvent): Unit = channels.foreach(_.unprompt(event))
def unprompt(event: ConsoleUnpromptEvent, force: Boolean): Unit = {
if (force)
channels.foreach(c => c.unprompt(event.copy(lastSource = Some(CommandSource(c.name)))))
else channels.foreach(_.unprompt(event))
}
def logMessage(event: LogEvent): Unit = {
channels.foreach {