@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3abstract class PhutilRemarkupBlockRule extends Phobject {
4
5 private $engine;
6 private $rules = array();
7
8 /**
9 * Determine the order in which blocks execute. Blocks with smaller priority
10 * numbers execute sooner than blocks with larger priority numbers. The
11 * default priority for blocks is `500`.
12 *
13 * Priorities are used to disambiguate syntax which can match multiple
14 * patterns. For example, ` - Lorem ipsum...` may be a code block or a
15 * list.
16 *
17 * @return int Priority at which this block should execute.
18 */
19 public function getPriority() {
20 return 500;
21 }
22
23 final public function getPriorityVector() {
24 return id(new PhutilSortVector())
25 ->addInt($this->getPriority())
26 ->addString(get_class($this));
27 }
28
29 abstract public function markupText($text, $children);
30
31 /**
32 * This will get an array of unparsed lines and return the number of lines
33 * from the first array value that it can parse.
34 *
35 * @param array $lines
36 * @param int $cursor
37 *
38 * @return int
39 */
40 abstract public function getMatchingLineCount(array $lines, $cursor);
41
42 protected function didMarkupText() {
43 return;
44 }
45
46 public function willMarkupChildBlocks() {
47 return;
48 }
49
50 public function didMarkupChildBlocks() {
51 return;
52 }
53
54 final public function setEngine(PhutilRemarkupEngine $engine) {
55 $this->engine = $engine;
56 $this->updateRules();
57 return $this;
58 }
59
60 final protected function getEngine() {
61 return $this->engine;
62 }
63
64 /**
65 * @param array<PhutilRemarkupRule> $rules
66 */
67 public function setMarkupRules(array $rules) {
68 assert_instances_of($rules, PhutilRemarkupRule::class);
69 $this->rules = $rules;
70 $this->updateRules();
71 return $this;
72 }
73
74 private function updateRules() {
75 $engine = $this->getEngine();
76 if ($engine) {
77 $this->rules = msort($this->rules, 'getPriority');
78 foreach ($this->rules as $rule) {
79 $rule->setEngine($engine);
80 }
81 }
82 return $this;
83 }
84
85 final public function getMarkupRules() {
86 return $this->rules;
87 }
88
89 final public function postprocess() {
90 $this->didMarkupText();
91 }
92
93 final protected function applyRules($text) {
94 foreach ($this->getMarkupRules() as $rule) {
95 $text = $rule->apply($text);
96 }
97 return $text;
98 }
99
100 public function supportsChildBlocks() {
101 return false;
102 }
103
104 public function extractChildText($text) {
105 throw new PhutilMethodNotImplementedException();
106 }
107
108 protected function renderRemarkupTable(array $out_rows) {
109 assert_instances_of($out_rows, 'array');
110
111 if ($this->getEngine()->isTextMode()) {
112 $lengths = array();
113 foreach ($out_rows as $r => $row) {
114 foreach ($row['content'] as $c => $cell) {
115 $text = $this->getEngine()->restoreText($cell['content']);
116 $lengths[$c][$r] = phutil_utf8_strlen($text);
117 }
118 }
119 $max_lengths = array_map('max', $lengths);
120
121 $out = array();
122 foreach ($out_rows as $r => $row) {
123 $headings = false;
124 foreach ($row['content'] as $c => $cell) {
125 $length = $max_lengths[$c] - $lengths[$c][$r];
126 $out[] = '| '.$cell['content'].str_repeat(' ', $length).' ';
127 if ($cell['type'] == 'th') {
128 $headings = true;
129 }
130 }
131 $out[] = "|\n";
132
133 if ($headings) {
134 foreach ($row['content'] as $c => $cell) {
135 $char = ($cell['type'] == 'th' ? '-' : ' ');
136 $out[] = '| '.str_repeat($char, $max_lengths[$c]).' ';
137 }
138 $out[] = "|\n";
139 }
140 }
141
142 return rtrim(implode('', $out), "\n");
143 }
144
145 if ($this->getEngine()->isHTMLMailMode()) {
146 $table_attributes = array(
147 'style' => 'border-collapse: separate;
148 border-spacing: 1px;
149 background: #d3d3d3;
150 margin: 12px 0;',
151 );
152 $cell_attributes = array(
153 'style' => 'background: #ffffff;
154 padding: 3px 6px;',
155 );
156 } else {
157 $table_attributes = array(
158 'class' => 'remarkup-table',
159 );
160 $cell_attributes = array();
161 }
162
163 $out = array();
164 $out[] = "\n";
165 foreach ($out_rows as $row) {
166 $cells = array();
167 foreach ($row['content'] as $cell) {
168 $cells[] = phutil_tag(
169 $cell['type'],
170 $cell_attributes,
171 $cell['content']);
172 }
173 $out[] = phutil_tag($row['type'], array(), $cells);
174 $out[] = "\n";
175 }
176
177 $table = phutil_tag('table', $table_attributes, $out);
178 return phutil_tag_div('remarkup-table-wrap', $table);
179 }
180
181}