From fa06681a8418b7e31af96e010bb424e178402f4d Mon Sep 17 00:00:00 2001 From: salmonik Date: Fri, 31 Jul 2026 17:19:09 +0200 Subject: tty + vt terminal split, rsdosedit editor (1:1 UNIX console) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 ' 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. --- rsnix/src/ps2.rs | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'rsnix/src/ps2.rs') 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 { Backspace, Tab, Escape, - CtrlC, - CtrlD, + /// Ctrl + key (e.g. Ctrl('c') = ^C, Ctrl('s') = ^S). + Ctrl(char), + /// Ctrl + arrow (0=up, 1=down, 2=left, 3=right) — word/page nav. + CtrlArrow(u8), ArrowUp, ArrowDown, ArrowLeft, @@ -306,13 +308,14 @@ fn process_byte(byte: u8) -> Option { ch.to_ascii_uppercase() }; } - // Ctrl+letter — the shell uses ^C (interrupt) and ^D (EOF). + // Ctrl+key — the terminal control-byte protocol (^C, ^D, ^S, ^X, …). let ctrl = state.modifiers & (MOD_LCTRL | MOD_RCTRL) != 0; if ctrl { - return match ch.to_ascii_lowercase() { - b'c' => Some(KeyEvent::CtrlC), - b'd' => Some(KeyEvent::CtrlD), - _ => None, // swallow other Ctrl+key combinations + let lc = ch.to_ascii_lowercase(); + return if lc.is_ascii_graphic() { + Some(KeyEvent::Ctrl(lc as char)) + } else { + None // swallow non-graphic Ctrl combos }; } if ch != 0 { @@ -334,10 +337,10 @@ fn process_e0(byte: u8) -> Option { update_modifiers(byte, true, true); match byte { - 0x48 => Some(KeyEvent::ArrowUp), - 0x50 => Some(KeyEvent::ArrowDown), - 0x4B => Some(KeyEvent::ArrowLeft), - 0x4D => Some(KeyEvent::ArrowRight), + 0x48 => Some(if ctrl_held() { KeyEvent::CtrlArrow(0) } else { KeyEvent::ArrowUp }), + 0x50 => Some(if ctrl_held() { KeyEvent::CtrlArrow(1) } else { KeyEvent::ArrowDown }), + 0x4B => Some(if ctrl_held() { KeyEvent::CtrlArrow(2) } else { KeyEvent::ArrowLeft }), + 0x4D => Some(if ctrl_held() { KeyEvent::CtrlArrow(3) } else { KeyEvent::ArrowRight }), 0x47 => Some(KeyEvent::Home), 0x4F => Some(KeyEvent::End), 0x49 => Some(KeyEvent::PageUp), @@ -371,3 +374,9 @@ fn set_mod(state: &mut KbdState, bit: u8, pressed: bool) { state.modifiers &= !bit; } } + +/// Is either Ctrl key held? +fn ctrl_held() -> bool { + let state = unsafe { &mut KBD }; + state.modifiers & (MOD_LCTRL | MOD_RCTRL) != 0 +} -- cgit v1.2.3