Skip to content

Commit fd9ba4f

Browse files
committed
fix: pass prompt text to readline in CLI::prompt() so backspace does not erase it
1 parent a826e69 commit fd9ba4f

4 files changed

Lines changed: 68 additions & 5 deletions

File tree

system/CLI/CLI.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -254,12 +254,12 @@ public static function prompt(string $field, $options = null, $validation = null
254254
$default = $options[0];
255255
}
256256

257-
static::fwrite(STDOUT, $field . (trim($field) !== '' ? ' ' : '') . $extraOutput . ': ');
258257
static::$lastWrite = 'write';
259258

260-
// Read the input from keyboard.
261-
$input = trim(static::$io->input());
262-
$input = ($input === '') ? (string) $default : $input;
259+
// The reader renders the prompt itself, so readline redraws repaint it instead of erasing it.
260+
$prompt = sprintf('%s%s%s: ', $field, trim($field) !== '' ? ' ' : '', $extraOutput);
261+
$input = trim(static::$io->input($prompt));
262+
$input = $input === '' ? (string) $default : $input;
263263

264264
if ($validation !== []) {
265265
while (! static::validate('"' . trim($field) . '"', $input, $validation)) {

system/CLI/InputOutput.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public function input(?string $prefix = null): string
4646
return readline($prefix); // @codeCoverageIgnore
4747
}
4848

49-
echo $prefix;
49+
$this->fwrite(STDOUT, $prefix ?? '');
5050

5151
$input = fgets(fopen('php://stdin', 'rb'));
5252

tests/system/CLI/CLITest.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use CodeIgniter\Exceptions\RuntimeException;
1818
use CodeIgniter\Superglobals;
1919
use CodeIgniter\Test\CIUnitTestCase;
20+
use CodeIgniter\Test\Mock\MockInputOutput;
2021
use CodeIgniter\Test\PhpStreamWrapper;
2122
use CodeIgniter\Test\StreamFilterTrait;
2223
use PHPUnit\Framework\Attributes\DataProvider;
@@ -143,6 +144,67 @@ public function testPromptInputZero(): void
143144
$this->assertSame('0', $output);
144145
}
145146

147+
public function testPromptPassesPromptTextToInputReader(): void
148+
{
149+
$io = new class () extends InputOutput {
150+
public ?string $receivedPrefix = null;
151+
152+
public function input(?string $prefix = null): string
153+
{
154+
$this->receivedPrefix = $prefix;
155+
156+
return 'red';
157+
}
158+
};
159+
CLI::setInputOutput($io);
160+
161+
$output = CLI::prompt('What is your favorite color?');
162+
163+
CLI::resetInputOutput();
164+
165+
$this->assertSame('red', $output);
166+
$this->assertSame('What is your favorite color? : ', $io->receivedPrefix);
167+
}
168+
169+
public function testPromptPassesDefaultOptionInPromptText(): void
170+
{
171+
$io = new class () extends InputOutput {
172+
public ?string $receivedPrefix = null;
173+
174+
public function input(?string $prefix = null): string
175+
{
176+
$this->receivedPrefix = $prefix;
177+
178+
return '';
179+
}
180+
};
181+
CLI::setInputOutput($io);
182+
183+
$output = CLI::prompt('What is your favorite color?', 'red');
184+
185+
CLI::resetInputOutput();
186+
187+
$this->assertSame('red', $output);
188+
$this->assertSame(
189+
sprintf('What is your favorite color? [%s]: ', CLI::color('red', 'green')),
190+
$io->receivedPrefix,
191+
);
192+
}
193+
194+
public function testInputWritesPrefixToStdout(): void
195+
{
196+
$io = new MockInputOutput();
197+
$io->setInputs(['blue']);
198+
CLI::setInputOutput($io);
199+
200+
$output = CLI::input('Name: ');
201+
202+
CLI::resetInputOutput();
203+
204+
$this->assertSame('blue', $output);
205+
$this->assertSame('Name: blue' . PHP_EOL, $io->getOutput());
206+
}
207+
146208
public function testPromptByKey(): void
147209
{
148210
PhpStreamWrapper::register();

user_guide_src/source/changelogs/v4.7.5.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Deprecations
3434
Bugs Fixed
3535
**********
3636

37+
- **CLI:** Fixed a bug where pressing backspace in a ``CLI::prompt()`` erased the prompt text when the ``readline`` extension is enabled. The prompt is now passed to ``readline()`` so line redraws repaint it.
3738
- **CLIRequest:** Fixed a bug where ``parseCommand()`` could throw a TypeError when ``argv`` is missing.
3839
- **Content Security Policy:** Fixed a bug where empty ``Content-Security-Policy``, ``Content-Security-Policy-Report-Only``, and ``Reporting-Endpoints`` response headers were generated when no corresponding values existed.
3940
- **Helpers:** Fixed a bug where ``get_dir_file_info()`` returned incomplete entries for subdirectories and missing files instead of omitting them.

0 commit comments

Comments
 (0)