mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-29 18:22:41 +01:00
Add static errors, supported protocols, and a dynamic function listing to external editor settings page
Summary: Ref T13515. - Previously valid editor URIs may become invalid without being changed (if an administrator removes a protocol from the list, for example), but this isn't explained very well. Show an error on the settings page if the current value isn't usable. - Generate a list of functions from an authority in the parser. - Generate a list of protocols from configuration. Test Plan: {F7370872} Maniphest Tasks: T13515 Differential Revision: https://secure.phabricator.com/D21146
This commit is contained in:
parent
7a79131bf2
commit
c79094d7a8
6 changed files with 214 additions and 24 deletions
|
@ -7,6 +7,7 @@ final class PhabricatorSettingsEditEngine
|
||||||
|
|
||||||
private $isSelfEdit;
|
private $isSelfEdit;
|
||||||
private $profileURI;
|
private $profileURI;
|
||||||
|
private $settingsPanel;
|
||||||
|
|
||||||
public function setIsSelfEdit($is_self_edit) {
|
public function setIsSelfEdit($is_self_edit) {
|
||||||
$this->isSelfEdit = $is_self_edit;
|
$this->isSelfEdit = $is_self_edit;
|
||||||
|
@ -26,6 +27,15 @@ final class PhabricatorSettingsEditEngine
|
||||||
return $this->profileURI;
|
return $this->profileURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setSettingsPanel($settings_panel) {
|
||||||
|
$this->settingsPanel = $settings_panel;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSettingsPanel() {
|
||||||
|
return $this->settingsPanel;
|
||||||
|
}
|
||||||
|
|
||||||
public function isEngineConfigurable() {
|
public function isEngineConfigurable() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -252,13 +262,29 @@ final class PhabricatorSettingsEditEngine
|
||||||
protected function newEditFormHeadContent(
|
protected function newEditFormHeadContent(
|
||||||
PhabricatorEditEnginePageState $state) {
|
PhabricatorEditEnginePageState $state) {
|
||||||
|
|
||||||
|
$content = array();
|
||||||
|
|
||||||
if ($state->getIsSave()) {
|
if ($state->getIsSave()) {
|
||||||
return id(new PHUIInfoView())
|
$content[] = id(new PHUIInfoView())
|
||||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
|
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
|
||||||
->appendChild(pht('Changes saved.'));
|
->appendChild(pht('Changes saved.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
$panel = $this->getSettingsPanel();
|
||||||
|
$content[] = $panel->newSettingsPanelEditFormHeadContent($state);
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newEditFormTailContent(
|
||||||
|
PhabricatorEditEnginePageState $state) {
|
||||||
|
|
||||||
|
$content = array();
|
||||||
|
|
||||||
|
$panel = $this->getSettingsPanel();
|
||||||
|
$content[] = $panel->newSettingsPanelEditFormTailContent($state);
|
||||||
|
|
||||||
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ abstract class PhabricatorEditEngineSettingsPanel
|
||||||
$engine = id(new PhabricatorSettingsEditEngine())
|
$engine = id(new PhabricatorSettingsEditEngine())
|
||||||
->setController($this->getController())
|
->setController($this->getController())
|
||||||
->setNavigation($this->getNavigation())
|
->setNavigation($this->getNavigation())
|
||||||
|
->setSettingsPanel($this)
|
||||||
->setIsSelfEdit($is_self)
|
->setIsSelfEdit($is_self)
|
||||||
->setProfileURI($profile_uri);
|
->setProfileURI($profile_uri);
|
||||||
|
|
||||||
|
@ -71,4 +72,14 @@ abstract class PhabricatorEditEngineSettingsPanel
|
||||||
return mpull($panel_settings, 'getSettingKey');
|
return mpull($panel_settings, 'getSettingKey');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newSettingsPanelEditFormHeadContent(
|
||||||
|
PhabricatorEditEnginePageState $state) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newSettingsPanelEditFormTailContent(
|
||||||
|
PhabricatorEditEnginePageState $state) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,4 +21,150 @@ final class PhabricatorExternalEditorSettingsPanel
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newSettingsPanelEditFormHeadContent(
|
||||||
|
PhabricatorEditEnginePageState $state) {
|
||||||
|
|
||||||
|
// The "Editor" setting stored in the database may be invalidated by
|
||||||
|
// configuration or software changes. If a saved URI becomes invalid
|
||||||
|
// (for example, its protocol is removed from the list of allowed
|
||||||
|
// protocols), it will stop working.
|
||||||
|
|
||||||
|
// If the stored value has a problem like this, show a static error
|
||||||
|
// message without requiring the user to save changes.
|
||||||
|
|
||||||
|
if ($state->getIsSubmit()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$pattern = $viewer->getUserSetting(PhabricatorEditorSetting::SETTINGKEY);
|
||||||
|
|
||||||
|
if (!strlen($pattern)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$caught = null;
|
||||||
|
try {
|
||||||
|
id(new PhabricatorEditorURIEngine())
|
||||||
|
->setPattern($pattern)
|
||||||
|
->validatePattern();
|
||||||
|
} catch (PhabricatorEditorURIParserException $ex) {
|
||||||
|
$caught = $ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$caught) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id(new PHUIInfoView())
|
||||||
|
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
|
||||||
|
->appendChild($caught->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newSettingsPanelEditFormTailContent(
|
||||||
|
PhabricatorEditEnginePageState $state) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$variables = PhabricatorEditorURIEngine::getVariableDefinitions();
|
||||||
|
|
||||||
|
$rows = array();
|
||||||
|
foreach ($variables as $key => $variable) {
|
||||||
|
$rows[] = array(
|
||||||
|
phutil_tag('tt', array(), '%'.$key),
|
||||||
|
$variable['name'],
|
||||||
|
$variable['example'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = id(new AphrontTableView($rows))
|
||||||
|
->setHeaders(
|
||||||
|
array(
|
||||||
|
pht('Variable'),
|
||||||
|
pht('Replaced With'),
|
||||||
|
pht('Example'),
|
||||||
|
))
|
||||||
|
->setColumnClasses(
|
||||||
|
array(
|
||||||
|
'center',
|
||||||
|
'pri',
|
||||||
|
'wide',
|
||||||
|
));
|
||||||
|
|
||||||
|
$variables_box = id(new PHUIObjectBoxView())
|
||||||
|
->setBackground(PHUIObjectBoxView::WHITE_CONFIG)
|
||||||
|
->setHeaderText(pht('External Editor URI Variables'))
|
||||||
|
->setTable($table);
|
||||||
|
|
||||||
|
$label_map = array(
|
||||||
|
'http' => pht('Hypertext Transfer Protocol'),
|
||||||
|
'https' => pht('Hypertext Transfer Protocol over SSL'),
|
||||||
|
'txmt' => pht('TextMate'),
|
||||||
|
'mvim' => pht('MacVim'),
|
||||||
|
'subl' => pht('Sublime Text'),
|
||||||
|
'vim' => pht('Vim'),
|
||||||
|
'emacs' => pht('Emacs'),
|
||||||
|
'vscode' => pht('Visual Studio Code'),
|
||||||
|
'editor' => pht('Generic Editor'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$default_label = phutil_tag('em', array(), pht('Supported Protocol'));
|
||||||
|
|
||||||
|
$config_key = 'uri.allowed-editor-protocols';
|
||||||
|
|
||||||
|
$protocols = PhabricatorEnv::getEnvConfig($config_key);
|
||||||
|
$protocols = array_keys($protocols);
|
||||||
|
sort($protocols);
|
||||||
|
|
||||||
|
$protocol_rows = array();
|
||||||
|
foreach ($protocols as $protocol) {
|
||||||
|
$label = idx($label_map, $protocol, $default_label);
|
||||||
|
|
||||||
|
$protocol_rows[] = array(
|
||||||
|
$protocol.'://',
|
||||||
|
$label,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$protocol_table = id(new AphrontTableView($protocol_rows))
|
||||||
|
->setNoDataString(
|
||||||
|
pht(
|
||||||
|
'Phabricator is not configured to allow any editor protocols.'))
|
||||||
|
->setHeaders(
|
||||||
|
array(
|
||||||
|
pht('Protocol'),
|
||||||
|
pht('Description'),
|
||||||
|
))
|
||||||
|
->setColumnClasses(
|
||||||
|
array(
|
||||||
|
'pri',
|
||||||
|
'wide',
|
||||||
|
));
|
||||||
|
|
||||||
|
$is_admin = $viewer->getIsAdmin();
|
||||||
|
|
||||||
|
$configure_button = id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setText(pht('View Configuration'))
|
||||||
|
->setIcon('fa-sliders')
|
||||||
|
->setHref(
|
||||||
|
urisprintf(
|
||||||
|
'/config/edit/%s/',
|
||||||
|
$config_key))
|
||||||
|
->setDisabled(!$is_admin);
|
||||||
|
|
||||||
|
$protocol_header = id(new PHUIHeaderView())
|
||||||
|
->setHeader(pht('Supported Editor Protocols'))
|
||||||
|
->addActionLink($configure_button);
|
||||||
|
|
||||||
|
$protocols_box = id(new PHUIObjectBoxView())
|
||||||
|
->setBackground(PHUIObjectBoxView::WHITE_CONFIG)
|
||||||
|
->setHeader($protocol_header)
|
||||||
|
->setTable($protocol_table);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$variables_box,
|
||||||
|
$protocols_box,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,20 +20,23 @@ final class PhabricatorEditorSetting
|
||||||
protected function getControlInstructions() {
|
protected function getControlInstructions() {
|
||||||
return pht(
|
return pht(
|
||||||
"Many text editors can be configured as URI handlers for special ".
|
"Many text editors can be configured as URI handlers for special ".
|
||||||
"protocols like `editor://`. If you have such an editor, Phabricator ".
|
"protocols like `editor://`. If you have installed and configured ".
|
||||||
"can generate links that you can click to open files locally.".
|
"such an editor, Phabricator can generate links that you can click ".
|
||||||
|
"to open files locally.".
|
||||||
"\n\n".
|
"\n\n".
|
||||||
"These special variables are supported:".
|
"Provide a URI pattern for building external editor URIs in your ".
|
||||||
|
"environment. For example, if you use TextMate on macOS, the pattern ".
|
||||||
|
"for your machine look like this:".
|
||||||
"\n\n".
|
"\n\n".
|
||||||
"| Value | Replaced With |\n".
|
"```name=\"Example: TextMate on macOS\"\n".
|
||||||
"|-------|---------------|\n".
|
"%s\n".
|
||||||
"| `%%f` | Filename |\n".
|
"```\n".
|
||||||
"| `%%l` | Line Number |\n".
|
|
||||||
"| `%%r` | Repository Callsign |\n".
|
|
||||||
"| `%%%%` | Literal `%%` |\n".
|
|
||||||
"\n\n".
|
"\n\n".
|
||||||
"For complete instructions on editor configuration, ".
|
"For complete instructions on editor configuration, ".
|
||||||
"see **[[ %s | %s ]]**.",
|
"see **[[ %s | %s ]]**.".
|
||||||
|
"\n\n".
|
||||||
|
"See the tables below for a list of supported variables and protocols.",
|
||||||
|
'txmt://open/?url=file:///Users/alincoln/editor_links/%r/%f&line=%l',
|
||||||
PhabricatorEnv::getDoclink('User Guide: Configuring an External Editor'),
|
PhabricatorEnv::getDoclink('User Guide: Configuring an External Editor'),
|
||||||
pht('User Guide: Configuring an External Editor'));
|
pht('User Guide: Configuring an External Editor'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,14 @@
|
||||||
|
|
||||||
Setting up an external editor to integrate with Diffusion and Differential.
|
Setting up an external editor to integrate with Diffusion and Differential.
|
||||||
|
|
||||||
= Overview =
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
You can configure a URI handler to allow you to open files from Differential
|
You can configure a URI handler to allow you to open files from Differential
|
||||||
and Diffusion in your preferred text editor.
|
and Diffusion in your preferred text editor.
|
||||||
|
|
||||||
= Configuring Editors =
|
Configuring Editors
|
||||||
|
===================
|
||||||
|
|
||||||
To configure an external editor, go to {nav Settings > Application Settings >
|
To configure an external editor, go to {nav Settings > Application Settings >
|
||||||
External Editor} and set "Editor Link" to a URI pattern (see below). This
|
External Editor} and set "Editor Link" to a URI pattern (see below). This
|
||||||
|
@ -17,15 +19,12 @@ Diffusion.
|
||||||
|
|
||||||
In general, you'll set this field to something like:
|
In general, you'll set this field to something like:
|
||||||
|
|
||||||
lang=uri
|
```lang=uri
|
||||||
editor://open/?file=%f
|
editor://open/?file=%f
|
||||||
|
```
|
||||||
|
|
||||||
Some editors support opening multiple files at once when filenames are separated
|
Configuring: TextMate on macOS
|
||||||
by spaces. If your editor supports this feature, set "Edit Multiple Files" to
|
==============================
|
||||||
"Supported". Otherwise, you can set it to "Not Supported" to disable "Open All"
|
|
||||||
buttons in the interface.
|
|
||||||
|
|
||||||
== Configuring: TextMate on OS X ==
|
|
||||||
|
|
||||||
TextMate installs a `txmt://` handler by default, so it's easy to configure
|
TextMate installs a `txmt://` handler by default, so it's easy to configure
|
||||||
this feature if you use TextMate.
|
this feature if you use TextMate.
|
||||||
|
@ -40,5 +39,6 @@ example, if you're developing Phabricator, it might look like this:
|
||||||
|
|
||||||
Then set your "Editor Link" to:
|
Then set your "Editor Link" to:
|
||||||
|
|
||||||
lang=uri
|
```lang=uri
|
||||||
txmt://open/?url=file:///Users/alincoln/editor_links/%r/%f&line=%l
|
txmt://open/?url=file:///Users/alincoln/editor_links/%r/%f&line=%l
|
||||||
|
```
|
||||||
|
|
|
@ -92,15 +92,19 @@ final class PhabricatorEditorURIEngine
|
||||||
return array(
|
return array(
|
||||||
'%' => array(
|
'%' => array(
|
||||||
'name' => pht('Literal Percent Symbol'),
|
'name' => pht('Literal Percent Symbol'),
|
||||||
|
'example' => '%',
|
||||||
),
|
),
|
||||||
'r' => array(
|
'r' => array(
|
||||||
'name' => pht('Repository Callsign'),
|
'name' => pht('Repository Callsign'),
|
||||||
|
'example' => 'XYZ',
|
||||||
),
|
),
|
||||||
'f' => array(
|
'f' => array(
|
||||||
'name' => pht('File Name'),
|
'name' => pht('File Name'),
|
||||||
|
'example' => pht('path/to/source.c'),
|
||||||
),
|
),
|
||||||
'l' => array(
|
'l' => array(
|
||||||
'name' => pht('Line Number'),
|
'name' => pht('Line Number'),
|
||||||
|
'example' => '777',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue