InputSource: expose isCanonicalEmpty for stdin-or-cwd routing#19
Merged
Conversation
Commands that emulate tools with 'read stdin OR walk the cwd' behaviour (ripgrep's no-path default) must know whether the embedder attached real input. The host process's fd 0 can't answer that for an embedded shell — an iBash 'echo x | rg pat' must read the pipe even though the app's fd 0 is a terminal or /dev/null. The binding can answer: shells bind the canonical .empty when no pipe or redirect feeds a command, anything else was attached on purpose. Identity-based on the shared cursor, so copies stay canonical while a manually built zero-byte stream counts as attached-but-empty — matching bash, where 'true | cmd' hands cmd a real (empty) pipe. Wanted by Cocoanetics/SwiftPorts#71 (rg no-path routing, issue SwiftPorts#65) to honour the in-process InputSource contract flagged in its review. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
odrobnik
added a commit
to Cocoanetics/SwiftPorts
that referenced
this pull request
Jun 11, 2026
Review feedback: defaulting the routing to the host process's fd 0 regressed the in-process entry point — an embedder that binds a real InputSource while the app's fd 0 is /dev/null (GUI hosts, CI) or a terminal would walk the cwd instead of reading the input it was handed, unless it learned to pass the new boolean. The default is now context-derived (stdinIsReadable: Bool? = nil): standalone — Shell.current is the process-default shell — keeps real rg's is_readable_stdin() against fd 0; an embedded shell answers from the binding itself via ShellKit's new InputSource.isCanonicalEmpty — .empty means the shell attached nothing (walk), anything else was bound on purpose (read). That also fixes the embedded pipeline path on terminal hosts, where fd-0 sampling ignored a bound pipe even before this PR. Requires Cocoanetics/ShellKit#19 (the pin follows ShellKit main — merge that first). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
odrobnik
added a commit
to Cocoanetics/SwiftPorts
that referenced
this pull request
Jun 11, 2026
* rg: walk the cwd unless stdin is actually readable input `rg PATTERN` with no path argument read (empty) stdin and reported no matches whenever fd 0 wasn't a TTY — a GUI host or CI harness hands its children /dev/null, which is neither a terminal nor readable input, and real rg walks the cwd there. Mirror upstream's is_readable_stdin(): consume stdin only when it's a regular file, FIFO, or socket (new TTY.isStdinReadable; GetFileType disk/pipe on Windows), walk the cwd otherwise. Detection errors mean 'walk', which also keeps a closed fd 0 out of the stdin-reading path. The decision threads through RgExecutable.run as a defaulted parameter so the tests pin both routes deterministically instead of inheriting whatever the test harness bound to fd 0. Also align the no-path display shape with real rg: the default walk prints bare relative paths (a.txt, not ./a.txt) — root display "." instead of "./", the same shape fd's default already uses. Fixes #65 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * rg: derive the no-path stdin routing from the binding when embedded Review feedback: defaulting the routing to the host process's fd 0 regressed the in-process entry point — an embedder that binds a real InputSource while the app's fd 0 is /dev/null (GUI hosts, CI) or a terminal would walk the cwd instead of reading the input it was handed, unless it learned to pass the new boolean. The default is now context-derived (stdinIsReadable: Bool? = nil): standalone — Shell.current is the process-default shell — keeps real rg's is_readable_stdin() against fd 0; an embedded shell answers from the binding itself via ShellKit's new InputSource.isCanonicalEmpty — .empty means the shell attached nothing (walk), anything else was bound on purpose (read). That also fixes the embedded pipeline path on terminal hosts, where fd-0 sampling ignored a bound pipe even before this PR. Requires Cocoanetics/ShellKit#19 (the pin follows ShellKit main — merge that first). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.
Commands that emulate tools with "read stdin OR walk the cwd" behaviour (ripgrep's no-path default) need to know whether the embedder attached real input. The host process's fd 0 can't answer that for an embedded shell — an iBash
echo x | rg patmust read the pipe even though the app's fd 0 is a terminal or/dev/null. The binding can answer: shells bind the canonical.emptywhen no pipe or redirect feeds a command (SwiftBash does exactly this), anything else was attached on purpose.isCanonicalEmptyis identity-based on the shared cursor, so copies of.emptystay canonical while a manually built zero-byte stream counts as attached-but-empty — matching bash, wheretrue | cmdhandscmda real (empty) pipe that it reads to EOF.Wanted by Cocoanetics/SwiftPorts#71 (rg no-path routing for SwiftPorts#65): its review flagged that sampling fd 0 regresses the in-process
InputSourcecontract; with this seam the routing comes from the binding itself. SwiftPorts pinsbranch: main, so merging this unblocks that PR's follow-up commit.59 tests pass (2 new).
🤖 Generated with Claude Code