Skip to content

feat: complete task names, and let a task read a command quietly - #52

Merged
refsz merged 1 commit into
mainfrom
feat/completion-and-quiet
Aug 25, 2026
Merged

feat: complete task names, and let a task read a command quietly#52
refsz merged 1 commit into
mainfrom
feat/completion-and-quiet

Conversation

@refsz

@refsz refsz commented Aug 25, 2026

Copy link
Copy Markdown
Owner

The last two findings from the drupal.z init work. 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 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 correct, so Application::complete() supplies the names itself — aliases included, since an alias is a name a user types. A task marked hidden: true stays 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 (withPreloadedData sets 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:

  > php -r echo PHP_VERSION;
  8.5.9                        <- looks like progress
Building against PHP 8.5.9     <- what the task wanted to say

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 from exec() to shell().

So ['quiet' => true] on exec() and shell():

$version = $ctx->exec(['git', 'rev-parse', 'HEAD'], ['quiet' => true])->getOutput();

It suppresses the output, not the command line — you still see > cat quiet.txt and 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() to ExecutorInterface. It is deleted instead. Two methods differing only in whether they display is a fork in an API that already has an options array — and executeQuiet() had no caller anywhere outside a single test.

Verified

vendor/bin/phpunit                        787 tests, 1360 assertions, OK (3 new)
vendor/bin/phpstan analyse                [OK] No errors
vendor/bin/php-cs-fixer fix --dry-run     0 of 158 files
vendor/bin/rector --dry-run               [OK]
mkdocs build --strict                     clean

The completion tests drive _complete on 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

@refsz
refsz force-pushed the feat/completion-and-quiet branch from d18367b to 4ec7d40 Compare August 25, 2026 18:29
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
refsz force-pushed the feat/completion-and-quiet branch from 4ec7d40 to aabc55e Compare August 25, 2026 18:35
@refsz
refsz merged commit ef709c7 into main Aug 25, 2026
10 checks passed
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