Skip to content

Commit a4d711c

Browse files
committed
Enable arrow keys to browse matched autocomplete options
1 parent 31ff3db commit a4d711c

File tree

1 file changed

+61
-60
lines changed

1 file changed

+61
-60
lines changed

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

Lines changed: 61 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,13 @@ public function ask(OutputInterface $output, $question, $default = null, array $
8686
}
8787
$ret = trim($ret);
8888
} else {
89-
$i = 0;
90-
$currentMatched = false;
9189
$ret = '';
9290

91+
$i = 0;
92+
$matches = array();
93+
$numMatches = 0;
94+
$ofs = 0;
95+
9396
// Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead)
9497
shell_exec('stty -icanon -echo');
9598

@@ -98,25 +101,9 @@ public function ask(OutputInterface $output, $question, $default = null, array $
98101

99102
// Read a keypress
100103
while ($c = fread($inputStream, 1)) {
101-
// Did we read an escape sequence?
102-
if ("\033" === $c) {
103-
$c .= fread($inputStream, 2);
104-
105-
// Escape sequences for arrow keys
106-
if ('A' === $c[2] || 'B' === $c[2] || 'C' === $c[2] || 'D' === $c[2]) {
107-
// todo
108-
}
109-
110-
continue;
111-
}
112-
113104
// Backspace Character
114105
if ("\177" === $c) {
115-
if ($i === 0) {
116-
continue;
117-
}
118-
119-
if (false === $currentMatched) {
106+
if (0 === $numMatches && 0 !== $i) {
120107
$i--;
121108
// Move cursor backwards
122109
$output->write("\033[1D");
@@ -126,63 +113,77 @@ public function ask(OutputInterface $output, $question, $default = null, array $
126113
$output->write("\033[K");
127114
$ret = substr($ret, 0, $i);
128115

129-
$currentMatched = false;
116+
$matches = array();
117+
$numMatches = 0;
130118

131119
continue;
132120
}
133121

134-
if ("\t" === $c || "\n" === $c) {
135-
if (false !== $currentMatched) {
136-
// Echo out completed match
137-
$output->write(substr($autocomplete[$currentMatched], strlen($ret)));
138-
$ret = $autocomplete[$currentMatched];
139-
$i = strlen($ret);
140-
}
122+
// Did we read an escape sequence?
123+
if ("\033" === $c) {
124+
$c .= fread($inputStream, 2);
125+
126+
if ('A' === $c[2] || 'B' === $c[2]) {
127+
if (0 === $i) {
128+
$matches = $autocomplete;
129+
$numMatches = count($matches);
130+
}
141131

142-
if ("\n" === $c) {
143-
$output->write($c);
144-
break;
132+
if (0 === $numMatches) {
133+
continue;
134+
}
135+
136+
$ofs += ('A' === $c[2]) ? -1 : 1;
137+
$ofs = ($numMatches + $ofs) % $numMatches;
145138
}
139+
} else if (ord($c) < 32) {
140+
if ("\t" === $c || "\n" === $c) {
141+
if ($numMatches > 0) {
142+
$ret = $matches[$ofs];
143+
// Echo out completed match
144+
$output->write(substr($ret, $i));
145+
$i = strlen($ret);
146+
}
146147

147-
$currentMatched = false;
148+
if ("\n" === $c) {
149+
$output->write($c);
150+
break;
151+
}
148152

149-
continue;
150-
}
153+
$matches = array();
154+
$numMatches = 0;
155+
}
151156

152-
if (ord($c) < 32) {
153157
continue;
154-
}
155-
156-
$output->write($c);
157-
$ret .= $c;
158-
$i++;
158+
} else {
159+
$output->write($c);
160+
$ret .= $c;
161+
$i++;
159162

160-
// Erase characters from cursor to end of line
161-
$output->write("\033[K");
163+
$matches = array();
164+
$numMatches = 0;
165+
$ofs = 0;
162166

163-
foreach ($autocomplete as $j => $value) {
164-
// Get a substring of the current autocomplete item based on number of chars typed (e.g. AcmeDemoBundle = Acme)
165-
$matchTest = substr($value, 0, $i);
167+
foreach ($autocomplete as $value) {
168+
// Get a substring of the current autocomplete item based on number of chars typed (e.g. AcmeDemoBundle = Acme)
169+
$matchTest = substr($value, 0, $i);
166170

167-
if ($ret === $matchTest) {
168-
if ($i === strlen($value)) {
169-
$currentMatched = false;
170-
break;
171+
if ($ret === $matchTest && $i !== strlen($value)) {
172+
$matches[$numMatches++] = $value;
171173
}
172-
173-
// Save cursor position
174-
$output->write("\0337");
175-
176-
$output->write('<hl>' . substr($value, $i) . '</hl>');
177-
178-
// Restore cursor position
179-
$output->write("\0338");
180-
181-
$currentMatched = $j;
182-
break;
183174
}
175+
}
176+
177+
// Erase characters from cursor to end of line
178+
$output->write("\033[K");
184179

185-
$currentMatched = false;
180+
if ($numMatches > 0) {
181+
// Save cursor position
182+
$output->write("\0337");
183+
// Write highlighted text
184+
$output->write('<hl>' . substr($matches[$ofs], $i) . '</hl>');
185+
// Restore cursor position
186+
$output->write("\0338");
186187
}
187188
}
188189

0 commit comments

Comments
 (0)