mirror of https://github.com/sbt/sbt.git
Merge pull request #4454 from eed3si9n/wip/prompt-fix
Fix prompt for task progress
This commit is contained in:
commit
34ef5ab500
|
|
@ -216,7 +216,7 @@ val completeProj = (project in file("internal") / "util-complete")
|
|||
exclude[DirectMissingMethodProblem]("sbt.internal.util.complete.History.this"),
|
||||
),
|
||||
)
|
||||
.configure(addSbtIO, addSbtUtilControl)
|
||||
.configure(addSbtIO, addSbtUtilControl, addSbtUtilLogging)
|
||||
|
||||
// A logic with restricted negation as failure for a unique, stable model
|
||||
val logicProj = (project in file("internal") / "util-logic")
|
||||
|
|
|
|||
|
|
@ -55,25 +55,40 @@ abstract class JLine extends LineReader {
|
|||
else
|
||||
readLineDirectRaw(prompt, mask)
|
||||
|
||||
private[this] val console = ConsoleOut.systemOut
|
||||
private[this] def readLineDirectRaw(prompt: String, mask: Option[Char]): Option[String] = {
|
||||
val newprompt = handleMultilinePrompt(prompt)
|
||||
mask match {
|
||||
val result = mask match {
|
||||
case Some(m) => Option(reader.readLine(newprompt, m))
|
||||
case None => Option(reader.readLine(newprompt))
|
||||
}
|
||||
|
||||
// since the task progress scrolls the logs upward, and expects the cursors to be on
|
||||
// the last text line, this moves the cursor up to complensate for user hitting return.
|
||||
val CursorUp1 = s"\u001B[A"
|
||||
if (ConsoleAppender.showProgress) console.print(CursorUp1)
|
||||
else ()
|
||||
result
|
||||
}
|
||||
|
||||
private[this] def handleMultilinePrompt(prompt: String): String = {
|
||||
val lines = """\r?\n""".r.split(prompt)
|
||||
lines.length match {
|
||||
case 0 | 1 => prompt
|
||||
case _ =>
|
||||
val lines0 = """\r?\n""".r.split(prompt)
|
||||
lines0.length match {
|
||||
case 0 | 1 => handleProgress(prompt)
|
||||
case _ =>
|
||||
val lines = lines0.toList map handleProgress
|
||||
// Workaround for regression jline/jline2#205
|
||||
reader.getOutput.write(lines.init.mkString("\n") + "\n")
|
||||
lines.last
|
||||
}
|
||||
}
|
||||
|
||||
private[this] def handleProgress(prompt: String): String = {
|
||||
import ConsoleAppender._
|
||||
if (showProgress) s"$ScrollUp$DeleteLine" + prompt
|
||||
else prompt
|
||||
}
|
||||
|
||||
private[this] def resume(): Unit = {
|
||||
jline.TerminalFactory.reset
|
||||
JLine.terminal.init
|
||||
|
|
|
|||
|
|
@ -77,8 +77,6 @@ object Aggregation {
|
|||
if (show.taskValues) printSettings(r, show.print)
|
||||
}
|
||||
if (show.success) printSuccess(start, stop, extracted, success, log)
|
||||
// wait for async logger to catch up
|
||||
Thread.sleep(100)
|
||||
}
|
||||
|
||||
def timedRun[T](
|
||||
|
|
@ -131,9 +129,9 @@ object Aggregation {
|
|||
if (get(showSuccess)) {
|
||||
if (get(showTiming)) {
|
||||
val msg = timingString(start, stop, structure.data, currentRef)
|
||||
if (success) log.success(msg + "\n") else log.error(msg + "\n")
|
||||
if (success) log.success(msg) else log.error(msg)
|
||||
} else if (success)
|
||||
log.success("" + "\n")
|
||||
log.success("")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ package internal
|
|||
import sbt.internal.util.{ RMap, ConsoleOut }
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import scala.concurrent.{ blocking, Future, ExecutionContext }
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger }
|
||||
import scala.collection.JavaConverters._
|
||||
import scala.collection.concurrent.TrieMap
|
||||
import TaskProgress._
|
||||
|
|
@ -29,6 +29,7 @@ private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecutePro
|
|||
private[this] val calledBy = new ConcurrentHashMap[Task[_], Task[_]]
|
||||
private[this] val anonOwners = new ConcurrentHashMap[Task[_], Task[_]]
|
||||
private[this] val isReady = new AtomicBoolean(false)
|
||||
private[this] val lastTaskCount = new AtomicInteger(0)
|
||||
private[this] val isAllCompleted = new AtomicBoolean(false)
|
||||
|
||||
override def initial: Unit = ()
|
||||
|
|
@ -55,8 +56,9 @@ private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecutePro
|
|||
}
|
||||
|
||||
override def workFinished[A](task: Task[A], result: Either[Task[A], Result[A]]): Unit = {
|
||||
val start = activeTasks.get(task)
|
||||
timings.put(task, System.nanoTime - start)
|
||||
activeTasks.remove(task)
|
||||
timings.put(task, System.nanoTime - activeTasks.get(task))
|
||||
// we need this to infer anonymous task names
|
||||
result.left.foreach { t =>
|
||||
calledBy.put(t, task)
|
||||
|
|
@ -64,9 +66,6 @@ private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecutePro
|
|||
}
|
||||
|
||||
override def completed[A](state: Unit, task: Task[A], result: Result[A]): Unit = ()
|
||||
override def allCompleted(state: Unit, results: RMap[Task, Result]): Unit = {
|
||||
isAllCompleted.set(true)
|
||||
}
|
||||
|
||||
import ExecutionContext.Implicits._
|
||||
Future {
|
||||
|
|
@ -75,7 +74,6 @@ private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecutePro
|
|||
Thread.sleep(500)
|
||||
}
|
||||
}
|
||||
readyLog()
|
||||
while (!isAllCompleted.get) {
|
||||
blocking {
|
||||
report()
|
||||
|
|
@ -85,34 +83,65 @@ private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecutePro
|
|||
}
|
||||
|
||||
private[this] val console = ConsoleOut.systemOut
|
||||
private[this] def readyLog(): Unit = {
|
||||
console.println("")
|
||||
console.println("")
|
||||
console.println("")
|
||||
console.println("")
|
||||
console.println("")
|
||||
console.println("")
|
||||
console.print(CursorUp5)
|
||||
override def allCompleted(state: Unit, results: RMap[Task, Result]): Unit = {
|
||||
isAllCompleted.set(true)
|
||||
// completionReport()
|
||||
}
|
||||
|
||||
private[this] val stopReportTask =
|
||||
private[this] val skipReportTasks =
|
||||
Set("run", "bgRun", "fgRun", "scala", "console", "consoleProject")
|
||||
private[this] def report(): Unit = console.lockObject.synchronized {
|
||||
val currentTasks = activeTasks.asScala.toList
|
||||
def report0: Unit = {
|
||||
val ltc = lastTaskCount.get
|
||||
val currentTasksCount = currentTasks.size
|
||||
def report0(): Unit = {
|
||||
console.print(s"$CursorDown1")
|
||||
currentTasks foreach {
|
||||
case (task, start) =>
|
||||
val elapsed = (System.nanoTime - start) / 1000000000L
|
||||
console.println(s"$DeleteLine | => ${taskName(task)} ${elapsed}s")
|
||||
}
|
||||
console.print(cursorUp(currentTasks.size + 1))
|
||||
if (ltc > currentTasksCount) deleteConsoleLines(ltc - currentTasksCount)
|
||||
else ()
|
||||
console.print(cursorUp(math.max(currentTasksCount, ltc) + 1))
|
||||
}
|
||||
val isStop = currentTasks
|
||||
if (containsSkipTasks(currentTasks)) ()
|
||||
else report0()
|
||||
lastTaskCount.set(currentTasksCount)
|
||||
}
|
||||
|
||||
// todo: use logger instead of console
|
||||
// private[this] def completionReport(): Unit = console.lockObject.synchronized {
|
||||
// val completedTasks = timings.asScala.toList
|
||||
// val notableTasks = completedTasks
|
||||
// .filter({
|
||||
// case (_, time: Long) => time >= 1000000000L * 10L
|
||||
// })
|
||||
// .sortBy({
|
||||
// case (_, time: Long) => -time
|
||||
// })
|
||||
// .take(5)
|
||||
// def report0(): Unit = {
|
||||
// console.print(s"$CursorDown1")
|
||||
// console.println(s"$DeleteLine notable completed tasks:")
|
||||
// notableTasks foreach {
|
||||
// case (task, time) =>
|
||||
// val elapsed = time / 1000000000L
|
||||
// console.println(s"$DeleteLine | => ${taskName(task)} ${elapsed}s")
|
||||
// }
|
||||
// }
|
||||
// if (containsSkipTasks(notableTasks) || notableTasks.isEmpty) ()
|
||||
// else report0()
|
||||
// }
|
||||
|
||||
private[this] def containsSkipTasks(tasks: List[(Task[_], Long)]): Boolean =
|
||||
tasks
|
||||
.map({ case (t, _) => taskName(t) })
|
||||
.exists(n => stopReportTask.exists(m => n.endsWith("/ " + m)))
|
||||
if (isStop) ()
|
||||
else report0
|
||||
.exists(n => skipReportTasks.exists(m => n.endsWith("/ " + m)))
|
||||
|
||||
private[this] def deleteConsoleLines(n: Int): Unit = {
|
||||
(1 to n) foreach { _ =>
|
||||
console.println(s"$DeleteLine")
|
||||
}
|
||||
}
|
||||
|
||||
private[this] val taskNameCache = TrieMap.empty[Task[_], String]
|
||||
|
|
@ -130,7 +159,6 @@ private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecutePro
|
|||
|
||||
private[sbt] object TaskProgress {
|
||||
final val DeleteLine = "\u001B[2K"
|
||||
final val CursorUp5 = cursorUp(5)
|
||||
def cursorUp(n: Int): String = s"\u001B[${n}A"
|
||||
def cursorDown(n: Int): String = s"\u001B[${n}B"
|
||||
final val CursorDown1 = cursorDown(1)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ object Dependencies {
|
|||
|
||||
// sbt modules
|
||||
private val ioVersion = "1.3.0-M3"
|
||||
private val utilVersion = "1.3.0-M2"
|
||||
private val utilVersion = "1.3.0-M3"
|
||||
private val lmVersion =
|
||||
sys.props.get("sbt.build.lm.version") match {
|
||||
case Some(version) => version
|
||||
|
|
|
|||
Loading…
Reference in New Issue