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:
parent
12dda5fa1b
commit
938d93a64c
11 changed files with 238 additions and 66 deletions
|
@ -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]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue