notecrumbs

a nostr opengraph server build on nostrdb and egui
git clone git://jb55.com/notecrumbs
Log | Files | Refs | README | LICENSE

commit 0e7b8d7c98dc72a49a89233c736766691c1536b6
parent 83e63394e8bfbec3e1cf290976a470f30a20f2b5
Author: William Casarin <jb55@jb55.com>
Date:   Mon,  1 Jan 2024 09:06:02 -0800

render mentions in previews

Diffstat:
Msrc/render.rs | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 107 insertions(+), 32 deletions(-)

diff --git a/src/render.rs b/src/render.rs @@ -301,9 +301,77 @@ fn setup_visuals(font_data: &egui::FontData, ctx: &egui::Context) { fonts::setup_fonts(font_data, ctx); } -fn wrapped_body_blocks(ui: &mut egui::Ui, note: &Note, blocks: &Blocks) { - let size = 50.0; +fn push_job_text(job: &mut LayoutJob, s: &str, color: Color32) { + job.append( + s, + 0.0, + TextFormat { + font_id: FontId::new(50.0, FontFamily::Proportional), + color, + ..Default::default() + }, + ) +} + +#[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 +} + +const ABBREV_SIZE: usize = 10; + +fn abbrev_str(name: &str) -> String { + if name.len() > ABBREV_SIZE { + let closest = floor_char_boundary(name, ABBREV_SIZE); + format!("{}...", &name[..closest]) + } else { + name.to_owned() + } +} + +fn push_job_user_mention( + job: &mut LayoutJob, + ndb: &Ndb, + block: &Block, + txn: &Transaction, + pk: &[u8; 32], +) { + let record = ndb.get_profile_by_pubkey(&txn, pk); + if let Ok(record) = record { + let profile = record.record.profile().unwrap(); + push_job_text( + job, + &format!("@{}", &abbrev_str(profile.name().unwrap_or("nostrich"))), + PURPLE, + ); + } else { + push_job_text(job, &format!("@{}", &abbrev_str(block.as_str())), PURPLE); + } +} +fn wrapped_body_blocks( + ui: &mut egui::Ui, + ndb: &Ndb, + note: &Note, + blocks: &Blocks, + txn: &Transaction, +) { let mut job = LayoutJob::default(); job.justify = false; job.halign = egui::Align::LEFT; @@ -314,39 +382,46 @@ fn wrapped_body_blocks(ui: &mut egui::Ui, note: &Note, blocks: &Blocks) { ..Default::default() }; - let purple = Color32::from_rgb(0xcc, 0x43, 0xc5); - for block in blocks.iter(note) { match block.blocktype() { - BlockType::Url => job.append( - block.as_str(), - 0.0, - TextFormat { - font_id: FontId::new(size, FontFamily::Proportional), - color: purple, - ..Default::default() - }, - ), + BlockType::Url => push_job_text(&mut job, block.as_str(), PURPLE), - BlockType::Hashtag => job.append( - &format!("#{}", block.as_str()), - 0.0, - TextFormat { - font_id: FontId::new(size, FontFamily::Proportional), - color: purple, - ..Default::default() - }, - ), + BlockType::Hashtag => { + push_job_text(&mut job, "#", PURPLE); + push_job_text(&mut job, block.as_str(), PURPLE); + } - _ => job.append( - block.as_str(), - 0.0, - TextFormat { - font_id: FontId::new(size, FontFamily::Proportional), - color: Color32::WHITE, - ..Default::default() - }, - ), + BlockType::MentionBech32 => { + let pk = match block.as_mention().unwrap() { + Mention::Event(ev) => push_job_text( + &mut job, + &format!("@{}", &abbrev_str(block.as_str())), + PURPLE, + ), + Mention::Note(ev) => { + push_job_text( + &mut job, + &format!("@{}", &abbrev_str(block.as_str())), + PURPLE, + ); + } + Mention::Profile(nprofile) => { + push_job_user_mention(&mut job, ndb, &block, &txn, nprofile.pubkey()) + } + Mention::Pubkey(npub) => { + push_job_user_mention(&mut job, ndb, &block, &txn, npub.pubkey()) + } + Mention::Secret(sec) => push_job_text(&mut job, "--redacted--", PURPLE), + Mention::Relay(relay) => { + push_job_text(&mut job, &abbrev_str(block.as_str()), PURPLE) + } + Mention::Addr(addr) => { + push_job_text(&mut job, &abbrev_str(block.as_str()), PURPLE) + } + }; + } + + _ => push_job_text(&mut job, block.as_str(), Color32::WHITE), }; } @@ -444,7 +519,7 @@ fn note_ui(app: &Notecrumbs, ctx: &egui::Context, note: &NoteRenderData) { let blocks = app.ndb.get_blocks_by_key(&txn, note.key().unwrap())?; - wrapped_body_blocks(ui, &note, &blocks); + wrapped_body_blocks(ui, &app.ndb, &note, &blocks, &txn); Ok(()) })();