From cd9ab8fdc9fc8b1dc3b4f4b43b47ceeb53c74d8f Mon Sep 17 00:00:00 2001 From: Nathan Aschbacher Date: Sat, 5 Aug 2017 21:44:56 -0700 Subject: [PATCH] Add exposing list markers *, -, +, or numeric to AST and API. Prior to this commit the node struct for a list contained a member to store whatever char was parsed from the markdown, but this value wasn't exposed through the API, nor was it made available in the output of the AST in any format. Following this commit a `cmark_marker_type` struct has been added to capture various forms of list markers: `CMARK_NUMERIC_MARKER` (for ordered lists) and `CMARK_ASTERISK_MARKER`, `CMARK_HYPHEN_MARKER`, & `CMARK_PLUS_MARKER` (for unordered lists). The value of which is stored in the `marker` member of the `cmark_list` node struct. This enables two primary features: 1. The bullet marker types are now preserved when converting from markdown to markdown. 2. The XML representation of the AST now has a `marker="hyphen"` (as well as numeric, asterisk, and plus) as an attribute on the list nodes. This is similar to the `delim="period"` attribute available on ordered list nodes. Tests have been added and are passing. The original test suite still passes as well. This commit also updates the racket-lang wrapper to support these new features as well as fixes a minor bug for a missing `no_delim` symbol because `NO_DELIM` wasn't defined in cmark.h --- api_test/main.c | 8 ++++++++ src/blocks.c | 8 ++++++++ src/cmark.h | 24 +++++++++++++++++++++++ src/commonmark.c | 17 +++++++++------- src/node.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ src/node.h | 1 + src/xml.c | 13 +++++++++++++ wrappers/wrapper.rkt | 6 +++++- 8 files changed, 115 insertions(+), 8 deletions(-) diff --git a/api_test/main.c b/api_test/main.c index d7202343b..e9777f1ac 100644 --- a/api_test/main.c +++ b/api_test/main.c @@ -103,6 +103,8 @@ static void accessors(test_batch_runner *runner) { cmark_node *bullet_list = cmark_node_next(heading); INT_EQ(runner, cmark_node_get_list_type(bullet_list), CMARK_BULLET_LIST, "get_list_type bullet"); + INT_EQ(runner, cmark_node_get_list_marker(bullet_list), CMARK_ASTERISK_MARKER, + "get_list_marker asterisk"); INT_EQ(runner, cmark_node_get_list_tight(bullet_list), 1, "get_list_tight tight"); @@ -111,6 +113,8 @@ static void accessors(test_batch_runner *runner) { "get_list_type ordered"); INT_EQ(runner, cmark_node_get_list_delim(ordered_list), CMARK_PERIOD_DELIM, "get_list_delim ordered"); + INT_EQ(runner, cmark_node_get_list_marker(ordered_list), CMARK_NUMERIC_MARKER, + "get_list_marker numeric"); INT_EQ(runner, cmark_node_get_list_start(ordered_list), 2, "get_list_start"); INT_EQ(runner, cmark_node_get_list_tight(ordered_list), 0, "get_list_tight loose"); @@ -144,10 +148,14 @@ static void accessors(test_batch_runner *runner) { OK(runner, cmark_node_set_heading_level(heading, 3), "set_heading_level"); + OK(runner, cmark_node_set_list_marker(bullet_list, CMARK_HYPHEN_MARKER), + "set_list_marker hyphen"); OK(runner, cmark_node_set_list_type(bullet_list, CMARK_ORDERED_LIST), "set_list_type ordered"); OK(runner, cmark_node_set_list_delim(bullet_list, CMARK_PAREN_DELIM), "set_list_delim paren"); + OK(runner, cmark_node_set_list_marker(bullet_list, CMARK_NUMERIC_MARKER), + "set_list_marker numeric"); OK(runner, cmark_node_set_list_start(bullet_list, 3), "set_list_start"); OK(runner, cmark_node_set_list_tight(bullet_list, 0), "set_list_tight loose"); diff --git a/src/blocks.c b/src/blocks.c index 5a293b2e0..4382ec26b 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -414,6 +414,13 @@ static bufsize_t parse_list_marker(cmark_mem *mem, cmark_chunk *input, data->marker_offset = 0; // will be adjusted later data->list_type = CMARK_BULLET_LIST; data->bullet_char = c; + if (c == '*') { + data->marker = CMARK_ASTERISK_MARKER; + } else if (c == '-') { + data->marker = CMARK_HYPHEN_MARKER; + } else if (c == '+') { + data->marker = CMARK_PLUS_MARKER; + } data->start = 0; data->delimiter = CMARK_NO_DELIM; data->tight = false; @@ -454,6 +461,7 @@ static bufsize_t parse_list_marker(cmark_mem *mem, cmark_chunk *input, data->marker_offset = 0; // will be adjusted later data->list_type = CMARK_ORDERED_LIST; data->bullet_char = 0; + data->marker = CMARK_NUMERIC_MARKER; data->start = start; data->delimiter = (c == '.' ? CMARK_PERIOD_DELIM : CMARK_PAREN_DELIM); data->tight = false; diff --git a/src/cmark.h b/src/cmark.h index d1a65aa88..ea099446d 100644 --- a/src/cmark.h +++ b/src/cmark.h @@ -83,6 +83,14 @@ typedef enum { CMARK_PAREN_DELIM } cmark_delim_type; +typedef enum { + CMARK_NO_MARKER, + CMARK_NUMERIC_MARKER, + CMARK_ASTERISK_MARKER, + CMARK_HYPHEN_MARKER, + CMARK_PLUS_MARKER +} cmark_marker_type; + typedef struct cmark_node cmark_node; typedef struct cmark_parser cmark_parser; typedef struct cmark_iter cmark_iter; @@ -308,6 +316,16 @@ CMARK_EXPORT cmark_delim_type cmark_node_get_list_delim(cmark_node *node); CMARK_EXPORT int cmark_node_set_list_delim(cmark_node *node, cmark_delim_type delim); +/** Returns the marker type of 'node' or CMARK_NO_MARKER if 'node' is not a + * list. + */ +CMARK_EXPORT cmark_marker_type cmark_node_get_list_marker(cmark_node *node); + +/** Sets the marker type of 'node', returning 1 on success and 0 on error. + */ +CMARK_EXPORT int cmark_node_set_list_marker(cmark_node *node, + cmark_marker_type marker); + /** Returns starting number of 'node', if it is an ordered list, otherwise 0. */ CMARK_EXPORT int cmark_node_get_list_start(cmark_node *node); @@ -633,8 +651,14 @@ const char *cmark_version_string(void); #define NODE_IMAGE CMARK_NODE_IMAGE #define BULLET_LIST CMARK_BULLET_LIST #define ORDERED_LIST CMARK_ORDERED_LIST +#define NO_DELIM CMARK_NO_DELIM #define PERIOD_DELIM CMARK_PERIOD_DELIM #define PAREN_DELIM CMARK_PAREN_DELIM +#define NO_MARKER CMARK_PERIOD_DELIM +#define NUMERIC_MARKER CMARK_NUMERIC_MARKER +#define ASTERISK_MARKER CMARK_ASTERISK_MARKER +#define HYPHEN_MARKER CMARK_HYPHEN_MARKER +#define PLUS_MARKER CMARK_PLUS_MARKER #endif #ifdef __cplusplus diff --git a/src/commonmark.c b/src/commonmark.c index 95a1ae5e5..e22f8f5fd 100644 --- a/src/commonmark.c +++ b/src/commonmark.c @@ -220,6 +220,14 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node, case CMARK_NODE_ITEM: if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) { marker_width = 4; + if (cmark_node_get_list_marker(node->parent) == CMARK_ASTERISK_MARKER) { + snprintf(listmarker, LISTMARKER_SIZE, " %s ", "*"); + } else if (cmark_node_get_list_marker(node->parent) == + CMARK_PLUS_MARKER) { + snprintf(listmarker, LISTMARKER_SIZE, " %s ", "+"); + } else { + snprintf(listmarker, LISTMARKER_SIZE, " %s ", "-"); + } } else { list_number = cmark_node_get_list_start(node->parent); list_delim = cmark_node_get_list_delim(node->parent); @@ -237,13 +245,8 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node, marker_width = strlen(listmarker); } if (entering) { - if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) { - LIT(" - "); - renderer->begin_content = true; - } else { - LIT(listmarker); - renderer->begin_content = true; - } + LIT(listmarker); + renderer->begin_content = true; for (i = marker_width; i--;) { cmark_strbuf_putc(renderer->prefix, ' '); } diff --git a/src/node.c b/src/node.c index c6c29028e..e44403c07 100644 --- a/src/node.c +++ b/src/node.c @@ -402,6 +402,52 @@ int cmark_node_set_list_delim(cmark_node *node, cmark_delim_type delim) { } } +cmark_marker_type cmark_node_get_list_marker(cmark_node *node) { + if (node == NULL) { + return CMARK_NO_MARKER; + } + + if (node->type == CMARK_NODE_LIST) { + return node->as.list.marker; + } else { + return CMARK_NO_MARKER; + } +} + +int cmark_node_set_list_marker(cmark_node *node, cmark_marker_type marker) { + if (node == NULL) { + return 0; + } + + if (node->type != CMARK_NODE_LIST) { + return 0; + } + + if (cmark_node_get_list_type(node) == CMARK_ORDERED_LIST && + marker == CMARK_NUMERIC_MARKER) { + node->as.list.bullet_char = 0; + node->as.list.marker = CMARK_NUMERIC_MARKER; + return 1; + } else if (cmark_node_get_list_type(node) == CMARK_BULLET_LIST && + marker == CMARK_ASTERISK_MARKER) { + node->as.list.bullet_char = '*'; + node->as.list.marker = marker; + return 1; + } else if (cmark_node_get_list_type(node) == CMARK_BULLET_LIST && + marker == CMARK_HYPHEN_MARKER) { + node->as.list.bullet_char = '-'; + node->as.list.marker = marker; + return 1; + } else if (cmark_node_get_list_type(node) == CMARK_BULLET_LIST && + marker == CMARK_PLUS_MARKER) { + node->as.list.bullet_char = '+'; + node->as.list.marker = marker; + return 1; + } else { + return 0; + } +} + int cmark_node_get_list_start(cmark_node *node) { if (node == NULL) { return 0; diff --git a/src/node.h b/src/node.h index 65d857f0b..c7f152fb3 100644 --- a/src/node.h +++ b/src/node.h @@ -20,6 +20,7 @@ typedef struct { cmark_delim_type delimiter; unsigned char bullet_char; bool tight; + cmark_marker_type marker; } cmark_list; typedef struct { diff --git a/src/xml.c b/src/xml.c index 4898cd2e8..8086a7609 100644 --- a/src/xml.c +++ b/src/xml.c @@ -35,6 +35,7 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type, cmark_strbuf *xml = state->xml; bool literal = false; cmark_delim_type delim; + cmark_marker_type marker; bool entering = (ev_type == CMARK_EVENT_ENTER); char buffer[BUFFER_SIZE]; @@ -79,9 +80,21 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type, } else if (delim == CMARK_PERIOD_DELIM) { cmark_strbuf_puts(xml, " delim=\"period\""); } + marker = cmark_node_get_list_marker(node); + if (marker == CMARK_NUMERIC_MARKER) { + cmark_strbuf_puts(xml, " marker=\"numeric\""); + } break; case CMARK_BULLET_LIST: cmark_strbuf_puts(xml, " type=\"bullet\""); + marker = cmark_node_get_list_marker(node); + if (marker == CMARK_ASTERISK_MARKER) { + cmark_strbuf_puts(xml, " marker=\"asterisk\""); + } else if (marker == CMARK_HYPHEN_MARKER) { + cmark_strbuf_puts(xml, " marker=\"hyphen\""); + } else if (marker == CMARK_PLUS_MARKER) { + cmark_strbuf_puts(xml, " marker=\"plus\""); + } break; default: break; diff --git a/wrappers/wrapper.rkt b/wrappers/wrapper.rkt index d9b34e849..5d0341f46 100644 --- a/wrappers/wrapper.rkt +++ b/wrappers/wrapper.rkt @@ -24,6 +24,8 @@ (_enum '(no_list bullet_list ordered_list))) (define _cmark_delim_type (_enum '(no_delim period_delim paren_delim))) + (define _cmark_marker_type + (_enum '(no_marker numeric_marker asterisk_marker hyphen_marker plus_marker))) (define _cmark_opts (_bitmask '(sourcepos = 1 hardbreaks = 2 normalize = 4 smart = 8))) @@ -62,6 +64,8 @@ (defcmark cmark_node_set_list_type (_fun _node _cmark_list_type -> _bool)) (defcmark cmark_node_get_list_delim (_fun _node -> _cmark_delim_type)) (defcmark cmark_node_set_list_delim (_fun _node _cmark_delim_type -> _bool)) + (defcmark cmark_node_get_list_marker (_fun _node -> _cmark_marker_type)) + (defcmark cmark_node_set_list_marker (_fun _node _cmark_marker_type -> _bool)) (defcmark cmark_node_get_list_start (_fun _node -> _int)) (defcmark cmark_node_set_list_start (_fun _node _int -> _bool)) (defcmark cmark_node_get_list_tight (_fun _node -> _bool)) @@ -110,7 +114,7 @@ (define-getters+setters getters+setters [header header_level] [code-block fence_info] [link url title] [image url title] - [list list_type list_delim list_start list_tight]) + [list list_type list_delim list_marker list_start list_tight]) (provide cmark->sexpr) (define (cmark->sexpr node)