From 2ef0fcae6abdde72a99b06989f49acc71d5ea620 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sun, 23 Sep 2012 18:14:27 +0200 Subject: [PATCH] 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. --- util/complete/LineReader.scala | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/util/complete/LineReader.scala b/util/complete/LineReader.scala index ecd1eafd9..9f3ca9036 100644 --- a/util/complete/LineReader.scala +++ b/util/complete/LineReader.scala @@ -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