symfony icon indicating copy to clipboard operation
symfony copied to clipboard

[Console] Fix various completion edge cases

Open Seldaek opened this issue 3 years ago • 2 comments

Q A
Branch? 5.4
Bug fix? yes
New feature? no
Deprecations? no
Tickets Fix #...
License MIT
Doc PR symfony/symfony-docs#...

Refs https://github.com/composer/composer/issues/11029

There are two things I am trying to fix here:

  • composer require yiisoft/yii-[TAB] works, but composer req yiisoft/yii-[TAB] does not work
  • composer up suggets upgrade update but both are aliases to the same command, so I fixed it to make it always just suggest one name, which lets the shell complete to composer update and then I can tab again to get more relevant completions.

The fixes work almost.. I have one problem for which I need help from someone (maybe @wouterj?).

See the changes in CompleteCommand. The current code is doing smth like:

  • try to find a command
  • if none found, autocomplete command names
  • if a command is found and the completion does not match the command name/aliases, suggest command name
  • otherwise bind the command and forward completion to the command

This is problematic because it breaks the 1st case I mentioned above, and it also is just fairly dodgy if you are trying to complete an arg with the command's name as input (e.g. composer require require) it will kinda stay stuck on suggesting the command's name even tho you are completing another arg here.

So I am trying to change it to a flow like:

  • try to find a command
  • if a command is found check where the completion input/caret is.
  • if the caret is at the end of the command name, complete that
  • otherwise bind the command and then check what can be completed

But it seems like CompletionInput does not work correctly there.. see these few examples from the completion debug output after I added some extra logging:

            $command = $this->findCommand($completionInput, $output);
            $this->log('  START, completing command name ("'.$completionInput->getCompletionName().'/'.$completionInput->getCompletionType().'")');
            if (null !== $command && !$completionInput->mustSuggestArgumentValuesFor('command')) {
                $command->mergeApplicationDefinition();
                $completionInput->bind($command->getDefinition());
                $this->log('  BOUND, completing command name ("'.$completionInput->getCompletionName().'/'.$completionInput->getCompletionType().'")');
            }
Input: ("|" indicates the cursor position)
  c req|
Command:
  /var/www/composer/bin/composer _complete -sbash -c1 -S2.4.999-dev+source -ic -ireq
Messages:
  START, completing command name ("command/argument_value")

Input: ("|" indicates the cursor position)
  c require |
Command:
  /var/www/composer/bin/composer _complete -sbash -c2 -S2.4.999-dev+source -ic -irequire
Messages:
  START, completing command name ("/none")
  BOUND, completing command name ("packages/argument_value")

Input: ("|" indicates the cursor position)
  c require foo|
Command:
  /var/www/composer/bin/composer _complete -sbash -c2 -S2.4.999-dev+source -ic -irequire -ifoo
Messages:
  START, completing command name ("command/argument_value")

As you can see when the input is c req| it completes the command argument as it should, then with c require | it also works as it should, detecting the space and moving to none completion. But then as soon as you have some more text it goes back to think it is completing the command argument and that makes no sense.

I am too dumb or tired to figure out what's going on in the CompletionInput class or its tests, so I'd appreciate input there :)

Seldaek avatar Aug 30 '22 14:08 Seldaek

Hey!

I think @technojit has recently worked with this code. Maybe they can help review this?

Cheers!

Carsonbot

carsonbot avatar Aug 31 '22 10:08 carsonbot

I am too dumb or tired to figure out what's going on in the CompletionInput class or its tests, so I'd appreciate input there :)

The CompletionInput is a monster, so you sure shouldn't feel dumb if you cannot follow it (it also took me an hour to relearn enough of the logic to find the issue).

In fact, you've found a bug that also exists on 5.4, I've submitted a fix: #47726 When that one is merged up, this one should work correctly.

I've played a lot with this PR locally in order to find this bug. The behavior looks very promising to me! Thanks for working on these edge-cases.

wouterj avatar Sep 29 '22 11:09 wouterj