static void rndr_raw_block(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data) { size_t org, sz; if (!text) return; /* FIXME: Do we *really* need to trim the HTML? How does that make a difference? */ sz = text->size; while (sz > 0 && text->data[sz - 1] == '\n') sz--; org = 0; while (org < sz && text->data[org] == '\n') org++; if (org >= sz) return; if (ob->size) hoedown_buffer_putc(ob, '\n'); hoedown_buffer_put(ob, text->data + org, sz - org); hoedown_buffer_putc(ob, '\n'); }
static void rndr_hrule(hoedown_buffer *ob, const hoedown_renderer_data *data) { uint8_t c = hoedown_document_hrule_char(((hoedown_context_test_renderer_state*) data->opaque)->doc); hoedown_buffer_putc(ob, c); hoedown_buffer_putc(ob, ' '); }
static int rndr_link(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *content, void *opaque) { hoedown_html_renderer_state *state = opaque; if (link != NULL && (state->flags & HOEDOWN_HTML_SAFELINK) != 0 && !hoedown_autolink_is_safe(link->data, link->size)) return 0; HOEDOWN_BUFPUTSL(ob, "<a href=\""); if (link && link->size) escape_href(ob, link->data, link->size); if (title && title->size) { HOEDOWN_BUFPUTSL(ob, "\" title=\""); escape_html(ob, title->data, title->size); } if (state->link_attributes) { hoedown_buffer_putc(ob, '\"'); state->link_attributes(ob, link, opaque); hoedown_buffer_putc(ob, '>'); } else { HOEDOWN_BUFPUTSL(ob, "\">"); } if (content && content->size) hoedown_buffer_put(ob, content->data, content->size); HOEDOWN_BUFPUTSL(ob, "</a>"); return 1; }
static int rndr_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data) { hoedown_html_renderer_state *state = data->opaque; HOEDOWN_BUFPUTSL(ob, "<a href=\""); if (link && link->size) escape_href(ob, link->data, link->size); if (title && title->size) { HOEDOWN_BUFPUTSL(ob, "\" title=\""); escape_html(ob, title->data, title->size); } if (state->link_attributes) { hoedown_buffer_putc(ob, '\"'); state->link_attributes(ob, link, data); hoedown_buffer_putc(ob, '>'); } else { HOEDOWN_BUFPUTSL(ob, "\">"); } if (content && content->size) hoedown_buffer_put(ob, content->data, content->size); HOEDOWN_BUFPUTSL(ob, "</a>"); return 1; }
// rndr_blockcode from HEAD. The "language-" prefix in class in needed to make // the HTML compatible with Prism. void hoedown_patch_render_blockcode( hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data) { if (ob->size) hoedown_buffer_putc(ob, '\n'); hoedown_html_renderer_state *state = data->opaque; hoedown_buffer *front = NULL; hoedown_buffer *back = NULL; if (lang && USE_BLOCKCODE_INFORMATION(state)) { front = hoedown_buffer_new(lang->size); back = hoedown_buffer_new(lang->size); hoedown_buffer *current = front; for (size_t i = 0; i < lang->size; i++) { uint8_t c = lang->data[i]; if (current == front && c == ':') current = back; else hoedown_buffer_putc(current, c); } lang = front; } HOEDOWN_BUFPUTSL(ob, "<pre"); if (state->flags & HOEDOWN_HTML_BLOCKCODE_LINE_NUMBERS) HOEDOWN_BUFPUTSL(ob, " class=\"line-numbers\""); if (back && back->size) { HOEDOWN_BUFPUTSL(ob, " data-information=\""); hoedown_buffer_put(ob, back->data, back->size); HOEDOWN_BUFPUTSL(ob, "\""); } HOEDOWN_BUFPUTSL(ob, "><code class=\"language-"); if (lang && lang->size) hoedown_escape_html(ob, lang->data, lang->size, 0); else HOEDOWN_BUFPUTSL(ob, "none"); HOEDOWN_BUFPUTSL(ob, "\">"); if (text) { // Remove last newline to prevent prism from adding a blank line at the // end of code blocks. size_t size = text->size; if (size > 0 && text->data[size - 1] == '\n') size--; hoedown_escape_html(ob, text->data, size, 0); } HOEDOWN_BUFPUTSL(ob, "</code></pre>\n"); hoedown_buffer_free(front); hoedown_buffer_free(back); }
static void rndr_blockcode(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_buffer *attr, const hoedown_renderer_data *data) { uint8_t c = hoedown_document_fencedcode_char(((hoedown_context_test_renderer_state*) data->opaque)->doc); if (c) hoedown_buffer_putc(ob, c); else hoedown_buffer_puts(ob, "unfenced blockcode"); hoedown_buffer_putc(ob, ' '); }
static void rndr_listitem(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *attr, hoedown_list_flags *flags, const hoedown_renderer_data *data) { uint8_t c; c = hoedown_document_ul_item_char(((hoedown_context_test_renderer_state*) data->opaque)->doc); hoedown_buffer_putc(ob, c); hoedown_buffer_putc(ob, ' '); if (content) hoedown_buffer_put(ob, content->data, content->size); }
static void rndr_raw_block(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque) { size_t org, sz; if (!text) return; sz = text->size; while (sz > 0 && text->data[sz - 1] == '\n') sz--; org = 0; while (org < sz && text->data[org] == '\n') org++; if (org >= sz) return; if (ob->size) hoedown_buffer_putc(ob, '\n'); hoedown_buffer_put(ob, text->data + org, sz - org); hoedown_buffer_putc(ob, '\n'); }
// rndr_blockcode from HEAD. The "language-" prefix in class in needed to make // the HTML compatible with Prism. void hoedown_patch_render_blockcode( hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data) { if (ob->size) hoedown_buffer_putc(ob, '\n'); if (lang) { hoedown_html_renderer_state_extra *extra = ((hoedown_html_renderer_state *)data->opaque)->opaque; hoedown_buffer *mapped = NULL; if (extra->language_addition) mapped = extra->language_addition(lang, extra->owner); HOEDOWN_BUFPUTSL(ob, "<pre><code class=\"language-"); if (mapped) { hoedown_escape_html(ob, mapped->data, mapped->size, 0); hoedown_buffer_free(mapped); } else { hoedown_escape_html(ob, lang->data, lang->size, 0); } HOEDOWN_BUFPUTSL(ob, "\">"); } else { HOEDOWN_BUFPUTSL(ob, "<pre><code>"); } if (text) hoedown_escape_html(ob, text->data, text->size, 0); HOEDOWN_BUFPUTSL(ob, "</code></pre>\n"); }
static int rndr_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *attr, const hoedown_renderer_data *data) { const hoedown_buffer *id; hoedown_link_type link_type; id = hoedown_document_link_id(((hoedown_context_test_renderer_state*) data->opaque)->doc); hoedown_buffer_puts(ob, "id: "); if (id) hoedown_buffer_put(ob, id->data, id->size); else hoedown_buffer_puts(ob, "no id"); hoedown_buffer_putc(ob, ' '); link_type = hoedown_document_link_type(((hoedown_context_test_renderer_state*) data->opaque)->doc); switch (link_type) { case HOEDOWN_LINK_INLINE: hoedown_buffer_puts(ob, "HOEDOWN_LINK_INLINE"); break; case HOEDOWN_LINK_REFERENCE: hoedown_buffer_puts(ob, "HOEDOWN_LINK_REFERENCE"); break; case HOEDOWN_LINK_EMPTY_REFERENCE: hoedown_buffer_puts(ob, "HOEDOWN_LINK_EMPTY_REFERENCE"); break; case HOEDOWN_LINK_SHORTCUT: hoedown_buffer_puts(ob, "HOEDOWN_LINK_SHORTCUT"); break; default: break; } return 1; }
static void rndr_hrule(struct hoedown_buffer *ob, void *opaque) { struct hoedown_html_renderopt *options = opaque; if (ob->size) hoedown_buffer_putc(ob, '\n'); hoedown_buffer_puts(ob, USE_XHTML(options) ? "<hr/>\n" : "<hr>\n"); }
static void rndr_test_link_attributes(hoedown_buffer *ob, const hoedown_buffer *url, const hoedown_renderer_data *data) { hoedown_buffer_puts(ob, " data-url=\""); hoedown_buffer_put(ob, url->data, url->size); hoedown_buffer_putc(ob, '\"'); }
static void rndr_hrule(hoedown_buffer *ob, void *opaque) { hoedown_html_renderer_state *state = opaque; if (ob->size) hoedown_buffer_putc(ob, '\n'); hoedown_buffer_puts(ob, USE_XHTML(state) ? "<hr/>\n" : "<hr>\n"); }
static void rndr_hrule(hoedown_buffer *ob, const hoedown_renderer_data *data) { hoedown_html_renderer_state *state = data->opaque; if (ob->size) hoedown_buffer_putc(ob, '\n'); hoedown_buffer_puts(ob, USE_XHTML(state) ? "<hr/>\n" : "<hr>\n"); }
void hoedown_escape_html(hoedown_buffer *ob, const uint8_t *data, size_t size, int secure) { size_t i = 0, mark; while (1) { mark = i; while (i < size && HTML_ESCAPE_TABLE[data[i]] == 0) i++; /* Optimization for cases where there's nothing to escape */ if (mark == 0 && i >= size) { hoedown_buffer_put(ob, data, size); return; } if (likely(i > mark)) hoedown_buffer_put(ob, data + mark, i - mark); if (i >= size) break; /* The forward slash is only escaped in secure mode */ if (!secure && data[i] == '/') { hoedown_buffer_putc(ob, '/'); } else { hoedown_buffer_puts(ob, HTML_ESCAPES[HTML_ESCAPE_TABLE[data[i]]]); } i++; } }
static void rndr_list(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque) { if (ob->size) hoedown_buffer_putc(ob, '\n'); hoedown_buffer_put(ob, flags & HOEDOWN_LIST_ORDERED ? "<ol>\n" : "<ul>\n", 5); if (text) hoedown_buffer_put(ob, text->data, text->size); hoedown_buffer_put(ob, flags & HOEDOWN_LIST_ORDERED ? "</ol>\n" : "</ul>\n", 6); }
static void rndr_table_body(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) { if (ob->size) hoedown_buffer_putc(ob, '\n'); HOEDOWN_BUFPUTSL(ob, "<tbody>\n"); hoedown_buffer_put(ob, content->data, content->size); HOEDOWN_BUFPUTSL(ob, "</tbody>\n"); }
static void rndr_list(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data) { if (ob->size) hoedown_buffer_putc(ob, '\n'); hoedown_buffer_put(ob, (const uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "<ol>\n" : "<ul>\n"), 5); if (content) hoedown_buffer_put(ob, content->data, content->size); hoedown_buffer_put(ob, (const uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "</ol>\n" : "</ul>\n"), 6); }
static void rndr_blockquote(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) { if (ob->size) hoedown_buffer_putc(ob, '\n'); HOEDOWN_BUFPUTSL(ob, "<blockquote>\n"); if (content) hoedown_buffer_put(ob, content->data, content->size); HOEDOWN_BUFPUTSL(ob, "</blockquote>\n"); }
static void rndr_blockquote(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque) { if (ob->size) hoedown_buffer_putc(ob, '\n'); HOEDOWN_BUFPUTSL(ob, "<blockquote>\n"); if (text) hoedown_buffer_put(ob, text->data, text->size); HOEDOWN_BUFPUTSL(ob, "</blockquote>\n"); }
static void rndr_blockcode(struct hoedown_buffer *ob, const struct hoedown_buffer *text, const struct hoedown_buffer *lang, void *opaque) { struct hoedown_html_renderopt *options = opaque; if (ob->size) hoedown_buffer_putc(ob, '\n'); if (lang && lang->size) { size_t i, cls = 0; if (options->flags & HOEDOWN_HTML_PRETTIFY) { BUFPUTSL(ob, "<pre><code class=\"prettyprint"); cls++; } else { BUFPUTSL(ob, "<pre><code class=\""); } for (i = 0; i < lang->size; ++i, ++cls) { while (i < lang->size && isspace(lang->data[i])) i++; if (i < lang->size) { size_t org = i; while (i < lang->size && !isspace(lang->data[i])) i++; if (lang->data[org] == '.') org++; if (cls) hoedown_buffer_putc(ob, ' '); escape_html(ob, lang->data + org, i - org); } } BUFPUTSL(ob, "\">"); } else if (options->flags & HOEDOWN_HTML_PRETTIFY) { BUFPUTSL(ob, "<pre><code class=\"prettyprint\">"); } else { BUFPUTSL(ob, "<pre><code>"); } if (text) escape_html(ob, text->data, text->size); BUFPUTSL(ob, "</code></pre>\n"); }
static void rndr_normal_text(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) { int escaped = hoedown_document_is_escaped(((hoedown_context_test_renderer_state*) data->opaque)->doc); if (escaped) { hoedown_buffer_putc(ob, '\\'); } if (content) hoedown_buffer_put(ob, content->data, content->size); }
/******************** * GENERIC RENDERER * ********************/ static int rndr_autolink(hoedown_buffer *ob, const hoedown_buffer *link, enum hoedown_autolink type, void *opaque) { hoedown_html_renderer_state *state = opaque; if (!link || !link->size) return 0; if ((state->flags & HOEDOWN_HTML_SAFELINK) != 0 && !hoedown_autolink_is_safe(link->data, link->size) && type != HOEDOWN_AUTOLINK_EMAIL) return 0; HOEDOWN_BUFPUTSL(ob, "<a href=\""); if (type == HOEDOWN_AUTOLINK_EMAIL) HOEDOWN_BUFPUTSL(ob, "mailto:"); escape_href(ob, link->data, link->size); if (state->link_attributes) { hoedown_buffer_putc(ob, '\"'); state->link_attributes(ob, link, opaque); hoedown_buffer_putc(ob, '>'); } else { HOEDOWN_BUFPUTSL(ob, "\">"); } /* * Pretty printing: if we get an email address as * an actual URI, e.g. `mailto:[email protected]`, we don't * want to print the `mailto:` prefix */ if (hoedown_buffer_prefix(link, "mailto:") == 0) { escape_html(ob, link->data + 7, link->size - 7); } else { escape_html(ob, link->data, link->size); } HOEDOWN_BUFPUTSL(ob, "</a>"); return 1; }
static void rndr_table(hoedown_buffer *ob, const hoedown_buffer *header, const hoedown_buffer *body, void *opaque) { if (ob->size) hoedown_buffer_putc(ob, '\n'); HOEDOWN_BUFPUTSL(ob, "<table><thead>\n"); if (header) hoedown_buffer_put(ob, header->data, header->size); HOEDOWN_BUFPUTSL(ob, "</thead><tbody>\n"); if (body) hoedown_buffer_put(ob, body->data, body->size); HOEDOWN_BUFPUTSL(ob, "</tbody></table>\n"); }
static int rndr_footnote_ref(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data) { const hoedown_buffer *id; id = hoedown_document_link_id(((hoedown_context_test_renderer_state*) data->opaque)->doc); if (id) { hoedown_buffer_puts(ob, "id: "); hoedown_buffer_put(ob, id->data, id->size); } hoedown_buffer_putc(ob, ' '); return 1; }
static void rndr_footnote_def(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data) { const hoedown_buffer *id; id = hoedown_document_footnote_id(((hoedown_context_test_renderer_state*) data->opaque)->doc); if (id) { hoedown_buffer_puts(ob, "id: "); hoedown_buffer_put(ob, id->data, id->size); } hoedown_buffer_putc(ob, ' '); if (content) hoedown_buffer_put(ob, content->data, content->size); }
static void rndr_paragraph(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) { int list_depth, blockquote_depth; list_depth = hoedown_document_list_depth(((hoedown_context_test_renderer_state*) data->opaque)->doc); blockquote_depth = hoedown_document_blockquote_depth(((hoedown_context_test_renderer_state*) data->opaque)->doc); hoedown_buffer_printf(ob, "list depth: %d blockquote depth: %d ", list_depth, blockquote_depth); if (content) { hoedown_buffer_puts(ob, "paragraph: "); hoedown_buffer_put(ob, content->data, content->size); } hoedown_buffer_putc(ob, '\n'); }
static void rndr_footnotes(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) { hoedown_html_renderer_state *state = data->opaque; if (ob->size) hoedown_buffer_putc(ob, '\n'); HOEDOWN_BUFPUTSL(ob, "<div class=\"footnotes\">\n"); hoedown_buffer_puts(ob, USE_XHTML(state) ? "<hr/>\n" : "<hr>\n"); HOEDOWN_BUFPUTSL(ob, "<ol>\n"); if (content) hoedown_buffer_put(ob, content->data, content->size); HOEDOWN_BUFPUTSL(ob, "\n</ol>\n</div>\n"); }
static void rndr_footnotes(struct hoedown_buffer *ob, const struct hoedown_buffer *text, void *opaque) { struct hoedown_html_renderopt *options = opaque; if (ob->size) hoedown_buffer_putc(ob, '\n'); BUFPUTSL(ob, "<div class=\"footnotes\">\n"); hoedown_buffer_puts(ob, USE_XHTML(options) ? "<hr/>\n" : "<hr>\n"); BUFPUTSL(ob, "<ol>\n"); if (text) hoedown_buffer_put(ob, text->data, text->size); BUFPUTSL(ob, "\n</ol>\n</div>\n"); }
static void rndr_header(hoedown_buffer *ob, const hoedown_buffer *text, int level, void *opaque) { hoedown_html_renderer_state *state = opaque; if (ob->size) hoedown_buffer_putc(ob, '\n'); if ((state->flags & HOEDOWN_HTML_TOC) && (level <= state->toc_data.nesting_level)) hoedown_buffer_printf(ob, "<h%d id=\"toc_%d\">", level, state->toc_data.header_count++); else hoedown_buffer_printf(ob, "<h%d>", level); if (text) hoedown_buffer_put(ob, text->data, text->size); hoedown_buffer_printf(ob, "</h%d>\n", level); }