mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 06:42:42 +01:00
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
This commit is contained in:
parent
0363febeb2
commit
90a614778c
11 changed files with 201 additions and 68 deletions
|
@ -9,10 +9,10 @@ return array(
|
|||
'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 @@ return array(
|
|||
'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 @@ return array(
|
|||
'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 @@ return array(
|
|||
'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 @@ return array(
|
|||
'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 @@ return array(
|
|||
'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 @@ return array(
|
|||
'javelin-install',
|
||||
'javelin-util',
|
||||
),
|
||||
'2ab10a76' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-uri',
|
||||
),
|
||||
'2ae077e1' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1683,6 +1677,12 @@ return array(
|
|||
'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 @@ return array(
|
|||
'phabricator-title',
|
||||
'phabricator-favicon',
|
||||
),
|
||||
'cae95e89' => array(
|
||||
'syntax-default-css',
|
||||
),
|
||||
'cd2b9b77' => array(
|
||||
'phui-oi-list-view-css',
|
||||
),
|
||||
|
@ -2103,6 +2100,9 @@ return array(
|
|||
'javelin-dom',
|
||||
'phabricator-draggable-list',
|
||||
),
|
||||
'e9c95dd4' => array(
|
||||
'syntax-default-css',
|
||||
),
|
||||
'ec1f3669' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-util',
|
||||
|
|
|
@ -69,4 +69,24 @@ final class DiffusionDocumentRenderingEngine
|
|||
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(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ final class PhabricatorDocumentRef
|
|||
private $file;
|
||||
private $byteLength;
|
||||
private $snippet;
|
||||
private $symbolMetadata = array();
|
||||
|
||||
public function setFile(PhabricatorFile $file) {
|
||||
$this->file = $file;
|
||||
|
@ -131,4 +132,15 @@ final class PhabricatorDocumentRef
|
|||
return $this->snippet;
|
||||
}
|
||||
|
||||
public function setSymbolMetadata(array $metadata) {
|
||||
$this->symbolMetadata = $metadata;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSymbolMetadata() {
|
||||
return $this->symbolMetadata;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ final class PhabricatorJSONDocumentEngine
|
|||
|
||||
return array(
|
||||
$message,
|
||||
$this->newTextDocumentContent($content),
|
||||
$this->newTextDocumentContent($ref, $content),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ final class PhabricatorSourceDocumentEngine
|
|||
|
||||
return array(
|
||||
$messages,
|
||||
$this->newTextDocumentContent($content),
|
||||
$this->newTextDocumentContent($ref, $content),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,12 +13,15 @@ abstract class PhabricatorTextDocumentEngine
|
|||
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) {
|
||||
|
|
|
@ -105,6 +105,7 @@ abstract class PhabricatorDocumentRenderingEngine
|
|||
'renderControlID' => $control_id,
|
||||
);
|
||||
} else {
|
||||
$this->willRenderRef($ref);
|
||||
$content = $engine->newDocument($ref);
|
||||
$config = array();
|
||||
}
|
||||
|
@ -158,6 +159,8 @@ abstract class PhabricatorDocumentRenderingEngine
|
|||
}
|
||||
|
||||
final public function newRenderResponse(PhabricatorDocumentRef $ref) {
|
||||
$this->willRenderRef($ref);
|
||||
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
|
@ -290,4 +293,8 @@ abstract class PhabricatorDocumentRenderingEngine
|
|||
return;
|
||||
}
|
||||
|
||||
protected function willRenderRef(PhabricatorDocumentRef $ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ final class PhabricatorSourceCodeView extends AphrontView {
|
|||
private $canClickHighlight = true;
|
||||
private $truncatedFirstBytes = false;
|
||||
private $truncatedFirstLines = false;
|
||||
private $symbolMetadata;
|
||||
|
||||
public function setLines(array $lines) {
|
||||
$this->lines = $lines;
|
||||
|
@ -39,6 +40,15 @@ final class PhabricatorSourceCodeView extends AphrontView {
|
|||
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 @@ final class PhabricatorSourceCodeView extends AphrontView {
|
|||
$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)));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -11,12 +11,29 @@ JX.behavior('repository-crossreference', function(config, statics) {
|
|||
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 @@ JX.behavior('repository-crossreference', function(config, statics) {
|
|||
unhighlight();
|
||||
return;
|
||||
}
|
||||
if (!isSignalkey(e)) {
|
||||
if (!hasHighlightModifierKey(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -76,7 +93,7 @@ JX.behavior('repository-crossreference', function(config, statics) {
|
|||
target = target.parentNode;
|
||||
}
|
||||
} else if (e.getType() === 'click') {
|
||||
openSearch(target, lang);
|
||||
openSearch(target, {lang: lang});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -85,13 +102,24 @@ JX.behavior('repository-crossreference', function(config, statics) {
|
|||
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 @@ JX.behavior('repository-crossreference', function(config, statics) {
|
|||
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 @@ JX.behavior('repository-crossreference', function(config, statics) {
|
|||
|
||||
var uri = JX.$U('/diffusion/symbol/' + symbol + '/');
|
||||
uri.addQueryParams(query);
|
||||
window.open(uri);
|
||||
|
||||
window.open(uri.toString());
|
||||
}
|
||||
|
||||
function linkAll() {
|
||||
|
@ -188,16 +219,6 @@ JX.behavior('repository-crossreference', function(config, statics) {
|
|||
// 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 @@ JX.behavior('repository-crossreference', function(config, statics) {
|
|||
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 @@ JX.behavior('repository-crossreference', function(config, statics) {
|
|||
['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.behavior('repository-crossreference', function(config, statics) {
|
|||
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 "<span />" 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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue