diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,10 +9,10 @@ 'names' => array( 'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.js' => '15191c65', - 'core.pkg.css' => '29452b31', + 'core.pkg.css' => '4a83e174', 'core.pkg.js' => '1ea38af8', 'differential.pkg.css' => '113e692c', - 'differential.pkg.js' => 'f6d809c0', + 'differential.pkg.js' => '3da2650a', 'diffusion.pkg.css' => 'a2d17c7d', 'diffusion.pkg.js' => '6134c5a1', 'maniphest.pkg.css' => '4845691a', @@ -113,14 +113,14 @@ 'rsrc/css/application/uiexample/example.css' => '528b19de', 'rsrc/css/core/core.css' => '62fa3ace', 'rsrc/css/core/remarkup.css' => '924fc97d', - 'rsrc/css/core/syntax.css' => 'cae95e89', + 'rsrc/css/core/syntax.css' => 'e9c95dd4', 'rsrc/css/core/z-index.css' => '9d8f7c4b', 'rsrc/css/diviner/diviner-shared.css' => '896f1d43', 'rsrc/css/font/font-awesome.css' => 'e838e088', 'rsrc/css/font/font-lato.css' => 'c7ccd872', 'rsrc/css/font/phui-font-icon-base.css' => '870a7360', 'rsrc/css/layout/phabricator-filetree-view.css' => 'b912ad97', - 'rsrc/css/layout/phabricator-source-code-view.css' => '31ee3c83', + 'rsrc/css/layout/phabricator-source-code-view.css' => 'c6fc6834', 'rsrc/css/phui/button/phui-button-bar.css' => 'f1ff5494', 'rsrc/css/phui/button/phui-button-simple.css' => '8e1baf68', 'rsrc/css/phui/button/phui-button.css' => '1863cc6e', @@ -423,7 +423,7 @@ 'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf', 'rsrc/js/application/releeph/releeph-request-state-change.js' => 'a0b57eb8', 'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f', - 'rsrc/js/application/repository/repository-crossreference.js' => '2ab10a76', + 'rsrc/js/application/repository/repository-crossreference.js' => '9a860428', 'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072', 'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08', 'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f', @@ -676,7 +676,7 @@ 'javelin-behavior-reorder-applications' => '76b9fc3e', 'javelin-behavior-reorder-columns' => 'e1d25dfb', 'javelin-behavior-reorder-profile-menu-items' => 'e2e0a072', - 'javelin-behavior-repository-crossreference' => '2ab10a76', + 'javelin-behavior-repository-crossreference' => '9a860428', 'javelin-behavior-scrollbar' => '834a1173', 'javelin-behavior-search-reorder-queries' => 'e9581f08', 'javelin-behavior-select-content' => 'bf5374ef', @@ -784,7 +784,7 @@ 'phabricator-search-results-css' => '505dd8cf', 'phabricator-shaped-request' => '7cbe244b', 'phabricator-slowvote-css' => 'a94b7230', - 'phabricator-source-code-view-css' => '31ee3c83', + 'phabricator-source-code-view-css' => 'c6fc6834', 'phabricator-standard-page-view' => '34ee718b', 'phabricator-textareautils' => '320810c8', 'phabricator-title' => '485aaa6c', @@ -884,7 +884,7 @@ 'sprite-login-css' => '396f3c3a', 'sprite-tokens-css' => '9cdfd599', 'syntax-default-css' => '9923583c', - 'syntax-highlighting-css' => 'cae95e89', + 'syntax-highlighting-css' => 'e9c95dd4', 'tokens-css' => '3d0f239e', 'typeahead-browse-css' => 'f2818435', 'unhandled-exception-css' => '4c96257a', @@ -1050,12 +1050,6 @@ 'javelin-install', 'javelin-util', ), - '2ab10a76' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-stratcom', - 'javelin-uri', - ), '2ae077e1' => array( 'javelin-behavior', 'javelin-dom', @@ -1683,6 +1677,12 @@ 'phuix-icon-view', 'javelin-behavior-phabricator-gesture', ), + '9a860428' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-stratcom', + 'javelin-uri', + ), '9bbf3762' => array( 'javelin-behavior', 'javelin-dom', @@ -1972,9 +1972,6 @@ 'phabricator-title', 'phabricator-favicon', ), - 'cae95e89' => array( - 'syntax-default-css', - ), 'cd2b9b77' => array( 'phui-oi-list-view-css', ), @@ -2103,6 +2100,9 @@ 'javelin-dom', 'phabricator-draggable-list', ), + 'e9c95dd4' => array( + 'syntax-default-css', + ), 'ec1f3669' => array( 'javelin-behavior', 'javelin-util', diff --git a/src/applications/diffusion/document/DiffusionDocumentRenderingEngine.php b/src/applications/diffusion/document/DiffusionDocumentRenderingEngine.php --- a/src/applications/diffusion/document/DiffusionDocumentRenderingEngine.php +++ b/src/applications/diffusion/document/DiffusionDocumentRenderingEngine.php @@ -69,4 +69,24 @@ return; } + protected function willRenderRef(PhabricatorDocumentRef $ref) { + $ref->setSymbolMetadata($this->getSymbolMetadata()); + } + + private function getSymbolMetadata() { + $drequest = $this->getDiffusionRequest(); + + $repo = $drequest->getRepository(); + $symbol_repos = nonempty($repo->getSymbolSources(), array()); + $symbol_repos[] = $repo->getPHID(); + + $lang = last(explode('.', $drequest->getPath())); + + return array( + 'repositories' => $symbol_repos, + 'lang' => $lang, + 'path' => $drequest->getPath(), + ); + } + } diff --git a/src/applications/files/document/PhabricatorDocumentRef.php b/src/applications/files/document/PhabricatorDocumentRef.php --- a/src/applications/files/document/PhabricatorDocumentRef.php +++ b/src/applications/files/document/PhabricatorDocumentRef.php @@ -8,6 +8,7 @@ private $file; private $byteLength; private $snippet; + private $symbolMetadata = array(); public function setFile(PhabricatorFile $file) { $this->file = $file; @@ -131,4 +132,15 @@ return $this->snippet; } + public function setSymbolMetadata(array $metadata) { + $this->symbolMetadata = $metadata; + return $this; + } + + public function getSymbolMetadata() { + return $this->symbolMetadata; + } + + + } diff --git a/src/applications/files/document/PhabricatorJSONDocumentEngine.php b/src/applications/files/document/PhabricatorJSONDocumentEngine.php --- a/src/applications/files/document/PhabricatorJSONDocumentEngine.php +++ b/src/applications/files/document/PhabricatorJSONDocumentEngine.php @@ -52,7 +52,7 @@ return array( $message, - $this->newTextDocumentContent($content), + $this->newTextDocumentContent($ref, $content), ); } diff --git a/src/applications/files/document/PhabricatorSourceDocumentEngine.php b/src/applications/files/document/PhabricatorSourceDocumentEngine.php --- a/src/applications/files/document/PhabricatorSourceDocumentEngine.php +++ b/src/applications/files/document/PhabricatorSourceDocumentEngine.php @@ -47,7 +47,7 @@ return array( $messages, - $this->newTextDocumentContent($content), + $this->newTextDocumentContent($ref, $content), ); } diff --git a/src/applications/files/document/PhabricatorTextDocumentEngine.php b/src/applications/files/document/PhabricatorTextDocumentEngine.php --- a/src/applications/files/document/PhabricatorTextDocumentEngine.php +++ b/src/applications/files/document/PhabricatorTextDocumentEngine.php @@ -13,12 +13,15 @@ return true; } - protected function newTextDocumentContent($content) { + protected function newTextDocumentContent( + PhabricatorDocumentRef $ref, + $content) { $lines = phutil_split_lines($content); $view = id(new PhabricatorSourceCodeView()) ->setHighlights($this->getHighlightedLines()) - ->setLines($lines); + ->setLines($lines) + ->setSymbolMetadata($ref->getSymbolMetadata()); $message = null; if ($this->encodingMessage !== null) { diff --git a/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php b/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php --- a/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php +++ b/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php @@ -105,6 +105,7 @@ 'renderControlID' => $control_id, ); } else { + $this->willRenderRef($ref); $content = $engine->newDocument($ref); $config = array(); } @@ -158,6 +159,8 @@ } final public function newRenderResponse(PhabricatorDocumentRef $ref) { + $this->willRenderRef($ref); + $request = $this->getRequest(); $viewer = $request->getViewer(); @@ -290,4 +293,8 @@ return; } + protected function willRenderRef(PhabricatorDocumentRef $ref) { + return; + } + } diff --git a/src/view/layout/PhabricatorSourceCodeView.php b/src/view/layout/PhabricatorSourceCodeView.php --- a/src/view/layout/PhabricatorSourceCodeView.php +++ b/src/view/layout/PhabricatorSourceCodeView.php @@ -8,6 +8,7 @@ private $canClickHighlight = true; private $truncatedFirstBytes = false; private $truncatedFirstLines = false; + private $symbolMetadata; public function setLines(array $lines) { $this->lines = $lines; @@ -39,6 +40,15 @@ return $this; } + public function setSymbolMetadata(array $symbol_metadata) { + $this->symbolMetadata = $symbol_metadata; + return $this; + } + + public function getSymbolMetadata() { + return $this->symbolMetadata; + } + public function render() { require_celerity_resource('phabricator-source-code-view-css'); require_celerity_resource('syntax-highlighting-css'); @@ -130,15 +140,24 @@ $classes[] = 'remarkup-code'; $classes[] = 'PhabricatorMonospaced'; + $symbol_metadata = $this->getSymbolMetadata(); + + $sigils = array(); + $sigils[] = 'phabricator-source'; + $sigils[] = 'has-symbols'; + + Javelin::initBehavior('repository-crossreference'); + return phutil_tag_div( 'phabricator-source-code-container', javelin_tag( 'table', array( 'class' => implode(' ', $classes), - 'sigil' => 'phabricator-source', + 'sigil' => implode(' ', $sigils), 'meta' => array( 'uri' => (string)$this->uri, + 'symbols' => $symbol_metadata, ), ), phutil_implode_html('', $rows))); diff --git a/webroot/rsrc/css/core/syntax.css b/webroot/rsrc/css/core/syntax.css --- a/webroot/rsrc/css/core/syntax.css +++ b/webroot/rsrc/css/core/syntax.css @@ -6,11 +6,6 @@ color: #aa0066; } -.remarkup-code .over-the-line { - color: #aa0066; - margin-right: 1px; -} - .remarkup-code td > span { display: inline; word-break: break-all; @@ -24,11 +19,9 @@ .remarkup-code .rbw_i { color: indigo; } .remarkup-code .rbw_v { color: violet; } -.repository-crossreference .remarkup-code .crossreference-item { - background: lightyellow; - border-bottom: 1px dotted #bbddbb; -} -.crossreference-cursor { +span.crossreference-item { + background: {$lightyellow}; + border-bottom: 1px solid {$yellow}; cursor: help; } diff --git a/webroot/rsrc/css/layout/phabricator-source-code-view.css b/webroot/rsrc/css/layout/phabricator-source-code-view.css --- a/webroot/rsrc/css/layout/phabricator-source-code-view.css +++ b/webroot/rsrc/css/layout/phabricator-source-code-view.css @@ -7,7 +7,6 @@ overflow-y: hidden; border: 1px solid {$paste.border}; border-radius: 3px; - background-color: {$paste.content}; } .phui-oi .phabricator-source-code-container { diff --git a/webroot/rsrc/js/application/repository/repository-crossreference.js b/webroot/rsrc/js/application/repository/repository-crossreference.js --- a/webroot/rsrc/js/application/repository/repository-crossreference.js +++ b/webroot/rsrc/js/application/repository/repository-crossreference.js @@ -11,12 +11,29 @@ var highlighted; var linked = []; - var isMac = navigator.platform.indexOf('Mac') > -1; - var signalKey = isMac ? 91 /*COMMAND*/ : 17 /*CTRL*/; - function isSignalkey(event) { - return isMac ? - event.getRawEvent().metaKey : - event.getRawEvent().ctrlKey; + function isMacOS() { + return (navigator.platform.indexOf('Mac') > -1); + } + + function isHighlightModifierKey(e) { + var signal_key; + if (isMacOS()) { + // On macOS, use the "Command" key. + signal_key = 91; + } else { + // On other platforms, use the "Control" key. + signal_key = 17; + } + + return (e.getRawEvent().keyCode === signal_key); + } + + function hasHighlightModifierKey(e) { + if (isMacOS()) { + return e.getRawEvent().metaKey; + } else { + return e.getRawEvent().ctrlKey; + } } var classHighlight = 'crossreference-item'; @@ -43,7 +60,7 @@ unhighlight(); return; } - if (!isSignalkey(e)) { + if (!hasHighlightModifierKey(e)) { return; } @@ -76,7 +93,7 @@ target = target.parentNode; } } else if (e.getType() === 'click') { - openSearch(target, lang); + openSearch(target, {lang: lang}); } }); } @@ -85,13 +102,24 @@ highlighted = null; } - function openSearch(target, lang) { + function openSearch(target, context) { var symbol = target.textContent || target.innerText; - var query = { - lang : lang, - repositories : config.repositories.join(','), - jump : true - }; + + context = context || {}; + context.lang = context.lang || null; + context.repositories = + context.repositories || + (config && config.repositories) || + []; + + var query = JX.copy({}, context); + if (query.repositories.length) { + query.repositories = query.repositories.join(','); + } else { + delete query.repositories; + } + query.jump = true; + var c = target.className; c = c.replace(classHighlight, '').trim(); @@ -112,9 +140,11 @@ query.line = line; } - var path = getPath(target); - if (path !== null) { - query.path = path; + if (!query.hasOwnProperty('path')) { + var path = getPath(target); + if (path !== null) { + query.path = path; + } } var char = getChar(target); @@ -124,7 +154,8 @@ var uri = JX.$U('/diffusion/symbol/' + symbol + '/'); uri.addQueryParams(query); - window.open(uri); + + window.open(uri.toString()); } function linkAll() { @@ -188,16 +219,6 @@ // Ignore. } - // This method works in Diffusion, when viewing the content of a file at - // a particular commit. - var file; - try { - file = JX.DOM.findAbove(target, 'div', 'diffusion-file-content-view'); - return JX.Stratcom.getData(file).path; - } catch (ex) { - // Ignore. - } - return null; } @@ -227,12 +248,6 @@ return null; } - if (config.container) { - link(JX.$(config.container), config.lang); - } else if (config.section) { - linkAll(JX.$(config.section)); - } - JX.Stratcom.listen( 'differential-preview-update', null, @@ -245,9 +260,10 @@ ['keydown', 'keyup'], null, function(e) { - if (e.getRawEvent().keyCode !== signalKey) { + if (!isHighlightModifierKey(e)) { return; } + setCursorMode(e.getType() === 'keydown'); if (!statics.active) { @@ -272,4 +288,68 @@ JX.DOM.alterClass(element, classMouseCursor, statics.active); }); } + + + if (config && config.container) { + link(JX.$(config.container), config.lang); + } + + JX.Stratcom.listen( + ['mouseover', 'mouseout', 'click'], + ['has-symbols', 'tag:span'], + function(e) { + var type = e.getType(); + + if (type === 'mouseout') { + unhighlight(); + return; + } + + if (!hasHighlightModifierKey(e)) { + return; + } + + var target = e.getTarget(); + + try { + // If we're in an inline comment, don't link symbols. + if (JX.DOM.findAbove(target, 'div', 'differential-inline-comment')) { + return; + } + } catch (ex) { + // Continue if we're not inside an inline comment. + } + + // If only part of the symbol was edited, the symbol name itself will + // have another "" inside of it which highlights only the + // edited part. Skip over it. + if (JX.DOM.isNode(target, 'span') && (target.className === 'bright')) { + target = target.parentNode; + } + + if (type === 'click') { + openSearch(target, e.getNodeData('has-symbols').symbols); + e.kill(); + return; + } + + if (e.getType() === 'mouseover') { + while (target && target !== document.body) { + if (!JX.DOM.isNode(target, 'span')) { + target = target.parentNode; + continue; + } + + if (!class_map.hasOwnProperty(target.className)) { + target = target.parentNode; + continue; + } + + highlighted = target; + JX.DOM.alterClass(highlighted, classHighlight, true); + break; + } + } + }); + });