use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use unicode_width::UnicodeWidthStr;
pub const UNICODE_BASELINE: (u8, u8, u8) = (11, 0, 0);
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct GlyphInfo {
pub width: u8,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RenderProfile {
pub id: String,
pub version: u32,
pub glyphs: BTreeMap<String, GlyphInfo>,
}
#[derive(Debug, Clone)]
pub struct GlyphRegistry {
profile: RenderProfile,
}
impl GlyphRegistry {
pub fn new(profile: RenderProfile) -> Self {
Self { profile }
}
pub fn profile(&self) -> &RenderProfile {
&self.profile
}
pub fn width(&self, grapheme: &str) -> u8 {
if let Some(info) = self.profile.glyphs.get(grapheme) {
return info.width.clamp(1, 2);
}
let w = UnicodeWidthStr::width(grapheme);
let w = if w == 0 { 1 } else { w };
(w.min(2)) as u8
}
}
impl RenderProfile {
pub fn empty(id: impl Into<String>, version: u32) -> Self {
Self {
id: id.into(),
version,
glyphs: BTreeMap::new(),
}
}
pub fn bbsstalgia_xtermjs_unicode11_example() -> Self {
let mut p = RenderProfile::empty("bbsstalgia-xtermjs-unicode11", 1);
p.set_width("🙂", 2);
p.set_width("⚙️", 2);
p.set_width("🧠", 2);
p.set_width("❤", 1);
p
}
}
impl RenderProfile {
pub fn set_width(&mut self, glyph: impl Into<String>, width: u8) {
let w = width.clamp(1, 2);
self.glyphs.insert(glyph.into(), GlyphInfo { width: w });
}
pub fn merge_glyphs_from(&mut self, other: &RenderProfile) {
for (g, info) in &other.glyphs {
self.glyphs.insert(g.clone(), info.clone());
}
}
}