mirror of
https://we.phorge.it/source/phorge.git
synced 2025-02-06 03:48:28 +01:00
Implement Graphviz, Figlet and Cowsay as Remarkup interpreter blocks
Summary: Fixes T3274. Fixes T3964. Ref T3591. Test Plan: {F70928} Reviewers: btrahan Reviewed By: btrahan CC: chad, aran Maniphest Tasks: T3274, T3964, T3591 Differential Revision: https://secure.phabricator.com/D7332
This commit is contained in:
parent
07b8c2cfd0
commit
b55cf56d2e
7 changed files with 206 additions and 46 deletions
|
@ -3433,7 +3433,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'phabricator-remarkup-css' =>
|
'phabricator-remarkup-css' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/7e8988dd/rsrc/css/core/remarkup.css',
|
'uri' => '/res/4c313572/rsrc/css/core/remarkup.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -4273,7 +4273,7 @@ celerity_register_resource_map(array(
|
||||||
), array(
|
), array(
|
||||||
'packages' =>
|
'packages' =>
|
||||||
array(
|
array(
|
||||||
'a4e76ef8' =>
|
'30de5267' =>
|
||||||
array(
|
array(
|
||||||
'name' => 'core.pkg.css',
|
'name' => 'core.pkg.css',
|
||||||
'symbols' =>
|
'symbols' =>
|
||||||
|
@ -4322,7 +4322,7 @@ celerity_register_resource_map(array(
|
||||||
41 => 'phabricator-tag-view-css',
|
41 => 'phabricator-tag-view-css',
|
||||||
42 => 'phui-list-view-css',
|
42 => 'phui-list-view-css',
|
||||||
),
|
),
|
||||||
'uri' => '/res/pkg/a4e76ef8/core.pkg.css',
|
'uri' => '/res/pkg/30de5267/core.pkg.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
),
|
),
|
||||||
'6041c6c8' =>
|
'6041c6c8' =>
|
||||||
|
@ -4514,15 +4514,15 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'reverse' =>
|
'reverse' =>
|
||||||
array(
|
array(
|
||||||
'aphront-dialog-view-css' => 'a4e76ef8',
|
'aphront-dialog-view-css' => '30de5267',
|
||||||
'aphront-error-view-css' => 'a4e76ef8',
|
'aphront-error-view-css' => '30de5267',
|
||||||
'aphront-list-filter-view-css' => 'a4e76ef8',
|
'aphront-list-filter-view-css' => '30de5267',
|
||||||
'aphront-pager-view-css' => 'a4e76ef8',
|
'aphront-pager-view-css' => '30de5267',
|
||||||
'aphront-panel-view-css' => 'a4e76ef8',
|
'aphront-panel-view-css' => '30de5267',
|
||||||
'aphront-table-view-css' => 'a4e76ef8',
|
'aphront-table-view-css' => '30de5267',
|
||||||
'aphront-tokenizer-control-css' => 'a4e76ef8',
|
'aphront-tokenizer-control-css' => '30de5267',
|
||||||
'aphront-tooltip-css' => 'a4e76ef8',
|
'aphront-tooltip-css' => '30de5267',
|
||||||
'aphront-typeahead-control-css' => 'a4e76ef8',
|
'aphront-typeahead-control-css' => '30de5267',
|
||||||
'differential-changeset-view-css' => '7cd7e387',
|
'differential-changeset-view-css' => '7cd7e387',
|
||||||
'differential-core-view-css' => '7cd7e387',
|
'differential-core-view-css' => '7cd7e387',
|
||||||
'differential-inline-comment-editor' => '5e9e5c4e',
|
'differential-inline-comment-editor' => '5e9e5c4e',
|
||||||
|
@ -4536,7 +4536,7 @@ celerity_register_resource_map(array(
|
||||||
'differential-table-of-contents-css' => '7cd7e387',
|
'differential-table-of-contents-css' => '7cd7e387',
|
||||||
'diffusion-commit-view-css' => '270f4eb4',
|
'diffusion-commit-view-css' => '270f4eb4',
|
||||||
'diffusion-icons-css' => '270f4eb4',
|
'diffusion-icons-css' => '270f4eb4',
|
||||||
'global-drag-and-drop-css' => 'a4e76ef8',
|
'global-drag-and-drop-css' => '30de5267',
|
||||||
'inline-comment-summary-css' => '7cd7e387',
|
'inline-comment-summary-css' => '7cd7e387',
|
||||||
'javelin-aphlict' => '6041c6c8',
|
'javelin-aphlict' => '6041c6c8',
|
||||||
'javelin-behavior' => '3e3be199',
|
'javelin-behavior' => '3e3be199',
|
||||||
|
@ -4611,56 +4611,56 @@ celerity_register_resource_map(array(
|
||||||
'javelin-util' => '3e3be199',
|
'javelin-util' => '3e3be199',
|
||||||
'javelin-vector' => '3e3be199',
|
'javelin-vector' => '3e3be199',
|
||||||
'javelin-workflow' => '3e3be199',
|
'javelin-workflow' => '3e3be199',
|
||||||
'lightbox-attachment-css' => 'a4e76ef8',
|
'lightbox-attachment-css' => '30de5267',
|
||||||
'maniphest-task-summary-css' => '49898640',
|
'maniphest-task-summary-css' => '49898640',
|
||||||
'phabricator-action-list-view-css' => 'a4e76ef8',
|
'phabricator-action-list-view-css' => '30de5267',
|
||||||
'phabricator-application-launch-view-css' => 'a4e76ef8',
|
'phabricator-application-launch-view-css' => '30de5267',
|
||||||
'phabricator-busy' => '6041c6c8',
|
'phabricator-busy' => '6041c6c8',
|
||||||
'phabricator-content-source-view-css' => '7cd7e387',
|
'phabricator-content-source-view-css' => '7cd7e387',
|
||||||
'phabricator-core-css' => 'a4e76ef8',
|
'phabricator-core-css' => '30de5267',
|
||||||
'phabricator-crumbs-view-css' => 'a4e76ef8',
|
'phabricator-crumbs-view-css' => '30de5267',
|
||||||
'phabricator-drag-and-drop-file-upload' => '5e9e5c4e',
|
'phabricator-drag-and-drop-file-upload' => '5e9e5c4e',
|
||||||
'phabricator-dropdown-menu' => '6041c6c8',
|
'phabricator-dropdown-menu' => '6041c6c8',
|
||||||
'phabricator-file-upload' => '6041c6c8',
|
'phabricator-file-upload' => '6041c6c8',
|
||||||
'phabricator-filetree-view-css' => 'a4e76ef8',
|
'phabricator-filetree-view-css' => '30de5267',
|
||||||
'phabricator-flag-css' => 'a4e76ef8',
|
'phabricator-flag-css' => '30de5267',
|
||||||
'phabricator-hovercard' => '6041c6c8',
|
'phabricator-hovercard' => '6041c6c8',
|
||||||
'phabricator-jump-nav' => 'a4e76ef8',
|
'phabricator-jump-nav' => '30de5267',
|
||||||
'phabricator-keyboard-shortcut' => '6041c6c8',
|
'phabricator-keyboard-shortcut' => '6041c6c8',
|
||||||
'phabricator-keyboard-shortcut-manager' => '6041c6c8',
|
'phabricator-keyboard-shortcut-manager' => '6041c6c8',
|
||||||
'phabricator-main-menu-view' => 'a4e76ef8',
|
'phabricator-main-menu-view' => '30de5267',
|
||||||
'phabricator-menu-item' => '6041c6c8',
|
'phabricator-menu-item' => '6041c6c8',
|
||||||
'phabricator-nav-view-css' => 'a4e76ef8',
|
'phabricator-nav-view-css' => '30de5267',
|
||||||
'phabricator-notification' => '6041c6c8',
|
'phabricator-notification' => '6041c6c8',
|
||||||
'phabricator-notification-css' => 'a4e76ef8',
|
'phabricator-notification-css' => '30de5267',
|
||||||
'phabricator-notification-menu-css' => 'a4e76ef8',
|
'phabricator-notification-menu-css' => '30de5267',
|
||||||
'phabricator-object-selector-css' => '7cd7e387',
|
'phabricator-object-selector-css' => '7cd7e387',
|
||||||
'phabricator-phtize' => '6041c6c8',
|
'phabricator-phtize' => '6041c6c8',
|
||||||
'phabricator-prefab' => '6041c6c8',
|
'phabricator-prefab' => '6041c6c8',
|
||||||
'phabricator-project-tag-css' => '49898640',
|
'phabricator-project-tag-css' => '49898640',
|
||||||
'phabricator-remarkup-css' => 'a4e76ef8',
|
'phabricator-remarkup-css' => '30de5267',
|
||||||
'phabricator-shaped-request' => '5e9e5c4e',
|
'phabricator-shaped-request' => '5e9e5c4e',
|
||||||
'phabricator-side-menu-view-css' => 'a4e76ef8',
|
'phabricator-side-menu-view-css' => '30de5267',
|
||||||
'phabricator-standard-page-view' => 'a4e76ef8',
|
'phabricator-standard-page-view' => '30de5267',
|
||||||
'phabricator-tag-view-css' => 'a4e76ef8',
|
'phabricator-tag-view-css' => '30de5267',
|
||||||
'phabricator-textareautils' => '6041c6c8',
|
'phabricator-textareautils' => '6041c6c8',
|
||||||
'phabricator-tooltip' => '6041c6c8',
|
'phabricator-tooltip' => '6041c6c8',
|
||||||
'phabricator-transaction-view-css' => 'a4e76ef8',
|
'phabricator-transaction-view-css' => '30de5267',
|
||||||
'phabricator-zindex-css' => 'a4e76ef8',
|
'phabricator-zindex-css' => '30de5267',
|
||||||
'phui-button-css' => 'a4e76ef8',
|
'phui-button-css' => '30de5267',
|
||||||
'phui-form-css' => 'a4e76ef8',
|
'phui-form-css' => '30de5267',
|
||||||
'phui-form-view-css' => 'a4e76ef8',
|
'phui-form-view-css' => '30de5267',
|
||||||
'phui-header-view-css' => 'a4e76ef8',
|
'phui-header-view-css' => '30de5267',
|
||||||
'phui-icon-view-css' => 'a4e76ef8',
|
'phui-icon-view-css' => '30de5267',
|
||||||
'phui-list-view-css' => 'a4e76ef8',
|
'phui-list-view-css' => '30de5267',
|
||||||
'phui-object-item-list-view-css' => 'a4e76ef8',
|
'phui-object-item-list-view-css' => '30de5267',
|
||||||
'phui-property-list-view-css' => 'a4e76ef8',
|
'phui-property-list-view-css' => '30de5267',
|
||||||
'phui-spacing-css' => 'a4e76ef8',
|
'phui-spacing-css' => '30de5267',
|
||||||
'sprite-apps-large-css' => 'a4e76ef8',
|
'sprite-apps-large-css' => '30de5267',
|
||||||
'sprite-gradient-css' => 'a4e76ef8',
|
'sprite-gradient-css' => '30de5267',
|
||||||
'sprite-icons-css' => 'a4e76ef8',
|
'sprite-icons-css' => '30de5267',
|
||||||
'sprite-menu-css' => 'a4e76ef8',
|
'sprite-menu-css' => '30de5267',
|
||||||
'sprite-status-css' => 'a4e76ef8',
|
'sprite-status-css' => '30de5267',
|
||||||
'syntax-highlighting-css' => 'a4e76ef8',
|
'syntax-highlighting-css' => '30de5267',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
@ -1536,6 +1536,9 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php',
|
'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php',
|
||||||
'PhabricatorRefreshCSRFController' => 'applications/auth/controller/PhabricatorRefreshCSRFController.php',
|
'PhabricatorRefreshCSRFController' => 'applications/auth/controller/PhabricatorRefreshCSRFController.php',
|
||||||
'PhabricatorRegistrationProfile' => 'applications/people/storage/PhabricatorRegistrationProfile.php',
|
'PhabricatorRegistrationProfile' => 'applications/people/storage/PhabricatorRegistrationProfile.php',
|
||||||
|
'PhabricatorRemarkupBlockInterpreterCowsay' => 'infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterCowsay.php',
|
||||||
|
'PhabricatorRemarkupBlockInterpreterFiglet' => 'infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterFiglet.php',
|
||||||
|
'PhabricatorRemarkupBlockInterpreterGraphviz' => 'infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterGraphviz.php',
|
||||||
'PhabricatorRemarkupControl' => 'view/form/control/PhabricatorRemarkupControl.php',
|
'PhabricatorRemarkupControl' => 'view/form/control/PhabricatorRemarkupControl.php',
|
||||||
'PhabricatorRemarkupRuleEmbedFile' => 'applications/files/remarkup/PhabricatorRemarkupRuleEmbedFile.php',
|
'PhabricatorRemarkupRuleEmbedFile' => 'applications/files/remarkup/PhabricatorRemarkupRuleEmbedFile.php',
|
||||||
'PhabricatorRemarkupRuleImageMacro' => 'applications/macro/remarkup/PhabricatorRemarkupRuleImageMacro.php',
|
'PhabricatorRemarkupRuleImageMacro' => 'applications/macro/remarkup/PhabricatorRemarkupRuleImageMacro.php',
|
||||||
|
@ -3747,6 +3750,9 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRedirectController' => 'PhabricatorController',
|
'PhabricatorRedirectController' => 'PhabricatorController',
|
||||||
'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController',
|
'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController',
|
||||||
'PhabricatorRegistrationProfile' => 'Phobject',
|
'PhabricatorRegistrationProfile' => 'Phobject',
|
||||||
|
'PhabricatorRemarkupBlockInterpreterCowsay' => 'PhutilRemarkupBlockInterpreter',
|
||||||
|
'PhabricatorRemarkupBlockInterpreterFiglet' => 'PhutilRemarkupBlockInterpreter',
|
||||||
|
'PhabricatorRemarkupBlockInterpreterGraphviz' => 'PhutilRemarkupBlockInterpreter',
|
||||||
'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl',
|
'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl',
|
||||||
'PhabricatorRemarkupRuleEmbedFile' => 'PhabricatorRemarkupRuleObject',
|
'PhabricatorRemarkupRuleEmbedFile' => 'PhabricatorRemarkupRuleObject',
|
||||||
'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule',
|
'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule',
|
||||||
|
|
|
@ -460,6 +460,7 @@ final class PhabricatorMarkupEngine {
|
||||||
$blocks[] = new PhutilRemarkupEngineRemarkupNoteBlockRule();
|
$blocks[] = new PhutilRemarkupEngineRemarkupNoteBlockRule();
|
||||||
$blocks[] = new PhutilRemarkupEngineRemarkupTableBlockRule();
|
$blocks[] = new PhutilRemarkupEngineRemarkupTableBlockRule();
|
||||||
$blocks[] = new PhutilRemarkupEngineRemarkupSimpleTableBlockRule();
|
$blocks[] = new PhutilRemarkupEngineRemarkupSimpleTableBlockRule();
|
||||||
|
$blocks[] = new PhutilRemarkupEngineRemarkupInterpreterRule();
|
||||||
|
|
||||||
$custom_block_rule_classes = $options['custom-block'];
|
$custom_block_rule_classes = $options['custom-block'];
|
||||||
if ($custom_block_rule_classes) {
|
if ($custom_block_rule_classes) {
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorRemarkupBlockInterpreterCowsay
|
||||||
|
extends PhutilRemarkupBlockInterpreter {
|
||||||
|
|
||||||
|
public function getInterpreterName() {
|
||||||
|
return 'cowsay';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function markupContent($content, array $argv) {
|
||||||
|
if (!Filesystem::binaryExists('cowsay')) {
|
||||||
|
return $this->markupError(
|
||||||
|
pht('Unable to locate the `cowsay` binary. Install cowsay.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$bin = idx($argv, 'think') ? 'cowthink' : 'cowsay';
|
||||||
|
$eyes = idx($argv, 'eyes', 'oo');
|
||||||
|
$tongue = idx($argv, 'tongue', ' ');
|
||||||
|
$cow = idx($argv, 'cow', 'default');
|
||||||
|
|
||||||
|
// NOTE: Strip this aggressively to prevent nonsense like
|
||||||
|
// `cow=/etc/passwd`. We could build a whiltelist with `cowsay -l`.
|
||||||
|
$cow = preg_replace('/[^a-z.-]+/', '', $cow);
|
||||||
|
|
||||||
|
$future = new ExecFuture(
|
||||||
|
'%s -e %s -T %s -f %s ',
|
||||||
|
$bin,
|
||||||
|
$eyes,
|
||||||
|
$tongue,
|
||||||
|
$cow);
|
||||||
|
|
||||||
|
$future->write($content);
|
||||||
|
|
||||||
|
list($err, $stdout, $stderr) = $future->resolve();
|
||||||
|
|
||||||
|
if ($err) {
|
||||||
|
return $this->markupError(
|
||||||
|
pht(
|
||||||
|
'Execution of `cowsay` failed:', $stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($this->getEngine()->isTextMode()) {
|
||||||
|
return $stdout;
|
||||||
|
}
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'PhabricatorMonospaced remarkup-cowsay',
|
||||||
|
),
|
||||||
|
$stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorRemarkupBlockInterpreterFiglet
|
||||||
|
extends PhutilRemarkupBlockInterpreter {
|
||||||
|
|
||||||
|
public function getInterpreterName() {
|
||||||
|
return 'figlet';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function markupContent($content, array $argv) {
|
||||||
|
if (!Filesystem::binaryExists('figlet')) {
|
||||||
|
return $this->markupError(
|
||||||
|
pht('Unable to locate the `figlet` binary. Install figlet.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$future = id(new ExecFuture('figlet'))
|
||||||
|
->write(trim($content, "\n"));
|
||||||
|
|
||||||
|
list($err, $stdout, $stderr) = $future->resolve();
|
||||||
|
|
||||||
|
if ($err) {
|
||||||
|
return $this->markupError(
|
||||||
|
pht(
|
||||||
|
'Execution of `figlet` failed:', $stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($this->getEngine()->isTextMode()) {
|
||||||
|
return $stdout;
|
||||||
|
}
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'PhabricatorMonospaced remarkup-figlet',
|
||||||
|
),
|
||||||
|
$stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorRemarkupBlockInterpreterGraphviz
|
||||||
|
extends PhutilRemarkupBlockInterpreter {
|
||||||
|
|
||||||
|
public function getInterpreterName() {
|
||||||
|
return 'dot';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function markupContent($content, array $argv) {
|
||||||
|
if (!Filesystem::binaryExists('dot')) {
|
||||||
|
return $this->markupError(
|
||||||
|
pht('Unable to locate the `dot` binary. Install Graphviz.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$future = id(new ExecFuture('dot -T%s', 'png'))
|
||||||
|
->write(trim($content));
|
||||||
|
|
||||||
|
list($err, $stdout, $stderr) = $future->resolve();
|
||||||
|
|
||||||
|
if ($err) {
|
||||||
|
return $this->markupError(
|
||||||
|
pht(
|
||||||
|
'Execution of `dot` failed, check your syntax: %s', $stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = PhabricatorFile::buildFromFileDataOrHash(
|
||||||
|
$stdout,
|
||||||
|
array(
|
||||||
|
'name' => 'graphviz.png',
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($this->getEngine()->isTextMode()) {
|
||||||
|
return '<'.$file->getBestURI().'>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'img',
|
||||||
|
array(
|
||||||
|
'src' => $file->getBestURI(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -329,6 +329,20 @@
|
||||||
border-right: 1px solid #cccccc;
|
border-right: 1px solid #cccccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.remarkup-interpreter-error {
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid {$red};
|
||||||
|
background-color: {$lightred};
|
||||||
|
}
|
||||||
|
|
||||||
|
.remarkup-cowsay {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remarkup-figlet {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
.remarkup-assist {
|
.remarkup-assist {
|
||||||
display: block;
|
display: block;
|
||||||
width: 14px;
|
width: 14px;
|
||||||
|
|
Loading…
Add table
Reference in a new issue