mirror of https://github.com/sbt/sbt.git
[2.x] fix: lastGrep ignores ANSI escape sequences when matching (#8726)
**Problem** When `last` output includes ANSI escape sequences (e.g. colored `[error]` lines), `lastGrep <pattern>` was matching against the raw string. The pattern could fail to match because it was compared to text like `\u001B[31merror\u001B[0m` instead of `error`, or matching was inconsistent. **Solution** - Strip ANSI from each line before running the regex, using `EscHelpers.stripColorsAndMoves` from `sbt.internal.util`. - **`Output.lastGrep`** (keys and file overloads): lines from the last run are stripped, then the pattern is applied to the stripped text; matching and printed lines are based on visible text. - **`Output.grep`**: each line is stripped before `showMatches(pattern)` so the pattern is applied only to visible content.
This commit is contained in:
parent
edd7061f15
commit
6d94d6db61
|
|
@ -19,6 +19,7 @@ import Aggregation.{ KeyValue, Values }
|
|||
import Types.idFun
|
||||
import Highlight.{ bold, showMatches }
|
||||
import annotation.tailrec
|
||||
import sbt.internal.util.EscHelpers
|
||||
|
||||
import sbt.io.IO
|
||||
|
||||
|
|
@ -43,7 +44,12 @@ object Output {
|
|||
printLines: Seq[String] => Unit
|
||||
)(using display: Show[ScopedKey[?]]): Unit = {
|
||||
val pattern = Pattern.compile(patternString)
|
||||
val lines = flatLines(lastLines(keys, streams))(_ flatMap showMatches(pattern))
|
||||
val lines = flatLines(lastLines(keys, streams)) { rawLines =>
|
||||
rawLines.flatMap { line =>
|
||||
val stripped = EscHelpers.stripColorsAndMoves(line)
|
||||
showMatches(pattern)(stripped)
|
||||
}
|
||||
}
|
||||
printLines(lines)
|
||||
}
|
||||
|
||||
|
|
@ -55,8 +61,13 @@ object Output {
|
|||
): Unit =
|
||||
printLines(grep(tailLines(file, tailDelim), patternString))
|
||||
|
||||
def grep(lines: Seq[String], patternString: String): Seq[String] =
|
||||
lines.flatMap(showMatches(Pattern.compile(patternString)))
|
||||
def grep(lines: Seq[String], patternString: String): Seq[String] = {
|
||||
val pattern = Pattern.compile(patternString)
|
||||
lines.flatMap { line =>
|
||||
val stripped = EscHelpers.stripColorsAndMoves(line)
|
||||
showMatches(pattern)(stripped)
|
||||
}
|
||||
}
|
||||
|
||||
def flatLines(outputs: Values[Seq[String]])(f: Seq[String] => Seq[String])(using
|
||||
display: Show[ScopedKey[?]]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
import scala.Console.{ RED, RESET }
|
||||
import verify.BasicTestSuite
|
||||
import sbt.internal.Output.grep
|
||||
|
||||
object OutputSpec extends BasicTestSuite {
|
||||
|
||||
test(
|
||||
"grep should match pattern against visible text when lines contain ANSI escape sequences (#4840)"
|
||||
) {
|
||||
// Line with ANSI color around "error" - user searching for "error" should find it (strip before match)
|
||||
val lineWithAnsi = s"${RED}error${RESET}: something failed"
|
||||
val lines = Seq("info: ok", lineWithAnsi, "warn: deprecated")
|
||||
val result = grep(lines, "error")
|
||||
assert(result.size == 1, s"expected 1 match, got ${result.size}: $result")
|
||||
// Pattern matched the visible "error" (ANSI was stripped before matching); result may have highlight from showMatches
|
||||
assert(result.head.contains("error"), s"result should contain 'error': ${result.head}")
|
||||
}
|
||||
|
||||
test("grep should not match when pattern appears only inside ANSI sequence") {
|
||||
// Line where "error" is not in the visible text (only in escape code - unrealistic but ensures we strip first)
|
||||
val lines = Seq("info: ok", "something failed")
|
||||
val result = grep(lines, "error")
|
||||
assert(result.isEmpty, s"expected no match, got: $result")
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue