work around unclosed jline history-related streams

This commit is contained in:
Mark Harrah 2012-01-14 21:09:11 -05:00
parent 3191eedf9e
commit 9b5ab3cb09
1 changed files with 40 additions and 25 deletions

View File

@ -3,23 +3,40 @@
*/ */
package sbt package sbt
import jline.{Completor, ConsoleReader} import jline.{Completor, ConsoleReader, History}
import java.io.File import java.io.{File,PrintWriter}
import complete.Parser import complete.Parser
abstract class JLine extends LineReader abstract class JLine extends LineReader
{ {
protected[this] val reader: ConsoleReader protected[this] val reader: ConsoleReader
protected[this] val historyPath: Option[File]
def readLine(prompt: String, mask: Option[Char] = None) = JLine.withJLine { unsynchronizedReadLine(prompt, mask) } def readLine(prompt: String, mask: Option[Char] = None) = JLine.withJLine { unsynchronizedReadLine(prompt, mask) }
private[this] def unsynchronizedReadLine(prompt: String, mask: Option[Char]) = private[this] def unsynchronizedReadLine(prompt: String, mask: Option[Char]) =
(mask match { readLineWithHistory(prompt, mask) match
case Some(m) => reader.readLine(prompt, m)
case None => reader.readLine(prompt)
}) match
{ {
case null => None case null => None
case x => Some(x.trim) case x => Some(x.trim)
} }
private[this] def readLineWithHistory(prompt: String, mask: Option[Char]): String =
historyPath match
{
case None => readLineDirect(prompt, mask)
case Some(file) =>
val h = reader.getHistory
JLine.loadHistory(h, file)
try { readLineDirect(prompt, mask) }
finally { JLine.saveHistory(h, file) }
}
private[this] def readLineDirect(prompt: String, mask: Option[Char]): String =
mask match {
case Some(m) => reader.readLine(prompt, m)
case None => reader.readLine(prompt)
}
} }
private object JLine private object JLine
{ {
@ -44,18 +61,20 @@ private object JLine
try { action } try { action }
finally { t.enableEcho() } finally { t.enableEcho() }
} }
private[sbt] def initializeHistory(cr: ConsoleReader, historyPath: Option[File]): Unit = private[sbt] def loadHistory(h: History, file: File)
for(historyLocation <- historyPath) {
{ h.setMaxSize(MaxHistorySize)
val historyFile = historyLocation.getAbsoluteFile if(file.isFile) IO.reader(file)( h.load )
ErrorHandling.wideConvert }
{ private[sbt] def saveHistory(h: History, file: File): Unit =
historyFile.getParentFile.mkdirs() Using.fileWriter()(file) { writer =>
val history = cr.getHistory val out = new PrintWriter(writer, false)
history.setMaxSize(MaxHistorySize) h.setOutput(out)
history.setHistoryFile(historyFile) h.flushBuffer()
} out.close()
h.setOutput(null)
} }
def simple(historyPath: Option[File]): SimpleReader = new SimpleReader(historyPath) def simple(historyPath: Option[File]): SimpleReader = new SimpleReader(historyPath)
val MaxHistorySize = 500 val MaxHistorySize = 500
} }
@ -64,24 +83,20 @@ trait LineReader
{ {
def readLine(prompt: String, mask: Option[Char] = None): Option[String] def readLine(prompt: String, mask: Option[Char] = None): Option[String]
} }
final class FullReader(historyPath: Option[File], complete: Parser[_]) extends JLine final class FullReader(val historyPath: Option[File], complete: Parser[_]) extends JLine
{ {
protected[this] val reader = protected[this] val reader =
{ {
val cr = new ConsoleReader val cr = new ConsoleReader
cr.setBellEnabled(false) cr.setBellEnabled(false)
JLine.initializeHistory(cr, historyPath)
sbt.complete.JLineCompletion.installCustomCompletor(cr, complete) sbt.complete.JLineCompletion.installCustomCompletor(cr, complete)
cr cr
} }
} }
class SimpleReader private[sbt] (historyPath: Option[File]) extends JLine class SimpleReader private[sbt] (val historyPath: Option[File]) extends JLine
{
protected[this] val reader = JLine.createReader()
JLine.initializeHistory(reader, historyPath)
}
object SimpleReader extends JLine
{ {
protected[this] val reader = JLine.createReader() protected[this] val reader = JLine.createReader()
} }
object SimpleReader extends SimpleReader(None)