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 Cmd::HotListAdd variant that opens the hotlist dialog with
a status hint to press Ins to add the current directory. This
provides the MC HotListAdd feature without changing the existing
Ctrl-X 'h' chord which already opens the hotlist dialog.
Tests: 1425 pass, zero warnings.
Add Delete EditorCmd variant and wire it into the F9 Edit menu
between Paste and Select All. With a selection, deletes the
selected text. Without a selection, deletes one character
forward (select_right + delete_selection).
Added 1 unit test verifying single-character forward delete.
Tests: 1425 pass (was 1424), zero warnings.
usb-core spawn.rs:
- class_driver_for_usb_class() extended to cover all Red Bear class drivers:
Audio(0x01)→redbear-usbaudiod, CDC ACM(0x02/0x02)→redbear-acmd,
CDC ECM(0x02/0x06)→redbear-ecmd, HID(0x03)→usbhidd,
Mass Storage(0x08)→usbscsid, Hub(0x09)→usbhubd,
Vendor(0xFF)→redbear-ftdi
- Subclass-aware matching (Audio Control vs Streaming, CDC ACM vs ECM)
- is_trusted_usb_driver() whitelist extended with all 7 driver binaries
- Test suite updated with new assertions (11/11 pass)
redbear-usb-hotplugd:
- DRIVER_MAP extended to 11 entries with subclass-aware matching
- Recursive port scanning: scan_ports_recursive() traverses child
hub port directories (handles port1.port2.port3 paths)
- extract_port_id() parses full port paths to extract controller
name and port string for child hub ports
- Protocol-aware extra arg: Storage passes protocol byte (0x50/0x62),
all other classes pass interface number
- Skips CDC Data interfaces (0x0A) and hub interfaces (0x09) when
reading descriptors — matches Linux's interface matching logic
- Improved disconnect detection via descriptor accessibility heuristic
- Cleaner structure: find_driver(), scan_controllers(), scan_ports(),
try_read_descriptors(), main loop with connect/disconnect tracking
All 7 Red Bear USB class drivers now auto-spawning on device connect:
usbhidd, usbscsid, usbhubd, redbear-acmd, redbear-ecmd,
redbear-usbaudiod, redbear-ftdi
Add a JsonLoad struct with load_avg_1m/5m/15m fields and include it in the --json snapshot. Values are read from app.load_avg. Build, 224 tests, clippy, and fmt clean.
Cross-referenced with Linux 7.1 drivers/usb/core/hub.c port event
handling and drivers/usb/core/driver.c device-driver binding.
New daemon (216 lines) that watches USB controllers for device
attachment/detachment and auto-spawns the appropriate class driver.
Architecture:
- Polls /scheme/usb/ every 1000ms for controller directories
- For each controller, enumerates root hub ports
- Reads device descriptors (class/subclass/protocol) via XhciClientHandle
- Maps class to driver binary: HID(0x03)→usbhidd, Storage(0x08)→usbscsid,
Hub(0x09)→usbhubd
- Spawns driver with <scheme> <port> <protocol> arguments
- Tracks spawned Child processes in HashMap<port_path, TrackedDevice>
- Detects disconnection (descriptor read fails) → kills driver + removes
from tracking
- Detects driver exit (try_wait) → removes from tracking
- Skips hub interfaces (usbhubd handles its own children)
Config:
- Added to redbear-mini.toml (inherited by redbear-full)
- Auto-started via 02_usb_hotplug.service (oneshot_async, after base.target
and pcid-spawner)
Driver map supports: HID (0x03), Mass Storage (0x08 with BOT protocol),
Hub (0x09). Additional class drivers extendable via DRIVER_MAP constant.
Mirror the local process_filter_input buffer into App so render_keybar can display it. While filtering, the keybar shows "Filter: <buffer> (N matches) Enter:apply Esc:clear ↑↓:select" in a warm style instead of the normal hints. Build, 224 tests, clippy, and fmt clean.
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.
Replace the generic kill-dialog footer with an explicit confirmation line: "Send SIGTERM to PID 1234 (sshd)? Enter: send Esc: cancel ↑↓: select". Extracts the signal name from the existing signal labels. Build, 224 tests, clippy, and fmt clean.
Add refresh_ms to SessionState (0 = not set, use config/default). Load it into App::poll_ms, give it priority over config when initializing the event-loop poll interval, and save it back in save_session(). Update all SessionState test initializers and assertions. Build, 224 tests, clippy, and fmt clean.
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.
Extend the header load-average line to also show system uptime and total process count. Uptime uses meminfo::format_uptime; process count uses app.processes.count(). All values stay on one line to keep HEADER_LINES at 8. Build, 224 tests, clippy, and fmt clean.
Cross-referenced with Linux 7.1 sound/usb/card.c, mixer.c, pcm.c
and include/uapi/linux/usb/audio.h.
Replaces the 32-line scan-and-symlink stub with a 280-line real class driver:
Audio Control Interface (Feature Unit):
- Volume control: GET_CUR / SET_CUR via class-specific control requests
(bmRequestType 0xA1/0x21, FU_VOLUME selector, per-channel)
- Mute control: GET_CUR / SET_CUR (FU_MUTE selector)
- AudioReq helper for bidirectional class-specific control requests
Audio Streaming Interface:
- Isochronous endpoint auto-detection (attributes & 0x03 == 0x01)
- Format heuristics from max packet size (stereo 16-bit 48kHz default)
- SET_CUR SAMPLING_FREQ_CONTROL (0x0100) for sample rate
- Bidirectional isoch I/O: isoch IN → stdout (recording),
stdin → isoch OUT (playback)
Eliminates P1-D last remaining stub — all 3 scan-and-symlink stubs
(ecmd, acmd, usbaudiod) now have real class driver implementations.
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.
Add a "Load: 0.42 0.55 0.61" line to render_header, color-coded by load versus core count (green <= 50% capacity, yellow <= 100%, red overcommitted). Bump HEADER_LINES from 7 to 8. Build, 224 tests, clippy, and fmt clean.
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.
Add KeyBindings::char_for() and replace the 7 hardcoded Key::Char arms in main.rs (quit, cycle_governor, refresh_now, toggle_help, snapshot, benchmark_start, benchmark_stop). Esc remains a quit fallback. All other keys stay hardcoded. Build, 224 tests, clippy, and fmt clean.
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.
Move all palette colors into Theme fields so dark/light/high-contrast/nord/gruvbox/solarized-dark are fully usable. Convert NiceEdit and AffinityEditor to regular render_dialog methods that take a theme. Update all render_* helpers to bind let theme = &app.theme and reference theme fields. All 224 tests pass; clippy and fmt clean.
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.
MC's Shift-F3 opens the viewer in raw mode without magic/binary
detection. Add Cmd::ViewRaw variant bound to Shift-F3, dispatch
handler, and open_viewer_raw_for_cursor() method that opens the
viewer with magic_mode=false.
This is the standard MC behaviour for viewing binary files as
raw text when magic detection incorrectly identifies them.
Tests: 1416 pass, zero warnings.
Add ToggleOverwrite EditorCmd variant, wire it into the Options
menu, and add a dispatch handler that toggles the overwrite
flag and shows [OVR]/[INS] in the status message (mirrors the
existing INS key behavior now accessible from the F9 menu).
Added 1 unit test verifying [OVR]→[INS] cycle.
Tests: 1416 pass (was 1415), zero warnings.
Extend the Owner dialog (C-x o) with a Recursive checkbox,
matching MC's CK_ChangeOwnAdvanced. Tab cycles through UID→GID
→Recursive. Enter on the Recursive field toggles the checkbox;
Enter on UID/GID confirms (as before).
- OwnerField::Recursive variant with next/prev cycling
- OwnerDialog::recursive field (default false)
- handle_key: Enter toggles checkbox when focused on Recursive
- render: shows [✔]/[☐] Recursive with focus highlight
- Updated field_cycle_helper test for the 3-field cycle
Tests: 1415 pass, zero warnings.
Add 4 unit tests covering the new W50 editor commands:
- mark_all_selects_entire_buffer: verify selection covers
the full buffer (start=0, end=buffer.len())
- close_clean_buffer_reopens_empty: verify Close on an
unmodified buffer resets to an empty buffer
- block_save_on_no_selection_shows_message: verify the
"No selection" message when nothing is selected
- insert_file_opens_insert_file_prompt: verify the mode
switches to InsertFile prompt
Tests: 1415 pass (was 1411), zero warnings.
The F9 audit found TLC had no Appearance dialog — the Skins...
dialog was the only appearance option. MC's CK_OptionsAppearance
offers five checkbox toggles plus a skin selector.
Create AppearanceDialog with 6 rows:
- Menubar (show/hide F9 menu bar)
- Keybar (show/hide F1-F10 key hint bar)
- Hint bar (show/hide status bar)
- Command prompt (show/hide command-line prompt)
- Mini status (show/hide mini-status above keybar)
- Skins... (opens the existing SkinDialog)
All five toggles write back to RuntimeConfig's show_* fields.
Enter toggles the checkbox; Esc dismisses; Skins... opens the
skin selection dialog transparently.
Added to F9 → Options menu as 'Appearance...' between
Confirmation and Skins, matching MC's menu ordering.
Added 4 unit tests: toggles default true, enter toggles off/on,
down cycles cursor, skin button opens skin outcome.
Tests: 1411 pass (was 1407), zero warnings.
MC parity gap: the editor F9 menu was missing 4 commands that
MC has. This adds them all:
- MarkAll (CK_MarkAll): select all text via start_selection +
set_position(0) + set_position(len)
- InsertFile (CK_InsertFile): open SaveAs-style prompt to pick
a file to insert at the cursor (reuses PromptKind::InsertFile)
- BlockSave (CK_BlockSave): open SaveAs prompt pre-filled with
the selected text, saves selection to a different file
- Close (CK_Close): close current buffer (prompt save if dirty)
All 4 added to the F9 File and Edit menus. Test updated for
new file menu item count (7→11).
Tests: 1407 pass, zero warnings.
Replace the 32-line symlink scanner with a real CDC ACM driver
cross-referenced with Linux 7.1 drivers/usb/class/cdc-acm.c.
Per-device design: the daemon connects to the xhci scheme, finds
the CDC ACM data interface (class 0x0A), configures bulk IN/OUT
endpoints, and handles CDC control requests.
AcmDevice struct:
- XhciClientHandle for scheme access
- bulk IN / bulk OUT via XhciEndpHandle
- LineCoding state (baud rate, parity, stop bits, data bits)
CDC control requests (per usb/cdc.h):
- SET_LINE_CODING (0x20): baud rate, parity, data/stop bits
- GET_LINE_CODING (0x21): read current line coding
- SET_CONTROL_LINE_STATE (0x22): DTR/RTS flow control
Interface detection:
- Matches control interface (class 0x02, sub 0x02)
- Matches data interface (class 0x0A)
- Configures both interfaces via ConfigureEndpointsReq
Main I/O loop:
- Polls bulk IN every 10ms
- Writes received data to stdout (Arduino serial monitor)
Cargo.toml updated with xhcid, common, and libredox deps.
Cross-reference: Linux 7.1
- drivers/usb/class/cdc-acm.c (2,186 lines)
- include/uapi/linux/usb/cdc.h: CDC control request defines