From 994a2196745637fd0805132711b1ed9354b75426 Mon Sep 17 00:00:00 2001 From: salmonik Date: Fri, 31 Jul 2026 17:28:31 +0200 Subject: vt: decode UTF-8, render box-drawing/arrow glyphs procedurally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The editor's gutter '│' (U+2502) appeared as '???' — write_bytes fed each UTF-8 byte to the state machine, which mapped every byte >= 0x80 to '?', and the Latin-1 font has no box-drawing glyphs anyway. - vt.write_bytes now decodes UTF-8 sequences; printable non-ASCII dispatches to the glyph path instead of the byte parser. - gop: unicode_glyph_bits() procedurally rasterises box-drawing (U+2500-257F light/heavy/double), arrows (U+2190-2193) and the em dash (U+2014) — pure geometry, no font data needed; blit_glyph falls back to it for ch >= 256. Verified via framebuffer dumps: editor gutter │ renders as a vertical line, help screen ═ separators and ←→↑↓ all render as lines (no '?'). Shell banner em dash renders too. --- rsnix/src/gop.rs | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 157 insertions(+), 4 deletions(-) (limited to 'rsnix/src/gop.rs') diff --git a/rsnix/src/gop.rs b/rsnix/src/gop.rs index 81b8945..9cb0d7d 100644 --- a/rsnix/src/gop.rs +++ b/rsnix/src/gop.rs @@ -135,13 +135,166 @@ impl Framebuffer { } /// Blit one glyph cell at (col, row) with explicit fg/bg colours. +/// Procedurally-rendered bitmaps for Unicode glyphs missing from the +/// 256-glyph Latin-1 font: box-drawing (U+2500–U+257F), arrows +/// (U+2190–U+2193) and the em dash (U+2014). Box drawing is pure +/// geometry, so these are computed, not stored. Same format as the font: +/// one byte per row, bit 7 = leftmost column. +fn unicode_glyph_bits(ch: u16) -> Option<[u8; 16]> { + let mut g = [0u8; 16]; + match ch { + // ─ light horizontal, ━ heavy horizontal + 0x2500 => { + g[7] = 0xFF; + g[8] = 0xFF; + } + 0x2501 => { + g[7] = 0xFF; + g[8] = 0xFF; + g[9] = 0xFF; + } + // │ light vertical, ┃ heavy vertical + 0x2502 => { + for y in 0..16 { + g[y] = 0x18; + } + } + 0x2503 => { + for y in 0..16 { + g[y] = 0x3C; + } + } + // corners ┌ ┐ └ ┘ + 0x250C => { + g[7] = 0xF0; + g[8] = 0xF8; + for y in 9..16 { + g[y] = 0x18; + } + } + 0x2510 => { + g[7] = 0x0F; + g[8] = 0x1F; + for y in 9..16 { + g[y] = 0x18; + } + } + 0x2514 => { + for y in 0..7 { + g[y] = 0x18; + } + g[7] = 0xF8; + g[8] = 0xF0; + } + 0x2518 => { + for y in 0..7 { + g[y] = 0x18; + } + g[7] = 0x1F; + g[8] = 0x0F; + } + // T junctions ├ ┤ ┬ ┴ and cross ┼ + 0x251C => { + for y in 0..16 { + g[y] = 0x18; + } + g[7] = 0xF8; + g[8] = 0xF8; + } + 0x2524 => { + for y in 0..16 { + g[y] = 0x18; + } + g[7] = 0x1F; + g[8] = 0x1F; + } + 0x252C => { + g[7] = 0xFF; + g[8] = 0xFF; + for y in 9..16 { + g[y] = 0x18; + } + } + 0x2534 => { + for y in 0..7 { + g[y] = 0x18; + } + g[7] = 0xFF; + g[8] = 0xFF; + } + 0x253C => { + for y in 0..16 { + g[y] = 0x18; + } + g[7] = 0xFF; + g[8] = 0xFF; + } + // ═ double horizontal, ║ double vertical + 0x2550 => { + g[6] = 0xFF; + g[9] = 0xFF; + } + 0x2551 => { + for y in 0..16 { + g[y] = 0x24; + } + } + // — em dash + 0x2014 => { + g[7] = 0xFF; + g[8] = 0xFF; + } + // ← → ↑ ↓ + 0x2190 => { + g[8] = 0xFF; + g[6] = 0xC0; + g[7] = 0xC0; + g[9] = 0xC0; + g[10] = 0xC0; + } + 0x2192 => { + g[8] = 0xFF; + g[6] = 0x03; + g[7] = 0x03; + g[9] = 0x03; + g[10] = 0x03; + } + 0x2191 => { + g[0] = 0x18; + g[1] = 0x3C; + g[2] = 0x7E; + for y in 3..16 { + g[y] = 0x18; + } + } + 0x2193 => { + for y in 0..13 { + g[y] = 0x18; + } + g[13] = 0x7E; + g[14] = 0x3C; + g[15] = 0x18; + } + _ => return None, + } + Some(g) +} + pub(crate) fn blit_glyph(col: usize, row: usize, ch: u16, fg: (u8, u8, u8), bg: (u8, u8, u8)) { if let Some(fb) = unsafe { FB.as_ref() } { - let glyph_idx = if ch < 256 { ch as usize } else { 32 }; let glyph = font::GLYPH_8X16; - let data = match glyph.get(glyph_idx) { - Some(d) => *d, - None => return, + let data = if ch < 256 { + match glyph.get(ch as usize) { + Some(d) => *d, + None => return, + } + } else if let Some(bits) = unicode_glyph_bits(ch) { + bits + } else { + match glyph.get(32) { + Some(d) => *d, + None => return, + } }; let fg = rgb(fg.0, fg.1, fg.2); -- cgit v1.2.3