diff --git a/src/abbrev.rs b/src/abbrev.rs new file mode 100644 index 00000000..7f5b71f9 --- /dev/null +++ b/src/abbrev.rs @@ -0,0 +1,20 @@ +#[inline] +pub fn floor_char_boundary(s: &str, index: usize) -> usize { + if index >= s.len() { + s.len() + } else { + let lower_bound = index.saturating_sub(3); + let new_index = s.as_bytes()[lower_bound..=index] + .iter() + .rposition(|b| is_utf8_char_boundary(*b)); + + // SAFETY: we know that the character boundary will be within four bytes + unsafe { lower_bound + new_index.unwrap_unchecked() } + } +} + +#[inline] +fn is_utf8_char_boundary(c: u8) -> bool { + // This is bit magic equivalent to: b < 128 || b >= 192 + (c as i8) >= -0x40 +} diff --git a/src/app.rs b/src/app.rs index 54960119..ef7ce1bf 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,3 +1,4 @@ +use crate::abbrev; use crate::contacts::Contacts; use crate::fonts::setup_fonts; use crate::images::fetch_img; @@ -321,6 +322,16 @@ fn pfp_image(ui: &mut egui::Ui, img: TextureId, size: f32) -> egui::Response { //.with_options() } +fn ui_abbreviate_name(ui: &mut egui::Ui, name: &str, len: usize) { + if name.len() > len { + let closest = abbrev::floor_char_boundary(name, len); + ui.strong(&name[..closest]); + ui.strong("..."); + } else { + ui.strong(name); + } +} + fn render_username(ui: &mut egui::Ui, contacts: &Contacts, pk: &Pubkey) { #[cfg(feature = "profiling")] puffin::profile_function!(); @@ -329,7 +340,7 @@ fn render_username(ui: &mut egui::Ui, contacts: &Contacts, pk: &Pubkey) { //ui.spacing_mut().item_spacing.x = 0.0; if let Some(prof) = contacts.profiles.get(pk) { if let Some(display_name) = prof.display_name() { - ui.strong(display_name); + ui_abbreviate_name(ui, &display_name, 20); } } else { ui.strong("nostrich"); diff --git a/src/lib.rs b/src/lib.rs index 74e9d5a8..787fe425 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ mod contacts; mod error; //mod note; //mod block; +mod abbrev; mod fonts; mod images; mod result;