ext/xhtml.c in redcarpet-1.10.1 vs ext/xhtml.c in redcarpet-1.11.0

- old
+ new

@@ -134,42 +134,70 @@ } static void rndr_blockcode(struct buf *ob, struct buf *text, struct buf *lang, void *opaque) { - static char *sh_lang = "bash"; - struct buf lang_shebang = {0, 0, 0, 0, 0}; - if (ob->size) bufputc(ob, '\n'); - /* - * Try to guess the language based on the shebang - */ - if (lang == NULL && text != NULL && text->size > 2) { - if (bufprefix(text, "#!/usr/bin/env ") == 0) { - size_t i = STRLEN("#!/usr/bin/env "); + if (lang && lang->size) { + size_t i = 0; + BUFPUTSL(ob, "<pre><code class=\""); - lang_shebang.data = text->data + i; - while (i < text->size && !isspace(text->data[i])) { - i++; lang_shebang.size++; - } + for (i = 0; i < lang->size; ++i) { + if (lang->data[i] == '.' && (i == 0 || isspace(lang->data[i - 1]))) + continue; - lang = &lang_shebang; - } else if (bufprefix(text, "#!/bin/sh") == 0 && isspace(text->data[STRLEN("#!/bin/sh")])) { - lang_shebang.data = sh_lang; - lang_shebang.size = strlen(sh_lang); - lang = &lang_shebang; + bufputc(ob, lang->data[i]); } - } + BUFPUTSL(ob, "\">"); + } else + BUFPUTSL(ob, "<pre><code>"); + + if (text) + lus_attr_escape(ob, text->data, text->size); + + BUFPUTSL(ob, "</code></pre>\n"); +} + +/* + * GitHub style code block: + * + * <pre lang="LANG"><code> + * ... + * </pre></code> + * + * Unlike other parsers, we store the language identifier in the <pre>, + * and don't let the user generate custom classes. + * + * The language identifier in the <pre> block gets postprocessed and all + * the code inside gets syntax highlighted with Pygments. This is much safer + * than letting the user specify a CSS class for highlighting. + * + * Note that we only generate HTML for the first specifier. + * E.g. + * ~~~~ {.python .numbered} => <pre lang="python"><code> + */ +static void +rndr_blockcode_github(struct buf *ob, struct buf *text, struct buf *lang, void *opaque) +{ + if (ob->size) bufputc(ob, '\n'); + if (lang && lang->size) { - BUFPUTSL(ob, "<pre><code class=\""); + size_t i = 0; + BUFPUTSL(ob, "<pre lang=\""); + + for (; i < lang->size; ++i) + if (isspace(lang->data[i])) + break; + if (lang->data[0] == '.') - bufput(ob, lang->data + 1, lang->size - 1); + bufput(ob, lang->data + 1, i - 1); else - bufput(ob, lang->data, lang->size); - BUFPUTSL(ob, "\">"); + bufput(ob, lang->data, i); + + BUFPUTSL(ob, "\"><code>"); } else BUFPUTSL(ob, "<pre><code>"); if (text) lus_attr_escape(ob, text->data, text->size); @@ -743,9 +771,12 @@ renderer->autolink = NULL; } if (render_flags & XHTML_SMARTYPANTS) renderer->normal_text = rndr_smartypants; + + if (render_flags & XHTML_GITHUB_BLOCKCODE) + renderer->blockcode = rndr_blockcode_github; } void ups_free_renderer(struct mkd_renderer *renderer) {