mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-18 21:02:41 +01:00
Display links to editor in Differential and Diffusion
Summary: It is possible to open a file in editor by registering a custom URI scheme (pseudo-protocol). Some editors register it by default. Having links to open the file in external editor is productivity booster although it is a little bit harder to set up. There are several other tools using file_link_format configuration directive (XDebug, Symfony) to bind to this protocol. I've added the example with editor: protocol which can be used as a proxy to actual editor (used by Nette Framework: http://wiki.nette.org/en/howto-editor-link). Test Plan: Configure Editor Link in User Preferences. Register URI scheme in OS. Open a file in Diffusion. Click on the Edit button. Open a revision in Differential. Click on the Edit button. Reviewers: epriestley Reviewed By: epriestley CC: aran, epriestley Differential Revision: https://secure.phabricator.com/D1422
This commit is contained in:
parent
79218b6e47
commit
067c7f8a74
12 changed files with 107 additions and 28 deletions
|
@ -330,16 +330,6 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/js/javelin/lib/behavior.js',
|
||||
),
|
||||
0 =>
|
||||
array(
|
||||
'uri' => '/res/14c48a9f/rsrc/js/javelin/lib/__tests__/behavior.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
),
|
||||
'disk' => '/rsrc/js/javelin/lib/__tests__/behavior.js',
|
||||
),
|
||||
'javelin-behavior-aphront-basic-tokenizer' =>
|
||||
array(
|
||||
'uri' => '/res/9be30797/rsrc/js/application/core/behavior-tokenizer.js',
|
||||
|
@ -471,7 +461,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-behavior-differential-dropdown-menus' =>
|
||||
array(
|
||||
'uri' => '/res/acba60ad/rsrc/js/application/differential/behavior-dropdown-menus.js',
|
||||
'uri' => '/res/7bfb2fdb/rsrc/js/application/differential/behavior-dropdown-menus.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1437,18 +1427,6 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/css/application/objectselector/object-selector.css',
|
||||
),
|
||||
'phabricator-prefab' =>
|
||||
array(
|
||||
'uri' => '/res/5784a112/rsrc/js/application/core/Prefab.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
1 => 'javelin-util',
|
||||
2 => 'javelin-dom',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/core/Prefab.js',
|
||||
),
|
||||
'phabricator-profile-css' =>
|
||||
array(
|
||||
'uri' => '/res/9869d10b/rsrc/css/application/profile/profile-view.css',
|
||||
|
@ -1467,6 +1445,29 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/css/application/profile/profile-header-view.css',
|
||||
),
|
||||
0 =>
|
||||
array(
|
||||
'uri' => '/res/b6096fdd/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-uri',
|
||||
1 => 'javelin-php-serializer',
|
||||
),
|
||||
'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
),
|
||||
'phabricator-prefab' =>
|
||||
array(
|
||||
'uri' => '/res/5784a112/rsrc/js/application/core/Prefab.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
1 => 'javelin-util',
|
||||
2 => 'javelin-dom',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/core/Prefab.js',
|
||||
),
|
||||
'phabricator-remarkup-css' =>
|
||||
array(
|
||||
'uri' => '/res/39f358b8/rsrc/css/core/remarkup.css',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -114,7 +114,8 @@ class DifferentialDiffViewController extends DifferentialController {
|
|||
|
||||
$details = id(new DifferentialChangesetListView())
|
||||
->setChangesets($changesets)
|
||||
->setRenderingReferences($refs);
|
||||
->setRenderingReferences($refs)
|
||||
->setUser($request->getUser());
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
id(new DifferentialPrimaryPaneView())
|
||||
|
|
|
@ -238,6 +238,7 @@ class DifferentialRevisionViewController extends DifferentialController {
|
|||
$changeset_view->setChangesets($visible_changesets);
|
||||
$changeset_view->setEditable(!$viewer_is_anonymous);
|
||||
$changeset_view->setStandaloneViews(true);
|
||||
$changeset_view->setUser($user);
|
||||
$changeset_view->setRevision($revision);
|
||||
$changeset_view->setDiff($target);
|
||||
$changeset_view->setRenderingReferences($rendering_references);
|
||||
|
|
|
@ -25,6 +25,7 @@ class DifferentialChangesetListView extends AphrontView {
|
|||
private $renderURI = '/differential/changeset/';
|
||||
private $whitespace;
|
||||
private $standaloneViews;
|
||||
private $user;
|
||||
private $symbolIndexes = array();
|
||||
private $repository;
|
||||
private $diff;
|
||||
|
@ -44,6 +45,11 @@ class DifferentialChangesetListView extends AphrontView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setUser(PhabricatorUser $user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRevision(DifferentialRevision $revision) {
|
||||
$this->revision = $revision;
|
||||
return $this;
|
||||
|
@ -133,6 +139,19 @@ class DifferentialChangesetListView extends AphrontView {
|
|||
$meta['rightURI'] = (string)$detail_uri->alter('view', 'new');
|
||||
}
|
||||
|
||||
if ($this->user) {
|
||||
$path = ltrim(
|
||||
$changeset->getAbsoluteRepositoryPath($this->diff, $repository),
|
||||
'/');
|
||||
$line = 1; // TODO: get first changed line
|
||||
$editor_link = $this->user->loadEditorLink($path, $line, $repository);
|
||||
if ($editor_link) {
|
||||
$meta['editor'] = $editor_link;
|
||||
} else {
|
||||
$meta['editorConfigure'] = '/settings/page/preferences/';
|
||||
}
|
||||
}
|
||||
|
||||
$detail_button = javelin_render_tag(
|
||||
'a',
|
||||
array(
|
||||
|
@ -145,7 +164,6 @@ class DifferentialChangesetListView extends AphrontView {
|
|||
"View Options \xE2\x96\xBC");
|
||||
}
|
||||
|
||||
|
||||
$detail->setChangeset($changeset);
|
||||
$detail->addButton($detail_button);
|
||||
$detail->setSymbolIndex(idx($this->symbolIndexes, $key));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -44,6 +44,7 @@ class DiffusionChangeController extends DiffusionController {
|
|||
'/diffusion/'.$drequest->getRepository()->getCallsign().'/diff/');
|
||||
$changeset_view->setWhitespace(
|
||||
DifferentialChangesetParser::WHITESPACE_SHOW_ALL);
|
||||
$changeset_view->setUser($this->getRequest()->getUser());
|
||||
|
||||
$content[] = $this->buildCrumbs(
|
||||
array(
|
||||
|
|
|
@ -200,6 +200,7 @@ class DiffusionCommitController extends DiffusionController {
|
|||
$change_list->setChangesets($changesets);
|
||||
$change_list->setRenderingReferences($references);
|
||||
$change_list->setRenderURI('/diffusion/'.$callsign.'/diff/');
|
||||
$change_list->setUser($user);
|
||||
|
||||
// TODO: This is pretty awkward, unify the CSS between Diffusion and
|
||||
// Differential better.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -95,6 +95,25 @@ class DiffusionBrowseFileController extends DiffusionController {
|
|||
$select.
|
||||
'<button>View</button>');
|
||||
$view_select_panel->appendChild($view_select_form);
|
||||
|
||||
$user = $request->getUser();
|
||||
if ($user) {
|
||||
$line = 1;
|
||||
$repository = $this->getDiffusionRequest()->getRepository();
|
||||
$editor_link = $user->loadEditorLink($path, $line, $repository);
|
||||
if ($editor_link) {
|
||||
$view_select_panel->addButton(
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $editor_link,
|
||||
'class' => 'button',
|
||||
),
|
||||
'Edit'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$view_select_panel->appendChild('<div style="clear: both;"></div>');
|
||||
|
||||
// Build the content of the file.
|
||||
|
|
|
@ -26,6 +26,7 @@ class PhabricatorUserPreferenceSettingsPanelController
|
|||
$preferences = $user->loadPreferences();
|
||||
|
||||
$pref_monospaced = PhabricatorUserPreferences::PREFERENCE_MONOSPACED;
|
||||
$pref_editor = PhabricatorUserPreferences::PREFERENCE_EDITOR;
|
||||
$pref_titles = PhabricatorUserPreferences::PREFERENCE_TITLES;
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
|
@ -35,6 +36,7 @@ class PhabricatorUserPreferenceSettingsPanelController
|
|||
$monospaced = preg_replace('/[^a-z0-9 ,"]+/i', '', $monospaced);
|
||||
|
||||
$preferences->setPreference($pref_titles, $request->getStr($pref_titles));
|
||||
$preferences->setPreference($pref_editor, $request->getStr($pref_editor));
|
||||
$preferences->setPreference($pref_monospaced, $monospaced);
|
||||
|
||||
$preferences->save();
|
||||
|
@ -64,6 +66,15 @@ EXAMPLE;
|
|||
'text' =>
|
||||
'In page titles, show Tool names as plain text: [Differential]',
|
||||
)))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel('Editor Link')
|
||||
->setName($pref_editor)
|
||||
->setCaption(
|
||||
'Link to edit files in external editor. '.
|
||||
'%f is replaced by filename, %l by line number, %r by repository. '.
|
||||
'Example: editor://open/?file=%f&line=%l&repository=%r')
|
||||
->setValue($preferences->getPreference($pref_editor)))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel('Monospaced Font')
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
class PhabricatorUserPreferences extends PhabricatorUserDAO {
|
||||
|
||||
const PREFERENCE_MONOSPACED = 'monospaced';
|
||||
const PREFERENCE_EDITOR = 'editor';
|
||||
const PREFERENCE_TITLES = 'titles';
|
||||
|
||||
const PREFERENCE_RE_PREFIX = 're-prefix';
|
||||
|
|
|
@ -403,6 +403,7 @@ class PhabricatorUser extends PhabricatorUserDAO {
|
|||
|
||||
$default_dict = array(
|
||||
PhabricatorUserPreferences::PREFERENCE_TITLES => 'glyph',
|
||||
PhabricatorUserPreferences::PREFERENCE_EDITOR => '',
|
||||
PhabricatorUserPreferences::PREFERENCE_MONOSPACED => '');
|
||||
|
||||
$preferences->setPreferences($default_dict);
|
||||
|
@ -412,6 +413,20 @@ class PhabricatorUser extends PhabricatorUserDAO {
|
|||
return $preferences;
|
||||
}
|
||||
|
||||
public function loadEditorLink($path,
|
||||
$line,
|
||||
PhabricatorRepository $repository) {
|
||||
$editor = $this->loadPreferences()->getPreference(
|
||||
PhabricatorUserPreferences::PREFERENCE_EDITOR);
|
||||
if ($editor) {
|
||||
return strtr($editor, array(
|
||||
'%f' => phutil_escape_uri($path),
|
||||
'%l' => phutil_escape_uri($line),
|
||||
'%r' => phutil_escape_uri($repository->getCallsign()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private static function tokenizeName($name) {
|
||||
if (function_exists('mb_strtolower')) {
|
||||
$name = mb_strtolower($name, 'UTF-8');
|
||||
|
|
|
@ -20,6 +20,7 @@ phutil_require_module('phabricator', 'storage/qsprintf');
|
|||
phutil_require_module('phabricator', 'storage/queryfx');
|
||||
|
||||
phutil_require_module('phutil', 'filesystem');
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'parser/uri');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
|
|
@ -56,6 +56,15 @@ JX.behavior('differential-dropdown-menus', function(config) {
|
|||
if (data.rightURI) {
|
||||
menu.addItem(link_to('Show Raw File (Right)', data.rightURI));
|
||||
}
|
||||
if (data.editor) {
|
||||
menu.addItem(new JX.PhabricatorMenuItem(
|
||||
'Open in Editor',
|
||||
JX.bind(null, location.assign, data.editor), // Open in the same window.
|
||||
data.editor));
|
||||
}
|
||||
if (data.editorConfigure) {
|
||||
menu.addItem(link_to('Configure Editor', data.editorConfigure));
|
||||
}
|
||||
|
||||
menu.listen(
|
||||
'open',
|
||||
|
|
Loading…
Reference in a new issue