1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-22 21:40:55 +01:00

Add an "eval" rule to Remarkup

Summary:
Ref T13658. This adds a simple expression evaluator to Remarkup and supports platform name expressions. The syntax is:

```
${{{strings.platform.server.name}}}
```

Note that this won't work inside code blocks (or literal blocks, or other block-level literal elements) right now, although it could be made to selectively (the ".path" expressions might be useful in documentation codeblocks).

Test Plan: {F9391006}

Reviewers: cspeckmim

Reviewed By: cspeckmim

Maniphest Tasks: T13658

Differential Revision: https://secure.phabricator.com/D21713
This commit is contained in:
epriestley 2021-07-27 14:02:48 -07:00
parent cc8cbed029
commit dbe2fb466f
3 changed files with 104 additions and 1 deletions

View file

@ -5770,6 +5770,7 @@ phutil_register_library_map(array(
'PhutilRemarkupEngine' => 'infrastructure/markup/remarkup/PhutilRemarkupEngine.php', 'PhutilRemarkupEngine' => 'infrastructure/markup/remarkup/PhutilRemarkupEngine.php',
'PhutilRemarkupEngineTestCase' => 'infrastructure/markup/remarkup/__tests__/PhutilRemarkupEngineTestCase.php', 'PhutilRemarkupEngineTestCase' => 'infrastructure/markup/remarkup/__tests__/PhutilRemarkupEngineTestCase.php',
'PhutilRemarkupEscapeRemarkupRule' => 'infrastructure/markup/markuprule/PhutilRemarkupEscapeRemarkupRule.php', 'PhutilRemarkupEscapeRemarkupRule' => 'infrastructure/markup/markuprule/PhutilRemarkupEscapeRemarkupRule.php',
'PhutilRemarkupEvalRule' => 'infrastructure/markup/markuprule/PhutilRemarkupEvalRule.php',
'PhutilRemarkupHeaderBlockRule' => 'infrastructure/markup/blockrule/PhutilRemarkupHeaderBlockRule.php', 'PhutilRemarkupHeaderBlockRule' => 'infrastructure/markup/blockrule/PhutilRemarkupHeaderBlockRule.php',
'PhutilRemarkupHighlightRule' => 'infrastructure/markup/markuprule/PhutilRemarkupHighlightRule.php', 'PhutilRemarkupHighlightRule' => 'infrastructure/markup/markuprule/PhutilRemarkupHighlightRule.php',
'PhutilRemarkupHorizontalRuleBlockRule' => 'infrastructure/markup/blockrule/PhutilRemarkupHorizontalRuleBlockRule.php', 'PhutilRemarkupHorizontalRuleBlockRule' => 'infrastructure/markup/blockrule/PhutilRemarkupHorizontalRuleBlockRule.php',
@ -12770,6 +12771,7 @@ phutil_register_library_map(array(
'PhutilRemarkupEngine' => 'PhutilMarkupEngine', 'PhutilRemarkupEngine' => 'PhutilMarkupEngine',
'PhutilRemarkupEngineTestCase' => 'PhutilTestCase', 'PhutilRemarkupEngineTestCase' => 'PhutilTestCase',
'PhutilRemarkupEscapeRemarkupRule' => 'PhutilRemarkupRule', 'PhutilRemarkupEscapeRemarkupRule' => 'PhutilRemarkupRule',
'PhutilRemarkupEvalRule' => 'PhutilRemarkupRule',
'PhutilRemarkupHeaderBlockRule' => 'PhutilRemarkupBlockRule', 'PhutilRemarkupHeaderBlockRule' => 'PhutilRemarkupBlockRule',
'PhutilRemarkupHighlightRule' => 'PhutilRemarkupRule', 'PhutilRemarkupHighlightRule' => 'PhutilRemarkupRule',
'PhutilRemarkupHorizontalRuleBlockRule' => 'PhutilRemarkupBlockRule', 'PhutilRemarkupHorizontalRuleBlockRule' => 'PhutilRemarkupBlockRule',

View file

@ -42,7 +42,7 @@ final class PhabricatorMarkupEngine extends Phobject {
private $objects = array(); private $objects = array();
private $viewer; private $viewer;
private $contextObject; private $contextObject;
private $version = 20; private $version = 21;
private $engineCaches = array(); private $engineCaches = array();
private $auxiliaryConfig = array(); private $auxiliaryConfig = array();
@ -504,6 +504,7 @@ final class PhabricatorMarkupEngine extends Phobject {
$rules = array(); $rules = array();
$rules[] = new PhutilRemarkupEscapeRemarkupRule(); $rules[] = new PhutilRemarkupEscapeRemarkupRule();
$rules[] = new PhutilRemarkupEvalRule();
$rules[] = new PhutilRemarkupMonospaceRule(); $rules[] = new PhutilRemarkupMonospaceRule();

View file

@ -0,0 +1,100 @@
<?php
final class PhutilRemarkupEvalRule extends PhutilRemarkupRule {
const KEY_EVAL = 'eval';
public function getPriority() {
return 50;
}
public function apply($text) {
return preg_replace_callback(
'/\${{{(.+?)}}}/',
array($this, 'newExpressionToken'),
$text);
}
public function newExpressionToken(array $matches) {
$expression = $matches[1];
if (!$this->isFlatText($expression)) {
return $matches[0];
}
$engine = $this->getEngine();
$token = $engine->storeText($expression);
$list_key = self::KEY_EVAL;
$expression_list = $engine->getTextMetadata($list_key, array());
$expression_list[] = array(
'token' => $token,
'expression' => $expression,
'original' => $matches[0],
);
$engine->setTextMetadata($list_key, $expression_list);
return $token;
}
public function didMarkupText() {
$engine = $this->getEngine();
$list_key = self::KEY_EVAL;
$expression_list = $engine->getTextMetadata($list_key, array());
foreach ($expression_list as $expression_item) {
$token = $expression_item['token'];
$expression = $expression_item['expression'];
$result = $this->evaluateExpression($expression);
if ($result === null) {
$result = $expression_item['original'];
}
$engine->overwriteStoredText($token, $result);
}
}
private function evaluateExpression($expression) {
static $string_map;
if ($string_map === null) {
$string_map = array(
'strings' => array(
'platform' => array(
'server' => array(
'name' => pht('Phabricator'),
'path' => pht('phabricator/'),
),
'client' => array(
'name' => pht('Arcanist'),
'path' => pht('arcanist/'),
),
),
),
);
}
$parts = explode('.', $expression);
$cursor = $string_map;
foreach ($parts as $part) {
if (isset($cursor[$part])) {
$cursor = $cursor[$part];
} else {
break;
}
}
if (is_string($cursor)) {
return $cursor;
}
return null;
}
}