diff options
| author | salmonik <salmonik@tuta.io> | 2026-07-31 17:19:09 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-07-31 17:19:09 +0200 |
| commit | fa06681a8418b7e31af96e010bb424e178402f4d (patch) | |
| tree | 3b2fa8674384078f73b62274c71e8279ca6d0644 /rsnix/src/ps2.rs | |
| parent | shell: ^C cancels the line / aborts streams, ^D = EOF → poweroff (diff) | |
| download | rs-dos-fa06681a8418b7e31af96e010bb424e178402f4d.tar.gz rs-dos-fa06681a8418b7e31af96e010bb424e178402f4d.zip | |
tty + vt terminal split, rsdosedit editor (1:1 UNIX console)
Kernel now has the classic UNIX console split, so full-screen ANSI apps
can run in ring 0:
- vt.rs: terminal emulator owning the text screen — cell grid (char +
fg/bg), logical cursor (inverse-video), scrolling, and a small ANSI
CSI parser (cursor position H/f, erase J/K, moves A-D, SGR 16-colour
with correct ANSI→VGA mapping, cursor show/hide ?25). Blits only
changed cells; scroll shifts cell grids + pixels and re-rasterises
only the exposed bottom row. gop_println!/clear_screen now render
through the vt; gop.rs is the raw rasteriser (colored glyph blits,
pixel shift).
- tty.rs: line discipline — canonical read_line (echo, line buffer,
^C cancel, ^D EOF) moved out of the shell, and raw read_byte that
translates KeyEvents to the terminal byte protocol (arrows → ESC[A-D,
Backspace → 0x7f, ^X → 0x18, Ctrl+arrows → ESC[1;5A-D, Home/End/PgUp/
PgDn/Delete). interrupt_pressed() stays for streaming commands.
- ps2: generic Ctrl(char) + CtrlArrow events (was: only CtrlC/CtrlD).
- rsdosedit: no_std port of the RNG rsedit editor as the first real
app — undo, syntax highlighting (verified green/gray/yellow on the
framebuffer), search, word nav, smart indent, ^S save / ^X exit /
^X again to discard. termios → tty raw, stdout → vt, std::fs → VFS
(ramfs), SIGWINCH → fixed geometry, force-exit window → key counter.
- shell: 'edit <path>' command; read_line/strbuf moved to rsnix.
- CONTEXT.md: layout + milestones + known-issue perf notes.
Verified in QEMU: full edit → type → arrow-move → insert → save → exit
round trip with byte-exact file content; ANSI colors via screendump.
Diffstat (limited to 'rsnix/src/ps2.rs')
| -rw-r--r-- | rsnix/src/ps2.rs | 31 |
1 files changed, 20 insertions, 11 deletions
diff --git a/rsnix/src/ps2.rs b/rsnix/src/ps2.rs index 1b10b3b..8dd58a0 100644 --- a/rsnix/src/ps2.rs +++ b/rsnix/src/ps2.rs | |||
| @@ -22,8 +22,10 @@ pub enum KeyEvent { | |||
| 22 | Backspace, | 22 | Backspace, |
| 23 | Tab, | 23 | Tab, |
| 24 | Escape, | 24 | Escape, |
| 25 | CtrlC, | 25 | /// Ctrl + key (e.g. Ctrl('c') = ^C, Ctrl('s') = ^S). |
| 26 | CtrlD, | 26 | Ctrl(char), |
| 27 | /// Ctrl + arrow (0=up, 1=down, 2=left, 3=right) — word/page nav. | ||
| 28 | CtrlArrow(u8), | ||
| 27 | ArrowUp, | 29 | ArrowUp, |
| 28 | ArrowDown, | 30 | ArrowDown, |
| 29 | ArrowLeft, | 31 | ArrowLeft, |
| @@ -306,13 +308,14 @@ fn process_byte(byte: u8) -> Option<KeyEvent> { | |||
| 306 | ch.to_ascii_uppercase() | 308 | ch.to_ascii_uppercase() |
| 307 | }; | 309 | }; |
| 308 | } | 310 | } |
| 309 | // Ctrl+letter — the shell uses ^C (interrupt) and ^D (EOF). | 311 | // Ctrl+key — the terminal control-byte protocol (^C, ^D, ^S, ^X, …). |
| 310 | let ctrl = state.modifiers & (MOD_LCTRL | MOD_RCTRL) != 0; | 312 | let ctrl = state.modifiers & (MOD_LCTRL | MOD_RCTRL) != 0; |
| 311 | if ctrl { | 313 | if ctrl { |
| 312 | return match ch.to_ascii_lowercase() { | 314 | let lc = ch.to_ascii_lowercase(); |
| 313 | b'c' => Some(KeyEvent::CtrlC), | 315 | return if lc.is_ascii_graphic() { |
| 314 | b'd' => Some(KeyEvent::CtrlD), | 316 | Some(KeyEvent::Ctrl(lc as char)) |
| 315 | _ => None, // swallow other Ctrl+key combinations | 317 | } else { |
| 318 | None // swallow non-graphic Ctrl combos | ||
| 316 | }; | 319 | }; |
| 317 | } | 320 | } |
| 318 | if ch != 0 { | 321 | if ch != 0 { |
| @@ -334,10 +337,10 @@ fn process_e0(byte: u8) -> Option<KeyEvent> { | |||
| 334 | update_modifiers(byte, true, true); | 337 | update_modifiers(byte, true, true); |
| 335 | 338 | ||
| 336 | match byte { | 339 | match byte { |
| 337 | 0x48 => Some(KeyEvent::ArrowUp), | 340 | 0x48 => Some(if ctrl_held() { KeyEvent::CtrlArrow(0) } else { KeyEvent::ArrowUp }), |
| 338 | 0x50 => Some(KeyEvent::ArrowDown), | 341 | 0x50 => Some(if ctrl_held() { KeyEvent::CtrlArrow(1) } else { KeyEvent::ArrowDown }), |
| 339 | 0x4B => Some(KeyEvent::ArrowLeft), | 342 | 0x4B => Some(if ctrl_held() { KeyEvent::CtrlArrow(2) } else { KeyEvent::ArrowLeft }), |
| 340 | 0x4D => Some(KeyEvent::ArrowRight), | 343 | 0x4D => Some(if ctrl_held() { KeyEvent::CtrlArrow(3) } else { KeyEvent::ArrowRight }), |
| 341 | 0x47 => Some(KeyEvent::Home), | 344 | 0x47 => Some(KeyEvent::Home), |
| 342 | 0x4F => Some(KeyEvent::End), | 345 | 0x4F => Some(KeyEvent::End), |
| 343 | 0x49 => Some(KeyEvent::PageUp), | 346 | 0x49 => Some(KeyEvent::PageUp), |
| @@ -371,3 +374,9 @@ fn set_mod(state: &mut KbdState, bit: u8, pressed: bool) { | |||
| 371 | state.modifiers &= !bit; | 374 | state.modifiers &= !bit; |
| 372 | } | 375 | } |
| 373 | } | 376 | } |
| 377 | |||
| 378 | /// Is either Ctrl key held? | ||
| 379 | fn ctrl_held() -> bool { | ||
| 380 | let state = unsafe { &mut KBD }; | ||
| 381 | state.modifiers & (MOD_LCTRL | MOD_RCTRL) != 0 | ||
| 382 | } | ||
