Add ToggleColumnMode EditorCmd to the F9 Edit menu. Toggles
between stream selection and column (block) selection mode.
If currently in column mode, clears to stream. If in stream
mode, starts column selection.
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 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