Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/diviner/markup/DivinerSymbolRemarkupRule.php
12256 views
1
<?php
2
3
final class DivinerSymbolRemarkupRule extends PhutilRemarkupRule {
4
5
const KEY_RULE_ATOM_REF = 'rule.diviner.atomref';
6
7
public function getPriority() {
8
return 200.0;
9
}
10
11
public function apply($text) {
12
// Grammar here is:
13
//
14
// rule = '@{' maybe_type name maybe_title '}'
15
// maybe_type = null | type ':' | type '@' book ':'
16
// name = name | name '@' context
17
// maybe_title = null | '|' title
18
//
19
// So these are all valid:
20
//
21
// @{name}
22
// @{type : name}
23
// @{name | title}
24
// @{type @ book : name @ context | title}
25
26
return preg_replace_callback(
27
'/(?:^|\B)@{'.
28
'(?:(?P<type>[^:]+?):)?'.
29
'(?P<name>[^}|]+?)'.
30
'(?:[|](?P<title>[^}]+))?'.
31
'}/',
32
array($this, 'markupSymbol'),
33
$text);
34
}
35
36
public function markupSymbol(array $matches) {
37
if (!$this->isFlatText($matches[0])) {
38
return $matches[0];
39
}
40
41
$type = (string)idx($matches, 'type');
42
$name = (string)$matches['name'];
43
$title = (string)idx($matches, 'title');
44
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));
49
50
$ref = array();
51
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;
58
}
59
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;
66
}
67
68
$ref['title'] = nonempty($title, $name);
69
70
foreach ($ref as $key => $value) {
71
if ($value === '') {
72
unset($ref[$key]);
73
}
74
}
75
76
$engine = $this->getEngine();
77
$token = $engine->storeText('');
78
79
$key = self::KEY_RULE_ATOM_REF;
80
$data = $engine->getTextMetadata($key, array());
81
$data[$token] = $ref;
82
$engine->setTextMetadata($key, $data);
83
84
return $token;
85
}
86
87
public function didMarkupText() {
88
$engine = $this->getEngine();
89
90
$key = self::KEY_RULE_ATOM_REF;
91
$data = $engine->getTextMetadata($key, array());
92
93
$renderer = $engine->getConfig('diviner.renderer');
94
95
foreach ($data as $token => $ref_dict) {
96
$ref = DivinerAtomRef::newFromDictionary($ref_dict);
97
$title = $ref->getTitle();
98
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.
104
105
$ref = $renderer->normalizeAtomRef($ref);
106
if ($ref) {
107
$title = nonempty($ref->getTitle(), $ref->getName());
108
$href = $renderer->getHrefForAtomRef($ref);
109
}
110
} else {
111
// Here, we're generating comment text or something like that. Just
112
// link to Diviner and let it sort things out.
113
114
$params = array(
115
'book' => $ref->getBook(),
116
'name' => $ref->getName(),
117
'type' => $ref->getType(),
118
'context' => $ref->getContext(),
119
'jump' => true,
120
);
121
122
$href = new PhutilURI('/diviner/find/', $params);
123
}
124
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;
133
}
134
}
135
136
if ($this->getEngine()->isTextMode()) {
137
if ($href) {
138
$link = $title.' <'.PhabricatorEnv::getProductionURI($href).'>';
139
} else {
140
$link = $title;
141
}
142
} else if ($href) {
143
if ($this->getEngine()->isHTMLMailMode()) {
144
$href = PhabricatorEnv::getProductionURI($href);
145
}
146
147
$link = $this->newTag(
148
'a',
149
array(
150
'class' => 'atom-ref',
151
'href' => $href,
152
),
153
$title);
154
} else {
155
$link = $this->newTag(
156
'span',
157
array(
158
'class' => 'atom-ref-invalid',
159
),
160
$title);
161
}
162
163
$engine->overwriteStoredText($token, $link);
164
}
165
}
166
167
}
168
169