Remove product literal strings in "pht()", part 18
[phabricator.git] / src / applications / diviner / markup / DivinerSymbolRemarkupRule.php
blobdb68927625e3c005fbd9b55c38d89faf1559485f
1 <?php
3 final class DivinerSymbolRemarkupRule extends PhutilRemarkupRule {
5 const KEY_RULE_ATOM_REF = 'rule.diviner.atomref';
7 public function getPriority() {
8 return 200.0;
11 public function apply($text) {
12 // Grammar here is:
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:
21 // @{name}
22 // @{type : name}
23 // @{name | title}
24 // @{type @ book : name @ context | title}
26 return preg_replace_callback(
27 '/(?:^|\B)@{'.
28 '(?:(?P<type>[^:]+?):)?'.
29 '(?P<name>[^}|]+?)'.
30 '(?:[|](?P<title>[^}]+))?'.
31 '}/',
32 array($this, 'markupSymbol'),
33 $text);
36 public function markupSymbol(array $matches) {
37 if (!$this->isFlatText($matches[0])) {
38 return $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));
50 $ref = array();
52 if (strpos($type, '@') !== false) {
53 list($type, $book) = explode('@', $type, 2);
54 $ref['type'] = trim($type);
55 $ref['book'] = trim($book);
56 } else {
57 $ref['type'] = $type;
60 if (strpos($name, '@') !== false) {
61 list($name, $context) = explode('@', $name, 2);
62 $ref['name'] = trim($name);
63 $ref['context'] = trim($context);
64 } else {
65 $ref['name'] = $name;
68 $ref['title'] = nonempty($title, $name);
70 foreach ($ref as $key => $value) {
71 if ($value === '') {
72 unset($ref[$key]);
76 $engine = $this->getEngine();
77 $token = $engine->storeText('');
79 $key = self::KEY_RULE_ATOM_REF;
80 $data = $engine->getTextMetadata($key, array());
81 $data[$token] = $ref;
82 $engine->setTextMetadata($key, $data);
84 return $token;
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();
99 $href = null;
100 if ($renderer) {
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);
106 if ($ref) {
107 $title = nonempty($ref->getTitle(), $ref->getName());
108 $href = $renderer->getHrefForAtomRef($ref);
110 } else {
111 // Here, we're generating comment text or something like that. Just
112 // link to Diviner and let it sort things out.
114 $params = array(
115 'book' => $ref->getBook(),
116 'name' => $ref->getName(),
117 'type' => $ref->getType(),
118 'context' => $ref->getContext(),
119 'jump' => true,
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.
127 if ($ref) {
128 switch ($ref->getType()) {
129 case 'function':
130 case 'method':
131 $title = $title.'()';
132 break;
136 if ($this->getEngine()->isTextMode()) {
137 if ($href) {
138 $link = $title.' <'.PhabricatorEnv::getProductionURI($href).'>';
139 } else {
140 $link = $title;
142 } else if ($href) {
143 if ($this->getEngine()->isHTMLMailMode()) {
144 $href = PhabricatorEnv::getProductionURI($href);
147 $link = $this->newTag(
148 'a',
149 array(
150 'class' => 'atom-ref',
151 'href' => $href,
153 $title);
154 } else {
155 $link = $this->newTag(
156 'span',
157 array(
158 'class' => 'atom-ref-invalid',
160 $title);
163 $engine->overwriteStoredText($token, $link);