mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +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' =>
|
||||
array(
|
||||
'uri' => '/res/7e8988dd/rsrc/css/core/remarkup.css',
|
||||
'uri' => '/res/4c313572/rsrc/css/core/remarkup.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -4273,7 +4273,7 @@ celerity_register_resource_map(array(
|
|||
), array(
|
||||
'packages' =>
|
||||
array(
|
||||
'a4e76ef8' =>
|
||||
'30de5267' =>
|
||||
array(
|
||||
'name' => 'core.pkg.css',
|
||||
'symbols' =>
|
||||
|
@ -4322,7 +4322,7 @@ celerity_register_resource_map(array(
|
|||
41 => 'phabricator-tag-view-css',
|
||||
42 => 'phui-list-view-css',
|
||||
),
|
||||
'uri' => '/res/pkg/a4e76ef8/core.pkg.css',
|
||||
'uri' => '/res/pkg/30de5267/core.pkg.css',
|
||||
'type' => 'css',
|
||||
),
|
||||
'6041c6c8' =>
|
||||
|
@ -4514,15 +4514,15 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'reverse' =>
|
||||
array(
|
||||
'aphront-dialog-view-css' => 'a4e76ef8',
|
||||
'aphront-error-view-css' => 'a4e76ef8',
|
||||
'aphront-list-filter-view-css' => 'a4e76ef8',
|
||||
'aphront-pager-view-css' => 'a4e76ef8',
|
||||
'aphront-panel-view-css' => 'a4e76ef8',
|
||||
'aphront-table-view-css' => 'a4e76ef8',
|
||||
'aphront-tokenizer-control-css' => 'a4e76ef8',
|
||||
'aphront-tooltip-css' => 'a4e76ef8',
|
||||
'aphront-typeahead-control-css' => 'a4e76ef8',
|
||||
'aphront-dialog-view-css' => '30de5267',
|
||||
'aphront-error-view-css' => '30de5267',
|
||||
'aphront-list-filter-view-css' => '30de5267',
|
||||
'aphront-pager-view-css' => '30de5267',
|
||||
'aphront-panel-view-css' => '30de5267',
|
||||
'aphront-table-view-css' => '30de5267',
|
||||
'aphront-tokenizer-control-css' => '30de5267',
|
||||
'aphront-tooltip-css' => '30de5267',
|
||||
'aphront-typeahead-control-css' => '30de5267',
|
||||
'differential-changeset-view-css' => '7cd7e387',
|
||||
'differential-core-view-css' => '7cd7e387',
|
||||
'differential-inline-comment-editor' => '5e9e5c4e',
|
||||
|
@ -4536,7 +4536,7 @@ celerity_register_resource_map(array(
|
|||
'differential-table-of-contents-css' => '7cd7e387',
|
||||
'diffusion-commit-view-css' => '270f4eb4',
|
||||
'diffusion-icons-css' => '270f4eb4',
|
||||
'global-drag-and-drop-css' => 'a4e76ef8',
|
||||
'global-drag-and-drop-css' => '30de5267',
|
||||
'inline-comment-summary-css' => '7cd7e387',
|
||||
'javelin-aphlict' => '6041c6c8',
|
||||
'javelin-behavior' => '3e3be199',
|
||||
|
@ -4611,56 +4611,56 @@ celerity_register_resource_map(array(
|
|||
'javelin-util' => '3e3be199',
|
||||
'javelin-vector' => '3e3be199',
|
||||
'javelin-workflow' => '3e3be199',
|
||||
'lightbox-attachment-css' => 'a4e76ef8',
|
||||
'lightbox-attachment-css' => '30de5267',
|
||||
'maniphest-task-summary-css' => '49898640',
|
||||
'phabricator-action-list-view-css' => 'a4e76ef8',
|
||||
'phabricator-application-launch-view-css' => 'a4e76ef8',
|
||||
'phabricator-action-list-view-css' => '30de5267',
|
||||
'phabricator-application-launch-view-css' => '30de5267',
|
||||
'phabricator-busy' => '6041c6c8',
|
||||
'phabricator-content-source-view-css' => '7cd7e387',
|
||||
'phabricator-core-css' => 'a4e76ef8',
|
||||
'phabricator-crumbs-view-css' => 'a4e76ef8',
|
||||
'phabricator-core-css' => '30de5267',
|
||||
'phabricator-crumbs-view-css' => '30de5267',
|
||||
'phabricator-drag-and-drop-file-upload' => '5e9e5c4e',
|
||||
'phabricator-dropdown-menu' => '6041c6c8',
|
||||
'phabricator-file-upload' => '6041c6c8',
|
||||
'phabricator-filetree-view-css' => 'a4e76ef8',
|
||||
'phabricator-flag-css' => 'a4e76ef8',
|
||||
'phabricator-filetree-view-css' => '30de5267',
|
||||
'phabricator-flag-css' => '30de5267',
|
||||
'phabricator-hovercard' => '6041c6c8',
|
||||
'phabricator-jump-nav' => 'a4e76ef8',
|
||||
'phabricator-jump-nav' => '30de5267',
|
||||
'phabricator-keyboard-shortcut' => '6041c6c8',
|
||||
'phabricator-keyboard-shortcut-manager' => '6041c6c8',
|
||||
'phabricator-main-menu-view' => 'a4e76ef8',
|
||||
'phabricator-main-menu-view' => '30de5267',
|
||||
'phabricator-menu-item' => '6041c6c8',
|
||||
'phabricator-nav-view-css' => 'a4e76ef8',
|
||||
'phabricator-nav-view-css' => '30de5267',
|
||||
'phabricator-notification' => '6041c6c8',
|
||||
'phabricator-notification-css' => 'a4e76ef8',
|
||||
'phabricator-notification-menu-css' => 'a4e76ef8',
|
||||
'phabricator-notification-css' => '30de5267',
|
||||
'phabricator-notification-menu-css' => '30de5267',
|
||||
'phabricator-object-selector-css' => '7cd7e387',
|
||||
'phabricator-phtize' => '6041c6c8',
|
||||
'phabricator-prefab' => '6041c6c8',
|
||||
'phabricator-project-tag-css' => '49898640',
|
||||
'phabricator-remarkup-css' => 'a4e76ef8',
|
||||
'phabricator-remarkup-css' => '30de5267',
|
||||
'phabricator-shaped-request' => '5e9e5c4e',
|
||||
'phabricator-side-menu-view-css' => 'a4e76ef8',
|
||||
'phabricator-standard-page-view' => 'a4e76ef8',
|
||||
'phabricator-tag-view-css' => 'a4e76ef8',
|
||||
'phabricator-side-menu-view-css' => '30de5267',
|
||||
'phabricator-standard-page-view' => '30de5267',
|
||||
'phabricator-tag-view-css' => '30de5267',
|
||||
'phabricator-textareautils' => '6041c6c8',
|
||||
'phabricator-tooltip' => '6041c6c8',
|
||||
'phabricator-transaction-view-css' => 'a4e76ef8',
|
||||
'phabricator-zindex-css' => 'a4e76ef8',
|
||||
'phui-button-css' => 'a4e76ef8',
|
||||
'phui-form-css' => 'a4e76ef8',
|
||||
'phui-form-view-css' => 'a4e76ef8',
|
||||
'phui-header-view-css' => 'a4e76ef8',
|
||||
'phui-icon-view-css' => 'a4e76ef8',
|
||||
'phui-list-view-css' => 'a4e76ef8',
|
||||
'phui-object-item-list-view-css' => 'a4e76ef8',
|
||||
'phui-property-list-view-css' => 'a4e76ef8',
|
||||
'phui-spacing-css' => 'a4e76ef8',
|
||||
'sprite-apps-large-css' => 'a4e76ef8',
|
||||
'sprite-gradient-css' => 'a4e76ef8',
|
||||
'sprite-icons-css' => 'a4e76ef8',
|
||||
'sprite-menu-css' => 'a4e76ef8',
|
||||
'sprite-status-css' => 'a4e76ef8',
|
||||
'syntax-highlighting-css' => 'a4e76ef8',
|
||||
'phabricator-transaction-view-css' => '30de5267',
|
||||
'phabricator-zindex-css' => '30de5267',
|
||||
'phui-button-css' => '30de5267',
|
||||
'phui-form-css' => '30de5267',
|
||||
'phui-form-view-css' => '30de5267',
|
||||
'phui-header-view-css' => '30de5267',
|
||||
'phui-icon-view-css' => '30de5267',
|
||||
'phui-list-view-css' => '30de5267',
|
||||
'phui-object-item-list-view-css' => '30de5267',
|
||||
'phui-property-list-view-css' => '30de5267',
|
||||
'phui-spacing-css' => '30de5267',
|
||||
'sprite-apps-large-css' => '30de5267',
|
||||
'sprite-gradient-css' => '30de5267',
|
||||
'sprite-icons-css' => '30de5267',
|
||||
'sprite-menu-css' => '30de5267',
|
||||
'sprite-status-css' => '30de5267',
|
||||
'syntax-highlighting-css' => '30de5267',
|
||||
),
|
||||
));
|
||||
|
|
|
@ -1536,6 +1536,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php',
|
||||
'PhabricatorRefreshCSRFController' => 'applications/auth/controller/PhabricatorRefreshCSRFController.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',
|
||||
'PhabricatorRemarkupRuleEmbedFile' => 'applications/files/remarkup/PhabricatorRemarkupRuleEmbedFile.php',
|
||||
'PhabricatorRemarkupRuleImageMacro' => 'applications/macro/remarkup/PhabricatorRemarkupRuleImageMacro.php',
|
||||
|
@ -3747,6 +3750,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRedirectController' => 'PhabricatorController',
|
||||
'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController',
|
||||
'PhabricatorRegistrationProfile' => 'Phobject',
|
||||
'PhabricatorRemarkupBlockInterpreterCowsay' => 'PhutilRemarkupBlockInterpreter',
|
||||
'PhabricatorRemarkupBlockInterpreterFiglet' => 'PhutilRemarkupBlockInterpreter',
|
||||
'PhabricatorRemarkupBlockInterpreterGraphviz' => 'PhutilRemarkupBlockInterpreter',
|
||||
'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl',
|
||||
'PhabricatorRemarkupRuleEmbedFile' => 'PhabricatorRemarkupRuleObject',
|
||||
'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule',
|
||||
|
|
|
@ -460,6 +460,7 @@ final class PhabricatorMarkupEngine {
|
|||
$blocks[] = new PhutilRemarkupEngineRemarkupNoteBlockRule();
|
||||
$blocks[] = new PhutilRemarkupEngineRemarkupTableBlockRule();
|
||||
$blocks[] = new PhutilRemarkupEngineRemarkupSimpleTableBlockRule();
|
||||
$blocks[] = new PhutilRemarkupEngineRemarkupInterpreterRule();
|
||||
|
||||
$custom_block_rule_classes = $options['custom-block'];
|
||||
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;
|
||||
}
|
||||
|
||||
.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 {
|
||||
display: block;
|
||||
width: 14px;
|
||||
|
|
Loading…
Reference in a new issue