From 447ab5011c01b04af063130ac91338b960bcd4b5 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Wed, 27 Mar 2019 16:51:26 -0700 Subject: [PATCH 1/2] Reduce latency of InputStream polling Calling InputStream.available has low overhead so there is no need to have such a long input latency. --- .../src/main/scala/sbt/internal/util/LineReader.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala index 0e9c0ed41..34153e45d 100644 --- a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala +++ b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala @@ -9,9 +9,11 @@ package sbt.internal.util import jline.console.ConsoleReader import jline.console.history.{ FileHistory, MemoryHistory } -import java.io.{ File, InputStream, FileInputStream, FileDescriptor, FilterInputStream } +import java.io.{ File, FileDescriptor, FileInputStream, FilterInputStream, InputStream } + import complete.Parser -import scala.concurrent.duration.Duration + +import scala.concurrent.duration._ import scala.annotation.tailrec abstract class JLine extends LineReader { @@ -120,7 +122,7 @@ private[sbt] object JLine { protected[this] val originalIn = new FileInputStream(FileDescriptor.in) private[sbt] def makeInputStream(injectThreadSleep: Boolean): InputStream = - if (injectThreadSleep) new InputStreamWrapper(originalIn, Duration("50 ms")) + if (injectThreadSleep) new InputStreamWrapper(originalIn, 2.milliseconds) else originalIn // When calling this, ensure that enableEcho has been or will be called. From 6b82a8d07e3c46debdfb6a038b84bbc731276a2b Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Sat, 23 Mar 2019 11:04:44 -0700 Subject: [PATCH 2/2] Don't use usingTerminal The usingTerminal method synchronizes the JLine object which can lead to deadlock if multiple threads call it. When we just to want to read the attributes of the terminal, but not modify it, there doesn't seem to be any reason to use a lock. --- .../src/main/scala/sbt/internal/util/LineReader.scala | 2 +- main/src/main/scala/sbt/CommandLineUIService.scala | 4 ++-- main/src/main/scala/sbt/internal/SettingGraph.scala | 2 +- main/src/main/scala/sbt/internal/TaskProgress.scala | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala index 34153e45d..ddf48ad34 100644 --- a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala +++ b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala @@ -127,7 +127,7 @@ private[sbt] object JLine { // When calling this, ensure that enableEcho has been or will be called. // TerminalFactory.get will initialize the terminal to disable echo. - private def terminal = jline.TerminalFactory.get + private[sbt] def terminal = jline.TerminalFactory.get private def withTerminal[T](f: jline.Terminal => T): T = synchronized { diff --git a/main/src/main/scala/sbt/CommandLineUIService.scala b/main/src/main/scala/sbt/CommandLineUIService.scala index bf4da75da..e88521268 100644 --- a/main/src/main/scala/sbt/CommandLineUIService.scala +++ b/main/src/main/scala/sbt/CommandLineUIService.scala @@ -27,9 +27,9 @@ trait CommandLineUIService extends InteractionService { } } - override def terminalWidth: Int = JLine.usingTerminal(_.getWidth) + override def terminalWidth: Int = JLine.terminal.getWidth - override def terminalHeight: Int = JLine.usingTerminal(_.getHeight) + override def terminalHeight: Int = JLine.terminal.getHeight } object CommandLineUIService extends CommandLineUIService diff --git a/main/src/main/scala/sbt/internal/SettingGraph.scala b/main/src/main/scala/sbt/internal/SettingGraph.scala index 118c568cc..77e33c097 100644 --- a/main/src/main/scala/sbt/internal/SettingGraph.scala +++ b/main/src/main/scala/sbt/internal/SettingGraph.scala @@ -82,7 +82,7 @@ object Graph { // [info] | // [info] +-quux def toAscii[A](top: A, children: A => Seq[A], display: A => String, defaultWidth: Int): String = { - val maxColumn = math.max(JLine.usingTerminal(_.getWidth), defaultWidth) - 8 + val maxColumn = math.max(JLine.terminal.getWidth, defaultWidth) - 8 val twoSpaces = " " + " " // prevent accidentally being converted into a tab def limitLine(s: String): String = if (s.length > maxColumn) s.slice(0, maxColumn - 2) + ".." diff --git a/main/src/main/scala/sbt/internal/TaskProgress.scala b/main/src/main/scala/sbt/internal/TaskProgress.scala index d73452355..d3120e2dd 100644 --- a/main/src/main/scala/sbt/internal/TaskProgress.scala +++ b/main/src/main/scala/sbt/internal/TaskProgress.scala @@ -25,7 +25,7 @@ private[sbt] final class TaskProgress private[this] val isStopped = new AtomicBoolean(false) override def initial(): Unit = { - ConsoleAppender.setTerminalWidth(JLine.usingTerminal(_.getWidth)) + ConsoleAppender.setTerminalWidth(JLine.terminal.getWidth) } override def afterReady(task: Task[_]): Unit = {