diff --git a/src/TextareaPrompt.php b/src/TextareaPrompt.php index 19a94e6b..859469a4 100644 --- a/src/TextareaPrompt.php +++ b/src/TextareaPrompt.php @@ -113,7 +113,7 @@ protected function handleUpKey(): void $lines = collect($this->lines()); // Line length + 1 for the newline character - $lineLengths = $lines->map(fn ($line, $index) => mb_strwidth($line) + ($index === $lines->count() - 1 ? 0 : 1)); + $lineLengths = $lines->map(fn ($line, $index) => mb_strlen($line) + ($index === $lines->count() - 1 ? 0 : 1)); $currentLineIndex = $this->currentLineIndex(); @@ -145,13 +145,13 @@ protected function handleDownKey(): void $lines = collect($this->lines()); // Line length + 1 for the newline character - $lineLengths = $lines->map(fn ($line, $index) => mb_strwidth($line) + ($index === $lines->count() - 1 ? 0 : 1)); + $lineLengths = $lines->map(fn ($line, $index) => mb_strlen($line) + ($index === $lines->count() - 1 ? 0 : 1)); $currentLineIndex = $this->currentLineIndex(); if ($currentLineIndex === $lines->count() - 1) { // They're already at the last line, jump them to the last position - $this->cursorPosition = mb_strwidth($lines->implode(PHP_EOL)); + $this->cursorPosition = mb_strlen($lines->implode(PHP_EOL)); return; } @@ -205,7 +205,7 @@ protected function currentLineIndex(): int $totalLineLength = 0; return (int) collect($this->lines())->search(function ($line) use (&$totalLineLength) { - $totalLineLength += mb_strwidth($line) + 1; + $totalLineLength += mb_strlen($line) + 1; return $totalLineLength > $this->cursorPosition; }) ?: 0; diff --git a/tests/Feature/TextareaPromptTest.php b/tests/Feature/TextareaPromptTest.php index 42d87ba5..07209195 100644 --- a/tests/Feature/TextareaPromptTest.php +++ b/tests/Feature/TextareaPromptTest.php @@ -198,3 +198,50 @@ expect($result)->toBe("abc\ndeg\nf"); }); + +it('correctly handles multi-byte strings for the down arrow', function () { + Prompt::fake([ + 'a', 'b', Key::ENTER, + 'c', 'd', 'e', 'f', Key::ENTER, + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'n', 'o', 'p', 'q', 'r', 's', Key::ENTER, + 't', 'u', 'v', 'w', 'x', 'y', 'z', + Key::UP, + Key::UP, + Key::UP, + Key::UP, + Key::RIGHT, + Key::DOWN, + 'y', 'o', + Key::CTRL_D, + ]); + + $result = textarea(label: 'What is your name?'); + + expect($result)->toBe( + "ab\ncyodef\nghijklmnnopqrs\ntuvwxyz" + ); +}); + +it('correctly handles multi-byte strings for the up arrow', function () { + Prompt::fake([ + 'a', 'b', Key::ENTER, + 'c', 'd', 'e', 'f', Key::ENTER, + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'n', 'o', 'p', 'q', 'r', 's', Key::ENTER, + 't', 'u', 'v', 'w', 'x', 'y', 'z', + Key::UP, + Key::UP, + Key::UP, + Key::UP, + Key::RIGHT, + Key::DOWN, + Key::UP, + 'y', 'o', + Key::CTRL_D, + ]); + + $result = textarea(label: 'What is your name?'); + + expect($result)->toBe( + "ayob\ncdef\nghijklmnnopqrs\ntuvwxyz" + ); +});