Move JLine apis into LineReader

It is better that sbt not expose the implementation detail that
LineReader is implemented by JLine. Other terminal related apis should
be handled by sbt.internal.util.Terminal.
This commit is contained in:
Ethan Atkins 2019-12-12 18:50:53 -08:00
parent 9218d3c087
commit a449b1ff2d
4 changed files with 55 additions and 18 deletions

View File

@ -16,6 +16,36 @@ import sbt.internal.util.complete.Parser
import scala.annotation.tailrec
import scala.concurrent.duration._
trait LineReader {
def readLine(prompt: String, mask: Option[Char] = None): Option[String]
def redraw(): Unit = ()
}
object LineReader {
val HandleCONT =
!java.lang.Boolean.getBoolean("sbt.disable.cont") && Signals.supported(Signals.CONT)
val MaxHistorySize = 500
def createReader(historyPath: Option[File], in: InputStream): ConsoleReader = {
val cr = Terminal.createReader(in)
cr.setExpandEvents(false) // https://issues.scala-lang.org/browse/SI-7650
cr.setBellEnabled(false)
val h = historyPath match {
case None => new MemoryHistory
case Some(file) => new FileHistory(file): MemoryHistory
}
h.setMaxSize(MaxHistorySize)
cr.setHistory(h)
cr
}
def simple(
historyPath: Option[File],
handleCONT: Boolean = HandleCONT,
injectThreadSleep: Boolean = false
): LineReader = new SimpleReader(historyPath, handleCONT, injectThreadSleep)
}
abstract class JLine extends LineReader {
protected[this] def handleCONT: Boolean
protected[this] def reader: ConsoleReader
@ -92,6 +122,7 @@ abstract class JLine extends LineReader {
}
}
@deprecated("Use LineReader apis", "1.4.0")
private[sbt] object JLine {
@deprecated("For binary compatibility only", "1.4.0")
protected[this] val originalIn = new FileInputStream(FileDescriptor.in)
@ -117,8 +148,10 @@ private[sbt] object JLine {
def usingTerminal[T](f: jline.Terminal => T): T =
Terminal.withCanonicalIn(f(Terminal.deprecatedTeminal))
@deprecated("unused", "1.4.0")
def createReader(): ConsoleReader = createReader(None, Terminal.wrappedSystemIn)
@deprecated("Use LineReader.createReader", "1.4.0")
def createReader(historyPath: Option[File], in: InputStream): ConsoleReader = {
val cr = Terminal.createReader(in)
cr.setExpandEvents(false) // https://issues.scala-lang.org/browse/SI-7650
@ -135,16 +168,18 @@ private[sbt] object JLine {
@deprecated("Avoid referencing JLine directly. Use Terminal.withRawSystemIn instead.", "1.4.0")
def withJLine[T](action: => T): T = Terminal.withRawSystemIn(action)
@deprecated("Use LineReader.simple instead", "1.4.0")
def simple(
historyPath: Option[File],
handleCONT: Boolean = HandleCONT,
handleCONT: Boolean = LineReader.HandleCONT,
injectThreadSleep: Boolean = false
): SimpleReader = new SimpleReader(historyPath, handleCONT, injectThreadSleep)
val MaxHistorySize = 500
@deprecated("Use LineReader.MaxHistorySize", "1.4.0")
val MaxHistorySize = LineReader.MaxHistorySize
val HandleCONT =
!java.lang.Boolean.getBoolean("sbt.disable.cont") && Signals.supported(Signals.CONT)
@deprecated("Use LineReader.HandleCONT", "1.4.0")
val HandleCONT = LineReader.HandleCONT
}
@deprecated("For binary compatibility only", "1.4.0")
@ -172,11 +207,6 @@ private[sbt] class InputStreamWrapper(is: InputStream, val poll: Duration)
}
}
trait LineReader {
def readLine(prompt: String, mask: Option[Char] = None): Option[String]
def redraw(): Unit = ()
}
final class FullReader(
historyPath: Option[File],
complete: Parser[_],
@ -187,11 +217,11 @@ final class FullReader(
def this(
historyPath: Option[File],
complete: Parser[_],
handleCONT: Boolean = JLine.HandleCONT,
handleCONT: Boolean = LineReader.HandleCONT,
injectThreadSleep: Boolean = false
) = this(historyPath, complete, handleCONT, JLine.makeInputStream(injectThreadSleep))
protected[this] val reader: ConsoleReader = {
val cr = JLine.createReader(historyPath, inputStream)
val cr = LineReader.createReader(historyPath, inputStream)
sbt.internal.util.complete.JLineCompletion.installCustomCompletor(cr, complete)
cr
}
@ -205,7 +235,7 @@ class SimpleReader private[sbt] (
def this(historyPath: Option[File], handleCONT: Boolean, injectThreadSleep: Boolean) =
this(historyPath, handleCONT, Terminal.wrappedSystemIn)
protected[this] val reader: ConsoleReader =
JLine.createReader(historyPath, inputStream)
LineReader.createReader(historyPath, inputStream)
}
object SimpleReader extends SimpleReader(None, JLine.HandleCONT, false)
object SimpleReader extends SimpleReader(None, LineReader.HandleCONT, false)

View File

@ -9,7 +9,7 @@ package sbt
import java.nio.file.Paths
import sbt.util.Level
import sbt.internal.util.{ AttributeKey, FullReader, JLine, Terminal }
import sbt.internal.util.{ AttributeKey, FullReader, LineReader, Terminal }
import sbt.internal.util.complete.{
Completion,
Completions,
@ -34,7 +34,9 @@ import BasicKeys._
import java.io.File
import sbt.io.IO
import sbt.util.Level
import scala.Function.tupled
import scala.collection.mutable.ListBuffer
import scala.util.control.NonFatal
@ -374,7 +376,7 @@ object BasicCommands {
val history = (s get historyPath) getOrElse (new File(s.baseDir, ".history")).some
val prompt = (s get shellPrompt) match { case Some(pf) => pf(s); case None => "> " }
val reader =
new FullReader(history, s.combinedParser, JLine.HandleCONT, Terminal.wrappedSystemIn)
new FullReader(history, s.combinedParser, LineReader.HandleCONT, Terminal.wrappedSystemIn)
val line = reader.readLine(prompt)
line match {
case Some(line) =>

View File

@ -29,7 +29,12 @@ private[sbt] final class ConsoleChannel(val name: String) extends CommandChannel
private val history = s.get(historyPath).getOrElse(Some(new File(s.baseDir, ".history")))
private val prompt = getPrompt(s)
private val reader =
new FullReader(history, s.combinedParser, JLine.HandleCONT, Terminal.throwOnClosedSystemIn)
new FullReader(
history,
s.combinedParser,
LineReader.HandleCONT,
Terminal.throwOnClosedSystemIn
)
setDaemon(true)
start()
override def run(): Unit =

View File

@ -15,7 +15,7 @@ import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
import sbt.internal.langserver.{ LogMessageParams, MessageType, PublishDiagnosticsParams }
import sbt.internal.protocol._
import sbt.internal.util.{ ConsoleAppender, JLine }
import sbt.internal.util.{ ConsoleAppender, LineReader }
import sbt.io.IO
import sbt.io.syntax._
import sbt.protocol._
@ -216,7 +216,7 @@ class NetworkClient(configuration: xsbti.AppConfiguration, arguments: List[Strin
}
def shell(): Unit = {
val reader = JLine.simple(None, JLine.HandleCONT, injectThreadSleep = true)
val reader = LineReader.simple(None, LineReader.HandleCONT, injectThreadSleep = true)
while (running.get) {
reader.readLine("> ", None) match {
case Some("shutdown") =>