From 70258c38548ecd8ab4a97e10d585202549bf75fc Mon Sep 17 00:00:00 2001 From: Joe Tannenbaum Date: Tue, 16 Apr 2024 21:23:08 -0400 Subject: [PATCH 1/3] fix for up and down arrows for multi byte strings --- src/TextareaPrompt.php | 11 ++++--- tests/Feature/TextareaPromptTest.php | 47 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/TextareaPrompt.php b/src/TextareaPrompt.php index 19a94e6b..4b2fabd7 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) => count(mb_str_split($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) => count(mb_str_split($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 = count(mb_str_split($lines->implode(PHP_EOL))); return; } @@ -163,6 +163,7 @@ protected function handleDownKey(): void $destinationLineLength = $lineLengths->get($currentLineIndex + 1) ?? $currentLines->last(); + if ($currentLineIndex + 1 !== $lines->count() - 1) { $destinationLineLength--; } @@ -205,7 +206,7 @@ protected function currentLineIndex(): int $totalLineLength = 0; return (int) collect($this->lines())->search(function ($line) use (&$totalLineLength) { - $totalLineLength += mb_strwidth($line) + 1; + $totalLineLength += count(mb_str_split($line)) + 1; return $totalLineLength > $this->cursorPosition; }) ?: 0; @@ -218,7 +219,7 @@ protected function cursorOffset(): int { $cursorOffset = 0; - preg_match_all('/\S{'.$this->width.',}/u', $this->value(), $matches, PREG_OFFSET_CAPTURE); + preg_match_all('/\S{' . $this->width . ',}/u', $this->value(), $matches, PREG_OFFSET_CAPTURE); foreach ($matches[0] as $match) { if ($this->cursorPosition + $cursorOffset >= $match[1] + mb_strwidth($match[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" + ); +}); From 54e28a290f1812d6b73a7e86d7deb2c3f4ea9c52 Mon Sep 17 00:00:00 2001 From: joetannenbaum Date: Wed, 17 Apr 2024 01:23:39 +0000 Subject: [PATCH 2/3] Fix code styling --- src/TextareaPrompt.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/TextareaPrompt.php b/src/TextareaPrompt.php index 4b2fabd7..ae7864ba 100644 --- a/src/TextareaPrompt.php +++ b/src/TextareaPrompt.php @@ -163,7 +163,6 @@ protected function handleDownKey(): void $destinationLineLength = $lineLengths->get($currentLineIndex + 1) ?? $currentLines->last(); - if ($currentLineIndex + 1 !== $lines->count() - 1) { $destinationLineLength--; } @@ -219,7 +218,7 @@ protected function cursorOffset(): int { $cursorOffset = 0; - preg_match_all('/\S{' . $this->width . ',}/u', $this->value(), $matches, PREG_OFFSET_CAPTURE); + preg_match_all('/\S{'.$this->width.',}/u', $this->value(), $matches, PREG_OFFSET_CAPTURE); foreach ($matches[0] as $match) { if ($this->cursorPosition + $cursorOffset >= $match[1] + mb_strwidth($match[0])) { From a6e96470b0808dde1cbbf3e1bf35929f18d21838 Mon Sep 17 00:00:00 2001 From: Joe Tannenbaum Date: Wed, 17 Apr 2024 09:28:16 -0400 Subject: [PATCH 3/3] mb_strlen instead of whatever i was doing before --- src/TextareaPrompt.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/TextareaPrompt.php b/src/TextareaPrompt.php index 4b2fabd7..e066e15c 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) => count(mb_str_split($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) => count(mb_str_split($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 = count(mb_str_split($lines->implode(PHP_EOL))); + $this->cursorPosition = mb_strlen($lines->implode(PHP_EOL)); return; } @@ -206,7 +206,7 @@ protected function currentLineIndex(): int $totalLineLength = 0; return (int) collect($this->lines())->search(function ($line) use (&$totalLineLength) { - $totalLineLength += count(mb_str_split($line)) + 1; + $totalLineLength += mb_strlen($line) + 1; return $totalLineLength > $this->cursorPosition; }) ?: 0;