Merge pull request #5688 from eatkins/client-jline-ui-fixes

Miscellaneous ui/jline fixes
This commit is contained in:
eugene yokota 2020-07-21 23:06:44 -04:00 committed by GitHub
commit 3908949d73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 28 additions and 31 deletions

View File

@ -80,8 +80,8 @@ private[sbt] final class ProgressState(
private[util] def printPrompt(terminal: Terminal, printStream: PrintStream): Unit = private[util] def printPrompt(terminal: Terminal, printStream: PrintStream): Unit =
if (terminal.prompt != Prompt.Running && terminal.prompt != Prompt.Batch) { if (terminal.prompt != Prompt.Running && terminal.prompt != Prompt.Batch) {
val prefix = if (terminal.isAnsiSupported) s"$DeleteLine$CursorLeft1000" else "" val prefix = if (terminal.isAnsiSupported) s"$DeleteLine$CursorLeft1000" else ""
val pmpt = prefix.getBytes ++ terminal.prompt.render().getBytes printStream.write(prefix.getBytes ++ terminal.prompt.render().getBytes)
pmpt.foreach(b => printStream.write(b & 0xFF)) printStream.flush()
} }
private[util] def write( private[util] def write(
terminal: Terminal, terminal: Terminal,
@ -90,10 +90,10 @@ private[sbt] final class ProgressState(
hasProgress: Boolean hasProgress: Boolean
): Unit = { ): Unit = {
addBytes(terminal, bytes) addBytes(terminal, bytes)
if (hasProgress && terminal.prompt != Prompt.Loading) { if (hasProgress) {
terminal.prompt match { terminal.prompt match {
case a: Prompt.AskUser if a.render.nonEmpty => case a: Prompt.AskUser if a.render.nonEmpty =>
printStream.print(System.lineSeparator + ClearScreenAfterCursor + CursorLeft1000) printStream.print(DeleteLine + ClearScreenAfterCursor + CursorLeft1000)
printStream.flush() printStream.flush()
case _ => case _ =>
} }

View File

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

View File

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

View File

@ -454,7 +454,12 @@ object Defaults extends BuildCommon {
def paths: Seq[Setting[_]] = Seq( def paths: Seq[Setting[_]] = Seq(
baseDirectory := thisProject.value.base, baseDirectory := thisProject.value.base,
target := baseDirectory.value / "target", 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", sourceDirectory := baseDirectory.value / "src",
sourceManaged := crossTarget.value / "src_managed", sourceManaged := crossTarget.value / "src_managed",
resourceManaged := crossTarget.value / "resource_managed", resourceManaged := crossTarget.value / "resource_managed",

View File

@ -102,7 +102,10 @@ private[sbt] object xMain {
} }
} }
} finally { } finally {
// Clear any stray progress lines
ShutdownHooks.close() ShutdownHooks.close()
System.out.print(ConsoleAppender.ClearScreenAfterCursor)
System.out.flush()
} }
} }
@ -913,8 +916,6 @@ object BuiltinCommands {
} }
def doLoadProject(s0: State, action: LoadAction.Value): State = { 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) welcomeBanner(s0)
checkSBTVersionChanged(s0) checkSBTVersionChanged(s0)
val (s1, base) = Project.loadAction(SessionVar.clear(s0), action) val (s1, base) = Project.loadAction(SessionVar.clear(s0), action)
@ -935,9 +936,7 @@ object BuiltinCommands {
SessionSettings.checkSession(session, s2) SessionSettings.checkSession(session, s2)
val s3 = addCacheStoreFactoryFactory(Project.setProject(session, structure, s2)) val s3 = addCacheStoreFactoryFactory(Project.setProject(session, structure, s2))
val s4 = setupGlobalFileTreeRepository(s3) val s4 = setupGlobalFileTreeRepository(s3)
val s5 = CheckBuildSources.init(LintUnused.lintUnusedFunc(s4)) CheckBuildSources.init(LintUnused.lintUnusedFunc(s4))
StandardMain.exchange.prompt(ConsolePromptEvent(s5))
s5
} }
private val setupGlobalFileTreeRepository: State => State = { state => private val setupGlobalFileTreeRepository: State => State = { state =>
@ -981,11 +980,9 @@ object BuiltinCommands {
val exchange = StandardMain.exchange val exchange = StandardMain.exchange
if (exchange.channels.exists(ContinuousCommands.isInWatch)) { if (exchange.channels.exists(ContinuousCommands.isInWatch)) {
val s1 = exchange.run(s0) val s1 = exchange.run(s0)
def needPrompt(c: CommandChannel) =
ContinuousCommands.isInWatch(c) && !ContinuousCommands.isPending(c)
exchange.channels.foreach { exchange.channels.foreach {
case c if needPrompt(c) => c.prompt(ConsolePromptEvent(s1)) case c if ContinuousCommands.isPending(c) =>
case _ => case c => c.prompt(ConsolePromptEvent(s1))
} }
val exec: Exec = getExec(s1, Duration.Inf) val exec: Exec = getExec(s1, Duration.Inf)
val remaining: List[Exec] = val remaining: List[Exec] =

View File

@ -198,9 +198,9 @@ object MainLoop {
state.put(sbt.Keys.currentTaskProgress, new Keys.TaskProgress(progress)) state.put(sbt.Keys.currentTaskProgress, new Keys.TaskProgress(progress))
} else state } else state
} }
exchange.setState(progressState) StandardMain.exchange.setState(progressState)
exchange.setExec(Some(exec)) StandardMain.exchange.setExec(Some(exec))
exchange.unprompt(ConsoleUnpromptEvent(exec.source), force = false) StandardMain.exchange.unprompt(ConsoleUnpromptEvent(exec.source))
val newState = Command.process(exec.commandLine, progressState) val newState = Command.process(exec.commandLine, progressState)
if (exec.execId.fold(true)(!_.startsWith(networkExecPrefix)) && if (exec.execId.fold(true)(!_.startsWith(networkExecPrefix)) &&
!exec.commandLine.startsWith(networkExecPrefix)) { !exec.commandLine.startsWith(networkExecPrefix)) {

View File

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

View File

@ -1254,11 +1254,11 @@ private[sbt] object ContinuousCommands {
} }
private[this] val preWatchCommand = watchCommand(preWatch) { (channel, state) => 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) watchState(channel).beforeCommand(state)
} }
private[this] val postWatchCommand = watchCommand(postWatch) { (channel, 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) val ws = watchState(channel)
watchStates.put(channel, ws.withPending(false)) watchStates.put(channel, ws.withPending(false))
ws.afterCommand(state) ws.afterCommand(state)
@ -1268,7 +1268,7 @@ private[sbt] object ContinuousCommands {
state state
} }
private[sbt] def stopWatchImpl(channelName: String): Unit = { 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 => Option(watchStates.get(channelName)).foreach { ws =>
ws.afterWatch() ws.afterWatch()
ws.callbacks.onExit() ws.callbacks.onExit()

View File

@ -73,7 +73,8 @@ private[sbt] final class TaskTraceEvent
() ()
} finally { } finally {
trace.close() trace.close()
console.println(s"wrote $outFile") try console.println(s"wrote $outFile")
catch { case _: java.nio.channels.ClosedChannelException => }
} }
} }
} }