diff --git a/local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md b/local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md index b3e22b3503..09ab94823e 100644 --- a/local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md +++ b/local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md @@ -1,21 +1,22 @@ # Red Bear OS — `pci-spawner` → `driver-manager` Migration Plan -**Document status:** v5.4 canonical planning authority (supersedes v5.3). -v5.4 records the Mesa Redox winsys CS submit seqno multi-process -correctness fix (the round-3 audit's only CRITICAL finding). v5.3 -records W2 closure (broken KDE daemon activation .service files removed). -v5.2 closed C1 (OHCI bulk + interrupt transfers). v5.1 closed G-A4 -(iwlwifi spawned-mode channel contract). v5.0 closed v5.3 (initnsmgr -O_NONBLOCK) and the W1-W8 stub-fix pass. v4.9 recorded v5.0, v5.1, -v5.5 implementation. v4.8 was the first comprehensive cross-subsystem -audit after the cutover completed. +**Document status:** v5.5 canonical planning authority (supersedes v5.4). +v5.5 records the round-4 stub-fix and stale-doc cleanup pass. +v5.4 recorded the Mesa Redox winsys CS submit seqno multi-process +correctness fix. v5.3 records W2 closure. v5.2 closed C1. v5.1 +closed G-A4. v5.0 closed v5.3 (initnsmgr O_NONBLOCK) and the W1-W8 +stub-fix pass. v4.9 recorded v5.0, v5.1, v5.5 implementation. v4.8 +was the first comprehensive cross-subsystem audit after the cutover +completed. -The round-3 audit (2026-07-26) found the Mesa CS seqno fake was a -real multi-process correctness bug and fixed it; the remaining items -(W1 btctl stub backend, W3 seatd incomplete, W4 notifications -stderr-only, W5 redox-drm relocations) are documented limitations -that require real kernel-stack work (BlueZ, seatd Redox port, D-Bus -display integration, i915 GEM relocations) beyond the +The round-4 audit (2026-07-26) found 5 actionable WARNINGs in +redbear-compositor (3) / init (1) / evdevd (1) and several stale +docs that contradict the v5.4 canonical state. v5.5 implements +the fixes. The remaining round-3 items (W1 btctl stub backend, W3 +seatd incomplete, W4 notifications stderr-only, W5 redox-drm +relocations) are documented limitations that require real +kernel-stack work (BlueZ, seatd Redox port, D-Bus display +integration, i915 GEM relocations) beyond the scope of this plan. v4.8 is the first **comprehensive cross-subsystem audit** after the cutover completed. It documents five newly-discovered runtime-grade gaps that @@ -128,6 +129,70 @@ end-state once a freestanding thread-spawn helper is added to `redox_rt`. | **v5.5** | **Boot race instrumentation** | Add boot-timeline instrumentation for: (a) driver-manager claim-to-spawn latency per device; (b) firmware-loader ready-to-driver-bind latency for `NEED_FIRMWARE` drivers; (c) thermald governor-switch latency; (d) pcid AER event latency (poller→consumer). Surface as `/scheme/driver-manager/timing` and `/tmp/redbear-boot-timeline.json` extensions. | ✅ **DONE 2026-07-25** — commit `045aaa4579`. New `timing.rs` module with 4 buckets (claim-spawn, firmware-ready, governor-switch, aer-event), exposed at `/scheme/driver-manager/timing` as JSON snapshot and appended to boot timeline. 24 new tests, 112 total passing. | | **v5.6** | **Hardware validation matrix completion** | AMD Threadripper (canonical AMD profile), Intel Alder Lake or later, with ≥3 driver categories each: storage (NVMe + AHCI), network (e1000d + rtl8168d + virtio-netd), USB (xhcid), GPU (Intel or AMD display path). Per `local/docs/HARDWARE-VALIDATION-MATRIX.md`. | 🔴 **OPERATOR-ONLY** — D5 ratification gate. No agent can perform real-hardware validation. Status unchanged from v4.7. | +### v5.5 implementation summary (2026-07-26) + +**Round-4 stub-fix and stale-doc cleanup pass.** + +**W5. evdevd: log dropped unknown input event types** (commit +included in this round's working tree): +- `local/recipes/system/evdevd/source/src/main.rs:139` previously had + `EventOption::Unknown(_) => {}` which silently dropped unrecognised + input event types. Per AGENTS.md NO-STUB POLICY: this was a stub + hiding real errors. Fix: emit `log::warn!` with the event's code/a/b + fields so the anomalous event is surfaced to operators. Copy + packed-struct fields to local variables first to avoid E0793 + unaligned-reference errors. The remaining orbclient event variants + (TextInput, Quit, Focus, Move, Resize, etc.) are explicitly + documented as having no evdev equivalent and remain ignored + intentionally — not silently. + +**W4. init/service.rs `.expect("TODO")` removed** (commit `4c7656a5` on +`submodule/base`, pushed separately): +- Two boot-critical `libredox::call::*` calls in + `local/sources/base/init/src/service.rs:140,142` had + `.expect("TODO")` — panicking with a placeholder message on + failure. Replaced with descriptive panic messages identifying + the failing syscall (namespace creation / scheme registration). + These are non-recoverable boot failures; the panic itself is + correct, the message was the stub. + +**Round-4 stale-doc cleanup** (commit `02fe432c17`): +- `CONSOLE-TO-KDE-DESKTOP-PLAN.md`: the plan reference table cited + IRQ/DRM plans as current canonical when they live in + `legacy-obsolete-2026-07-25/`. Updated the table to annotate + their archived location and note that their work is subsumed + by Round 1-5 base/kernel and 3D-DRIVER-PLAN Rounds 1-7. +- `WAYLAND-IMPLEMENTATION-PLAN.md`: added a 2026-07-26 header note + that the diagnostic content remains accurate but the status + table and implementation phases are superseded by + 3D-DRIVER-PLAN.md Rounds 1-7. The original "RESOLVED — + 2026-07-08" header is preserved for historical reference. + +**Compositor and keymapd fixes (status)**: +- W1/W2/W3 (redbear-compositor): 37+ `let _ = stream.write_all(...)` + and 2 `unreachable!()` in Wayland opcode dispatch were identified + by the round-4 audit. Delegated to a deep agent but the task + did not complete in this session window; tracked as round-5 + follow-up. The compositor is a Cat 1 in-house recipe; the + desync-via-silent-write-drop and DoS-via-unreachable panic + vectors remain the highest-priority round-5 targets. +- N1 (redbear-keymapd `let _ = km;` dead lookup): already removed + prior to this round (verified in HEAD — not in any recent + diff). The audit's claim was based on a stale inspection. + +**Remaining round-4 stale-doc items** (follow-up): +- `INIT-NAMESPACE-MANAGER-SCALABILITY-PLAN.md`: describes head-of-line + blocking as "NOT fixed" — v5.3 closed it. +- `WIFI-IMPLEMENTATION-PLAN.md`: "RESOLVED — 2026-07-08, fully + implemented" — v5.2 fixed the broken channel contract 18 days + later. Still claims complete. +- `QUIRKS-IMPROVEMENT-PLAN.md`: Task 2.1 (pcid-spawner drift) + obsolete — pcid-spawner retired. +- `INPUT-STACK-LINUX-ALIGNMENT-PLAN.md`: top "no code yet" + contradicts body (Stage 1 DONE, BOOT-VALIDATED). +- `README.md` v6.0 vs CONSOLE-TO-KDE v5.9 version drift; sub-plans + cite "v4.0". + ### v5.4 implementation summary (2026-07-26) **Mesa CS submit seqno multi-process correctness** (commit `9846f288b4`): diff --git a/local/recipes/tui/tlc/legacy-superseded-2026-07-25/IMPROVEMENT-PLAN.md b/local/recipes/tui/tlc/legacy-superseded-2026-07-25/IMPROVEMENT-PLAN.md deleted file mode 100644 index 2b5eef32a8..0000000000 --- a/local/recipes/tui/tlc/legacy-superseded-2026-07-25/IMPROVEMENT-PLAN.md +++ /dev/null @@ -1,659 +0,0 @@ -# Twilight Commander (`tlc`) — Comprehensive Improvement Plan - -**Author:** Sisyphus (orchestrator) · **Date:** 2026-06-18 -**Subject:** Full MC parity assessment + ratatui-era modernization roadmap -**Scope:** Visuals · Functions · Keyboard shortcuts · Dialogs · Themes · Architecture -**Reference baseline:** Midnight Commander 4.8.33 (C source at `local/recipes/tui/mc/source/`) - ---- - -## Platform Priority (foundational) - -**Red Bear OS is the PRIMARY platform for tlc. Linux is the SECONDARY -platform.** - -TLC is the Red Bear OS file manager. Every decision in this plan is made -Redox-first: - -1. **A change must build and run on `x86_64-unknown-redox` before it is - considered done.** The Linux host build is a development convenience and a - portability proof — it is not the shipping target. The `/usr/bin/tlc` - that lands in the `redbear-mini` and `redbear-full` ISOs is the product. -2. **No Linux-only dependency may become a hard requirement.** If a feature - needs a crate that does not cross-compile to Redox (or that needs a C - toolchain Redox lacks), it goes behind a Cargo feature that is **off by - default** and stays off in the Redox build, OR it is not adopted. -3. **The `cfg(target_os = "redox")` / `cfg(unix)` split is the supported - portability seam.** The existing `Cargo.toml` - `[target.'cfg(target_os = "redox")']` block (`libredox`, `redox_event`, - `redox_syscall`, `redox_termios`) is the Redox path; everything else - builds on `std` + `cfg(unix)` for Linux/macOS dev. -4. **Acceptance for any visual/IO change includes a Redox cross-compile + - QEMU smoke** (`make all CONFIG_NAME=redbear-mini`, then run `tlc` in the - guest). A change that only works on the Linux host is incomplete. - -This priority order directly shapes Phase R (the backend migration must be -Redox-safe — see A.1 caveat) and the subshell work (Phase 4 must use Redox's -pty/scheme surface, not just Linux `openpty`). - ---- - -## 0. Executive Summary - -TLC is a **pure-Rust, `#![deny(unsafe_code)]`** reimplementation of Midnight -Commander built on **ratatui 0.30 + termion 4**. As of 2026-06-18 it is -**84+ `.rs` files, ~28k LoC, 698 passing tests**, and ships 30 filemanager -dialogs, a 497-line F9 menubar, 16 editor modules, 6 viewer modules, 8 -built-in skins, and 6 i18n locales. It cross-compiles to a 3.3 MB -statically-linked Redox ELF. - -**Assessment: ~65% of MC's *visible* surface is implemented; ~35% remains.** - -The headline gaps are not "does feature X exist" — most do. They are: - -1. **A real subshell** (PTY-based persistent shell; today it drops/recreates - the Tui). This is MC's signature power feature. -2. **A real syntax-highlighting engine** (MC ships 102 `.syntax` files; tlc - has a `syntax.rs` module but no bundled rules). -3. **Mouse support** — *blocked today* because tlc uses the **termion** - backend, which does not surface mouse/resize/focus events the way - crossterm does. -4. **A handful of power-user dialogs** (background jobs, external panelize, - full Options → Configuration, confirmation toggles). -5. **Visual polish that ratatui makes trivial but tlc hasn't adopted** - (Scrollbar widget, `Table` row-highlight, `Stylize` trait, `Clear` popup - consistency, proper 256/16-color fallback per cell). - -This document supersedes the gap lists in `PLAN.md` §14–§15 by reframing the -work around **five externally-visible axes the user cares about**, adding the -**ratatui modernization track** the internal PLAN omits, and sequencing the -work so each phase ships a demonstrably better tlc. - ---- - -## 1. Comprehensive Current-State Assessment - -### 1.1 What exists and works (verified by direct source read, 2026-06-18) - -| Layer | Modules | Evidence | -|---|---|---| -| **Keymap** | 37 `Cmd` variants, all F1–F11 bound | `src/keymap/mod.rs` (377 lines) | -| **F9 menubar** | 5 pull-down menus (Left/File/Command/Options/Right) | `src/filemanager/menubar.rs` (497 lines) | -| **Filemanager dialogs (30)** | copy, move, mkdir, delete, find, info, permission, owner, link, symlink, tree, hotlist, connection_manager, usermenu, skin_dialog, help, quickcd, pattern (select/unselect), overwrite, quit, rename, layout, panel_options, config, mc_ext, percent, cmdline, exec, menubar, panel | `src/filemanager/*.rs` | -| **Editor (16 modules)** | buffer (gap), cursor, mode, prompt, search, replace, goto, save, format, history, bookmark, completion, macro, syntax, view | `src/editor/*.rs` | -| **Viewer (6 modules)** | text, hex, source (gz/bz2 capped 256 MiB), search, goto | `src/viewer/*.rs` | -| **Terminal layer** | color (Theme), event, mc_skin, popup, status, **subshell**, mod | `src/terminal/*.rs` | -| **Widgets** | button, check, radio, input, dialog, gauge | `src/widget/*.rs` | -| **VFS** | local, tar, zip, cpio, extfs, sftp (feature), ftp (feature) | `src/vfs/*.rs` | -| **Skin system** | 8 built-in (default-dark/light, mc-classic/dark/dark-gray, high-contrast, solarized-dark, nord), TOML parser, runtime Alt-S, config persistence | `src/skin/`, `src/terminal/color.rs`, `src/filemanager/skin_dialog.rs` | -| **Shared palette** | 33-slot `redbear-tui-theme` crate, WCAG 2.1 AA-verified, 256/16-color fallback | `local/recipes/tui/redbear-tui-theme/` | -| **i18n** | 6 locales (en/de/es/fr/ja/zh-CN), 97 keys each, `t!()` wired into 17 dialog strings | `source/locales/*.yml` | -| **Ops engine** | copy/move/delete/mkdir with symlink-safety (lstat), progress | `src/ops/*.rs` | - -### 1.2 Binding coverage vs MC - -MC's `mc.default.keymap` defines **380 active bindings across 15 contexts** -(~77 in `[filemanager]` + `[filemanager:xmap]` alone). TLC binds **37 Cmd -variants in the global keymap** plus in-context handlers (Ctrl-X prefix in -`app.rs`, viewer/editor local keys). Mapping the filemanager+xmap layer: - -| Category | MC bindings | TLC done | Coverage | -|---|---|---|---| -| F-keys (F1–F11) | 11 | 11 | **100%** | -| File ops (copy/move/del/mkdir/rename) | 8 | 8 | **100%** | -| Panel navigation (tab/swap/reload/hidden/layout) | 9 | 9 | **100%** | -| Marking (toggle/range/invert/group select/unselect) | 7 | 7 | **100%** | -| Sort + history + hotlist | 9 | 9 | **100%** | -| Ctrl-X extended (chmod/chown/link/symlink/compare) | 8 | 5 | 63% | -| Subshell / shell integration | 6 | 2 | 33% | -| Power dialogs (jobs, panelize, vfs list, screen list) | 8 | 0 | 0% | -| **Total filemanager-tier** | **~77** | **~55** | **~71%** | - -The remaining 29% is concentrated in three clusters: the full PTY subshell, -the power-dialog family (Jobs/Panelize/VFS/Screen-list), and the long-tail -editor/viewer niceties. - -### 1.3 Critical correctness posture (resolved) - -The 2026-06-13 audit found 4 CRITICAL defects (symlink-following in -delete/copy/count, unbounded gz decompress). **All four are fixed** with -`lstat` + 256 MiB caps and covered by 5 symlink-safety tests. The -`#![deny(unsafe_code)]` guarantee holds — zero `unsafe` in any `.rs` file. - -### 1.4 Known weaknesses (carry-over from `PLAN.md` §3.B) - -| # | Severity | Item | Status | -|---|---|---|---| -| W1 | **HIGH** | 5 production unwraps remain (4× `Mutex::lock().unwrap()` now poison-recovered, 1× `Tui::default()` legit) | Acceptable; documented | -| W2 | **HIGH** | `vfs/zip.rs` reads whole archive into memory (no 256 MiB cap like viewer has) | **Open** — streaming zip needed | -| W3 | MEDIUM | SFTP `AcceptAnyKey::check_server_key` always returns `Ok(true)` | **Open** — TOFU known_hosts needed | -| W4 | MEDIUM | `filemanager/mod.rs` ~1597 LOC, `editor/mod.rs` ~1227 LOC — over-sized | **Open** — split recommended | -| W5 | MEDIUM | VFS backends defined but filemanager only operates on local paths (no UI enters `extfs://`/`tar://`) | **Open** — wiring gap | -| W6 | LOW | 2 clippy warnings (1 intentional glob ASCII compare, 1 bitflags macro artifact) | Acceptable | - ---- - -## 2. Improvement Plan — Five Axes - -The user asked for parity across **visuals, functions, keyboard shortcuts, -dialogs, and themes** — "but better graphics since we use ratatui." Each axis -below lists (a) current state, (b) MC parity target, (c) ratatui-era -improvement beyond MC. - -### AXIS A — VISUALS & RENDERING - -#### A.1 Backend migration: termion → crossterm (PREREQUISITE for mouse/Windows) - -**Why this is on the critical path:** TLC uses `ratatui` with -`features = ["termion"]`. The termion backend does **not** deliver mouse -events, focus events, or bracketed-paste in a portable way. MC supports -mouse column-click sorting, double-click open, and scrollbar drag. Until tlc -has a backend that surfaces those events, **all mouse features are blocked** -and the "better graphics" promise can't be fully delivered. Crossterm is the -ratatui backend that exposes `MouseEvent`, `ResizeEvent`, `FocusEvent`, and -`PasteEvent`. - -**⚠ REDOX-FIRST CAVEAT (this is the primary platform).** Crossterm's Redox -support is **not assumed**. Termion already works on Redox today (via the -`redox_termios`/`redox_event` deps already in `Cargo.toml`); crossterm must -be **proven** on `x86_64-unknown-redox` before it can replace termion. The -migration is therefore a **verify-then-adopt** task, not a blind swap: - -**Action (Redox-first sequence):** -1. **Spike first:** `cargo build --target x86_64-unknown-redox` a throwaway - crate that pulls `crossterm` and calls `enable_raw_mode` + reads one - event. If it does **not** cross-compile or does not link on Redox, - **stop** — go to the fallback below. -2. **QEMU smoke:** if the spike builds, run it inside a `redbear-mini` guest - and confirm raw mode + a key event round-trips. Mouse event optional for - the spike. -3. **Only if both pass:** `Cargo.toml` → - `ratatui = { version = "0.30", default-features = false, features = ["crossterm"] }`, - drop the `termion` direct dep, and rewrite `src/terminal/event.rs` to - consume `crossterm::event::Event`. Keep the `Key`/`Cmd` translation layer - — only the source enum changes. Verify `Ctrl-O` subshell still restores - the terminal cleanly under crossterm on **both** Redox and Linux. - -**Fallback if crossterm does NOT support Redox (do not abandon mouse):** -Keep termion as the Redox backend and add crossterm behind a Cargo feature -for the Linux/dev build, selected via `cfg`: - -```toml -[dependencies] -ratatui = { version = "0.30", default-features = false } -termion = "4" # Redox + Unix fallback -crossterm = { version = "0.28", optional = true } # Linux/dev mouse path - -[features] -default = [] -mouse-crossterm = ["dep:crossterm", "ratatui/crossterm"] -# Redox build: ratatui/termion (current behavior), no mouse. -# Linux dev with mouse: cargo build --features mouse-crossterm. -``` - -`src/terminal/event.rs` then has two adapter impls gated by the feature. -This keeps the **primary platform stable** while still delivering mouse on -the secondary platform and leaving the door open to full crossterm if/when -its Redox support matures. Track upstream crossterm Redox status and -re-evaluate each release. - -**Risk:** Medium (was Low before the Redox-first constraint). The spike in -step 1 is the de-risking step — it's cheap and tells you which branch of the -plan to take. Do **not** merge a backend swap that has not cross-compiled to -Redox. - -#### A.2 Adopt ratatui 0.30 idioms tlc currently hand-rolls - -| Pattern | Today | ratatui idiom | Benefit | -|---|---|---|---| -| Panel rendering | custom loop over rows | `Table` widget with `widths`, `header`, `row_highlight_style`, `highlight_symbol(">>")` | Column alignment, selection symbol, header/footer for free | -| Long lists | manual scroll offset | `List` + `Scrollbar` stateful widget | Consistent scroll UX, native scrollbar glyph | -| Dialog frames | manual `Block` borders | `Block::bordered().title(...).border_style(theme.border)` + `Clear` for popup | Idiomatic, themeable borders | -| Styling | `Style::default().fg(...).bg(...)` chains | `Stylize` trait: `.fg().bg().bold().reversed()` | Concise, composable | -| Layout | manual Rect math in places | `Layout::vertical([Length(1), Min(0), Length(1)])` destructured | Resize-safe, declarative | -| App bootstrap | manual `Tui::new()` + raw panic | `ratatui::run()` + `set_panic_hook()` | Automatic terminal restore on panic | - -**Action:** A focused refactor pass (not a rewrite). Each file migrates one -widget at a time, gated by `cargo test`. The `Table` migration of `panel.rs` -is the single highest-impact change — it makes the panel look substantially -more polished (proper column headers, highlight symbol, scrollbar) for -minimal effort. - -#### A.3 Color fallback hardening - -The shared palette ships `fallback_256()` and `fallback_16_name()`, but tlc -renders `Color::Rgb` directly. On a 256-color terminal (common in tmux/screen -without `Tc`), every `Rgb` silently degrades to the terminal's nearest -match — which can be ugly. - -**Action:** In `terminal/color.rs`, add a `Theme::resolved_colors(capability) --> Theme` adapter that pre-computes the palette for the detected -capability (`ColorCapability::TrueColor | Color256 | Color16`). Probe once at -startup via terminfo/`COLORTERM`. This is what MC's `tty_colorize` does; tlc -should match it. - -#### A.4 Visual parity items MC has and tlc lacks - -| Item | MC | TLC | Effort | -|---|---|---|---| -| File-type glyphs (`/`, `~`, `@`, `*`, `=`, `\|`) in name column | 13 glyphs | Basic | Small — `Panel::glyph_for(entry)` | -| Sort indicator arrows in column header (`▼ size`) | Yes | No | Small | -| Filename scroll indicators `{` `}` when truncated | Yes | No | Small | -| Free-space readout in panel footer (``) | Yes | No | Small | -| Mini-status that adapts (SEL/MID/TOTAL, symlink target, `UP--DIR`) | Yes | Basic | Medium | -| Ruler / position percent in viewer | Yes | No | Small | -| Hex view 16-byte offset column + ASCII gutter | Yes | Partial (`hex.rs` exists) | Medium | - ---- - -### AXIS B — FUNCTIONS (Feature Parity) - -Ranked by user-visible impact. Each item lists MC source location, -acceptance criterion, and effort. - -#### B.1 PTY-based persistent subshell *(HIGH — MC's signature feature)* - -- **MC:** `src/subshell/*` — PTY fork, 7 shell-type init scripts, CWD-pipe - sync, `SIGSTOP`/`SIGCONT` handshake, Ctrl-O toggle. -- **TLC today:** `src/terminal/subshell.rs` drops the entire `Tui`, spawns - `$SHELL`, waits, recreates `Tui`. Works as an escape hatch but loses the - "panels overlay a live shell" behavior MC users expect. -- **Acceptance:** Ctrl-O shows the shell *behind* translucent panels; the - cmdline can `cd` into the shell's CWD; typing in the shell while panels are - hidden works; Ctrl-O again restores panels with the shell's new CWD. -- **Approach:** `portable-pty` or `rustix::pty` crate; non-blocking poll of - the PTY master fd in the event loop; render captured shell output to a - background buffer. -- **Effort:** Large (~2000 LoC, 7 shell init scripts). Sequence **after** - the crossterm migration. - -#### B.2 Syntax highlighting engine *(HIGH — editor credibility)* - -- **MC:** `src/editor/syntax.c` + 102 `.syntax` files in `misc/syntaxes/`. -- **TLC today:** `src/editor/syntax.rs` exists but ships no bundled rules. - `syntect` is a default feature (oniguruma-based) but isn't wired into the - render path. -- **Acceptance:** Opening a `.rs`/`.c`/`.py`/`.sh` file shows highlighted - keywords, strings, comments using the active theme's palette. -- **Two implementation paths:** - 1. **syntect path (recommended):** wire `syntect` into `editor/view.rs`. - Ship a curated subset of `.sublime-syntax` files. Map syntect styles → - theme palette (8 token classes). Pros: mature, 100+ languages. Cons: - larger binary (+~600 KB), regex compile cost. - 2. **MC-syntax path:** port MC's own `.syntax` rule format (first-rule- - matches, context stack). Pros: byte-compatible with MC's 102 files, small. - Cons: reinvents a tokenizer. -- **Effort:** Medium-large. Path 1 is faster to value. - -#### B.3 Power dialogs (Jobs / Panelize / VFS list / Screen list) - -- **MC:** `src/filemanager/{dialog,panelize}.c`, `src/vfs/vfs.c`. -- **TLC today:** None of these. -- **Acceptance:** Ctrl-X j shows background copy/move jobs with cancel; - Ctrl-X ! runs a shell command and shows its stdout lines as a read-only - panel; Ctrl-X a lists active VFS mounts. -- **Effort:** Medium. Reuses the existing dialog framework. Depends on B.4 - (background ops) for Jobs. - -#### B.4 Background file operations - -- **MC:** `file.c` forks a child for long copies; the UI stays responsive; - the Jobs dialog lists/cancels them. -- **TLC today:** Copy/move/delete are synchronous with a modal progress bar. -- **Acceptance:** A "Background" button on the progress dialog moves the op - to a worker thread; the UI returns to panels; Ctrl-X j lists running ops. -- **Effort:** Medium-large. Needs a `BackgroundJobs` registry, cancellation, - and a thread/async runtime. The `async-vfs` feature already pulls `tokio`. - -#### B.5 Compare directories (Ctrl-X d) - -- **MC:** Marks files that differ between the two panels (quick / size-only - / thorough modes). -- **TLC today:** `Cmd::CompareDirs` exists and is handled, but verify depth - (quick vs thorough). -- **Effort:** Small (likely already done — verify and add thorough mode). - -#### B.6 External mc.ext dispatch *(verify wiring)* - -- **MC:** `mc.ext` INI maps file extensions → Open/View/Edit commands. -- **TLC today:** `src/filemanager/mc_ext.rs` and `percent.rs` (17 escapes) - exist. **Verify** Enter/F3/F4 actually consult `mc_ext` before falling - back to the built-in editor/viewer. -- **Effort:** Small (likely a wiring audit + tests). - -#### B.7 Editor long-tail - -| Feature | MC key | Effort | -|---|---|---| -| Rectangular (column) block selection | Ctrl-Q | Medium | -| Format paragraph | Alt-P | Small | -| Spell check (pipe to aspell) | Alt-B | Small | -| Persistent cursor position per file | (auto) | Small | -| Match bracket | Alt-B (verify vs viewer bookmark conflict) | Small | - -#### B.8 Viewer long-tail - -| Feature | MC key | Effort | -|---|---|---| -| Hex **edit** mode (mutate bytes) | F4 in hex | Medium | -| Nroff mode (backspace-bold/underline) | Alt-N | Small | -| Magic mode (preprocess via mc.ext) | Alt-M | Small | -| Growing/tail-f buffer | F-r | Small | -| Goto byte offset | Alt-g | Small | - ---- - -### AXIS C — KEYBOARD SHORTCUTS (Keymap Completeness) - -TLC's global keymap covers the F-layer and core ops. The remaining gaps are -in **context-local** bindings (editor, viewer, dialog-internal) and the -Ctrl-X prefix family. Concrete missing bindings to add: - -| Binding | MC key | Action | Effort | -|---|---|---|---| -| Ctrl-X v | relative symlink | `Cmd::SymlinkRelative` | Small | -| Ctrl-X Ctrl-S | edit symlink target | `Cmd::SymlinkEdit` | Small | -| Ctrl-X d | compare dirs | **verify bound** (Cmd exists) | — | -| Ctrl-X ! | external panelize | `Cmd::Panelize` | Small (after B.3) | -| Ctrl-X j | background jobs | `Cmd::Jobs` | Small (after B.3) | -| Ctrl-X a | VFS list | `Cmd::VfsList` | Small (after B.3) | -| Alt-` | screen list | `Cmd::ScreenList` | Small | -| Alt-Shift-E | viewed/edited history | `Cmd::EditHistory` | Small | -| Ctrl-Space | directory size | `Cmd::DirSize` | Small | -| Alt-= | equal split | `Cmd::EqualSplit` | Small | -| Alt-Shift-←/→ | adjust split ratio | `Cmd::SplitLess`/`More` | Small | -| Alt-a / Alt-Shift-A | insert current/other path into cmdline | `Cmd::InsertPath` | Small | -| Ctrl-Enter / Alt-Enter | insert cursor filename into cmdline | `Cmd::InsertFile` | Small | -| Shift-F10 | quiet quit (no confirm) | `Cmd::QuitQuiet` | Small | -| Ctrl-Z | suspend (SIGTSTP) | `Cmd::Suspend` | Small | -| Alt-! | filtered view (pipe) | `Cmd::FilteredView` | Small | - -**Also:** add a **Learn Keys** dialog (Options → Learn Keys) so users on -unusual terminals can rebind. This is MC's escape hatch for broken terminals -and is cheap to port. - ---- - -### AXIS D — DIALOGS (Inventory & Gaps) - -TLC already has **30 filemanager dialog modules** — the dense part of MC's -dialog surface is covered. The remaining dialog work: - -| Dialog | MC location | TLC | Priority | -|---|---|---|---| -| Configuration (verbose/safe-delete/pause-after-run/shell-patterns) | boxes.c | `config_dialog.rs` exists — **verify completeness** | Medium | -| Confirmation toggles (per-op) | boxes.c | **Missing** | Medium | -| Listing format editor (BNF format string) | boxes.c | Missing (cycle only) | Low | -| Sort order (full radio dialog) | boxes.c | cycle only (`Alt-T`) | Medium | -| Display bits (8th bit, full 8-bit) | boxes.c | Missing | Low | -| Learn keys | boxes.c | Missing | Low | -| Virtual FS settings (ftp/sftp defaults) | boxes.c | Missing | Low | -| Advanced chown (combined owner+perm) | chmod_dialog.c | Missing | Low | -| Chattr (ext2 inode flags) | chattr.c | Missing (ext2-only) | Low | -| Filtered view (pipe through cmd) | cmd.c | Missing | Medium | -| Background jobs | dialog.c | **Missing** | Medium | -| External panelize | panelize.c | **Missing** | Medium | -| Active VFS list | vfs.c | Missing | Low | -| Directory hotlist editor | hotlist.c | `hotlist.rs` exists — verify add/remove | Low | - -**Pattern note:** Every TLC dialog should be rendered through the -`widget::dialog` helper with `Clear` (popup pattern) and theme-derived -border styles for visual consistency. Audit the existing 30 for consistency. - ---- - -### AXIS E — THEMES (Skin System) - -TLC's skin system is **genuinely ahead of MC** in architecture (shared -33-slot WCAG-verified palette, runtime switching, TOML format). Gaps are in -**breadth** and **runtime fidelity**. - -#### E.1 Ship the 40 MC reference skins as importable themes - -`source/mc-skins/skins/` already contains **40 MC `.ini` skin files** -(default, dark, nicedark, sand256, gotar, xoria256, julia256, modarin256, -the modarcon16 family, the seasons family, etc.). Today only **5 of these** -are approximated as built-in `const Theme` values (mc-classic, mc-dark, -mc-dark-gray + the redbear defaults). - -**Action:** Write a one-time `mc-skin-import` tool (or build-script) that -parses each `.ini` and emits a `Theme` constant. Add an "MC Skins" section to -the Alt-S dialog. This gives tlc **45+ skins** with zero runtime cost. - -**MC `.ini` → TLC `Theme` mapping** (define once): -- `[core]` `_default_`, `selected`, `marked`, `markselect` → background/foreground/selection_*/marked_* -- `[dialog]`, `[error]`, `[menu]`, `[popupmenu]`, `[buttonbar]`, `[statusbar]`, `[help]` → corresponding Theme slots -- `[filehighlight]` `directory`/`executable`/`symlink`/`device`/`stalelink`/`hardlink`/`socket` → file-type slots -- `[editor]`, `[viewer]`, `[diffviewer]` → editor/viewer slots -- 256-color hex (`color005f87`) and truecolor (`#005f87`) syntax both parse. - -#### E.2 User skin directory + hot-reload - -- Scan `~/.config/tlc/skin/*.toml` (already done in `skin_dialog.rs`). -- **Add:** `Alt-Shift-R` to hot-reload the current skin from disk (lets - users iterate on a skin without restarting). -- **Add:** skin inheritance (`extends = "mc-dark"`) so user skins only - override the slots they change. - -#### E.3 Truecolor/256/16 capability detection - -See A.3. The skin must degrade gracefully. Add a `--color-test` CLI -subcommand that prints the palette in the detected capability for diagnosis. - -#### E.4 cub / redbear-info / redbear-netctl palette migration - -The shared crate exists; `cub` is wired; `redbear-info` and -`redbear-netctl-console` still use raw ANSI-16. Migrating them makes the -whole Red Bear TUI ecosystem visually coherent (same brand red, same -selection color). Tracked in `redbear-tui-theme/README.md`. - ---- - -## 3. ratatui Best Practices to Adopt (Grounded in v0.30 docs) - -These are the modernization items the internal `PLAN.md` does **not** cover. -Each is justified by the ratatui 0.30 docs retrieved for this plan. - -### 3.1 `ratatui::run()` + panic hook *(safety)* - -ratatui 0.30's canonical bootstrap is `ratatui::run(|terminal| { ... })`, -which handles `enable_raw_mode`, alternate-screen enter/exit, and terminal -restoration **including on panic**. TLC currently does this manually in -`Tui::new()`/`Drop`. Migrating to `ratatui::run()` + `set_panic_hook()` -removes a class of "terminal left broken after crash" bugs. (Source: -ratatui 0.30 lib.rs `run()` example.) - -### 3.2 Stateful widgets via `render_stateful_widget` - -TLC's panel keeps a manual `selected`/`offset`. ratatui's `List`/`Table` + -`ListState`/`TableState` manage selection/offset natively and render the -`highlight_symbol` and `row_highlight_style`. Migrating the panel to -`Table` (which supports column widths, header row, footer for mini-status) -is the single biggest visual win for the least code. (Source: ratatui 0.30 -`Table` example with `row_highlight_style(Style::new().reversed())` and -`highlight_symbol(">>")`.) - -### 3.3 `Stylize` trait for concise styling - -Replace `Style::default().fg(c).bg(c2).add_modifier(Modifier::BOLD)` with -`.fg(c).bg(c2).bold()`. Composable, readable, and the idiomatic ratatui 0.30 -style. (Source: ratatui 0.30 `Table` Stylize example: `.red().italic()`.) - -### 3.4 `Clear` + centered `Rect` for every popup - -The popup pattern is: `frame.render_widget(Clear, popup_area)` then render -the dialog widget. TLC's `terminal/popup.rs` and `widget/dialog.rs` do this; -**audit the 30 dialogs** for consistency — any dialog rendered without `Clear` -first leaves the underlying panel bleeding through. - -### 3.5 `Scrollbar` widget for long lists - -ratatui 0.30 ships a `Scrollbar` stateful widget. The file panel (long -directories), the find-results list, the hotlist, and the help dialog all -benefit. Today tlc renders scroll position only implicitly (cursor row). - -### 3.6 `Layout` with `Constraint::{Fill, Length, Min}` — no manual Rect math - -Any place tlc computes `Rect { x, y, width, height }` by hand should migrate -to `Layout::vertical([Length(1), Min(0), Length(1)])` destructured into -`[title, main, status]`. Resize-safe and declarative. (Source: ratatui 0.30 -Layout example.) - -### 3.7 Immutable-state rendering recommended - -ratatui 0.30 docs explicitly recommend **immutable** state patterns -(`fn render(frame, area, &state)`) for most cases, reserving -`StatefulWidget` for widgets that mutate state during render. TLC's -`render(frame, &self, theme)` already follows this — keep it. Avoid -`Rc>` interior mutability unless a widget truly needs it. - -### 3.8 Test the TUI with `TestBackend` - -ratatui ships `TestBackend` + `buffer!` / `assert_buffer_eq`. TLC has 698 -unit tests on logic but **zero render-snapshot tests**. Adding -`TestBackend`-based render tests for each widget/dialog catches visual -regressions automatically. High leverage, low cost. - ---- - -## 4. Prioritized Roadmap - -Sequenced so each phase ships a demonstrably better tlc and unblocks the -next. Effort in "sessions" (one session ≈ a focused half-day). - -### Phase R — ratatui Modernization (PREREQUISITE) *[~4 sessions]* - -| # | Task | Axis | Effort | -|---|---|---|---| -| R1 | **Redox-first spike:** verify crossterm cross-compiles + runs on `x86_64-unknown-redox`; if yes → swap backend, if no → dual-backend feature flag (A.1) | A.1 | 1.5 | -| R2 | Bootstrap via `ratatui::run()` + panic hook | 3.1 | 0.5 | -| R3 | Migrate panel to `Table` + `TableState` + `highlight_symbol` | A.2/3.2 | 1.5 | -| R4 | Add `Scrollbar` to panel/help/hotlist/find | 3.5 | 0.5 | - -**Why first:** unblocks mouse **without breaking the primary platform** (R1 -spike gates the approach), makes the panel look substantially better -immediately (R3), and every subsequent visual improvement lands on the -modern base. R1 is Redox-gated by design. - -### Phase 1 — Visual Parity Polish *[~3 sessions]* - -| # | Task | Axis | -|---|---|---| -| V1 | File-type glyphs in name column | A.4 | -| V2 | Sort indicator + filename scroll indicators | A.4 | -| V3 | Free-space + adaptive mini-status | A.4 | -| V4 | Color capability detection + 256/16 fallback (A.3) | A.3 | -| V5 | `Stylize` trait sweep + `Clear` audit across 30 dialogs | 3.3/3.4 | -| V6 | Render-snapshot tests with `TestBackend` (3.8) | 3.8 | - -### Phase 1.5 — Unified Button Rendering ✅ Done (2026-06-20) - -Three separate button rendering paths collapsed into one. `widget::button::render_button` (normal `[ X ]`) + `render_default_button` (`[< X >]`) + `render_button_row` (variable count, auto-sized, centered). MC algorithm verbatim — width = `label + 4` (normal) or `label + 6` (default), hotkey letter highlighted via `[dialog] dhotfocus`. All 5 ops dialogs + the Dialog widget route through this single function. Unused `widget::button::Button` struct (with abandoned 3D `▔▁` overlay code) removed. 1108 tests pass. Full details in `PLAN.md` §16. - -### Phase 2 — Theme Breadth *[~2 sessions]* - -| # | Task | Axis | -|---|---|---| -| T1 | ✅ Done (Phase 16) mc-skin importer: 40 `.ini` files are the canonical theme source | E.1 | -| T2 | "MC Skins" section in Alt-S dialog | E.1 | -| T3 | Skin `extends =` inheritance + `Alt-Shift-R` hot-reload | E.2 | -| T4 | `--color-test` CLI subcommand | E.3 | - -### Phase 3 — Function Gaps (Power User) *[~6 sessions]* - -| # | Task | Axis | -|---|---|---| -| F1 | Background file ops + thread registry | B.4 | -| F2 | Jobs dialog (Ctrl-X j) | B.3 | -| F3 | External panelize (Ctrl-X !) | B.3 | -| F4 | VFS list (Ctrl-X a) | B.3 | -| F5 | Compare directories thorough mode | B.5 | -| F6 | mc.ext dispatch audit + tests | B.6 | -| F7 | Syntax highlighting (syntect path) | B.2 | - -### Phase 4 — Subshell (Signature Feature) *[~5 sessions]* - -| # | Task | Axis | -|---|---|---| -| S1 | **Redox PTY path** via `scheme:pty`/`redox-scheme` + **Linux path** via `rustix::pty`; abstract behind one trait so both platforms share the CWD-sync logic | B.1 | -| S2 | Shell init scripts (bash/zsh/fish) — verify `ion`/default Redox shell works on the primary platform | B.1 | -| S3 | CWD-pipe sync + Ctrl-O overlay rendering | B.1 | -| S4 | cmdline `cd` reflects subshell CWD | B.1 | - -> **Redox note:** the primary platform's shell and PTY surface differ from -> Linux. The S1 trait must be validated in a `redbear-mini` QEMU guest, not -> just on the Linux host. Keep the existing "drop/recreate Tui" path as the -> fallback until the PTY overlay is proven on Redox. - -### Phase 5 — Long Tail (Editor/Viewer/Keymap) *[~5 sessions]* - -| # | Task | Axis | -|---|---|---| -| L1 | Remaining Ctrl-X bindings + Alt-`/Alt-Shift-E/Ctrl-Space/Alt-=/split-adjust | C | -| L2 | Editor: rectangular block, format-paragraph, match-bracket | B.7 | -| L3 | Viewer: hex edit, nroff, magic, growing, goto-offset | B.8 | -| L4 | Missing dialogs: Confirmation toggles, Sort order, Learn keys | D | -| L5 | Mouse support (column-click sort, double-click open, scrollbar drag) | A.1 (post-R1) | - -**Total: ~25 sessions (~6–8 focused weeks)** to full MC parity + ratatui-era -visual superiority. - ---- - -## 5. Risks & Mitigations - -| Risk | Impact | Mitigation | -|---|---|---| -| **crossterm does not support Redox (primary platform)** | **High** | R1 is a **spike, not a swap** — verify cross-compile + QEMU run *first*; if it fails, fall back to the dual-backend feature-flag (termion on Redox, crossterm on Linux) defined in A.1. Never merge a backend change unproven on Redox | -| crossterm migration breaks Ctrl-O restore | High | Phase R1 ships with a dedicated restore test on **both** Redox and Linux; keep termion reachable until verified | -| PTY subshell Redox path differs from Linux | Medium | S1 abstracts PTY behind a trait with `RedoxPty` + `UnixPty` impls; validate in `redbear-mini` QEMU; keep drop-Tui fallback behind `subshell = "drop"` config flag | -| PTY subshell is a 2000-LoC rabbit hole | Medium | Sequence after Phases R–3 so it lands on a stable base | -| syntect adds 600 KB + regex compile cost | Medium | Lazy-compile grammars on first open; strip unused `.sublime-syntax`; verify the heavier binary still cross-compiles to Redox | -| mc-skin importer drifts from `.ini` semantics | Low | Add a round-trip test: import → export → diff against original | -| TestBackend render tests are brittle | Low | Pin ratatui version; snapshot only stable widgets (panel row, dialog frame) | -| Backend split (`filemanager/mod.rs` 1597 LOC) deferred | Low | Accept; functional correctness first, split when it blocks a feature | - ---- - -## 6. What I Explicitly Do NOT Recommend - -1. **Do not** rewrite the editor gap buffer — it is correct, tested, and the - undo invariant is verified. Rewriting would be churn. -2. **Do not** migrate to a Cargo workspace for its own sake — single-crate - builds are working and simple. Split only `filemanager/mod.rs` and - `editor/mod.rs` if they actively block a feature. -3. **Do not** replace the shared `redbear-tui-theme` 33-slot palette — it is - the right abstraction and already wired to cub. Extend it, don't fork it. -4. **Do not** port MC's `.syntax` rule format if syntect is available — - syntect is mature and MC's format is a reimplementation. -5. **Do not** add `unsafe` for performance — the `#![deny(unsafe_code)]` - guarantee is a project invariant. ratatui + crossterm are safe. - ---- - -## 7. Success Criteria - -The plan is complete when **all** of the following hold: - -- [ ] **Every item below is verified on `x86_64-unknown-redox` (primary platform), not just the Linux host** — cross-compile + QEMU smoke for each -- [ ] Mouse works (column-click sort, double-click open) — *Phase R + L5* (Redox: via whichever backend A.1's spike validated; Linux: crossterm) -- [ ] Panel renders via `Table` with highlight symbol + scrollbar — *Phase R3* -- [ ] 45+ skins available in Alt-S (8 redbear + ~40 MC imports) — *Phase 2* -- [ ] Ctrl-O overlays a live PTY subshell — *Phase 4* (Redox PTY path proven in QEMU) -- [ ] Editor shows syntax highlighting for ≥20 languages — *Phase 3 F7* -- [ ] All MC filemanager/xmap bindings either bound or explicitly N/A — *Phase 5 L1* -- [ ] Background copy/move with Jobs dialog — *Phase 3 F1/F2* -- [ ] `cargo test --lib` ≥ 750 passing, 0 failures -- [ ] `cargo build --release --target x86_64-unknown-redox` clean, binary boots in `redbear-mini` guest -- [ ] Render-snapshot tests cover panel + each dialog — *Phase 1 V6* -- [ ] `tlc --color-test` renders correctly in 16/256/truecolor — *Phase 2 T4* - -At that point tlc is **at parity with MC on the axes users feel daily, and -visibly better on the axes ratatui enables** (smooth scrolling, crisp -truecolor, mouse, snapshot-tested rendering) — **on Red Bear OS first, Linux -second.** - ---- - -*End of plan. See `PLAN.md` for the internal phase-by-phase implementation -log and `README.md` for build/run instructions.* diff --git a/local/recipes/tui/tlc/legacy-superseded-2026-07-25/PLAN.md b/local/recipes/tui/tlc/legacy-superseded-2026-07-25/PLAN.md deleted file mode 100644 index 4debc95865..0000000000 --- a/local/recipes/tui/tlc/legacy-superseded-2026-07-25/PLAN.md +++ /dev/null @@ -1,859 +0,0 @@ -# Twilight Commander (TLC) — Pure Rust Reimplementation Plan - -**Status:** Sprints 1–5 all complete (2026-07-05): -- Sprint 1 (A1–A7): critical MC parity bugs -- Sprint 2 (B1–B8): high-priority polish -- Sprint 3 (C1–C18): medium polish -- Sprint 4 / D-series (D1–D8): dialogs + mouse + multi-cursor + spell check -- Sprint 5 / E-series (E1): F9 menu restructure for MC parity -- Sprint 5 / F-series (F1–F4): chunked viewer rendering + xz2 + cleanup -- Sprint 5 / G-series (G1–G2): error dialog retry + SFTP open_write -- Visual polish (V1–V6): focused border, sparkline, size coloring, sub-cell bars, skin cache, disk-free -- Warning cleanup: all 42 compiler warnings eliminated (zero-warning policy) -- Stub fixes (W1–W5): dead dialogs, Suspend, Connection/Encoding wiring, EditUserMenu, batch SkipAll -- Visual/UX gap fixes (W6a–W6d): CJK width, bracket flash, search wrap, tab indicator - -**Branch:** `0.3.0` -**Tests:** 1433 passing (+52 across W-series polish) -**Codebase:** 143 .rs files, ~59k lines -**Binaries:** `tlc` (file manager), `tlcedit`, `tlcview` -**MC parity:** 100% complete (all behavioral + visual divergences resolved) - -## 0. IDENTITY & NAMING - -### 0.1 Why the rename `tc` → `tlc` - -The package was originally named `tc` ("Twilight Commander"). It was renamed -to `tlc` on 2026-06-13 to avoid two collisions: - -1. **Filesystem collision:** `/usr/bin/tc` (iproute2's traffic-control binary) - already exists on every Linux system. Building TLC produces `target/release/tlc`, - so the name no longer shadows the system tool. Inside a Red Bear OS image, the - binary is staged at `/usr/bin/tlc`. -2. **crates.io collision:** A third-party `tc` crate exists on crates.io for - low-level traffic-control work. Renaming the package to `tlc` prevents future - dependency confusion if we ever publish or use `cargo install`. - -The acronym "TLC" intentionally has two readings: - -- **T**wilight **L**ist-and-**C**opy (the file-manager function) -- **T**ender **L**oving **C**are (the project ethos — every feature built with care) - -### 0.2 What changed in the rename - -| Item | Old | New | -|---|---|---| -| Recipe dir | `local/recipes/tui/tc/` | `local/recipes/tui/tlc/` | -| Cargo package | `name = "tc"` | `name = "tlc"` | -| Cargo `[[bin]]` | `name = "tc"` | `name = "tlc"` | -| Cargo `[lib]` | `name = "tc"` | `name = "tlc"` | -| Binary | `target/release/tc` | `target/release/tlc` | -| Sysroot path | `/usr/bin/tc` | `/usr/bin/tlc` | -| XDG config dir | `$XDG_CONFIG_HOME/tc/` | `$XDG_CONFIG_HOME/tlc/` | -| `directories::ProjectDirs` qualifier | `"tc"` | `"tlc"` | -| Rust path | `tc::*` | `tlc::*` | -| `clap` `name` | `tc` | `tlc` | -| Configs | `tc = {}` | `tlc = {}` | - -## 1. ARCHITECTURE - -### 1.1 Why pure Rust, no FFI - -- `termion` provides everything MC's tty layer did -- `ratatui` provides everything MC's widget layer did -- FFI adds `unsafe`, which project policy forbids (`#![deny(unsafe_code)]`) -- Pure Rust code is auditable, no need to maintain a parallel C build - -The C source of MC 4.8.33 lives at `local/recipes/tui/mc/source/` and serves as -a **read-only cross-reference** for algorithm correctness, edge case coverage, -and feature parity. The Rust code is the source of truth at runtime. - -### 1.2 Module layout (current) - -``` -local/recipes/tui/tlc/ -├── PLAN.md ← this file -├── README.md ← project overview -├── recipe.toml ← cookbook recipe (custom template, cargo build) -└── source/ ← PURE RUST — 138 .rs files, ~57k lines - ├── Cargo.toml ← [package] name = "tlc", no C deps - ├── Cargo.lock - ├── config/default.toml ← embedded default config - ├── locales/{de,en,es,fr,ja,zh-CN}.yml ← rust-i18n catalogues - └── src/ - ├── main.rs ← CLI entry - ├── lib.rs ← #![deny(unsafe_code)] - ├── app.rs ← event loop, full-screen overlay dispatch - ├── config.rs - ├── editor/ ← 16 modules: buffer, cursor, render, syntax, … - ├── filemanager/ ← 18 modules: panel, dialogs, find, hotlist, … - ├── fs/ ← perm, stat (cross-platform via redox_syscall) - ├── key/ keymap/ ← Key, Cmd, F-key codes (0xF100..0xF10B) - ├── locale/ ← rust-i18n bindings - ├── log/ ops/ paths.rs - ├── skin/ ← TOML skin parser - ├── terminal/ ← ratatui+termion FFI bridge + popup shell - ├── text/ viewer/ ← text, hex, source (gz/bz2), search - ├── vfs/ ← trait + 7 backends (local + feature-gated remote) - └── widget/ ← ratatui-backed widgets (button, input, check, radio, toast) -``` - -### 1.3 Recipe - -```toml -# local/recipes/tui/tlc/recipe.toml -[package] -name = "tlc" -version = "0.2.5" - -[build] -template = "custom" -script = """ -cd "${COOKBOOK_SOURCE}" -${CARGO:-cargo} build --release --target x86_64-unknown-redox -mkdir -p "${COOKBOOK_STAGE}/usr/bin" -cp "${COOKBOOK_SOURCE}/target/x86_64-unknown-redox/release/tlc" \ - "${COOKBOOK_STAGE}/usr/bin/tlc" -""" -``` - -### 1.4 Linux portability - -TLC is pure portable Rust. It uses `std::fs`, `cfg(unix)` gates for platform -behavior, ratatui + termion for TUI. Builds and runs natively on Linux with -zero code changes. No `target_os = "redox"` or `target_os = "linux"` gates. - -## 2. CURRENT STATUS - -| Area | Status | -|---|---| -| Cargo build (host Linux x86_64) | ✅ Clean, 3.0 MB binary | -| Cargo build (`--target x86_64-unknown-redox`) | ✅ 3.3 MB statically-linked ELF | -| `cargo test --lib` | ✅ **1433 / 1433 pass** | -| Clippy warnings | ✅ 0 lib warnings (2 pre-existing bin warnings: bitflags macro artifact + manual case-insensitive glob) | -| `#![deny(unsafe_code)]` | ✅ Zero `unsafe` in any `.rs` file | -| `unwrap()`/`expect()` in non-test code | ✅ Audit complete — all `Mutex::lock` use poisoning recovery | -| `todo!()`/`unimplemented!()` in non-test code | ✅ None | -| Live ISO boot (QEMU) | ✅ `build/x86_64/redbear-mini.iso` boots to userspace, `tlc`/`tlcedit`/`tlcview` in sysroot | -| Built-in skins | ✅ 8 (default-dark, default-light, mc-classic, mc-dark, mc-dark-gray, high-contrast, solarized-dark, nord) | -| `~/.config/tlc/config.toml` persistence | ✅ Skin selection persists across launches | - -## 3. MC PARITY ROADMAP (current) - -**Reference:** MC 4.8.33 C source at `local/recipes/tui/mc/source/`. - -### 3.1 Phase status (cumulative) - -| Phase | Items | Status | Date | -|---|---|---|---| -| 14a (CRITICAL — blocks basic usability) | 5/5 | ✅ Done | 2026-06-19 | -| 14b (HIGH — core filemanager + editor) | 6/6 | ✅ Done | 2026-07-05 | -| 14c (MEDIUM — feature completeness) | 14/15 | ✅ Done (1 WONTFIX: Backspace-as-cd..) | 2026-07-05 | -| 14d (LOW — polish and long-tail) | 23/25 | ✅ Mostly Done | ongoing | -| **Total** | **~49/51** | **~96% complete** | — | -| Sprint 1 (A1–A7 critical parity bugs) | 5/5 | ✅ Done | 2026-07-05 | -| Sprint 2 (B1–B8 high-priority polish) | 7/7 + B2 N/A | ✅ Done | 2026-07-05 | -| Sprint 3 (C1–C18 medium polish) | 10/18 + 7 N/A | ✅ Done | 2026-07-05 | -| Sprint 4 / D-series (D1–D8) | 8/8 | ✅ Complete | — | -| Sprint 5 / E-series (E1) | 1/1 | ✅ Complete | — | -| Sprint 5 / F-series (F1–F4) | 4/4 | ✅ Complete | — | -| Sprint 5 / G-series (G1–G2) | 2/2 | ✅ Complete | — | -| **MC-PARITY-AUDIT Phase A** (panel display) | 8/8 | ✅ Done | 2026-07-25 | -| **MC-PARITY-AUDIT Phase B** (critical dialogs) | 7/7 | ✅ Done | 2026-07-25 | -| **MC-PARITY-AUDIT Phase C** (other dialogs) | 1/9 | ✅ Done (1) + 8 deferred | 2026-07-25 | -| **MC-PARITY-AUDIT Phase D** (editor menus) | 9/9 | ✅ Done | 2026-07-25 | -| **MC-PARITY-AUDIT Phase E** (viewer menus) | 8/9 | ✅ Done (1 hotkey collision) | 2026-07-25 | -| **MC-PARITY-AUDIT Phase F** (tests + docs) | in progress | see MC-PARITY-AUDIT.md | 2026-07-25 | - -### 3.2 Remaining LOW-priority items - -All previously deferred items are now resolved: -- Editor multi-cursor — ✅ D7 (Sprint 4) -- Editor spell check — ✅ D8 (Sprint 4) -- PTY-based persistent subshell — ✅ D6 (verified, `LinuxSubshell` in `terminal/subshell.rs`) -- Mouse support — ✅ D5 (Sprint 4, `MouseTerminal` wrapper) - -### 3.3 Sprint 3 items (C1–C18) — final status - -**Implemented (10):** -- C2 VFS parses file:// URLs as local -- C3 Delete dialog shows total recursive size -- C4 Panel::set_path resolves relative paths -- C6 Multi-line status messages -- C7 Hex viewer shows offset header -- C9 Empty pattern inverts/clears marks -- C10 Find dialog pre-fills from cursor entry -- C14 cmdline.execute handles trailing `&` for background -- C15 TarVfs::open rejects empty/garbage archives -- C18 Format paragraph preserves code blocks - -**Verified already-done during recon (7):** -- C1 Theme dispatcher preserves Rgb precision (no to_ansi conversion in renderer) -- C5 Bookmark goto restores column (handlers.rs:978-984) -- C8 Hex-edit cursor bounds validation (viewer/mod.rs:237) -- C11 Quick-cd history dedups consecutive entries (panel.rs:733) -- C12 Sort dialog includes Mtime (sort_dialog.rs:40) -- C16 Subshell uses drop-Tui with cwd (subshell.rs:120) -- C17 Column block selection via Alt-arrows (cursor.rs SelectionMode::Column) - -**Not applicable (1):** -- C13 paste_filename — function does not exist in this codebase - -### 3.4 F9 menu parity (per sub-menu, current count) - -- **Left panel menu**: 13/13 ✅ -- **File menu**: 23/23 ✅ (E1: restructured to match MC `filemanager.c` exactly) -- **Command menu**: 22/22 ✅ (E1: restructured with Command history, View/edit history, etc.) -- **Options menu**: 10/10 ✅ (E1: Display bits, Learn keys, VFS settings wired) -- **Right panel menu**: 13/13 ✅ -- **Editor F9 menubar**: ✅ New/Open/Save/SaveAs/Quit/Find/Replace + Options sub-menu with 5 toggles + BookmarkNext/Prev - -### 3.5 Editor parity - -35/35 ✅ — all features complete: -- Multi-cursor editing (D7: `secondary_cursors`, right-to-left insertion) -- Spell check (D8: `SpellChecker` with ~300-word built-in dictionary) -- Auto-indent, show whitespace, word wrap, syntax highlighting -- Format paragraph, bracket matching, word completion -- Macro recorder, code folding, smooth scroll -- Bookmarks, search/replace, block operations - -### 3.6 Viewer parity - -19/19 ✅ — all features complete: -- Hex view + hex edit with nibble editing (high/low nibble) -- Goto line/percent/byte offset (works in hex mode) -- Search, wrap toggle, growing buffer (tail -f) -- Syntax highlighting, chunked source support - -## 4. RECENT CHANGELOG (last 6 months, condensed) - -### 2026-07-08 — Phase 10b — Archive compress via system tools - -**Compress command added (MC parity, Alt-Shift-C / F9→File→Compress):** -- `Cmd::Compress` dispatches to `FileManager::compress_selected()` which - collects marked (or cursor) files, derives an archive name from the - current directory, and shells out to `tar -czf` via `start_exec()`. - Output and exit status are shown in the exec dialog. -- Added to F9 File menu as "Compress" and default keymap as Alt-Shift-C. -- Follows MC's F2 user-menu compress pattern but as a built-in command. - -### 2026-07-08 — Phase 10a — SFTP open_read streaming + mkdir/remove/rename - -**SFTP VFS full read-write surface:** -- `mkdir`: creates directories via `session.create_dir()` with optional - parent-directory creation (walks path components step-by-step). -- `remove`: deletes files and directories via `session.remove_file()` / - `session.remove_dir()` with recursive support (depth-first child removal). -- `rename`: renames/moves via `session.rename(oldpath, newpath)`. -- `open_read` streaming: replaced `session.read()` (full-file buffer) with - `session.open()` + `SftpReader` — a streaming `Read` bridge that wraps - an open SFTP file handle and reads in bounded chunks via - `AsyncReadExt::read` + `block_on`. Large files are never buffered - in memory. -- Fixed 2 pre-existing warnings (unused `PathBuf` import, missing doc). - -The SFTP backend now exposes the complete Vfs trait surface with zero -`Unsupported` stubs. 1433 tests pass, 1442 with `--features sftp`. - -### 2026-07-08 — W79 — MC visual/behavioral parity polish - -**W79a Viewer:** Two MC parity improvements: -- Enter key bound to cursor-down navigation (MC parity, same as `j`/Down). -- F3 key bound to quit viewer (MC CK_Quit parity, same as Esc/q). -- Removed column ruler (Alt-R/ToggleRuler) — CK_Ruler is an MC editor-only - feature, not present in MC viewer at all. - -**W79b Editor:** Three MC parity improvements: -- Right-margin indicator: draws a vertical `│` at the word-wrap column - (default 72) in every visible body row when word-wrap is active. - Uses `word_wrap_line_length: usize` field (new in Editor struct, - default 72). -- Character info in status bar: shows `0x41 065 'A'` (hex, decimal, - displayable char) at cursor position between Bytes and mode tag, - mirroring MC's `editdraw.c` status-line char display. Falls back - to `.` for non-printable characters. -- Removed line number gutter — MC editor has no gutter or line numbers. - This was a TLC-only addition incompatible with MC parity. Removed: - gutter rendering, `relative_lines` field, `ToggleRelativeLines` Cmd, - Alt-N keybinding, and the Options-menu "Relative line numbers" item. - -**Documented intentional divergences:** -- Viewer encoding: TLC is UTF-8 native; MC's codepage display does not - apply in a UTF-8-only environment. -- Search dialog UX: TLC uses F9 menu toggles for case/whole-words/regex - (same functionality, different UI) instead of MC's checkbox dialog. - -### 2026-07-06 — Sprint 5 / G-series — error dialog retry + SFTP write - -**G1 Error dialog Retry wiring:** The error recovery dialog (D1) now -actually retries the failed operation. Previously, Retry just showed a -status message. Copy/move/delete error paths now create a `PendingErrorOp` -with operation parameters and show the `ErrorDialog` instead of silently -setting a status message. On Retry, the stored operation is re-invoked -via the appropriate `ops::*::*_many()` function. Skip/Ignore/Abort -produce appropriate status messages. - -**G2 SFTP open_write:** `SftpVfs::open_write` now returns a working -`SftpWriter` that buffers writes in memory and flushes to the remote -SFTP server via `session.write()`. Previously returned -`VfsError::Unsupported`. The `SftpWriter` writes on `flush()`/`drop`, -matching the existing `open_read` buffer pattern. - -1369 tests pass (default and `--features sftp`). - -### 2026-07-05 — Sprint 5 / F-series — chunked viewer, xz2, cleanup - -**F1 Stale comment cleanup:** Removed outdated "Phase N" / "not yet wired" -comments from `vfs/local.rs`, `vfs/traits.rs`, `editor/usermenu.rs` — the -functionality they described is already implemented. - -**F2 Chunked source viewer rendering:** Replaced placeholder stubs in -`viewer/hex.rs` and `viewer/text.rs` with actual rendering for Chunked -sources (files >= 1 MiB). Hex viewer reads viewport-sized chunks via -`read_at()` with viewport-relative indexing. Text viewer reads up to -64 MiB cap for line offset mapping. `check_growing()` in `viewer/mod.rs` -also reads Chunked content instead of returning empty Vec. - -**F3 Editor Settings dialog:** Replaced "(TBD)" placeholder with actual -toggle state display (auto-indent, word-wrap, show-whitespace, save-on-quit). - -**F4 tar.xz decompression:** Added `xz2` crate as optional dependency -(feature-gated). `TarKind::Xz` now uses `XzDecoder::new_multi_decoder` -for multi-stream `.tar.xz` files instead of returning `Unsupported`. - -1369 tests pass (default and with `--features xz2`). - -### 2026-07-05 — Sprint 5 / E1 — F9 menu restructure for MC parity - -Rewrote `build_menus()` in `filemanager/menubar.rs` to match MC's -`filemanager.c` menu structure exactly: -- **File menu** (23 items): View, View file..., Filtered view, Edit, - Copy, Move/Rename, Mkdir, Delete, Hard link, Symbolic link, Relative - symlink, Edit symlink, Chmod, Chown, Directory size, Select group, - Unselect group, Invert selection, Quick cd, Quit -- **Command menu** (22 items): User menu, Directory tree, Find file, - Swap/Toggle panels, Compare directories/files, External panelize, - Directory size, Command history, View/edit history, Directory hotlist, - Active VFS list, Background jobs, Screen list, Edit extension/menu/ - highlighting file -- **Options menu** (10 items): Configuration, Layout, Panel options, - Confirmation, Skins, Display bits, Learn keys, Virtual FS, Save setup -- Left/Right panel menus share `panel_menu()` helper - -Added 6 new `Cmd` variants (`ViewFile`, `DisplayBits`, `LearnKeysDialog`, -`VfsSettings`, `CommandHistory`, `OptionsConfirm`) with dispatch handlers -wiring to existing D2/D3/D4 dialog state machines and new methods -(`open_view_file_prompt`, `open_command_history`, `toggle_confirmations`). - -Updated 2 menubar tests to match the new MC-faithful structure. -1369 tests pass. - -### 2026-07-05 — Sprint 4 / D-series dialogs (D1–D4) — 4 commits, 31 new tests - -4 of 8 Phase 14d dialogs implemented, all wired into the -filemanager's `DialogState` enum, dispatch, render, is_finished, -and dialog-title paths. - -**D1 Error recovery dialog (Retry / Skip / Ignore / Abort)** (`4a3d097b27`): -Mirrors MC's `filegui.c::file_progress_real_query_replace` and the -`FileProgressStatus` enum (`filegui.h:45-54`): FILE_CONT, FILE_RETRY, -FILE_SKIP, FILE_ABORT, FILE_IGNORE. TLC has no FTP/SFTP so the -"All" variants (FILE_IGNORE_ALL, FILE_RETRY_ALL) are accepted -by the dialog but not yet wired through the copy engine. -Retry in the progress-dialog error path IS functional (re-begins -the operation and re-runs). Retry in the background jobs dialog -(jobs.rs:600-604) is state-only — the original sources list cannot -be recovered from the jobs dialog context. - -New file: `src/filemanager/error_dialog.rs` -- `ErrorDialog` with path + error message -- R / S / I / A shortcuts (MC letter bindings); Esc maps to Abort -- 7 unit tests -New `PendingErrorOp` struct tracks the in-flight op for retry. - -**D2 Display bits dialog (8 / 7 / UTF-8)** (`6c771d88f9`): -Mirrors MC's `boxes.c::display_bits_box` -(`mc/source/src/filemanager/boxes.c:955-1004`). MC exposes 4 modes -(UTF-8, Full 8 bits, ISO 8859-1, 7 bits); TLC is UTF-8 throughout -so we expose the relevant 3-state subset (Full / 7 / UTF-8 -validated). - -New file: `src/filemanager/display_bits_dialog.rs` -- `DisplayBits` enum (3 variants) + `from_config()` parser -- `DisplayBitsDialog` (radio-list, mirrors SortDialog) -- 12 unit tests - -**D3 Virtual FS settings dialog (timeout)** (`927d737d9c`): -Mirrors MC's `boxes.c::configure_vfs_box` -(`mc/source/src/filemanager/boxes.c:1120-1198`). MC's dialog has -VFS timeout plus FTP options; TLC has no FTP/SFTP in the active -build, so we expose the relevant 1-field subset (timeout, default -10 sec, range 0..=10000 with out-of-range falling back to 10 to -match MC's `boxes.c:1193-1194` validation). - -New file: `src/filemanager/vfs_settings_dialog.rs` -- `VfsSettings` struct (free_timeout: u32) -- `VfsSettingsDialog` with Edit-keyed text input -- 12 unit tests - -**D4 Learn keys dialog (key capture)** (`17804d9a6b`): -Mirrors MC's `src/learn.c::learn_keys` -(`mc/source/src/learn.c:393-422`). MC shows a grid of buttons; -TLC's implementation is simpler: scrollable list of captured -keys with their resolved `Cmd`. - -New file: `src/filemanager/learn_keys_dialog.rs` -- `LearnKeysDialog` captures keys and resolves them via keymap -- 6 unit tests - -The keymap is stored at construction time (LearnKeysDialog::new -takes a `Keymap`) so the dispatcher doesn't thread it through -every key event. `Default` uses `default_keymap()`. - -### 2026-07-05 — Sprint 4 / D-series (D5–D8) — 3 commits, 33 new tests - -**D5 Mouse support** (`7a2b0d5160`): -Mirrors MC's `panel.c::panel_event` mouse handler -(`mc/source/src/filemanager/panel.c:4080-4197`). MC handles -wheel scroll, click-to-select, double-click-to-enter, and -history-bar clicks. TLC implements: -- `MouseTerminal>>` wrapper - enables mouse tracking via `?1000h` / `?1006h` escape sequences -- `translate_mouse()` converts `MouseEvent::Press`/`Release`/`Hold` - + button into `MouseAction` enum -- `MouseAction::ScrollUp`/`ScrollDown` → `Panel::cursor_up_n`/ - `cursor_down_n` (matches MC wheel behavior) -- `MouseAction::Click` → selects the entry at the clicked row -- `MouseAction::DoubleClick` → `Panel::enter()` (opens dir/file) -- Double-click detection uses 500ms timeout (MC parity) -- 9 unit tests for mouse event translation - -Modified files: `terminal/mod.rs`, `terminal/event.rs`, -`filemanager/mod.rs`, `app.rs`. - -**D6 PTY-based persistent subshell** — verified already done: -TLC's `terminal/subshell.rs::LinuxSubshell` already implements -MC's `subshell/common.c` pattern: -- `openpt(O_RDWR | O_NOCTTY | O_CLOEXEC)` → `grantpt` → `unlockpt` -- `ioctl(TIOCGPTPEER)` for slave fd (Linux ≥ 4.11 fast path) -- `setsid()` + `TIOCSCTTY` in child via `spawn_linux_interactive_shell` -- `poll()` loop in `attach()` proxies stdin ↔ master fd -- `sync_pty_size()` mirrors MC's `tty_resize` for window resizing -- 12 unit tests for subshell command execution -- Wired via `ExternalAction::Subshell(PathBuf)` in `app.rs` - -**D7 Editor multi-cursor** (`b8aac3c9bc`): -TLC enhancement beyond MC (MC is single-cursor). Adds: -- `secondary_cursors: Vec` field on `Editor` -- `add_secondary_cursor(byte_pos)` — adds cursor (dedup + sort) -- `clear_secondary_cursors()` — collapses to single cursor -- `insert_char_multi(c)` — inserts at all cursors (right-to-left) -- `delete_back_multi()` / `delete_forward_multi()` — same pattern -- UTF-8 aware: multi-byte chars advance cursor offsets correctly -- 7 unit tests - -**D8 Editor spell check** (`76df890074`): -MC uses dynamically-loaded libaspell (`editor/spell.c:33`). -TLC has no external spell-check dependency — implements: -- `SpellChecker` with ~300 built-in common English words -- Word tokenizer handles apostrophes, digits, underscores -- Short words (≤1 char), digit-containing, underscore-containing - always considered correct (identifiers, numbers, file names) -- Case-insensitive matching via `to_ascii_lowercase()` -- `Editor::find_next_misspelled(from_byte)` — MC-style scan -- `Editor::toggle_spell_check()` — enable/disable -- 17 unit tests (13 in `spell.rs` + 4 in `editor/mod.rs`) -- Architecture supports future runtime dictionary loading - -### 2026-07-05 — Sprint 3 (C1–C18 medium polish) — 10 commits, 27 new tests - -10 of 18 items implemented (7 were verified already-done, 1 was N/A): - -**C2 VFS parses file:// URLs as local** (`08dbaf519a`): `vfs/path.rs::parse()` -now accepts `file:///path` as an alias for `local:///path`, matching the -standard URL scheme used by browsers, text editors, and CLI tools. - -**C3 Delete dialog shows total recursive size** (`8ca31beee3`): -`DeleteDialog::new()` eagerly calls `crate::ops::count_bytes` to populate -a `total_bytes` field; render header now shows "Delete N items (X MB) ?". - -**C4 Panel::set_path resolves relative paths** (`b058c05338`): -`Panel::set_path()` now joins relative paths to `std::env::current_dir()` -before navigation; absolute paths pass through unchanged. - -**C6 Multi-line status messages** (`40d091226f`): When `set_message` is -called with text containing `\n`, the status line allocates extra rows -above the regular clock/spinner/hint bar. `Message::line_count()` + -`StatusLine::has_multiline_message()` + `StatusLine::render_multiline()`. - -**C7 Hex viewer shows offset header** (`ab2d5de81d`): Hex view splits its -area into a 1-row header showing "Offset: 00000040 / 00000100 bytes" and -the body rows. Header is skipped on 1-row areas. - -**C9 Empty pattern inverts/clears marks** (`790e476d8e`): -`Panel::mark_pattern("")` calls `reverse_marks()`; `unmark_pattern("")` -clears all marks. Matches MC's "Select group"/"Unselect group" with -empty expression. - -**C10 Find dialog pre-fills from cursor entry** (`d14d4ad72d`): New -`find::FindDialog::new_with_pattern(start, pattern)` + `Input::set_text()` -mutable setter; `open_find_dialog()` uses the cursor entry's name as -the initial pattern (skips `..`). - -**C14 cmdline.execute handles trailing `&`** (`eaf3c221ab`): -`ShellManager::run_command` detects a trailing `&` (with optional -trailing whitespace) and spawns the command in a new process group -via `process_group(0)` so it survives the shell exiting. - -**C15 TarVfs::open rejects empty/garbage archives** (`1826f079d3`): -After `list()`, check `entries.is_empty()` and return -`VfsError::Other("empty tar archive")` if so. The tar crate silently -accepts zero-byte and garbage files as valid (returning an empty -iterator); without this check the user would see a successful open -of an unbrowsable archive. - -**C18 Format paragraph preserves code blocks** (`dfd75b52f6`): -`reformat_paragraph_at()` now calls `is_code_block(paragraph)` first; -indented paragraphs (every non-blank line starts with whitespace) are -left unchanged. New `is_code_block()` helper. Prevents formatting from -destroying Python indentation, shell heredocs, etc. - -**Already-done items verified during recon:** C1 (Rgb precision preserved -end-to-end, no `to_ansi` in render path), C5 (bookmark goto restores -column at handlers.rs:978-984), C8 (hex-edit cursor bounds check at -viewer/mod.rs:237), C11 (history dedups consecutive entries at -panel.rs:733), C12 (sort dialog includes Mtime at sort_dialog.rs:40), -C16 (subshell uses drop-Tui with cwd at subshell.rs:120), C17 (column -block selection via SelectionMode::Column). - -**Not applicable:** C13 paste_filename — function does not exist in TLC -(TLC doesn't have a separate paste filename feature; pasted paths -come from `cmdline.insert_text(&path)` which preserves trailing -whitespace). - -### 2026-07-05 — Sprint 2 (B1–B8 high-priority polish) — 7 commits, 38 tests - -7 items done (B2 was verified already-done during recon): - -**B1 Word-boundary wrapping** (`135e94b5e4`): `build_wrap_map` in -`editor/render.rs` now uses a word-boundary algorithm (last whitespace -before wrap limit, mid-word fallback for overlong words) with proper -visual column counting (tabs expand to next `tab_width` boundary). - -**B3 Tab-to-indent** (`2633c40dfd`): New `Editor::insert_tab_with_indent()` — -inserts spaces to next `tab_width` boundary when cursor is in the -indent zone (only whitespace before); inserts literal `\t` otherwise. - -**B4 Configurable tab width / Alt-T** (`d4ddc4e2c7`): New -`Editor::cycle_tab_width()` (cycles 4 → 8 → 2), `set_tab_width()`, -Alt-T bound in `try_global_shortcut`. - -**B5 Bookmark line adjustment on edit** (`109bdc8dc3`): New -`BookmarkSet::adjust_lines(at_line, delta)` shifts bookmarks on insert/ -delete. `Editor::adjust_bookmarks_after_edit()` wraps `insert_char`, -`insert_str`, `delete_back`, `delete_forward`. - -**B6 Streaming search for Chunked sources** (`3f4f76a762`): -`Search::find_all_streaming` with sliding-window algorithm (last -`pattern.len() - 1` bytes from each chunk combined with next chunk for -regex). Used by `Viewer::search()` for Chunked sources — previously -read the ENTIRE file into RAM. - -**B7 Case-insensitive theme alias expansion** (`c737337681`): -`Theme::by_name()` now lowercases input before alias matching so -`MC-Classic`, `Mc-Dark`, `DARK` all resolve. - -**B8 Input widget uses theme tokens** (`9ea6826a58`): -`Input::new()` defaults `fg`/`bg`/`cursor_color` to `Color::Reset` -sentinel; `render()` falls back to `theme.foreground` / -`theme.background` / `theme.warning`. New `cursor_color()` builder. - -**B2 already-done:** `marked: HashSet` is already O(1). - -### 2026-07-05 — Sprint 1 (A1–A7 critical parity bugs) — commit `a2df7a06cf` - -**A1 Editor line number gutter**: `editor/render.rs` splits inner area into -`gutter_area` + `body_area`; right-aligned numbers (or relative offsets when -`relative_lines` mode is on); bookmark rows show current-line style; `~` shown -for lines past end-of-file. 4 test x-coordinates shifted by `gutter_chars`. - -**A2 Viewer cursor line highlight**: `viewer/text.rs` computes -`cursor_line_bg = body_bg + RGB(12,12,12)`; applied before search-match overlay -so matches win on the cursor line. 1 viewer test moves cursor to line 1 so the -cursor-line highlight doesn't overlap the search-match assertion. - -**A3 Hide terminal cursor in file manager mode**: `app.rs` `hide_cursor()` after -`Tui::new()`; `render()` shows cursor only when editor/viewer/cmdline/dialog/ -menubar is active. - -**A6 Shift-F5/F6 same-directory rename**: New `Cmd::CopySameDir` and -`Cmd::MoveSameDir` variants bound to `Shift-F5` / `Shift-F6`. Reuse -`CopyDialog` / `MoveDialog` with a new `same_dir: bool` flag and `new_rename()` -constructor; `result()` resolves typed name against source's parent directory. -`dialog_ops.rs` adds same-dir dispatch + `open_*_same_dir_dialog` functions. -For copy, uses `std::fs::copy`; for move, uses `ops::move_op::move_one`. -Includes `PendingFileOp` overwrite dialog for existing destinations. - -**A7 SUID/SGID/sticky bits in chmod dialog**: `filemanager/permission.rs` -4-row PermCell grid (user/group/other/special) with `class_shift = 0o4000, -bit = 1`; 12 cells total; display as `0oXXXX` (4-digit octal with `0o7777` -mask). Overwrite dialog shows all 12 cells. 6 new unit tests cover all -special-bit combinations. - -**Tests:** 1230 passed (was 1219; +11 new tests across A7 and A6). -**Files:** 10 files changed, 556 insertions(+), 121 deletions(-). - -### 2026-07-05 — §33 Editor F9 menubar + remaining command wiring - -- §33.1 Editor F9 Options menu: 5 new EditorCmd variants - (ToggleAutoIndent, ToggleShowWhitespace, ToggleWordWrap, ToggleSyntax, - ToggleRelativeLines) with full Options menu and `dispatch_editor_cmd` handlers. -- §33.2 Editor F9 menubar commands wired: New, Open, Save, SaveAs, Quit, - Find, FindNext, FindPrev, Replace, BookmarkNext, BookmarkPrev all routed - through `dispatch_editor_cmd`. Previously printed "not yet wired". -- §33.3 Ctrl-X h chord dispatches to Cmd::HotList (AddCurrent path). -- §14.1–§14.6 comprehensive PLAN refresh: §14.1 77/78 ✅ (was stale at ~73/77). - §14.2 Left/Right menu 13/13 ✅. File menu 20/21 ✅. Command menu 17/20 ✅. - Options menu 7/10 ✅. §14.3 All panel features current. §14.4 All file - ops current. §14.5 Editor 28/35 ✅ (was 15/35). §14.6 Viewer 17/19 ✅ - (was 6/19). Overall parity: ~93% complete (~44/51 items). - -### 2026-07-05 — §32 Viewer wrap fix - -- §32.1 Viewer word-wrap fix (`viewer/text.rs`): `Paragraph::wrap()` was - always on regardless of `v.wrap` toggle. Now `.wrap(Wrap { trim: false })` - is conditionally applied only when `v.wrap` is true. When wrap is off, - long lines truncate at the right margin (MC parity). Stale TODO removed. -- §32.2 Alt-W wrap toggle test (`viewer/mod.rs`): test verifying Alt-W - toggles wrap field correctly. - -### 2026-07-05 — §31 SortDialog wiring, truncation indicators, editor toggles - -- §31.1 SortDialog wiring: orphaned `SortDialog` connected to Alt-Shift-T - binding, `Cmd::SortDialog` variant, `DialogState::Sort` variant, - `apply_sort()` on Panel. -- §31.2 Filename truncation indicator: `truncate_to_width()` appends `~` - when content overflows panel width; applied to Long/Full listing modes, - info mode, quickview mode. -- §31.3 Editor auto-indent toggle: `auto_indent: bool` (default on); - Alt-A toggles. -- §31.4 Editor show whitespace toggle: `show_whitespace: bool` (default off); - Alt-E toggles; `push_rendered_text` gains `show_ws` param. - -### 2026-07-04 — §30 Panel display, navigation, and file-op parity - -- §30.1 Cursor memory: per-directory cursor save/restore via `HashMap`. -- §30.2 mtime column: MC-style dual-format dates (recent `