diff --git a/integration/feature/full-run-logs/src/FullRunLogsTests.scala b/integration/feature/full-run-logs/src/FullRunLogsTests.scala
index 62d70ca9848..f9c677a012c 100644
--- a/integration/feature/full-run-logs/src/FullRunLogsTests.scala
+++ b/integration/feature/full-run-logs/src/FullRunLogsTests.scala
@@ -31,24 +31,25 @@ object FullRunLogsTests extends UtestIntegrationTestSuite {
res.isSuccess ==> true
assert("\\[\\d+\\]
hello
".r.matches(res.out))
- val expectedErrorRegex =
- s"""========================================== run --text hello ======================================
- |==================================================================================================
- |[build.mill-/] compile
- |[build.mill-] [info] compiling 1 Scala source to ${tester.workspacePath}/out/mill-build/compile.dest/classes ...
- |[build.mill-] [info] done compiling
- |[/] compile
- |[] [info] compiling 1 Java source to ${tester.workspacePath}/out/compile.dest/classes ...
- |[] [info] done compiling
- |[/] run
- |[/] ================================== run --text hello ==================================s
- |=================================================================================================="""
- .stripMargin
- .replaceAll("(\r\n)|\r", "\n")
- .replace('\\', '/')
- .split("")
- .map(java.util.regex.Pattern.quote)
- .mkString("=? ?[\\d]+")
+ val expectedErrorRegex = java.util.regex.Pattern
+ .quote(
+ s""" run --text hello
+ |
+ |[build.mill-/] compile
+ |[build.mill-] [info] compiling 1 Scala source to ${tester.workspacePath}/out/mill-build/compile.dest/classes ...
+ |[build.mill-] [info] done compiling
+ |[/] compile
+ |[] [info] compiling 1 Java source to ${tester.workspacePath}/out/compile.dest/classes ...
+ |[] [info] done compiling
+ |[/] run
+ |[/] run --text hello s
+ |"""
+ .stripMargin
+ .replaceAll("(\r\n)|\r", "\n")
+ .replace('\\', '/')
+ )
+ .replace("", "\\E\\d+\\Q")
+ .replace("", "\\E=+\\Q")
assert(expectedErrorRegex.r.matches(res.err.replace('\\', '/').replaceAll("(\r\n)|\r", "\n")))
}
diff --git a/main/util/src/mill/util/PromptLoggerUtil.scala b/main/util/src/mill/util/PromptLoggerUtil.scala
index 6589532454d..7d09586cd31 100644
--- a/main/util/src/mill/util/PromptLoggerUtil.scala
+++ b/main/util/src/mill/util/PromptLoggerUtil.scala
@@ -150,7 +150,7 @@ private object PromptLoggerUtil {
// For non-interactive jobs, the prompt won't be at the bottom of the terminal but
// will instead be in the middle of a big log file with logs above and below, so we
// need some kind of footer to tell the reader when the prompt ends and logs begin
- val footer = Option.when(!interactive)("=" * maxWidth).toList
+ val footer = Option.when(!interactive)("=" * header.length).toList
header :: body ::: footer
}
@@ -187,28 +187,24 @@ private object PromptLoggerUtil {
val headerPrefixStr = if (!interactive || ending) headerPrefix else s" $headerPrefix"
val headerSuffixStr = headerSuffix0
val titleText = s" $titleText0 "
- // -12 just to ensure we always have some ==== divider on each side of the title
+
+ val dividerMaxLength = 30
+ val dividerMinLength = 15
val maxTitleLength =
- maxWidth - math.max(headerPrefixStr.length, headerSuffixStr.length) * 2 - 12
+ maxWidth - headerPrefixStr.length - headerSuffixStr.length - dividerMinLength * 2
val shortenedTitle = splitShorten(titleText, maxTitleLength)
- // +2 to offset the title a bit to the right so it looks centered, as the `headerPrefixStr`
- // is usually longer than `headerSuffixStr`. We use a fixed offset rather than dynamically
- // offsetting by `headerPrefixStr.length` to prevent the title from shifting left and right
- // as the `headerPrefixStr` changes, even at the expense of it not being perfectly centered.
- val leftDivider = "=" * ((maxWidth / 2) - (titleText.length / 2) - headerPrefixStr.length + 2)
- val rightDivider =
- "=" * (
- maxWidth - headerPrefixStr.length - leftDivider.length -
- shortenedTitle.length - headerSuffixStr.length
- )
- val headerString =
- headerPrefixStr + leftDivider + shortenedTitle + rightDivider + headerSuffixStr
- assert(
- headerString.length == maxWidth,
- s"${pprint.apply(headerString)} is length ${headerString.length}, requires $maxWidth"
+ val rightDiv = "=" * math.min(
+ dividerMaxLength,
+ (maxWidth - headerPrefixStr.length - headerSuffixStr.length - shortenedTitle.length) / 2
)
- headerString
+ val leftDiv = "=" * math.min(
+ dividerMaxLength,
+ maxWidth - headerPrefixStr.length - headerSuffixStr.length - shortenedTitle.length - rightDiv.length
+ )
+
+ val headerString = headerPrefixStr + leftDiv + shortenedTitle + rightDiv + headerSuffixStr
+ splitShorten(headerString, maxWidth)
}
def splitShorten(s: String, maxLength: Int): String = {
diff --git a/main/util/test/src/mill/util/PromptLoggerTests.scala b/main/util/test/src/mill/util/PromptLoggerTests.scala
index 28b146342ed..9f79125a9f2 100644
--- a/main/util/test/src/mill/util/PromptLoggerTests.scala
+++ b/main/util/test/src/mill/util/PromptLoggerTests.scala
@@ -78,8 +78,8 @@ object PromptLoggerTests extends TestSuite {
promptLogger.close()
check(promptLogger, baos, width = 999 /*log file has no line wrapping*/ )(
- "================================================ TITLE ===========================================",
- "==================================================================================================",
+ "============================== TITLE ==============================",
+ "===================================================================",
// Make sure that the first time a prefix is reported,
// we print the verbose prefix along with the ticker string
"[1/456] my-task",
@@ -89,17 +89,17 @@ object PromptLoggerTests extends TestSuite {
// the double space prefix (since it's non-interactive and we don't need space for a cursor),
// the time elapsed, the reported title and ticker, the list of active tickers, followed by the
// footer
- "[123/456] ====================================== TITLE ======================================= 10s",
+ "[123/456] ============================== TITLE ============================== 10s",
"[1] my-task 10s",
- "==================================================================================================",
+ "=================================================================================",
"[1] WORLD",
// Calling `refreshPrompt()` after closing the ticker shows the prompt without
// the ticker in the list, with an updated time elapsed
- "[123/456] ====================================== TITLE ======================================= 20s",
- "==================================================================================================",
+ "[123/456] ============================== TITLE ============================== 20s",
+ "=================================================================================",
// Closing the prompt prints the prompt one last time with an updated time elapsed
- "[123/456] ====================================== TITLE ======================================= 30s",
- "==================================================================================================",
+ "[123/456] ============================== TITLE ============================== 30s",
+ "=================================================================================",
""
)
}
@@ -113,7 +113,7 @@ object PromptLoggerTests extends TestSuite {
promptLogger.setPromptHeaderPrefix("123/456")
promptLogger.refreshPrompt()
check(promptLogger, baos)(
- " [123/456] ========================== TITLE =================================="
+ " [123/456] ============================== TITLE =============================="
)
promptLogger.setPromptLine(Seq("1"), "/456", "my-task")
@@ -130,7 +130,7 @@ object PromptLoggerTests extends TestSuite {
"",
"[1/456] my-task",
"[1] HELLO",
- " [123/456] ========================== TITLE ============================== 10s",
+ " [123/456] ============================ TITLE ============================ 10s",
"[1] my-task 10s"
)
@@ -143,7 +143,7 @@ object PromptLoggerTests extends TestSuite {
"[1/456] my-task",
"[1] HELLO",
"[1] WORLD",
- " [123/456] ========================== TITLE ============================== 10s",
+ " [123/456] ============================ TITLE ============================ 10s",
"[1] my-task 10s"
)
@@ -175,7 +175,7 @@ object PromptLoggerTests extends TestSuite {
"[3/456] my-task-short-lived",
"[3] hello short lived",
"[3] goodbye short lived",
- " [123/456] ========================== TITLE ============================== 10s",
+ " [123/456] ============================ TITLE ============================ 10s",
"[1] my-task 10s"
)
@@ -196,7 +196,7 @@ object PromptLoggerTests extends TestSuite {
"[3/456] my-task-short-lived",
"[3] hello short lived",
"[3] goodbye short lived",
- " [123/456] ========================== TITLE ============================== 11s",
+ " [123/456] ============================ TITLE ============================ 11s",
"[1] my-task 11s",
"[2] my-task-new 1s"
)
@@ -218,7 +218,7 @@ object PromptLoggerTests extends TestSuite {
"[3/456] my-task-short-lived",
"[3] hello short lived",
"[3] goodbye short lived",
- " [123/456] ========================== TITLE ============================== 11s",
+ " [123/456] ============================ TITLE ============================ 11s",
"[1] my-task 11s",
"[2] my-task-new 1s"
)
@@ -239,7 +239,7 @@ object PromptLoggerTests extends TestSuite {
"[3/456] my-task-short-lived",
"[3] hello short lived",
"[3] goodbye short lived",
- " [123/456] ========================== TITLE ============================== 12s",
+ " [123/456] ============================ TITLE ============================ 12s",
"[2] my-task-new 2s",
""
)
@@ -259,7 +259,7 @@ object PromptLoggerTests extends TestSuite {
"[3/456] my-task-short-lived",
"[3] hello short lived",
"[3] goodbye short lived",
- " [123/456] ========================== TITLE ============================== 22s",
+ " [123/456] ============================ TITLE ============================ 22s",
"[2] my-task-new 12s"
)
now += 10000
@@ -275,7 +275,7 @@ object PromptLoggerTests extends TestSuite {
"[3/456] my-task-short-lived",
"[3] hello short lived",
"[3] goodbye short lived",
- "[123/456] ============================ TITLE ============================== 32s",
+ "[123/456] ============================= TITLE ============================= 32s",
""
)
}
@@ -298,20 +298,20 @@ object PromptLoggerTests extends TestSuite {
now += 1000
promptLogger.refreshPrompt()
check(promptLogger, baos)(
- " [123/456] ========================== TITLE =============================== 1s",
+ " [123/456] ============================= TITLE ============================ 1s",
"[1] my-task 1s detail"
)
prefixLogger.ticker("detail-too-long-gets-truncated-abcdefghijklmnopqrstuvwxyz1234567890")
promptLogger.refreshPrompt()
check(promptLogger, baos)(
- " [123/456] ========================== TITLE =============================== 1s",
+ " [123/456] ============================= TITLE ============================ 1s",
"[1] my-task 1s detail-too-long-gets-truncated...fghijklmnopqrstuvwxyz1234567890"
)
promptLogger.removePromptLine(Seq("1"))
now += 10000
promptLogger.refreshPrompt()
check(promptLogger, baos)(
- " [123/456] ========================== TITLE ============================== 11s"
+ " [123/456] ============================ TITLE ============================ 11s"
)
}
}
diff --git a/main/util/test/src/mill/util/PromptLoggerUtilTests.scala b/main/util/test/src/mill/util/PromptLoggerUtilTests.scala
index 35c88e3b758..fc4ae5ccf95 100644
--- a/main/util/test/src/mill/util/PromptLoggerUtilTests.scala
+++ b/main/util/test/src/mill/util/PromptLoggerUtilTests.scala
@@ -78,47 +78,56 @@ object PromptLoggerUtilTests extends TestSuite {
val rendered = renderHeader(prefix, title, suffix, maxWidth)
// leave two spaces open on the left so there's somewhere to park the cursor
assert(expected == rendered)
- assert(rendered.length == maxWidth)
+ assert(rendered.length <= maxWidth)
rendered
}
- test("simple") - check(
- "PREFIX",
- "TITLE",
- " SUFFIX",
- 60,
- expected = " PREFIX ==================== TITLE ================= SUFFIX"
+ def checkSimple(maxWidth: Int, expected: String) =
+ check("PREFIX", "TITLE", " SUFFIX", maxWidth, expected)
+ test("extra") - checkSimple(
+ 200,
+ " PREFIX ============================== TITLE ============================== SUFFIX"
)
-
- test("short") - check(
- "PREFIX",
- "TITLE",
- " SUFFIX",
- 40,
- expected = " PREFIX ========== TITLE ======= SUFFIX"
+ test("exact") - checkSimple(
+ 83,
+ " PREFIX ============================== TITLE ============================== SUFFIX"
)
-
- test("shorter") - check(
- "PREFIX",
- "TITLE",
- " SUFFIX",
- 25,
- expected = " PREFIX ========= SUFFIX"
+ test("short") - checkSimple(
+ 82, // One `=` is removed from the right
+ " PREFIX ============================== TITLE ============================= SUFFIX"
+ )
+ test("shorter") - checkSimple(
+ 81, // Next `=` is removed from the right
+ " PREFIX ============================= TITLE ============================= SUFFIX"
)
- test("truncateTitle") - check(
- "PREFIX",
- "TITLE_ABCDEFGHIJKLMNOPQRSTUVWXYZ",
- " SUFFIX",
- 60,
- expected = " PREFIX ====== TITLE_ABCDEFG...OPQRSTUVWXYZ ======== SUFFIX"
+ test("shorter2") - checkSimple(
+ 70, // Lots of `=`s removed from both left and right
+ " PREFIX ======================== TITLE ======================= SUFFIX"
)
- test("asymmetricTruncateTitle") - check(
- "PREFIX_LONG",
- "TITLE_ABCDEFGHIJKLMNOPQRSTUVWXYZ",
- " SUFFIX",
- 60,
- expected = " PREFIX_LONG = TITLE_AB...TUVWXYZ ================== SUFFIX"
+ test("beforeShortenTitle") - checkSimple(
+ 53, // Minimum number of `=` on each side (15) before shortening title
+ " PREFIX =============== TITLE =============== SUFFIX"
+ )
+ test("shortenTitle") - checkSimple(
+ 52, // Begin shortening Title
+ " PREFIX =============== T... =============== SUFFIX"
+ )
+ test("shortenTitle2") - checkSimple(
+ 51,
+ " PREFIX =============== ... =============== SUFFIX"
+ )
+ test("shortenTitle3") - checkSimple(
+ 50, // Title is already minimized, have to shorten other parts
+ " PREFIX =============== ...=============== SUFFIX"
+ )
+ test("titleEntirelyGone") - checkSimple(
+ 30, // Title section entirely removed
+ " PREFIX ============== SUFFIX"
+ )
+ test("shortenTitle3") - checkSimple(
+ 10, // `=`s are all removed
+ " PR...FIX"
)
}
@@ -129,7 +138,7 @@ object PromptLoggerUtilTests extends TestSuite {
titleText: String = "__.compile"
)(statuses: (Int, Status)*) = {
renderPrompt(
- consoleWidth = 60,
+ consoleWidth = 74,
consoleHeight = 20,
now = now,
startTimeMillis = now - 1337000,
@@ -147,7 +156,7 @@ object PromptLoggerUtilTests extends TestSuite {
1 -> Status(Some(StatusEntry("world", now - 2000)), 0, None)
)
val expected = List(
- " 123/456 =============== __.compile ================ 1337s",
+ " 123/456 ======================= __.compile ====================== 1337s",
"hello 1s",
"world 2s"
)
@@ -172,7 +181,7 @@ object PromptLoggerUtilTests extends TestSuite {
)
val expected = List(
- " 123/456 ======== __.compile.abcdefghijklmn ======== 1337s",
+ " 123/456 =============== __.compile.abcdefghijklmn =============== 1337s",
"#1 hello1234567890abcefghijklmnopqrstuvwxyz1234567890123 1s",
"#2 world 2s",
"#3 i am cow 3s",
@@ -181,7 +190,7 @@ object PromptLoggerUtilTests extends TestSuite {
)
assert(rendered == expected)
}
- test("minAfterTruncation") {
+ test("minAfterTruncateHeader") {
val rendered =
renderPromptTest(interactive = true, titleText = "__.compile.abcdefghijklmno")(
0 -> Status(
@@ -204,8 +213,40 @@ object PromptLoggerUtilTests extends TestSuite {
)
val expected = List(
- " 123/456 ======= __.compile....efghijklmno ========= 1337s",
- "#1 hello1234567890abcefghijk...pqrstuvwxyz12345678901234 1s",
+ " 123/456 =============== __.compile....efghijklmno =============== 1337s",
+ "#1 hello1234567890abcefghijklmnopqrstuvwxyz12345678901234 1s",
+ "#2 world 2s",
+ "#3 i am cow 3s",
+ "#4 hear me moo 4s",
+ "... and 2 more threads"
+ )
+ assert(rendered == expected)
+ }
+ test("minAfterTruncateRow") {
+ val rendered =
+ renderPromptTest(interactive = true, titleText = "__.compile.abcdefghijklmno")(
+ 0 -> Status(
+ Some(StatusEntry(
+ "#1 hello1234567890abcefghijklmnopqrstuvwxyz1234567890123456789012345678",
+ now - 1000
+ )),
+ 0,
+ None
+ ),
+ 1 -> Status(Some(StatusEntry("#2 world", now - 2000)), 0, None),
+ 2 -> Status(Some(StatusEntry("#3 i am cow", now - 3000)), 0, None),
+ 3 -> Status(Some(StatusEntry("#4 hear me moo", now - 4000)), 0, None),
+ 4 -> Status(Some(StatusEntry("#5 i weigh twice as much as you", now - 5000)), 0, None),
+ 5 -> Status(
+ Some(StatusEntry("#6 and I look good on the barbecue", now - 6000)),
+ 0,
+ None
+ )
+ )
+
+ val expected = List(
+ " 123/456 =============== __.compile....efghijklmno =============== 1337s",
+ "#1 hello1234567890abcefghijklmnopqr...wxyz1234567890123456789012345678 1s",
"#2 world 2s",
"#3 i am cow 3s",
"#4 hear me moo 4s",
@@ -236,13 +277,14 @@ object PromptLoggerUtilTests extends TestSuite {
)
)
val expected = List(
- " 123/456 __.compile....z1234567890 ================ 1337s",
- "#1 hello1234567890abcefghijk...abcefghijklmnopqrstuvwxyz 1s",
+ " 123/456 =============== __.compile....z1234567890 =============== 1337s",
+ "#1 hello1234567890abcefghijklmnopqr...4567890abcefghijklmnopqrstuvwxyz 1s",
"#2 world 2s",
"#3 i am cow 3s",
"#4 hear me moo 4s",
"... and 3 more threads"
)
+
assert(rendered == expected)
}
test("detail") {
@@ -269,11 +311,11 @@ object PromptLoggerUtilTests extends TestSuite {
)
)
val expected = List(
- " 123/456 =============== __.compile ================ 1337s",
- "1 hello 1s", // no detail
- "2 world 2s HELLO", // simple detail
- "3 truncated-detail 3s HELLO WORLD abcde...tuvwxyz1234567890", // truncated detail
- "4 long-status-eliminated-det...lmnopqrstuvwxyz1234567890 4s"
+ " 123/456 ======================= __.compile ====================== 1337s",
+ "1 hello 1s",
+ "2 world 2s HELLO",
+ "3 truncated-detail 3s HELLO WORLD abcdefghijklmnopqrstuvwxyz1234567890",
+ "4 long-status-eliminated-detail-abcdefghijklmnopqrstuvwxyz1234567890 4s.."
)
assert(rendered == expected)
}
@@ -322,8 +364,8 @@ object PromptLoggerUtilTests extends TestSuite {
)
val expected = List(
- " 123/456 __.compile....z1234567890 ================ 1337s",
- "#1 hello1234567890abcefghijk...abcefghijklmnopqrstuvwxyz 1s",
+ " 123/456 =============== __.compile....z1234567890 =============== 1337s",
+ "#1 hello1234567890abcefghijklmnopqr...4567890abcefghijklmnopqrstuvwxyz 1s",
"#3 i am cow 3s",
"",
"",
@@ -358,8 +400,8 @@ object PromptLoggerUtilTests extends TestSuite {
)
val expected = List(
- " 123/456 __.compile....z1234567890 ================ 1337s",
- "#1 hello1234567890abcefghijk...abcefghijklmnopqrstuvwxyz 1s",
+ " 123/456 =============== __.compile....z1234567890 =============== 1337s",
+ "#1 hello1234567890abcefghijklmnopqr...4567890abcefghijklmnopqrstuvwxyz 1s",
"#3 i am cow 3s"
)
@@ -410,11 +452,11 @@ object PromptLoggerUtilTests extends TestSuite {
// Make sure the non-interactive prompt does not show the blank lines,
// and it contains a footer line to mark the end of the prompt in logs
val expected = List(
- "123/456 __.compile.ab...xyz1234567890 ============== 1337s",
- "#1 hello1234567890abcefghijk...abcefghijklmnopqrstuvwxyz 1s",
+ "123/456 =============== __.compile.a...yz1234567890 =============== 1337s",
+ "#1 hello1234567890abcefghijklmnopqr...4567890abcefghijklmnopqrstuvwxyz 1s",
"#2 world 2s",
"#3 i am cow 3s",
- "==========================================================="
+ "========================================================================="
)
assert(rendered == expected)
}