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 5500d38367
commit 2ef0fcae6a
1 changed files with 21 additions and 4 deletions

View File

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