Skip to content

add support for colspan/rowspan in tables #46

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions api_test/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1417,6 +1417,160 @@ static void parser_interrupt(test_batch_runner *runner) {
cmark_syntax_extension_free(cmark_get_default_mem_allocator(), my_ext);
}

static void compare_table_spans_html(test_batch_runner *runner, const char *markdown, bool use_ditto,
const char *expected_html, const char *msg) {
int options = CMARK_OPT_TABLE_SPANS;
if (use_ditto)
options |= CMARK_OPT_TABLE_ROWSPAN_DITTO;
cmark_parser *parser = cmark_parser_new(options);
cmark_parser_attach_syntax_extension(parser, cmark_find_syntax_extension("table"));

cmark_parser_feed(parser, markdown, strlen(markdown));

cmark_node *doc = cmark_parser_finish(parser);
char *html = cmark_render_html(doc, options, NULL);
STR_EQ(runner, html, expected_html, msg);

free(html);
cmark_node_free(doc);
cmark_parser_free(parser);
}

static void table_spans(test_batch_runner *runner) {
{
static const char markdown[] =
"| one | two |\n"
"| --- | --- |\n"
"| hello ||\n";
static const char html[] =
"<table>\n"
"<thead>\n"
"<tr>\n"
"<th>one</th>\n"
"<th>two</th>\n"
"</tr>\n"
"</thead>\n"
"<tbody>\n"
"<tr>\n"
"<td colspan=\"2\">hello</td>\n"
"</tr>\n"
"</tbody>\n"
"</table>\n";
compare_table_spans_html(runner, markdown, false, html,
"table colspans should work when enabled");
}
{
static const char markdown[] =
"| one | two |\n"
"| --- | ----- |\n"
"| big | small |\n"
"| ^ | small |\n";
static const char html[] =
"<table>\n"
"<thead>\n"
"<tr>\n"
"<th>one</th>\n"
"<th>two</th>\n"
"</tr>\n"
"</thead>\n"
"<tbody>\n"
"<tr>\n"
"<td rowspan=\"2\">big</td>\n"
"<td>small</td>\n"
"</tr>\n"
"<tr>\n"
"<td>small</td>\n"
"</tr>\n"
"</tbody>\n"
"</table>\n";
compare_table_spans_html(runner, markdown, false, html,
"table rowspans should work when enabled");
}
{
static const char markdown[] =
"| one | two |\n"
"| --- | ----- |\n"
"| big | small |\n"
"| \" | small |\n";
static const char html[] =
"<table>\n"
"<thead>\n"
"<tr>\n"
"<th>one</th>\n"
"<th>two</th>\n"
"</tr>\n"
"</thead>\n"
"<tbody>\n"
"<tr>\n"
"<td rowspan=\"2\">big</td>\n"
"<td>small</td>\n"
"</tr>\n"
"<tr>\n"
"<td>small</td>\n"
"</tr>\n"
"</tbody>\n"
"</table>\n";
compare_table_spans_html(runner, markdown, true, html,
"rowspan ditto marks should work when enabled");
}
{
static const char markdown[] =
"| one | two | three |\n"
"| --- | --- | ----- |\n"
"| big || small |\n"
"| ^ || small |\n";
static const char html[] =
"<table>\n"
"<thead>\n"
"<tr>\n"
"<th>one</th>\n"
"<th>two</th>\n"
"<th>three</th>\n"
"</tr>\n"
"</thead>\n"
"<tbody>\n"
"<tr>\n"
"<td colspan=\"2\" rowspan=\"2\">big</td>\n"
"<td>small</td>\n"
"</tr>\n"
"<tr>\n"
"<td>small</td>\n"
"</tr>\n"
"</tbody>\n"
"</table>\n";
compare_table_spans_html(runner, markdown, false, html,
"colspan and rowspan should combine sensibly");
}
{
static const char markdown[] =
"| one | two | three |\n"
"| --- | --- | ----- |\n"
"| big || small |\n"
"| \" || small |\n";
static const char html[] =
"<table>\n"
"<thead>\n"
"<tr>\n"
"<th>one</th>\n"
"<th>two</th>\n"
"<th>three</th>\n"
"</tr>\n"
"</thead>\n"
"<tbody>\n"
"<tr>\n"
"<td colspan=\"2\" rowspan=\"2\">big</td>\n"
"<td>small</td>\n"
"</tr>\n"
"<tr>\n"
"<td>small</td>\n"
"</tr>\n"
"</tbody>\n"
"</table>\n";
compare_table_spans_html(runner, markdown, true, html,
"colspan and rowspan should combine when ditto marks are enabled");
}
}

int main() {
int retval;
test_batch_runner *runner = test_batch_runner_new();
Expand Down Expand Up @@ -1452,6 +1606,7 @@ int main() {
verify_custom_attributes_node(runner);
verify_custom_attributes_node_with_footnote(runner);
parser_interrupt(runner);
table_spans(runner);

test_print_summary(runner);
retval = test_ok(runner) ? 0 : 1;
Expand Down
8 changes: 8 additions & 0 deletions bin/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ void print_usage() {
printf(" with two tildes\n");
printf(" --table-prefer-style-attributes Use style attributes to align table cells\n"
" instead of align attributes.\n");
printf(" --table-spans Enable parsing row- and column-span\n"
" in tables\n");
printf(" --table-rowspan-ditto Use a double-quote 'ditto mark' to indicate\n"
" row span in tables instead of a caret.\n");
printf(" --full-info-string Include remainder of code block info\n"
" string in a separate attribute.\n");
printf(" --help, -h Print usage information\n");
Expand Down Expand Up @@ -167,6 +171,10 @@ int main(int argc, char *argv[]) {
options |= CMARK_OPT_FULL_INFO_STRING;
} else if (strcmp(argv[i], "--table-prefer-style-attributes") == 0) {
options |= CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES;
} else if (strcmp(argv[i], "--table-spans") == 0) {
options |= CMARK_OPT_TABLE_SPANS;
} else if (strcmp(argv[i], "--table-rowspan-ditto") == 0) {
options |= CMARK_OPT_TABLE_ROWSPAN_DITTO;
} else if (strcmp(argv[i], "--strikethrough-double-tilde") == 0) {
options |= CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE;
} else if (strcmp(argv[i], "--sourcepos") == 0) {
Expand Down
32 changes: 32 additions & 0 deletions extensions/include/cmark-gfm-core-extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,38 @@ int cmark_gfm_extensions_set_table_alignments(cmark_node *node, uint16_t ncols,
CMARK_GFM_EXTENSIONS_EXPORT
int cmark_gfm_extensions_get_table_row_is_header(cmark_node *node);

/** Sets the column span for the table cell, returning 1 on success and 0 on error.
*/
CMARK_GFM_EXTENSIONS_EXPORT
int cmark_gfm_extensions_set_table_cell_colspan(cmark_node *node, unsigned colspan);

/** Sets the row span for the table cell, returning 1 on success and 0 on error.
*/
CMARK_GFM_EXTENSIONS_EXPORT
int cmark_gfm_extensions_set_table_cell_rowspan(cmark_node *node, unsigned rowspan);

/**
Gets the column span for the table cell, returning \c UINT_MAX on error.

A value of 0 indicates that the cell is a "filler" cell, intended to be overlapped with a previous
cell with a span > 1.

Column span is only parsed when \c CMARK_OPT_TABLE_SPANS is set.
*/
CMARK_GFM_EXTENSIONS_EXPORT
unsigned cmark_gfm_extensions_get_table_cell_colspan(cmark_node *node);

/**
Gets the row span for the table cell, returning \c UINT_MAX on error.

A value of 0 indicates that the cell is a "filler" cell, intended to be overlapped with a previous
cell with a span > 1.

Row span is only parsed when \c CMARK_OPT_TABLE_SPANS is set.
*/
CMARK_GFM_EXTENSIONS_EXPORT
unsigned cmark_gfm_extensions_get_table_cell_rowspan(cmark_node *node);

/** Sets whether the node is a table header row, returning 1 on success and 0 on error.
*/
CMARK_GFM_EXTENSIONS_EXPORT
Expand Down
Loading