1
0
Fork 0
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:
epriestley 2020-04-18 15:59:30 -07:00
parent 7a79131bf2
commit c79094d7a8
6 changed files with 214 additions and 24 deletions

View file

@ -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;
} }
} }

View file

@ -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;
}
} }

View file

@ -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,
);
}
} }

View file

@ -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'));
} }

View file

@ -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
```

View file

@ -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',
), ),
); );
} }