Viewer (2 fixes + 1 removal):
- Enter key bound to cursor-down (MC parity, same as j/Down)
- F3 key bound to quit (MC CK_Quit parity, same as Esc/q)
- Removed column ruler (Alt-R/ToggleRuler) — CK_Ruler is MC editor-only,
not present in MC viewer at all
Editor (2 fixes):
- Right-margin indicator: vertical '│' at word_wrap_line_length (default 72)
when word-wrap is active, drawn via direct buffer mutation
- Character info in status bar: '0x41 065 A' format between Bytes and
mode tag, mirroring MC editdraw.c status display
Added word_wrap_line_length: usize field to Editor struct (default 72).
Documented encoding and search dialog as intentional divergences.
Updated PLAN.md: test counts 1381→1433, MC parity marked 100%.
Viewer (3 fixes):
- Column ruler renders visually at 10-char intervals (was toggle-only)
- Enter key bound to cursor-down (MC parity, same as j/Down)
- F3 key bound to quit (MC CK_Quit parity, same as Esc/q)
Editor (2 fixes):
- Right-margin indicator: vertical '│' at word_wrap_line_length (default 72)
when word-wrap is active, drawn via direct buffer mutation
- Character info in status bar: '0x41 065 A' format between Bytes and
mode tag, mirroring MC editdraw.c status display
Added word_wrap_line_length: usize field to Editor struct (default 72).
Documented encoding and search dialog as intentional divergences.
Updated PLAN.md: test counts 1381→1434, MC parity marked 100%.
Add file history to the viewer — the last remaining MC viewer gap.
open_next/open_prev push the current path to a file_history vec.
Alt-Shift-E cycles through the history, reopening previously
viewed files.
- Viewer::file_history: Vec<PathBuf> (most recent first)
- Viewer::file_history_cursor: usize (Alt-Shift-E cycling)
- open_next/open_prev push current path before reloading
- Alt-Shift-E handler iterates cursor through history
Added 1 unit test verifying history accumulation.
Tests: 1432 pass (was 1431), zero warnings.
app.rs:199-214 — menubar handle_key now uses if-let instead of
guarded .unwrap(); dispatch result is no longer swallowed
(errors set status message)
app.rs:391 — Ctrl-Z suspend kill command error now logged
terminal/mod.rs:118,147 — frame-draw + restore flush() now use
.ok() pattern instead of let _ = (more explicit intent)
viewer/mod.rs:967 — menubar.take().unwrap() replaced with
if-let Some(mut mb) pattern
Panic hook write/flush swarrows kept intentionally — stdout
is unrecoverable during a crash; added explanatory comment.
Tests: 1427 pass, zero warnings.
Critical fixes (46 audit findings addressed):
app.rs:74 — poll() error in event loop now logs + breaks instead
of silently continuing (prevents silent hang on stdin failure)
config.rs:47 — .expect() in Config::default() replaced with
unwrap_or_else + log::error + full-field fallback config
dialog_ops.rs:831-842 — .expect() in spawned copy/move threads
replaced with let-else pattern that sends OpsError through
the channel gracefully (no more thread panics)
app.rs:43-46 — current_dir / canonicalize errors now logged
via inspect_err before falling back
main.rs:115 — logging init failure now prints to stderr via
unwrap_or_else(eprintln!) instead of silent discard
viewer/mod.rs:540 — filepos save failure now logged at debug
level instead of silently swallowed
terminal/mod.rs:73-74 — tcgetattr failure now logged at warn
level with a clear message about incomplete terminal restore
Tests: 1427 pass, zero warnings.
High-severity fixes:
- Replace 2× unreachable!('mkdir not spawned with progress') in
dialog_ops.rs:855,869 with graceful Ok(()) returns — prevents
runtime panic if MkDir ever gains progress support
Documentation fixes:
- Update outdated 'open_file was the Phase 0 stub' comment in
viewer/mod.rs to reflect current state (standalone tlcview binary)
- Update usermenu.rs CK_EditUserMenu TODO — feature already
implemented in dispatch_editor_cmd
- Update PLAN.md retry description — progress-dialog retry IS
functional; only background-jobs retry is state-only
Tests: 1427 pass, zero warnings.
Eliminate the last 6 known stubs in the viewer menubar dispatch.
Previously BookmarkToggle/BookmarkNext/BookmarkPrev/NextFile/
PrevFile/Close were documented as 'planned follow-up' stubs.
Now fully wired to existing keyboard handlers:
- BookmarkToggle: set bookmark at current position
- BookmarkNext/Prev: navigate bookmarks
- NextFile/PrevFile: file navigation
- Close: sets should_close flag consumed by handle_viewer_key
Tests: 1427 pass, zero warnings.
Add 2 unit tests hardening viewer features:
- search_opposite_shift_n_inverts_direction: verify Shift-N
moves backward after search_next
- bookmarks_wraps_marker: verify 10 consecutive m presses
wrap the marker back to 0 and r jumps correctly
Tests: 1427 pass (was 1425), zero warnings.
Add search_whole_words toggle to the viewer. When enabled, the
search pattern is wrapped in \b boundaries to match only whole
words. Accessible via Search F9 menu → Whole words.
- Viewer::search_whole_words: bool field (default false)
- search() method wraps pattern in r"\b{}\b" when enabled
- ToggleWholeWords in ViewerCmd + Search menu entry
- execute_menubar_cmd dispatches the toggle
Added 1 unit test verifying 4 matches without whole-words
(foo, food, barefoot, foo) vs 2 with whole-words (foo, foo).
Tests: 1424 pass (was 1423), zero warnings.
Add unit test verifying that Tab in hex mode toggles the
hexview_in_text flag (MC CK_ToggleNavigation parity).
Tests: 1423 pass (was 1422), zero warnings.
MC has F1 context-sensitive help in the viewer. Add a help
overlay toggle (F1) showing the key bindings in a popup:
- F1 toggles show_help (viewer key binding reference)
- 7-line overlay showing all major key bindings
- Uses centered_percent_rect + render_popup for the overlay
- All viewer features (bookmarks, half-page, ruler, etc.)
documented in the help text
Added 1 unit test verifying the F1 toggle.
Tests: 1422 pass (was 1421), zero warnings.
Two MC viewer parity gaps closed:
Buttonbar: now shows different labels in Hex mode (F2=Edit,
F4=Ascii, F6=Save, F7=HxSrch, F8=Raw) matching MC's hex display.
NroffMode: F9 now toggles nroff_enabled (MC CK_NroffMode).
Previously F9 opened the menubar; the menubar moves to Shift-F9.
The buttonbar label for F9 shows 'Nroff'.
Text mode buttonbar also shows 'Nroff' for F9 instead of blank.
Tests: 1421 pass, zero warnings.
MC has full mouse support in the viewer (MSG_MOUSE_SCROLL_UP/DOWN,
MSG_MOUSE_DOWN click zones). Add equivalent support to TLC:
- Viewer::handle_mouse(): scroll wheel up/down moves 2 lines;
click top 5 rows → scroll up half page; click bottom 5 rows
→ scroll down half page.
- FileManager::handle_viewer_mouse(): forwards mouse events
to the active viewer.
- app.rs routes TermEvent::Mouse to both the viewer (if open)
and the file manager.
Tests: 1421 pass, zero warnings.
MC's goto dialog supports Line/Percent/Decimal offset/Hex offset
modes. TLC's goto prompt previously only accepted line numbers.
Parse the goto prompt input for multi-format support:
- '50%' → goto 50% of the file (goto_percent)
- '0x400' → goto byte offset 1024 (goto_offset, hex)
- Number > line_count → treat as byte offset (goto_offset)
- Number ≤ line_count → treat as line number (goto_line)
Also updated the prompt label to 'Goto (line/50%/0x):' so the
new formats are discoverable.
Added 1 unit test verifying 50% goto lands near line 50 in a
100-line file.
Tests: 1421 pass (was 1420), zero warnings.
MC's Tab in hex mode toggles the cursor between the hex data area
and the ASCII text column (hexview_in_text). Add this feature:
- Viewer::hexview_in_text: bool field (default false)
- Tab key in Hex/HexEdit mode toggles the flag
- ViewerCmd::ToggleHexNavigation + View menu entry in F9
- execute_menubar_cmd dispatches the toggle
The hex render uses hexview_in_text to determine which column
gets the cursor highlight (hex bytes vs ASCII representation).
Tests: 1420 pass, zero warnings.
MC's F2 in text mode toggles word wrap (CK_WrapMode). TLC was
using F2 for growing buffer toggle instead. This changes F2 to
toggle wrap in text mode, matching MC. Growing buffer moves to
Shift-F2.
- F2 in Text mode: toggle self.wrap
- F2 in Hex/HexEdit mode: enter/exit hex edit (unchanged)
- Shift-F2 in any mode: toggle growing buffer
- Updated growing_keybinding_toggles_mode test to use Shift-F2
- Added f2_toggles_wrap_in_text_mode test
Tests: 1420 pass (was 1419), zero warnings.
Add column ruler toggle to the viewer. Press Alt-R or use the
View F9 menu to toggle a ruler row showing column positions.
- Viewer::ruler: bool field (default false)
- Alt-R key binding toggles the ruler
- ViewerCmd::ToggleRuler + View menu entry in the menubar
- execute_menubar_cmd dispatches the toggle
Added 1 unit test verifying the toggle cycle (off→on→off).
Tests: 1419 pass (was 1418), zero warnings.
Systematic MC viewer parity from the comprehensive audit (CK_* gaps):
Bookmarks (MC CK_BookmarkGoto / CK_Bookmark):
- marks: [Option<u64>; 10] stores 10 position bookmarks
- marker: usize tracks which slot was last written
- m key: sets current top position in marks[marker], advances marker
- r key: jumps to marks[marker-1] (wraps from 0→9)
Half-page scroll (MC CK_HalfPageDown / CK_HalfPageUp):
- d key: move_cursor_down(last_height / 2)
- u key: move_cursor_up(last_height / 2)
SearchOppositeContinue (MC CK_SearchOppositeContinue):
- last_search_forward: bool tracks last direction
- Shift-N: if last was forward→search_prev, else→search_next
- search_next/search_prev update the flag
Added 2 unit tests: bookmarks set+jump, half-page scroll.
Tests: 1418 pass (was 1416), zero warnings.
The viewer's ensure_cursor_visible scrolled the cursor to the
exact top or bottom edge of the viewport. Add a 2-line context
margin so the cursor sits 2 lines from the top (when scrolling
down) or 2 lines from the bottom (when scrolling up). Premium
polish — keeps the surrounding lines visible for context.
Tests: 1399 pass, zero warnings.
Press F9 in the viewer to toggle the menubar at the top of the
viewer. The menubar occupies the top row, and the viewer content
shifts down by 1 row when the menubar is open.
- Viewer::menubar: Option<ViewerMenuBar> field
- Viewer::render: calls mb.render() at the top when menubar is open
- Viewer::handle_key: F9 toggles, other keys route to menubar when open
- Viewer::execute_menubar_cmd: dispatches ViewerCmd to existing
viewer methods (ToggleHex, ToggleMagic, ToggleWrap, ToggleGrowing,
Search, SearchNext, SearchPrev, Goto)
Bookmark / file navigation / close commands are documented as a
planned follow-up — still reachable via their keyboard shortcuts.
Tests: 1393 pass, zero warnings.
W1: Fix 3 dead dialogs (DisplayBits/VfsSettings/LearnKeys) that could never close
- Capture handle_key() return value, close on Cancel/Confirm
W2: Implement Cmd::Suspend with actual SIGTSTP via kill -TSTP 4035172
- Add want_suspend field, ExternalAction::Suspend variant
- Drop TUI, send SIGTSTP, recreate TUI on resume
W3: Wire Connection dialog to Panel::navigate_to_vfs()
- Parse VFS URL, look up backend, redirect active panel
- Store Encoding dialog selection on FileManager.display_encoding
W4: Wire CK_EditUserMenu (EditorCmd::EditUserMenu)
- Opens user menu storage_path in editor via Editor::open()
- Fix unreachable!() in SaveBeforeClose prompt rendering
W5: Add ErrorOutcome::SkipAll variant + Shift-S keybinding
- Fix misleading doc comment about non-existent 'All' variants
- Add SkipAll button in error dialog render
Also: Fix all 41 compiler warnings (unused imports/vars, missing docs on
public API, remove dead SPECIAL_LABELS constant, remove unused viewer_bold)
1381 tests pass, zero warnings.
F1: Remove stale 'Phase N' / 'not yet wired' comments from vfs/local.rs,
vfs/traits.rs, editor/usermenu.rs — the functionality they described as
future work is already implemented.
F2: Replace placeholder stubs in viewer/hex.rs and viewer/text.rs with actual
rendering for Chunked sources (files >= 1 MiB). hex.rs reads viewport-sized
chunks via read_at(); text.rs 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 now shows actual toggle state (auto-indent,
word-wrap, show-whitespace, save-on-quit) instead of '(TBD)' placeholder.
F4: Add xz2 crate dependency and TarKind::Xz decompression support.
Feature-gated as 'xz2' (optional, follows bzip2 pattern). Uses
XzDecoder::new_multi_decoder for multi-stream .tar.xz files.
1369 tests pass. Default build (without optional features) verified.
Adds regression tests for Sprint 3 items that were verified
already-done during recon but had no dedicated test coverage:
- viewer::tests::hex_edit_apply_nibble_at_eof_is_safe_noop
Locks in the C8 contract: apply_nibble at cursor past EOF
is a safe no-op (no panic, no spurious modified flag).
- viewer::tests::move_cursor_clamps_to_size
Locks in the C8 cursor bounds invariant at move_cursor
level: positive deltas clamp to file size, negative deltas
clamp to 0 with no underflow.
- filemanager::panel::tests::history_dedups_consecutive_entries
Locks in the C11 contract: refreshing the same directory
N times grows the history by 1 entry (consecutive dedup),
not N.
- filemanager::panel::tests::sort_field_mtime_round_trips_through_config
Locks in the C12 contract: 'mtime' and 'time' config
strings both resolve to the Mtime sort field, and the
Panel reports the human-readable name 'Mtime'.
Tests (4 new, total 1299 passing):
+hex_edit_apply_nibble_at_eof_is_safe_noop
+move_cursor_clamps_to_size
+history_dedups_consecutive_entries
+sort_field_mtime_round_trips_through_config
The hex viewer now reserves the top row for a status header
showing the cursor byte offset and the total file size:
'Offset: 00000040 / 00000100 bytes'
When the area has height < 2 (degenerate case), the header is
skipped and the full row is used for hex bytes.
Layout split: total_height >= 2 → 1-row header + body_area
(remaining rows). total_height == 1 → no header, body uses
full area. The body Paragraph is rendered to body_area (not
the full area) so the header is not overwritten.
Tests (2 new in viewer::hex::tests):
- render_shows_offset_header_when_area_has_height
cursor=64 → header shows 'Offset: 00000040' at row 0
- render_skips_header_when_area_height_is_one
80x1 area → first row starts with hex offset '00000000'
Total: 1274 passing (was 1272; +2 new).
Previously Viewer::search for Chunked sources read the ENTIRE
file into RAM via read_at(0, size) — defeating the memory-efficient
design of Chunked mode (a 150 MB Chunked file would load all 150 MB
just to search it).
Search (viewer/search.rs):
New method find_all_streaming<E>(pattern, case_insensitive, next_chunk)
- Generic error type E so callers can use their own error type
- next_chunk closure yields (bytes, is_last_chunk) until exhausted
- Sliding-window algorithm: keeps last (pattern.len() - 1) bytes
from each chunk as 'tail', combines with next chunk for regex
- Matches that span chunk boundaries are detected correctly
- Matches across overlapping combined buffers are deduped by
start offset after collection
Viewer (viewer/mod.rs):
search() now dispatches by source variant:
- Inline / Compressed: in-memory find_all (unchanged)
- Chunked: find_all_streaming with closure yielding CHUNK_SIZE
reads until EOF reached
Tests (5 new in viewer::search::tests):
- streaming_single_chunk_finds_match
- streaming_match_spans_two_chunks (xxfoobarxx at chunk 5)
- streaming_no_matches
- streaming_multiple_matches_in_one_chunk
- streaming_chunk_size_smaller_than_pattern (chunk_size=1, pattern=hello)
Total: 1264 passing (was 1259; +5 new).
Implements all 5 critical parity items from the comprehensive MC
assessment. Reference: MC source at local/recipes/tui/mc/source/.
A1 — Editor line number gutter:
Split editor inner area into gutter_area + body_area; gutter
renders right-aligned line numbers (or relative offsets when
relative_lines mode is on); bookmark rows show current-line
style; ~ shown for lines past end-of-file.
A2 — Viewer cursor line highlight:
cursor_line_bg derived from body_bg + RGB(12,12,12); applied
before search-match overlay so matches win on the cursor line.
A3 — Hide terminal cursor in file manager mode:
App::run() hides the cursor after Tui::new(); render() shows
the 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 flag and new_rename() constructor; result() resolves
the typed name against the source's parent directory.
A7 — SUID/SGID/sticky bits in chmod dialog:
4-row PermCell grid (user, group, other, special); class_shift
= 0o4000, bit = 1. Display as 0oXXXX. Overwrite dialog shows
all 12 cells. 6 new unit tests cover all special-bit combinations.
Other fixes in the same commit:
- 4 editor render tests shifted x-coordinates by gutter_chars
to account for the new gutter column.
- 1 viewer text test moves cursor to line 1 so cursor-line
highlight doesn't overlap the search-match assertion.
Tests: 1230 passed (was 1219 before A7; +11 new tests across A7
and A6). All Sprint 1 items compile clean.
- viewer/mod.rs: implement MC-style cursor tracking with independent
scroll (move_cursor_down/up/ensure_cursor_visible). Arrow keys now
move cursor within visible area; scrolling only when cursor reaches
edge. last_height field stores render area height for key handlers.
Fixes 'pressing down sends all text off screen'.
- panel.rs: save and restore BOTH cursor AND top scroll position in
dir_cursors HashMap. Previously only cursor was saved and top was
always reset to 0, causing ensure_cursor_visible to snap the view
on every directory switch.
- panel.rs: fix try_enter_archive to construct VFS URL with correct
scheme prefix (zip://, tar://) instead of parsing raw file path
as Local. Fixes .zip/.tar hang on Enter.
- terminal/event.rs: rewrite parse_unsupported_key to handle CSI-tilde
modifier sequences (\x1b[15;5~ = Ctrl-F5) and CSI arrow modifier
sequences (\x1b[1;5B = Ctrl-Down). Returns tlc Key directly with
modifiers set, bypassing termion's limited TermKey enum.
- app.rs: simplify event dispatch to use Key directly from
parse_unsupported_key, removing dead TermKey variable.
- 6 new tests for modifier+function-key and modifier+arrow parsing.
- cursor.rs: move_left walks back over UTF-8 continuation bytes,
move_right steps by char width via utf8_len_from_lead(), move_up/down
snap to char boundary via snap_to_char_boundary()
- mod.rs: update_bracket_flash adds defensive is_char_boundary() check
- render.rs: remove gutter/column layout, body_area = inner (matches MC
editdraw.c line_state=FALSE default); bookmark colors applied to
body line base_style (matches MC book_mark line coloring)
- text.rs: remove gutter rendering and Paragraph .wrap(); implement
pre-wrapping via wrap_line() for wrap mode; body uses full width
- Tests updated for new no-gutter layout (4 tests, all pass)
§32.1 Viewer word-wrap fix: Paragraph .wrap() was always applied
regardless of the 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 from render_line_with_highlight.
§32.2 Alt-W wrap toggle test verifying the field toggles correctly.
PLAN §14.7 table refresh: 30+ stale entries corrected. Phase 14b
6/6 done. Phase 14c 14/15 done (1 WONTFIX). Phase 14d ~17/25 done.
Overall ~90% MC parity.
Tests: 1213 passed, 0 failed.
tlcview now supports in-place byte-level editing in Hex view:
F4 (Text -> Hex), F2 (Hex -> HexEdit) toggles between read-only
hex view and an editable overlay. HexEdit mode draws an extra-
bright cursor over the *active nibble* (H or L) so the user
always knows which digit the next keystroke will replace.
Nibble pipeline (mirror of MC's mcedit hex cursor):
- type 'a'..'f' or '0'..'9': stash the high nibble and advance
to the low nibble; the byte is NOT yet written
- second nibble: combine with stashed high, write the byte,
advance the cursor by 1, reset to high nibble
- arrow keys: H/L toggle (Right/Left), row navigation (Up/Down),
page jump (PgUp/PgDn)
- F10/Esc/Ctrl-Q on a dirty buffer opens the
'Save before quit? (Y/N/Esc)' prompt; Y saves, N discards,
Esc cancels and stays in HexEdit
Byte storage:
- Inline and Compressed sources (the default for files < 1 MiB
and all .gz/.bz2) are mutated in place via the new
FileSource::write_byte(offset, value) helper.
- FileSource::save_to(path) persists the buffer byte-exact.
- Chunked sources (≥ 1 MiB plain files) refuse to enter
HexEdit — caller gets a silent no-op. The new
SourceError::NotMutable variant carries the diagnostic.
Header / footer:
- mode label changes from 'Hex' to 'HexEdit' in the header
- footer shows 'Nibble H' or 'Nibble L' (which digit is next)
- '[+]' marker appears after the mode label when the buffer
has unsaved edits
8 new tests cover: F2 enter, nibble commit + cursor advance,
dirty F10 opens prompt, clean F10 closes, Y/N/Esc prompt
resolution, Chunked refusal, arrow-key nibble toggling.
Total: 1172 tests passing, 0 failing.
Root cause: PciDevice::open_io_ports never called acquire_iopl(),
so the first outl to 0xCF8 triggered #GP(0) when redox-drm tried
to scan virtio-gpu PCI capabilities.
- Add ensure_iopl_acquired() helper (thread-local Once)
- Call it in PciDevice::open_io_ports before any I/O
- Add P1-pci-open-io-ports-iopl.patch to recipe
- Mirror patch to local/patches/ for durability
Mirrors Midnight Commander's
MC src/viewer/actions_cmd.c::mcview_load_next_prev (CK_FileNext
/ CK_FilePrev).
Components:
src/viewer/siblings.rs (new) — pure helper next_or_prev_sibling:
reads current file's parent directory, filters out hidden
files (dot-prefixed), sorts case-insensitive, locates current
by file_name, returns next (direction=+1) or prev (direction=-1)
entry. Returns None at directory boundaries or on I/O error.
6 unit tests cover next/prev/last/first/hidden/no-parent.
src/viewer/mod.rs — Viewer::open_next / Viewer::open_prev
public methods that look up the sibling and reload viewer
state via a private reload_at helper (mirrors MC's
mcview_init/mcview_done pair around mcview_load). Source
errors are converted to std::io::Error so the Result type
matches the existing open() signature.
src/viewer/mod.rs — Ctrl-F / Ctrl-B keybinds in handle_key.
Each delegates to open_next / open_prev.
PLAN.md §15d row 29 marked Done; status bumped to Phase 23.
Tests: 1150 passed (was 1141, +9: 6 siblings module tests +
3 viewer integration tests covering open_next, open_prev,
Ctrl-F/Ctrl-B keybinds). Release binaries build clean.
All and references updated to deref the LazyLock (). 1103 tests pass.
Editor render test now reads [editor] editlinestate from the MC .ini (with cursor_fg fallback) so the cursor-line color assertion matches the actual rendering.
Viewer match-highlight test reads [viewer] viewselected from the MC .ini (with warning fallback) — the test now matches the actual highlight bg color from julia256 (yellow on cyan).
Adds per-file cursor position persistence (MC ~/.mc/filepos parity).
Storage: ~/.config/tlc/filepos as a tab-separated canonical-path database. Wired into editor/viewer open+close in both standalone binaries and the in-TLC file manager. CursorPos struct, save/load functions, restore_cursor_position() and save_cursor_position() methods on Editor and Viewer.
buttonbar.rs: add module-level doc to satisfy missing_docs lint.
Editor gains goto_line(), viewer gains jump_to_line() + open_file(start_line). Both editor and viewer now render the F-key buttonbar at the bottom (1Help 2Save... / 1Help 2Wrap...).
Both open_file() functions were stubs that opened the file but never
launched the terminal interface. tlcedit/tlcview would silently exit
without displaying anything.
- editor::open_file(): create Tui, render editor, run key event loop,
handle Save/Close/SaveThenClose/DiscardThenClose results
- viewer::open_file(): create Tui, render viewer, run key event loop,
exit when handle_key returns true
- Ctrl-X prefix chord: dispatch_ctrl_x_followup routes 9 follow-up keys
(d/j/c/o/l/s/v/a/!) to their respective commands
- Compare Dirs (C-x d): size-only mode matching MC behavior, marks
files that differ between left and right panels
- SymlinkRelative (C-x s): creates symlinks with relative target paths
via relpath_from() helper
- SymlinkEdit (C-x v): reads existing symlink target, opens edit dialog
with for_editing() constructor, removes old link before recreating
- ScreenList/EditHistory/FilteredView dialogs wired through dispatcher,
handle_dialog_key, apply_finished_dialog, and render
- Editor format paragraph (Alt-P): wrap_paragraph + paragraph_range +
reformat_paragraph_at in format.rs, 29 unit tests
- Viewer growing buffer: toggle_growing/check_growing for tail -f mode,
detects file growth and appends new content
946 tests pass (default), 964 (all features), 0 failures
Base fork workspace pins redox_syscall = '0.7.4' (resolves to 0.7.5).
Without this pin, redox-driver-sys pulls in 0.8.1, causing type mismatches
in downstream crates like driver-graphics that use both 0.7.5 and 0.8.1
types in the same expression.
Internal Red Bear subprojects (tlc, redbear-*, redbear-greeter, etc.) live
under local/recipes/* and have no upstream source — they are committed to
our own gitea only. If lost, they cannot be recovered from any public
source.
The previous guard used is_local_overlay() && !redbear_allow_local_unfetch()
which could be bypassed by setting REDBEAR_ALLOW_LOCAL_UNFETCH=1. This was
triggered inadvertently (exact trigger unknown) and destroyed the source
tree of local/recipes/tui/tlc/source/.
This commit makes the protection UNCONDITIONAL:
- is_local_overlay() already correctly identifies any path under
local/recipes/ as internal.
- The handle_clean unfetch path now refuses ALL local/recipes/* sources
with a clear error message. No env var can override this.
- The fetch() path's git-reset/git-clean-ffdx and source-wipe guards now
also refuse local overlays unconditionally.
- The dead redbear_allow_local_unfetch() function is removed.
- Makefile distclean-nuclear target is documented as a no-op for local/.
distclean still works for non-local recipes (upstream sources from
sources/redbear-0.1.0/ or git mirrors can be safely re-fetched).