Skip to content

Commit 2534bad

Browse files
authored
Merge pull request #42 from clue-labs/no-mbstring
Suggest using ext-mbstring, otherwise use regex fallback
2 parents 9447177 + 994b456 commit 2534bad

File tree

3 files changed

+46
-8
lines changed

3 files changed

+46
-8
lines changed

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
"clue/utf8-react": "^0.1",
1818
"clue/term-react": "^0.1.1"
1919
},
20+
"suggest": {
21+
"ext-mbstring": "Using ext-mbstring should provide slightly better performance for handling I/O"
22+
},
2023
"autoload": {
2124
"psr-4": { "Clue\\React\\Stdio\\": "src/" }
2225
}

src/Readline.php

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -747,22 +747,57 @@ protected function processLine()
747747
$this->emit('data', array($line));
748748
}
749749

750-
protected function strlen($str)
750+
private function strlen($str)
751751
{
752-
return mb_strlen($str, $this->encoding);
752+
// prefer mb_strlen() if available
753+
if (function_exists('mb_strlen')) {
754+
return mb_strlen($str, $this->encoding);
755+
}
756+
757+
// otherwise replace all unicode chars with dots and count dots
758+
return strlen(preg_replace('/./us', '.', $str));
753759
}
754760

755-
protected function substr($str, $start = 0, $len = null)
761+
private function substr($str, $start = 0, $len = null)
756762
{
757763
if ($len === null) {
758764
$len = $this->strlen($str) - $start;
759765
}
760-
return (string)mb_substr($str, $start, $len, $this->encoding);
766+
767+
// prefer mb_substr() if available
768+
if (function_exists('mb_substr')) {
769+
return (string)mb_substr($str, $start, $len, $this->encoding);
770+
}
771+
772+
// otherwise build array with all unicode chars and slice array
773+
preg_match_all('/./us', $str, $matches);
774+
775+
return implode('', array_slice($matches[0], $start, $len));
761776
}
762777

763-
private function strwidth($str)
764-
{
765-
return mb_strwidth($str, $this->encoding);
778+
/** @internal */
779+
public function strwidth($str)
780+
{
781+
// prefer mb_strwidth() if available
782+
if (function_exists('mb_strwidth')) {
783+
return mb_strwidth($str, $this->encoding);
784+
}
785+
786+
// otherwise replace each double-width unicode graphemes with two dots, all others with single dot and count number of dots
787+
// mbstring's list of double-width graphemes is *very* long: https://3v4l.org/GEg3u
788+
// let's use symfony's list from https://github.com/symfony/polyfill-mbstring/blob/e79d363049d1c2128f133a2667e4f4190904f7f4/Mbstring.php#L523
789+
// which looks like they originally came from http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
790+
return strlen(preg_replace(
791+
array(
792+
'/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u',
793+
'/./us',
794+
),
795+
array(
796+
'..',
797+
'.',
798+
),
799+
$str
800+
));
766801
}
767802

768803
/** @internal */

src/Stdio.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ public function getReadline()
228228

229229
private function width($str)
230230
{
231-
return mb_strwidth($str, 'utf-8') - 2 * substr_count($str, "\x08");
231+
return $this->readline->strwidth($str) - 2 * substr_count($str, "\x08");
232232
}
233233

234234
/** @internal */

0 commit comments

Comments
 (0)