1
0
Fork 0
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:
vrana 2012-01-16 11:08:54 -08:00
parent 79218b6e47
commit 067c7f8a74
12 changed files with 107 additions and 28 deletions

View file

@ -330,16 +330,6 @@ celerity_register_resource_map(array(
), ),
'disk' => '/rsrc/js/javelin/lib/behavior.js', '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' => 'javelin-behavior-aphront-basic-tokenizer' =>
array( array(
'uri' => '/res/9be30797/rsrc/js/application/core/behavior-tokenizer.js', 'uri' => '/res/9be30797/rsrc/js/application/core/behavior-tokenizer.js',
@ -471,7 +461,7 @@ celerity_register_resource_map(array(
), ),
'javelin-behavior-differential-dropdown-menus' => 'javelin-behavior-differential-dropdown-menus' =>
array( 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', 'type' => 'js',
'requires' => 'requires' =>
array( array(
@ -1437,18 +1427,6 @@ celerity_register_resource_map(array(
), ),
'disk' => '/rsrc/css/application/objectselector/object-selector.css', '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' => 'phabricator-profile-css' =>
array( array(
'uri' => '/res/9869d10b/rsrc/css/application/profile/profile-view.css', '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', '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' => 'phabricator-remarkup-css' =>
array( array(
'uri' => '/res/39f358b8/rsrc/css/core/remarkup.css', 'uri' => '/res/39f358b8/rsrc/css/core/remarkup.css',

View file

@ -1,7 +1,7 @@
<?php <?php
/* /*
* Copyright 2011 Facebook, Inc. * Copyright 2012 Facebook, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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()) $details = id(new DifferentialChangesetListView())
->setChangesets($changesets) ->setChangesets($changesets)
->setRenderingReferences($refs); ->setRenderingReferences($refs)
->setUser($request->getUser());
return $this->buildStandardPageResponse( return $this->buildStandardPageResponse(
id(new DifferentialPrimaryPaneView()) id(new DifferentialPrimaryPaneView())

View file

@ -238,6 +238,7 @@ class DifferentialRevisionViewController extends DifferentialController {
$changeset_view->setChangesets($visible_changesets); $changeset_view->setChangesets($visible_changesets);
$changeset_view->setEditable(!$viewer_is_anonymous); $changeset_view->setEditable(!$viewer_is_anonymous);
$changeset_view->setStandaloneViews(true); $changeset_view->setStandaloneViews(true);
$changeset_view->setUser($user);
$changeset_view->setRevision($revision); $changeset_view->setRevision($revision);
$changeset_view->setDiff($target); $changeset_view->setDiff($target);
$changeset_view->setRenderingReferences($rendering_references); $changeset_view->setRenderingReferences($rendering_references);

View file

@ -25,6 +25,7 @@ class DifferentialChangesetListView extends AphrontView {
private $renderURI = '/differential/changeset/'; private $renderURI = '/differential/changeset/';
private $whitespace; private $whitespace;
private $standaloneViews; private $standaloneViews;
private $user;
private $symbolIndexes = array(); private $symbolIndexes = array();
private $repository; private $repository;
private $diff; private $diff;
@ -44,6 +45,11 @@ class DifferentialChangesetListView extends AphrontView {
return $this; return $this;
} }
public function setUser(PhabricatorUser $user) {
$this->user = $user;
return $this;
}
public function setRevision(DifferentialRevision $revision) { public function setRevision(DifferentialRevision $revision) {
$this->revision = $revision; $this->revision = $revision;
return $this; return $this;
@ -133,6 +139,19 @@ class DifferentialChangesetListView extends AphrontView {
$meta['rightURI'] = (string)$detail_uri->alter('view', 'new'); $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( $detail_button = javelin_render_tag(
'a', 'a',
array( array(
@ -145,7 +164,6 @@ class DifferentialChangesetListView extends AphrontView {
"View Options \xE2\x96\xBC"); "View Options \xE2\x96\xBC");
} }
$detail->setChangeset($changeset); $detail->setChangeset($changeset);
$detail->addButton($detail_button); $detail->addButton($detail_button);
$detail->setSymbolIndex(idx($this->symbolIndexes, $key)); $detail->setSymbolIndex(idx($this->symbolIndexes, $key));

View file

@ -1,7 +1,7 @@
<?php <?php
/* /*
* Copyright 2011 Facebook, Inc. * Copyright 2012 Facebook, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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/'); '/diffusion/'.$drequest->getRepository()->getCallsign().'/diff/');
$changeset_view->setWhitespace( $changeset_view->setWhitespace(
DifferentialChangesetParser::WHITESPACE_SHOW_ALL); DifferentialChangesetParser::WHITESPACE_SHOW_ALL);
$changeset_view->setUser($this->getRequest()->getUser());
$content[] = $this->buildCrumbs( $content[] = $this->buildCrumbs(
array( array(

View file

@ -200,6 +200,7 @@ class DiffusionCommitController extends DiffusionController {
$change_list->setChangesets($changesets); $change_list->setChangesets($changesets);
$change_list->setRenderingReferences($references); $change_list->setRenderingReferences($references);
$change_list->setRenderURI('/diffusion/'.$callsign.'/diff/'); $change_list->setRenderURI('/diffusion/'.$callsign.'/diff/');
$change_list->setUser($user);
// TODO: This is pretty awkward, unify the CSS between Diffusion and // TODO: This is pretty awkward, unify the CSS between Diffusion and
// Differential better. // Differential better.

View file

@ -1,7 +1,7 @@
<?php <?php
/* /*
* Copyright 2011 Facebook, Inc. * Copyright 2012 Facebook, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -95,6 +95,25 @@ class DiffusionBrowseFileController extends DiffusionController {
$select. $select.
'<button>View</button>'); '<button>View</button>');
$view_select_panel->appendChild($view_select_form); $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>'); $view_select_panel->appendChild('<div style="clear: both;"></div>');
// Build the content of the file. // Build the content of the file.

View file

@ -26,6 +26,7 @@ class PhabricatorUserPreferenceSettingsPanelController
$preferences = $user->loadPreferences(); $preferences = $user->loadPreferences();
$pref_monospaced = PhabricatorUserPreferences::PREFERENCE_MONOSPACED; $pref_monospaced = PhabricatorUserPreferences::PREFERENCE_MONOSPACED;
$pref_editor = PhabricatorUserPreferences::PREFERENCE_EDITOR;
$pref_titles = PhabricatorUserPreferences::PREFERENCE_TITLES; $pref_titles = PhabricatorUserPreferences::PREFERENCE_TITLES;
if ($request->isFormPost()) { if ($request->isFormPost()) {
@ -35,6 +36,7 @@ class PhabricatorUserPreferenceSettingsPanelController
$monospaced = preg_replace('/[^a-z0-9 ,"]+/i', '', $monospaced); $monospaced = preg_replace('/[^a-z0-9 ,"]+/i', '', $monospaced);
$preferences->setPreference($pref_titles, $request->getStr($pref_titles)); $preferences->setPreference($pref_titles, $request->getStr($pref_titles));
$preferences->setPreference($pref_editor, $request->getStr($pref_editor));
$preferences->setPreference($pref_monospaced, $monospaced); $preferences->setPreference($pref_monospaced, $monospaced);
$preferences->save(); $preferences->save();
@ -64,6 +66,15 @@ EXAMPLE;
'text' => 'text' =>
'In page titles, show Tool names as plain text: [Differential]', '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( ->appendChild(
id(new AphrontFormTextControl()) id(new AphrontFormTextControl())
->setLabel('Monospaced Font') ->setLabel('Monospaced Font')

View file

@ -19,6 +19,7 @@
class PhabricatorUserPreferences extends PhabricatorUserDAO { class PhabricatorUserPreferences extends PhabricatorUserDAO {
const PREFERENCE_MONOSPACED = 'monospaced'; const PREFERENCE_MONOSPACED = 'monospaced';
const PREFERENCE_EDITOR = 'editor';
const PREFERENCE_TITLES = 'titles'; const PREFERENCE_TITLES = 'titles';
const PREFERENCE_RE_PREFIX = 're-prefix'; const PREFERENCE_RE_PREFIX = 're-prefix';

View file

@ -403,6 +403,7 @@ class PhabricatorUser extends PhabricatorUserDAO {
$default_dict = array( $default_dict = array(
PhabricatorUserPreferences::PREFERENCE_TITLES => 'glyph', PhabricatorUserPreferences::PREFERENCE_TITLES => 'glyph',
PhabricatorUserPreferences::PREFERENCE_EDITOR => '',
PhabricatorUserPreferences::PREFERENCE_MONOSPACED => ''); PhabricatorUserPreferences::PREFERENCE_MONOSPACED => '');
$preferences->setPreferences($default_dict); $preferences->setPreferences($default_dict);
@ -412,6 +413,20 @@ class PhabricatorUser extends PhabricatorUserDAO {
return $preferences; 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) { private static function tokenizeName($name) {
if (function_exists('mb_strtolower')) { if (function_exists('mb_strtolower')) {
$name = mb_strtolower($name, 'UTF-8'); $name = mb_strtolower($name, 'UTF-8');

View file

@ -20,6 +20,7 @@ phutil_require_module('phabricator', 'storage/qsprintf');
phutil_require_module('phabricator', 'storage/queryfx'); phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_module('phutil', 'filesystem'); phutil_require_module('phutil', 'filesystem');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'parser/uri'); phutil_require_module('phutil', 'parser/uri');
phutil_require_module('phutil', 'utils'); phutil_require_module('phutil', 'utils');

View file

@ -56,6 +56,15 @@ JX.behavior('differential-dropdown-menus', function(config) {
if (data.rightURI) { if (data.rightURI) {
menu.addItem(link_to('Show Raw File (Right)', 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( menu.listen(
'open', 'open',