mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-21 16:02:20 +00:00
fix(completion): a description with a newline broke its menu row
`elide` exists to make a completion description fit one row, and it only
ever bounded the length. A newline defeats the row at any length: gpui
breaks on it whatever the row says, so the description grows a second
line and its tail paints over whatever the menu is floating above.
This is shipped data, not a hypothetical. 122 of the specs in
`assets/completions` carry a newline in a description, and the break is
early enough to land inside the budget the menu hands out: ten of them
break before column 30. `go build -race` opens "Enable data race
detection." and breaks at column 27.
Folding in `elide` rather than at the call site, because every caller of
it wants one line by definition — and because the early return for text
already under budget was the path that handed a newline straight back
untouched, which a fix at the call site would have had to remember.
One cluster in, one cluster out, so the budget still measures what is
drawn.
Found by finishing the enumeration 1c203cc started, this time by asking
which *data source* a drawn string comes from rather than which module
draws it. Completion descriptions come from spec files, and 97 of those
ship in this repo.
This commit is contained in:
@@ -6561,7 +6561,16 @@ fn description_budget(cell_width: f32, label_cells: usize, menu_w: f32) -> usize
|
||||
/// explains: a completion description is arbitrary text from a shell plugin,
|
||||
/// and cutting a cluster in half renders as a character the description never
|
||||
/// contained.
|
||||
///
|
||||
/// The line breaks go first, for the same reason and a nearer one: this exists
|
||||
/// to make a description fit a row, and a newline defeats that at any length.
|
||||
/// 122 of the specs shipped in `assets/completions` carry one — `go build
|
||||
/// -race` opens "Enable data race detection." and breaks at column 27, inside
|
||||
/// any budget this menu hands out — so without the fold the row grows and its
|
||||
/// tail paints over whatever the menu is floating above. Folding is one
|
||||
/// cluster for one cluster, so the budget still measures what is drawn.
|
||||
fn elide(text: &str, budget: usize) -> String {
|
||||
let text = one_line(text);
|
||||
let clusters: Vec<&str> = text.graphemes(true).collect();
|
||||
if clusters.len() <= budget {
|
||||
return text.to_string();
|
||||
@@ -8060,6 +8069,21 @@ mod tests {
|
||||
assert_eq!(elide("abcd", 4), "abcd");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_description_that_carries_a_line_break_still_draws_on_one_row() {
|
||||
// Verbatim from `assets/completions/go.json`, which is one of 122
|
||||
// shipped specs whose descriptions contain a newline. Nothing about
|
||||
// the budget saves this: the break is at column 27.
|
||||
let out = elide("Enable data race detection.\nSee more at docs.", 40);
|
||||
assert!(!out.contains('\n'), "{out:?}");
|
||||
assert!(out.starts_with("Enable data race detection.↵"), "{out:?}");
|
||||
|
||||
// Under budget is the case that used to slip through untouched — the
|
||||
// early return handed the text straight back, newline and all.
|
||||
let short = elide("a\nb", 40);
|
||||
assert_eq!(short, "a↵b");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_elided_description_spends_its_budget_on_whole_clusters() {
|
||||
use unicode_segmentation::UnicodeSegmentation as _;
|
||||
|
||||
Reference in New Issue
Block a user