merged branch lmcd/autocomplete-arrows-new (PR #6564)
This PR was merged into the master branch. Commits -------2b73975
Add new tests and fix problem with the second option being chosen on down arrow8a0bcfb
Use strpos in place of substr9864d95
Not much use in blanking the array each timea4d711c
Enable arrow keys to browse matched autocomplete options Discussion ---------- [Console] Enable arrow keys to browse matched autocomplete options See notes in original autocomplete pull request: #6391 See also @bamarni's pull request implementing more or less the same stuff: #6561 --------------------------------------------------------------------------- by fabpot at 2013-01-05T10:12:47Z Looks good to me. Can you add some unit tests? --------------------------------------------------------------------------- by bamarni at 2013-01-05T12:51:51Z 1 line addition... you definitely got me on the diff! That's what I had mind too, excepted for the default highlight, but as you said it's usually displayed in the question so it 's not necessary. 👍 --------------------------------------------------------------------------- by lmcd at 2013-01-06T04:07:02Z @fabpot Added tests
This commit is contained in:
commit
64bf80c2bb
@ -86,10 +86,13 @@ class DialogHelper extends Helper
|
||||
}
|
||||
$ret = trim($ret);
|
||||
} else {
|
||||
$i = 0;
|
||||
$currentMatched = false;
|
||||
$ret = '';
|
||||
|
||||
$i = 0;
|
||||
$matches = array();
|
||||
$numMatches = 0;
|
||||
$ofs = -1;
|
||||
|
||||
// Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead)
|
||||
shell_exec('stty -icanon -echo');
|
||||
|
||||
@ -98,91 +101,92 @@ class DialogHelper extends Helper
|
||||
|
||||
// Read a keypress
|
||||
while ($c = fread($inputStream, 1)) {
|
||||
// Did we read an escape sequence?
|
||||
if ("\033" === $c) {
|
||||
$c .= fread($inputStream, 2);
|
||||
|
||||
// Escape sequences for arrow keys
|
||||
if ('A' === $c[2] || 'B' === $c[2] || 'C' === $c[2] || 'D' === $c[2]) {
|
||||
// todo
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Backspace Character
|
||||
if ("\177" === $c) {
|
||||
if ($i === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (false === $currentMatched) {
|
||||
if (0 === $numMatches && 0 !== $i) {
|
||||
$i--;
|
||||
// Move cursor backwards
|
||||
$output->write("\033[1D");
|
||||
}
|
||||
|
||||
if ($i === 0) {
|
||||
$ofs = -1;
|
||||
}
|
||||
|
||||
// Erase characters from cursor to end of line
|
||||
$output->write("\033[K");
|
||||
$ret = substr($ret, 0, $i);
|
||||
|
||||
$currentMatched = false;
|
||||
$numMatches = 0;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ("\t" === $c || "\n" === $c) {
|
||||
if (false !== $currentMatched) {
|
||||
// Echo out completed match
|
||||
$output->write(substr($autocomplete[$currentMatched], strlen($ret)));
|
||||
$ret = $autocomplete[$currentMatched];
|
||||
$i = strlen($ret);
|
||||
// Did we read an escape sequence?
|
||||
if ("\033" === $c) {
|
||||
$c .= fread($inputStream, 2);
|
||||
|
||||
if ('A' === $c[2] || 'B' === $c[2]) {
|
||||
if (0 === $i) {
|
||||
$matches = $autocomplete;
|
||||
$numMatches = count($matches);
|
||||
|
||||
if ('A' === $c[2] && -1 === $ofs) {
|
||||
$ofs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 === $numMatches) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ofs += ('A' === $c[2]) ? -1 : 1;
|
||||
$ofs = ($numMatches + $ofs) % $numMatches;
|
||||
}
|
||||
} else if (ord($c) < 32) {
|
||||
if ("\t" === $c || "\n" === $c) {
|
||||
if ($numMatches > 0) {
|
||||
$ret = $matches[$ofs];
|
||||
// Echo out completed match
|
||||
$output->write(substr($ret, $i));
|
||||
$i = strlen($ret);
|
||||
}
|
||||
|
||||
if ("\n" === $c) {
|
||||
$output->write($c);
|
||||
break;
|
||||
}
|
||||
|
||||
$numMatches = 0;
|
||||
}
|
||||
|
||||
if ("\n" === $c) {
|
||||
$output->write($c);
|
||||
break;
|
||||
continue;
|
||||
} else {
|
||||
$output->write($c);
|
||||
$ret .= $c;
|
||||
$i++;
|
||||
|
||||
$numMatches = 0;
|
||||
$ofs = 0;
|
||||
|
||||
foreach ($autocomplete as $value) {
|
||||
// If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle)
|
||||
if (0 === strpos($value, $ret) && $i !== strlen($value)) {
|
||||
$matches[$numMatches++] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$currentMatched = false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ord($c) < 32) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$output->write($c);
|
||||
$ret .= $c;
|
||||
$i++;
|
||||
|
||||
// Erase characters from cursor to end of line
|
||||
$output->write("\033[K");
|
||||
|
||||
foreach ($autocomplete as $j => $value) {
|
||||
// Get a substring of the current autocomplete item based on number of chars typed (e.g. AcmeDemoBundle = Acme)
|
||||
$matchTest = substr($value, 0, $i);
|
||||
|
||||
if ($ret === $matchTest) {
|
||||
if ($i === strlen($value)) {
|
||||
$currentMatched = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Save cursor position
|
||||
$output->write("\0337");
|
||||
|
||||
$output->write('<hl>' . substr($value, $i) . '</hl>');
|
||||
|
||||
// Restore cursor position
|
||||
$output->write("\0338");
|
||||
|
||||
$currentMatched = $j;
|
||||
break;
|
||||
}
|
||||
|
||||
$currentMatched = false;
|
||||
if ($numMatches > 0) {
|
||||
// Save cursor position
|
||||
$output->write("\0337");
|
||||
// Write highlighted text
|
||||
$output->write('<hl>' . substr($matches[$ofs], $i) . '</hl>');
|
||||
// Restore cursor position
|
||||
$output->write("\0338");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,18 +55,24 @@ class DialogHelperTest extends \PHPUnit_Framework_TestCase
|
||||
rewind($output->getStream());
|
||||
$this->assertEquals('What time is it?', stream_get_contents($output->getStream()));
|
||||
|
||||
$bundles = array('AcmeDemoBundle', 'AsseticBundle');
|
||||
$bundles = array('AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle');
|
||||
|
||||
// Acm<NEWLINE>
|
||||
// Ac<BACKSPACE><BACKSPACE>s<TAB>Test<NEWLINE>
|
||||
// <NEWLINE>
|
||||
$inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n");
|
||||
// <UP ARROW><UP ARROW><NEWLINE>
|
||||
// <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB><NEWLINE>
|
||||
// <DOWN ARROW><NEWLINE>
|
||||
$inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\n");
|
||||
$dialog->setInputStream($inputStream);
|
||||
|
||||
if ($this->hasSttyAvailable()) {
|
||||
$this->assertEquals('AcmeDemoBundle', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles));
|
||||
$this->assertEquals('AsseticBundleTest', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles));
|
||||
$this->assertEquals('FrameworkBundle', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles));
|
||||
$this->assertEquals('SecurityBundle', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles));
|
||||
$this->assertEquals('FooBundleTest', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles));
|
||||
$this->assertEquals('AcmeDemoBundle', $dialog->ask($this->getOutputStream(), 'Please select a bundle', 'FrameworkBundle', $bundles));
|
||||
} else {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
Reference in New Issue
Block a user