Skip to content

Commit eb9a6a3

Browse files
add support for colspan/rowspan in tables (#46)
rdar://97739626
1 parent 476f7b4 commit eb9a6a3

File tree

6 files changed

+466
-28
lines changed

6 files changed

+466
-28
lines changed

api_test/main.c

+155
Original file line numberDiff line numberDiff line change
@@ -1417,6 +1417,160 @@ static void parser_interrupt(test_batch_runner *runner) {
14171417
cmark_syntax_extension_free(cmark_get_default_mem_allocator(), my_ext);
14181418
}
14191419

1420+
static void compare_table_spans_html(test_batch_runner *runner, const char *markdown, bool use_ditto,
1421+
const char *expected_html, const char *msg) {
1422+
int options = CMARK_OPT_TABLE_SPANS;
1423+
if (use_ditto)
1424+
options |= CMARK_OPT_TABLE_ROWSPAN_DITTO;
1425+
cmark_parser *parser = cmark_parser_new(options);
1426+
cmark_parser_attach_syntax_extension(parser, cmark_find_syntax_extension("table"));
1427+
1428+
cmark_parser_feed(parser, markdown, strlen(markdown));
1429+
1430+
cmark_node *doc = cmark_parser_finish(parser);
1431+
char *html = cmark_render_html(doc, options, NULL);
1432+
STR_EQ(runner, html, expected_html, msg);
1433+
1434+
free(html);
1435+
cmark_node_free(doc);
1436+
cmark_parser_free(parser);
1437+
}
1438+
1439+
static void table_spans(test_batch_runner *runner) {
1440+
{
1441+
static const char markdown[] =
1442+
"| one | two |\n"
1443+
"| --- | --- |\n"
1444+
"| hello ||\n";
1445+
static const char html[] =
1446+
"<table>\n"
1447+
"<thead>\n"
1448+
"<tr>\n"
1449+
"<th>one</th>\n"
1450+
"<th>two</th>\n"
1451+
"</tr>\n"
1452+
"</thead>\n"
1453+
"<tbody>\n"
1454+
"<tr>\n"
1455+
"<td colspan=\"2\">hello</td>\n"
1456+
"</tr>\n"
1457+
"</tbody>\n"
1458+
"</table>\n";
1459+
compare_table_spans_html(runner, markdown, false, html,
1460+
"table colspans should work when enabled");
1461+
}
1462+
{
1463+
static const char markdown[] =
1464+
"| one | two |\n"
1465+
"| --- | ----- |\n"
1466+
"| big | small |\n"
1467+
"| ^ | small |\n";
1468+
static const char html[] =
1469+
"<table>\n"
1470+
"<thead>\n"
1471+
"<tr>\n"
1472+
"<th>one</th>\n"
1473+
"<th>two</th>\n"
1474+
"</tr>\n"
1475+
"</thead>\n"
1476+
"<tbody>\n"
1477+
"<tr>\n"
1478+
"<td rowspan=\"2\">big</td>\n"
1479+
"<td>small</td>\n"
1480+
"</tr>\n"
1481+
"<tr>\n"
1482+
"<td>small</td>\n"
1483+
"</tr>\n"
1484+
"</tbody>\n"
1485+
"</table>\n";
1486+
compare_table_spans_html(runner, markdown, false, html,
1487+
"table rowspans should work when enabled");
1488+
}
1489+
{
1490+
static const char markdown[] =
1491+
"| one | two |\n"
1492+
"| --- | ----- |\n"
1493+
"| big | small |\n"
1494+
"| \" | small |\n";
1495+
static const char html[] =
1496+
"<table>\n"
1497+
"<thead>\n"
1498+
"<tr>\n"
1499+
"<th>one</th>\n"
1500+
"<th>two</th>\n"
1501+
"</tr>\n"
1502+
"</thead>\n"
1503+
"<tbody>\n"
1504+
"<tr>\n"
1505+
"<td rowspan=\"2\">big</td>\n"
1506+
"<td>small</td>\n"
1507+
"</tr>\n"
1508+
"<tr>\n"
1509+
"<td>small</td>\n"
1510+
"</tr>\n"
1511+
"</tbody>\n"
1512+
"</table>\n";
1513+
compare_table_spans_html(runner, markdown, true, html,
1514+
"rowspan ditto marks should work when enabled");
1515+
}
1516+
{
1517+
static const char markdown[] =
1518+
"| one | two | three |\n"
1519+
"| --- | --- | ----- |\n"
1520+
"| big || small |\n"
1521+
"| ^ || small |\n";
1522+
static const char html[] =
1523+
"<table>\n"
1524+
"<thead>\n"
1525+
"<tr>\n"
1526+
"<th>one</th>\n"
1527+
"<th>two</th>\n"
1528+
"<th>three</th>\n"
1529+
"</tr>\n"
1530+
"</thead>\n"
1531+
"<tbody>\n"
1532+
"<tr>\n"
1533+
"<td colspan=\"2\" rowspan=\"2\">big</td>\n"
1534+
"<td>small</td>\n"
1535+
"</tr>\n"
1536+
"<tr>\n"
1537+
"<td>small</td>\n"
1538+
"</tr>\n"
1539+
"</tbody>\n"
1540+
"</table>\n";
1541+
compare_table_spans_html(runner, markdown, false, html,
1542+
"colspan and rowspan should combine sensibly");
1543+
}
1544+
{
1545+
static const char markdown[] =
1546+
"| one | two | three |\n"
1547+
"| --- | --- | ----- |\n"
1548+
"| big || small |\n"
1549+
"| \" || small |\n";
1550+
static const char html[] =
1551+
"<table>\n"
1552+
"<thead>\n"
1553+
"<tr>\n"
1554+
"<th>one</th>\n"
1555+
"<th>two</th>\n"
1556+
"<th>three</th>\n"
1557+
"</tr>\n"
1558+
"</thead>\n"
1559+
"<tbody>\n"
1560+
"<tr>\n"
1561+
"<td colspan=\"2\" rowspan=\"2\">big</td>\n"
1562+
"<td>small</td>\n"
1563+
"</tr>\n"
1564+
"<tr>\n"
1565+
"<td>small</td>\n"
1566+
"</tr>\n"
1567+
"</tbody>\n"
1568+
"</table>\n";
1569+
compare_table_spans_html(runner, markdown, true, html,
1570+
"colspan and rowspan should combine when ditto marks are enabled");
1571+
}
1572+
}
1573+
14201574
int main() {
14211575
int retval;
14221576
test_batch_runner *runner = test_batch_runner_new();
@@ -1452,6 +1606,7 @@ int main() {
14521606
verify_custom_attributes_node(runner);
14531607
verify_custom_attributes_node_with_footnote(runner);
14541608
parser_interrupt(runner);
1609+
table_spans(runner);
14551610

14561611
test_print_summary(runner);
14571612
retval = test_ok(runner) ? 0 : 1;

bin/main.c

+8
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ void print_usage() {
6262
printf(" with two tildes\n");
6363
printf(" --table-prefer-style-attributes Use style attributes to align table cells\n"
6464
" instead of align attributes.\n");
65+
printf(" --table-spans Enable parsing row- and column-span\n"
66+
" in tables\n");
67+
printf(" --table-rowspan-ditto Use a double-quote 'ditto mark' to indicate\n"
68+
" row span in tables instead of a caret.\n");
6569
printf(" --full-info-string Include remainder of code block info\n"
6670
" string in a separate attribute.\n");
6771
printf(" --help, -h Print usage information\n");
@@ -167,6 +171,10 @@ int main(int argc, char *argv[]) {
167171
options |= CMARK_OPT_FULL_INFO_STRING;
168172
} else if (strcmp(argv[i], "--table-prefer-style-attributes") == 0) {
169173
options |= CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES;
174+
} else if (strcmp(argv[i], "--table-spans") == 0) {
175+
options |= CMARK_OPT_TABLE_SPANS;
176+
} else if (strcmp(argv[i], "--table-rowspan-ditto") == 0) {
177+
options |= CMARK_OPT_TABLE_ROWSPAN_DITTO;
170178
} else if (strcmp(argv[i], "--strikethrough-double-tilde") == 0) {
171179
options |= CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE;
172180
} else if (strcmp(argv[i], "--sourcepos") == 0) {

extensions/include/cmark-gfm-core-extensions.h

+32
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,38 @@ int cmark_gfm_extensions_set_table_alignments(cmark_node *node, uint16_t ncols,
3232
CMARK_GFM_EXTENSIONS_EXPORT
3333
int cmark_gfm_extensions_get_table_row_is_header(cmark_node *node);
3434

35+
/** Sets the column span for the table cell, returning 1 on success and 0 on error.
36+
*/
37+
CMARK_GFM_EXTENSIONS_EXPORT
38+
int cmark_gfm_extensions_set_table_cell_colspan(cmark_node *node, unsigned colspan);
39+
40+
/** Sets the row span for the table cell, returning 1 on success and 0 on error.
41+
*/
42+
CMARK_GFM_EXTENSIONS_EXPORT
43+
int cmark_gfm_extensions_set_table_cell_rowspan(cmark_node *node, unsigned rowspan);
44+
45+
/**
46+
Gets the column span for the table cell, returning \c UINT_MAX on error.
47+
48+
A value of 0 indicates that the cell is a "filler" cell, intended to be overlapped with a previous
49+
cell with a span > 1.
50+
51+
Column span is only parsed when \c CMARK_OPT_TABLE_SPANS is set.
52+
*/
53+
CMARK_GFM_EXTENSIONS_EXPORT
54+
unsigned cmark_gfm_extensions_get_table_cell_colspan(cmark_node *node);
55+
56+
/**
57+
Gets the row span for the table cell, returning \c UINT_MAX on error.
58+
59+
A value of 0 indicates that the cell is a "filler" cell, intended to be overlapped with a previous
60+
cell with a span > 1.
61+
62+
Row span is only parsed when \c CMARK_OPT_TABLE_SPANS is set.
63+
*/
64+
CMARK_GFM_EXTENSIONS_EXPORT
65+
unsigned cmark_gfm_extensions_get_table_cell_rowspan(cmark_node *node);
66+
3567
/** Sets whether the node is a table header row, returning 1 on success and 0 on error.
3668
*/
3769
CMARK_GFM_EXTENSIONS_EXPORT

0 commit comments

Comments
 (0)