Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docs/contributing/TECHNICAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,10 @@ rewrite_compound(cmd, excluded) [src/discover/registry.rs]
|
| Step 2 — Split on operators, rewrite each segment
| Operator (&&, ||, ;) → rewrite both sides
| Pipe (|) → keep producers/intermediate stages raw
| rewrite only a pipeline-safe final stage
| Pipe (|) → keep intermediate stages raw
| rewrite a pipeline-safe final stage, or the
| producer when its rule allows it and all
| consumers are display-only (#3171)
| Stderr pipe (|&) → keep the complete pipeline raw
| Shellism (&) → rewrite both sides (background)
|
Expand Down
2 changes: 1 addition & 1 deletion src/discover/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ When a hook sends `cargo fmt --all && cargo test 2>&1 | tail -20`:
→ [Arg("cargo"), Arg("test"), Redirect("2>&1"), Operator("&&"), Arg("git"), Arg("status")]
```

**Compound splitting** — The rewrite engine walks the tokens, splitting on `Operator` (`&&`, `||`, `;`) and typed `Pipe` tokens (`|`, `|&`). For normal pipelines, producers and intermediate stages stay raw, and only an argument-safe final stage marked `pipeline_final_safe` is rewritten. The initial safe set is ordinary `grep` and `rg` invocations; search pattern-file forms (`-f`/`--file`) defer because they can consume pipeline stdin as configuration. Stderr pipelines (`|&`) and pipelines containing opaque shell groups remain raw.
**Compound splitting** — The rewrite engine walks the tokens, splitting on `Operator` (`&&`, `||`, `;`) and typed `Pipe` tokens (`|`, `|&`). For normal pipelines, intermediate stages stay raw. A final stage whose rule's `pipeline_safety` allows it (ordinary `grep` and `rg` invocations) is rewritten; search pattern-file forms (`-f`/`--file`) defer because they can consume pipeline stdin as configuration. The producer stage is rewritten when its rule's `pipeline_safety` allows it and every downstream stage is a display-only consumer (`cat`, `head`, non-following `tail`) with no file-target redirect (#3171). Stderr pipelines (`|&`) and pipelines containing opaque shell groups remain raw.

**Per-segment rewriting** — Each segment goes through:

Expand Down
2 changes: 1 addition & 1 deletion src/discover/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ fn contains_substitution(cmd: &str) -> bool {

// `>&N`/`>&-` (and `N>&M`) is fd-dup/close; bare `>&` before a word is
// `>word 2>&1` — a file target.
fn redirect_has_file_target(tokens: &[ParsedToken], i: usize) -> bool {
pub(crate) fn redirect_has_file_target(tokens: &[ParsedToken], i: usize) -> bool {
let value = &tokens[i].value;
if let Some(pos) = value.find(">&") {
let tail = &value[pos + 2..];
Expand Down
Loading