Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[Console] Bash completion integration#42251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
fabpot merged 2 commits intosymfony:5.4fromwouterj:issue-38275/shell-autocomplete
Oct 19, 2021

Conversation

@wouterj
Copy link
Member

@wouterjwouterj commentedJul 24, 2021
edited
Loading

QA
Branch?5.4
Bug fix?no
New feature?yes
Deprecations?no
TicketsFix#38275
LicenseMIT
Doc PR-

This is a first shot at implementing interactive bash completion support in the Console component. Besides completing option and command names, commands can overrideCommand::complete() to implement completing values.

I've added an example code to thesecrets:remove command, which now supports autocompletion quite nicely:render1630315116886

And support for other applications usingsymfony/console is automatically included (if the autocompletion script is installed for that specific application):
render1630314403752

This PR only implements Bash completion. Zsh and Fish have much more sophisticated completion systems, but I propose to keep those for a future PR if there is a need for this.

How it works

  1. A bash completion function (_console) is defined bybin/console completion bash for theconsole command (name of the "binary" file)
  2. This completion function calls the localbin/console _complete command to come up with suggestions
  3. Bash parses these suggestions and shows them to the user.

This has one drawback: the_console function is defined globally only once. This means we cannot easily change it, as it would break if you run different Symfony versions. We should probably add versioning (e.g.bin/console _complete --version=1.0) and don't suggest anything if the version doesn't match.

Maybe it would be safer to mark this feature as experimental and target 6.0, to allow us to fine tune the shell related sides over the lifespan of 6.x?#42251 (comment)

Steps to test yourself

Load this PR in your project, open a bash shell and run this command to "install" completion for this project:

bin/console completion bash > /etc/bash_completion.d/console

Then reload the bash shell and enjoy autocompletion.

TODO

  • Autocompleting in the middle of the input doesn't work yet (i.e.bin/console --en<TAB> cache:clear)
  • Better error handling
  • Add abin/console completion command to dump the_console file, so users can install this locally
  • Add some versioning, to allow us to change the_console file in the future
  • See how we can better support standalone usage (e.g. Composer) Tested on Laravel's artisan, works flawlessly

kbond, damienalexandre, ro0NL, javiereguiluz, ogizanagi, shyim, JoshuaBehrens, seferov, lyrixx, linaori, and 30 more reacted with thumbs up emojitarlepp, OskarStark, fbourigault, chalasr, W0rma, javiereguiluz, ogizanagi, shyim, JoshuaBehrens, lyrixx, and 22 more reacted with hooray emojinicolas-grekas, lyrixx, linaori, kayneth, ismail1432, fpesch, chapterjason, Toflar, Guikingone, ahmed-bhs, and 21 more reacted with heart emojidamienalexandre, 94noni, jkrzefski, chapterjason, DamienHarper, zlodes, and SmetDenis reacted with eyes emoji
@wouterjwouterj requested a review fromchalasr as acode ownerJuly 24, 2021 16:33
@carsonbotcarsonbot changed the title[WIP] [Console] Bash completion integration[Console] [WIP] Bash completion integrationJul 24, 2021
@wouterjwouterjforce-pushed theissue-38275/shell-autocomplete branch 2 times, most recently from47efd2b to0623991CompareJuly 24, 2021 19:46
@Nyholm
Copy link
Member

Thank you.

This looks super cool. =)

OskarStark, amigabits, and ging-dev reacted with rocket emoji

@wouterjwouterjforce-pushed theissue-38275/shell-autocomplete branch from0623991 to5986f27CompareJuly 25, 2021 10:46
@wouterjwouterj changed the title[Console] [WIP] Bash completion integration[Console] Bash completion integrationJul 25, 2021
@wouterj
Copy link
MemberAuthor

Thanks :)

I've updated this PR to complete most of the important TODO items (and also updated the usage in the PR description). It still needs more unit tests (I used a local shell script to test things, I need to convert it to unit tests) and I need to add a line to the CHANGELOG. Other than that, I think this in a final state, so ready for reviews :)

@wouterjwouterjforce-pushed theissue-38275/shell-autocomplete branch from5986f27 to8873ba0CompareJuly 25, 2021 10:52
@wouterjwouterjforce-pushed theissue-38275/shell-autocomplete branch from8873ba0 tocff89a6CompareJuly 27, 2021 19:13
@derrabusderrabus added this to the5.4 milestoneJul 29, 2021
@wouterjwouterjforce-pushed theissue-38275/shell-autocomplete branch fromcff89a6 toca0b1dbCompareJuly 30, 2021 09:45
@OskarStark
Copy link
Contributor

Should we target6.0 and mark this big new feature as@experimental?

@Nyholm
Copy link
Member

My general opinion is that we mark too many classes experimental.

But I let@wouterj decide in this specific case.

wouterj, OskarStark, chalasr, Iyadhfaleh, and dunglas reacted with thumbs up emoji

@wouterj
Copy link
MemberAuthor

wouterj commentedAug 2, 2021
edited
Loading

The public API side of this feature is quite minimal (one method inConsole which needs full BC and 2 classes that we should mark as@final). The feature itself is purely DX (i.e. it's not that big of a deal if it stops working), so I agree with not marking this as experimental.

Adding support for ZSH might break things, but a community member already stepped up to provide a PR for this if this is merged, so this can be caught before the 5.4 release. Other than that, all complexity of this feature is in theCompletionInput::bind() method, which will all be normal "bug fixes".


I guess the lack of reviewers in this PR indicates that it's probably a bit difficult to review. Some hints:

  • The main logic is inCompleteCommand andCompletionInput. The command receives an array of input "words" (similar to$argv) and the index in that array of the current cursor position (to know where completion is requested). Based on this,CompletionInput has to provide the correct type, value, option name, etc. That is the core logic of this PR (see also its tests).
  • From a DX side, seeSecretsRemoveCommand::complete(),Command::complete() andApplication::complete() for PHP usage of this feature.
  • If you're into bash, consider reviewingcompletion.bash andBashCompletionOutput. That latter is not doing much (only providing completion options as space-separated values). The first one is a bit more complex than the basic bash completion function, in order to simplify working with colons in the command names and= signs in between option name and value.

@dkarlovi
Copy link
Contributor

@wouterj I'm looking for a simple way to test this in my actual app, IMO it would be most beneficial to figure it all out. I'll provide my findings if I find a way to do that.

Other than that, a cool sample might be to make a fork of Composer with this enabled. It might make it simple to visualize once you can test it for yourself easily.

@dkarlovi
Copy link
Contributor

Also, this is an absurdly valuable feature, thank you a lot for working on this! 😍

wouterj, JoshuaBehrens, OskarStark, and bigfoot90 reacted with heart emoji

@wouterj
Copy link
MemberAuthor

@dkarlovi if you have an app running Symfony 5.3, you can try to clone my fork locally and use thelink utility:

git clone https://github.com/wouterj/symfony -b issue-38275/shell-autocompletecd symfony./link /path/to/project

And then use theeval $(bin/console completion bash) in your app.

dkarlovi reacted with hooray emojidkarlovi reacted with eyes emoji

@dkarlovi

This comment has been minimized.

@dkarlovi
Copy link
Contributor

@wouterj which Bash did you use to test this? For me, if I test withbin/console, it doesn't work, but./console works, but need to change CWD obviously.

To get it to work, I needed to change it like this:

complete -F _sf_console bin/console

Also, theeval trick you gave didn't register the completion for me (checked withcomplete -p console), had to pipe it to a file and source it

bin/console completion bash > foo.shsource foo.sh

@dkarlovi
Copy link
Contributor

One thing which might be neat to have is to provide a flag for the dumper, something like

bin/console completion bash --verbose-completion

or similar, where it would create additional code in there to help you debug it if you're working on it. Might be too niche, maybe wait for use cases, but as I was testing this, I needed to edit the completion function to add them myself.

Copy link
Contributor

@theofidrytheofidry left a comment
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

A few minor comments/nitpicks. A big 👍 for this feature


$option =$this->getOptionFromToken($optionToken);
if (null ===$option && !$this->isCursorFree()) {
$this->completionType =self::TYPE_OPTION_NAME;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I tend to find this sort of API a bit brittle: it's easy to miss that all properties need to be set together. I am also not sure if this class is supposed to be extendable or not (it is not final at least, didn't check how hard/easy it would be to extend).

WDYT of adding a private accessorsetCompletionValues(string $type, string $anme, string $value)?

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I do agree with you that this a bit brittle, but this is indeed not meant to be extended (I've made the class final now - thanks to your comment). The same comment as#42251 (comment) applies here imho.
Besides, we don't always set all 3 properties at the same time, sometimes only 1 or 2.


$relevantToken =$this->getRelevantToken();
if ('-' ===$relevantToken[0]) {
// the current token is an input option: complete either option name or option value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

what about moving the different blocks into dedicated methods? e.g.addCompletionForInputOption()

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

As with all parsing, it's really horrible code (lots of nested if statements) but not so easy to clean-up.

In this case,$relevantToken[0] === '-' can have multiple meanings: Either it's just- or--, indicating the next tokens are all argument values. Or it's the start of an option (short or long). And things get even more messy with things like-eprod,-vvv and-ev (indicating respectively an option with its value, an option without value, and 2 options).

I also don't think it's worth cleaning this code up. All "messiness" is contained in a single method, which will not be touched regularly (how we parse options, arguments and values is pretty static).

@wouterjwouterjforce-pushed theissue-38275/shell-autocomplete branch fromf071e5f to7810d19CompareOctober 18, 2021 19:02
@wouterj
Copy link
MemberAuthor

Thanks for the review@theofidry!

PR updated and rebased. We have a new failure (7.2) but I can't find any error logs whatsoever about this failure.

@wouterjwouterjforce-pushed theissue-38275/shell-autocomplete branch from7810d19 toe0a174fCompareOctober 19, 2021 08:38
@wouterj
Copy link
MemberAuthor

Thanks, PR updated.

@fabpot
Copy link
Member

Thank you@wouterj.

wouterj, chalasr, and jdreesen reacted with rocket emoji

@fabpotfabpot merged commitcf8a997 intosymfony:5.4Oct 19, 2021
symfony-splitter pushed a commit to symfony/framework-bundle that referenced this pull requestOct 19, 2021
This PR was squashed before being merged into the 5.4 branch.Discussion----------[Console] Bash completion integration| Q             | A| ------------- | ---| Branch?       | 5.4| Bug fix?      | no| New feature?  | yes| Deprecations? | no| Tickets       | Fix #38275| License       | MIT| Doc PR        | -This is a first shot at implementing interactive bash completion support in the Console component. Besides completing option and command names, commands can override `Command::complete()` to implement completing values.I've added an example code to the `secrets:remove` command, which now supports autocompletion quite nicely: ![render1630315116886](https://user-images.githubusercontent.com/749025/136708284-bf2e4c12-7cb7-4d5e-9c8d-68bcdca6fd7c.gif)And support for other applications using `symfony/console` is automatically included (if the autocompletion script is installed for that specific application):![render1630314403752](https://user-images.githubusercontent.com/749025/136708323-dfbccb77-dcbd-4d1e-8bb5-85b88f0b358b.gif)This PR only implements Bash completion. Zsh and Fish have much more sophisticated completion systems, but I propose to keep those for a future PR if there is a need for this.### How it works1. A bash completion function (`_console`) is defined by `bin/console completion bash` for the `console` command (name of the "binary" file)2. This completion function calls the local `bin/console _complete` command to come up with suggestions3. Bash parses these suggestions and shows them to the user.This has one drawback: the `_console` function is defined globally only once. This means we cannot easily change it, as it would break if you run different Symfony versions. We should probably add versioning (e.g. `bin/console _complete --version=1.0`) and don't suggest anything if the version doesn't match.<s> **Maybe it would be safer to mark this feature as experimental and target 6.0, to allow us to fine tune the shell related sides over the lifespan of 6.x?** </s>symfony/symfony#42251 (comment)### Steps to test yourselfLoad this PR in your project, open a bash shell and run this command to "install" completion for this project:```bin/console completion bash > /etc/bash_completion.d/console````Then reload the bash shell and enjoy autocompletion.### TODO* [x] Autocompleting in the middle of the input doesn't work yet (i.e. `bin/console --en<TAB> cache:clear`)* [x] Better error handling* [x] Add a `bin/console completion` command to dump the `_console` file, so users can install this locally* [x] Add some versioning, to allow us to change the `_console` file in the future* [x] <s>See how we can better support standalone usage (e.g. Composer)</s> Tested on Laravel's artisan, works flawlesslyCommits-------e0a174f877 [FrameworkBundle] Add CLI completion to secrets:remove82ef399de3 [Console] Bash completion integration
@wouterjwouterj deleted the issue-38275/shell-autocomplete branchOctober 19, 2021 09:40
if (!file_exists($debugFile)) {
touch($debugFile);
}
$process =newProcess(['tail','-f',$debugFile],null,null,null,0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

what happens on windows (and yes, bash can be used on windows, which does not imply thattail is available in the PATH AFAICT) ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This needs some more special casing. For example, you might not havesymfony/process installed.

return$parseOptions;
}

privatefunctiongetOptionValueFromToken(string$optionToken):string
Copy link
Member

@GromNaNGromNaNOct 19, 2021
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Is this function actually used?


private$tokens;
private$currentIndex;
private$indexToArgumentIndex = [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This property is not used.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@dunglasdunglasdunglas left review comments

@nicolas-grekasnicolas-grekasnicolas-grekas left review comments

@GromNaNGromNaNGromNaN left review comments

@stofstofstof left review comments

@derrabusderrabusderrabus left review comments

@fabpotfabpotfabpot approved these changes

@chalasrchalasrAwaiting requested review from chalasrchalasr is a code owner

+4 more reviewers

@dkarlovidkarlovidkarlovi approved these changes

@ro0NLro0NLro0NL left review comments

@theofidrytheofidrytheofidry left review comments

@Neirda24Neirda24Neirda24 left review comments

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Projects

None yet

Milestone

5.4

Development

Successfully merging this pull request may close these issues.

[Console][UX][DX] shell completion support directly in the Console component

15 participants

@wouterj@Nyholm@OskarStark@dkarlovi@chalasr@Neirda24@fabpot@dunglas@nicolas-grekas@GromNaN@stof@ro0NL@derrabus@theofidry@carsonbot

[8]ページ先頭

©2009-2025 Movatter.jp