feat: complete task names, and let a task read a command quietly - #52
Merged
Conversation
refsz
force-pushed
the
feat/completion-and-quiet
branch
from
August 25, 2026 18:29
d18367b to
4ec7d40
Compare
Two findings from the drupal.z init work, both small, both reported with a cause.
Task names were missing from the shell completion. `sputnik <TAB>` offered the
core commands and not a single task; `sputnik ddev<TAB>` the same. Tasks are
registered with setHidden(true) so that renderTaskList() stays the only list, and
Symfony's completion filters exactly isHidden() out of the suggestions for the
command argument - hiding and not-suggesting hang off one property. Hiding stays
right, so Application::complete() supplies the names itself, aliases included. A
task marked hidden stays out, which has its own test.
The performance worry in the report is unfounded: discoverAll() is guarded by a
flag and the container hands the discovery over pre-populated, so a second call
per TAB returns the array without touching the filesystem.
Nothing to reinstall after this - the installed script asks the binary at TAB
time, so replacing the PHAR is enough.
Second: a task could not run a command without streaming its output. That is not
about noise, it is about a command run for its value being displayed as if it
were progress:
> php -r echo PHP_VERSION;
8.5.9 <- looks like progress
Building against PHP 8.5.9 <- what the task wanted to say
With a version string that is silly; with the hundred lines of a generated
completion script it is unusable, which is where it was reported. And the only
way around it was a shell redirect - which brings back a shell for no reason,
against the whole point of argv execution.
So `['quiet' => true]` on exec() and shell(). It suppresses the output, not the
command line: you still see what ran and whether it worked, just not its
contents. A test pins that.
executeQuiet() is gone rather than lifted into the interface as proposed. Two
methods differing only in whether they display is a fork in an API that already
has an options array, and it had no caller outside a single test.
refsz
force-pushed
the
feat/completion-and-quiet
branch
from
August 25, 2026 18:35
4ec7d40 to
aabc55e
Compare
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.
The last two findings from the drupal.z
initwork. Both small, both reported with a cause already identified.Task names were missing from the completion
Reproduced against 0.2.4 —
sputnik <TAB>offered the ten core commands and not a single task, while a task's options completed fine once its name was typed out.The cause in the report is right: tasks are registered with
setHidden(true)so thatrenderTaskList()stays the only list, and Symfony's completion filters exactlyisHidden()out of the suggestions for thecommandargument. Hiding and not-suggesting hang off one property.Hiding stays correct, so
Application::complete()supplies the names itself — aliases included, since an alias is a name a user types. A task markedhidden: truestays out, with its own test so that does not regress.The performance worry in the report is unfounded.
discoverAll()is guarded by a flag, and the container hands the discovery over pre-populated (withPreloadedDatasets it), so a second call per TAB returns the array without touching the filesystem. No memo needed.Nothing to reinstall: the installed script asks the binary at TAB time, so replacing the PHAR is enough.
A task could not read a command without streaming it
This is not about noise. A command run for its value was displayed as if it were progress:
The value appears twice. With a version string that is silly; with the hundred lines of a generated completion script it is unusable, which is where it was reported.
The stronger argument is what the absence forced: the only way around it was a shell redirect —
shell('… > /tmp/file'), which is what drupal.z did. That brings back a shell purely to suppress output, against the whole point of argv execution in #30. A missing option was pushing people fromexec()toshell().So
['quiet' => true]onexec()andshell():It suppresses the output, not the command line — you still see
> cat quiet.txtand the✓, so that something ran stays visible and only its contents do not. A test pins that distinction, and the payload in it comes from a file rather than an argument, because an argument would reach the terminal through the echoed command line anyway.Not lifted into the interface
The report proposed promoting
executeQuiet()toExecutorInterface. It is deleted instead. Two methods differing only in whether they display is a fork in an API that already has an options array — andexecuteQuiet()had no caller anywhere outside a single test.Verified
The completion tests drive
_completeon the real binary, the way the installed script does.With this, everything from the drupal.z report is addressed except the preflight proposal, which I argued against separately — #51 fixes the damage it described by persisting a context switch after its listeners, and the reachability probe is not needed for that.
🤖 Generated with Claude Code
https://claude.ai/code/session_018CTvnzcNYmFgm2HQcm821A