From 88e2f2704fde2de932115a33ae9561a4f1abe8f3 Mon Sep 17 00:00:00 2001 From: Match <132382032+gayanMatch@users.noreply.github.com> Date: Tue, 13 Jan 2026 11:44:09 -0800 Subject: [PATCH] [2.x] fix: Fixes --no-colors setting for sbtn (#8517) --- .../scala/sbt/internal/util/Terminal.scala | 6 +- .../sbt/internal/util/TerminalColorSpec.scala | 66 +++++++++++++++++++ .../sbt/internal/client/NetworkClient.scala | 26 +++++--- 3 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 internal/util-logging/src/test/scala/sbt/internal/util/TerminalColorSpec.scala diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala b/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala index 72ec2bb01..6ca70cd8f 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala @@ -1034,11 +1034,11 @@ object Terminal { private def doWrite(rawBytes: Array[Byte]): Unit = withPrintStream { ps => val (toWrite, len) = if (rawBytes.contains(27.toByte)) { - if (!Terminal.isAnsiSupported || !Terminal.isColorEnabled) + if (!self.isAnsiSupported || !self.isColorEnabled) EscHelpers.strip( rawBytes, - stripAnsi = !Terminal.isAnsiSupported, - stripColor = !Terminal.isColorEnabled + stripAnsi = !self.isAnsiSupported, + stripColor = !self.isColorEnabled ) else (rawBytes, rawBytes.length) } else (rawBytes, rawBytes.length) diff --git a/internal/util-logging/src/test/scala/sbt/internal/util/TerminalColorSpec.scala b/internal/util-logging/src/test/scala/sbt/internal/util/TerminalColorSpec.scala new file mode 100644 index 000000000..50839d56e --- /dev/null +++ b/internal/util-logging/src/test/scala/sbt/internal/util/TerminalColorSpec.scala @@ -0,0 +1,66 @@ +/* + * sbt + * Copyright 2023, Scala center + * Copyright 2011 - 2022, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt.internal.util + +import org.scalatest.flatspec.AnyFlatSpec +import java.io.{ ByteArrayOutputStream, InputStream } + +class TerminalColorSpec extends AnyFlatSpec { + private def createTerminal( + colorEnabled: Boolean, + ansiSupported: Boolean, + out: ByteArrayOutputStream + ): Terminal.TerminalImpl = + new Terminal.TerminalImpl( + new Terminal.WriteableInputStream(new InputStream { def read() = -1 }, "test"), + out, + new ByteArrayOutputStream(), + "test" + ) { + private[sbt] def getSizeImpl: (Int, Int) = (80, 24) + override def isColorEnabled: Boolean = colorEnabled + override def isAnsiSupported: Boolean = ansiSupported + override private[sbt] def progressState: ProgressState = new ProgressState(1) + override def isSuccessEnabled: Boolean = true + override def isSupershellEnabled: Boolean = false + override def isEchoEnabled: Boolean = true + override def setEchoEnabled(toggle: Boolean): Unit = () + override def getBooleanCapability(capability: String): Boolean = false + override def getNumericCapability(capability: String): Integer = null + override def getStringCapability(capability: String): String = null + override private[sbt] def getAttributes: Map[String, String] = Map.empty + override private[sbt] def setAttributes(attributes: Map[String, String]): Unit = () + override private[sbt] def setSize(width: Int, height: Int): Unit = () + override private[sbt] def enterRawMode(): Unit = () + override private[sbt] def exitRawMode(): Unit = () + } + + private val ESC = "\u001b" + private val coloredText = s"$ESC[31mred text$ESC[0m" + + "Terminal with colors disabled" should "strip color codes from output" in { + val out = new ByteArrayOutputStream() + val term = createTerminal(colorEnabled = false, ansiSupported = true, out) + term.outputStream.write(coloredText.getBytes("UTF-8")) + term.outputStream.flush() + val output = out.toString("UTF-8") + assert(!output.contains(ESC)) + assert(output.contains("red text")) + } + + "Terminal with colors enabled" should "preserve color codes in output" in { + val out = new ByteArrayOutputStream() + val term = createTerminal(colorEnabled = true, ansiSupported = true, out) + term.outputStream.write(coloredText.getBytes("UTF-8")) + term.outputStream.flush() + val output = out.toString("UTF-8") + assert(output.contains(ESC)) + assert(output.contains("red text")) + } +} diff --git a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala index 1d17e59a3..e267e2ffe 100644 --- a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala +++ b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala @@ -1140,18 +1140,25 @@ object NetworkClient { override def success(msg: String): Unit = appender.success(msg) } } - private def simpleConsoleInterface(doPrintln: String => Unit): ConsoleInterface = + private def simpleConsoleInterface( + doPrintln: String => Unit, + useColor: Boolean = Terminal.isColorEnabled + ): ConsoleInterface = new ConsoleInterface { import scala.Console.{ GREEN, RED, RESET, YELLOW } override def appendLog(level: Level.Value, message: => String): Unit = synchronized { - val prefix = level match { - case Level.Error => s"[$RED$level$RESET]" - case Level.Warn => s"[$YELLOW$level$RESET]" - case _ => s"[$RESET$level$RESET]" - } + val prefix = + if (useColor) level match { + case Level.Error => s"[$RED$level$RESET]" + case Level.Warn => s"[$YELLOW$level$RESET]" + case _ => s"[$RESET$level$RESET]" + } + else s"[$level]" message.linesIterator.foreach(line => doPrintln(s"$prefix $line")) } - override def success(msg: String): Unit = doPrintln(s"[${GREEN}success$RESET] $msg") + override def success(msg: String): Unit = + if (useColor) doPrintln(s"[${GREEN}success$RESET] $msg") + else doPrintln(s"[success] $msg") } private[client] class Arguments( val baseDirectory: File, @@ -1331,7 +1338,7 @@ object NetworkClient { if (terminal.getLastLine.isDefined) terminal.printStream.println() terminal.printStream.println(line) } - val interface = NetworkClient.simpleConsoleInterface(doPrint) + val interface = NetworkClient.simpleConsoleInterface(doPrint, terminal.isColorEnabled) val printStream = terminal.printStream new NetworkClient(arguments, interface, inputStream, errorStream, printStream, useJNI) } @@ -1342,7 +1349,8 @@ object NetworkClient { errorStream: PrintStream, useJNI: Boolean, ): NetworkClient = { - val interface = NetworkClient.simpleConsoleInterface(printStream.println) + val interface = + NetworkClient.simpleConsoleInterface(printStream.println, Terminal.isColorEnabled) new NetworkClient(arguments, interface, inputStream, errorStream, printStream, useJNI) } def main(args: Array[String]): Unit = {