@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+206 -46
+46 -46
src/__celerity_resource_map__.php
··· 3433 3433 ), 3434 3434 'phabricator-remarkup-css' => 3435 3435 array( 3436 - 'uri' => '/res/7e8988dd/rsrc/css/core/remarkup.css', 3436 + 'uri' => '/res/4c313572/rsrc/css/core/remarkup.css', 3437 3437 'type' => 'css', 3438 3438 'requires' => 3439 3439 array( ··· 4273 4273 ), array( 4274 4274 'packages' => 4275 4275 array( 4276 - 'a4e76ef8' => 4276 + '30de5267' => 4277 4277 array( 4278 4278 'name' => 'core.pkg.css', 4279 4279 'symbols' => ··· 4322 4322 41 => 'phabricator-tag-view-css', 4323 4323 42 => 'phui-list-view-css', 4324 4324 ), 4325 - 'uri' => '/res/pkg/a4e76ef8/core.pkg.css', 4325 + 'uri' => '/res/pkg/30de5267/core.pkg.css', 4326 4326 'type' => 'css', 4327 4327 ), 4328 4328 '6041c6c8' => ··· 4514 4514 ), 4515 4515 'reverse' => 4516 4516 array( 4517 - 'aphront-dialog-view-css' => 'a4e76ef8', 4518 - 'aphront-error-view-css' => 'a4e76ef8', 4519 - 'aphront-list-filter-view-css' => 'a4e76ef8', 4520 - 'aphront-pager-view-css' => 'a4e76ef8', 4521 - 'aphront-panel-view-css' => 'a4e76ef8', 4522 - 'aphront-table-view-css' => 'a4e76ef8', 4523 - 'aphront-tokenizer-control-css' => 'a4e76ef8', 4524 - 'aphront-tooltip-css' => 'a4e76ef8', 4525 - 'aphront-typeahead-control-css' => 'a4e76ef8', 4517 + 'aphront-dialog-view-css' => '30de5267', 4518 + 'aphront-error-view-css' => '30de5267', 4519 + 'aphront-list-filter-view-css' => '30de5267', 4520 + 'aphront-pager-view-css' => '30de5267', 4521 + 'aphront-panel-view-css' => '30de5267', 4522 + 'aphront-table-view-css' => '30de5267', 4523 + 'aphront-tokenizer-control-css' => '30de5267', 4524 + 'aphront-tooltip-css' => '30de5267', 4525 + 'aphront-typeahead-control-css' => '30de5267', 4526 4526 'differential-changeset-view-css' => '7cd7e387', 4527 4527 'differential-core-view-css' => '7cd7e387', 4528 4528 'differential-inline-comment-editor' => '5e9e5c4e', ··· 4536 4536 'differential-table-of-contents-css' => '7cd7e387', 4537 4537 'diffusion-commit-view-css' => '270f4eb4', 4538 4538 'diffusion-icons-css' => '270f4eb4', 4539 - 'global-drag-and-drop-css' => 'a4e76ef8', 4539 + 'global-drag-and-drop-css' => '30de5267', 4540 4540 'inline-comment-summary-css' => '7cd7e387', 4541 4541 'javelin-aphlict' => '6041c6c8', 4542 4542 'javelin-behavior' => '3e3be199', ··· 4611 4611 'javelin-util' => '3e3be199', 4612 4612 'javelin-vector' => '3e3be199', 4613 4613 'javelin-workflow' => '3e3be199', 4614 - 'lightbox-attachment-css' => 'a4e76ef8', 4614 + 'lightbox-attachment-css' => '30de5267', 4615 4615 'maniphest-task-summary-css' => '49898640', 4616 - 'phabricator-action-list-view-css' => 'a4e76ef8', 4617 - 'phabricator-application-launch-view-css' => 'a4e76ef8', 4616 + 'phabricator-action-list-view-css' => '30de5267', 4617 + 'phabricator-application-launch-view-css' => '30de5267', 4618 4618 'phabricator-busy' => '6041c6c8', 4619 4619 'phabricator-content-source-view-css' => '7cd7e387', 4620 - 'phabricator-core-css' => 'a4e76ef8', 4621 - 'phabricator-crumbs-view-css' => 'a4e76ef8', 4620 + 'phabricator-core-css' => '30de5267', 4621 + 'phabricator-crumbs-view-css' => '30de5267', 4622 4622 'phabricator-drag-and-drop-file-upload' => '5e9e5c4e', 4623 4623 'phabricator-dropdown-menu' => '6041c6c8', 4624 4624 'phabricator-file-upload' => '6041c6c8', 4625 - 'phabricator-filetree-view-css' => 'a4e76ef8', 4626 - 'phabricator-flag-css' => 'a4e76ef8', 4625 + 'phabricator-filetree-view-css' => '30de5267', 4626 + 'phabricator-flag-css' => '30de5267', 4627 4627 'phabricator-hovercard' => '6041c6c8', 4628 - 'phabricator-jump-nav' => 'a4e76ef8', 4628 + 'phabricator-jump-nav' => '30de5267', 4629 4629 'phabricator-keyboard-shortcut' => '6041c6c8', 4630 4630 'phabricator-keyboard-shortcut-manager' => '6041c6c8', 4631 - 'phabricator-main-menu-view' => 'a4e76ef8', 4631 + 'phabricator-main-menu-view' => '30de5267', 4632 4632 'phabricator-menu-item' => '6041c6c8', 4633 - 'phabricator-nav-view-css' => 'a4e76ef8', 4633 + 'phabricator-nav-view-css' => '30de5267', 4634 4634 'phabricator-notification' => '6041c6c8', 4635 - 'phabricator-notification-css' => 'a4e76ef8', 4636 - 'phabricator-notification-menu-css' => 'a4e76ef8', 4635 + 'phabricator-notification-css' => '30de5267', 4636 + 'phabricator-notification-menu-css' => '30de5267', 4637 4637 'phabricator-object-selector-css' => '7cd7e387', 4638 4638 'phabricator-phtize' => '6041c6c8', 4639 4639 'phabricator-prefab' => '6041c6c8', 4640 4640 'phabricator-project-tag-css' => '49898640', 4641 - 'phabricator-remarkup-css' => 'a4e76ef8', 4641 + 'phabricator-remarkup-css' => '30de5267', 4642 4642 'phabricator-shaped-request' => '5e9e5c4e', 4643 - 'phabricator-side-menu-view-css' => 'a4e76ef8', 4644 - 'phabricator-standard-page-view' => 'a4e76ef8', 4645 - 'phabricator-tag-view-css' => 'a4e76ef8', 4643 + 'phabricator-side-menu-view-css' => '30de5267', 4644 + 'phabricator-standard-page-view' => '30de5267', 4645 + 'phabricator-tag-view-css' => '30de5267', 4646 4646 'phabricator-textareautils' => '6041c6c8', 4647 4647 'phabricator-tooltip' => '6041c6c8', 4648 - 'phabricator-transaction-view-css' => 'a4e76ef8', 4649 - 'phabricator-zindex-css' => 'a4e76ef8', 4650 - 'phui-button-css' => 'a4e76ef8', 4651 - 'phui-form-css' => 'a4e76ef8', 4652 - 'phui-form-view-css' => 'a4e76ef8', 4653 - 'phui-header-view-css' => 'a4e76ef8', 4654 - 'phui-icon-view-css' => 'a4e76ef8', 4655 - 'phui-list-view-css' => 'a4e76ef8', 4656 - 'phui-object-item-list-view-css' => 'a4e76ef8', 4657 - 'phui-property-list-view-css' => 'a4e76ef8', 4658 - 'phui-spacing-css' => 'a4e76ef8', 4659 - 'sprite-apps-large-css' => 'a4e76ef8', 4660 - 'sprite-gradient-css' => 'a4e76ef8', 4661 - 'sprite-icons-css' => 'a4e76ef8', 4662 - 'sprite-menu-css' => 'a4e76ef8', 4663 - 'sprite-status-css' => 'a4e76ef8', 4664 - 'syntax-highlighting-css' => 'a4e76ef8', 4648 + 'phabricator-transaction-view-css' => '30de5267', 4649 + 'phabricator-zindex-css' => '30de5267', 4650 + 'phui-button-css' => '30de5267', 4651 + 'phui-form-css' => '30de5267', 4652 + 'phui-form-view-css' => '30de5267', 4653 + 'phui-header-view-css' => '30de5267', 4654 + 'phui-icon-view-css' => '30de5267', 4655 + 'phui-list-view-css' => '30de5267', 4656 + 'phui-object-item-list-view-css' => '30de5267', 4657 + 'phui-property-list-view-css' => '30de5267', 4658 + 'phui-spacing-css' => '30de5267', 4659 + 'sprite-apps-large-css' => '30de5267', 4660 + 'sprite-gradient-css' => '30de5267', 4661 + 'sprite-icons-css' => '30de5267', 4662 + 'sprite-menu-css' => '30de5267', 4663 + 'sprite-status-css' => '30de5267', 4664 + 'syntax-highlighting-css' => '30de5267', 4665 4665 ), 4666 4666 ));
+6
src/__phutil_library_map__.php
··· 1536 1536 'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php', 1537 1537 'PhabricatorRefreshCSRFController' => 'applications/auth/controller/PhabricatorRefreshCSRFController.php', 1538 1538 'PhabricatorRegistrationProfile' => 'applications/people/storage/PhabricatorRegistrationProfile.php', 1539 + 'PhabricatorRemarkupBlockInterpreterCowsay' => 'infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterCowsay.php', 1540 + 'PhabricatorRemarkupBlockInterpreterFiglet' => 'infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterFiglet.php', 1541 + 'PhabricatorRemarkupBlockInterpreterGraphviz' => 'infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterGraphviz.php', 1539 1542 'PhabricatorRemarkupControl' => 'view/form/control/PhabricatorRemarkupControl.php', 1540 1543 'PhabricatorRemarkupRuleEmbedFile' => 'applications/files/remarkup/PhabricatorRemarkupRuleEmbedFile.php', 1541 1544 'PhabricatorRemarkupRuleImageMacro' => 'applications/macro/remarkup/PhabricatorRemarkupRuleImageMacro.php', ··· 3747 3750 'PhabricatorRedirectController' => 'PhabricatorController', 3748 3751 'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController', 3749 3752 'PhabricatorRegistrationProfile' => 'Phobject', 3753 + 'PhabricatorRemarkupBlockInterpreterCowsay' => 'PhutilRemarkupBlockInterpreter', 3754 + 'PhabricatorRemarkupBlockInterpreterFiglet' => 'PhutilRemarkupBlockInterpreter', 3755 + 'PhabricatorRemarkupBlockInterpreterGraphviz' => 'PhutilRemarkupBlockInterpreter', 3750 3756 'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl', 3751 3757 'PhabricatorRemarkupRuleEmbedFile' => 'PhabricatorRemarkupRuleObject', 3752 3758 'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule',
+1
src/infrastructure/markup/PhabricatorMarkupEngine.php
··· 460 460 $blocks[] = new PhutilRemarkupEngineRemarkupNoteBlockRule(); 461 461 $blocks[] = new PhutilRemarkupEngineRemarkupTableBlockRule(); 462 462 $blocks[] = new PhutilRemarkupEngineRemarkupSimpleTableBlockRule(); 463 + $blocks[] = new PhutilRemarkupEngineRemarkupInterpreterRule(); 463 464 464 465 $custom_block_rule_classes = $options['custom-block']; 465 466 if ($custom_block_rule_classes) {
+55
src/infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterCowsay.php
··· 1 + <?php 2 + 3 + final class PhabricatorRemarkupBlockInterpreterCowsay 4 + extends PhutilRemarkupBlockInterpreter { 5 + 6 + public function getInterpreterName() { 7 + return 'cowsay'; 8 + } 9 + 10 + public function markupContent($content, array $argv) { 11 + if (!Filesystem::binaryExists('cowsay')) { 12 + return $this->markupError( 13 + pht('Unable to locate the `cowsay` binary. Install cowsay.')); 14 + } 15 + 16 + $bin = idx($argv, 'think') ? 'cowthink' : 'cowsay'; 17 + $eyes = idx($argv, 'eyes', 'oo'); 18 + $tongue = idx($argv, 'tongue', ' '); 19 + $cow = idx($argv, 'cow', 'default'); 20 + 21 + // NOTE: Strip this aggressively to prevent nonsense like 22 + // `cow=/etc/passwd`. We could build a whiltelist with `cowsay -l`. 23 + $cow = preg_replace('/[^a-z.-]+/', '', $cow); 24 + 25 + $future = new ExecFuture( 26 + '%s -e %s -T %s -f %s ', 27 + $bin, 28 + $eyes, 29 + $tongue, 30 + $cow); 31 + 32 + $future->write($content); 33 + 34 + list($err, $stdout, $stderr) = $future->resolve(); 35 + 36 + if ($err) { 37 + return $this->markupError( 38 + pht( 39 + 'Execution of `cowsay` failed:', $stderr)); 40 + } 41 + 42 + 43 + if ($this->getEngine()->isTextMode()) { 44 + return $stdout; 45 + } 46 + 47 + return phutil_tag( 48 + 'div', 49 + array( 50 + 'class' => 'PhabricatorMonospaced remarkup-cowsay', 51 + ), 52 + $stdout); 53 + } 54 + 55 + }
+40
src/infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterFiglet.php
··· 1 + <?php 2 + 3 + final class PhabricatorRemarkupBlockInterpreterFiglet 4 + extends PhutilRemarkupBlockInterpreter { 5 + 6 + public function getInterpreterName() { 7 + return 'figlet'; 8 + } 9 + 10 + public function markupContent($content, array $argv) { 11 + if (!Filesystem::binaryExists('figlet')) { 12 + return $this->markupError( 13 + pht('Unable to locate the `figlet` binary. Install figlet.')); 14 + } 15 + 16 + $future = id(new ExecFuture('figlet')) 17 + ->write(trim($content, "\n")); 18 + 19 + list($err, $stdout, $stderr) = $future->resolve(); 20 + 21 + if ($err) { 22 + return $this->markupError( 23 + pht( 24 + 'Execution of `figlet` failed:', $stderr)); 25 + } 26 + 27 + 28 + if ($this->getEngine()->isTextMode()) { 29 + return $stdout; 30 + } 31 + 32 + return phutil_tag( 33 + 'div', 34 + array( 35 + 'class' => 'PhabricatorMonospaced remarkup-figlet', 36 + ), 37 + $stdout); 38 + } 39 + 40 + }
+44
src/infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterGraphviz.php
··· 1 + <?php 2 + 3 + final class PhabricatorRemarkupBlockInterpreterGraphviz 4 + extends PhutilRemarkupBlockInterpreter { 5 + 6 + public function getInterpreterName() { 7 + return 'dot'; 8 + } 9 + 10 + public function markupContent($content, array $argv) { 11 + if (!Filesystem::binaryExists('dot')) { 12 + return $this->markupError( 13 + pht('Unable to locate the `dot` binary. Install Graphviz.')); 14 + } 15 + 16 + $future = id(new ExecFuture('dot -T%s', 'png')) 17 + ->write(trim($content)); 18 + 19 + list($err, $stdout, $stderr) = $future->resolve(); 20 + 21 + if ($err) { 22 + return $this->markupError( 23 + pht( 24 + 'Execution of `dot` failed, check your syntax: %s', $stderr)); 25 + } 26 + 27 + $file = PhabricatorFile::buildFromFileDataOrHash( 28 + $stdout, 29 + array( 30 + 'name' => 'graphviz.png', 31 + )); 32 + 33 + if ($this->getEngine()->isTextMode()) { 34 + return '<'.$file->getBestURI().'>'; 35 + } 36 + 37 + return phutil_tag( 38 + 'img', 39 + array( 40 + 'src' => $file->getBestURI(), 41 + )); 42 + } 43 + 44 + }
+14
webroot/rsrc/css/core/remarkup.css
··· 329 329 border-right: 1px solid #cccccc; 330 330 } 331 331 332 + .remarkup-interpreter-error { 333 + padding: 8px; 334 + border: 1px solid {$red}; 335 + background-color: {$lightred}; 336 + } 337 + 338 + .remarkup-cowsay { 339 + white-space: pre-wrap; 340 + } 341 + 342 + .remarkup-figlet { 343 + white-space: pre-wrap; 344 + } 345 + 332 346 .remarkup-assist { 333 347 display: block; 334 348 width: 14px;