Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

[2.2][Console] Fix autocompletion of command names when namespaces conflict #7589

Closed
wants to merge 2 commits into from

2 participants

@Seldaek
Collaborator

Fixes #7234

Currently autocompletion of namespaces works on all namespaces at once. This fixes it to only search inside subnamespaces once we matched the first level namespace. Otherwise if you have api:doc and generate:doctrine:entity commands, typing gen:doc:entity trips it up because it thinks "doc" is "api:doc", and you end up with a completed name of generate:doc:entity which does not match any command.

@fabpot fabpot referenced this pull request from a commit
@fabpot fabpot merged branch Seldaek/autocomplete_fix (PR #7589)
This PR was submitted for the 2.2 branch but it was merged into the 2.1 branch instead (closes #7589).

Discussion
----------

[2.2][Console] Fix autocompletion of command names when namespaces conflict

Fixes #7234

Currently autocompletion of namespaces works on *all* namespaces at once. This fixes it to only search inside subnamespaces once we matched the first level namespace. Otherwise if you have `api:doc` and `generate:doctrine:entity` commands, typing `gen:doc:entity` trips it up because it thinks "doc" is "api:doc", and you end up with a completed name of `generate:doc:entity` which does not match any command.

Commits
-------

fa465b1 [2.2][Console] Fix autocompletion of command names when namespaces conflict
95927c7
@fabpot fabpot closed this
@mmucklo mmucklo referenced this pull request from a commit
@fabpot fabpot merged branch Seldaek/autocomplete_fix (PR #7589)
This PR was submitted for the 2.2 branch but it was merged into the 2.1 branch instead (closes #7589).

Discussion
----------

[2.2][Console] Fix autocompletion of command names when namespaces conflict

Fixes #7234

Currently autocompletion of namespaces works on *all* namespaces at once. This fixes it to only search inside subnamespaces once we matched the first level namespace. Otherwise if you have `api:doc` and `generate:doctrine:entity` commands, typing `gen:doc:entity` trips it up because it thinks "doc" is "api:doc", and you end up with a completed name of `generate:doc:entity` which does not match any command.

Commits
-------

fa465b1 [2.2][Console] Fix autocompletion of command names when namespaces conflict
fffa53e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
42 src/Symfony/Component/Console/Application.php
@@ -492,20 +492,24 @@ public function getNamespaces()
*/
public function findNamespace($namespace)
{
- $allNamespaces = array();
- foreach ($this->getNamespaces() as $n) {
- $allNamespaces[$n] = explode(':', $n);
- }
-
- $found = array();
+ $allNamespaces = $this->getNamespaces();
+ $found = '';
foreach (explode(':', $namespace) as $i => $part) {
- $abbrevs = static::getAbbreviations(array_unique(array_values(array_filter(array_map(function ($p) use ($i) { return isset($p[$i]) ? $p[$i] : ''; }, $allNamespaces)))));
+ // select sub-namespaces matching the current namespace we found
+ $namespaces = array();
+ foreach ($allNamespaces as $n) {
+ if ('' === $found || 0 === strpos($n, $found)) {
+ $namespaces[$n] = explode(':', $n);
+ }
+ }
+
+ $abbrevs = static::getAbbreviations(array_unique(array_values(array_filter(array_map(function ($p) use ($i) { return isset($p[$i]) ? $p[$i] : ''; }, $namespaces)))));
if (!isset($abbrevs[$part])) {
$message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
if (1 <= $i) {
- $part = implode(':', $found).':'.$part;
+ $part = $found.':'.$part;
}
if ($alternatives = $this->findAlternativeNamespace($part, $abbrevs)) {
@@ -521,14 +525,19 @@ public function findNamespace($namespace)
throw new \InvalidArgumentException($message);
}
+ // there are multiple matches, but $part is an exact match of one of them so we select it
+ if (in_array($part, $abbrevs[$part])) {
+ $abbrevs[$part] = array($part);
+ }
+
if (count($abbrevs[$part]) > 1) {
throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions($abbrevs[$part])));
}
- $found[] = $abbrevs[$part][0];
+ $found .= $found ? ':' . $abbrevs[$part][0] : $abbrevs[$part][0];
}
- return implode(':', $found);
+ return $found;
}
/**
@@ -651,21 +660,12 @@ public static function getAbbreviations($names)
{
$abbrevs = array();
foreach ($names as $name) {
- for ($len = strlen($name) - 1; $len > 0; --$len) {
+ for ($len = strlen($name); $len > 0; --$len) {
$abbrev = substr($name, 0, $len);
- if (!isset($abbrevs[$abbrev])) {
- $abbrevs[$abbrev] = array($name);
- } else {
- $abbrevs[$abbrev][] = $name;
- }
+ $abbrevs[$abbrev][] = $name;
}
}
- // Non-abbreviations always get entered, even if they aren't unique
- foreach ($names as $name) {
- $abbrevs[$name] = array($name);
- }
-
return $abbrevs;
}
View
10 src/Symfony/Component/Console/Tests/ApplicationTest.php
@@ -345,6 +345,16 @@ public function testFindAlternativeNamespace()
}
}
+ public function testFindNamespaceDoesNotFailOnDeepSimilarNamespaces()
+ {
+ $application = $this->getMock('Symfony\Component\Console\Application', array('getNamespaces'));
+ $application->expects($this->once())
+ ->method('getNamespaces')
+ ->will($this->returnValue(array('foo:sublong', 'bar:sub')));
+
+ $this->assertEquals('foo:sublong', $application->findNamespace('f:sub'));
+ }
+
public function testSetCatchExceptions()
{
$application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
Something went wrong with that request. Please try again.