From f3120f8f159b87cee8d17f1462e4b72bda3dc2ad Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Wed, 18 Nov 2020 13:26:07 -0800 Subject: [PATCH] Fix supershell blowing away lines on windows In 85d17889b6ff39c4d93f516fc247b91be73514f0, I attempted to fix supershell messages getting interlaced with log lines. It turned out that that approach didn't work with windows and was causing all of the output to bet blown away. A better approach is to check if the bytes we're writing contain one or more line separators. If so, we can wrap the bytes in a string and split the string into lines. Then we can append a ClearScreenAfterCursor before every newline. I think the problem with windows was that the ClearScreenAfterCursor was coming between the carraige return and the newline. --- .../sbt/internal/util/ProgressState.scala | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/ProgressState.scala b/internal/util-logging/src/main/scala/sbt/internal/util/ProgressState.scala index bb02574a0..d989d328b 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/ProgressState.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/ProgressState.scala @@ -85,6 +85,9 @@ private[sbt] final class ProgressState( prefix.getBytes ++ terminal.prompt.render().getBytes("UTF-8") } else Array.empty } + private[this] val cleanPrompt = + (DeleteLine + ClearScreenAfterCursor + CursorLeft1000).getBytes("UTF-8") + private[this] val clearScreenBytes = ClearScreenAfterCursor.getBytes("UTF-8") private[util] def write( terminal: Terminal, bytes: Array[Byte], @@ -96,23 +99,29 @@ private[sbt] final class ProgressState( addBytes(terminal, bytes) val toWrite = new ArrayBuffer[Byte] terminal.prompt match { - case a: Prompt.AskUser if a.render.nonEmpty && canClearPrompt => - toWrite ++= (DeleteLine + ClearScreenAfterCursor + CursorLeft1000).getBytes("UTF-8") - case _ => + case a: Prompt.AskUser if a.render.nonEmpty && canClearPrompt => toWrite ++= cleanPrompt + case _ => } - bytes.foreach { b => - if (b == 10) toWrite ++= ClearScreenAfterCursor.getBytes("UTF-8") - toWrite += b - } - toWrite ++= ClearScreenAfterCursor.getBytes("UTF-8") - if (bytes.endsWith(lineSeparatorBytes)) { + val endsWithNewLine = bytes.endsWith(lineSeparatorBytes) + if (endsWithNewLine || bytes.containsSlice(lineSeparatorBytes)) { + val parts = new String(bytes, "UTF-8").split(System.lineSeparator) + def appendLine(l: String, appendNewline: Boolean): Unit = { + toWrite ++= l.getBytes("UTF-8") + toWrite ++= clearScreenBytes + if (appendNewline) toWrite ++= lineSeparatorBytes + } + parts.dropRight(1).foreach(appendLine(_, true)) + parts.lastOption.foreach(appendLine(_, bytes.endsWith(lineSeparatorBytes))) + } else toWrite ++= bytes + toWrite ++= clearScreenBytes + if (endsWithNewLine) { if (progressLines.get.nonEmpty) { val lastLine = terminal.prompt match { case a: Prompt.AskUser => a.render() case _ => currentLine.getOrElse("") } val lines = printProgress(terminal, lastLine) - toWrite ++= (ClearScreenAfterCursor + lines).getBytes("UTF-8") + toWrite ++= lines.getBytes("UTF-8") } toWrite ++= getPrompt(terminal) }