@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.

Make repository symbol references work with DocumentEngine

Summary: Ref T13105. Ref T13047. This makes symbol indexes work with DocumentEngine in Files, and restores support in Diffusion.

Test Plan: Command-clicked stuff, got taken to the symbol index with reasonable metadata in Diffusion, Differential and Files.

Reviewers: mydeveloperday

Reviewed By: mydeveloperday

Maniphest Tasks: T13105, T13047

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

+201 -68
+17 -17
resources/celerity/map.php
··· 9 9 'names' => array( 10 10 'conpherence.pkg.css' => 'e68cf1fa', 11 11 'conpherence.pkg.js' => '15191c65', 12 - 'core.pkg.css' => '29452b31', 12 + 'core.pkg.css' => '4a83e174', 13 13 'core.pkg.js' => '1ea38af8', 14 14 'differential.pkg.css' => '113e692c', 15 - 'differential.pkg.js' => 'f6d809c0', 15 + 'differential.pkg.js' => '3da2650a', 16 16 'diffusion.pkg.css' => 'a2d17c7d', 17 17 'diffusion.pkg.js' => '6134c5a1', 18 18 'maniphest.pkg.css' => '4845691a', ··· 113 113 'rsrc/css/application/uiexample/example.css' => '528b19de', 114 114 'rsrc/css/core/core.css' => '62fa3ace', 115 115 'rsrc/css/core/remarkup.css' => '924fc97d', 116 - 'rsrc/css/core/syntax.css' => 'cae95e89', 116 + 'rsrc/css/core/syntax.css' => 'e9c95dd4', 117 117 'rsrc/css/core/z-index.css' => '9d8f7c4b', 118 118 'rsrc/css/diviner/diviner-shared.css' => '896f1d43', 119 119 'rsrc/css/font/font-awesome.css' => 'e838e088', 120 120 'rsrc/css/font/font-lato.css' => 'c7ccd872', 121 121 'rsrc/css/font/phui-font-icon-base.css' => '870a7360', 122 122 'rsrc/css/layout/phabricator-filetree-view.css' => 'b912ad97', 123 - 'rsrc/css/layout/phabricator-source-code-view.css' => '31ee3c83', 123 + 'rsrc/css/layout/phabricator-source-code-view.css' => 'c6fc6834', 124 124 'rsrc/css/phui/button/phui-button-bar.css' => 'f1ff5494', 125 125 'rsrc/css/phui/button/phui-button-simple.css' => '8e1baf68', 126 126 'rsrc/css/phui/button/phui-button.css' => '1863cc6e', ··· 423 423 'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf', 424 424 'rsrc/js/application/releeph/releeph-request-state-change.js' => 'a0b57eb8', 425 425 'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f', 426 - 'rsrc/js/application/repository/repository-crossreference.js' => '2ab10a76', 426 + 'rsrc/js/application/repository/repository-crossreference.js' => '9a860428', 427 427 'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072', 428 428 'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08', 429 429 'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f', ··· 676 676 'javelin-behavior-reorder-applications' => '76b9fc3e', 677 677 'javelin-behavior-reorder-columns' => 'e1d25dfb', 678 678 'javelin-behavior-reorder-profile-menu-items' => 'e2e0a072', 679 - 'javelin-behavior-repository-crossreference' => '2ab10a76', 679 + 'javelin-behavior-repository-crossreference' => '9a860428', 680 680 'javelin-behavior-scrollbar' => '834a1173', 681 681 'javelin-behavior-search-reorder-queries' => 'e9581f08', 682 682 'javelin-behavior-select-content' => 'bf5374ef', ··· 784 784 'phabricator-search-results-css' => '505dd8cf', 785 785 'phabricator-shaped-request' => '7cbe244b', 786 786 'phabricator-slowvote-css' => 'a94b7230', 787 - 'phabricator-source-code-view-css' => '31ee3c83', 787 + 'phabricator-source-code-view-css' => 'c6fc6834', 788 788 'phabricator-standard-page-view' => '34ee718b', 789 789 'phabricator-textareautils' => '320810c8', 790 790 'phabricator-title' => '485aaa6c', ··· 884 884 'sprite-login-css' => '396f3c3a', 885 885 'sprite-tokens-css' => '9cdfd599', 886 886 'syntax-default-css' => '9923583c', 887 - 'syntax-highlighting-css' => 'cae95e89', 887 + 'syntax-highlighting-css' => 'e9c95dd4', 888 888 'tokens-css' => '3d0f239e', 889 889 'typeahead-browse-css' => 'f2818435', 890 890 'unhandled-exception-css' => '4c96257a', ··· 1050 1050 'javelin-install', 1051 1051 'javelin-util', 1052 1052 ), 1053 - '2ab10a76' => array( 1054 - 'javelin-behavior', 1055 - 'javelin-dom', 1056 - 'javelin-stratcom', 1057 - 'javelin-uri', 1058 - ), 1059 1053 '2ae077e1' => array( 1060 1054 'javelin-behavior', 1061 1055 'javelin-dom', ··· 1683 1677 'phuix-icon-view', 1684 1678 'javelin-behavior-phabricator-gesture', 1685 1679 ), 1680 + '9a860428' => array( 1681 + 'javelin-behavior', 1682 + 'javelin-dom', 1683 + 'javelin-stratcom', 1684 + 'javelin-uri', 1685 + ), 1686 1686 '9bbf3762' => array( 1687 1687 'javelin-behavior', 1688 1688 'javelin-dom', ··· 1972 1972 'phabricator-title', 1973 1973 'phabricator-favicon', 1974 1974 ), 1975 - 'cae95e89' => array( 1976 - 'syntax-default-css', 1977 - ), 1978 1975 'cd2b9b77' => array( 1979 1976 'phui-oi-list-view-css', 1980 1977 ), ··· 2102 2099 'javelin-workflow', 2103 2100 'javelin-dom', 2104 2101 'phabricator-draggable-list', 2102 + ), 2103 + 'e9c95dd4' => array( 2104 + 'syntax-default-css', 2105 2105 ), 2106 2106 'ec1f3669' => array( 2107 2107 'javelin-behavior',
+20
src/applications/diffusion/document/DiffusionDocumentRenderingEngine.php
··· 69 69 return; 70 70 } 71 71 72 + protected function willRenderRef(PhabricatorDocumentRef $ref) { 73 + $ref->setSymbolMetadata($this->getSymbolMetadata()); 74 + } 75 + 76 + private function getSymbolMetadata() { 77 + $drequest = $this->getDiffusionRequest(); 78 + 79 + $repo = $drequest->getRepository(); 80 + $symbol_repos = nonempty($repo->getSymbolSources(), array()); 81 + $symbol_repos[] = $repo->getPHID(); 82 + 83 + $lang = last(explode('.', $drequest->getPath())); 84 + 85 + return array( 86 + 'repositories' => $symbol_repos, 87 + 'lang' => $lang, 88 + 'path' => $drequest->getPath(), 89 + ); 90 + } 91 + 72 92 }
+12
src/applications/files/document/PhabricatorDocumentRef.php
··· 8 8 private $file; 9 9 private $byteLength; 10 10 private $snippet; 11 + private $symbolMetadata = array(); 11 12 12 13 public function setFile(PhabricatorFile $file) { 13 14 $this->file = $file; ··· 130 131 131 132 return $this->snippet; 132 133 } 134 + 135 + public function setSymbolMetadata(array $metadata) { 136 + $this->symbolMetadata = $metadata; 137 + return $this; 138 + } 139 + 140 + public function getSymbolMetadata() { 141 + return $this->symbolMetadata; 142 + } 143 + 144 + 133 145 134 146 }
+1 -1
src/applications/files/document/PhabricatorJSONDocumentEngine.php
··· 52 52 53 53 return array( 54 54 $message, 55 - $this->newTextDocumentContent($content), 55 + $this->newTextDocumentContent($ref, $content), 56 56 ); 57 57 } 58 58
+1 -1
src/applications/files/document/PhabricatorSourceDocumentEngine.php
··· 47 47 48 48 return array( 49 49 $messages, 50 - $this->newTextDocumentContent($content), 50 + $this->newTextDocumentContent($ref, $content), 51 51 ); 52 52 } 53 53
+5 -2
src/applications/files/document/PhabricatorTextDocumentEngine.php
··· 13 13 return true; 14 14 } 15 15 16 - protected function newTextDocumentContent($content) { 16 + protected function newTextDocumentContent( 17 + PhabricatorDocumentRef $ref, 18 + $content) { 17 19 $lines = phutil_split_lines($content); 18 20 19 21 $view = id(new PhabricatorSourceCodeView()) 20 22 ->setHighlights($this->getHighlightedLines()) 21 - ->setLines($lines); 23 + ->setLines($lines) 24 + ->setSymbolMetadata($ref->getSymbolMetadata()); 22 25 23 26 $message = null; 24 27 if ($this->encodingMessage !== null) {
+7
src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php
··· 105 105 'renderControlID' => $control_id, 106 106 ); 107 107 } else { 108 + $this->willRenderRef($ref); 108 109 $content = $engine->newDocument($ref); 109 110 $config = array(); 110 111 } ··· 158 159 } 159 160 160 161 final public function newRenderResponse(PhabricatorDocumentRef $ref) { 162 + $this->willRenderRef($ref); 163 + 161 164 $request = $this->getRequest(); 162 165 $viewer = $request->getViewer(); 163 166 ··· 287 290 protected function addApplicationCrumbs( 288 291 PHUICrumbsView $crumbs, 289 292 PhabricatorDocumentRef $ref = null) { 293 + return; 294 + } 295 + 296 + protected function willRenderRef(PhabricatorDocumentRef $ref) { 290 297 return; 291 298 } 292 299
+20 -1
src/view/layout/PhabricatorSourceCodeView.php
··· 8 8 private $canClickHighlight = true; 9 9 private $truncatedFirstBytes = false; 10 10 private $truncatedFirstLines = false; 11 + private $symbolMetadata; 11 12 12 13 public function setLines(array $lines) { 13 14 $this->lines = $lines; ··· 37 38 public function setTruncatedFirstLines($truncated_first_lines) { 38 39 $this->truncatedFirstLines = $truncated_first_lines; 39 40 return $this; 41 + } 42 + 43 + public function setSymbolMetadata(array $symbol_metadata) { 44 + $this->symbolMetadata = $symbol_metadata; 45 + return $this; 46 + } 47 + 48 + public function getSymbolMetadata() { 49 + return $this->symbolMetadata; 40 50 } 41 51 42 52 public function render() { ··· 130 140 $classes[] = 'remarkup-code'; 131 141 $classes[] = 'PhabricatorMonospaced'; 132 142 143 + $symbol_metadata = $this->getSymbolMetadata(); 144 + 145 + $sigils = array(); 146 + $sigils[] = 'phabricator-source'; 147 + $sigils[] = 'has-symbols'; 148 + 149 + Javelin::initBehavior('repository-crossreference'); 150 + 133 151 return phutil_tag_div( 134 152 'phabricator-source-code-container', 135 153 javelin_tag( 136 154 'table', 137 155 array( 138 156 'class' => implode(' ', $classes), 139 - 'sigil' => 'phabricator-source', 157 + 'sigil' => implode(' ', $sigils), 140 158 'meta' => array( 141 159 'uri' => (string)$this->uri, 160 + 'symbols' => $symbol_metadata, 142 161 ), 143 162 ), 144 163 phutil_implode_html('', $rows)));
+3 -10
webroot/rsrc/css/core/syntax.css
··· 6 6 color: #aa0066; 7 7 } 8 8 9 - .remarkup-code .over-the-line { 10 - color: #aa0066; 11 - margin-right: 1px; 12 - } 13 - 14 9 .remarkup-code td > span { 15 10 display: inline; 16 11 word-break: break-all; ··· 24 19 .remarkup-code .rbw_i { color: indigo; } 25 20 .remarkup-code .rbw_v { color: violet; } 26 21 27 - .repository-crossreference .remarkup-code .crossreference-item { 28 - background: lightyellow; 29 - border-bottom: 1px dotted #bbddbb; 30 - } 31 - .crossreference-cursor { 22 + span.crossreference-item { 23 + background: {$lightyellow}; 24 + border-bottom: 1px solid {$yellow}; 32 25 cursor: help; 33 26 } 34 27
-1
webroot/rsrc/css/layout/phabricator-source-code-view.css
··· 7 7 overflow-y: hidden; 8 8 border: 1px solid {$paste.border}; 9 9 border-radius: 3px; 10 - background-color: {$paste.content}; 11 10 } 12 11 13 12 .phui-oi .phabricator-source-code-container {
+115 -35
webroot/rsrc/js/application/repository/repository-crossreference.js
··· 11 11 var highlighted; 12 12 var linked = []; 13 13 14 - var isMac = navigator.platform.indexOf('Mac') > -1; 15 - var signalKey = isMac ? 91 /*COMMAND*/ : 17 /*CTRL*/; 16 - function isSignalkey(event) { 17 - return isMac ? 18 - event.getRawEvent().metaKey : 19 - event.getRawEvent().ctrlKey; 14 + function isMacOS() { 15 + return (navigator.platform.indexOf('Mac') > -1); 16 + } 17 + 18 + function isHighlightModifierKey(e) { 19 + var signal_key; 20 + if (isMacOS()) { 21 + // On macOS, use the "Command" key. 22 + signal_key = 91; 23 + } else { 24 + // On other platforms, use the "Control" key. 25 + signal_key = 17; 26 + } 27 + 28 + return (e.getRawEvent().keyCode === signal_key); 29 + } 30 + 31 + function hasHighlightModifierKey(e) { 32 + if (isMacOS()) { 33 + return e.getRawEvent().metaKey; 34 + } else { 35 + return e.getRawEvent().ctrlKey; 36 + } 20 37 } 21 38 22 39 var classHighlight = 'crossreference-item'; ··· 43 60 unhighlight(); 44 61 return; 45 62 } 46 - if (!isSignalkey(e)) { 63 + if (!hasHighlightModifierKey(e)) { 47 64 return; 48 65 } 49 66 ··· 76 93 target = target.parentNode; 77 94 } 78 95 } else if (e.getType() === 'click') { 79 - openSearch(target, lang); 96 + openSearch(target, {lang: lang}); 80 97 } 81 98 }); 82 99 } ··· 85 102 highlighted = null; 86 103 } 87 104 88 - function openSearch(target, lang) { 105 + function openSearch(target, context) { 89 106 var symbol = target.textContent || target.innerText; 90 - var query = { 91 - lang : lang, 92 - repositories : config.repositories.join(','), 93 - jump : true 94 - }; 107 + 108 + context = context || {}; 109 + context.lang = context.lang || null; 110 + context.repositories = 111 + context.repositories || 112 + (config && config.repositories) || 113 + []; 114 + 115 + var query = JX.copy({}, context); 116 + if (query.repositories.length) { 117 + query.repositories = query.repositories.join(','); 118 + } else { 119 + delete query.repositories; 120 + } 121 + query.jump = true; 122 + 95 123 var c = target.className; 96 124 c = c.replace(classHighlight, '').trim(); 97 125 ··· 112 140 query.line = line; 113 141 } 114 142 115 - var path = getPath(target); 116 - if (path !== null) { 117 - query.path = path; 143 + if (!query.hasOwnProperty('path')) { 144 + var path = getPath(target); 145 + if (path !== null) { 146 + query.path = path; 147 + } 118 148 } 119 149 120 150 var char = getChar(target); ··· 124 154 125 155 var uri = JX.$U('/diffusion/symbol/' + symbol + '/'); 126 156 uri.addQueryParams(query); 127 - window.open(uri); 157 + 158 + window.open(uri.toString()); 128 159 } 129 160 130 161 function linkAll() { ··· 188 219 // Ignore. 189 220 } 190 221 191 - // This method works in Diffusion, when viewing the content of a file at 192 - // a particular commit. 193 - var file; 194 - try { 195 - file = JX.DOM.findAbove(target, 'div', 'diffusion-file-content-view'); 196 - return JX.Stratcom.getData(file).path; 197 - } catch (ex) { 198 - // Ignore. 199 - } 200 - 201 222 return null; 202 223 } 203 224 ··· 227 248 return null; 228 249 } 229 250 230 - if (config.container) { 231 - link(JX.$(config.container), config.lang); 232 - } else if (config.section) { 233 - linkAll(JX.$(config.section)); 234 - } 235 - 236 251 JX.Stratcom.listen( 237 252 'differential-preview-update', 238 253 null, ··· 245 260 ['keydown', 'keyup'], 246 261 null, 247 262 function(e) { 248 - if (e.getRawEvent().keyCode !== signalKey) { 263 + if (!isHighlightModifierKey(e)) { 249 264 return; 250 265 } 266 + 251 267 setCursorMode(e.getType() === 'keydown'); 252 268 253 269 if (!statics.active) { ··· 272 288 JX.DOM.alterClass(element, classMouseCursor, statics.active); 273 289 }); 274 290 } 291 + 292 + 293 + if (config && config.container) { 294 + link(JX.$(config.container), config.lang); 295 + } 296 + 297 + JX.Stratcom.listen( 298 + ['mouseover', 'mouseout', 'click'], 299 + ['has-symbols', 'tag:span'], 300 + function(e) { 301 + var type = e.getType(); 302 + 303 + if (type === 'mouseout') { 304 + unhighlight(); 305 + return; 306 + } 307 + 308 + if (!hasHighlightModifierKey(e)) { 309 + return; 310 + } 311 + 312 + var target = e.getTarget(); 313 + 314 + try { 315 + // If we're in an inline comment, don't link symbols. 316 + if (JX.DOM.findAbove(target, 'div', 'differential-inline-comment')) { 317 + return; 318 + } 319 + } catch (ex) { 320 + // Continue if we're not inside an inline comment. 321 + } 322 + 323 + // If only part of the symbol was edited, the symbol name itself will 324 + // have another "<span />" inside of it which highlights only the 325 + // edited part. Skip over it. 326 + if (JX.DOM.isNode(target, 'span') && (target.className === 'bright')) { 327 + target = target.parentNode; 328 + } 329 + 330 + if (type === 'click') { 331 + openSearch(target, e.getNodeData('has-symbols').symbols); 332 + e.kill(); 333 + return; 334 + } 335 + 336 + if (e.getType() === 'mouseover') { 337 + while (target && target !== document.body) { 338 + if (!JX.DOM.isNode(target, 'span')) { 339 + target = target.parentNode; 340 + continue; 341 + } 342 + 343 + if (!class_map.hasOwnProperty(target.className)) { 344 + target = target.parentNode; 345 + continue; 346 + } 347 + 348 + highlighted = target; 349 + JX.DOM.alterClass(highlighted, classHighlight, true); 350 + break; 351 + } 352 + } 353 + }); 354 + 275 355 });