summaryrefslogtreecommitdiffstats
path: root/rsnix/src/gop.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-07-31 17:28:31 +0200
committersalmonik <salmonik@tuta.io>2026-07-31 17:28:31 +0200
commit994a2196745637fd0805132711b1ed9354b75426 (patch)
treec666940f060aa8db028c75fd3aef799fabbd69b4 /rsnix/src/gop.rs
parenttty + vt terminal split, rsdosedit editor (1:1 UNIX console) (diff)
downloadrs-dos-994a2196745637fd0805132711b1ed9354b75426.tar.gz
rs-dos-994a2196745637fd0805132711b1ed9354b75426.zip
vt: decode UTF-8, render box-drawing/arrow glyphs procedurally
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.
Diffstat (limited to 'rsnix/src/gop.rs')
-rw-r--r--rsnix/src/gop.rs161
1 files changed, 157 insertions, 4 deletions
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 {
135} 135}
136 136
137/// Blit one glyph cell at (col, row) with explicit fg/bg colours. 137/// Blit one glyph cell at (col, row) with explicit fg/bg colours.
138/// Procedurally-rendered bitmaps for Unicode glyphs missing from the
139/// 256-glyph Latin-1 font: box-drawing (U+2500–U+257F), arrows
140/// (U+2190–U+2193) and the em dash (U+2014). Box drawing is pure
141/// geometry, so these are computed, not stored. Same format as the font:
142/// one byte per row, bit 7 = leftmost column.
143fn unicode_glyph_bits(ch: u16) -> Option<[u8; 16]> {
144 let mut g = [0u8; 16];
145 match ch {
146 // ─ light horizontal, ━ heavy horizontal
147 0x2500 => {
148 g[7] = 0xFF;
149 g[8] = 0xFF;
150 }
151 0x2501 => {
152 g[7] = 0xFF;
153 g[8] = 0xFF;
154 g[9] = 0xFF;
155 }
156 // │ light vertical, ┃ heavy vertical
157 0x2502 => {
158 for y in 0..16 {
159 g[y] = 0x18;
160 }
161 }
162 0x2503 => {
163 for y in 0..16 {
164 g[y] = 0x3C;
165 }
166 }
167 // corners ┌ ┐ └ ┘
168 0x250C => {
169 g[7] = 0xF0;
170 g[8] = 0xF8;
171 for y in 9..16 {
172 g[y] = 0x18;
173 }
174 }
175 0x2510 => {
176 g[7] = 0x0F;
177 g[8] = 0x1F;
178 for y in 9..16 {
179 g[y] = 0x18;
180 }
181 }
182 0x2514 => {
183 for y in 0..7 {
184 g[y] = 0x18;
185 }
186 g[7] = 0xF8;
187 g[8] = 0xF0;
188 }
189 0x2518 => {
190 for y in 0..7 {
191 g[y] = 0x18;
192 }
193 g[7] = 0x1F;
194 g[8] = 0x0F;
195 }
196 // T junctions ├ ┤ ┬ ┴ and cross ┼
197 0x251C => {
198 for y in 0..16 {
199 g[y] = 0x18;
200 }
201 g[7] = 0xF8;
202 g[8] = 0xF8;
203 }
204 0x2524 => {
205 for y in 0..16 {
206 g[y] = 0x18;
207 }
208 g[7] = 0x1F;
209 g[8] = 0x1F;
210 }
211 0x252C => {
212 g[7] = 0xFF;
213 g[8] = 0xFF;
214 for y in 9..16 {
215 g[y] = 0x18;
216 }
217 }
218 0x2534 => {
219 for y in 0..7 {
220 g[y] = 0x18;
221 }
222 g[7] = 0xFF;
223 g[8] = 0xFF;
224 }
225 0x253C => {
226 for y in 0..16 {
227 g[y] = 0x18;
228 }
229 g[7] = 0xFF;
230 g[8] = 0xFF;
231 }
232 // ═ double horizontal, ║ double vertical
233 0x2550 => {
234 g[6] = 0xFF;
235 g[9] = 0xFF;
236 }
237 0x2551 => {
238 for y in 0..16 {
239 g[y] = 0x24;
240 }
241 }
242 // — em dash
243 0x2014 => {
244 g[7] = 0xFF;
245 g[8] = 0xFF;
246 }
247 // ← → ↑ ↓
248 0x2190 => {
249 g[8] = 0xFF;
250 g[6] = 0xC0;
251 g[7] = 0xC0;
252 g[9] = 0xC0;
253 g[10] = 0xC0;
254 }
255 0x2192 => {
256 g[8] = 0xFF;
257 g[6] = 0x03;
258 g[7] = 0x03;
259 g[9] = 0x03;
260 g[10] = 0x03;
261 }
262 0x2191 => {
263 g[0] = 0x18;
264 g[1] = 0x3C;
265 g[2] = 0x7E;
266 for y in 3..16 {
267 g[y] = 0x18;
268 }
269 }
270 0x2193 => {
271 for y in 0..13 {
272 g[y] = 0x18;
273 }
274 g[13] = 0x7E;
275 g[14] = 0x3C;
276 g[15] = 0x18;
277 }
278 _ => return None,
279 }
280 Some(g)
281}
282
138pub(crate) fn blit_glyph(col: usize, row: usize, ch: u16, fg: (u8, u8, u8), bg: (u8, u8, u8)) { 283pub(crate) fn blit_glyph(col: usize, row: usize, ch: u16, fg: (u8, u8, u8), bg: (u8, u8, u8)) {
139 if let Some(fb) = unsafe { FB.as_ref() } { 284 if let Some(fb) = unsafe { FB.as_ref() } {
140 let glyph_idx = if ch < 256 { ch as usize } else { 32 };
141 let glyph = font::GLYPH_8X16; 285 let glyph = font::GLYPH_8X16;
142 let data = match glyph.get(glyph_idx) { 286 let data = if ch < 256 {
143 Some(d) => *d, 287 match glyph.get(ch as usize) {
144 None => return, 288 Some(d) => *d,
289 None => return,
290 }
291 } else if let Some(bits) = unicode_glyph_bits(ch) {
292 bits
293 } else {
294 match glyph.get(32) {
295 Some(d) => *d,
296 None => return,
297 }
145 }; 298 };
146 299
147 let fg = rgb(fg.0, fg.1, fg.2); 300 let fg = rgb(fg.0, fg.1, fg.2);