Page MenuHomePhabricator

D7332.diff

diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php
--- a/src/__celerity_resource_map__.php
+++ b/src/__celerity_resource_map__.php
@@ -3433,7 +3433,7 @@
),
'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 @@
), array(
'packages' =>
array(
- 'a4e76ef8' =>
+ '30de5267' =>
array(
'name' => 'core.pkg.css',
'symbols' =>
@@ -4322,7 +4322,7 @@
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 @@
),
'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 @@
'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 @@
'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',
),
));
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1536,6 +1536,9 @@
'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 @@
'PhabricatorRedirectController' => 'PhabricatorController',
'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController',
'PhabricatorRegistrationProfile' => 'Phobject',
+ 'PhabricatorRemarkupBlockInterpreterCowsay' => 'PhutilRemarkupBlockInterpreter',
+ 'PhabricatorRemarkupBlockInterpreterFiglet' => 'PhutilRemarkupBlockInterpreter',
+ 'PhabricatorRemarkupBlockInterpreterGraphviz' => 'PhutilRemarkupBlockInterpreter',
'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl',
'PhabricatorRemarkupRuleEmbedFile' => 'PhabricatorRemarkupRuleObject',
'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule',
diff --git a/src/infrastructure/markup/PhabricatorMarkupEngine.php b/src/infrastructure/markup/PhabricatorMarkupEngine.php
--- a/src/infrastructure/markup/PhabricatorMarkupEngine.php
+++ b/src/infrastructure/markup/PhabricatorMarkupEngine.php
@@ -460,6 +460,7 @@
$blocks[] = new PhutilRemarkupEngineRemarkupNoteBlockRule();
$blocks[] = new PhutilRemarkupEngineRemarkupTableBlockRule();
$blocks[] = new PhutilRemarkupEngineRemarkupSimpleTableBlockRule();
+ $blocks[] = new PhutilRemarkupEngineRemarkupInterpreterRule();
$custom_block_rule_classes = $options['custom-block'];
if ($custom_block_rule_classes) {
diff --git a/src/infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterCowsay.php b/src/infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterCowsay.php
new file mode 100644
--- /dev/null
+++ b/src/infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterCowsay.php
@@ -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);
+ }
+
+}
diff --git a/src/infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterFiglet.php b/src/infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterFiglet.php
new file mode 100644
--- /dev/null
+++ b/src/infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterFiglet.php
@@ -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);
+ }
+
+}
diff --git a/src/infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterGraphviz.php b/src/infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterGraphviz.php
new file mode 100644
--- /dev/null
+++ b/src/infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterGraphviz.php
@@ -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(),
+ ));
+ }
+
+}
diff --git a/webroot/rsrc/css/core/remarkup.css b/webroot/rsrc/css/core/remarkup.css
--- a/webroot/rsrc/css/core/remarkup.css
+++ b/webroot/rsrc/css/core/remarkup.css
@@ -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;

File Metadata

Mime Type
text/x-diff
Storage Engine
amazon-s3
Storage Format
Raw Data
Storage Handle
phabricator/aq/3e/mke66sxxe37gsecb
Default Alt Text
D7332.diff (13 KB)

Event Timeline