Fix #552 Compensate for JLine's absent EOF detection.

In the unsupported terminal mode, JLine treats a broken
stdin as an endless stream of empty lines. This is problematic
for idea-sbt-plugin: if the IntelliJ process is forcibly killed
and leaves the child SBT process running, it consumes considerable
CPU processing these.

Patching JLine itself would be the cleanest solution (the change
has already been applied to JLine 2), but I've shied away from that
and instead wrapped the InputStream that is read by JLine to
intercept the result of -1 from read(). When this happens, the
flat `inputEof` is set to true.
This commit is contained in:
Jason Zaugg 2012-09-23 18:14:27 +02:00 committed by Mark Harrah
parent c8ffd6a54d
commit efa362c583
1 changed files with 21 additions and 4 deletions

View File

@ -3,14 +3,17 @@
*/ */
package sbt package sbt
import jline.{Completor, ConsoleReader, History} import jline.{ConsoleReader, History}
import java.io.{File,PrintWriter} import java.io.{File, InputStream, PrintWriter}
import complete.Parser import complete.Parser
import java.util.concurrent.atomic.AtomicBoolean
abstract class JLine extends LineReader abstract class JLine extends LineReader
{ {
protected[this] val handleCONT: Boolean protected[this] val handleCONT: Boolean
protected[this] val reader: ConsoleReader 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] 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) }
@ -39,10 +42,14 @@ abstract class JLine extends LineReader
else else
readLineDirectRaw(prompt, mask) readLineDirectRaw(prompt, mask)
private[this] def readLineDirectRaw(prompt: String, mask: Option[Char]): String = private[this] def readLineDirectRaw(prompt: String, mask: Option[Char]): String =
mask match { {
val line = mask match {
case Some(m) => reader.readLine(prompt, m) case Some(m) => reader.readLine(prompt, m)
case None => reader.readLine(prompt) case None => reader.readLine(prompt)
} }
if (inputEof.get) null else line
}
private[this] def resume() private[this] def resume()
{ {
jline.Terminal.resetTerminal jline.Terminal.resetTerminal
@ -109,6 +116,16 @@ final class FullReader(val historyPath: Option[File], complete: Parser[_], val h
protected[this] val reader = protected[this] val reader =
{ {
val cr = new ConsoleReader 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) cr.setBellEnabled(false)
sbt.complete.JLineCompletion.installCustomCompletor(cr, complete) sbt.complete.JLineCompletion.installCustomCompletor(cr, complete)
cr cr