mirror of https://github.com/sbt/sbt.git
Rename Terminal member fields for clarity
Also provide additional source commentary.
This commit is contained in:
parent
4eedaea49e
commit
5238c78dfd
|
|
@ -11,7 +11,7 @@ import java.io.{ InputStream, OutputStream, PrintStream }
|
||||||
import java.nio.channels.ClosedChannelException
|
import java.nio.channels.ClosedChannelException
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
||||||
import java.util.concurrent.{ ArrayBlockingQueue, CountDownLatch, Executors, LinkedBlockingQueue }
|
import java.util.concurrent.{ CountDownLatch, Executors, LinkedBlockingQueue }
|
||||||
|
|
||||||
import jline.DefaultTerminal2
|
import jline.DefaultTerminal2
|
||||||
import jline.console.ConsoleReader
|
import jline.console.ConsoleReader
|
||||||
|
|
@ -48,9 +48,6 @@ trait Terminal extends AutoCloseable {
|
||||||
*/
|
*/
|
||||||
def getLineHeightAndWidth(line: String): (Int, Int)
|
def getLineHeightAndWidth(line: String): (Int, Int)
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* Gets the input stream for this Terminal. This could be a wrapper around System.in for the
|
* Gets the input stream for this Terminal. This could be a wrapper around System.in for the
|
||||||
* process or it could be a remote input stream for a network channel.
|
* process or it could be a remote input stream for a network channel.
|
||||||
|
|
@ -102,15 +99,21 @@ trait Terminal extends AutoCloseable {
|
||||||
*/
|
*/
|
||||||
def isSupershellEnabled: Boolean
|
def isSupershellEnabled: Boolean
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The methods below this comment are implementation details that are in
|
||||||
|
* some cases specific to jline2. These methods may need to change or be
|
||||||
|
* removed if/when sbt upgrades to jline 3.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the last line written to the terminal's output stream.
|
* Returns the last line written to the terminal's output stream.
|
||||||
* @return the last line
|
* @return the last line
|
||||||
*/
|
*/
|
||||||
def getLastLine: Option[String]
|
private[sbt] def getLastLine: Option[String]
|
||||||
|
|
||||||
def getBooleanCapability(capability: String): Boolean
|
private[sbt] def getBooleanCapability(capability: String): Boolean
|
||||||
def getNumericCapability(capability: String): Int
|
private[sbt] def getNumericCapability(capability: String): Int
|
||||||
def getStringCapability(capability: String): String
|
private[sbt] def getStringCapability(capability: String): String
|
||||||
|
|
||||||
private[sbt] def name: String
|
private[sbt] def name: String
|
||||||
private[sbt] def withRawSystemIn[T](f: => T): T = f
|
private[sbt] def withRawSystemIn[T](f: => T): T = f
|
||||||
|
|
@ -151,12 +154,19 @@ object Terminal {
|
||||||
Terminal.console.printStream.println(s"[info] $string")
|
Terminal.console.printStream.println(s"[info] $string")
|
||||||
}
|
}
|
||||||
private[sbt] def set(terminal: Terminal) = {
|
private[sbt] def set(terminal: Terminal) = {
|
||||||
currentTerminal.set(terminal)
|
activeTerminal.set(terminal)
|
||||||
jline.TerminalFactory.set(terminal.toJLine)
|
jline.TerminalFactory.set(terminal.toJLine)
|
||||||
}
|
}
|
||||||
implicit class TerminalOps(private val term: Terminal) extends AnyVal {
|
implicit class TerminalOps(private val term: Terminal) extends AnyVal {
|
||||||
def ansi(richString: => String, string: => String): String =
|
def ansi(richString: => String, string: => String): String =
|
||||||
if (term.isAnsiSupported) richString else string
|
if (term.isAnsiSupported) richString else string
|
||||||
|
/*
|
||||||
|
* Whenever we are dealing with JLine, which is true in sbt's ConsoleReader
|
||||||
|
* as well as in the scala `console` task, we need to provide a jline.Terminal2
|
||||||
|
* instance that can be consumed by the ConsoleReader. The ConsoleTerminal
|
||||||
|
* already wraps a jline terminal, so we can just return the wrapped jline
|
||||||
|
* terminal.
|
||||||
|
*/
|
||||||
private[sbt] def toJLine: jline.Terminal with jline.Terminal2 = term match {
|
private[sbt] def toJLine: jline.Terminal with jline.Terminal2 = term match {
|
||||||
case t: ConsoleTerminal => t.term
|
case t: ConsoleTerminal => t.term
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -189,6 +199,10 @@ object Terminal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Closes the standard input and output streams for the process. This allows
|
||||||
|
* the sbt client to detach from the server it launches.
|
||||||
|
*/
|
||||||
def close(): Unit = {
|
def close(): Unit = {
|
||||||
if (System.console == null) {
|
if (System.console == null) {
|
||||||
originalOut.close()
|
originalOut.close()
|
||||||
|
|
@ -250,7 +264,7 @@ object Terminal {
|
||||||
} else f
|
} else f
|
||||||
|
|
||||||
private[this] object ProxyTerminal extends Terminal {
|
private[this] object ProxyTerminal extends Terminal {
|
||||||
private def t: Terminal = currentTerminal.get
|
private def t: Terminal = activeTerminal.get
|
||||||
override def getWidth: Int = t.getWidth
|
override def getWidth: Int = t.getWidth
|
||||||
override def getHeight: Int = t.getHeight
|
override def getHeight: Int = t.getHeight
|
||||||
override def getLineHeightAndWidth(line: String): (Int, Int) = t.getLineHeightAndWidth(line)
|
override def getLineHeightAndWidth(line: String): (Int, Int) = t.getLineHeightAndWidth(line)
|
||||||
|
|
@ -365,14 +379,28 @@ object Terminal {
|
||||||
|
|
||||||
private[sbt] def withPrintStream[T](f: PrintStream => T): T = console.withPrintStream(f)
|
private[sbt] def withPrintStream[T](f: PrintStream => T): T = console.withPrintStream(f)
|
||||||
private[this] val attached = new AtomicBoolean(true)
|
private[this] val attached = new AtomicBoolean(true)
|
||||||
private[this] val terminalHolder = new AtomicReference(wrap(jline.TerminalFactory.get))
|
|
||||||
private[this] val currentTerminal = new AtomicReference[Terminal](terminalHolder.get)
|
/**
|
||||||
jline.TerminalFactory.set(terminalHolder.get.toJLine)
|
* A wrapped instance of a jline.Terminal2 instance. It should only ever be changed when the
|
||||||
|
* backgrounds sbt with ctrl+z and then foregrounds sbt which causes a call to reset. The
|
||||||
|
* Terminal.console method returns this terminal and the ConsoleChannel delegates its
|
||||||
|
* terminal method to it.
|
||||||
|
*/
|
||||||
|
private[this] val consoleTerminalHolder = new AtomicReference(wrap(jline.TerminalFactory.get))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The terminal that is currently being used by the proxyInputStream and proxyOutputStream.
|
||||||
|
* It is set through the Terminal.set method which is called by the SetTerminal command, which
|
||||||
|
* is used to change the terminal during task evaluation. This allows us to route System.in and
|
||||||
|
* System.out through the terminal's input and output streams.
|
||||||
|
*/
|
||||||
|
private[this] val activeTerminal = new AtomicReference[Terminal](consoleTerminalHolder.get)
|
||||||
|
jline.TerminalFactory.set(consoleTerminalHolder.get.toJLine)
|
||||||
private[this] object proxyInputStream extends InputStream {
|
private[this] object proxyInputStream extends InputStream {
|
||||||
def read(): Int = currentTerminal.get().inputStream.read()
|
def read(): Int = activeTerminal.get().inputStream.read()
|
||||||
}
|
}
|
||||||
private[this] object proxyOutputStream extends OutputStream {
|
private[this] object proxyOutputStream extends OutputStream {
|
||||||
private[this] def os = currentTerminal.get().outputStream
|
private[this] def os = activeTerminal.get().outputStream
|
||||||
def write(byte: Int): Unit = {
|
def write(byte: Int): Unit = {
|
||||||
os.write(byte)
|
os.write(byte)
|
||||||
os.flush()
|
os.flush()
|
||||||
|
|
@ -406,6 +434,16 @@ object Terminal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = {
|
private[this] def wrap(terminal: jline.Terminal): Terminal = {
|
||||||
val term: jline.Terminal with jline.Terminal2 = new jline.Terminal with jline.Terminal2 {
|
val term: jline.Terminal with jline.Terminal2 = new jline.Terminal with jline.Terminal2 {
|
||||||
private[this] val hasConsole = System.console != null
|
private[this] val hasConsole = System.console != null
|
||||||
|
|
@ -449,7 +487,7 @@ object Terminal {
|
||||||
private[sbt] def reset(): Unit = {
|
private[sbt] def reset(): Unit = {
|
||||||
jline.TerminalFactory.reset()
|
jline.TerminalFactory.reset()
|
||||||
console.close()
|
console.close()
|
||||||
terminalHolder.set(wrap(jline.TerminalFactory.get))
|
consoleTerminalHolder.set(wrap(jline.TerminalFactory.get))
|
||||||
}
|
}
|
||||||
|
|
||||||
// translate explicit class names to type in order to support
|
// translate explicit class names to type in order to support
|
||||||
|
|
@ -479,7 +517,7 @@ object Terminal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private[sbt] def console: Terminal = terminalHolder.get match {
|
private[sbt] def console: Terminal = consoleTerminalHolder.get match {
|
||||||
case null => throw new IllegalStateException("Uninitialized terminal.")
|
case null => throw new IllegalStateException("Uninitialized terminal.")
|
||||||
case term => term
|
case term => term
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue