lotabout.skim/fuzz
LoricAndre d7e294eb7d
fix: allow execute actions to run interactive commands (#1132)
* fix(tui): stop input reader and give execute() children their own tty

Interactive/ncurses programs run via an `execute()` action (e.g. `ncdu`)
would freeze after a few keystrokes. Two independent problems caused it:

1. skim's background input reader (the `EventStream` task started in
   `Tui::start`) kept reading the terminal while the child ran, so skim and
   the child raced for keystrokes on the same tty — roughly half the keys
   were stolen from the child.

2. The child inherited skim's stdin (fd 0), which is a pipe whenever items
   are piped in (`find | sk`). An interactive child then had no keyboard
   source at all.

Fix both:

- Add `Tui::stop_and_join`, which cancels the event-pump task and blocks
  until it has dropped its `EventStream`, guaranteeing skim has released the
  terminal before the child starts. `run_foreground` calls it before running
  the child and `Tui::start` after.

- Give the child its own stdin opened from the controlling terminal
  (`/dev/tty`, or `CONIN$` on Windows), falling back to inheriting skim's
  stdin if that fails.

Because running a foreground process needs the `Tui` (which `handle_action`
does not have), `Execute` now only expands the command and returns a new
`Event::RunExecute`, which `handle_event` runs via `run_foreground`. This
mirrors the existing `RunPreview` pattern. `execute-silent` is unchanged.

Update ARCHITECTURE.md (event dispatch table, terminal lifecycle, and
cross-reference line numbers) and add tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QBQ1chjHyN3JNTWqMMED44

* test(execute): add tmux e2e test; fix reader restart and post-execute repaint

Add a tmux-based integration test (tests/execute.rs, unix-gated so it runs
on the Linux and macOS CI legs) that drives an interactive child through an
`execute` action and asserts it keeps receiving keystrokes, then that skim
is interactive again once the child exits. It covers both the fullscreen and
inline (`--height`) layouts.

Writing the test surfaced two bugs in the execute reader-suspend work that
unit tests could not catch:

1. Reader never resumed. `Tui::stop_and_join` cancels the shared
   `CancellationToken`, but `Tui::start` reused that same token — and a
   cancelled token stays cancelled — so the respawned reader observed the
   cancellation immediately and exited without reading input. `start` now
   installs a fresh token on every call (also fixing the latent
   restart-while-running path).

2. Post-execute repaint hung when stdout was redirected. The repaint went
   through `Event::Redraw` → `tui.clear()`, and ratatui's `Terminal::clear`
   queries the cursor position, which crossterm writes to stdout via
   `ESC [ 6 n`. skim renders to stderr and its stdout is routinely redirected
   (`sk > file`), so the query reached no terminal, got no reply, and stalled
   the UI for seconds before erroring out. Replace it with
   `Tui::force_full_redraw`, which resets ratatui's diff buffers for a full
   repaint with no cursor query and works for both fullscreen and inline
   viewports.

Update ARCHITECTURE.md and the cross-reference table accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QBQ1chjHyN3JNTWqMMED44

* ci: fix matrix

* fix: pop kitty keyboard flag before entering execute

* chore: remove duplication in backend.rs

* chore: refactor

* fix: kitty maintains a different set of flags in alt screen

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-21 09:01:53 +00:00
..
fuzz_targets feat: add cargo-fuzz targets for hand-rolled text parsers (#1106) 2026-07-04 18:01:46 +02:00
.gitignore feat: add cargo-fuzz targets for hand-rolled text parsers (#1106) 2026-07-04 18:01:46 +02:00
Cargo.lock fix: allow execute actions to run interactive commands (#1132) 2026-07-21 09:01:53 +00:00
Cargo.toml feat: add cargo-fuzz targets for hand-rolled text parsers (#1106) 2026-07-04 18:01:46 +02:00
README.md feat: add cargo-fuzz targets for hand-rolled text parsers (#1106) 2026-07-04 18:01:46 +02:00

Fuzzing

This directory contains cargo-fuzz (libFuzzer) targets for skim's hand-written, untrusted-input-facing parsers: text that flows in from stdin, --ansi sequences, --nth/--with-nth field specs, the search query syntax, and --bind key maps. These are exactly the places where skim does manual byte/char-index bookkeeping on attacker- or data-controlled strings, which is the most panic-prone code in the project.

Targets

Target Exercises
ansi_strip helper::item::strip_ansi — ANSI escape stripping & byte/char index map
field_extract field::{FieldRange, get_string_by_field, parse_matching_fields, parse_transform_fields}--nth/--with-nth
fuzzy_match fuzzy_matcher::{skim, fzy, clangd} — the fuzzy matching algorithms
query_match Matcher::create_engine_factory + DefaultSkimItem — the full query → engine → match pipeline (exact/regex/AND-OR/fuzzy, with ANSI)
keymap_parse binds::KeyMap — the --bind key-map parser

Each target asserts more than "doesn't panic" where a cheap invariant is available (e.g. reported match indices must be valid char indices into the matched text, index mappings must stay monotonic and land on char boundaries).

Running

Install cargo-fuzz (requires a nightly toolchain):

cargo install cargo-fuzz

Run a target:

cargo +nightly fuzz run ansi_strip

Run for a bounded time (useful in CI or for a quick check):

cargo +nightly fuzz run query_match -- -max_total_time=60

Reproducing a crash

cargo fuzz run writes failing inputs to fuzz/artifacts/<target>/. Replay one with:

cargo +nightly fuzz run <target> fuzz/artifacts/<target>/crash-<hash>

Adding a target

Add a new fuzz_targets/<name>.rs, register it in fuzz/Cargo.toml's [[bin]] list, and prefer asserting a real invariant of the function under test (bounds, monotonicity, round-tripping) rather than only catching panics.