mirror of https://github.com/sbt/sbt.git
Move ProgressState into its own file
This didn't really belong in ConsoleAppender.scala anymore.
This commit is contained in:
parent
b6354656b1
commit
ed4d40d3e2
|
|
@ -9,7 +9,7 @@ package sbt.internal.util
|
||||||
|
|
||||||
import java.io.{ PrintStream, PrintWriter }
|
import java.io.{ PrintStream, PrintWriter }
|
||||||
import java.lang.StringBuilder
|
import java.lang.StringBuilder
|
||||||
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger, AtomicReference }
|
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger }
|
||||||
|
|
||||||
import org.apache.logging.log4j.core.appender.AbstractAppender
|
import org.apache.logging.log4j.core.appender.AbstractAppender
|
||||||
import org.apache.logging.log4j.core.{ LogEvent => XLogEvent }
|
import org.apache.logging.log4j.core.{ LogEvent => XLogEvent }
|
||||||
|
|
@ -18,8 +18,6 @@ import org.apache.logging.log4j.{ Level => XLevel }
|
||||||
import sbt.internal.util.ConsoleAppender._
|
import sbt.internal.util.ConsoleAppender._
|
||||||
import sbt.util._
|
import sbt.util._
|
||||||
|
|
||||||
import scala.collection.mutable.ArrayBuffer
|
|
||||||
|
|
||||||
object ConsoleLogger {
|
object ConsoleLogger {
|
||||||
// These are provided so other modules do not break immediately.
|
// These are provided so other modules do not break immediately.
|
||||||
@deprecated("Use EscHelpers.ESC instead", "0.13.x")
|
@deprecated("Use EscHelpers.ESC instead", "0.13.x")
|
||||||
|
|
@ -553,138 +551,3 @@ class ConsoleAppender private[ConsoleAppender] (
|
||||||
}
|
}
|
||||||
|
|
||||||
final class SuppressedTraceContext(val traceLevel: Int, val useFormat: Boolean)
|
final class SuppressedTraceContext(val traceLevel: Int, val useFormat: Boolean)
|
||||||
private[sbt] final class ProgressState(
|
|
||||||
val progressLines: AtomicReference[Seq[String]],
|
|
||||||
val padding: AtomicInteger,
|
|
||||||
val blankZone: Int,
|
|
||||||
val currentLineBytes: AtomicReference[ArrayBuffer[Byte]],
|
|
||||||
) {
|
|
||||||
def this(blankZone: Int) =
|
|
||||||
this(
|
|
||||||
new AtomicReference(Nil),
|
|
||||||
new AtomicInteger(0),
|
|
||||||
blankZone,
|
|
||||||
new AtomicReference(new ArrayBuffer[Byte]),
|
|
||||||
)
|
|
||||||
def reset(): Unit = {
|
|
||||||
progressLines.set(Nil)
|
|
||||||
padding.set(0)
|
|
||||||
currentLineBytes.set(new ArrayBuffer[Byte])
|
|
||||||
}
|
|
||||||
private[util] def clearBytes(): Unit = {
|
|
||||||
val pad = padding.get
|
|
||||||
if (currentLineBytes.get.isEmpty && pad > 0) padding.decrementAndGet()
|
|
||||||
currentLineBytes.set(new ArrayBuffer[Byte])
|
|
||||||
}
|
|
||||||
|
|
||||||
private[util] def addBytes(terminal: Terminal, bytes: ArrayBuffer[Byte]): Unit = {
|
|
||||||
val previous = currentLineBytes.get
|
|
||||||
val padding = this.padding.get
|
|
||||||
val prevLineCount = if (padding > 0) terminal.lineCount(new String(previous.toArray)) else 0
|
|
||||||
previous ++= bytes
|
|
||||||
if (padding > 0) {
|
|
||||||
val newLineCount = terminal.lineCount(new String(previous.toArray))
|
|
||||||
val diff = newLineCount - prevLineCount
|
|
||||||
this.padding.set(math.max(padding - diff, 0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private[util] def printPrompt(terminal: Terminal, printStream: PrintStream): Unit =
|
|
||||||
if (terminal.prompt != Prompt.Running && terminal.prompt != Prompt.Batch) {
|
|
||||||
val prefix = if (terminal.isAnsiSupported) s"$DeleteLine$CursorLeft1000" else ""
|
|
||||||
val pmpt = prefix.getBytes ++ terminal.prompt.render().getBytes
|
|
||||||
pmpt.foreach(b => printStream.write(b & 0xFF))
|
|
||||||
}
|
|
||||||
private[util] def reprint(terminal: Terminal, printStream: PrintStream): Unit = {
|
|
||||||
printPrompt(terminal, printStream)
|
|
||||||
if (progressLines.get.nonEmpty) {
|
|
||||||
val lines = printProgress(terminal, terminal.getLastLine.getOrElse(""))
|
|
||||||
printStream.print(ClearScreenAfterCursor + lines)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private[util] def printProgress(
|
|
||||||
terminal: Terminal,
|
|
||||||
lastLine: String
|
|
||||||
): String = {
|
|
||||||
val previousLines = progressLines.get
|
|
||||||
if (previousLines.nonEmpty) {
|
|
||||||
val currentLength = previousLines.foldLeft(0)(_ + terminal.lineCount(_))
|
|
||||||
val (height, width) = terminal.getLineHeightAndWidth(lastLine)
|
|
||||||
val left = cursorLeft(1000) // resets the position to the left
|
|
||||||
val offset = width > 0
|
|
||||||
val pad = math.max(padding.get - height, 0)
|
|
||||||
val start = (if (offset) "\n" else "")
|
|
||||||
val totalSize = currentLength + blankZone + pad
|
|
||||||
val blank = left + s"\n$DeleteLine" * (totalSize - currentLength)
|
|
||||||
val lines = previousLines.mkString(DeleteLine, s"\n$DeleteLine", s"\n$DeleteLine")
|
|
||||||
val resetCursorUp = cursorUp(totalSize + (if (offset) 1 else 0))
|
|
||||||
val resetCursor = resetCursorUp + left + lastLine
|
|
||||||
start + blank + lines + resetCursor
|
|
||||||
} else {
|
|
||||||
ClearScreenAfterCursor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private[sbt] object ProgressState {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receives a new task report and replaces the old one. In the event that the new
|
|
||||||
* report has fewer lines than the previous report, padding lines are added on top
|
|
||||||
* so that the console log lines remain contiguous. When a console line is printed
|
|
||||||
* at the info or greater level, we can decrement the padding because the console
|
|
||||||
* line will have filled in the blank line.
|
|
||||||
*/
|
|
||||||
private[sbt] def updateProgressState(
|
|
||||||
pe: ProgressEvent,
|
|
||||||
terminal: Terminal
|
|
||||||
): Unit = {
|
|
||||||
val state = terminal.progressState
|
|
||||||
val isRunning = terminal.prompt == Prompt.Running
|
|
||||||
val isBatch = terminal.prompt == Prompt.Batch
|
|
||||||
val isWatch = terminal.prompt == Prompt.Watch
|
|
||||||
val noPrompt = terminal.prompt == Prompt.NoPrompt
|
|
||||||
if (terminal.isSupershellEnabled) {
|
|
||||||
if (!pe.skipIfActive.getOrElse(false) || (!isRunning && !isBatch)) {
|
|
||||||
terminal.withPrintStream { ps =>
|
|
||||||
val info =
|
|
||||||
if ((isRunning || isBatch || noPrompt) && pe.channelName
|
|
||||||
.fold(true)(_ == terminal.name)) {
|
|
||||||
pe.items.map { item =>
|
|
||||||
val elapsed = item.elapsedMicros / 1000000L
|
|
||||||
s" | => ${item.name} ${elapsed}s"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pe.command.toSeq.flatMap { cmd =>
|
|
||||||
val tail = if (isWatch) Nil else "enter 'cancel' to stop evaluation" :: Nil
|
|
||||||
s"sbt server is running '$cmd'" :: tail
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val currentLength = info.foldLeft(0)(_ + terminal.lineCount(_))
|
|
||||||
val previousLines = state.progressLines.getAndSet(info)
|
|
||||||
val prevLength = previousLines.foldLeft(0)(_ + terminal.lineCount(_))
|
|
||||||
val lastLine = terminal.prompt match {
|
|
||||||
case Prompt.Running | Prompt.Batch => terminal.getLastLine.getOrElse("")
|
|
||||||
case a => a.render()
|
|
||||||
}
|
|
||||||
val prevSize = prevLength + state.padding.get
|
|
||||||
|
|
||||||
val newPadding = math.max(0, prevSize - currentLength)
|
|
||||||
state.padding.set(newPadding)
|
|
||||||
state.printPrompt(terminal, ps)
|
|
||||||
ps.print(state.printProgress(terminal, lastLine))
|
|
||||||
ps.flush()
|
|
||||||
}
|
|
||||||
} else if (state.progressLines.get.nonEmpty) {
|
|
||||||
state.progressLines.set(Nil)
|
|
||||||
terminal.withPrintStream { ps =>
|
|
||||||
val lastLine = terminal.getLastLine.getOrElse("")
|
|
||||||
ps.print(lastLine + ClearScreenAfterCursor)
|
|
||||||
ps.flush()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sbt.internal.util
|
||||||
|
|
||||||
|
import java.io.PrintStream
|
||||||
|
import java.util.concurrent.atomic.{ AtomicInteger, AtomicReference }
|
||||||
|
|
||||||
|
import sbt.internal.util.ConsoleAppender.{
|
||||||
|
ClearScreenAfterCursor,
|
||||||
|
CursorLeft1000,
|
||||||
|
DeleteLine,
|
||||||
|
cursorLeft,
|
||||||
|
cursorUp,
|
||||||
|
}
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
|
||||||
|
private[sbt] final class ProgressState(
|
||||||
|
val progressLines: AtomicReference[Seq[String]],
|
||||||
|
val padding: AtomicInteger,
|
||||||
|
val blankZone: Int,
|
||||||
|
val currentLineBytes: AtomicReference[ArrayBuffer[Byte]],
|
||||||
|
) {
|
||||||
|
def this(blankZone: Int) =
|
||||||
|
this(
|
||||||
|
new AtomicReference(Nil),
|
||||||
|
new AtomicInteger(0),
|
||||||
|
blankZone,
|
||||||
|
new AtomicReference(new ArrayBuffer[Byte]),
|
||||||
|
)
|
||||||
|
def reset(): Unit = {
|
||||||
|
progressLines.set(Nil)
|
||||||
|
padding.set(0)
|
||||||
|
currentLineBytes.set(new ArrayBuffer[Byte])
|
||||||
|
}
|
||||||
|
private[util] def clearBytes(): Unit = {
|
||||||
|
val pad = padding.get
|
||||||
|
if (currentLineBytes.get.isEmpty && pad > 0) padding.decrementAndGet()
|
||||||
|
currentLineBytes.set(new ArrayBuffer[Byte])
|
||||||
|
}
|
||||||
|
|
||||||
|
private[util] def addBytes(terminal: Terminal, bytes: ArrayBuffer[Byte]): Unit = {
|
||||||
|
val previous = currentLineBytes.get
|
||||||
|
val padding = this.padding.get
|
||||||
|
val prevLineCount = if (padding > 0) terminal.lineCount(new String(previous.toArray)) else 0
|
||||||
|
previous ++= bytes
|
||||||
|
if (padding > 0) {
|
||||||
|
val newLineCount = terminal.lineCount(new String(previous.toArray))
|
||||||
|
val diff = newLineCount - prevLineCount
|
||||||
|
this.padding.set(math.max(padding - diff, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private[util] def printPrompt(terminal: Terminal, printStream: PrintStream): Unit =
|
||||||
|
if (terminal.prompt != Prompt.Running && terminal.prompt != Prompt.Batch) {
|
||||||
|
val prefix = if (terminal.isAnsiSupported) s"$DeleteLine$CursorLeft1000" else ""
|
||||||
|
val pmpt = prefix.getBytes ++ terminal.prompt.render().getBytes
|
||||||
|
pmpt.foreach(b => printStream.write(b & 0xFF))
|
||||||
|
}
|
||||||
|
private[util] def reprint(terminal: Terminal, printStream: PrintStream): Unit = {
|
||||||
|
printPrompt(terminal, printStream)
|
||||||
|
if (progressLines.get.nonEmpty) {
|
||||||
|
val lines = printProgress(terminal, terminal.getLastLine.getOrElse(""))
|
||||||
|
printStream.print(ClearScreenAfterCursor + lines)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private[util] def printProgress(
|
||||||
|
terminal: Terminal,
|
||||||
|
lastLine: String
|
||||||
|
): String = {
|
||||||
|
val previousLines = progressLines.get
|
||||||
|
if (previousLines.nonEmpty) {
|
||||||
|
val currentLength = previousLines.foldLeft(0)(_ + terminal.lineCount(_))
|
||||||
|
val (height, width) = terminal.getLineHeightAndWidth(lastLine)
|
||||||
|
val left = cursorLeft(1000) // resets the position to the left
|
||||||
|
val offset = width > 0
|
||||||
|
val pad = math.max(padding.get - height, 0)
|
||||||
|
val start = (if (offset) "\n" else "")
|
||||||
|
val totalSize = currentLength + blankZone + pad
|
||||||
|
val blank = left + s"\n$DeleteLine" * (totalSize - currentLength)
|
||||||
|
val lines = previousLines.mkString(DeleteLine, s"\n$DeleteLine", s"\n$DeleteLine")
|
||||||
|
val resetCursorUp = cursorUp(totalSize + (if (offset) 1 else 0))
|
||||||
|
val resetCursor = resetCursorUp + left + lastLine
|
||||||
|
start + blank + lines + resetCursor
|
||||||
|
} else {
|
||||||
|
ClearScreenAfterCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private[sbt] object ProgressState {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives a new task report and replaces the old one. In the event that the new
|
||||||
|
* report has fewer lines than the previous report, padding lines are added on top
|
||||||
|
* so that the console log lines remain contiguous. When a console line is printed
|
||||||
|
* at the info or greater level, we can decrement the padding because the console
|
||||||
|
* line will have filled in the blank line.
|
||||||
|
*/
|
||||||
|
private[sbt] def updateProgressState(
|
||||||
|
pe: ProgressEvent,
|
||||||
|
terminal: Terminal
|
||||||
|
): Unit = {
|
||||||
|
val state = terminal.progressState
|
||||||
|
val isRunning = terminal.prompt == Prompt.Running
|
||||||
|
val isBatch = terminal.prompt == Prompt.Batch
|
||||||
|
val isWatch = terminal.prompt == Prompt.Watch
|
||||||
|
val noPrompt = terminal.prompt == Prompt.NoPrompt
|
||||||
|
if (terminal.isSupershellEnabled) {
|
||||||
|
if (!pe.skipIfActive.getOrElse(false) || (!isRunning && !isBatch)) {
|
||||||
|
terminal.withPrintStream { ps =>
|
||||||
|
val info =
|
||||||
|
if ((isRunning || isBatch || noPrompt) && pe.channelName
|
||||||
|
.fold(true)(_ == terminal.name)) {
|
||||||
|
pe.items.map { item =>
|
||||||
|
val elapsed = item.elapsedMicros / 1000000L
|
||||||
|
s" | => ${item.name} ${elapsed}s"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pe.command.toSeq.flatMap { cmd =>
|
||||||
|
val tail = if (isWatch) Nil else "enter 'cancel' to stop evaluation" :: Nil
|
||||||
|
s"sbt server is running '$cmd'" :: tail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val currentLength = info.foldLeft(0)(_ + terminal.lineCount(_))
|
||||||
|
val previousLines = state.progressLines.getAndSet(info)
|
||||||
|
val prevLength = previousLines.foldLeft(0)(_ + terminal.lineCount(_))
|
||||||
|
val lastLine = terminal.prompt match {
|
||||||
|
case Prompt.Running | Prompt.Batch => terminal.getLastLine.getOrElse("")
|
||||||
|
case a => a.render()
|
||||||
|
}
|
||||||
|
val prevSize = prevLength + state.padding.get
|
||||||
|
|
||||||
|
val newPadding = math.max(0, prevSize - currentLength)
|
||||||
|
state.padding.set(newPadding)
|
||||||
|
state.printPrompt(terminal, ps)
|
||||||
|
ps.print(state.printProgress(terminal, lastLine))
|
||||||
|
ps.flush()
|
||||||
|
}
|
||||||
|
} else if (state.progressLines.get.nonEmpty) {
|
||||||
|
state.progressLines.set(Nil)
|
||||||
|
terminal.withPrintStream { ps =>
|
||||||
|
val lastLine = terminal.getLastLine.getOrElse("")
|
||||||
|
ps.print(lastLine + ClearScreenAfterCursor)
|
||||||
|
ps.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue