diff --git a/src/markup/engine/__tests__/remarkup/simple-table-with-leading-space.txt b/src/markup/engine/__tests__/remarkup/simple-table-with-leading-space.txt
new file mode 100644
index 0000000..418baa5
--- /dev/null
+++ b/src/markup/engine/__tests__/remarkup/simple-table-with-leading-space.txt
@@ -0,0 +1,7 @@
+ |a|b|
+~~~~~~~~~~
+
+~~~~~~~~~~
+| a | b |
diff --git a/src/markup/engine/__tests__/remarkup/table-with-leading-space.txt b/src/markup/engine/__tests__/remarkup/table-with-leading-space.txt
new file mode 100644
index 0000000..b0a45cd
--- /dev/null
+++ b/src/markup/engine/__tests__/remarkup/table-with-leading-space.txt
@@ -0,0 +1,7 @@
+
+~~~~~~~~~~
+
+~~~~~~~~~~
+| cell |
diff --git a/src/markup/engine/remarkup/blockrule/PhutilRemarkupSimpleTableBlockRule.php b/src/markup/engine/remarkup/blockrule/PhutilRemarkupSimpleTableBlockRule.php
index 9b47f40..474a18a 100644
--- a/src/markup/engine/remarkup/blockrule/PhutilRemarkupSimpleTableBlockRule.php
+++ b/src/markup/engine/remarkup/blockrule/PhutilRemarkupSimpleTableBlockRule.php
@@ -1,73 +1,73 @@
'td', 'content' => $this->applyRules($cell));
}
if (!$headings) {
$rows[] = array('type' => 'tr', 'content' => $cells);
} else if ($rows) {
// Mark previous row with headings.
foreach ($cells as $i => $cell) {
if ($cell['content']) {
$rows[last_key($rows)]['content'][$i]['type'] = 'th';
}
}
}
}
if (!$rows) {
return $this->applyRules($text);
}
return $this->renderRemarkupTable($rows);
}
}
diff --git a/src/markup/engine/remarkup/blockrule/PhutilRemarkupTableBlockRule.php b/src/markup/engine/remarkup/blockrule/PhutilRemarkupTableBlockRule.php
index 776bd16..1250eba 100644
--- a/src/markup/engine/remarkup/blockrule/PhutilRemarkupTableBlockRule.php
+++ b/src/markup/engine/remarkup/blockrule/PhutilRemarkupTableBlockRule.php
@@ -1,107 +1,107 @@
/i', $lines[$cursor])) {
+ if (preg_match('/^\s*/i', $lines[$cursor])) {
$num_lines++;
$cursor++;
while (isset($lines[$cursor])) {
$num_lines++;
if (preg_match('@
$@i', $lines[$cursor])) {
break;
}
$cursor++;
}
}
return $num_lines;
}
public function markupText($text, $children) {
$matches = array();
- if (!preg_match('@^$@si', $text, $matches)) {
+ if (!preg_match('@^\s*$@si', $text, $matches)) {
return $this->fail(
$text,
pht('Bad table (expected %s)', ''));
}
$body = $matches[1];
$row_fragment = '(?:\s*(.*)
\s*)';
$cell_fragment = '(?:\s*<(td|th)>(.*)(?:td|th)>\s*)';
// Test that the body contains only valid rows.
if (!preg_match('@^'.$row_fragment.'+$@Usi', $body)) {
return $this->fail(
$body,
pht('Bad table syntax (expected rows %s)', '...
'));
}
// Capture the rows.
$row_regex = '@'.$row_fragment.'@Usi';
if (!preg_match_all($row_regex, $body, $matches, PREG_SET_ORDER)) {
throw new Exception(
pht('Bug in Remarkup tables, parsing fails for input: %s', $text));
}
$out_rows = array();
$rows = $matches;
foreach ($rows as $row) {
$content = $row[1];
// Test that the row contains only valid cells.
if (!preg_match('@^'.$cell_fragment.'+$@Usi', $content)) {
return $this->fail(
$content,
pht('Bad table syntax (expected cells %s)', '... | '));
}
// Capture the cells.
$cell_regex = '@'.$cell_fragment.'@Usi';
if (!preg_match_all($cell_regex, $content, $matches, PREG_SET_ORDER)) {
throw new Exception(
pht('Bug in Remarkup tables, parsing fails for input: %s', $text));
}
$out_cells = array();
foreach ($matches as $cell) {
$cell_type = $cell[1];
$cell_content = $cell[2];
$out_cells[] = array(
'type' => $cell_type,
'content' => $this->applyRules($cell_content),
);
}
$out_rows[] = array(
'type' => 'tr',
'content' => $out_cells,
);
}
return $this->renderRemarkupTable($out_rows);
}
private function fail($near, $message) {
$message = sprintf(
'%s near: %s',
$message,
id(new PhutilUTF8StringTruncator())
->setMaximumGlyphs(32000)
->truncateString($near));
if ($this->getEngine()->isTextMode()) {
return '('.$message.')';
}
return hsprintf('%s
', $message);
}
}