mirror of https://github.com/sbt/sbt.git
Fix switching between raw and canonical input
There were a number of issues with swithcing between raw and canonical issues that affected both the server and the thin client. These were reported in #5863 and #5856. In both cases, there were issues with reading input or having the input be displayed. Debugging those issues revealed a number of issues with how we were using the jline 3 system terminal and the hybrid interaction with the jline 2 terminal. This commit eliminates all of our internal jline 2 usage. The only remaining jline 2 usage is that we create and override the global terminal for the scala console for scala versions < 2.13. By moving away from jline 2, I was also able to fix #5828, which reported that the home, end and delete keys were not working. One of the big issues that this commit addresses is that the NetworkClient was always performing blocking reads on System.in. This was problematic because it turns out that you can't switch between raw and canonical modes when there is a read present. To fix this, the server now sends a message to the client when it wants to read bytes and only then does the client create a background thread to read a single byte. I also figured out how to set the terminal type properly for the thin client on windows where we had been manually setting the capabilities to ansi, which only worked for some keys. This fix required switching to the WindowsInputStream that I introduced in a prior commit. Before we were using the jline 2 wrapped input stream which was converting some system events, like home and end, to the wrong escape sequence mappings. The remainder of the commit is mostly just converting from jline 2 apis to jline 3 apis. I verified that tab completions, the scala console, the ammonite console and a run task that read from System.in all work with both the server and the thin client on mac, linux and windows after these changes. Fixes #5828, #5863, #5856
This commit is contained in:
parent
410a8dd4b1
commit
bb8b9a1c99
|
|
@ -21,6 +21,7 @@ import org.jline.reader.{
|
|||
ParsedLine,
|
||||
UserInterruptException,
|
||||
}
|
||||
import org.jline.utils.ClosedException
|
||||
import sbt.internal.util.complete.Parser
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
|
@ -87,7 +88,7 @@ object LineReader {
|
|||
case e: EndOfFileException =>
|
||||
if (terminal == Terminal.console && System.console == null) None
|
||||
else Some("exit")
|
||||
case _: IOError => Some("exit")
|
||||
case _: IOError | _: ClosedException => Some("exit")
|
||||
case _: UserInterruptException | _: ClosedByInterruptException |
|
||||
_: UncheckedIOException =>
|
||||
throw new InterruptedException
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
|||
import org.jline.utils.InfoCmp.Capability
|
||||
import org.jline.utils.{ ClosedException, NonBlockingReader }
|
||||
import org.jline.terminal.{ Attributes, Size, Terminal => JTerminal }
|
||||
import org.jline.terminal.Attributes.{ InputFlag, LocalFlag }
|
||||
import org.jline.terminal.Terminal.SignalHandler
|
||||
import org.jline.terminal.impl.{ AbstractTerminal, DumbTerminal }
|
||||
import org.jline.terminal.impl.jansi.JansiSupportImpl
|
||||
|
|
@ -24,12 +25,7 @@ import scala.util.Try
|
|||
import java.util.concurrent.LinkedBlockingQueue
|
||||
|
||||
private[sbt] object JLine3 {
|
||||
private val capabilityMap = Capability
|
||||
.values()
|
||||
.map { c =>
|
||||
c.toString -> c
|
||||
}
|
||||
.toMap
|
||||
private[util] val initialAttributes = new AtomicReference[Attributes]
|
||||
|
||||
private[this] val forceWindowsJansiHolder = new AtomicBoolean(false)
|
||||
private[sbt] def forceWindowsJansi(): Unit = forceWindowsJansiHolder.set(true)
|
||||
|
|
@ -51,6 +47,7 @@ private[sbt] object JLine3 {
|
|||
term
|
||||
}
|
||||
private[util] def system: org.jline.terminal.Terminal = {
|
||||
val term =
|
||||
if (forceWindowsJansiHolder.get) windowsJansi()
|
||||
else {
|
||||
// Only use jna on windows. Both jna and jansi use illegal reflective
|
||||
|
|
@ -63,6 +60,11 @@ private[sbt] object JLine3 {
|
|||
.paused(true)
|
||||
.build()
|
||||
}
|
||||
initialAttributes.get match {
|
||||
case null => initialAttributes.set(term.getAttributes)
|
||||
case _ =>
|
||||
}
|
||||
term
|
||||
}
|
||||
private[sbt] def apply(term: Terminal): JTerminal = {
|
||||
if (System.getProperty("jline.terminal", "") == "none" || !Terminal.formatEnabledInEnv)
|
||||
|
|
@ -70,7 +72,12 @@ private[sbt] object JLine3 {
|
|||
else wrapTerminal(term)
|
||||
}
|
||||
private[this] def wrapTerminal(term: Terminal): JTerminal = {
|
||||
new AbstractTerminal(term.name, "ansi", Charset.forName("UTF-8"), SignalHandler.SIG_DFL) {
|
||||
new AbstractTerminal(
|
||||
term.name,
|
||||
"nocapabilities",
|
||||
Charset.forName("UTF-8"),
|
||||
SignalHandler.SIG_DFL
|
||||
) {
|
||||
val closed = new AtomicBoolean(false)
|
||||
setOnClose { () =>
|
||||
doClose()
|
||||
|
|
@ -84,7 +91,6 @@ private[sbt] object JLine3 {
|
|||
}
|
||||
}
|
||||
}
|
||||
parseInfoCmp()
|
||||
override val input: InputStream = new InputStream {
|
||||
override def read: Int = {
|
||||
val res = term.inputStream match {
|
||||
|
|
@ -166,45 +172,47 @@ private[sbt] object JLine3 {
|
|||
* are the same.
|
||||
*/
|
||||
override def getStringCapability(cap: Capability): String = {
|
||||
term.getStringCapability(cap.toString, jline3 = true)
|
||||
}
|
||||
override def getNumericCapability(cap: Capability): Integer = {
|
||||
term.getNumericCapability(cap.toString, jline3 = true)
|
||||
}
|
||||
override def getBooleanCapability(cap: Capability): Boolean = {
|
||||
term.getBooleanCapability(cap.toString, jline3 = true)
|
||||
term.getStringCapability(cap.toString)
|
||||
}
|
||||
override def getNumericCapability(cap: Capability): Integer =
|
||||
term.getNumericCapability(cap.toString)
|
||||
override def getBooleanCapability(cap: Capability): Boolean =
|
||||
term.getBooleanCapability(cap.toString)
|
||||
def getAttributes(): Attributes = attributesFromMap(term.getAttributes)
|
||||
def getSize(): Size = new Size(term.getWidth, term.getHeight)
|
||||
def setAttributes(a: Attributes): Unit = term.setAttributes(toMap(a))
|
||||
def setAttributes(a: Attributes): Unit = {} // don't allow the jline line reader to change attributes
|
||||
def setSize(size: Size): Unit = term.setSize(size.getColumns, size.getRows)
|
||||
|
||||
/**
|
||||
* Override enterRawMode because the default implementation modifies System.in
|
||||
* to be non-blocking which means it immediately returns -1 if there is no
|
||||
* data available, which is not desirable for us.
|
||||
*/
|
||||
override def enterRawMode(): Attributes = enterRawModeImpl(this)
|
||||
override def enterRawMode(): Attributes = {
|
||||
// don't actually modify the term, that is handled by LineReader
|
||||
attributesFromMap(term.getAttributes)
|
||||
}
|
||||
}
|
||||
}
|
||||
private def enterRawModeImpl(term: JTerminal): Attributes = {
|
||||
val prvAttr = term.getAttributes()
|
||||
val newAttr = new Attributes(prvAttr)
|
||||
newAttr.setLocalFlags(
|
||||
EnumSet
|
||||
.of(Attributes.LocalFlag.ICANON, Attributes.LocalFlag.ECHO, Attributes.LocalFlag.IEXTEN),
|
||||
false
|
||||
)
|
||||
newAttr.setInputFlags(
|
||||
EnumSet
|
||||
.of(Attributes.InputFlag.IXON, Attributes.InputFlag.ICRNL, Attributes.InputFlag.INLCR),
|
||||
false
|
||||
)
|
||||
newAttr.setLocalFlags(EnumSet.of(LocalFlag.ICANON, LocalFlag.ECHO, LocalFlag.IEXTEN), false)
|
||||
newAttr.setInputFlags(EnumSet.of(InputFlag.IXON, InputFlag.ICRNL, InputFlag.INLCR), false)
|
||||
term.setAttributes(newAttr)
|
||||
prvAttr
|
||||
}
|
||||
private[util] def enterRawMode(term: JTerminal): Map[String, String] =
|
||||
toMap(enterRawModeImpl(term))
|
||||
private[util] def enterRawMode(term: JTerminal): Unit = {
|
||||
val prevAttr = initialAttributes.get
|
||||
val newAttr = new Attributes(prevAttr)
|
||||
// These flags are copied from the jline3 enterRawMode but the jline implementation
|
||||
// also puts the input stream in non blocking mode, which we do not want.
|
||||
newAttr.setLocalFlags(EnumSet.of(LocalFlag.ICANON, LocalFlag.IEXTEN, LocalFlag.ECHO), false)
|
||||
newAttr.setInputFlags(EnumSet.of(InputFlag.IXON, InputFlag.ICRNL, InputFlag.INLCR), false)
|
||||
term.setAttributes(newAttr)
|
||||
()
|
||||
}
|
||||
private[util] def exitRawMode(term: JTerminal): Unit = {
|
||||
val initAttr = initialAttributes.get
|
||||
val newAttr = new Attributes(initAttr)
|
||||
newAttr.setLocalFlags(EnumSet.of(LocalFlag.ICANON, LocalFlag.ECHO), true)
|
||||
term.setAttributes(newAttr)
|
||||
}
|
||||
private[util] def toMap(jattributes: Attributes): Map[String, String] = {
|
||||
val result = new java.util.LinkedHashMap[String, String]
|
||||
result.put(
|
||||
|
|
@ -233,14 +241,14 @@ private[sbt] object JLine3 {
|
|||
)
|
||||
result.asScala.toMap
|
||||
}
|
||||
private[this] val iflagMap: Map[String, Attributes.InputFlag] =
|
||||
Attributes.InputFlag.values.map(f => f.name.toLowerCase -> f).toMap
|
||||
private[this] val iflagMap: Map[String, InputFlag] =
|
||||
InputFlag.values.map(f => f.name.toLowerCase -> f).toMap
|
||||
private[this] val oflagMap: Map[String, Attributes.OutputFlag] =
|
||||
Attributes.OutputFlag.values.map(f => f.name.toLowerCase -> f).toMap
|
||||
private[this] val cflagMap: Map[String, Attributes.ControlFlag] =
|
||||
Attributes.ControlFlag.values.map(f => f.name.toLowerCase -> f).toMap
|
||||
private[this] val lflagMap: Map[String, Attributes.LocalFlag] =
|
||||
Attributes.LocalFlag.values.map(f => f.name.toLowerCase -> f).toMap
|
||||
private[this] val lflagMap: Map[String, LocalFlag] =
|
||||
LocalFlag.values.map(f => f.name.toLowerCase -> f).toMap
|
||||
private[this] val charMap: Map[String, Attributes.ControlChar] =
|
||||
Attributes.ControlChar.values().map(f => f.name.toLowerCase -> f).toMap
|
||||
private[util] def attributesFromMap(map: Map[String, String]): Attributes = {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import java.util.{ Arrays, Locale }
|
|||
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
||||
import java.util.concurrent.{ Executors, LinkedBlockingQueue, TimeUnit }
|
||||
|
||||
import jline.DefaultTerminal2
|
||||
import jline.console.ConsoleReader
|
||||
import scala.annotation.tailrec
|
||||
import scala.concurrent.duration._
|
||||
|
|
@ -104,6 +103,13 @@ trait Terminal extends AutoCloseable {
|
|||
*/
|
||||
def isSupershellEnabled: Boolean
|
||||
|
||||
/**
|
||||
* Toggles whether or not the terminal should echo characters back to stdout
|
||||
*
|
||||
* @return the previous value of the toggle
|
||||
*/
|
||||
def setEchoEnabled(toggle: Boolean): Unit
|
||||
|
||||
/*
|
||||
* The methods below this comment are implementation details that are in
|
||||
* some cases specific to jline2. These methods may need to change or be
|
||||
|
|
@ -126,15 +132,21 @@ trait Terminal extends AutoCloseable {
|
|||
*/
|
||||
private[sbt] def getLines: Seq[String]
|
||||
|
||||
private[sbt] def getBooleanCapability(capability: String, jline3: Boolean): Boolean
|
||||
private[sbt] def getNumericCapability(capability: String, jline3: Boolean): Integer
|
||||
private[sbt] def getStringCapability(capability: String, jline3: Boolean): String
|
||||
private[sbt] def getBooleanCapability(capability: String): Boolean
|
||||
private[sbt] def getNumericCapability(capability: String): Integer
|
||||
private[sbt] def getStringCapability(capability: String): String
|
||||
private[sbt] def getAttributes: Map[String, String]
|
||||
private[sbt] def setAttributes(attributes: Map[String, String]): Unit
|
||||
private[sbt] def setSize(width: Int, height: Int): Unit
|
||||
|
||||
private[sbt] def name: String
|
||||
private[sbt] def withRawInput[T](f: => T): T = f
|
||||
private[sbt] final def withRawInput[T](f: => T): T = {
|
||||
enterRawMode()
|
||||
try f
|
||||
catch { case e: InterruptedIOException => throw new InterruptedException } finally exitRawMode()
|
||||
}
|
||||
private[sbt] def enterRawMode(): Unit
|
||||
private[sbt] def exitRawMode(): Unit
|
||||
private[sbt] def write(bytes: Int*): Unit
|
||||
private[sbt] def printStream: PrintStream
|
||||
private[sbt] def withPrintStream[T](f: PrintStream => T): T
|
||||
|
|
@ -188,7 +200,6 @@ object Terminal {
|
|||
* terminal.
|
||||
*/
|
||||
private[sbt] def toJLine: jline.Terminal with jline.Terminal2 = term match {
|
||||
case t: ConsoleTerminal => t.term
|
||||
case _ =>
|
||||
new jline.Terminal with jline.Terminal2 {
|
||||
override def init(): Unit = {}
|
||||
|
|
@ -206,15 +217,12 @@ object Terminal {
|
|||
override def disableInterruptCharacter(): Unit = {}
|
||||
override def enableInterruptCharacter(): Unit = {}
|
||||
override def getOutputEncoding: String = null
|
||||
override def getBooleanCapability(capability: String): Boolean = {
|
||||
term.getBooleanCapability(capability, jline3 = false)
|
||||
}
|
||||
override def getNumericCapability(capability: String): Integer = {
|
||||
term.getNumericCapability(capability, jline3 = false)
|
||||
}
|
||||
override def getStringCapability(capability: String): String = {
|
||||
term.getStringCapability(capability, jline3 = false)
|
||||
}
|
||||
override def getBooleanCapability(capability: String): Boolean =
|
||||
term.getBooleanCapability(capability)
|
||||
override def getNumericCapability(capability: String): Integer =
|
||||
term.getNumericCapability(capability)
|
||||
override def getStringCapability(capability: String): String =
|
||||
term.getStringCapability(capability)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -318,7 +326,7 @@ object Terminal {
|
|||
// In ci environments, don't touch the io streams unless run with -Dsbt.io.virtual=true
|
||||
if (System.getProperty("sbt.io.virtual", "") == "true" || (logFormatEnabled.getOrElse(true) && !isCI)) {
|
||||
hasProgress.set(isServer)
|
||||
consoleTerminalHolder.set(wrap(jline.TerminalFactory.get))
|
||||
consoleTerminalHolder.set(newConsoleTerminal())
|
||||
activeTerminal.set(consoleTerminalHolder.get)
|
||||
try withOut(withIn(f))
|
||||
finally {
|
||||
|
|
@ -333,7 +341,7 @@ object Terminal {
|
|||
* back to blocking mode. We can then close the console. We do
|
||||
* this on a background thread in case the read blocks indefinitely.
|
||||
*/
|
||||
val prev = c.system.enterRawMode()
|
||||
c.system.enterRawMode()
|
||||
val runnable: Runnable = () => {
|
||||
try Util.ignoreResult(c.inputStream.read)
|
||||
catch { case _: InterruptedException => }
|
||||
|
|
@ -344,7 +352,6 @@ object Terminal {
|
|||
// The thread should exit almost instantly but give it 200ms to spin up
|
||||
thread.join(200)
|
||||
if (thread.isAlive) thread.interrupt()
|
||||
c.system.setAttributes(prev)
|
||||
c.close()
|
||||
case c => c.close()
|
||||
}
|
||||
|
|
@ -357,6 +364,8 @@ object Terminal {
|
|||
private[this] object ProxyTerminal extends Terminal {
|
||||
private def t: Terminal = activeTerminal.get
|
||||
override private[sbt] def progressState: ProgressState = t.progressState
|
||||
override private[sbt] def enterRawMode(): Unit = t.enterRawMode()
|
||||
override private[sbt] def exitRawMode(): Unit = t.exitRawMode()
|
||||
override def getWidth: Int = t.getWidth
|
||||
override def getHeight: Int = t.getHeight
|
||||
override def getLineHeightAndWidth(line: String): (Int, Int) = t.getLineHeightAndWidth(line)
|
||||
|
|
@ -369,17 +378,17 @@ object Terminal {
|
|||
override def isEchoEnabled: Boolean = t.isEchoEnabled
|
||||
override def isSuccessEnabled: Boolean = t.isSuccessEnabled
|
||||
override def isSupershellEnabled: Boolean = t.isSupershellEnabled
|
||||
override def getBooleanCapability(capability: String, jline3: Boolean): Boolean =
|
||||
t.getBooleanCapability(capability, jline3)
|
||||
override def getNumericCapability(capability: String, jline3: Boolean): Integer =
|
||||
t.getNumericCapability(capability, jline3)
|
||||
override def getStringCapability(capability: String, jline3: Boolean): String =
|
||||
t.getStringCapability(capability, jline3)
|
||||
override def setEchoEnabled(toggle: Boolean): Unit = t.setEchoEnabled(toggle)
|
||||
override def getBooleanCapability(capability: String): Boolean =
|
||||
t.getBooleanCapability(capability)
|
||||
override def getNumericCapability(capability: String): Integer =
|
||||
t.getNumericCapability(capability)
|
||||
override def getStringCapability(capability: String): String =
|
||||
t.getStringCapability(capability)
|
||||
override private[sbt] def getAttributes: Map[String, String] = t.getAttributes
|
||||
override private[sbt] def setAttributes(attributes: Map[String, String]): Unit =
|
||||
t.setAttributes(attributes)
|
||||
override private[sbt] def setSize(width: Int, height: Int): Unit = t.setSize(width, height)
|
||||
override def withRawInput[T](f: => T): T = t.withRawInput(f)
|
||||
override def printStream: PrintStream = t.printStream
|
||||
override def withPrintStream[T](f: PrintStream => T): T = t.withPrintStream(f)
|
||||
override private[sbt] def withRawOutput[R](f: => R): R = t.withRawOutput(f)
|
||||
|
|
@ -438,6 +447,10 @@ object Terminal {
|
|||
final def write(bytes: Int*): Unit = readThread.synchronized {
|
||||
bytes.foreach(b => buffer.put(b))
|
||||
}
|
||||
def setRawMode(toggle: Boolean): Unit = in match {
|
||||
case win: WindowsInputStream => win.setRawMode(toggle)
|
||||
case _ =>
|
||||
}
|
||||
private[this] val executor =
|
||||
Executors.newSingleThreadExecutor(r => new Thread(r, s"sbt-$name-input-reader"))
|
||||
private[this] val buffer = new LinkedBlockingQueue[Integer]
|
||||
|
|
@ -500,8 +513,10 @@ object Terminal {
|
|||
()
|
||||
}
|
||||
}
|
||||
private[this] lazy val nonBlockingIn: WriteableInputStream =
|
||||
new WriteableInputStream(jline.TerminalFactory.get.wrapInIfNeeded(originalIn), "console")
|
||||
private[this] def nonBlockingIn(term: org.jline.terminal.Terminal): WriteableInputStream = {
|
||||
val in = if (Util.isNonCygwinWindows) new WindowsInputStream(term, originalIn) else originalIn
|
||||
new WriteableInputStream(in, "console")
|
||||
}
|
||||
|
||||
private[this] val inputStream = new AtomicReference[InputStream](System.in)
|
||||
private[this] def withOut[T](f: => T): T = {
|
||||
|
|
@ -699,75 +714,16 @@ object Terminal {
|
|||
}
|
||||
private[sbt] def startedByRemoteClient = props.isDefined
|
||||
|
||||
/**
|
||||
* Creates an instance of [[Terminal]] that delegates most of its methods to an underlying
|
||||
* jline.Terminal2 instance. In the long run, sbt should upgrade to jline3, which has a
|
||||
* completely different terminal interface so whereever possible, we should avoid
|
||||
* directly referencing jline.Terminal. Wrapping jline Terminal in sbt terminal helps
|
||||
* with that goal.
|
||||
*
|
||||
* @param terminal the jline terminal to wrap
|
||||
* @return an sbt Terminal
|
||||
*/
|
||||
private[this] def wrap(terminal: jline.Terminal): Terminal = {
|
||||
val term: jline.Terminal with jline.Terminal2 = new jline.Terminal with jline.Terminal2 {
|
||||
private[this] val hasConsole = System.console != null
|
||||
private[this] def alive = hasConsole && attached.get
|
||||
private[this] val term2: jline.Terminal2 = terminal match {
|
||||
case t: jline.Terminal2 => t
|
||||
case _ => new DefaultTerminal2(terminal)
|
||||
}
|
||||
override def init(): Unit =
|
||||
if (alive)
|
||||
try terminal.init()
|
||||
catch {
|
||||
case _: InterruptedException | _: java.io.IOError =>
|
||||
}
|
||||
override def restore(): Unit =
|
||||
try terminal.restore()
|
||||
catch {
|
||||
case _: InterruptedException | _: java.io.IOError =>
|
||||
}
|
||||
override def reset(): Unit =
|
||||
try terminal.reset()
|
||||
catch { case _: InterruptedException => }
|
||||
override def isSupported: Boolean = terminal.isSupported
|
||||
override def getWidth: Int = props.map(_.width).getOrElse(terminal.getWidth)
|
||||
override def getHeight: Int = props.map(_.height).getOrElse(terminal.getHeight)
|
||||
override val isAnsiSupported: Boolean = terminal.isAnsiSupported && formatEnabledInEnv
|
||||
override def wrapOutIfNeeded(out: OutputStream): OutputStream = terminal.wrapOutIfNeeded(out)
|
||||
override def wrapInIfNeeded(in: InputStream): InputStream = terminal.wrapInIfNeeded(in)
|
||||
override def hasWeirdWrap: Boolean = terminal.hasWeirdWrap
|
||||
override def isEchoEnabled: Boolean = terminal.isEchoEnabled
|
||||
|
||||
override def setEchoEnabled(enabled: Boolean): Unit =
|
||||
if (alive) terminal.setEchoEnabled(enabled)
|
||||
override def disableInterruptCharacter(): Unit =
|
||||
if (alive) terminal.disableInterruptCharacter()
|
||||
override def enableInterruptCharacter(): Unit =
|
||||
if (alive) terminal.enableInterruptCharacter()
|
||||
override def getOutputEncoding: String = terminal.getOutputEncoding
|
||||
override def getBooleanCapability(capability: String): Boolean =
|
||||
term2.getBooleanCapability(capability)
|
||||
override def getNumericCapability(capability: String): Integer =
|
||||
term2.getNumericCapability(capability)
|
||||
override def getStringCapability(capability: String): String = {
|
||||
term2.getStringCapability(capability)
|
||||
}
|
||||
}
|
||||
term.restore()
|
||||
term.setEchoEnabled(true)
|
||||
new ConsoleTerminal(
|
||||
term,
|
||||
if (System.console == null) nullWriteableInputStream else nonBlockingIn,
|
||||
originalOut
|
||||
)
|
||||
private[this] def newConsoleTerminal(): Terminal = {
|
||||
val system = JLine3.system
|
||||
val in = if (System.console == null) nullWriteableInputStream else nonBlockingIn(system)
|
||||
new ConsoleTerminal(in, originalOut, system)
|
||||
}
|
||||
|
||||
private[sbt] def reset(): Unit = {
|
||||
jline.TerminalFactory.reset()
|
||||
console.close()
|
||||
consoleTerminalHolder.set(wrap(jline.TerminalFactory.get))
|
||||
consoleTerminalHolder.set(newConsoleTerminal())
|
||||
}
|
||||
|
||||
// translate explicit class names to type in order to support
|
||||
|
|
@ -813,52 +769,56 @@ object Terminal {
|
|||
|
||||
@deprecated("For compatibility only", "1.4.0")
|
||||
private[sbt] def deprecatedTeminal: jline.Terminal = console.toJLine
|
||||
private class ConsoleTerminal(
|
||||
val term: jline.Terminal with jline.Terminal2,
|
||||
private[util] class ConsoleTerminal(
|
||||
in: WriteableInputStream,
|
||||
out: OutputStream
|
||||
out: OutputStream,
|
||||
private[util] val system: org.jline.terminal.Terminal,
|
||||
) extends TerminalImpl(in, out, originalErr, "console0") {
|
||||
private[util] lazy val system = JLine3.system
|
||||
private[this] val rawMode = new AtomicBoolean(false)
|
||||
enterRawMode()
|
||||
override private[sbt] def getSizeImpl: (Int, Int) = {
|
||||
val size = system.getSize
|
||||
(size.getColumns, size.getRows)
|
||||
}
|
||||
override lazy val isAnsiSupported: Boolean = term.isAnsiSupported && !isCI
|
||||
override lazy val isAnsiSupported: Boolean = formatEnabledInEnv && !isCI
|
||||
override private[sbt] def progressState: ProgressState = consoleProgressState.get
|
||||
override def isEchoEnabled: Boolean = system.echo()
|
||||
override def isEchoEnabled: Boolean =
|
||||
try system.echo()
|
||||
catch { case _: InterruptedIOException => false }
|
||||
override def isSuccessEnabled: Boolean = true
|
||||
override def getBooleanCapability(capability: String, jline3: Boolean): Boolean =
|
||||
if (jline3) capabilityMap.get(capability).fold(false)(system.getBooleanCapability)
|
||||
else term.getBooleanCapability(capability)
|
||||
override def getNumericCapability(capability: String, jline3: Boolean): Integer =
|
||||
if (jline3) capabilityMap.get(capability).fold(null: Integer)(system.getNumericCapability)
|
||||
else term.getNumericCapability(capability)
|
||||
override def getStringCapability(capability: String, jline3: Boolean): String =
|
||||
if (jline3) capabilityMap.get(capability).fold(null: String)(system.getStringCapability)
|
||||
else term.getStringCapability(capability)
|
||||
override private[sbt] def restore(): Unit = term.restore()
|
||||
override def setEchoEnabled(toggle: Boolean): Unit =
|
||||
try Util.ignoreResult(system.echo(toggle))
|
||||
catch { case _: InterruptedIOException => }
|
||||
override def getBooleanCapability(capability: String): Boolean =
|
||||
capabilityMap.get(capability).fold(false)(system.getBooleanCapability)
|
||||
override def getNumericCapability(capability: String): Integer =
|
||||
capabilityMap.get(capability).fold(null: Integer)(system.getNumericCapability)
|
||||
override def getStringCapability(capability: String): String = {
|
||||
val res = capabilityMap.get(capability).fold(null: String)(system.getStringCapability)
|
||||
res
|
||||
}
|
||||
override private[sbt] def restore(): Unit = exitRawMode()
|
||||
|
||||
override private[sbt] def getAttributes: Map[String, String] =
|
||||
Try(JLine3.toMap(system.getAttributes)).getOrElse(Map.empty)
|
||||
override private[sbt] def setAttributes(attributes: Map[String, String]): Unit =
|
||||
override private[sbt] def setAttributes(attributes: Map[String, String]): Unit = {
|
||||
system.setAttributes(JLine3.attributesFromMap(attributes))
|
||||
}
|
||||
override private[sbt] def setSize(width: Int, height: Int): Unit =
|
||||
system.setSize(new org.jline.terminal.Size(width, height))
|
||||
|
||||
override def withRawInput[T](f: => T): T = term.synchronized {
|
||||
try {
|
||||
term.init()
|
||||
term.setEchoEnabled(false)
|
||||
f
|
||||
} catch { case _: InterruptedIOException => throw new InterruptedException } finally {
|
||||
term.restore()
|
||||
term.setEchoEnabled(true)
|
||||
override private[sbt] def enterRawMode(): Unit = if (rawMode.compareAndSet(false, true)) {
|
||||
in.setRawMode(true)
|
||||
JLine3.enterRawMode(system)
|
||||
}
|
||||
override private[sbt] def exitRawMode(): Unit = if (rawMode.compareAndSet(true, false)) {
|
||||
in.setRawMode(false)
|
||||
JLine3.exitRawMode(system)
|
||||
}
|
||||
override def isColorEnabled: Boolean =
|
||||
props
|
||||
.map(_.color)
|
||||
.getOrElse(isColorEnabledProp.getOrElse(term.isAnsiSupported && formatEnabledInEnv))
|
||||
.getOrElse(isColorEnabledProp.getOrElse(formatEnabledInEnv))
|
||||
|
||||
override def isSupershellEnabled: Boolean =
|
||||
props
|
||||
|
|
@ -871,8 +831,9 @@ object Terminal {
|
|||
})
|
||||
override def close(): Unit = {
|
||||
try {
|
||||
system.setAttributes(JLine3.initialAttributes.get)
|
||||
system.close()
|
||||
term.restore()
|
||||
in.close()
|
||||
} catch { case NonFatal(_) => }
|
||||
super.close()
|
||||
}
|
||||
|
|
@ -972,13 +933,15 @@ object Terminal {
|
|||
private[sbt] class DefaultTerminal extends Terminal {
|
||||
override def close(): Unit = {}
|
||||
override private[sbt] def progressState: ProgressState = new ProgressState(1)
|
||||
override def getBooleanCapability(capability: String, jline3: Boolean): Boolean = false
|
||||
override private[sbt] def enterRawMode(): Unit = {}
|
||||
override private[sbt] def exitRawMode(): Unit = {}
|
||||
override def getBooleanCapability(capability: String): Boolean = false
|
||||
override def getHeight: Int = 0
|
||||
override def getLastLine: Option[String] = None
|
||||
override def getLines: Seq[String] = Nil
|
||||
override def getLineHeightAndWidth(line: String): (Int, Int) = (0, 0)
|
||||
override def getNumericCapability(capability: String, jline3: Boolean): Integer = null
|
||||
override def getStringCapability(capability: String, jline3: Boolean): String = null
|
||||
override def getNumericCapability(capability: String): Integer = null
|
||||
override def getStringCapability(capability: String): String = null
|
||||
override def getWidth: Int = 0
|
||||
override def inputStream: InputStream = nullInputStream
|
||||
override def isAnsiSupported: Boolean = false
|
||||
|
|
@ -986,6 +949,7 @@ object Terminal {
|
|||
override def isEchoEnabled: Boolean = false
|
||||
override def isSuccessEnabled: Boolean = true
|
||||
override def isSupershellEnabled: Boolean = false
|
||||
override def setEchoEnabled(toggle: Boolean): Unit = {}
|
||||
override def outputStream: OutputStream = _ => {}
|
||||
override def errorStream: OutputStream = _ => {}
|
||||
override private[sbt] def getAttributes: Map[String, String] = Map.empty
|
||||
|
|
@ -1000,7 +964,7 @@ object Terminal {
|
|||
}
|
||||
private[sbt] object NullTerminal extends DefaultTerminal
|
||||
private[sbt] object SimpleTerminal extends DefaultTerminal {
|
||||
override lazy val inputStream: InputStream = nonBlockingIn
|
||||
override lazy val inputStream: InputStream = originalIn
|
||||
override lazy val outputStream: OutputStream = originalOut
|
||||
override lazy val errorStream: OutputStream = originalErr
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ public class BootServerSocket implements AutoCloseable {
|
|||
private final Object lock = new Object();
|
||||
private final LinkedBlockingQueue<ClientSocket> clientSocketReads = new LinkedBlockingQueue<>();
|
||||
private final Path socketFile;
|
||||
private final AtomicBoolean needInput = new AtomicBoolean(false);
|
||||
|
||||
private class ClientSocket implements AutoCloseable {
|
||||
final Socket socket;
|
||||
|
|
@ -116,6 +117,11 @@ public class BootServerSocket implements AutoCloseable {
|
|||
final InputStream inputStream = socket.getInputStream();
|
||||
while (alive.get()) {
|
||||
try {
|
||||
synchronized (needInput) {
|
||||
while (!needInput.get() && alive.get()) needInput.wait();
|
||||
}
|
||||
if (alive.get()) {
|
||||
socket.getOutputStream().write(5);
|
||||
int b = inputStream.read();
|
||||
if (b != -1) {
|
||||
bytes.put(b);
|
||||
|
|
@ -123,6 +129,8 @@ public class BootServerSocket implements AutoCloseable {
|
|||
} else {
|
||||
alive.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
alive.set(false);
|
||||
}
|
||||
|
|
@ -209,10 +217,18 @@ public class BootServerSocket implements AutoCloseable {
|
|||
@Override
|
||||
public int read() {
|
||||
try {
|
||||
synchronized (needInput) {
|
||||
needInput.set(true);
|
||||
needInput.notifyAll();
|
||||
}
|
||||
ClientSocket clientSocket = clientSocketReads.take();
|
||||
return clientSocket.bytes.take();
|
||||
} catch (final InterruptedException e) {
|
||||
return -1;
|
||||
} finally {
|
||||
synchronized (needInput) {
|
||||
needInput.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,8 +38,10 @@ import scala.util.{ Failure, Properties, Success, Try }
|
|||
import Serialization.{
|
||||
CancelAll,
|
||||
attach,
|
||||
cancelReadSystemIn,
|
||||
cancelRequest,
|
||||
promptChannel,
|
||||
readSystemIn,
|
||||
systemIn,
|
||||
systemErr,
|
||||
systemOut,
|
||||
|
|
@ -50,6 +52,8 @@ import Serialization.{
|
|||
terminalGetSize,
|
||||
terminalPropertiesQuery,
|
||||
terminalPropertiesResponse,
|
||||
terminalSetEcho,
|
||||
terminalSetRawMode,
|
||||
terminalSetSize,
|
||||
getTerminalAttributes,
|
||||
setTerminalAttributes,
|
||||
|
|
@ -149,11 +153,15 @@ class NetworkClient(
|
|||
|
||||
private[this] val stdinBytes = new LinkedBlockingQueue[Int]
|
||||
private[this] val inLock = new Object
|
||||
private[this] val inputThread = new AtomicReference(new RawInputThread)
|
||||
private[this] val inputThread = new AtomicReference[RawInputThread]
|
||||
private[this] val exitClean = new AtomicBoolean(true)
|
||||
private[this] val sbtProcess = new AtomicReference[Process](null)
|
||||
private class ConnectionRefusedException(t: Throwable) extends Throwable(t)
|
||||
private class ServerFailedException extends Exception
|
||||
private[this] def startInputThread(): Unit = inputThread.get match {
|
||||
case null => inputThread.set(new RawInputThread)
|
||||
case _ =>
|
||||
}
|
||||
|
||||
// Open server connection based on the portfile
|
||||
def init(promptCompleteUsers: Boolean, retry: Boolean): ServerConnection =
|
||||
|
|
@ -165,6 +173,7 @@ class NetworkClient(
|
|||
if (noStdErr) System.exit(0)
|
||||
else if (noTab) waitForServer(portfile, log = true, startServer = true)
|
||||
else {
|
||||
startInputThread()
|
||||
stdinBytes.take match {
|
||||
case 9 =>
|
||||
errorStream.println("\nStarting server...")
|
||||
|
|
@ -250,7 +259,12 @@ class NetworkClient(
|
|||
Option(inputThread.get).foreach(_.close())
|
||||
Option(interactiveThread.get).foreach(_.interrupt)
|
||||
}
|
||||
case "readInput" =>
|
||||
case `readSystemIn` => startInputThread()
|
||||
case `cancelReadSystemIn` =>
|
||||
inputThread.get match {
|
||||
case null =>
|
||||
case t => t.close()
|
||||
}
|
||||
case _ => self.onNotification(msg)
|
||||
}
|
||||
}
|
||||
|
|
@ -289,9 +303,10 @@ class NetworkClient(
|
|||
var socket: Option[Socket] =
|
||||
if (!Properties.isLinux) Try(ClientSocket.localSocket(bootSocketName, useJNI)).toOption
|
||||
else None
|
||||
val term = Terminal.console
|
||||
term.exitRawMode()
|
||||
val process = socket match {
|
||||
case None if startServer =>
|
||||
val term = Terminal.console
|
||||
if (log) console.appendLog(Level.Info, "server was not detected. starting an instance")
|
||||
|
||||
val props =
|
||||
|
|
@ -349,6 +364,7 @@ class NetworkClient(
|
|||
s.getInputStream.read match {
|
||||
case -1 | 0 => readThreadAlive.set(false)
|
||||
case 2 => gotInputBack = true
|
||||
case 5 => term.enterRawMode(); startInputThread()
|
||||
case 3 if gotInputBack => readThreadAlive.set(false)
|
||||
case i if gotInputBack => stdinBytes.offer(i)
|
||||
case i => printStream.write(i)
|
||||
|
|
@ -381,9 +397,6 @@ class NetworkClient(
|
|||
while (!gotInputBack && !stdinBytes.isEmpty && socket.isDefined) {
|
||||
val out = s.getOutputStream
|
||||
val b = stdinBytes.poll
|
||||
// echo stdin during boot
|
||||
printStream.write(b)
|
||||
printStream.flush()
|
||||
out.write(b)
|
||||
out.flush()
|
||||
}
|
||||
|
|
@ -610,18 +623,13 @@ class NetworkClient(
|
|||
case (`terminalCapabilities`, Some(json)) =>
|
||||
Converter.fromJson[TerminalCapabilitiesQuery](json) match {
|
||||
case Success(terminalCapabilitiesQuery) =>
|
||||
val jline3 = terminalCapabilitiesQuery.jline3
|
||||
val response = TerminalCapabilitiesResponse(
|
||||
terminalCapabilitiesQuery.boolean
|
||||
.map(Terminal.console.getBooleanCapability(_, jline3)),
|
||||
.map(Terminal.console.getBooleanCapability(_)),
|
||||
terminalCapabilitiesQuery.numeric
|
||||
.map(
|
||||
c => Option(Terminal.console.getNumericCapability(c, jline3)).fold(-1)(_.toInt)
|
||||
),
|
||||
.map(c => Option(Terminal.console.getNumericCapability(c)).fold(-1)(_.toInt)),
|
||||
terminalCapabilitiesQuery.string
|
||||
.map(
|
||||
s => Option(Terminal.console.getStringCapability(s, jline3)).getOrElse("null")
|
||||
),
|
||||
.map(s => Option(Terminal.console.getStringCapability(s)).getOrElse("null")),
|
||||
)
|
||||
sendCommandResponse(
|
||||
terminalCapabilitiesResponse,
|
||||
|
|
@ -677,6 +685,21 @@ class NetworkClient(
|
|||
sendCommandResponse("", TerminalSetSizeResponse(), msg.id)
|
||||
case Failure(_) =>
|
||||
}
|
||||
case (`terminalSetEcho`, Some(json)) =>
|
||||
Converter.fromJson[TerminalSetEchoCommand](json) match {
|
||||
case Success(echo) =>
|
||||
Terminal.console.setEchoEnabled(echo.toggle)
|
||||
sendCommandResponse("", TerminalSetEchoResponse(), msg.id)
|
||||
case Failure(_) =>
|
||||
}
|
||||
case (`terminalSetRawMode`, Some(json)) =>
|
||||
Converter.fromJson[TerminalSetRawModeCommand](json) match {
|
||||
case Success(raw) =>
|
||||
if (raw.toggle) Terminal.console.enterRawMode()
|
||||
else Terminal.console.exitRawMode()
|
||||
sendCommandResponse("", TerminalSetRawModeResponse(), msg.id)
|
||||
case Failure(_) =>
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
|
@ -787,6 +810,7 @@ class NetworkClient(
|
|||
else if (noTab) updateCompletions()
|
||||
else {
|
||||
errorStream.print(s"\nNo cached $label names found. Press '<tab>' to compile: ")
|
||||
startInputThread()
|
||||
stdinBytes.take match {
|
||||
case 9 => updateCompletions()
|
||||
case _ => Nil
|
||||
|
|
@ -901,17 +925,18 @@ class NetworkClient(
|
|||
start()
|
||||
val stopped = new AtomicBoolean(false)
|
||||
override final def run(): Unit = {
|
||||
@tailrec def read(): Unit = {
|
||||
def read(): Unit = {
|
||||
inputStream.read match {
|
||||
case -1 =>
|
||||
case b =>
|
||||
inLock.synchronized(stdinBytes.offer(b))
|
||||
if (attached.get()) drain()
|
||||
if (!stopped.get()) read()
|
||||
}
|
||||
}
|
||||
try Terminal.console.withRawInput(read())
|
||||
catch { case _: InterruptedException | NonFatal(_) => stopped.set(true) }
|
||||
try read()
|
||||
catch { case _: InterruptedException | NonFatal(_) => stopped.set(true) } finally {
|
||||
inputThread.set(null)
|
||||
}
|
||||
}
|
||||
|
||||
def drain(): Unit = inLock.synchronized {
|
||||
|
|
@ -1095,6 +1120,7 @@ object NetworkClient {
|
|||
System.out.flush()
|
||||
})
|
||||
Runtime.getRuntime.addShutdownHook(hook)
|
||||
if (Util.isNonCygwinWindows) sbt.internal.util.JLine3.forceWindowsJansi()
|
||||
System.exit(Terminal.withStreams(false) {
|
||||
val term = Terminal.console
|
||||
try client(base, restOfArgs, term.inputStream, System.err, term, useJNI)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ import scala.collection.mutable
|
|||
import scala.concurrent.duration._
|
||||
import scala.util.Try
|
||||
import scala.util.control.NonFatal
|
||||
import Serialization.attach
|
||||
import Serialization.{ attach, cancelReadSystemIn, readSystemIn }
|
||||
|
||||
import sjsonnew._
|
||||
import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter }
|
||||
|
|
@ -643,12 +643,19 @@ final class NetworkChannel(
|
|||
|
||||
private[this] lazy val inputStream: InputStream = new InputStream {
|
||||
override def read(): Int = {
|
||||
import sjsonnew.BasicJsonProtocol._
|
||||
try {
|
||||
jsonRpcNotify(readSystemIn, "")
|
||||
inputBuffer.take & 0xFF match {
|
||||
case -1 => throw new ClosedChannelException()
|
||||
case b => b
|
||||
}
|
||||
} catch { case e: IOException => -1 }
|
||||
} catch {
|
||||
case e: IOException =>
|
||||
try jsonRpcNotify(cancelReadSystemIn, "")
|
||||
catch { case _: IOException => }
|
||||
-1
|
||||
}
|
||||
}
|
||||
override def available(): Int = inputBuffer.size
|
||||
}
|
||||
|
|
@ -816,34 +823,19 @@ final class NetworkChannel(
|
|||
Some(result(queue.take))
|
||||
}
|
||||
}
|
||||
override def getBooleanCapability(capability: String, jline3: Boolean): Boolean =
|
||||
override def getBooleanCapability(capability: String): Boolean =
|
||||
getCapability(
|
||||
TerminalCapabilitiesQuery(
|
||||
boolean = Some(capability),
|
||||
numeric = None,
|
||||
string = None,
|
||||
jline3
|
||||
),
|
||||
TerminalCapabilitiesQuery(boolean = Some(capability), numeric = None, string = None),
|
||||
_.boolean.getOrElse(false)
|
||||
).getOrElse(false)
|
||||
override def getNumericCapability(capability: String, jline3: Boolean): Integer =
|
||||
override def getNumericCapability(capability: String): Integer =
|
||||
getCapability(
|
||||
TerminalCapabilitiesQuery(
|
||||
boolean = None,
|
||||
numeric = Some(capability),
|
||||
string = None,
|
||||
jline3
|
||||
),
|
||||
TerminalCapabilitiesQuery(boolean = None, numeric = Some(capability), string = None),
|
||||
(_: TerminalCapabilitiesResponse).numeric.map(Integer.valueOf).getOrElse(-1: Integer)
|
||||
).getOrElse(-1: Integer)
|
||||
override def getStringCapability(capability: String, jline3: Boolean): String =
|
||||
override def getStringCapability(capability: String): String =
|
||||
getCapability(
|
||||
TerminalCapabilitiesQuery(
|
||||
boolean = None,
|
||||
numeric = None,
|
||||
string = Some(capability),
|
||||
jline3
|
||||
),
|
||||
TerminalCapabilitiesQuery(boolean = None, numeric = None, string = Some(capability)),
|
||||
_.string.flatMap {
|
||||
case "null" => None
|
||||
case s => Some(s)
|
||||
|
|
@ -899,6 +891,25 @@ final class NetworkChannel(
|
|||
try queue.take
|
||||
catch { case _: InterruptedException => }
|
||||
}
|
||||
private[this] def setRawMode(toggle: Boolean): Unit = {
|
||||
if (!closed.get || false) {
|
||||
import sbt.protocol.codec.JsonProtocol._
|
||||
val raw = TerminalSetRawModeCommand(toggle)
|
||||
val queue = VirtualTerminal.setTerminalRawMode(name, jsonRpcRequest, raw)
|
||||
try queue.take
|
||||
catch { case _: InterruptedException => }
|
||||
}
|
||||
}
|
||||
override private[sbt] def enterRawMode(): Unit = setRawMode(true)
|
||||
override private[sbt] def exitRawMode(): Unit = setRawMode(false)
|
||||
override def setEchoEnabled(toggle: Boolean): Unit =
|
||||
if (!closed.get) {
|
||||
import sbt.protocol.codec.JsonProtocol._
|
||||
val echo = TerminalSetEchoCommand(toggle)
|
||||
val queue = VirtualTerminal.setTerminalEcho(name, jsonRpcRequest, echo)
|
||||
try queue.take
|
||||
catch { case _: InterruptedException => () }
|
||||
}
|
||||
|
||||
override def flush(): Unit = doFlush()
|
||||
override def toString: String = s"NetworkTerminal($name)"
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@ import sbt.protocol.Serialization.{
|
|||
terminalCapabilities,
|
||||
terminalGetSize,
|
||||
terminalPropertiesQuery,
|
||||
terminalSetEcho,
|
||||
terminalSetSize,
|
||||
terminalSetRawMode,
|
||||
}
|
||||
import sjsonnew.support.scalajson.unsafe.Converter
|
||||
import sbt.protocol.{
|
||||
|
|
@ -35,7 +37,9 @@ import sbt.protocol.{
|
|||
TerminalGetSizeQuery,
|
||||
TerminalGetSizeResponse,
|
||||
TerminalSetAttributesCommand,
|
||||
TerminalSetEchoCommand,
|
||||
TerminalSetSizeCommand,
|
||||
TerminalSetRawModeCommand,
|
||||
}
|
||||
import sbt.protocol.codec.JsonProtocol._
|
||||
import sbt.protocol.TerminalGetSizeResponse
|
||||
|
|
@ -53,6 +57,10 @@ object VirtualTerminal {
|
|||
new ConcurrentHashMap[(String, String), ArrayBlockingQueue[Unit]]
|
||||
private[this] val pendingTerminalGetSize =
|
||||
new ConcurrentHashMap[(String, String), ArrayBlockingQueue[TerminalGetSizeResponse]]
|
||||
private[this] val pendingTerminalSetEcho =
|
||||
new ConcurrentHashMap[(String, String), ArrayBlockingQueue[Unit]]
|
||||
private[this] val pendingTerminalSetRawMode =
|
||||
new ConcurrentHashMap[(String, String), ArrayBlockingQueue[Unit]]
|
||||
private[sbt] def sendTerminalPropertiesQuery(
|
||||
channelName: String,
|
||||
jsonRpcRequest: (String, String, String) => Unit
|
||||
|
|
@ -134,6 +142,30 @@ object VirtualTerminal {
|
|||
queue
|
||||
}
|
||||
|
||||
private[sbt] def setTerminalEcho(
|
||||
channelName: String,
|
||||
jsonRpcRequest: (String, String, TerminalSetEchoCommand) => Unit,
|
||||
query: TerminalSetEchoCommand
|
||||
): ArrayBlockingQueue[Unit] = {
|
||||
val id = UUID.randomUUID.toString
|
||||
val queue = new ArrayBlockingQueue[Unit](1)
|
||||
pendingTerminalSetEcho.put((channelName, id), queue)
|
||||
jsonRpcRequest(id, terminalSetEcho, query)
|
||||
queue
|
||||
}
|
||||
|
||||
private[sbt] def setTerminalRawMode(
|
||||
channelName: String,
|
||||
jsonRpcRequest: (String, String, TerminalSetRawModeCommand) => Unit,
|
||||
query: TerminalSetRawModeCommand
|
||||
): ArrayBlockingQueue[Unit] = {
|
||||
val id = UUID.randomUUID.toString
|
||||
val queue = new ArrayBlockingQueue[Unit](1)
|
||||
pendingTerminalSetEcho.put((channelName, id), queue)
|
||||
jsonRpcRequest(id, terminalSetRawMode, query)
|
||||
queue
|
||||
}
|
||||
|
||||
val handler = ServerHandler { cb =>
|
||||
ServerIntent(requestHandler(cb), responseHandler(cb), notificationHandler(cb))
|
||||
}
|
||||
|
|
@ -193,6 +225,16 @@ object VirtualTerminal {
|
|||
case null =>
|
||||
case buffer => buffer.put(response.getOrElse(TerminalGetSizeResponse(1, 1)))
|
||||
}
|
||||
case r if pendingTerminalSetEcho.get((callback.name, r.id)) != null =>
|
||||
pendingTerminalSetEcho.remove((callback.name, r.id)) match {
|
||||
case null =>
|
||||
case buffer => buffer.put(())
|
||||
}
|
||||
case r if pendingTerminalSetRawMode.get((callback.name, r.id)) != null =>
|
||||
pendingTerminalSetRawMode.remove((callback.name, r.id)) match {
|
||||
case null =>
|
||||
case buffer => buffer.put(())
|
||||
}
|
||||
}
|
||||
private val notificationHandler: Handler[JsonRpcNotificationMessage] =
|
||||
callback => {
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ object Dependencies {
|
|||
val jline3Version = "3.16.0" // Once the base jline version is upgraded, we can use the official jline-terminal
|
||||
val jline3Terminal = "org.scala-sbt.jline3" % "jline-terminal" % s"$jline3Version-sbt-211a082ed6326908dc84ca017ce4430728f18a8a"
|
||||
val jline3Jansi = "org.jline" % "jline-terminal-jansi" % jline3Version
|
||||
val jline3JNA = "org.jline" % "jline-terminal-jna" % jline3Version
|
||||
val jline3Reader = "org.jline" % "jline-reader" % jline3Version
|
||||
val jansi = "org.fusesource.jansi" % "jansi" % "1.18"
|
||||
val scalatest = "org.scalatest" %% "scalatest" % "3.0.8"
|
||||
|
|
|
|||
|
|
@ -7,23 +7,22 @@ package sbt.protocol
|
|||
final class TerminalCapabilitiesQuery private (
|
||||
val boolean: Option[String],
|
||||
val numeric: Option[String],
|
||||
val string: Option[String],
|
||||
val jline3: Boolean) extends sbt.protocol.CommandMessage() with Serializable {
|
||||
val string: Option[String]) extends sbt.protocol.CommandMessage() with Serializable {
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case x: TerminalCapabilitiesQuery => (this.boolean == x.boolean) && (this.numeric == x.numeric) && (this.string == x.string) && (this.jline3 == x.jline3)
|
||||
case x: TerminalCapabilitiesQuery => (this.boolean == x.boolean) && (this.numeric == x.numeric) && (this.string == x.string)
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
37 * (37 * (37 * (37 * (37 * (17 + "sbt.protocol.TerminalCapabilitiesQuery".##) + boolean.##) + numeric.##) + string.##) + jline3.##)
|
||||
37 * (37 * (37 * (37 * (17 + "sbt.protocol.TerminalCapabilitiesQuery".##) + boolean.##) + numeric.##) + string.##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"TerminalCapabilitiesQuery(" + boolean + ", " + numeric + ", " + string + ", " + jline3 + ")"
|
||||
"TerminalCapabilitiesQuery(" + boolean + ", " + numeric + ", " + string + ")"
|
||||
}
|
||||
private[this] def copy(boolean: Option[String] = boolean, numeric: Option[String] = numeric, string: Option[String] = string, jline3: Boolean = jline3): TerminalCapabilitiesQuery = {
|
||||
new TerminalCapabilitiesQuery(boolean, numeric, string, jline3)
|
||||
private[this] def copy(boolean: Option[String] = boolean, numeric: Option[String] = numeric, string: Option[String] = string): TerminalCapabilitiesQuery = {
|
||||
new TerminalCapabilitiesQuery(boolean, numeric, string)
|
||||
}
|
||||
def withBoolean(boolean: Option[String]): TerminalCapabilitiesQuery = {
|
||||
copy(boolean = boolean)
|
||||
|
|
@ -43,12 +42,9 @@ final class TerminalCapabilitiesQuery private (
|
|||
def withString(string: String): TerminalCapabilitiesQuery = {
|
||||
copy(string = Option(string))
|
||||
}
|
||||
def withJline3(jline3: Boolean): TerminalCapabilitiesQuery = {
|
||||
copy(jline3 = jline3)
|
||||
}
|
||||
}
|
||||
object TerminalCapabilitiesQuery {
|
||||
|
||||
def apply(boolean: Option[String], numeric: Option[String], string: Option[String], jline3: Boolean): TerminalCapabilitiesQuery = new TerminalCapabilitiesQuery(boolean, numeric, string, jline3)
|
||||
def apply(boolean: String, numeric: String, string: String, jline3: Boolean): TerminalCapabilitiesQuery = new TerminalCapabilitiesQuery(Option(boolean), Option(numeric), Option(string), jline3)
|
||||
def apply(boolean: Option[String], numeric: Option[String], string: Option[String]): TerminalCapabilitiesQuery = new TerminalCapabilitiesQuery(boolean, numeric, string)
|
||||
def apply(boolean: String, numeric: String, string: String): TerminalCapabilitiesQuery = new TerminalCapabilitiesQuery(Option(boolean), Option(numeric), Option(string))
|
||||
}
|
||||
|
|
|
|||
32
protocol/src/main/contraband-scala/sbt/protocol/TerminalSetEchoCommand.scala
generated
Normal file
32
protocol/src/main/contraband-scala/sbt/protocol/TerminalSetEchoCommand.scala
generated
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol
|
||||
final class TerminalSetEchoCommand private (
|
||||
val toggle: Boolean) extends sbt.protocol.CommandMessage() with Serializable {
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case x: TerminalSetEchoCommand => (this.toggle == x.toggle)
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
37 * (37 * (17 + "sbt.protocol.TerminalSetEchoCommand".##) + toggle.##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"TerminalSetEchoCommand(" + toggle + ")"
|
||||
}
|
||||
private[this] def copy(toggle: Boolean = toggle): TerminalSetEchoCommand = {
|
||||
new TerminalSetEchoCommand(toggle)
|
||||
}
|
||||
def withToggle(toggle: Boolean): TerminalSetEchoCommand = {
|
||||
copy(toggle = toggle)
|
||||
}
|
||||
}
|
||||
object TerminalSetEchoCommand {
|
||||
|
||||
def apply(toggle: Boolean): TerminalSetEchoCommand = new TerminalSetEchoCommand(toggle)
|
||||
}
|
||||
29
protocol/src/main/contraband-scala/sbt/protocol/TerminalSetEchoResponse.scala
generated
Normal file
29
protocol/src/main/contraband-scala/sbt/protocol/TerminalSetEchoResponse.scala
generated
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol
|
||||
final class TerminalSetEchoResponse private () extends sbt.protocol.EventMessage() with Serializable {
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case _: TerminalSetEchoResponse => true
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
37 * (17 + "sbt.protocol.TerminalSetEchoResponse".##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"TerminalSetEchoResponse()"
|
||||
}
|
||||
private[this] def copy(): TerminalSetEchoResponse = {
|
||||
new TerminalSetEchoResponse()
|
||||
}
|
||||
|
||||
}
|
||||
object TerminalSetEchoResponse {
|
||||
|
||||
def apply(): TerminalSetEchoResponse = new TerminalSetEchoResponse()
|
||||
}
|
||||
32
protocol/src/main/contraband-scala/sbt/protocol/TerminalSetRawModeCommand.scala
generated
Normal file
32
protocol/src/main/contraband-scala/sbt/protocol/TerminalSetRawModeCommand.scala
generated
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol
|
||||
final class TerminalSetRawModeCommand private (
|
||||
val toggle: Boolean) extends sbt.protocol.CommandMessage() with Serializable {
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case x: TerminalSetRawModeCommand => (this.toggle == x.toggle)
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
37 * (37 * (17 + "sbt.protocol.TerminalSetRawModeCommand".##) + toggle.##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"TerminalSetRawModeCommand(" + toggle + ")"
|
||||
}
|
||||
private[this] def copy(toggle: Boolean = toggle): TerminalSetRawModeCommand = {
|
||||
new TerminalSetRawModeCommand(toggle)
|
||||
}
|
||||
def withToggle(toggle: Boolean): TerminalSetRawModeCommand = {
|
||||
copy(toggle = toggle)
|
||||
}
|
||||
}
|
||||
object TerminalSetRawModeCommand {
|
||||
|
||||
def apply(toggle: Boolean): TerminalSetRawModeCommand = new TerminalSetRawModeCommand(toggle)
|
||||
}
|
||||
29
protocol/src/main/contraband-scala/sbt/protocol/TerminalSetRawModeReponse.scala
generated
Normal file
29
protocol/src/main/contraband-scala/sbt/protocol/TerminalSetRawModeReponse.scala
generated
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol
|
||||
final class TerminalSetRawModeReponse private () extends sbt.protocol.EventMessage() with Serializable {
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case _: TerminalSetRawModeReponse => true
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
37 * (17 + "sbt.protocol.TerminalSetRawModeReponse".##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"TerminalSetRawModeReponse()"
|
||||
}
|
||||
private[this] def copy(): TerminalSetRawModeReponse = {
|
||||
new TerminalSetRawModeReponse()
|
||||
}
|
||||
|
||||
}
|
||||
object TerminalSetRawModeReponse {
|
||||
|
||||
def apply(): TerminalSetRawModeReponse = new TerminalSetRawModeReponse()
|
||||
}
|
||||
29
protocol/src/main/contraband-scala/sbt/protocol/TerminalSetRawModeResponse.scala
generated
Normal file
29
protocol/src/main/contraband-scala/sbt/protocol/TerminalSetRawModeResponse.scala
generated
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol
|
||||
final class TerminalSetRawModeResponse private () extends sbt.protocol.EventMessage() with Serializable {
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case _: TerminalSetRawModeResponse => true
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
37 * (17 + "sbt.protocol.TerminalSetRawModeResponse".##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"TerminalSetRawModeResponse()"
|
||||
}
|
||||
private[this] def copy(): TerminalSetRawModeResponse = {
|
||||
new TerminalSetRawModeResponse()
|
||||
}
|
||||
|
||||
}
|
||||
object TerminalSetRawModeResponse {
|
||||
|
||||
def apply(): TerminalSetRawModeResponse = new TerminalSetRawModeResponse()
|
||||
}
|
||||
|
|
@ -6,6 +6,6 @@
|
|||
package sbt.protocol.codec
|
||||
|
||||
import _root_.sjsonnew.JsonFormat
|
||||
trait CommandMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.InitCommandFormats with sbt.protocol.codec.ExecCommandFormats with sbt.protocol.codec.SettingQueryFormats with sbt.protocol.codec.AttachFormats with sbt.protocol.codec.TerminalCapabilitiesQueryFormats with sbt.protocol.codec.TerminalSetAttributesCommandFormats with sbt.protocol.codec.TerminalAttributesQueryFormats with sbt.protocol.codec.TerminalGetSizeQueryFormats with sbt.protocol.codec.TerminalSetSizeCommandFormats =>
|
||||
implicit lazy val CommandMessageFormat: JsonFormat[sbt.protocol.CommandMessage] = flatUnionFormat9[sbt.protocol.CommandMessage, sbt.protocol.InitCommand, sbt.protocol.ExecCommand, sbt.protocol.SettingQuery, sbt.protocol.Attach, sbt.protocol.TerminalCapabilitiesQuery, sbt.protocol.TerminalSetAttributesCommand, sbt.protocol.TerminalAttributesQuery, sbt.protocol.TerminalGetSizeQuery, sbt.protocol.TerminalSetSizeCommand]("type")
|
||||
trait CommandMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.InitCommandFormats with sbt.protocol.codec.ExecCommandFormats with sbt.protocol.codec.SettingQueryFormats with sbt.protocol.codec.AttachFormats with sbt.protocol.codec.TerminalCapabilitiesQueryFormats with sbt.protocol.codec.TerminalSetAttributesCommandFormats with sbt.protocol.codec.TerminalAttributesQueryFormats with sbt.protocol.codec.TerminalGetSizeQueryFormats with sbt.protocol.codec.TerminalSetSizeCommandFormats with sbt.protocol.codec.TerminalSetEchoCommandFormats with sbt.protocol.codec.TerminalSetRawModeCommandFormats =>
|
||||
implicit lazy val CommandMessageFormat: JsonFormat[sbt.protocol.CommandMessage] = flatUnionFormat11[sbt.protocol.CommandMessage, sbt.protocol.InitCommand, sbt.protocol.ExecCommand, sbt.protocol.SettingQuery, sbt.protocol.Attach, sbt.protocol.TerminalCapabilitiesQuery, sbt.protocol.TerminalSetAttributesCommand, sbt.protocol.TerminalAttributesQuery, sbt.protocol.TerminalGetSizeQuery, sbt.protocol.TerminalSetSizeCommand, sbt.protocol.TerminalSetEchoCommand, sbt.protocol.TerminalSetRawModeCommand]("type")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@
|
|||
package sbt.protocol.codec
|
||||
|
||||
import _root_.sjsonnew.JsonFormat
|
||||
trait EventMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.ChannelAcceptedEventFormats with sbt.protocol.codec.LogEventFormats with sbt.protocol.codec.ExecStatusEventFormats with sbt.internal.util.codec.JValueFormats with sbt.protocol.codec.SettingQuerySuccessFormats with sbt.protocol.codec.SettingQueryFailureFormats with sbt.protocol.codec.TerminalPropertiesResponseFormats with sbt.protocol.codec.TerminalCapabilitiesResponseFormats with sbt.protocol.codec.TerminalSetAttributesResponseFormats with sbt.protocol.codec.TerminalAttributesResponseFormats with sbt.protocol.codec.TerminalGetSizeResponseFormats with sbt.protocol.codec.TerminalSetSizeResponseFormats =>
|
||||
implicit lazy val EventMessageFormat: JsonFormat[sbt.protocol.EventMessage] = flatUnionFormat11[sbt.protocol.EventMessage, sbt.protocol.ChannelAcceptedEvent, sbt.protocol.LogEvent, sbt.protocol.ExecStatusEvent, sbt.protocol.SettingQuerySuccess, sbt.protocol.SettingQueryFailure, sbt.protocol.TerminalPropertiesResponse, sbt.protocol.TerminalCapabilitiesResponse, sbt.protocol.TerminalSetAttributesResponse, sbt.protocol.TerminalAttributesResponse, sbt.protocol.TerminalGetSizeResponse, sbt.protocol.TerminalSetSizeResponse]("type")
|
||||
trait EventMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.ChannelAcceptedEventFormats with sbt.protocol.codec.LogEventFormats with sbt.protocol.codec.ExecStatusEventFormats with sbt.internal.util.codec.JValueFormats with sbt.protocol.codec.SettingQuerySuccessFormats with sbt.protocol.codec.SettingQueryFailureFormats with sbt.protocol.codec.TerminalPropertiesResponseFormats with sbt.protocol.codec.TerminalCapabilitiesResponseFormats with sbt.protocol.codec.TerminalSetAttributesResponseFormats with sbt.protocol.codec.TerminalAttributesResponseFormats with sbt.protocol.codec.TerminalGetSizeResponseFormats with sbt.protocol.codec.TerminalSetSizeResponseFormats with sbt.protocol.codec.TerminalSetEchoResponseFormats with sbt.protocol.codec.TerminalSetRawModeResponseFormats =>
|
||||
implicit lazy val EventMessageFormat: JsonFormat[sbt.protocol.EventMessage] = flatUnionFormat13[sbt.protocol.EventMessage, sbt.protocol.ChannelAcceptedEvent, sbt.protocol.LogEvent, sbt.protocol.ExecStatusEvent, sbt.protocol.SettingQuerySuccess, sbt.protocol.SettingQueryFailure, sbt.protocol.TerminalPropertiesResponse, sbt.protocol.TerminalCapabilitiesResponse, sbt.protocol.TerminalSetAttributesResponse, sbt.protocol.TerminalAttributesResponse, sbt.protocol.TerminalGetSizeResponse, sbt.protocol.TerminalSetSizeResponse, sbt.protocol.TerminalSetEchoResponse, sbt.protocol.TerminalSetRawModeResponse]("type")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol
|
|||
with sbt.protocol.codec.TerminalAttributesQueryFormats
|
||||
with sbt.protocol.codec.TerminalGetSizeQueryFormats
|
||||
with sbt.protocol.codec.TerminalSetSizeCommandFormats
|
||||
with sbt.protocol.codec.TerminalSetEchoCommandFormats
|
||||
with sbt.protocol.codec.TerminalSetRawModeCommandFormats
|
||||
with sbt.protocol.codec.CommandMessageFormats
|
||||
with sbt.protocol.codec.CompletionParamsFormats
|
||||
with sbt.protocol.codec.ChannelAcceptedEventFormats
|
||||
|
|
@ -28,6 +30,8 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol
|
|||
with sbt.protocol.codec.TerminalAttributesResponseFormats
|
||||
with sbt.protocol.codec.TerminalGetSizeResponseFormats
|
||||
with sbt.protocol.codec.TerminalSetSizeResponseFormats
|
||||
with sbt.protocol.codec.TerminalSetEchoResponseFormats
|
||||
with sbt.protocol.codec.TerminalSetRawModeResponseFormats
|
||||
with sbt.protocol.codec.EventMessageFormats
|
||||
with sbt.protocol.codec.SettingQueryResponseFormats
|
||||
with sbt.protocol.codec.CompletionResponseFormats
|
||||
|
|
|
|||
|
|
@ -14,9 +14,8 @@ implicit lazy val TerminalCapabilitiesQueryFormat: JsonFormat[sbt.protocol.Termi
|
|||
val boolean = unbuilder.readField[Option[String]]("boolean")
|
||||
val numeric = unbuilder.readField[Option[String]]("numeric")
|
||||
val string = unbuilder.readField[Option[String]]("string")
|
||||
val jline3 = unbuilder.readField[Boolean]("jline3")
|
||||
unbuilder.endObject()
|
||||
sbt.protocol.TerminalCapabilitiesQuery(boolean, numeric, string, jline3)
|
||||
sbt.protocol.TerminalCapabilitiesQuery(boolean, numeric, string)
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
|
|
@ -26,7 +25,6 @@ implicit lazy val TerminalCapabilitiesQueryFormat: JsonFormat[sbt.protocol.Termi
|
|||
builder.addField("boolean", obj.boolean)
|
||||
builder.addField("numeric", obj.numeric)
|
||||
builder.addField("string", obj.string)
|
||||
builder.addField("jline3", obj.jline3)
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
27
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalSetEchoCommandFormats.scala
generated
Normal file
27
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalSetEchoCommandFormats.scala
generated
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol.codec
|
||||
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
|
||||
trait TerminalSetEchoCommandFormats { self: sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val TerminalSetEchoCommandFormat: JsonFormat[sbt.protocol.TerminalSetEchoCommand] = new JsonFormat[sbt.protocol.TerminalSetEchoCommand] {
|
||||
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.protocol.TerminalSetEchoCommand = {
|
||||
__jsOpt match {
|
||||
case Some(__js) =>
|
||||
unbuilder.beginObject(__js)
|
||||
val toggle = unbuilder.readField[Boolean]("toggle")
|
||||
unbuilder.endObject()
|
||||
sbt.protocol.TerminalSetEchoCommand(toggle)
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
}
|
||||
override def write[J](obj: sbt.protocol.TerminalSetEchoCommand, builder: Builder[J]): Unit = {
|
||||
builder.beginObject()
|
||||
builder.addField("toggle", obj.toggle)
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
27
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalSetEchoResponseFormats.scala
generated
Normal file
27
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalSetEchoResponseFormats.scala
generated
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol.codec
|
||||
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
|
||||
trait TerminalSetEchoResponseFormats { self: sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val TerminalSetEchoResponseFormat: JsonFormat[sbt.protocol.TerminalSetEchoResponse] = new JsonFormat[sbt.protocol.TerminalSetEchoResponse] {
|
||||
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.protocol.TerminalSetEchoResponse = {
|
||||
__jsOpt match {
|
||||
case Some(__js) =>
|
||||
unbuilder.beginObject(__js)
|
||||
|
||||
unbuilder.endObject()
|
||||
sbt.protocol.TerminalSetEchoResponse()
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
}
|
||||
override def write[J](obj: sbt.protocol.TerminalSetEchoResponse, builder: Builder[J]): Unit = {
|
||||
builder.beginObject()
|
||||
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
27
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalSetRawModeCommandFormats.scala
generated
Normal file
27
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalSetRawModeCommandFormats.scala
generated
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol.codec
|
||||
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
|
||||
trait TerminalSetRawModeCommandFormats { self: sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val TerminalSetRawModeCommandFormat: JsonFormat[sbt.protocol.TerminalSetRawModeCommand] = new JsonFormat[sbt.protocol.TerminalSetRawModeCommand] {
|
||||
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.protocol.TerminalSetRawModeCommand = {
|
||||
__jsOpt match {
|
||||
case Some(__js) =>
|
||||
unbuilder.beginObject(__js)
|
||||
val toggle = unbuilder.readField[Boolean]("toggle")
|
||||
unbuilder.endObject()
|
||||
sbt.protocol.TerminalSetRawModeCommand(toggle)
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
}
|
||||
override def write[J](obj: sbt.protocol.TerminalSetRawModeCommand, builder: Builder[J]): Unit = {
|
||||
builder.beginObject()
|
||||
builder.addField("toggle", obj.toggle)
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
27
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalSetRawModeReponseFormats.scala
generated
Normal file
27
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalSetRawModeReponseFormats.scala
generated
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol.codec
|
||||
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
|
||||
trait TerminalSetRawModeReponseFormats { self: sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val TerminalSetRawModeReponseFormat: JsonFormat[sbt.protocol.TerminalSetRawModeReponse] = new JsonFormat[sbt.protocol.TerminalSetRawModeReponse] {
|
||||
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.protocol.TerminalSetRawModeReponse = {
|
||||
__jsOpt match {
|
||||
case Some(__js) =>
|
||||
unbuilder.beginObject(__js)
|
||||
|
||||
unbuilder.endObject()
|
||||
sbt.protocol.TerminalSetRawModeReponse()
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
}
|
||||
override def write[J](obj: sbt.protocol.TerminalSetRawModeReponse, builder: Builder[J]): Unit = {
|
||||
builder.beginObject()
|
||||
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
27
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalSetRawModeResponseFormats.scala
generated
Normal file
27
protocol/src/main/contraband-scala/sbt/protocol/codec/TerminalSetRawModeResponseFormats.scala
generated
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.protocol.codec
|
||||
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
|
||||
trait TerminalSetRawModeResponseFormats { self: sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val TerminalSetRawModeResponseFormat: JsonFormat[sbt.protocol.TerminalSetRawModeResponse] = new JsonFormat[sbt.protocol.TerminalSetRawModeResponse] {
|
||||
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.protocol.TerminalSetRawModeResponse = {
|
||||
__jsOpt match {
|
||||
case Some(__js) =>
|
||||
unbuilder.beginObject(__js)
|
||||
|
||||
unbuilder.endObject()
|
||||
sbt.protocol.TerminalSetRawModeResponse()
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
}
|
||||
override def write[J](obj: sbt.protocol.TerminalSetRawModeResponse, builder: Builder[J]): Unit = {
|
||||
builder.beginObject()
|
||||
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -97,7 +97,6 @@ type TerminalCapabilitiesQuery implements CommandMessage {
|
|||
boolean: String
|
||||
numeric: String
|
||||
string: String
|
||||
jline3: Boolean!
|
||||
}
|
||||
|
||||
type TerminalCapabilitiesResponse implements EventMessage {
|
||||
|
|
@ -138,3 +137,15 @@ type TerminalSetSizeCommand implements CommandMessage {
|
|||
}
|
||||
|
||||
type TerminalSetSizeResponse implements EventMessage {}
|
||||
|
||||
type TerminalSetEchoCommand implements CommandMessage {
|
||||
toggle: Boolean!
|
||||
}
|
||||
|
||||
type TerminalSetEchoResponse implements EventMessage {}
|
||||
|
||||
type TerminalSetRawModeCommand implements CommandMessage {
|
||||
toggle: Boolean!
|
||||
}
|
||||
|
||||
type TerminalSetRawModeResponse implements EventMessage {}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import sbt.internal.protocol.{
|
|||
|
||||
object Serialization {
|
||||
private[sbt] val VsCode = "application/vscode-jsonrpc; charset=utf-8"
|
||||
val readSystemIn = "sbt/readSystemIn"
|
||||
val cancelReadSystemIn = "sbt/cancelReadSystemIn"
|
||||
val systemIn = "sbt/systemIn"
|
||||
val systemOut = "sbt/systemOut"
|
||||
val systemErr = "sbt/systemErr"
|
||||
|
|
@ -41,6 +43,8 @@ object Serialization {
|
|||
val getTerminalAttributes = "sbt/getTerminalAttributes"
|
||||
val terminalGetSize = "sbt/terminalGetSize"
|
||||
val terminalSetSize = "sbt/terminalSetSize"
|
||||
val terminalSetEcho = "sbt/terminalSetEcho"
|
||||
val terminalSetRawMode = "sbt/terminalSetRawMode"
|
||||
val CancelAll = "__CancelAll"
|
||||
|
||||
@deprecated("unused", since = "1.4.0")
|
||||
|
|
|
|||
Loading…
Reference in New Issue