Skip to content

Stream merge redirects#276

Merged
mitchpaulus merged 2 commits into
mainfrom
stream-merge-redirects
Jul 10, 2026
Merged

Stream merge redirects#276
mitchpaulus merged 2 commits into
mainfrom
stream-merge-redirects

Conversation

@mitchpaulus

Copy link
Copy Markdown
Owner

No description provided.

mitchpaulus and others added 2 commits July 10, 2026 11:16
New single-token merge redirects (no internal spaces): 2>&1 sends stderr
to stdout's final destination, 1>&2 sends stdout to stderr's. Unlike
POSIX these are not order-sensitive fd duplication; the merged stream
aliases the other stream's resolved destination, so `2>&1 *` captures
both streams interleaved and `[[make] 2>&1 [grep err]] |;` sends stderr
through the pipe, cross-platform. Works on command lists, pipeline
stages, and quotations.

Each stream now has exactly one destination: combining two destinations
on the same stream (capture + file redirect, &> + 2>, a second >, merge
+ anything on that stream, circular double merge, or 2>&1 with <>) is an
error at both runtime and in the static type checker, with identical
messages. Previously the extra redirect was silently ignored or
last-wins. The checker tracks per-stream destination states (file,
in-place, merged) on the command type; <> now statically requires a
Path target to match the runtime.

Also fixes: loop quotations ignored stderr redirects and append mode and
dropped the enclosing quotation's redirected streams (both loop paths
now build their context via BuildExecutionContext), and CopyListParams
never copied AppendOutput.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Quotations accept only the redirects that don't change their stack
effect: file redirects (>, >>, 2>, 2>>, &>, &>>), stdin (<), and the
merges (2>&1, 1>&2). The captures (*, *b, ^, ^b) and the in-place
redirect (<>) are rejected on quotations with a clear message at both
runtime and in the static type checker.

Previously a capture on a quotation fell into the multiplication branch
at runtime ("Cannot do '*' operation on a stack with only one item"),
and the type checker wrongly accepted <> on a quotation that the
runtime then rejected. Capture individual command lists instead, e.g.
[[cmd1] [cmd2]] (* !) map.

Docs now state the allowed/excluded operator sets, that destination
conflicts on quotations are enforced at runtime (redirects never change
a quotation's stack effect, so they are invisible to the checker), and
the open-per-execution rule: a >-redirected quotation truncates its
file on every execution (use >> to accumulate), except loop, which
opens the file once for all iterations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mitchpaulus
mitchpaulus merged commit d3a732f into main Jul 10, 2026
1 check passed
@mitchpaulus
mitchpaulus deleted the stream-merge-redirects branch July 10, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant