diff --git a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php --- a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php +++ b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php @@ -214,8 +214,9 @@ ->setBarColor($color) ->addByline(pht('Creator: %s', $creator_handle->renderLink())) ->addAttribute(pht('From %s to %s', $from, $to)) - ->addAttribute( - phutil_utf8_shorten($event->getDescription(), 64)); + ->addAttribute(id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(64) + ->truncateString($event->getDescription())); $list->addItem($item); } diff --git a/src/applications/chatlog/controller/PhabricatorChatLogChannelLogController.php b/src/applications/chatlog/controller/PhabricatorChatLogChannelLogController.php --- a/src/applications/chatlog/controller/PhabricatorChatLogChannelLogController.php +++ b/src/applications/chatlog/controller/PhabricatorChatLogChannelLogController.php @@ -108,7 +108,9 @@ $out = array(); foreach ($blocks as $block) { $author = $block['author']; - $author = phutil_utf8_shorten($author, 18); + $author = id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(18) + ->truncateString($author); $author = phutil_tag('td', array('class' => 'author'), $author); $href = $uri->alter('at', $block['id']); diff --git a/src/applications/conduit/method/ConduitConnectConduitAPIMethod.php b/src/applications/conduit/method/ConduitConnectConduitAPIMethod.php --- a/src/applications/conduit/method/ConduitConnectConduitAPIMethod.php +++ b/src/applications/conduit/method/ConduitConnectConduitAPIMethod.php @@ -59,9 +59,9 @@ $client = $request->getValue('client'); $client_version = (int)$request->getValue('clientVersion'); $client_description = (string)$request->getValue('clientDescription'); - // TODO: This should be character-oriented, not display-oriented. - // See T3307. - $client_description = phutil_utf8_shorten($client_description, 255); + $client_description = id(new PhutilUTF8StringTruncator()) + ->setMaximumCodepoints(255) + ->truncateString($client_description); $username = (string)$request->getValue('user'); // Log the connection, regardless of the outcome of checks below. diff --git a/src/applications/conpherence/view/ConpherenceFileWidgetView.php b/src/applications/conpherence/view/ConpherenceFileWidgetView.php --- a/src/applications/conpherence/view/ConpherenceFileWidgetView.php +++ b/src/applications/conpherence/view/ConpherenceFileWidgetView.php @@ -20,7 +20,9 @@ ''); $file_view = id(new PhabricatorFileLinkView()) ->setFilePHID($file->getPHID()) - ->setFileName(phutil_utf8_shorten($file->getName(), 28)) + ->setFileName(id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(28) + ->truncateString($file->getName())) ->setFileViewable($file->isViewableImage()) ->setFileViewURI($file->getBestURI()) ->setCustomClass('file-title'); diff --git a/src/applications/differential/controller/DifferentialDiffViewController.php b/src/applications/differential/controller/DifferentialDiffViewController.php --- a/src/applications/differential/controller/DifferentialDiffViewController.php +++ b/src/applications/differential/controller/DifferentialDiffViewController.php @@ -62,8 +62,10 @@ array( 'value' => $revision->getID(), ), - phutil_utf8_shorten( - 'D'.$revision->getID().' '.$revision->getTitle(), 128)); + id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(128) + ->truncateString( + 'D'.$revision->getID().' '.$revision->getTitle())); } $select[] = hsprintf(''); } diff --git a/src/applications/differential/event/DifferentialHovercardEventListener.php b/src/applications/differential/event/DifferentialHovercardEventListener.php --- a/src/applications/differential/event/DifferentialHovercardEventListener.php +++ b/src/applications/differential/event/DifferentialHovercardEventListener.php @@ -69,7 +69,9 @@ if ($rev->getSummary()) { $hovercard->addField(pht('Summary'), - phutil_utf8_shorten($rev->getSummary(), 120)); + id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(120) + ->truncateString($rev->getSummary())); } $hovercard->addTag( diff --git a/src/applications/differential/parser/DifferentialCommitMessageParser.php b/src/applications/differential/parser/DifferentialCommitMessageParser.php --- a/src/applications/differential/parser/DifferentialCommitMessageParser.php +++ b/src/applications/differential/parser/DifferentialCommitMessageParser.php @@ -141,7 +141,11 @@ if (isset($fields[$key_title])) { $terminal = '...'; $title = $fields[$key_title]; - $short = phutil_utf8_shorten($title, 250, $terminal); + $short = id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(250) + ->setTerminator($terminal) + ->truncateString($title); + if ($short != $title) { // If we shortened the title, split the rest into the summary, so diff --git a/src/applications/differential/view/DifferentialLocalCommitsView.php b/src/applications/differential/view/DifferentialLocalCommitsView.php --- a/src/applications/differential/view/DifferentialLocalCommitsView.php +++ b/src/applications/differential/view/DifferentialLocalCommitsView.php @@ -77,7 +77,9 @@ $message = idx($commit, 'message'); $summary = idx($commit, 'summary'); - $summary = phutil_utf8_shorten($summary, 80); + $summary = id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(80) + ->truncateString($summary); $view = new AphrontMoreView(); $view->setSome($summary); diff --git a/src/applications/diffusion/controller/DiffusionBrowseFileController.php b/src/applications/diffusion/controller/DiffusionBrowseFileController.php --- a/src/applications/diffusion/controller/DiffusionBrowseFileController.php +++ b/src/applications/diffusion/controller/DiffusionBrowseFileController.php @@ -684,7 +684,10 @@ 'size' => 600, ), ), - phutil_utf8_shorten($line['commit'], 9, '')); + id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(9) + ->setTerminator('') + ->truncateString($line['commit'])); $revision_id = null; if (idx($commits, $commit)) { diff --git a/src/applications/feed/story/PhabricatorFeedStory.php b/src/applications/feed/story/PhabricatorFeedStory.php --- a/src/applications/feed/story/PhabricatorFeedStory.php +++ b/src/applications/feed/story/PhabricatorFeedStory.php @@ -378,7 +378,9 @@ final protected function renderSummary($text, $len = 128) { if ($len) { - $text = phutil_utf8_shorten($text, $len); + $text = id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs($len) + ->truncateString($text); } switch ($this->getRenderingTarget()) { case PhabricatorApplicationTransaction::TARGET_HTML: diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuild.php b/src/applications/harbormaster/storage/build/HarbormasterBuild.php --- a/src/applications/harbormaster/storage/build/HarbormasterBuild.php +++ b/src/applications/harbormaster/storage/build/HarbormasterBuild.php @@ -196,7 +196,9 @@ $log_source, $log_type) { - $log_source = phutil_utf8_shorten($log_source, 250); + $log_source = id(new PhutilUTF8StringTruncator()) + ->setMaximumCodepoints(250) + ->truncateString($log_source); $log = HarbormasterBuildLog::initializeNewBuildLog($build_target) ->setLogSource($log_source) diff --git a/src/applications/herald/storage/transcript/HeraldObjectTranscript.php b/src/applications/herald/storage/transcript/HeraldObjectTranscript.php --- a/src/applications/herald/storage/transcript/HeraldObjectTranscript.php +++ b/src/applications/herald/storage/transcript/HeraldObjectTranscript.php @@ -52,7 +52,7 @@ if (strlen($value) <= $length) { return $value; } else { - // NOTE: phutil_utf8_shorten() has huge runtime for giant strings. + // NOTE: huge runtime for giant strings. return phutil_utf8ize(substr($value, 0, $length)."\n<...>"); } } else if (is_array($value)) { diff --git a/src/applications/maniphest/export/ManiphestExcelDefaultFormat.php b/src/applications/maniphest/export/ManiphestExcelDefaultFormat.php --- a/src/applications/maniphest/export/ManiphestExcelDefaultFormat.php +++ b/src/applications/maniphest/export/ManiphestExcelDefaultFormat.php @@ -104,7 +104,9 @@ $task->getTitle(), $projects, PhabricatorEnv::getProductionURI('/T'.$task->getID()), - phutil_utf8_shorten($task->getDescription(), 512), + id(new PhutilUTF8StringTruncator()) + ->setMaximumBytes(512) + ->truncateString($task->getDescription()), ); } diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php --- a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php +++ b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php @@ -563,7 +563,9 @@ $body = idx($params, 'body', ''); $max = PhabricatorEnv::getEnvConfig('metamta.email-body-limit'); if (strlen($body) > $max) { - $body = phutil_utf8_shorten($body, $max); + $body = id(new PhutilUTF8StringTruncator()) + ->setMaximumBytes($max) + ->truncateString($body); $body .= "\n"; $body .= pht('(This email was truncated at %d bytes.)', $max); } diff --git a/src/applications/people/event/PhabricatorPeopleHovercardEventListener.php b/src/applications/people/event/PhabricatorPeopleHovercardEventListener.php --- a/src/applications/people/event/PhabricatorPeopleHovercardEventListener.php +++ b/src/applications/people/event/PhabricatorPeopleHovercardEventListener.php @@ -59,7 +59,9 @@ if ($profile->getBlurb()) { $hovercard->addField(pht('Blurb'), - phutil_utf8_shorten($profile->getBlurb(), 120)); + id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(120) + ->truncateString($profile->getBlurb())); } $event->setValue('hovercard', $hovercard); diff --git a/src/applications/phame/conduit/PhameCreatePostConduitAPIMethod.php b/src/applications/phame/conduit/PhameCreatePostConduitAPIMethod.php --- a/src/applications/phame/conduit/PhameCreatePostConduitAPIMethod.php +++ b/src/applications/phame/conduit/PhameCreatePostConduitAPIMethod.php @@ -90,7 +90,9 @@ $post->setTitle($title); $phame_title = $request->getValue( 'phameTitle', - phutil_utf8_shorten($title, 64)); + id(new PhutilUTF8StringTruncator()) + ->setMaximumCodepoints(64) + ->truncateString($title)); $post->setPhameTitle(PhabricatorSlug::normalize($phame_title)); $post->setBody($body); $post->save(); diff --git a/src/applications/pholio/storage/PholioTransaction.php b/src/applications/pholio/storage/PholioTransaction.php --- a/src/applications/pholio/storage/PholioTransaction.php +++ b/src/applications/pholio/storage/PholioTransaction.php @@ -297,7 +297,9 @@ if ($text) { return phutil_escape_html_newlines( - phutil_utf8_shorten($text, 128)); + id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(128) + ->truncateString($text)); } return parent::getBodyForFeed($story); diff --git a/src/applications/phriction/editor/PhrictionDocumentEditor.php b/src/applications/phriction/editor/PhrictionDocumentEditor.php --- a/src/applications/phriction/editor/PhrictionDocumentEditor.php +++ b/src/applications/phriction/editor/PhrictionDocumentEditor.php @@ -264,6 +264,9 @@ } if ($feed_action) { + $content = id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(140) + ->truncateString($new_content->getContent()); id(new PhabricatorFeedStoryPublisher()) ->setRelatedPHIDs($related_phids) ->setStoryAuthorPHID($this->getActor()->getPHID()) @@ -273,7 +276,7 @@ array( 'phid' => $document->getPHID(), 'action' => $feed_action, - 'content' => phutil_utf8_shorten($new_content->getContent(), 140), + 'content' => $content, 'project' => $project_phid, 'movedFromPHID' => $this->fromDocumentPHID, )) diff --git a/src/applications/ponder/storage/PonderAnswerTransaction.php b/src/applications/ponder/storage/PonderAnswerTransaction.php --- a/src/applications/ponder/storage/PonderAnswerTransaction.php +++ b/src/applications/ponder/storage/PonderAnswerTransaction.php @@ -71,7 +71,9 @@ switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return phutil_escape_html_newlines( - phutil_utf8_shorten($new, 128)); + id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(128) + ->truncateString($new)); break; } return parent::getBodyForFeed($story); diff --git a/src/applications/ponder/storage/PonderQuestionTransaction.php b/src/applications/ponder/storage/PonderQuestionTransaction.php --- a/src/applications/ponder/storage/PonderQuestionTransaction.php +++ b/src/applications/ponder/storage/PonderQuestionTransaction.php @@ -252,14 +252,18 @@ if ($old === null) { $question = $story->getObject($this->getObjectPHID()); return phutil_escape_html_newlines( - phutil_utf8_shorten($question->getContent(), 128)); + id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(128) + ->truncateString($question->getContent())); } break; case self::TYPE_ANSWERS: $answer = $this->getNewAnswerObject($story); if ($answer) { return phutil_escape_html_newlines( - phutil_utf8_shorten($answer->getContent(), 128)); + id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(128) + ->truncateString($answer->getContent())); } break; } diff --git a/src/applications/repository/storage/PhabricatorRepositoryCommitData.php b/src/applications/repository/storage/PhabricatorRepositoryCommitData.php --- a/src/applications/repository/storage/PhabricatorRepositoryCommitData.php +++ b/src/applications/repository/storage/PhabricatorRepositoryCommitData.php @@ -30,7 +30,9 @@ public static function summarizeCommitMessage($message) { $summary = phutil_split_lines($message, $retain_endings = false); $summary = head($summary); - $summary = phutil_utf8_shorten($summary, self::SUMMARY_MAX_LENGTH); + $summary = id(new PhutilUTF8StringTruncator()) + ->setMaximumCodepoints(self::SUMMARY_MAX_LENGTH) + ->truncateString($summary); return $summary; } diff --git a/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php b/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php --- a/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php +++ b/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php @@ -155,7 +155,9 @@ $description = $poll->getDescription(); if (strlen($description)) { - $item->addAttribute(phutil_utf8_shorten($poll->getDescription(), 120)); + $item->addAttribute(id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(120) + ->truncateString($poll->getDescription())); } if ($author) { diff --git a/src/view/form/control/AphrontFormPolicyControl.php b/src/view/form/control/AphrontFormPolicyControl.php --- a/src/view/form/control/AphrontFormPolicyControl.php +++ b/src/view/form/control/AphrontFormPolicyControl.php @@ -58,9 +58,12 @@ continue; } } + $policy_short_name = id(new PhutilUTF8StringTruncator()) + ->setMaximumGlyphs(28) + ->truncateString($policy->getName()); $options[$policy->getType()][$policy->getPHID()] = array( - 'name' => phutil_utf8_shorten($policy->getName(), 28), + 'name' => $policy_short_name, 'full' => $policy->getName(), 'icon' => $policy->getIcon(), );