From b1dcf031a585d8f6ba8cc86f3e215c9673f9bd18 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Thu, 9 Jul 2020 08:52:24 -0700 Subject: [PATCH] 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. --- .../src/main/scala/sbt/internal/util/Prompt.scala | 1 + .../src/main/scala/sbt/internal/util/Terminal.scala | 2 +- .../src/main/scala/sbt/internal/ui/UserThread.scala | 7 ++++--- main/src/main/scala/sbt/Main.scala | 12 +++++++++--- main/src/main/scala/sbt/MainLoop.scala | 2 +- .../main/scala/sbt/internal/CommandExchange.scala | 6 +++++- 6 files changed, 21 insertions(+), 9 deletions(-) diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/Prompt.scala b/internal/util-logging/src/main/scala/sbt/internal/util/Prompt.scala index c87f4dca4..53c4f3849 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/Prompt.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/Prompt.scala @@ -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 } diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala b/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala index 76bb7ec39..0c2d50414 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala @@ -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 } diff --git a/main-command/src/main/scala/sbt/internal/ui/UserThread.scala b/main-command/src/main/scala/sbt/internal/ui/UserThread.scala index e868c3682..97accf35b 100644 --- a/main-command/src/main/scala/sbt/internal/ui/UserThread.scala +++ b/main-command/src/main/scala/sbt/internal/ui/UserThread.scala @@ -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) diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 3d886a3ca..ea02165d1 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -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] = diff --git a/main/src/main/scala/sbt/MainLoop.scala b/main/src/main/scala/sbt/MainLoop.scala index 8b144f4d5..0ba3099cc 100644 --- a/main/src/main/scala/sbt/MainLoop.scala +++ b/main/src/main/scala/sbt/MainLoop.scala @@ -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)) { diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index 29091ce96..6347c3f5d 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -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 {