diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/ProgressState.scala b/internal/util-logging/src/main/scala/sbt/internal/util/ProgressState.scala index ca2c3a99f..d27fe9dcd 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/ProgressState.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/ProgressState.scala @@ -80,8 +80,8 @@ private[sbt] final class ProgressState( private[util] def printPrompt(terminal: Terminal, printStream: PrintStream): Unit = if (terminal.prompt != Prompt.Running && terminal.prompt != Prompt.Batch) { val prefix = if (terminal.isAnsiSupported) s"$DeleteLine$CursorLeft1000" else "" - val pmpt = prefix.getBytes ++ terminal.prompt.render().getBytes - pmpt.foreach(b => printStream.write(b & 0xFF)) + printStream.write(prefix.getBytes ++ terminal.prompt.render().getBytes) + printStream.flush() } private[util] def write( terminal: Terminal, @@ -90,10 +90,10 @@ private[sbt] final class ProgressState( hasProgress: Boolean ): Unit = { addBytes(terminal, bytes) - if (hasProgress && terminal.prompt != Prompt.Loading) { + if (hasProgress) { terminal.prompt match { case a: Prompt.AskUser if a.render.nonEmpty => - printStream.print(System.lineSeparator + ClearScreenAfterCursor + CursorLeft1000) + printStream.print(DeleteLine + ClearScreenAfterCursor + CursorLeft1000) printStream.flush() case _ => } 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 eb5e4a660..90f02f66c 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 @@ -34,6 +34,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 private[sbt] case object NoPrompt extends NoPrompt } 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 97accf35b..e868c3682 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, Loading, Running } +import sbt.internal.util.Prompt.{ AskUser, Running } private[sbt] class UserThread(val channel: CommandChannel) extends AutoCloseable { private[this] val uiThread = new AtomicReference[(UITask, Thread)] @@ -70,9 +70,8 @@ private[sbt] class UserThread(val channel: CommandChannel) extends AutoCloseable } val state = consolePromptEvent.state terminal.prompt match { - case Loading | Running => - terminal.setPrompt(AskUser(() => UITask.shellPrompt(terminal, state))) - case _ => + case 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/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index f783d2d3a..6a5cdd6fb 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -454,7 +454,12 @@ object Defaults extends BuildCommon { def paths: Seq[Setting[_]] = Seq( baseDirectory := thisProject.value.base, target := baseDirectory.value / "target", - historyPath := (historyPath or target(t => Option(t / ".history"))).value, + // Use a different history path for jline3 because the jline2 format is + // incompatible. By sbt 1.4.0, we should consider revering this to t / ".history" + // and possibly rewriting the jline2 history in a jline3 compatible format if the + // history file is incompatible. For now, just use a different file to facilitate + // going back and forth between 1.3.x and 1.4.x. + historyPath := (historyPath or target(t => Option(t / ".history3"))).value, sourceDirectory := baseDirectory.value / "src", sourceManaged := crossTarget.value / "src_managed", resourceManaged := crossTarget.value / "resource_managed", diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index c9862bedc..9b3b71e35 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -102,7 +102,10 @@ private[sbt] object xMain { } } } finally { + // Clear any stray progress lines ShutdownHooks.close() + System.out.print(ConsoleAppender.ClearScreenAfterCursor) + System.out.flush() } } @@ -913,8 +916,6 @@ 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) @@ -935,9 +936,7 @@ object BuiltinCommands { SessionSettings.checkSession(session, s2) val s3 = addCacheStoreFactoryFactory(Project.setProject(session, structure, s2)) val s4 = setupGlobalFileTreeRepository(s3) - val s5 = CheckBuildSources.init(LintUnused.lintUnusedFunc(s4)) - StandardMain.exchange.prompt(ConsolePromptEvent(s5)) - s5 + CheckBuildSources.init(LintUnused.lintUnusedFunc(s4)) } private val setupGlobalFileTreeRepository: State => State = { state => @@ -981,11 +980,9 @@ 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 needPrompt(c) => c.prompt(ConsolePromptEvent(s1)) - case _ => + case c if ContinuousCommands.isPending(c) => + case c => c.prompt(ConsolePromptEvent(s1)) } 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 53a662371..09f26e96e 100644 --- a/main/src/main/scala/sbt/MainLoop.scala +++ b/main/src/main/scala/sbt/MainLoop.scala @@ -198,9 +198,9 @@ object MainLoop { state.put(sbt.Keys.currentTaskProgress, new Keys.TaskProgress(progress)) } else state } - exchange.setState(progressState) - exchange.setExec(Some(exec)) - exchange.unprompt(ConsoleUnpromptEvent(exec.source), force = false) + StandardMain.exchange.setState(progressState) + StandardMain.exchange.setExec(Some(exec)) + StandardMain.exchange.unprompt(ConsoleUnpromptEvent(exec.source)) 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 ab169877d..d4c6bbf27 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -357,11 +357,7 @@ private[sbt] final class CommandExchange { case c => c.prompt(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 unprompt(event: ConsoleUnpromptEvent): Unit = channels.foreach(_.unprompt(event)) def logMessage(event: LogEvent): Unit = { channels.foreach { diff --git a/main/src/main/scala/sbt/internal/Continuous.scala b/main/src/main/scala/sbt/internal/Continuous.scala index 0ea51c4a2..86618ceb2 100644 --- a/main/src/main/scala/sbt/internal/Continuous.scala +++ b/main/src/main/scala/sbt/internal/Continuous.scala @@ -1254,11 +1254,11 @@ private[sbt] object ContinuousCommands { } private[this] val preWatchCommand = watchCommand(preWatch) { (channel, state) => - StandardMain.exchange.channelForName(channel).foreach(_.terminal.setPrompt(Prompt.Running)) + StandardMain.exchange.channelForName(channel).foreach(_.terminal.setPrompt(Prompt.Watch)) watchState(channel).beforeCommand(state) } private[this] val postWatchCommand = watchCommand(postWatch) { (channel, state) => - StandardMain.exchange.unprompt(ConsoleUnpromptEvent(Some(CommandSource(channel))), false) + StandardMain.exchange.unprompt(ConsoleUnpromptEvent(Some(CommandSource(channel)))) val ws = watchState(channel) watchStates.put(channel, ws.withPending(false)) ws.afterCommand(state) @@ -1268,7 +1268,7 @@ private[sbt] object ContinuousCommands { state } private[sbt] def stopWatchImpl(channelName: String): Unit = { - StandardMain.exchange.unprompt(ConsoleUnpromptEvent(Some(CommandSource(channelName))), false) + StandardMain.exchange.unprompt(ConsoleUnpromptEvent(Some(CommandSource(channelName)))) Option(watchStates.get(channelName)).foreach { ws => ws.afterWatch() ws.callbacks.onExit() diff --git a/main/src/main/scala/sbt/internal/TaskTraceEvent.scala b/main/src/main/scala/sbt/internal/TaskTraceEvent.scala index de8b4eede..b623c70cc 100644 --- a/main/src/main/scala/sbt/internal/TaskTraceEvent.scala +++ b/main/src/main/scala/sbt/internal/TaskTraceEvent.scala @@ -73,7 +73,8 @@ private[sbt] final class TaskTraceEvent () } finally { trace.close() - console.println(s"wrote $outFile") + try console.println(s"wrote $outFile") + catch { case _: java.nio.channels.ClosedChannelException => } } } }