http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5672da15/compiler/modules/CommonMark/src/cmark_ctype.c ---------------------------------------------------------------------- diff --git a/compiler/modules/CommonMark/src/cmark_ctype.c b/compiler/modules/CommonMark/src/cmark_ctype.c new file mode 100644 index 0000000..5de8199 --- /dev/null +++ b/compiler/modules/CommonMark/src/cmark_ctype.c @@ -0,0 +1,53 @@ +#include <stdint.h> + +#include "cmark_ctype.h" + +/** 1 = space, 2 = punct, 3 = digit, 4 = alpha, 0 = other + */ +static const int8_t cmark_ctype_class[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, + /* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 2 */ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + /* 3 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + /* 4 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + /* 5 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, + /* 6 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + /* 7 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0, + /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/** + * Returns 1 if c is a "whitespace" character as defined by the spec. + */ +int cmark_isspace(char c) +{ + return cmark_ctype_class[(int8_t)c] == 1; +} + +/** + * Returns 1 if c is an ascii punctuation character. + */ +int cmark_ispunct(char c) +{ + return cmark_ctype_class[(int8_t)c] == 2; +} + +int cmark_isalnum(char c) +{ + int8_t result; + result = cmark_ctype_class[(int8_t)c]; + return (result == 3 || result == 4); +} + +int cmark_isdigit(char c) +{ + return cmark_ctype_class[(int8_t)c] == 3; +}
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5672da15/compiler/modules/CommonMark/src/cmark_ctype.h ---------------------------------------------------------------------- diff --git a/compiler/modules/CommonMark/src/cmark_ctype.h b/compiler/modules/CommonMark/src/cmark_ctype.h new file mode 100644 index 0000000..f803946 --- /dev/null +++ b/compiler/modules/CommonMark/src/cmark_ctype.h @@ -0,0 +1,24 @@ +#ifndef CMARK_CMARK_CTYPE_H +#define CMARK_CMARK_CTYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** Locale-independent versions of functions from ctype.h. + * We want cmark to behave the same no matter what the system locale. + */ + +int cmark_isspace(char c); + +int cmark_ispunct(char c); + +int cmark_isalnum(char c); + +int cmark_isdigit(char c); + +#ifdef __cplusplus +} +#endif + +#endif http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5672da15/compiler/modules/CommonMark/src/cmark_export.h ---------------------------------------------------------------------- diff --git a/compiler/modules/CommonMark/src/cmark_export.h b/compiler/modules/CommonMark/src/cmark_export.h index fa14b4d..1102c36 100644 --- a/compiler/modules/CommonMark/src/cmark_export.h +++ b/compiler/modules/CommonMark/src/cmark_export.h @@ -1,7 +1,35 @@ + #ifndef CMARK_EXPORT_H #define CMARK_EXPORT_H -#define CMARK_EXPORT -#define CMARK_NO_EXPORT +#ifdef CMARK_STATIC_DEFINE +# define CMARK_EXPORT +# define CMARK_NO_EXPORT +#else +# ifndef CMARK_EXPORT +# ifdef libcmark_EXPORTS + /* We are building this library */ +# define CMARK_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define CMARK_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef CMARK_NO_EXPORT +# define CMARK_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef CMARK_DEPRECATED +# define CMARK_DEPRECATED __attribute__ ((__deprecated__)) +# define CMARK_DEPRECATED_EXPORT CMARK_EXPORT __attribute__ ((__deprecated__)) +# define CMARK_DEPRECATED_NO_EXPORT CMARK_NO_EXPORT __attribute__ ((__deprecated__)) +#endif + +#define DEFINE_NO_DEPRECATED 0 +#if DEFINE_NO_DEPRECATED +# define CMARK_NO_DEPRECATED +#endif #endif http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5672da15/compiler/modules/CommonMark/src/config.h ---------------------------------------------------------------------- diff --git a/compiler/modules/CommonMark/src/config.h b/compiler/modules/CommonMark/src/config.h index ce3064e..ecfa334 100644 --- a/compiler/modules/CommonMark/src/config.h +++ b/compiler/modules/CommonMark/src/config.h @@ -9,3 +9,7 @@ typedef char bool; #endif #define CMARK_ATTRIBUTE(list) + +#ifndef CHY_HAS_VA_COPY + #define va_copy(dest, src) ((dest) = (src)) +#endif http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5672da15/compiler/modules/CommonMark/src/config.h.in ---------------------------------------------------------------------- diff --git a/compiler/modules/CommonMark/src/config.h.in b/compiler/modules/CommonMark/src/config.h.in index 5294bc9..c1e9597 100644 --- a/compiler/modules/CommonMark/src/config.h.in +++ b/compiler/modules/CommonMark/src/config.h.in @@ -15,3 +15,9 @@ #else #define CMARK_ATTRIBUTE(list) #endif + +#cmakedefine HAVE_VA_COPY + +#ifndef HAVE_VA_COPY + #define va_copy(dest, src) ((dest) = (src)) +#endif http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5672da15/compiler/modules/CommonMark/src/houdini.h ---------------------------------------------------------------------- diff --git a/compiler/modules/CommonMark/src/houdini.h b/compiler/modules/CommonMark/src/houdini.h index 9e1200e..9f00f6d 100644 --- a/compiler/modules/CommonMark/src/houdini.h +++ b/compiler/modules/CommonMark/src/houdini.h @@ -31,19 +31,19 @@ extern "C" { #define HOUDINI_ESCAPED_SIZE(x) (((x) * 12) / 10) #define HOUDINI_UNESCAPED_SIZE(x) (x) -extern size_t houdini_unescape_ent(strbuf *ob, const uint8_t *src, size_t size); -extern int houdini_escape_html(strbuf *ob, const uint8_t *src, size_t size); -extern int houdini_escape_html0(strbuf *ob, const uint8_t *src, size_t size, int secure); -extern int houdini_unescape_html(strbuf *ob, const uint8_t *src, size_t size); -extern void houdini_unescape_html_f(strbuf *ob, const uint8_t *src, size_t size); -extern int houdini_escape_xml(strbuf *ob, const uint8_t *src, size_t size); -extern int houdini_escape_uri(strbuf *ob, const uint8_t *src, size_t size); -extern int houdini_escape_url(strbuf *ob, const uint8_t *src, size_t size); -extern int houdini_escape_href(strbuf *ob, const uint8_t *src, size_t size); -extern int houdini_unescape_uri(strbuf *ob, const uint8_t *src, size_t size); -extern int houdini_unescape_url(strbuf *ob, const uint8_t *src, size_t size); -extern int houdini_escape_js(strbuf *ob, const uint8_t *src, size_t size); -extern int houdini_unescape_js(strbuf *ob, const uint8_t *src, size_t size); +extern size_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src, size_t size); +extern int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src, size_t size); +extern int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src, size_t size, int secure); +extern int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src, size_t size); +extern void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src, size_t size); +extern int houdini_escape_xml(cmark_strbuf *ob, const uint8_t *src, size_t size); +extern int houdini_escape_uri(cmark_strbuf *ob, const uint8_t *src, size_t size); +extern int houdini_escape_url(cmark_strbuf *ob, const uint8_t *src, size_t size); +extern int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src, size_t size); +extern int houdini_unescape_uri(cmark_strbuf *ob, const uint8_t *src, size_t size); +extern int houdini_unescape_url(cmark_strbuf *ob, const uint8_t *src, size_t size); +extern int houdini_escape_js(cmark_strbuf *ob, const uint8_t *src, size_t size); +extern int houdini_unescape_js(cmark_strbuf *ob, const uint8_t *src, size_t size); #ifdef __cplusplus } http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5672da15/compiler/modules/CommonMark/src/houdini_href_e.c ---------------------------------------------------------------------- diff --git a/compiler/modules/CommonMark/src/houdini_href_e.c b/compiler/modules/CommonMark/src/houdini_href_e.c index 1c99432..7527780 100644 --- a/compiler/modules/CommonMark/src/houdini_href_e.c +++ b/compiler/modules/CommonMark/src/houdini_href_e.c @@ -49,7 +49,7 @@ static const char HREF_SAFE[] = { }; int -houdini_escape_href(strbuf *ob, const uint8_t *src, size_t size) +houdini_escape_href(cmark_strbuf *ob, const uint8_t *src, size_t size) { static const uint8_t hex_chars[] = "0123456789ABCDEF"; size_t i = 0, org; @@ -63,7 +63,7 @@ houdini_escape_href(strbuf *ob, const uint8_t *src, size_t size) i++; if (likely(i > org)) - strbuf_put(ob, src + org, i - org); + cmark_strbuf_put(ob, src + org, i - org); /* escaping */ if (i >= size) @@ -73,23 +73,23 @@ houdini_escape_href(strbuf *ob, const uint8_t *src, size_t size) /* amp appears all the time in URLs, but needs * HTML-entity escaping to be inside an href */ case '&': - strbuf_puts(ob, "&"); + cmark_strbuf_puts(ob, "&"); break; /* the single quote is a valid URL character * according to the standard; it needs HTML * entity escaping too */ case '\'': - strbuf_puts(ob, "'"); + cmark_strbuf_puts(ob, "'"); break; - /* the space can be escaped to %20 or a plus - * sign. we're going with the generic escape - * for now. the plus thing is more commonly seen - * when building GET strings */ + /* the space can be escaped to %20 or a plus + * sign. we're going with the generic escape + * for now. the plus thing is more commonly seen + * when building GET strings */ #if 0 case ' ': - strbuf_putc(ob, '+'); + cmark_strbuf_putc(ob, '+'); break; #endif @@ -97,7 +97,7 @@ houdini_escape_href(strbuf *ob, const uint8_t *src, size_t size) default: hex_str[1] = hex_chars[(src[i] >> 4) & 0xF]; hex_str[2] = hex_chars[src[i] & 0xF]; - strbuf_put(ob, hex_str, 3); + cmark_strbuf_put(ob, hex_str, 3); } i++; http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5672da15/compiler/modules/CommonMark/src/houdini_html_e.c ---------------------------------------------------------------------- diff --git a/compiler/modules/CommonMark/src/houdini_html_e.c b/compiler/modules/CommonMark/src/houdini_html_e.c index db5034b..1a4c3e1 100644 --- a/compiler/modules/CommonMark/src/houdini_html_e.c +++ b/compiler/modules/CommonMark/src/houdini_html_e.c @@ -35,17 +35,17 @@ static const char HTML_ESCAPE_TABLE[] = { }; static const char *HTML_ESCAPES[] = { - "", - """, - "&", - "'", - "/", - "<", - ">" + "", + """, + "&", + "'", + "/", + "<", + ">" }; int -houdini_escape_html0(strbuf *ob, const uint8_t *src, size_t size, int secure) +houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src, size_t size, int secure) { size_t i = 0, org, esc = 0; @@ -55,7 +55,7 @@ houdini_escape_html0(strbuf *ob, const uint8_t *src, size_t size, int secure) i++; if (i > org) - strbuf_put(ob, src + org, i - org); + cmark_strbuf_put(ob, src + org, i - org); /* escaping */ if (unlikely(i >= size)) @@ -63,9 +63,9 @@ houdini_escape_html0(strbuf *ob, const uint8_t *src, size_t size, int secure) /* The forward slash is only escaped in secure mode */ if ((src[i] == '/' || src[i] == '\'') && !secure) { - strbuf_putc(ob, src[i]); + cmark_strbuf_putc(ob, src[i]); } else { - strbuf_puts(ob, HTML_ESCAPES[esc]); + cmark_strbuf_puts(ob, HTML_ESCAPES[esc]); } i++; @@ -75,7 +75,7 @@ houdini_escape_html0(strbuf *ob, const uint8_t *src, size_t size, int secure) } int -houdini_escape_html(strbuf *ob, const uint8_t *src, size_t size) +houdini_escape_html(cmark_strbuf *ob, const uint8_t *src, size_t size) { return houdini_escape_html0(ob, src, size, 1); } http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5672da15/compiler/modules/CommonMark/src/houdini_html_u.c ---------------------------------------------------------------------- diff --git a/compiler/modules/CommonMark/src/houdini_html_u.c b/compiler/modules/CommonMark/src/houdini_html_u.c index b88b9d1..ecd7faa 100644 --- a/compiler/modules/CommonMark/src/houdini_html_u.c +++ b/compiler/modules/CommonMark/src/houdini_html_u.c @@ -8,7 +8,7 @@ #include "html_unescape.h" size_t -houdini_unescape_ent(strbuf *ob, const uint8_t *src, size_t size) +houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src, size_t size) { size_t i = 0; @@ -55,7 +55,8 @@ houdini_unescape_ent(strbuf *ob, const uint8_t *src, size_t size) const struct html_ent *entity = find_entity((char *)src, i); if (entity != NULL) { - strbuf_put(ob, entity->utf8, entity->utf8_len); + size_t len = strnlen((const char *)entity->utf8, 4); + cmark_strbuf_put(ob, entity->utf8, len); return i + 1; } @@ -68,7 +69,7 @@ houdini_unescape_ent(strbuf *ob, const uint8_t *src, size_t size) } int -houdini_unescape_html(strbuf *ob, const uint8_t *src, size_t size) +houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src, size_t size) { size_t i = 0, org, ent; @@ -82,10 +83,10 @@ houdini_unescape_html(strbuf *ob, const uint8_t *src, size_t size) if (i >= size) return 0; - strbuf_grow(ob, HOUDINI_UNESCAPED_SIZE(size)); + cmark_strbuf_grow(ob, HOUDINI_UNESCAPED_SIZE(size)); } - strbuf_put(ob, src + org, i - org); + cmark_strbuf_put(ob, src + org, i - org); } /* escaping */ @@ -99,14 +100,14 @@ houdini_unescape_html(strbuf *ob, const uint8_t *src, size_t size) /* not really an entity */ if (ent == 0) - strbuf_putc(ob, '&'); + cmark_strbuf_putc(ob, '&'); } return 1; } -void houdini_unescape_html_f(strbuf *ob, const uint8_t *src, size_t size) +void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src, size_t size) { if (!houdini_unescape_html(ob, src, size)) - strbuf_put(ob, src, size); + cmark_strbuf_put(ob, src, size); } http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5672da15/compiler/modules/CommonMark/src/html.c ---------------------------------------------------------------------- diff --git a/compiler/modules/CommonMark/src/html.c b/compiler/modules/CommonMark/src/html.c index 60229cc..abc3e83 100644 --- a/compiler/modules/CommonMark/src/html.c +++ b/compiler/modules/CommonMark/src/html.c @@ -11,10 +11,7 @@ // Functions to convert cmark_nodes to HTML strings. -static bool -finish_node(strbuf *html, cmark_node *node, bool tight); - -static void escape_html(strbuf *dest, const unsigned char *source, int length) +static void escape_html(cmark_strbuf *dest, const unsigned char *source, int length) { if (length < 0) length = strlen((char *)source); @@ -22,7 +19,7 @@ static void escape_html(strbuf *dest, const unsigned char *source, int length) houdini_escape_html0(dest, source, (size_t)length, 0); } -static void escape_href(strbuf *dest, const unsigned char *source, int length) +static void escape_href(cmark_strbuf *dest, const unsigned char *source, int length) { if (length < 0) length = strlen((char *)source); @@ -30,328 +27,298 @@ static void escape_href(strbuf *dest, const unsigned char *source, int length) houdini_escape_href(dest, source, (size_t)length); } -static inline void cr(strbuf *html) +static inline void cr(cmark_strbuf *html) { if (html->size && html->ptr[html->size - 1] != '\n') - strbuf_putc(html, '\n'); + cmark_strbuf_putc(html, '\n'); } -// Convert the inline children of a node to a plain string. -static void inlines_to_plain_html(strbuf *html, cmark_node* node) -{ - cmark_node* cur = node->first_child; - - if (cur == NULL) { - return; - } - - while (true) { - switch(cur->type) { - case NODE_TEXT: - case NODE_INLINE_CODE: - case NODE_INLINE_HTML: - escape_html(html, cur->as.literal.data, cur->as.literal.len); - break; - - case NODE_LINEBREAK: - case NODE_SOFTBREAK: - strbuf_putc(html, ' '); - break; +struct render_state { + cmark_strbuf* html; + cmark_node *plain; +}; - default: - break; - } - - if (cur->first_child) { - cur = cur->first_child; - continue; - } - - next_sibling: - if (cur->next) { - cur = cur->next; - continue; - } - cur = cur->parent; - if (cur == node) { - break; - } - goto next_sibling; +static void +S_render_sourcepos(cmark_node *node, cmark_strbuf *html, long options) +{ + if (CMARK_OPT_SOURCEPOS & options) { + cmark_strbuf_printf(html, " data-sourcepos=\"%d:%d-%d:%d\"", + cmark_node_get_start_line(node), + cmark_node_get_start_column(node), + cmark_node_get_end_line(node), + cmark_node_get_end_column(node)); } } - -// Convert a cmark_node to HTML. -static void node_to_html(strbuf *html, cmark_node *node) +static int +S_render_node(cmark_node *node, cmark_event_type ev_type, + struct render_state *state, long options) { - cmark_node *cur; - char start_header[] = "<h0>"; - bool tight = false; - bool visit_children; - strbuf *info; - - if (node == NULL) { - return; - } + cmark_node *parent; + cmark_node *grandparent; + cmark_strbuf *html = state->html; + char start_header[] = "<h0"; + char end_header[] = "</h0"; + bool tight; - cur = node; - while (true) { - // Only NODE_IMAGE wants to skip its children. - visit_children = true; + bool entering = (ev_type == CMARK_EVENT_ENTER); - switch(cur->type) { - case NODE_DOCUMENT: - break; + if (state->plain == node) { // back at original node + state->plain = NULL; + } - case NODE_PARAGRAPH: - if (!tight) { - cr(html); - strbuf_puts(html, "<p>"); - } + if (state->plain != NULL) { + switch(node->type) { + case CMARK_NODE_TEXT: + case CMARK_NODE_CODE: + case CMARK_NODE_INLINE_HTML: + escape_html(html, node->as.literal.data, + node->as.literal.len); break; - case NODE_BLOCK_QUOTE: - cr(html); - strbuf_puts(html, "<blockquote>\n"); - // BLOCK_QUOTE doesn't use any of the 'as' structs, - // so the 'list' member can be used to store the - // current value of 'tight'. - cur->as.list.tight = tight; - tight = false; + case CMARK_NODE_LINEBREAK: + case CMARK_NODE_SOFTBREAK: + cmark_strbuf_putc(html, ' '); break; - case NODE_LIST_ITEM: - cr(html); - strbuf_puts(html, "<li>"); + default: break; + } + return 1; + } - case NODE_LIST: { - cmark_list *list = &cur->as.list; - bool tmp; + switch (node->type) { + case CMARK_NODE_DOCUMENT: + break; - // make sure a list starts at the beginning of the line: + case CMARK_NODE_BLOCK_QUOTE: + if (entering) { cr(html); - - if (list->list_type == CMARK_BULLET_LIST) { - strbuf_puts(html, "<ul>\n"); - } - else if (list->start == 1) { - strbuf_puts(html, "<ol>\n"); - } - else { - strbuf_printf(html, "<ol start=\"%d\">\n", - list->start); - } - - // Store the current value of 'tight' by swapping. - tmp = list->tight; - list->tight = tight; - tight = tmp; - break; + cmark_strbuf_puts(html, "<blockquote"); + S_render_sourcepos(node, html, options); + cmark_strbuf_puts(html, ">\n"); + } else { + cr(html); + cmark_strbuf_puts(html, "</blockquote>\n"); } + break; - case NODE_HEADER: - cr(html); - start_header[2] = '0' + cur->as.header.level; - strbuf_puts(html, start_header); - break; + case CMARK_NODE_LIST: { + cmark_list_type list_type = node->as.list.list_type; + int start = node->as.list.start; - case NODE_CODE_BLOCK: - info = &cur->as.code.info; + if (entering) { cr(html); - - if (&cur->as.code.fence_length == 0 - || strbuf_len(info) == 0) { - strbuf_puts(html, "<pre><code>"); + if (list_type == CMARK_BULLET_LIST) { + cmark_strbuf_puts(html, "<ul"); + S_render_sourcepos(node, html, options); + cmark_strbuf_puts(html, ">\n"); + } else if (start == 1) { + cmark_strbuf_puts(html, "<ol"); + S_render_sourcepos(node, html, options); + cmark_strbuf_puts(html, ">\n"); + } else { + cmark_strbuf_printf(html, + "<ol start=\"%d\"", + start); + S_render_sourcepos(node, html, options); + cmark_strbuf_puts(html, ">\n"); } - else { - int first_tag = strbuf_strchr(info, ' ', 0); - if (first_tag < 0) - first_tag = strbuf_len(info); - - strbuf_puts(html, - "<pre><code class=\"language-"); - escape_html(html, info->ptr, first_tag); - strbuf_puts(html, "\">"); - } - - escape_html(html, cur->string_content.ptr, cur->string_content.size); - break; + } else { + cmark_strbuf_puts(html, + list_type == CMARK_BULLET_LIST ? + "</ul>\n" : "</ol>\n"); + } + break; + } - case NODE_HTML: + case CMARK_NODE_ITEM: + if (entering) { cr(html); - strbuf_put(html, cur->string_content.ptr, cur->string_content.size); - break; + cmark_strbuf_puts(html, "<li"); + S_render_sourcepos(node, html, options); + cmark_strbuf_putc(html, '>'); + } else { + cmark_strbuf_puts(html, "</li>\n"); + } + break; - case NODE_HRULE: + case CMARK_NODE_HEADER: + if (entering) { cr(html); - strbuf_puts(html, "<hr />\n"); - break; - - case NODE_REFERENCE_DEF: - break; - - case NODE_TEXT: - escape_html(html, cur->as.literal.data, cur->as.literal.len); - break; - - case NODE_LINEBREAK: - strbuf_puts(html, "<br />\n"); - break; - - case NODE_SOFTBREAK: - strbuf_putc(html, '\n'); - break; - - case NODE_INLINE_CODE: - strbuf_puts(html, "<code>"); - escape_html(html, cur->as.literal.data, cur->as.literal.len); - break; - - case NODE_INLINE_HTML: - strbuf_put(html, - cur->as.literal.data, - cur->as.literal.len); - break; - - case NODE_LINK: - strbuf_puts(html, "<a href=\""); - if (cur->as.link.url) - escape_href(html, cur->as.link.url, -1); - - if (cur->as.link.title) { - strbuf_puts(html, "\" title=\""); - escape_html(html, cur->as.link.title, -1); - } - - strbuf_puts(html, "\">"); - break; - - case NODE_IMAGE: - strbuf_puts(html, "<img src=\""); - if (cur->as.link.url) - escape_href(html, cur->as.link.url, -1); - - strbuf_puts(html, "\" alt=\""); - inlines_to_plain_html(html, cur); + start_header[2] = '0' + node->as.header.level; + cmark_strbuf_puts(html, start_header); + S_render_sourcepos(node, html, options); + cmark_strbuf_putc(html, '>'); + } else { + end_header[3] = '0' + node->as.header.level; + cmark_strbuf_puts(html, end_header); + cmark_strbuf_puts(html, ">\n"); + } + break; - if (cur->as.link.title) { - strbuf_puts(html, "\" title=\""); - escape_html(html, cur->as.link.title, -1); + case CMARK_NODE_CODE_BLOCK: + cr(html); + + if (!node->as.code.fenced || node->as.code.info.len == 0) { + cmark_strbuf_puts(html, "<pre"); + S_render_sourcepos(node, html, options); + cmark_strbuf_puts(html, "><code>"); + } else { + int first_tag = 0; + while (first_tag < node->as.code.info.len && + node->as.code.info.data[first_tag] != ' ') { + first_tag += 1; } - strbuf_puts(html, "\" />"); - visit_children = false; - break; - - case NODE_STRONG: - strbuf_puts(html, "<strong>"); - break; - - case NODE_EMPH: - strbuf_puts(html, "<em>"); - break; - - default: - assert(false); + cmark_strbuf_puts(html, "<pre"); + S_render_sourcepos(node, html, options); + cmark_strbuf_puts(html, "><code class=\"language-"); + escape_html(html, node->as.code.info.data, first_tag); + cmark_strbuf_puts(html, "\">"); } - if (visit_children && cur->first_child) { - cur = cur->first_child; - continue; - } + escape_html(html, node->as.code.literal.data, + node->as.code.literal.len); + cmark_strbuf_puts(html, "</code></pre>\n"); + break; - next_sibling: - tight = finish_node(html, cur, tight); - if (cur == node) { - break; - } - if (cur->next) { - cur = cur->next; - continue; - } - cur = cur->parent; - goto next_sibling; - } -} + case CMARK_NODE_HTML: + cr(html); + cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); + break; -// Returns the restored value of 'tight'. -static bool -finish_node(strbuf *html, cmark_node *node, bool tight) -{ - char end_header[] = "</h0>\n"; + case CMARK_NODE_HRULE: + cr(html); + cmark_strbuf_puts(html, "<hr"); + S_render_sourcepos(node, html, options); + cmark_strbuf_puts(html, " />\n"); + break; - switch (node->type) { - case NODE_PARAGRAPH: + case CMARK_NODE_PARAGRAPH: + parent = cmark_node_parent(node); + grandparent = cmark_node_parent(parent); + if (grandparent != NULL && + grandparent->type == CMARK_NODE_LIST) { + tight = grandparent->as.list.tight; + } else { + tight = false; + } if (!tight) { - strbuf_puts(html, "</p>\n"); + if (entering) { + cr(html); + cmark_strbuf_puts(html, "<p"); + S_render_sourcepos(node, html, options); + cmark_strbuf_putc(html, '>'); + } else { + cmark_strbuf_puts(html, "</p>\n"); + } } break; - case NODE_BLOCK_QUOTE: { - cmark_list *list = &node->as.list; - strbuf_puts(html, "</blockquote>\n"); - // Restore old 'tight' value. - tight = list->tight; - list->tight = false; + case CMARK_NODE_TEXT: + escape_html(html, node->as.literal.data, + node->as.literal.len); break; - } - case NODE_LIST_ITEM: - strbuf_puts(html, "</li>\n"); + case CMARK_NODE_LINEBREAK: + cmark_strbuf_puts(html, "<br />\n"); break; - case NODE_LIST: { - cmark_list *list = &node->as.list; - bool tmp; - strbuf_puts(html, - list->list_type == CMARK_BULLET_LIST ? - "</ul>\n" : "</ol>\n"); - // Restore old 'tight' value. - tmp = tight; - tight = list->tight; - list->tight = tmp; + case CMARK_NODE_SOFTBREAK: + if (options & CMARK_OPT_HARDBREAKS) { + cmark_strbuf_puts(html, "<br />\n"); + } else { + cmark_strbuf_putc(html, '\n'); + } break; - } - case NODE_HEADER: - end_header[3] = '0' + node->as.header.level; - strbuf_puts(html, end_header); + case CMARK_NODE_CODE: + cmark_strbuf_puts(html, "<code>"); + escape_html(html, node->as.literal.data, node->as.literal.len); + cmark_strbuf_puts(html, "</code>"); break; - case NODE_CODE_BLOCK: - strbuf_puts(html, "</code></pre>\n"); + case CMARK_NODE_INLINE_HTML: + cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); break; - case NODE_INLINE_CODE: - strbuf_puts(html, "</code>"); + case CMARK_NODE_STRONG: + if (entering) { + cmark_strbuf_puts(html, "<strong>"); + } else { + cmark_strbuf_puts(html, "</strong>"); + } break; - case NODE_LINK: - strbuf_puts(html, "</a>"); + case CMARK_NODE_EMPH: + if (entering) { + cmark_strbuf_puts(html, "<em>"); + } else { + cmark_strbuf_puts(html, "</em>"); + } break; - case NODE_STRONG: - strbuf_puts(html, "</strong>"); + case CMARK_NODE_LINK: + if (entering) { + cmark_strbuf_puts(html, "<a href=\""); + if (node->as.link.url) + escape_href(html, node->as.link.url, -1); + + if (node->as.link.title) { + cmark_strbuf_puts(html, "\" title=\""); + escape_html(html, node->as.link.title, -1); + } + + cmark_strbuf_puts(html, "\">"); + } else { + cmark_strbuf_puts(html, "</a>"); + } break; - case NODE_EMPH: - strbuf_puts(html, "</em>"); + case CMARK_NODE_IMAGE: + if (entering) { + cmark_strbuf_puts(html, "<img src=\""); + if (node->as.link.url) + escape_href(html, node->as.link.url, -1); + + cmark_strbuf_puts(html, "\" alt=\""); + state->plain = node; + } else { + if (node->as.link.title) { + cmark_strbuf_puts(html, "\" title=\""); + escape_html(html, node->as.link.title, -1); + } + + cmark_strbuf_puts(html, "\" />"); + } break; default: + assert(false); break; } - return tight; + // cmark_strbuf_putc(html, 'x'); + return 1; } -char *cmark_render_html(cmark_node *root) +char *cmark_render_html(cmark_node *root, long options) { char *result; - strbuf html = GH_BUF_INIT; - node_to_html(&html, root); - result = (char *)strbuf_detach(&html); - strbuf_free(&html); + cmark_strbuf html = GH_BUF_INIT; + cmark_event_type ev_type; + cmark_node *cur; + struct render_state state = { &html, NULL }; + cmark_iter *iter = cmark_iter_new(root); + + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { + cur = cmark_iter_get_node(iter); + S_render_node(cur, ev_type, &state, options); + } + result = (char *)cmark_strbuf_detach(&html); + + cmark_iter_free(iter); + cmark_strbuf_free(&html); return result; }
