mirror of https://github.com/sbt/sbt.git
Allow users to configure standard input setting
Certain tasks may prefer to have the input set to raw mode and/or have echo off. The specific use case is that it is difficult to get the ammonite console to work correctly with the thin client. The problem is that the ammonite console runs some tty commands. These commands will only work on the tty of the thin client when the thin client itself has launched the sbt server session (since they share the same tty). Once the thin client that launched the server exits, the ammonite console will never work again with that server session. A workaround is to launch sbt separately and leave that server session open. Then, if the run task is configured with canonical input set to false and echo disabled, the thin client will work. In the future, it's possible that ammonite could be updated to not rely on calling stty commands and then the thin client could work with the ammonite console even after the initial thin client session has exited provided canonical input and echo are disabled.
This commit is contained in:
parent
0427e5f9c5
commit
ddb626a9be
|
|
@ -386,6 +386,8 @@ object Defaults extends BuildCommon {
|
|||
sys.env.contains("CI") || SysProp.ci,
|
||||
// watch related settings
|
||||
pollInterval :== Watch.defaultPollInterval,
|
||||
canonicalInput :== true,
|
||||
echoInput :== true,
|
||||
) ++ LintUnused.lintSettings
|
||||
++ DefaultBackgroundJobService.backgroundJobServiceSettings
|
||||
++ RemoteCache.globalSettings
|
||||
|
|
@ -1700,6 +1702,20 @@ object Defaults extends BuildCommon {
|
|||
/** Implements `cleanFiles` task. */
|
||||
private[sbt] def cleanFilesTask: Initialize[Task[Vector[File]]] = Def.task { Vector.empty[File] }
|
||||
|
||||
private[this] def termWrapper(canonical: Boolean, echo: Boolean): (() => Unit) => (() => Unit) =
|
||||
(f: () => Unit) =>
|
||||
() => {
|
||||
val term = Terminal.get
|
||||
if (!canonical) {
|
||||
term.enterRawMode()
|
||||
if (echo) term.setEchoEnabled(echo)
|
||||
} else if (!echo) term.setEchoEnabled(false)
|
||||
try f()
|
||||
finally {
|
||||
if (!canonical) term.exitRawMode()
|
||||
if (!echo) term.setEchoEnabled(true)
|
||||
}
|
||||
}
|
||||
def bgRunMainTask(
|
||||
products: Initialize[Task[Classpath]],
|
||||
classpath: Initialize[Task[Classpath]],
|
||||
|
|
@ -1713,6 +1729,7 @@ object Defaults extends BuildCommon {
|
|||
val service = bgJobService.value
|
||||
val (mainClass, args) = parser.parsed
|
||||
val hashClasspath = (bgHashClasspath in bgRunMain).value
|
||||
val wrapper = termWrapper(canonicalInput.value, echoInput.value)
|
||||
service.runInBackgroundWithLoader(resolvedScoped.value, state.value) { (logger, workingDir) =>
|
||||
val files =
|
||||
if (copyClasspath.value)
|
||||
|
|
@ -1722,9 +1739,9 @@ object Defaults extends BuildCommon {
|
|||
scalaRun.value match {
|
||||
case r: Run =>
|
||||
val loader = r.newLoader(cp)
|
||||
(Some(loader), () => r.runWithLoader(loader, cp, mainClass, args, logger).get)
|
||||
(Some(loader), wrapper(() => r.runWithLoader(loader, cp, mainClass, args, logger).get))
|
||||
case sr =>
|
||||
(None, () => sr.run(mainClass, cp, args, logger).get)
|
||||
(None, wrapper(() => sr.run(mainClass, cp, args, logger).get))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1743,6 +1760,7 @@ object Defaults extends BuildCommon {
|
|||
val service = bgJobService.value
|
||||
val mainClass = mainClassTask.value getOrElse sys.error("No main class detected.")
|
||||
val hashClasspath = (bgHashClasspath in bgRun).value
|
||||
val wrapper = termWrapper(canonicalInput.value, echoInput.value)
|
||||
service.runInBackgroundWithLoader(resolvedScoped.value, state.value) { (logger, workingDir) =>
|
||||
val files =
|
||||
if (copyClasspath.value)
|
||||
|
|
@ -1753,9 +1771,9 @@ object Defaults extends BuildCommon {
|
|||
scalaRun.value match {
|
||||
case r: Run =>
|
||||
val loader = r.newLoader(cp)
|
||||
(Some(loader), () => r.runWithLoader(loader, cp, mainClass, args, logger).get)
|
||||
(Some(loader), wrapper(() => r.runWithLoader(loader, cp, mainClass, args, logger).get))
|
||||
case sr =>
|
||||
(None, () => sr.run(mainClass, cp, args, logger).get)
|
||||
(None, wrapper(() => sr.run(mainClass, cp, args, logger).get))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ object Keys {
|
|||
val logBuffered = settingKey[Boolean]("True if logging should be buffered until work completes.").withRank(CSetting)
|
||||
val sLog = settingKey[Logger]("Logger usable by settings during project loading.").withRank(CSetting)
|
||||
val serverLog = taskKey[Unit]("A dummy task to set server log level using Global / serverLog / logLevel.").withRank(CTask)
|
||||
val canonicalInput = settingKey[Boolean]("Toggles whether a task should use canonical input (line buffered with echo) or raw input").withRank(DSetting)
|
||||
val echoInput = settingKey[Boolean]("Toggles whether a task should echo user input").withRank(DSetting)
|
||||
|
||||
// Project keys
|
||||
val autoGeneratedProject = settingKey[Boolean]("If it exists, represents that the project (and name) were automatically created, rather than user specified.").withRank(DSetting)
|
||||
|
|
|
|||
Loading…
Reference in New Issue