mirror of
https://github.com/lotabout/skim.git
synced 2026-09-10 07:16:23 -04:00
* Add `start` and `load` events alongside `change` Introduce `start` and `load` bindable events, mirroring the existing `change` event, so `--bind start:<action>` and `--bind load:<action>` work. To avoid scattering magic high-F-key literals (`F(255)` for `change`), add a `SkimEvent` enum in `binds.rs` with `Start`, `Load` and `Change` variants that transparently convert to the reserved `KeyEvent`s used to route them through the keymap. `parse_key` now accepts the friendly names `start`, `load` and `change` via `SkimEvent::from_name`. The keymap key type stays `KeyEvent`, so the public API is unchanged. Firing: - `change` is emitted by `on_query_changed` (now via the named variant). - `start` fires exactly once when skim enters its event loop (`Skim::fire_start_event`). - `load` fires once the reader has finished AND the freshly-read items have been rendered into the list, so a `load` binding acts on a fully-populated, stable list. It is re-armed on `reload`. Add unit coverage for the event-name round-trip and integration tests for `start` and `load` bindings, and document the events in ARCHITECTURE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019QKxusGbxLxqWdYyeqrb68 * Add result/focus/zero/one events and action follow-up bindings Extend the bindable-event set and generalise binding so that actions can themselves be bound. New finder events (fired from the post-draw `Event::Render` path, so a binding sees a stable, up-to-date list): - `result` — filtering for the current query completed - `focus` — the focused item changed (cursor move or result update) - `zero` — a completed search has no matches - `one` — a completed search has exactly one match `zero`/`one` read `MatcherControl::get_num_matched()` rather than the rendered list count, which can briefly lag the matcher. Actions as events: any action can be bound as if it were an event, so a follow-up chain runs after it (e.g. `reload:first`, `first:last`). This is parsed by `parse_action_binds` into `SkimOptions::action_binds` (keyed by `Action::name`) and applied in `handle_action`, which now wraps the per-variant `dispatch_action`. - Keys win: a name shared by a key and an action binds the key; use an `act-` prefix to target the action (`act-up:down`). - New `skip` action suppresses the triggering action's own behaviour, so `act-up:skip+down` remaps the up action to down and `up:skip` disables the up key. Also fixes `parse_key` so a non-numeric `f…` name (e.g. `focus`, `first`) falls through to name/event matching instead of erroring on the function- key branch. Adds unit and snapshot tests and documents everything in ARCHITECTURE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019QKxusGbxLxqWdYyeqrb68 * Rename skip action to suppress and document it in the manpage Rename the `skip` action to `suppress`, which more clearly conveys that it cancels the triggering action's default behaviour. Add it to the manpage actions list, noting that when bound to an action it suppresses that action's default (so the rest of the chain runs in its place), and when bound to a key it is equivalent to `ignore`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019QKxusGbxLxqWdYyeqrb68 * Fire finder events from callbacks instead of the render path Move the synthetic finder events off the per-render check: - `focus` now rides along with `App::on_selection_changed` (via a small `take_focus_event` helper), firing only when the focused item actually changes on cursor movement. - `load`/`result`/`zero`/`one` track async reader/matcher completion, which has no synchronous callback, so `App::poll_completion_events` edge-triggers them from the `Heartbeat` handler rather than the render path. A `Render` is queued just before them so a list-inspecting binding (e.g. `load:first`) still sees the finished results. This removes the branching that previously ran on every render tick and keeps the event logic out of the unrelated `dispatch_action` arms. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019QKxusGbxLxqWdYyeqrb68 * misc tweaks incl. noremap * fixes * docs: document new binds * coderabbit review * fix: address Copilot review comments on action binds - Split `--bind` specs with top-level comma splitting in `SkimOptions::build` so commas inside parenthesized action arguments (e.g. `act-up:execute(echo a,b)`) no longer garble follow-up bindings. Reuses the existing `split_top_level` helper (now `pub(crate)`), matching `KeyMap::add_keymaps_str`. - Correct the misleading `load` event comment in `check_reader`: the event is fired from `App::poll_completion_events` (the heartbeat handler), not the render path. - Add a unit test covering commas inside action arguments. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pxems1gNKKezFcxtZfURJp * fix: harden action-trigger binds (logging, runtime bind/unbind, API surface) Address three review findings on the action-trigger feature: - Log dropped `--bind` specs: an unknown trigger name or an invalid follow-up chain in parse_action_binds is now reported via debug! instead of vanishing silently, matching the keymap path's behavior. - Make the runtime `bind`/`unbind` actions manage action triggers as well as keys: `bind(act-up:last)` merges into action_binds and `unbind(act-up)` removes the trigger, with the same keys-win precedence as `--bind`. Trigger-name resolution is shared through a new binds::action_trigger_name helper. - Narrow the new App fields (reader_done, load_event_fired, result_pending) to pub(crate): they are a Skim<->App coordination protocol, not public API. Update the manpage (regenerated sk.1) and ARCHITECTURE.md accordingly, and cover the new behavior with unit tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TgSqqsXn1GfQRZhQWAWi7t * fix: don't abort the event loop on an invalid if-* branch chain `if-*` branch chains are stored unparsed by `parse_action`, so an invalid action name only surfaces when the binding fires. `dispatch_conditional` propagated that parse error out of `App::handle_event`, killing the whole finder mid-session on a bind typo. Log and skip the chain instead, matching the invalid-chain handling of `parse_action_binds`. Also refresh the stale line numbers in the ARCHITECTURE.md cross-reference table. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TgSqqsXn1GfQRZhQWAWi7t * fix: make sure to render before start in sync mode * chore: push snaps * fix: misc * fix: address review comments on start event, if-* logging and docs - skim.rs: retry the one-shot `start` event from `tick()` so a momentarily full bounded `event_tx` at the `start()`/`enter()` call sites can no longer drop it permanently. Idempotent via the `start_fired` guard. - app.rs: log an invalid `if-*` conditional action chain at `warn!` instead of `debug!` so a misconfigured binding is discoverable by default. - ARCHITECTURE.md: clarify that `Skim::check_reader` only records `reader_done`; `App::poll_completion_events` owns and emits `load`/`result`/`zero`/`one`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019QKxusGbxLxqWdYyeqrb68 * chore: minor formatting --------- Co-authored-by: Claude <noreply@anthropic.com>
30 lines
2.1 KiB
Plaintext
30 lines
2.1 KiB
Plaintext
---
|
|
source: tests/binds.rs
|
|
description: "input: items [\"a\", \"b\", \"c\"]\noptions: --bind zero:set-header(none)\nafter:\n @char 'z'"
|
|
---
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" "
|
|
" none "
|
|
" 0/3 0/0"
|
|
"> z "
|
|
cursor: (24, 4)
|