hoedown/hoedown — pull request #124 by jmendeth (2014-09-14 12:24:00+00:00)
Title: Renderer API

This proposal sets the API regarding renderer callbacks, for version 3.
These are the most important changes:

## `content` vs `text`

When a renderer callback is passed a `content` buffer, that buffer contains *rendered output*, that is, output coming from other renderer callbacks. Example: the `emphasis` callback.

But other buffers such as `text` only contain data extracted from the Markdown source. Example: the `codespan` callback.

Why is this important? In an HTML renderer callback, `content` will have HTML, so it shouldn't be escaped. But `text` isn't HTML, it's taken from the input, so it should be escaped.

If you escape `content`, it won't render as expected. If you forget to escape `text`, you're creating a security hole, and it won't render as expected. So it's important to make that distinction (right now we're using `text` everywhere).

## `hoedown_renderer_data`

Instead of passing `void *opaque` as last parameter to the callback, we're now passing a pointer to `hoedown_renderer_data` struct. That struct contains the `void *opaque`.

But it can also contain other general parameters, that are not specific to the callback but useful for the renderer to access. That way, we keep signatures short and maintain compatibility.

## `hoedown_internal`

A new opaque type, `hoedown_internal`, is declared. The `hoedown_renderer_data` struct has a `hoedown_internal *doc` field, that is actually the `hoedown_document` instance, casted to `hoedown_internal *`.

Why is that useful? It provides a good way to expose internals. For example, if we wanted to expose `parse_inline` as said in #99, we'd expose this function:

~~~ c
/* Internal function */
void hoedown_internal_parse_inline(hoedown_internal *doc, hoedown_buffer *ob, uint8_t *data, size_t size);
~~~

whose definition would be

~~~ c
void hoedown_internal_parse_inline(hoedown_internal *doc, hoedown_buffer *ob, uint8_t *data, size_t size) {
parse_inline((hoedown_document *)doc, ob, data, size);
}
~~~

The user cannot call it with a regular `hoedown_document` pointer, which would crash the program:

~~~ c
hoedown_renderer *renderer = hoedown_html_renderer_new(0, 0);
hoedown_document *doc = hoedown_document_new(renderer, 0, 16);

hoedown_buffer *ob = hoedown_buffer_new(16);
hoedown_internal_parse_inline(doc, ob, "Hello!", 6); // wrong code
hoedown_document_render_inline(doc, ob, "Hello!", 6); // correct
~~~

But the user can call it from a renderer (which is the intended use):

~~~ c
void rndr_linebreak(hoedown_buffer *ob, const hoedown_renderer_data *data) {
hoedown_internal_parse_inline(data->doc, ob, "Hello!", 6); // correct
hoedown_document_render_inline(data->doc, ob, "Hello!", 6); // wrong code
}
~~~