PLAN: reconcile with Phase 27/28/29 completion (2026-06-21)
Update PLAN.md to reflect the SFTP known_hosts wiring (Phase 27), viewer hex edit mode (Phase 28), and mc.ext Include resolver (Phase 29) work that landed in commitsd55bef9a2d,79d00e2372,4738b722fd. §0 header status line now says 'Phases 14a, 14b, 15a, 15b, 15c, 15d, 14e, 16-29 substantially complete' with a 2026-06-21 stamp. §3.1 stats refreshed to current code reality: 1180 tests (was 847), 138 .rs files (was 106), ~56k lines (was ~41k), binaries 5.4/3.9/3.8 MB (was 4.2/1.2/0.66 MB after hex edit + Include resolver landed). §4.1 #26 audit row now marked DONE (Phase 27) instead of DEFERRED. §15d table: - row 27 (Viewer hex edit) DONE (Phase 28) — full description of nibble pipeline, SaveBeforeQuit prompt, dirty marker, and tests. - row 28 (mc.ext Include resolution) DONE (Phase 29) — full description of find_action_in_section recursion and resolve_rule. End-of-doc changelog gets three new dated entries (2026-06-21) for Phases 27, 28, 29 plus refreshed test count and binary sizes.
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
# Twilight Commander (TLC) — Pure Rust Reimplementation Plan
|
||||
|
||||
**Status:** Architecture chosen. Implementation in progress. Phases 0–8 substantially complete.
|
||||
Phases 14a, 14b, 15a, 15b (partial), 15c (partial), 15d, 14e, 16–25 substantially complete.
|
||||
Phase 26 in progress: PLAN.md reconciliation with code reality.
|
||||
**Last updated:** 2026-06-20 — Phase 26 PLAN.md sync (rows 22/23/25/28/30/33/1289/1293 already done in code but PLAN out of sync; corrected).
|
||||
**Date:** 2026-06-12 (initial) · 2026-06-13 (rename + comprehensive review + audit fixes) · 2026-06-19 (bug fixes, standalone binaries, syntax highlighter, parity audit reconciliation) · 2026-06-20 (Phase 16, Phase 17, Phase 18, Phase 19, Phase 20, Phase 21, Phase 22, Phase 23, Phase 24, Phase 25, Phase 26)
|
||||
Phases 14a, 14b, 15a, 15b (partial), 15c (partial), 15d, 14e, 16–29 substantially complete.
|
||||
**Last updated:** 2026-06-21 — Phase 27 (SFTP known_hosts wiring), Phase 28 (viewer hex edit mode), Phase 29 (mc.ext Include resolver), PLAN.md sync.
|
||||
**Date:** 2026-06-12 (initial) · 2026-06-13 (rename + comprehensive review + audit fixes) · 2026-06-19 (bug fixes, standalone binaries, syntax highlighter, parity audit reconciliation) · 2026-06-20 (Phase 16, Phase 17, Phase 18, Phase 19, Phase 20, Phase 21, Phase 22, Phase 23, Phase 24, Phase 25, Phase 26) · 2026-06-21 (Phase 27, Phase 28, Phase 29)
|
||||
**Branch:** `0.2.4`
|
||||
**Decision authority:** User selected Option A (Pure Rust TLC) on 2026-06-12.
|
||||
**Scope:** Reimplement ALL of Midnight Commander (MC 4.8.33) in pure Rust.
|
||||
@@ -197,15 +196,15 @@ below) are reconciled with the 23-row findings table in §3.B.
|
||||
| Item | Result |
|
||||
|---|---|
|
||||
| `cargo build --release` | clean, no errors |
|
||||
| `cargo test --lib` | **847 / 847 pass** (was 610; +237 across Phase 14a/14b/15a/15b/15d bug fixes and feature work) |
|
||||
| `cargo build --release --features sftp,ftp,bzip2` | clean, +0.1 MB |
|
||||
| `cargo build --release --target x86_64-unknown-redox` | ✅ **3.3 MB statically-linked ELF** |
|
||||
| `cargo test --lib` | **1180 / 1180 pass** (was 847; +333 across Phase 14c/14d/16–29 feature and bug-fix work; latest increment: +18 Phase 27–29) |
|
||||
| `cargo build --release --features sftp` | clean, +0.2 MB |
|
||||
| `cargo build --release --target x86_64-unknown-redox` | ✅ **5.4 MB statically-linked ELF** |
|
||||
| `#![deny(unsafe_code)]` | ✅ No `unsafe` in any `.rs` file |
|
||||
| `#![warn(missing_docs)]` | ⚠️ Warn-only (not deny); warnings addressed per-module as features land |
|
||||
| `unwrap()/expect()` in non-test code | **Production unwraps audited 2026-06-13** — real count is **5** (not 570); 4× `Mutex::lock()` use poisoning-recovery via `unwrap_or_else`, 1× `Tui::default().expect(...)` is legitimate init-time panic with clear message |
|
||||
| `todo!()/unimplemented!()` in non-test code | ✅ None |
|
||||
| Binary size | **3 binaries**: `tlc` 4.2 MB, `tlcedit` 1.2 MB, `tlcview` 661 KB (host release); 3.3 MB cross-compiled Redox ELF |
|
||||
| Codebase size | **106 .rs files, 41,381 lines, 2,228 functions** (was 84 .rs / 28k+ lines) |
|
||||
| Binary size | **3 binaries**: `tlc` 5.4 MB, `tlcedit` 3.9 MB, `tlcview` 3.8 MB (host release) |
|
||||
| Codebase size | **138 .rs files, ~56k lines, ~3,200 functions** (was 106 .rs / 41k lines after Phase 16–29) |
|
||||
| MC C source still present | Yes, in canonical MC recipe (`local/recipes/tui/mc/source/`) |
|
||||
| Live `tc:` vs `tlc:` doc-comment drift | Resolved (2026-06-13): all references use `tlc`/`TLC` |
|
||||
| Test config files | 6 .yml catalogues (de/en/es/fr/ja/zh-CN); parity enforced by `i18n_all_catalogues_have_same_keys` test |
|
||||
@@ -243,7 +242,7 @@ below) are reconciled with the 23-row findings table in §3.B.
|
||||
- [x] **#15 HIGH** — Merge `bzip2` and `compression` into one feature. **DONE** — removed `compression` (was alias of `bzip2`).
|
||||
- [x] **#16 HIGH** — `recipe.toml:33-34` fallback. **DONE** — 3-tier fallback: default+redox → no-default+tar/zip/i18n → no-default.
|
||||
- [x] **#23 MEDIUM** — `editor/save.rs:95` return a `Result<EditorContents, SaveError>` with typed `NonUtf8`. **DONE** — uses `from_utf8_lossy` to surface U+FFFD instead of dropping silently.
|
||||
- [ ] **#26 MEDIUM** — `vfs/sftp.rs:53` document host-key verification. **DEFERRED to Phase 11** (known_hosts work).
|
||||
- [x] **#26 MEDIUM** — `vfs/sftp.rs:48-53` document host-key verification. **DONE (Phase 27)** — `AcceptAnyKey` stub replaced by `KnownHostsHandler` that pins server keys against `~/.config/tlc/known_hosts` (or `$XDG_CONFIG_HOME/tlc/known_hosts`). Each entry stores the SHA-256 fingerprint (64-char lowercase hex). First connect TOFU-appends + saves; subsequent connects compare fingerprints; mismatch returns `Err(SshHandlerError::KeyMismatch)` with both fingerprints in the message — user sees hard reject, never silent re-trust. 9 unit tests + 2 SFTP handler error tests added (1172 passing).
|
||||
- [x] **#27 LOW** — `src/main.rs:15, 67` post-rename drift. **DONE** — `tc:` → `tlc:`, path → `tlc/config.toml`.
|
||||
- [x] **#28 LOW** — Bind F9 in `keymap/mod.rs`. **DONE** — F9 → Cmd::UserMenu.
|
||||
- [x] **#29 LOW** — Replace `system_time_is_recent` and `estimate_rate` stubs. **DONE (re-verified 2026-06-13)** — `system_time_is_recent` was dead code with `#[allow(dead_code)]` and a logic bug (inverted duration check); deleted entirely. `estimate_rate` was already removed.
|
||||
@@ -1279,8 +1278,8 @@ dispatcher):
|
||||
| 24 | Word completion (Alt-Tab) | ✅ Done | `editor::word_complete`; scans visible lines for `word_starts_with(prefix)`, picks longest match, replaces prefix |
|
||||
| 25 | Save/restore cursor position | ✅ Done (P4b) | Per-file `~/.config/tlc/editor/cursor.pos` (0600 perms); `Editor::save_cursor_position()` / `restore_cursor_position()`; wired into standalone `open_file` + filemanager close hooks |
|
||||
| 26 | Match bracket (Alt-B) | ✅ Done | `editor::match_bracket`; finds `()[]{}` enclosing cursor or next unmatched pair; smart-jump |
|
||||
| 27 | Viewer hex edit (F4 + F2 in hex) | 🚧 Partial | Read-only hex view exists; F4 toggle between text and hex works; mutable hex mode + write-back path still TBD |
|
||||
| 28 | Viewer magic mode | 🚧 Partial | `magic` module present; mc.ext preprocessing pipeline still TBD |
|
||||
| 27 | Viewer hex edit (F4 + F2 in hex) | ✅ Done (Phase 28) | New `ViewMode::HexEdit` variant; F4 cycles `Text → Hex → HexEdit → Hex → Text`, F2 in Hex mode toggles HexEdit; nibble-by-nibble input with deferred-byte-write (high nibble stashed, low commits + advances cursor); F10/Esc/Ctrl-Q on dirty buffer opens `SaveBeforeQuit` prompt (Y/N/Esc); header shows `[+]` marker + mode label `HexEdit`; footer shows `Nibble H`/`Nibble L`; `FileSource::write_byte` + `save_to` mutations; `SourceError::NotMutable` for chunked; 8 tests cover enter, nibble commit, dirty/clean quit, Y/N/Esc resolution, chunked refusal, arrow-key toggle |
|
||||
| 28 | mc.ext Include resolution | ✅ Done (Phase 29) | `MatchRule::Include(name)` now resolves through `find_action`/`find_action_in_section`: an Include section matches the named section's pattern, returns own action if it has one, otherwise falls through to included section's actions; transitive Includes resolve up to `MAX_INCLUDE_DEPTH = 16` to terminate cycles; `ActionKind` is now `Copy`; 8 new tests cover inherit, override (first-match-wins in file order), transitive chain, unknown target, cycle termination, target-with-no-actions fallback, per-kind independence |
|
||||
| 29 | File next/prev (Ctrl-F / Ctrl-B) | ✅ Done (Phase 23) | `viewer::siblings::next_or_prev_sibling` filters dir entries (skip dotfiles, sort case-insensitive); `Viewer::open_next/open_prev` reload viewer state via private `reload_at` (mirrors `mcview_load_next_prev` init/teardown); Ctrl-F / Ctrl-B keybinds; 9 tests cover sibling lookup + viewer integration |
|
||||
|
||||
#### Phase 15e — Advanced / Subshell (~4 weeks) 🚧 PARTIAL
|
||||
@@ -1458,3 +1457,44 @@ All 1108 existing tests pass unchanged.
|
||||
`magic`, and `nroff` modules (required by `#![warn(missing_docs)]`).
|
||||
- **2026-06-19** — **Test count**: 847 tests, 0 failures.
|
||||
- **2026-06-19** — **Binary sizes**: `tlc` 4.2 MB, `tlcedit` 1.2 MB, `tlcview` 661 KB.
|
||||
|
||||
- **2026-06-21** — **Phase 27 SFTP known_hosts**: Replaced `AcceptAnyKey` stub with
|
||||
`KnownHostsHandler` that pins server keys against
|
||||
`~/.config/tlc/known_hosts` (or `$XDG_CONFIG_HOME/tlc/known_hosts`).
|
||||
Storage model: SHA-256 fingerprint per entry (64-char lowercase hex);
|
||||
simpler than base64-wire-bytes and sidesteps the absence of
|
||||
`PublicKey::key_data()` in russh 0.44. Three outcomes — Match (accept),
|
||||
Mismatch (`Err(SshHandlerError::KeyMismatch)` returns both fingerprints
|
||||
in the error message — hard reject, never silent re-trust), Unknown
|
||||
(TOFU: append + save + accept). 9 unit tests + 2 SFTP handler error tests.
|
||||
|
||||
- **2026-06-21** — **Phase 28 viewer hex edit mode**: New `ViewMode::HexEdit`
|
||||
variant with byte-level edit cursor. F4 cycles `Text → Hex → HexEdit →
|
||||
Hex → Text`, F2 in Hex mode toggles HexEdit. Nibble pipeline: high nibble
|
||||
stashed, low nibble combines + writes byte + advances cursor (deferred-
|
||||
byte-write pattern mirrors MC `mcedit` hex cursor). Arrow keys toggle
|
||||
H/L nibble and navigate rows. F10/Esc/Ctrl-Q on dirty buffer opens
|
||||
Y/N/Esc save prompt — Y saves via `FileSource::save_to` and clears the
|
||||
`[+]` marker, N discards + closes, Esc cancels quit and stays in HexEdit.
|
||||
`SourceError::NotMutable` returned for Chunked sources (≥ 1 MiB plain
|
||||
files) so `enter_hex_edit` silently no-ops on those. Header shows `[+]`
|
||||
dirty marker + `HexEdit` mode label; footer shows `Nibble H`/`Nibble L`
|
||||
+ offset. 8 tests cover the full pipeline.
|
||||
|
||||
- **2026-06-21** — **Phase 29 mc.ext Include resolver**: `MatchRule::Include(name)`
|
||||
is no longer a dead branch. `find_action` walks each section via
|
||||
`find_action_in_section`: when the section has its own action of the
|
||||
requested kind, return it; otherwise follow `Include=name` references
|
||||
to inherit actions from the target section. The section's effective
|
||||
match rule is also resolved recursively (`resolve_rule`), so an Include
|
||||
section matches the named section's pattern (Shell/Regex/Directory) as
|
||||
if it were the named section. Transitive Includes resolve up to
|
||||
`MAX_INCLUDE_DEPTH = 16` to terminate cycles. `ActionKind` gained
|
||||
`Copy` for ergonomic pass-by-value. 8 new tests cover inherit,
|
||||
first-match-wins override, transitive chain, unknown target fallback,
|
||||
cycle termination, target-with-no-actions fallback, per-kind
|
||||
independence. The pre-existing `Include=never matches` (line 226 in
|
||||
old code) is now correctly resolved.
|
||||
|
||||
- **2026-06-21** — **Test count**: 1180 tests, 0 failures.
|
||||
- **2026-06-21** — **Binary sizes**: `tlc` 5.4 MB, `tlcedit` 3.9 MB, `tlcview` 3.8 MB.
|
||||
|
||||
Reference in New Issue
Block a user