@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
3final class PhutilRemarkupSimpleTableBlockRule extends PhutilRemarkupBlockRule {
4
5 public function getMatchingLineCount(array $lines, $cursor) {
6 $num_lines = 0;
7 while (isset($lines[$cursor])) {
8 if (preg_match('/^(\s*\|.*+\n?)+$/', $lines[$cursor])) {
9 $num_lines++;
10 $cursor++;
11 } else {
12 break;
13 }
14 }
15
16 return $num_lines;
17 }
18
19 public function markupText($text, $children) {
20 $matches = array();
21
22 $rows = array();
23 foreach (explode("\n", $text) as $line) {
24 // Ignore ending delimiters.
25 $line = rtrim($line, '|');
26
27 // NOTE: The complexity in this regular expression allows us to match
28 // a table like "| a | [[ href | b ]] | c |".
29
30 preg_match_all(
31 '/\|'.
32 '('.
33 '(?:'.
34 '(?:\\[\\[.*?\\]\\])'. // [[ ... | ... ]], a link
35 '|'.
36 '(?:[^|[]+)'. // Anything but "|" or "[".
37 '|'.
38 '(?:\\[[^\\|[])'. // "[" followed by anything but "[" or "|"
39 ')*'.
40 ')/', $line, $matches);
41
42 $any_header = false;
43 $any_content = false;
44
45 $cells = array();
46 foreach ($matches[1] as $cell) {
47 $cell = trim($cell);
48
49 // If this row only has empty cells and "--" cells, and it has at
50 // least one "--" cell, it's marking the rows above as <th> cells
51 // instead of <td> cells.
52
53 // If it has other types of cells, it's always a content row.
54
55 // If it has only empty cells, it's an empty row.
56
57 if (strlen($cell)) {
58 if (preg_match('/^--+\z/', $cell)) {
59 $any_header = true;
60 } else {
61 $any_content = true;
62 }
63 }
64
65 $cells[] = array('type' => 'td', 'content' => $this->applyRules($cell));
66 }
67
68 $is_header = ($any_header && !$any_content);
69
70 if (!$is_header) {
71 $rows[] = array('type' => 'tr', 'content' => $cells);
72 } else if ($rows) {
73 // Mark previous row with headings.
74 foreach ($cells as $i => $cell) {
75 if ($cell['content']) {
76 $last_key = last_key($rows);
77 if (!isset($rows[$last_key]['content'][$i])) {
78 // If this row has more cells than the previous row, there may
79 // not be a cell above this one to turn into a <th />.
80 continue;
81 }
82
83 $rows[$last_key]['content'][$i]['type'] = 'th';
84 }
85 }
86 }
87 }
88
89 if (!$rows) {
90 return $this->applyRules($text);
91 }
92
93 return $this->renderRemarkupTable($rows);
94 }
95
96}