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

Already on GitHub? Sign in to your account

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

Closed
wants to merge 2 commits into
from
Jump to file or symbol
Failed to load files and symbols.
+31 −21
Split
@@ -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;
}
@@ -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'));