From 9595fcedb01ea378d890a9821d5ad8c334b80cb9 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 5 Feb 2024 23:49:30 +0900 Subject: [PATCH] Update terminal width when progress animation is updated (#463) Without updating the terminal width for each progress update, a progress line may be printed as more than one line, so line clearing will not work as expected and many lines will be printed when overflowing max columns of line. Ninja also checks the terminal width every line print: https://github.com/ninja-build/ninja/blob/fd7067652cae480190bf13b2ee5475efdf09ac7d/src/line_printer.cc#L110 This particularly improves the build and test progress report of SwiftPM. **Before** https://github.com/apple/swift-tools-support-core/assets/11702759/7c32c2d5-0469-479b-a542-6ffd0656610a **After** https://github.com/apple/swift-tools-support-core/assets/11702759/71e6ce59-f888-4a19-819a-3012c9ea378f --- Sources/TSCBasic/TerminalController.swift | 16 ++++++++-------- Sources/TSCUtility/ProgressAnimation.swift | 14 ++++++++------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Sources/TSCBasic/TerminalController.swift b/Sources/TSCBasic/TerminalController.swift index 19556e58..e7b9bf6f 100644 --- a/Sources/TSCBasic/TerminalController.swift +++ b/Sources/TSCBasic/TerminalController.swift @@ -64,7 +64,14 @@ public final class TerminalController { private var stream: WritableByteStream /// Width of the terminal. - public let width: Int + public var width: Int { + // Determine the terminal width otherwise assume a default. + if let terminalWidth = TerminalController.terminalWidth(), terminalWidth > 0 { + return terminalWidth + } else { + return 80 + } + } /// Code to clear the line on a tty. private let clearLineString = "\u{001B}[2K" @@ -84,13 +91,6 @@ public final class TerminalController { return nil } - // Determine the terminal width otherwise assume a default. - if let terminalWidth = TerminalController.terminalWidth(), terminalWidth > 0 { - width = terminalWidth - } else { - width = 80 - } - #if os(Windows) // Enable VT100 interpretation let hOut = GetStdHandle(STD_OUTPUT_HANDLE) diff --git a/Sources/TSCUtility/ProgressAnimation.swift b/Sources/TSCUtility/ProgressAnimation.swift index c0383531..ced8c27b 100644 --- a/Sources/TSCUtility/ProgressAnimation.swift +++ b/Sources/TSCUtility/ProgressAnimation.swift @@ -117,9 +117,10 @@ public final class RedrawingNinjaProgressAnimation: ProgressAnimationProtocol { terminal.clearLine() let progressText = "[\(step)/\(total)] \(text)" - if progressText.utf8.count > terminal.width { + let width = terminal.width + if progressText.utf8.count > width { let suffix = "…" - terminal.write(String(progressText.prefix(terminal.width - suffix.utf8.count))) + terminal.write(String(progressText.prefix(width - suffix.utf8.count))) terminal.write(suffix) } else { terminal.write(progressText) @@ -211,8 +212,9 @@ public final class RedrawingLitProgressAnimation: ProgressAnimationProtocol { public func update(step: Int, total: Int, text: String) { assert(step <= total) + let width = terminal.width if !hasDisplayedHeader { - let spaceCount = terminal.width / 2 - header.utf8.count / 2 + let spaceCount = width / 2 - header.utf8.count / 2 terminal.write(repeating(string: " ", count: spaceCount)) terminal.write(header, inColor: .cyan, bold: true) terminal.endLine() @@ -225,7 +227,7 @@ public final class RedrawingLitProgressAnimation: ProgressAnimationProtocol { let prefix = "\(paddedPercentage)% " + terminal.wrap("[", inColor: .green, bold: true) terminal.write(prefix) - let barWidth = terminal.width - prefix.utf8.count + let barWidth = width - prefix.utf8.count let n = Int(Double(barWidth) * Double(percentage) / 100.0) terminal.write(repeating(string: "=", count: n) + repeating(string: "-", count: barWidth - n), inColor: .green) @@ -233,10 +235,10 @@ public final class RedrawingLitProgressAnimation: ProgressAnimationProtocol { terminal.endLine() terminal.clearLine() - if text.utf8.count > terminal.width { + if text.utf8.count > width { let prefix = "…" terminal.write(prefix) - terminal.write(String(text.suffix(terminal.width - prefix.utf8.count))) + terminal.write(String(text.suffix(width - prefix.utf8.count))) } else { terminal.write(text) }