Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/markup/markuprule/PhutilRemarkupEvalRule.php
- This file was added.
<?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, | |||||
); | |||||
$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); | |||||
$engine->overwriteStoredText($token, $result); | |||||
} | |||||
} | |||||
private function evaluateExpression($expression) { | |||||
static $string_map; | |||||
if ($string_map === null) { | |||||
$string_map = array( | |||||
'strings' => array( | |||||
cspeckmim: Were you thinking of other non-string behavior being useful in the future, so .e.g `${{{config. | |||||
epriestleyAuthorUnsubmitted Done Inline Actions
Yeah, I'm not sure how much traction this will really get but I imagine making the things-that-can-be-evaluated modular so a source could expose Config or, perhaps, nonsense like:
epriestley: > Were you thinking of other non-string behavior being useful in the future, so .e.g… | |||||
'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 pht( | |||||
'<Failed to evaluate expression "%s".>', | |||||
$expression); | |||||
cspeckmimUnsubmitted Not Done Inline ActionsOh, so would this just return $expression in the case that the lookup failed, or include the escape characters as well, return '${{{'.$expression.'}}}'; Or should we try to return the original text passed in above without reconstructing it cspeckmim: Oh, so would this just return `$expression` in the case that the lookup failed, or include the… | |||||
} | |||||
} |
Were you thinking of other non-string behavior being useful in the future, so .e.g ${{{config.phabricator.base-uri}}} could substitute the value of the config or something (assuming policy checks are added)?