diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/EscHelpers.scala b/internal/util-logging/src/main/scala/sbt/internal/util/EscHelpers.scala index ad394994c..26ad513a8 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/EscHelpers.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/EscHelpers.scala @@ -66,8 +66,9 @@ object EscHelpers { } else { sb.append(s, start, escIndex) val next: Int = + if (escIndex + 1 >= s.length) skipESC(s, escIndex + 1) // If it's a CSI we skip past it and then look for a terminator. - if (isCSI(s.charAt(escIndex + 1))) skipESC(s, escIndex + 2) + else if (isCSI(s.charAt(escIndex + 1))) skipESC(s, escIndex + 2) else if (isAnsiTwoCharacterTerminator(s.charAt(escIndex + 1))) escIndex + 2 else { // There could be non-ANSI character sequences we should make sure we handle here. diff --git a/internal/util-logging/src/test/scala/Escapes.scala b/internal/util-logging/src/test/scala/Escapes.scala index 9db109d7f..2464286bb 100644 --- a/internal/util-logging/src/test/scala/Escapes.scala +++ b/internal/util-logging/src/test/scala/Escapes.scala @@ -34,6 +34,16 @@ object Escapes extends Properties("Escapes") { !hasEscapeSequence(removed) } + private[this] final val ecs = ESC.toString + private val partialEscapeSequences = + Gen.oneOf(Gen const ecs, Gen const ecs ++ "[", Gen.choose('@', '_').map(ecs :+ _)) + + property("removeEscapeSequences handles partial escape sequences") = + forAll(partialEscapeSequences) { s => + val removed: String = removeEscapeSequences(s) + s"Escape sequence removed: '$removed'" |: !hasEscapeSequence(removed) + } + property("removeEscapeSequences returns string without escape sequences") = forAllNoShrink(genWithoutEscape, genEscapePairs) { (start: String, escapes: List[EscapeAndNot]) =>