feat(cli): Use ellipses when truncating progress (#15955)

### What does this PR try to resolve?

Use ellipses when truncating progress instead of three periods. While
this allows an extra two characters to fit on screen, the main
motivation it to reduce the visual quirkiness or the resulting output.

### How to test and review this PR?

This applies the review feedback left in #15330

Closes #15330
This commit is contained in:
Weihang Lo 2025-09-12 02:02:39 +00:00 committed by GitHub
commit faa4915898
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -75,6 +75,7 @@ struct Format {
max_width: usize,
max_print: usize,
term_integration: TerminalIntegration,
unicode: bool,
}
/// Controls terminal progress integration via OSC sequences.
@ -229,6 +230,7 @@ impl<'gctx> Progress<'gctx> {
// even on narrow (e.g. 80 char) terminals.
max_print: 50,
term_integration: TerminalIntegration::from_config(gctx),
unicode: gctx.shell().err_unicode(),
},
name: name.to_string(),
done: false,
@ -261,8 +263,7 @@ impl<'gctx> Progress<'gctx> {
/// * `cur` should be how far along the progress is.
/// * `max` is the maximum value for the progress bar.
/// * `msg` is a small piece of text to display at the end of the progress
/// bar. It will be truncated with `...` if it does not fit on the
/// terminal.
/// bar. It will be truncated with `…` if it does not fit on the terminal.
///
/// This may not actually update the display if `tick` is being called too
/// quickly.
@ -521,7 +522,10 @@ impl Format {
fn render(&self, string: &mut String, msg: &str) {
let mut avail_msg_len = self.max_width - string.len() - 15;
let mut ellipsis_pos = 0;
if avail_msg_len <= 3 {
let (ellipsis, ellipsis_width) = if self.unicode { ("", 1) } else { ("...", 3) };
if avail_msg_len <= ellipsis_width {
return;
}
for c in msg.chars() {
@ -529,12 +533,12 @@ impl Format {
if avail_msg_len >= display_width {
avail_msg_len -= display_width;
string.push(c);
if avail_msg_len >= 3 {
if avail_msg_len >= ellipsis_width {
ellipsis_pos = string.len();
}
} else {
string.truncate(ellipsis_pos);
string.push_str("...");
string.push_str(ellipsis);
break;
}
}
@ -569,6 +573,7 @@ fn test_progress_status() {
max_print: 40,
max_width: 60,
term_integration: TerminalIntegration::new(false),
unicode: true,
};
assert_eq!(
format.progress_status(0, 4, ""),
@ -610,7 +615,7 @@ fn test_progress_status() {
);
assert_eq!(
format.progress_status(3, 4, ": msg that's just fit"),
Some("[=============> ] 3/4: msg that's just...".to_string())
Some("[=============> ] 3/4: msg that's just f…".to_string())
);
// combining diacritics have width zero and thus can fit max_width.
@ -623,16 +628,16 @@ fn test_progress_status() {
// some non-ASCII ellipsize test
assert_eq!(
format.progress_status(3, 4, "_123456789123456e\u{301}\u{301}8\u{301}90a"),
Some("[=============> ] 3/4_123456789123456e\u{301}\u{301}...".to_string())
Some("[=============> ] 3/4_123456789123456e\u{301}\u{301}8\u{301}9…".to_string())
);
assert_eq!(
format.progress_status(3, 4, ":每個漢字佔據了兩個字元"),
Some("[=============> ] 3/4每個漢字佔據了...".to_string())
Some("[=============> ] 3/4每個漢字佔據了兩…".to_string())
);
assert_eq!(
// handle breaking at middle of character
format.progress_status(3, 4, "-每個漢字佔據了兩個字元"),
Some("[=============> ] 3/4-每個漢字佔據了...".to_string())
Some("[=============> ] 3/4-每個漢字佔據了兩…".to_string())
);
}
@ -643,6 +648,7 @@ fn test_progress_status_percentage() {
max_print: 40,
max_width: 60,
term_integration: TerminalIntegration::new(false),
unicode: true,
};
assert_eq!(
format.progress_status(0, 77, ""),
@ -669,6 +675,7 @@ fn test_progress_status_too_short() {
max_print: 25,
max_width: 25,
term_integration: TerminalIntegration::new(false),
unicode: true,
};
assert_eq!(
format.progress_status(1, 1, ""),
@ -680,6 +687,7 @@ fn test_progress_status_too_short() {
max_print: 24,
max_width: 24,
term_integration: TerminalIntegration::new(false),
unicode: true,
};
assert_eq!(format.progress_status(1, 1, ""), None);
}