gpui: Add truncate and text_ellipsis to TextStyle (#14850)

Release Notes:

- N/A

Ref issue #4996

## Demo

```
cargo run -p gpui --example text_wrapper 
```



https://github.com/user-attachments/assets/a7fcebf7-f287-4517-960d-76b12722a2d7

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
This commit is contained in:
Jason Lee 2024-08-24 02:02:51 +08:00 committed by GitHub
parent 12dda5fa1b
commit 938d93a64c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 238 additions and 66 deletions

View file

@ -1,4 +1,4 @@
use crate::{px, FontId, FontRun, Pixels, PlatformTextSystem};
use crate::{px, FontId, FontRun, Pixels, PlatformTextSystem, SharedString};
use collections::HashMap;
use std::{iter, sync::Arc};
@ -98,6 +98,32 @@ impl LineWrapper {
})
}
/// Truncate a line of text to the given width with this wrapper's font and font size.
pub fn truncate_line(
&mut self,
line: SharedString,
truncate_width: Pixels,
ellipsis: Option<&str>,
) -> SharedString {
let mut width = px(0.);
if let Some(ellipsis) = ellipsis {
for c in ellipsis.chars() {
width += self.width_for_char(c);
}
}
let mut char_indices = line.char_indices();
for (ix, c) in char_indices {
let char_width = self.width_for_char(c);
width += char_width;
if width > truncate_width {
return SharedString::from(format!("{}{}", &line[..ix], ellipsis.unwrap_or("")));
}
}
line.clone()
}
pub(crate) fn is_word_char(c: char) -> bool {
// ASCII alphanumeric characters, for English, numbers: `Hello123`, etc.
c.is_ascii_alphanumeric() ||
@ -181,8 +207,7 @@ mod tests {
use crate::{TextRun, WindowTextSystem, WrapBoundary};
use rand::prelude::*;
#[test]
fn test_wrap_line() {
fn build_wrapper() -> LineWrapper {
let dispatcher = TestDispatcher::new(StdRng::seed_from_u64(0));
let cx = TestAppContext::new(dispatcher, None);
cx.text_system()
@ -193,63 +218,90 @@ mod tests {
.into()])
.unwrap();
let id = cx.text_system().font_id(&font("Zed Plex Mono")).unwrap();
LineWrapper::new(id, px(16.), cx.text_system().platform_text_system.clone())
}
cx.update(|cx| {
let text_system = cx.text_system().clone();
let mut wrapper =
LineWrapper::new(id, px(16.), text_system.platform_text_system.clone());
assert_eq!(
wrapper
.wrap_line("aa bbb cccc ddddd eeee", px(72.))
.collect::<Vec<_>>(),
&[
Boundary::new(7, 0),
Boundary::new(12, 0),
Boundary::new(18, 0)
],
);
assert_eq!(
wrapper
.wrap_line("aaa aaaaaaaaaaaaaaaaaa", px(72.0))
.collect::<Vec<_>>(),
&[
Boundary::new(4, 0),
Boundary::new(11, 0),
Boundary::new(18, 0)
],
);
assert_eq!(
wrapper
.wrap_line(" aaaaaaa", px(72.))
.collect::<Vec<_>>(),
&[
Boundary::new(7, 5),
Boundary::new(9, 5),
Boundary::new(11, 5),
]
);
assert_eq!(
wrapper
.wrap_line(" ", px(72.))
.collect::<Vec<_>>(),
&[
Boundary::new(7, 0),
Boundary::new(14, 0),
Boundary::new(21, 0)
]
);
assert_eq!(
wrapper
.wrap_line(" aaaaaaaaaaaaaa", px(72.))
.collect::<Vec<_>>(),
&[
Boundary::new(7, 0),
Boundary::new(14, 3),
Boundary::new(18, 3),
Boundary::new(22, 3),
]
);
});
#[test]
fn test_wrap_line() {
let mut wrapper = build_wrapper();
assert_eq!(
wrapper
.wrap_line("aa bbb cccc ddddd eeee", px(72.))
.collect::<Vec<_>>(),
&[
Boundary::new(7, 0),
Boundary::new(12, 0),
Boundary::new(18, 0)
],
);
assert_eq!(
wrapper
.wrap_line("aaa aaaaaaaaaaaaaaaaaa", px(72.0))
.collect::<Vec<_>>(),
&[
Boundary::new(4, 0),
Boundary::new(11, 0),
Boundary::new(18, 0)
],
);
assert_eq!(
wrapper
.wrap_line(" aaaaaaa", px(72.))
.collect::<Vec<_>>(),
&[
Boundary::new(7, 5),
Boundary::new(9, 5),
Boundary::new(11, 5),
]
);
assert_eq!(
wrapper
.wrap_line(" ", px(72.))
.collect::<Vec<_>>(),
&[
Boundary::new(7, 0),
Boundary::new(14, 0),
Boundary::new(21, 0)
]
);
assert_eq!(
wrapper
.wrap_line(" aaaaaaaaaaaaaa", px(72.))
.collect::<Vec<_>>(),
&[
Boundary::new(7, 0),
Boundary::new(14, 3),
Boundary::new(18, 3),
Boundary::new(22, 3),
]
);
}
#[test]
fn test_truncate_line() {
let mut wrapper = build_wrapper();
assert_eq!(
wrapper.truncate_line("aa bbb cccc ddddd eeee ffff gggg".into(), px(220.), None),
"aa bbb cccc ddddd eeee"
);
assert_eq!(
wrapper.truncate_line(
"aa bbb cccc ddddd eeee ffff gggg".into(),
px(220.),
Some("")
),
"aa bbb cccc ddddd eee…"
);
assert_eq!(
wrapper.truncate_line(
"aa bbb cccc ddddd eeee ffff gggg".into(),
px(220.),
Some("......")
),
"aa bbb cccc dddd......"
);
}
#[test]