3 final class DivinerSymbolRemarkupRule
extends PhutilRemarkupRule
{
5 const KEY_RULE_ATOM_REF
= 'rule.diviner.atomref';
7 public function getPriority() {
11 public function apply($text) {
14 // rule = '@{' maybe_type name maybe_title '}'
15 // maybe_type = null | type ':' | type '@' book ':'
16 // name = name | name '@' context
17 // maybe_title = null | '|' title
19 // So these are all valid:
24 // @{type @ book : name @ context | title}
26 return preg_replace_callback(
28 '(?:(?P<type>[^:]+?):)?'.
30 '(?:[|](?P<title>[^}]+))?'.
32 array($this, 'markupSymbol'),
36 public function markupSymbol(array $matches) {
37 if (!$this->isFlatText($matches[0])) {
41 $type = (string)idx($matches, 'type');
42 $name = (string)$matches['name'];
43 $title = (string)idx($matches, 'title');
45 // Collapse sequences of whitespace into a single space.
46 $type = preg_replace('/\s+/', ' ', trim($type));
47 $name = preg_replace('/\s+/', ' ', trim($name));
48 $title = preg_replace('/\s+/', ' ', trim($title));
52 if (strpos($type, '@') !== false) {
53 list($type, $book) = explode('@', $type, 2);
54 $ref['type'] = trim($type);
55 $ref['book'] = trim($book);
60 if (strpos($name, '@') !== false) {
61 list($name, $context) = explode('@', $name, 2);
62 $ref['name'] = trim($name);
63 $ref['context'] = trim($context);
68 $ref['title'] = nonempty($title, $name);
70 foreach ($ref as $key => $value) {
76 $engine = $this->getEngine();
77 $token = $engine->storeText('');
79 $key = self
::KEY_RULE_ATOM_REF
;
80 $data = $engine->getTextMetadata($key, array());
82 $engine->setTextMetadata($key, $data);
87 public function didMarkupText() {
88 $engine = $this->getEngine();
90 $key = self
::KEY_RULE_ATOM_REF
;
91 $data = $engine->getTextMetadata($key, array());
93 $renderer = $engine->getConfig('diviner.renderer');
95 foreach ($data as $token => $ref_dict) {
96 $ref = DivinerAtomRef
::newFromDictionary($ref_dict);
97 $title = $ref->getTitle();
101 // Here, we're generating documentation. If possible, we want to find
102 // the real atom ref so we can render the correct default title and
103 // render invalid links in an alternate style.
105 $ref = $renderer->normalizeAtomRef($ref);
107 $title = nonempty($ref->getTitle(), $ref->getName());
108 $href = $renderer->getHrefForAtomRef($ref);
111 // Here, we're generating comment text or something like that. Just
112 // link to Diviner and let it sort things out.
115 'book' => $ref->getBook(),
116 'name' => $ref->getName(),
117 'type' => $ref->getType(),
118 'context' => $ref->getContext(),
122 $href = new PhutilURI('/diviner/find/', $params);
125 // TODO: This probably is not the best place to do this. Move it somewhere
126 // better when it becomes more clear where it should actually go.
128 switch ($ref->getType()) {
131 $title = $title.'()';
136 if ($this->getEngine()->isTextMode()) {
138 $link = $title.' <'.PhabricatorEnv
::getProductionURI($href).'>';
143 if ($this->getEngine()->isHTMLMailMode()) {
144 $href = PhabricatorEnv
::getProductionURI($href);
147 $link = $this->newTag(
150 'class' => 'atom-ref',
155 $link = $this->newTag(
158 'class' => 'atom-ref-invalid',
163 $engine->overwriteStoredText($token, $link);