feat(filters): global layers pipeline and levels (v1: decorative only)#2297
Open
aeppling wants to merge 6 commits into
Open
feat(filters): global layers pipeline and levels (v1: decorative only)#2297aeppling wants to merge 6 commits into
aeppling wants to merge 6 commits into
Conversation
Introduce a generic filter pipeline routed centrally in core::runner so every command flows through the enabled layers before its own filter, which always runs last. - core::pipeline: `Layers` (per-command, code-level policy), `Pipeline` with `run` (captured) and `stream` (streaming) modes, and the decorative layer (light/reasonable/high) shared by both via `decorative_line`. - Levels resolved once and cached (env RTK_DECORATIVE > [levels] config > default) to protect the <10ms startup budget. - runner applies the pipeline for captured (run_filtered/_with_exit) and streamed (run_streamed) paths, gated by RunOptions.layers (default all on). - config: new [levels] section (decorative). - mypy routes through the pipeline centrally (inline strip_ansi removed).
…ers) Separate concerns so adding a layer is a new file, not bloat in one: - pipeline/mod.rs — Pipeline, Layers, run()/stream() (layer-agnostic) - pipeline/levels.rs — Levels + cached env/config resolution - pipeline/decorative.rs — the decorative layer + its streaming adapter No behaviour change; pure code movement.
Commands with no cmds/ handler and no TOML filter previously passed through unfiltered. They now stream live through the global pipeline. Routing order is unchanged: cmds -> TOML -> global fallback pipeline; it fires only when neither matched. - Streams (not captures): forwards output live, never hangs on never-terminating commands; layers apply per line via Pipeline::stream. - Interactivity is decided by TTY, not a command list: terminal stdout passes through, piped stdout streams through the pipeline. - runner streamed mode honors RunOptions.inherit_stdin (for piped input). - core::stream::Identity: a no-op StreamFilter (the empty layer set's inner).
These filters route through runner, so the decorative pipeline layer already strips ANSI before their custom filter runs; their own strip_ansi was a runtime no-op. Removed it. - next_cmd, rake_cmd: drop strip_ansi (rake's ANSI test fixture de-ANSIfied, since ANSI handling is now the pipeline's job). - glab_cmd: drop the strip_ansi step; GitLab-specific section/bare-ANSI regex cleanup stays. Commands that bypass runner (dotnet/binlog, gt, playwright) keep their own stripping — they are not covered by the central pipeline.
Raw-output commands (cat, head, tail, base64, xxd, hexdump, od, strings, dd) must stay byte-exact, so they bypass the global fallback pipeline and pass through untouched. Users extend the list via [levels].exclude in config (same location as the layer levels). Also fix LevelsConfig parsing: decorative now has a serde default, so a partial [levels] table (e.g. only exclude) no longer drops the whole config.
- src/core/pipeline/README.md: technical flow — layers vs levels vs custom, run/stream modes, where it is wired (runner), global fallback + exclude, level resolution, how to add a layer. - TECHNICAL.md: generic pipeline in filter execution + updated fallback flow. - configuration.md: [levels] (decorative + exclude), RTK_DECORATIVE env var, and a user-facing "Filter levels" section.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add a centralized, layered output pipeline (
core::pipeline), applied inrunnerbefore each command's own filter — for both captured and streamed commands. First layer: decorative (strip ANSI, collapse blank runs, drop box-drawing athigh), user-tunable via[levels].decorativeorRTK_DECORATIVE(light/reasonable/high).Add a global fallback pipeline: commands with no
cmds/handler and no TOML filter now stream through the pipeline too, TTY-gated (terminal → passthrough, piped → filter), with a built-in + user-extensible ([levels].exclude) exclude list so raw-output commands (cat,head,base64, …) stay byte-exact. Routing order unchanged: cmds → TOML → fallback.Remove now-redundant per-command ANSI stripping for commands the pipeline covers.
Test plan
cargo fmt --all && cargo clippy --all-targets && cargo test, 2078 passed, 0 failed; clippy cleanrtk <command>output inspectedrtk printf '…\x1b…\n\n\n…'→ ANSI stripped, blank runs collapsed;RTK_DECORATIVE=lightpreserves blanksrtk cat <file>→ raw passthrough (excluded);[levels].exclude=["printf"]→ printf rawrtk df→ TOML filter path unaffected (RTK_NO_TOML=1falls through to the pipeline)false→ 1, unknown command → 127