10000 Improve UX on not found namespace/command · symfony/symfony@efb7099 · GitHub
[go: up one dir, main page]

Skip to content

Commit efb7099

Browse files
committed
Improve UX on not found namespace/command
1 parent 51bc35c commit efb7099

File tree

3 files changed

+52
-10
lines changed

3 files changed

+52
-10
lines changed

src/Symfony/Component/Console/Application.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
use Symfony\Component\Console\Command\HelpCommand;
3131
use Symfony\Component\Console\Command\ListCommand;
3232
use Symfony\Component\Console\Helper\HelperSet;
33+
use Symfony\Component\Console\Helper\Helper;
3334
use Symfony\Component\Console\Helper\FormatterHelper;
3435
use Symfony\Component\Console\Event\ConsoleCommandEvent;
3536
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
@@ -503,7 +504,7 @@ public function findNamespace($namespace)
503504

504505
$exact = in_array($namespace, $namespaces, true);
505506
if (count($namespaces) > 1 && !$exact) {
506-
throw new CommandNotFoundException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
507+
throw new CommandNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
507508
}
508509

509510
return $exact ? $namespace : reset($namespaces);
@@ -559,9 +560,20 @@ public function find($name)
559560

560561
$exact = in_array($name, $commands, true);
561562
if (count($commands) > 1 && !$exact) {
562-
$suggestions = $this->getAbbreviationSuggestions(array_values($commands));
563+
$usableWidth = $this->terminal->getWidth() - 10;
564+
$abbrevs = array_values($commands);
565+
$maxLen = 0;
566+
foreach ($abbrevs as $abbrev) {
567+
$maxLen = max(Helper::strlen($abbrev), $maxLen);
568+
}
569+
$abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen) {
570+
$abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription();
571+
572+
return Helper::strlen($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev;
573+
}, array_values($commands));
574+
$suggestions = $this->getAbbreviationSuggestions($abbrevs);
563575

564-
throw new CommandNotFoundException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions), array_values($commands));
576+
throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $name, $suggestions), array_values($commands));
565577
}
566578

567579
return $this->get($exact ? $name : reset($commands));
@@ -944,7 +956,7 @@ protected function getDefaultHelperSet()
944956
*/
945957
private function getAbbreviationSuggestions($abbrevs)
946958
{
947-
return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
959+
return ' '.implode("\n ", $abbrevs);
948960
}
949961

950962
/**

src/Symfony/Component/Console/Helper/Helper.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,24 @@ public static function strlen($string)
5858
return mb_strwidth($string, $encoding);
5959
}
6060

61+
/**
62+
* Returns the subset of a string, using mb_substr if it is available.
63+
*
64+
* @param string $string String to subset
65+
* @param int $from Start offset
66+
* @param int|null $length Length to read
67+
*
68+
* @return string The string subset
69+
*/
70+
public static function substr($string, $from, $length = null)
71+
{
72+
if (false === $encoding = mb_detect_encoding($string, null, true)) {
73+
return substr($string);
74+
}
75+
76+
return mb_substr($string, $from, $length, $encoding);
77+
}
78+
6179
public static function formatTime($secs)
6280
{
6381
static $timeFormats = array(

src/Symfony/Component/Console/Tests/ApplicationTest.php

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use Symfony\Component\Console\Event\ConsoleCommandEvent;
2929
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
3030
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
31+
use Symfony\Component\Console\Exception\CommandNotFoundException;
3132
use Symfony\Component\EventDispatcher\EventDispatcher;
3233

3334
class ApplicationTest extends \PHPUnit_Framework_TestCase
@@ -211,16 +212,15 @@ public function testFindNamespaceWithSubnamespaces()
211212
$this->assertEquals('foo', $application->findNamespace('foo'), '->findNamespace() returns commands even if the commands are only contained in subnamespaces');
212213
}
213214

214-
/**
215-
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
216-
* @expectedExceptionMessage The namespace "f" is ambiguous (foo, foo1).
217-
*/
218215
public function testFindAmbiguousNamespace()
219216
{
220217
$application = new Application();
221218
$application->add(new \BarBucCommand());
222219
$application->add(new \FooCommand());
223220
$application->add(new \Foo2Command());
221+
222+
$expectedMsg = "The namespace \"f\" is ambiguous.\nDid you mean one of these?\n foo\n foo1";
223+
$this->setExpectedException(CommandNotFoundException::class, $expectedMsg);
224224
$application->findNamespace('f');
225225
}
226226

@@ -279,8 +279,20 @@ public function provideAmbiguousAbbreviations()
279279
{
280280
return array(
281281
array('f', 'Command "f" is not defined.'),
282-
array('a', 'Command "a" is ambiguous (afoobar, afoobar1 and 1 more).'),
283-
array('foo:b', 'Command "foo:b" is ambiguous (foo:bar, foo:bar1 and 1 more).'),
282+
array(
283+
'a',
284+
"Command \"a\" is ambiguous.\nDid you mean one of these?\n".
285+
" afoobar The foo:bar command\n".
286+
" afoobar1 The foo:bar1 command\n".
287+
' afoobar2 The foo1:bar command',
288+
),
289+
array(
290+
'foo:b',
291+
"Command \"foo:b\" is ambiguous.\nDid you mean one of these?\n".
292+
" foo:bar The foo:bar command\n".
293+
" foo:bar1 The foo:bar1 command\n".
294+
' foo1:bar The foo1:bar command',
295+
),
284296
);
285297
}
286298

0 commit comments

Comments
 (0)
0