mirror of https://github.com/sbt/sbt.git
Switch from JLine 1.0 to 2.10.
This commit is contained in:
parent
1870edfd27
commit
92e99cfef0
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
package xsbt.boot
|
||||
|
||||
import jline.ConsoleReader
|
||||
import jline.console.ConsoleReader
|
||||
abstract class JLine
|
||||
{
|
||||
protected[this] val reader: ConsoleReader
|
||||
|
|
@ -17,12 +17,12 @@ abstract class JLine
|
|||
}
|
||||
private object JLine
|
||||
{
|
||||
def terminal = jline.Terminal.getTerminal
|
||||
def terminal = jline.TerminalFactory.get
|
||||
def createReader() =
|
||||
terminal.synchronized
|
||||
{
|
||||
val cr = new ConsoleReader
|
||||
terminal.enableEcho()
|
||||
terminal.setEchoEnabled(true)
|
||||
cr.setBellEnabled(false)
|
||||
cr
|
||||
}
|
||||
|
|
@ -31,9 +31,9 @@ private object JLine
|
|||
val t = terminal
|
||||
t.synchronized
|
||||
{
|
||||
t.disableEcho()
|
||||
t.setEchoEnabled(false)
|
||||
try { action }
|
||||
finally { t.enableEcho() }
|
||||
finally { t.setEchoEnabled(true) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ object Graph
|
|||
// [info] |
|
||||
// [info] +-quux
|
||||
def toAscii[A](top: A, children: A => Seq[A], display: A => String): String = {
|
||||
val maxColumn = JLine.usingTerminal(_.getTerminalWidth) - 8
|
||||
val maxColumn = JLine.usingTerminal(_.getWidth) - 8
|
||||
val twoSpaces = " " + " " // prevent accidentally being converted into a tab
|
||||
def limitLine(s: String): String =
|
||||
if (s.length > maxColumn) s.slice(0, maxColumn - 2) + ".."
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ object %s {
|
|||
object Common
|
||||
{
|
||||
def lib(m: ModuleID) = libraryDependencies += m
|
||||
lazy val jlineDep = "jline" % "jline" % "1.0" intransitive()
|
||||
lazy val jlineDep = "jline" % "jline" % "2.10" intransitive()
|
||||
lazy val jline = lib(jlineDep)
|
||||
lazy val ivy = lib("org.apache.ivy" % "ivy" % "2.3.0-rc1")
|
||||
lazy val httpclient = lib("commons-httpclient" % "commons-httpclient" % "3.1")
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
*/
|
||||
package sbt
|
||||
|
||||
import jline.{ConsoleReader, History}
|
||||
import jline.console.ConsoleReader
|
||||
import jline.console.history.{FileHistory, MemoryHistory}
|
||||
import java.io.{File, InputStream, PrintWriter}
|
||||
import complete.Parser
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
|
@ -12,9 +13,6 @@ abstract class JLine extends LineReader
|
|||
{
|
||||
protected[this] val handleCONT: Boolean
|
||||
protected[this] val reader: ConsoleReader
|
||||
/** Is the input stream at EOF? Compensates for absent EOF detection in JLine's UnsupportedTerminal. */
|
||||
protected[this] val inputEof = new AtomicBoolean(false)
|
||||
protected[this] val historyPath: Option[File]
|
||||
|
||||
def readLine(prompt: String, mask: Option[Char] = None) = JLine.withJLine { unsynchronizedReadLine(prompt, mask) }
|
||||
|
||||
|
|
@ -26,14 +24,12 @@ abstract class JLine extends LineReader
|
|||
}
|
||||
|
||||
private[this] def readLineWithHistory(prompt: String, mask: Option[Char]): String =
|
||||
historyPath match
|
||||
reader.getHistory match
|
||||
{
|
||||
case None => readLineDirect(prompt, mask)
|
||||
case Some(file) =>
|
||||
val h = reader.getHistory
|
||||
JLine.loadHistory(h, file)
|
||||
case fh: FileHistory =>
|
||||
try { readLineDirect(prompt, mask) }
|
||||
finally { JLine.saveHistory(h, file) }
|
||||
finally { fh.flush() }
|
||||
case _ => readLineDirect(prompt, mask)
|
||||
}
|
||||
|
||||
private[this] def readLineDirect(prompt: String, mask: Option[Char]): String =
|
||||
|
|
@ -44,34 +40,33 @@ abstract class JLine extends LineReader
|
|||
private[this] def readLineDirectRaw(prompt: String, mask: Option[Char]): String =
|
||||
{
|
||||
val newprompt = handleMultilinePrompt(prompt)
|
||||
val line = mask match {
|
||||
mask match {
|
||||
case Some(m) => reader.readLine(newprompt, m)
|
||||
case None => reader.readLine(newprompt)
|
||||
}
|
||||
if (inputEof.get) null else line
|
||||
}
|
||||
|
||||
private[this] def handleMultilinePrompt(prompt: String): String = {
|
||||
val lines = """\r?\n""".r.split(prompt)
|
||||
lines.size match {
|
||||
case 0 | 1 => prompt
|
||||
case _ => reader.printString(lines.init.mkString("\n") + "\n"); lines.last;
|
||||
case _ => reader.print(lines.init.mkString("\n") + "\n"); lines.last;
|
||||
}
|
||||
}
|
||||
|
||||
private[this] def resume()
|
||||
{
|
||||
jline.Terminal.resetTerminal
|
||||
JLine.terminal.disableEcho()
|
||||
jline.TerminalFactory.reset
|
||||
JLine.terminal.setEchoEnabled(false)
|
||||
reader.drawLine()
|
||||
reader.flushConsole()
|
||||
reader.flush()
|
||||
}
|
||||
}
|
||||
private object JLine
|
||||
{
|
||||
// When calling this, ensure that enableEcho has been or will be called.
|
||||
// getTerminal will initialize the terminal to disable echo.
|
||||
private def terminal = jline.Terminal.getTerminal
|
||||
// TerminalFactory.get will initialize the terminal to disable echo.
|
||||
private def terminal = jline.TerminalFactory.get
|
||||
private def withTerminal[T](f: jline.Terminal => T): T =
|
||||
synchronized
|
||||
{
|
||||
|
|
@ -82,33 +77,26 @@ private object JLine
|
|||
* This ensures synchronized access as well as re-enabling echo after getting the Terminal. */
|
||||
def usingTerminal[T](f: jline.Terminal => T): T =
|
||||
withTerminal { t =>
|
||||
t.enableEcho()
|
||||
t.setEchoEnabled(true)
|
||||
f(t)
|
||||
}
|
||||
def createReader() =
|
||||
def createReader(historyPath: Option[File]) =
|
||||
usingTerminal { t =>
|
||||
val cr = new ConsoleReader
|
||||
cr.setBellEnabled(false)
|
||||
val h = historyPath match {
|
||||
case None => new MemoryHistory
|
||||
case Some(file) => new FileHistory(file)
|
||||
}
|
||||
h.setMaxSize(MaxHistorySize)
|
||||
cr.setHistory(h)
|
||||
cr
|
||||
}
|
||||
def withJLine[T](action: => T): T =
|
||||
withTerminal { t =>
|
||||
t.disableEcho()
|
||||
t.setEchoEnabled(false)
|
||||
try { action }
|
||||
finally { t.enableEcho() }
|
||||
}
|
||||
private[sbt] def loadHistory(h: History, file: File)
|
||||
{
|
||||
h.setMaxSize(MaxHistorySize)
|
||||
if(file.isFile) IO.reader(file)( h.load )
|
||||
}
|
||||
private[sbt] def saveHistory(h: History, file: File): Unit =
|
||||
Using.fileWriter()(file) { writer =>
|
||||
val out = new PrintWriter(writer, false)
|
||||
h.setOutput(out)
|
||||
h.flushBuffer()
|
||||
out.close()
|
||||
h.setOutput(null)
|
||||
finally { t.setEchoEnabled(true) }
|
||||
}
|
||||
|
||||
def simple(historyPath: Option[File], handleCONT: Boolean = HandleCONT): SimpleReader = new SimpleReader(historyPath, handleCONT)
|
||||
|
|
@ -120,30 +108,19 @@ trait LineReader
|
|||
{
|
||||
def readLine(prompt: String, mask: Option[Char] = None): Option[String]
|
||||
}
|
||||
final class FullReader(val historyPath: Option[File], complete: Parser[_], val handleCONT: Boolean = JLine.HandleCONT) extends JLine
|
||||
final class FullReader(historyPath: Option[File], complete: Parser[_], val handleCONT: Boolean = JLine.HandleCONT) extends JLine
|
||||
{
|
||||
protected[this] val reader =
|
||||
{
|
||||
val cr = new ConsoleReader
|
||||
if (!cr.getTerminal.isSupported) {
|
||||
val input = cr.getInput
|
||||
cr.setInput(new InputStream {
|
||||
def read(): Int = {
|
||||
val c = input.read()
|
||||
if (c == -1) inputEof.set(true)
|
||||
c
|
||||
}
|
||||
})
|
||||
}
|
||||
cr.setBellEnabled(false)
|
||||
val cr = JLine.createReader(historyPath)
|
||||
sbt.complete.JLineCompletion.installCustomCompletor(cr, complete)
|
||||
cr
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleReader private[sbt] (val historyPath: Option[File], val handleCONT: Boolean) extends JLine
|
||||
class SimpleReader private[sbt] (historyPath: Option[File], val handleCONT: Boolean) extends JLine
|
||||
{
|
||||
protected[this] val reader = JLine.createReader()
|
||||
protected[this] val reader = JLine.createReader(historyPath)
|
||||
}
|
||||
object SimpleReader extends SimpleReader(None, JLine.HandleCONT)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
*/
|
||||
package sbt.complete
|
||||
|
||||
import jline.{CandidateListCompletionHandler,Completor,CompletionHandler,ConsoleReader}
|
||||
import jline.console.ConsoleReader
|
||||
import jline.console.completer.{CandidateListCompletionHandler,Completer,CompletionHandler}
|
||||
import scala.annotation.tailrec
|
||||
import collection.JavaConversions
|
||||
|
||||
|
|
@ -15,8 +16,8 @@ object JLineCompletion
|
|||
installCustomCompletor(customCompletor(complete), reader)
|
||||
def installCustomCompletor(complete: (ConsoleReader, Int) => Boolean, reader: ConsoleReader): Unit =
|
||||
{
|
||||
reader.removeCompletor(DummyCompletor)
|
||||
reader.addCompletor(DummyCompletor)
|
||||
reader.removeCompleter(DummyCompletor)
|
||||
reader.addCompleter(DummyCompletor)
|
||||
reader.setCompletionHandler(new CustomHandler(complete))
|
||||
}
|
||||
|
||||
|
|
@ -24,13 +25,13 @@ object JLineCompletion
|
|||
{
|
||||
private[this] var previous: Option[(String,Int)] = None
|
||||
private[this] var level: Int = 1
|
||||
override def complete(reader: ConsoleReader, candidates: java.util.List[_], position: Int) = {
|
||||
override def complete(reader: ConsoleReader, candidates: java.util.List[CharSequence], position: Int) = {
|
||||
val current = Some(bufferSnapshot(reader))
|
||||
level = if(current == previous) level + 1 else 1
|
||||
previous = current
|
||||
try completeImpl(reader, level)
|
||||
catch { case e: Exception =>
|
||||
reader.printString("\nException occurred while determining completions.")
|
||||
reader.print("\nException occurred while determining completions.")
|
||||
e.printStackTrace()
|
||||
false
|
||||
}
|
||||
|
|
@ -40,9 +41,9 @@ object JLineCompletion
|
|||
// always provides dummy completions so that the custom completion handler gets called
|
||||
// (ConsoleReader doesn't call the handler if there aren't any completions)
|
||||
// the custom handler will then throw away the candidates and call the custom function
|
||||
private[this] final object DummyCompletor extends Completor
|
||||
private[this] final object DummyCompletor extends Completer
|
||||
{
|
||||
override def complete(buffer: String, cursor: Int, candidates: java.util.List[_]): Int =
|
||||
override def complete(buffer: String, cursor: Int, candidates: java.util.List[CharSequence]): Int =
|
||||
{
|
||||
candidates.asInstanceOf[java.util.List[String]] add "dummy"
|
||||
0
|
||||
|
|
@ -73,19 +74,19 @@ object JLineCompletion
|
|||
def customCompletor(f: (String, Int) => (Seq[String], Seq[String])): (ConsoleReader, Int) => Boolean =
|
||||
(reader, level) => {
|
||||
val success = complete(beforeCursor(reader), reader => f(reader, level), reader)
|
||||
reader.flushConsole()
|
||||
reader.flush()
|
||||
success
|
||||
}
|
||||
|
||||
def bufferSnapshot(reader: ConsoleReader): (String, Int) =
|
||||
{
|
||||
val b = reader.getCursorBuffer
|
||||
(b.getBuffer.toString, b.cursor)
|
||||
(b.buffer.toString, b.cursor)
|
||||
}
|
||||
def beforeCursor(reader: ConsoleReader): String =
|
||||
{
|
||||
val b = reader.getCursorBuffer
|
||||
b.getBuffer.substring(0, b.cursor)
|
||||
b.buffer.substring(0, b.cursor)
|
||||
}
|
||||
|
||||
// returns false if there was nothing to insert and nothing to display
|
||||
|
|
@ -120,16 +121,16 @@ object JLineCompletion
|
|||
def printCompletions(cs: Seq[String], reader: ConsoleReader)
|
||||
{
|
||||
val print = shouldPrint(cs, reader)
|
||||
reader.printNewline()
|
||||
reader.println()
|
||||
if(print) printLinesAndColumns(cs, reader)
|
||||
}
|
||||
def printLinesAndColumns(cs: Seq[String], reader: ConsoleReader)
|
||||
{
|
||||
val (lines, columns) = cs partition hasNewline
|
||||
for(line <- lines) {
|
||||
reader.printString(line)
|
||||
reader.print(line)
|
||||
if(line.charAt(line.length - 1) != '\n')
|
||||
reader.printNewline()
|
||||
reader.println()
|
||||
}
|
||||
reader.printColumns(JavaConversions.seqAsJavaList(columns.map(_.trim)))
|
||||
}
|
||||
|
|
@ -137,15 +138,15 @@ object JLineCompletion
|
|||
def shouldPrint(cs: Seq[String], reader: ConsoleReader): Boolean =
|
||||
{
|
||||
val size = cs.size
|
||||
(size <= reader.getAutoprintThreshhold) ||
|
||||
(size <= reader.getAutoprintThreshold) ||
|
||||
confirm("Display all %d possibilities? (y or n) ".format(size), 'y', 'n', reader)
|
||||
}
|
||||
def confirm(prompt: String, trueC: Char, falseC: Char, reader: ConsoleReader): Boolean =
|
||||
{
|
||||
reader.printNewline()
|
||||
reader.printString(prompt)
|
||||
reader.flushConsole()
|
||||
reader.readCharacter( Array(trueC, falseC) ) == trueC
|
||||
reader.println()
|
||||
reader.print(prompt)
|
||||
reader.flush()
|
||||
reader.readCharacter(trueC, falseC) == trueC
|
||||
}
|
||||
|
||||
def commonPrefix(s: Seq[String]): String = if(s.isEmpty) "" else s reduceLeft commonPrefix
|
||||
|
|
|
|||
|
|
@ -81,9 +81,9 @@ object ConsoleLogger
|
|||
|
||||
private[this] def ansiSupported =
|
||||
try {
|
||||
val terminal = jline.Terminal.getTerminal
|
||||
terminal.enableEcho() // #460
|
||||
terminal.isANSISupported
|
||||
val terminal = jline.TerminalFactory.get
|
||||
terminal.setEchoEnabled(true) // #460
|
||||
terminal.isAnsiSupported
|
||||
} catch {
|
||||
case e: Exception => !isWindows
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue