diff --git a/CHANGELOG.md b/CHANGELOG.md index 12ff55d..d9d7a41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,11 @@ Changes since [v1.6.0](https://github.com/gitonomy/gitlib/releases/tag/v1.6.0). ### Minor +- Replace `Gitonomy\Git\Util\StringHelper` with `symfony/string`'s `CodePointString`, which + covers the same UTF-8-aware `strlen`/`substr`/`strpos`/`strrpos` operations. + **Breaking:** `StringHelper` is removed, along with its configurable encoding + (`getEncoding()`/`setEncoding()`); the library now consistently targets `UTF-8`. + ([#252](https://github.com/gitonomy/gitlib/pull/252)) - Modernize for PHP 8.4+, Symfony 6.4/7.4/8.1+ and PHPUnit 12: full property/parameter/return type coverage, `readonly`/`final` where applicable, PHPUnit 12 attributes, and new php-cs-fixer/PHPStan/Castor tooling. diff --git a/composer.json b/composer.json index 7104d44..53b6196 100644 --- a/composer.json +++ b/composer.json @@ -37,8 +37,8 @@ "require": { "php": "^8.4", "ext-pcre": "*", - "symfony/polyfill-mbstring": "^1.7", - "symfony/process": "^6.4 || ^7.4 || ^8.1" + "symfony/process": "^6.4 || ^7.4 || ^8.1", + "symfony/string": "^7.4.6 || ^8.0.6" }, "require-dev": { "ext-fileinfo": "*", diff --git a/src/Gitonomy/Git/Commit.php b/src/Gitonomy/Git/Commit.php index 2e0215f..a82c573 100644 --- a/src/Gitonomy/Git/Commit.php +++ b/src/Gitonomy/Git/Commit.php @@ -17,7 +17,7 @@ use Gitonomy\Git\Exception\ProcessException; use Gitonomy\Git\Exception\ReferenceNotFoundException; use Gitonomy\Git\Reference\Branch; -use Gitonomy\Git\Util\StringHelper; +use Symfony\Component\String\CodePointString; /** * Representation of a Git commit. @@ -139,7 +139,7 @@ public function getShortHash(): string */ public function getFixedShortHash(int $length = 6): string { - return StringHelper::substr($this->revision, 0, $length); + return new CodePointString($this->revision)->slice(0, $length)->toString(); } /** @@ -191,7 +191,7 @@ public function getTree(): Tree public function getLastModification(?string $path = null): self { if (null !== $path && str_starts_with($path, '/')) { - $path = StringHelper::substr($path, 1); + $path = new CodePointString($path)->slice(1)->toString(); } if ($getWorkingDir = $this->repository->getWorkingDir()) { @@ -216,12 +216,14 @@ public function getShortMessage(int $length = 50, bool $preserve = false, string { $message = $this->getSubjectMessage(); - if (StringHelper::strlen($message) > $length) { - if ($preserve && false !== ($breakpoint = StringHelper::strpos($message, ' ', $length))) { + $codePointMessage = new CodePointString($message); + + if ($codePointMessage->length() > $length) { + if ($preserve && null !== ($breakpoint = $codePointMessage->indexOf(' ', $length))) { $length = $breakpoint; } - return rtrim(StringHelper::substr($message, 0, $length)).$separator; + return rtrim($codePointMessage->slice(0, $length)->toString()).$separator; } return $message; @@ -269,7 +271,7 @@ public function getIncludingBranches(bool $local = true, bool $remote = true): a $branchesName = explode("\n", trim(str_replace('*', '', $result))); $branchesName = array_filter($branchesName, static function ($v) { - return false === StringHelper::strpos($v, '->'); + return null === new CodePointString($v)->indexOf('->'); }); $branchesName = array_map('trim', $branchesName); @@ -279,7 +281,7 @@ public function getIncludingBranches(bool $local = true, bool $remote = true): a foreach ($branchesName as $branchName) { if (false === $local) { $branches[] = $references->getRemoteBranch($branchName); - } elseif (0 === StringHelper::strrpos($branchName, 'remotes/')) { + } elseif (0 === new CodePointString($branchName)->indexOfLast('remotes/')) { $branches[] = $references->getRemoteBranch(str_replace('remotes/', '', $branchName)); } else { $branches[] = $references->getBranch($branchName); diff --git a/src/Gitonomy/Git/Log.php b/src/Gitonomy/Git/Log.php index bc4c43d..7d5137f 100644 --- a/src/Gitonomy/Git/Log.php +++ b/src/Gitonomy/Git/Log.php @@ -15,7 +15,6 @@ use Gitonomy\Git\Diff\Diff; use Gitonomy\Git\Exception\ProcessException; use Gitonomy\Git\Exception\ReferenceNotFoundException; -use Gitonomy\Git\Util\StringHelper; /** * @author Alexandre Salomé @@ -120,7 +119,7 @@ public function getSingleCommit(): Commit */ public function getCommits(): array { - $args = ['--encoding='.StringHelper::getEncoding(), '--format=raw']; + $args = ['--encoding=UTF-8', '--format=raw']; if (null !== $this->offset) { $args[] = '--skip='.$this->offset; diff --git a/src/Gitonomy/Git/Reference/Branch.php b/src/Gitonomy/Git/Reference/Branch.php index f4edbf5..fdf4e43 100644 --- a/src/Gitonomy/Git/Reference/Branch.php +++ b/src/Gitonomy/Git/Reference/Branch.php @@ -15,7 +15,7 @@ use Gitonomy\Git\Exception\ProcessException; use Gitonomy\Git\Exception\RuntimeException; use Gitonomy\Git\Reference; -use Gitonomy\Git\Util\StringHelper; +use Symfony\Component\String\CodePointString; /** * Representation of a branch reference. @@ -82,7 +82,7 @@ public function isMergedTo(string $destinationBranchName = 'master', bool $compa $output = explode("\n", trim(str_replace(['*', 'remotes/'], '', $result))); $filtered_output = array_filter($output, static function ($v) { - return false === StringHelper::strpos($v, '->'); + return null === new CodePointString($v)->indexOf('->'); }); $trimmed_output = array_map('trim', $filtered_output); diff --git a/src/Gitonomy/Git/Util/StringHelper.php b/src/Gitonomy/Git/Util/StringHelper.php deleted file mode 100644 index 9b9db38..0000000 --- a/src/Gitonomy/Git/Util/StringHelper.php +++ /dev/null @@ -1,57 +0,0 @@ - - * (c) Julien DIDIER - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -namespace Gitonomy\Git\Util; - -/** - * Helper class to support language particularity. - * - * @author Alexandre Salomé - */ -final class StringHelper -{ - private static string $encoding = 'utf-8'; - - public static function getEncoding(): string - { - return self::$encoding; - } - - public static function setEncoding(string $encoding): void - { - self::$encoding = $encoding; - } - - public static function strlen(string $string): int - { - return \function_exists('mb_strlen') ? mb_strlen($string, self::$encoding) : \strlen($string); - } - - public static function substr(string $string, int $start, ?int $length = null): string - { - if (null === $length) { - $length = self::strlen($string); - } - - return \function_exists('mb_substr') ? mb_substr($string, $start, $length, self::$encoding) : substr($string, $start, $length); - } - - public static function strpos(string $haystack, string $needle, int $offset = 0): int|false - { - return \function_exists('mb_strpos') ? mb_strpos($haystack, $needle, $offset, self::$encoding) : strpos($haystack, $needle, $offset); - } - - public static function strrpos(string $haystack, string $needle, int $offset = 0): int|false - { - return \function_exists('mb_strrpos') ? mb_strrpos($haystack, $needle, $offset, self::$encoding) : strrpos($haystack, $needle, $offset); - } -}