@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Truncate long source lines in Paste search result list snippets

Summary:
An attempt to resolve T9600.

- `PhabricatorPasteQuery` builds truncated snippet when requested using `needSnippet()`.
- `PhabricatorPasteSearchEngine` uses Paste snippet istead of content.
- `PhabricatorSourceCodeView` accepts truncated source and type instead of line limit.

Test Plan: Generated some content for Paste application and also added huge JSON oneliner. Checked Paste application pages in browser.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: Korvin

Maniphest Tasks: T9600

Differential Revision: https://secure.phabricator.com/D14313

+202 -42
+2
src/__phutil_library_map__.php
··· 2552 2552 'PhabricatorPasteRemarkupRule' => 'applications/paste/remarkup/PhabricatorPasteRemarkupRule.php', 2553 2553 'PhabricatorPasteSchemaSpec' => 'applications/paste/storage/PhabricatorPasteSchemaSpec.php', 2554 2554 'PhabricatorPasteSearchEngine' => 'applications/paste/query/PhabricatorPasteSearchEngine.php', 2555 + 'PhabricatorPasteSnippet' => 'applications/paste/snippet/PhabricatorPasteSnippet.php', 2555 2556 'PhabricatorPasteTestDataGenerator' => 'applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php', 2556 2557 'PhabricatorPasteTransaction' => 'applications/paste/storage/PhabricatorPasteTransaction.php', 2557 2558 'PhabricatorPasteTransactionComment' => 'applications/paste/storage/PhabricatorPasteTransactionComment.php', ··· 6633 6634 'PhabricatorPasteRemarkupRule' => 'PhabricatorObjectRemarkupRule', 6634 6635 'PhabricatorPasteSchemaSpec' => 'PhabricatorConfigSchemaSpec', 6635 6636 'PhabricatorPasteSearchEngine' => 'PhabricatorApplicationSearchEngine', 6637 + 'PhabricatorPasteSnippet' => 'Phobject', 6636 6638 'PhabricatorPasteTestDataGenerator' => 'PhabricatorTestDataGenerator', 6637 6639 'PhabricatorPasteTransaction' => 'PhabricatorApplicationTransaction', 6638 6640 'PhabricatorPasteTransactionComment' => 'PhabricatorApplicationTransactionComment',
-2
src/applications/paste/controller/PhabricatorPasteController.php
··· 39 39 40 40 public function buildSourceCodeView( 41 41 PhabricatorPaste $paste, 42 - $max_lines = null, 43 42 $highlights = array()) { 44 43 45 44 $lines = phutil_split_lines($paste->getContent()); 46 45 47 46 return id(new PhabricatorSourceCodeView()) 48 - ->setLimit($max_lines) 49 47 ->setLines($lines) 50 48 ->setHighlights($highlights) 51 49 ->setURI(new PhutilURI($paste->getURI()));
+1 -4
src/applications/paste/controller/PhabricatorPasteViewController.php
··· 56 56 ->setHeader($header) 57 57 ->addPropertyList($properties); 58 58 59 - $source_code = $this->buildSourceCodeView( 60 - $paste, 61 - null, 62 - $this->highlightMap); 59 + $source_code = $this->buildSourceCodeView($paste, $this->highlightMap); 63 60 64 61 require_celerity_resource('paste-css'); 65 62 $source_code = phutil_tag(
+126 -10
src/applications/paste/query/PhabricatorPasteQuery.php
··· 10 10 11 11 private $needContent; 12 12 private $needRawContent; 13 + private $needSnippets; 13 14 private $languages; 14 15 private $includeNoLanguage; 15 16 private $dateCreatedAfter; ··· 44 45 45 46 public function needRawContent($need_raw_content) { 46 47 $this->needRawContent = $need_raw_content; 48 + return $this; 49 + } 50 + 51 + public function needSnippets($need_snippets) { 52 + $this->needSnippets = $need_snippets; 47 53 return $this; 48 54 } 49 55 ··· 91 97 $pastes = $this->loadContent($pastes); 92 98 } 93 99 100 + if ($this->needSnippets) { 101 + $pastes = $this->loadSnippets($pastes); 102 + } 103 + 94 104 return $pastes; 95 105 } 96 106 ··· 166 176 )); 167 177 } 168 178 179 + private function getSnippetCacheKey(PhabricatorPaste $paste) { 180 + return implode( 181 + ':', 182 + array( 183 + 'P'.$paste->getID(), 184 + $paste->getFilePHID(), 185 + $paste->getLanguage(), 186 + 'snippet', 187 + )); 188 + } 189 + 169 190 private function loadRawContent(array $pastes) { 170 191 $file_phids = mpull($pastes, 'getFilePHID'); 171 192 $files = id(new PhabricatorFileQuery()) ··· 250 271 return $pastes; 251 272 } 252 273 274 + private function loadSnippets(array $pastes) { 275 + $cache = new PhabricatorKeyValueDatabaseCache(); 276 + 277 + $cache = new PhutilKeyValueCacheProfiler($cache); 278 + $cache->setProfiler(PhutilServiceProfiler::getInstance()); 279 + 280 + $keys = array(); 281 + foreach ($pastes as $paste) { 282 + $keys[] = $this->getSnippetCacheKey($paste); 283 + } 284 + 285 + $caches = $cache->getKeys($keys); 286 + 287 + $need_raw = array(); 288 + $have_cache = array(); 289 + foreach ($pastes as $paste) { 290 + $key = $this->getSnippetCacheKey($paste); 291 + if (isset($caches[$key])) { 292 + $snippet_data = phutil_json_decode($caches[$key], true); 293 + $snippet = new PhabricatorPasteSnippet( 294 + phutil_safe_html($snippet_data['content']), 295 + $snippet_data['type']); 296 + $paste->attachSnippet($snippet); 297 + $have_cache[$paste->getPHID()] = true; 298 + } else { 299 + $need_raw[$key] = $paste; 300 + } 301 + } 302 + 303 + if (!$need_raw) { 304 + return $pastes; 305 + } 306 + 307 + $write_data = array(); 308 + 309 + $have_raw = $this->loadRawContent($need_raw); 310 + $have_raw = mpull($have_raw, null, 'getPHID'); 311 + foreach ($pastes as $key => $paste) { 312 + $paste_phid = $paste->getPHID(); 313 + if (isset($have_cache[$paste_phid])) { 314 + continue; 315 + } 316 + 317 + if (empty($have_raw[$paste_phid])) { 318 + unset($pastes[$key]); 319 + continue; 320 + } 321 + 322 + $snippet = $this->buildSnippet($paste); 323 + $paste->attachSnippet($snippet); 324 + $snippet_data = array( 325 + 'content' => (string)$snippet->getContent(), 326 + 'type' => (string)$snippet->getType(), 327 + ); 328 + $write_data[$this->getSnippetCacheKey($paste)] = phutil_json_encode( 329 + $snippet_data); 330 + } 331 + 332 + if ($write_data) { 333 + $cache->setKeys($write_data); 334 + } 335 + 336 + return $pastes; 337 + } 338 + 253 339 private function buildContent(PhabricatorPaste $paste) { 254 - $language = $paste->getLanguage(); 255 - $source = $paste->getRawContent(); 340 + return $this->highlightSource( 341 + $paste->getRawContent(), 342 + $paste->getTitle(), 343 + $paste->getLanguage()); 344 + } 256 345 257 - if (empty($language)) { 258 - return PhabricatorSyntaxHighlighter::highlightWithFilename( 259 - $paste->getTitle(), 260 - $source); 261 - } else { 262 - return PhabricatorSyntaxHighlighter::highlightWithLanguage( 263 - $language, 264 - $source); 346 + private function buildSnippet(PhabricatorPaste $paste) { 347 + $snippet_type = PhabricatorPasteSnippet::FULL; 348 + $snippet = $paste->getRawContent(); 349 + 350 + if (strlen($snippet) > 1024) { 351 + $snippet_type = PhabricatorPasteSnippet::FIRST_BYTES; 352 + $snippet = id(new PhutilUTF8StringTruncator()) 353 + ->setMaximumBytes(1024) 354 + ->setTerminator('') 355 + ->truncateString($snippet); 265 356 } 357 + 358 + $lines = phutil_split_lines($snippet); 359 + if (count($lines) > 5) { 360 + $snippet_type = PhabricatorPasteSnippet::FIRST_LINES; 361 + $snippet = implode('', array_slice($lines, 0, 5)); 362 + } 363 + 364 + return new PhabricatorPasteSnippet( 365 + $this->highlightSource( 366 + $snippet, 367 + $paste->getTitle(), 368 + $paste->getLanguage()), 369 + $snippet_type); 370 + } 371 + 372 + private function highlightSource($source, $title, $language) { 373 + if (empty($language)) { 374 + return PhabricatorSyntaxHighlighter::highlightWithFilename( 375 + $title, 376 + $source); 377 + } else { 378 + return PhabricatorSyntaxHighlighter::highlightWithLanguage( 379 + $language, 380 + $source); 381 + } 266 382 } 267 383 268 384 public function getQueryApplicationClass() {
+7 -3
src/applications/paste/query/PhabricatorPasteSearchEngine.php
··· 13 13 14 14 public function newQuery() { 15 15 return id(new PhabricatorPasteQuery()) 16 - ->needContent(true); 16 + ->needSnippets(true); 17 17 } 18 18 19 19 protected function buildQueryFromParameters(array $map) { ··· 136 136 $created = phabricator_date($paste->getDateCreated(), $viewer); 137 137 $author = $handles[$paste->getAuthorPHID()]->renderLink(); 138 138 139 - $lines = phutil_split_lines($paste->getContent()); 139 + $snippet_type = $paste->getSnippet()->getType(); 140 + $lines = phutil_split_lines($paste->getSnippet()->getContent()); 140 141 141 142 $preview = id(new PhabricatorSourceCodeView()) 142 - ->setLimit(5) 143 143 ->setLines($lines) 144 + ->setTruncatedFirstBytes( 145 + $snippet_type == PhabricatorPasteSnippet::FIRST_BYTES) 146 + ->setTruncatedFirstLines( 147 + $snippet_type == PhabricatorPasteSnippet::FIRST_LINES) 144 148 ->setURI(new PhutilURI($paste->getURI())); 145 149 146 150 $source_code = phutil_tag(
+24
src/applications/paste/snippet/PhabricatorPasteSnippet.php
··· 1 + <?php 2 + 3 + final class PhabricatorPasteSnippet extends Phobject { 4 + 5 + const FULL = 'full'; 6 + const FIRST_LINES = 'first_lines'; 7 + const FIRST_BYTES = 'first_bytes'; 8 + 9 + private $content; 10 + private $type; 11 + 12 + public function __construct($content, $type) { 13 + $this->content = $content; 14 + $this->type = $type; 15 + } 16 + 17 + public function getContent() { 18 + return $this->content; 19 + } 20 + 21 + public function getType() { 22 + return $this->type; 23 + } 24 + }
+10
src/applications/paste/storage/PhabricatorPaste.php
··· 28 28 29 29 private $content = self::ATTACHABLE; 30 30 private $rawContent = self::ATTACHABLE; 31 + private $snippet = self::ATTACHABLE; 31 32 32 33 public static function initializeNewPaste(PhabricatorUser $actor) { 33 34 $app = id(new PhabricatorApplicationQuery()) ··· 132 133 133 134 public function attachRawContent($raw_content) { 134 135 $this->rawContent = $raw_content; 136 + return $this; 137 + } 138 + 139 + public function getSnippet() { 140 + return $this->assertAttached($this->snippet); 141 + } 142 + 143 + public function attachSnippet(PhabricatorPasteSnippet $snippet) { 144 + $this->snippet = $snippet; 135 145 return $this; 136 146 } 137 147
+32 -23
src/view/layout/PhabricatorSourceCodeView.php
··· 3 3 final class PhabricatorSourceCodeView extends AphrontView { 4 4 5 5 private $lines; 6 - private $limit; 7 6 private $uri; 8 7 private $highlights = array(); 9 8 private $canClickHighlight = true; 10 - 11 - public function setLimit($limit) { 12 - $this->limit = $limit; 13 - return $this; 14 - } 9 + private $truncatedFirstBytes = false; 10 + private $truncatedFirstLines = false; 15 11 16 12 public function setLines(array $lines) { 17 13 $this->lines = $lines; ··· 33 29 return $this; 34 30 } 35 31 32 + public function setTruncatedFirstBytes($truncated_first_bytes) { 33 + $this->truncatedFirstBytes = $truncated_first_bytes; 34 + return $this; 35 + } 36 + 37 + public function setTruncatedFirstLines($truncated_first_lines) { 38 + $this->truncatedFirstLines = $truncated_first_lines; 39 + return $this; 40 + } 41 + 36 42 public function render() { 37 43 require_celerity_resource('phabricator-source-code-view-css'); 38 44 require_celerity_resource('syntax-highlighting-css'); ··· 46 52 47 53 $rows = array(); 48 54 49 - foreach ($this->lines as $line) { 50 - $hit_limit = $this->limit && 51 - ($line_number == $this->limit) && 52 - (count($this->lines) != $this->limit); 53 - 54 - if ($hit_limit) { 55 - $content_number = ''; 56 - $content_line = phutil_tag( 55 + $lines = $this->lines; 56 + if ($this->truncatedFirstLines) { 57 + $lines[] = phutil_tag( 57 58 'span', 58 59 array( 59 60 'class' => 'c', 60 61 ), 61 62 pht('...')); 62 - } else { 63 - $content_number = $line_number; 64 - // NOTE: See phabricator-oncopy behavior. 65 - $content_line = hsprintf("\xE2\x80\x8B%s", $line); 66 - } 63 + } else if ($this->truncatedFirstBytes) { 64 + $last_key = last_key($lines); 65 + $lines[$last_key] = hsprintf( 66 + '%s%s', 67 + $lines[$last_key], 68 + phutil_tag( 69 + 'span', 70 + array( 71 + 'class' => 'c', 72 + ), 73 + pht('...'))); 74 + } 75 + 76 + foreach ($lines as $line) { 77 + 78 + // NOTE: See phabricator-oncopy behavior. 79 + $content_line = hsprintf("\xE2\x80\x8B%s", $line); 67 80 68 81 $row_attributes = array(); 69 82 if (isset($this->highlights[$line_number])) { ··· 105 118 ), 106 119 $content_line), 107 120 )); 108 - 109 - if ($hit_limit) { 110 - break; 111 - } 112 121 113 122 $line_number++; 114 123 }