Merge pull request #38 from jmendeth/language-classes
Simplify and harden fenced code blocks
This commit is contained in:
commit
a7e72d2c72
3 changed files with 47 additions and 113 deletions
36
src/html.c
36
src/html.c
|
@ -104,35 +104,10 @@ rndr_blockcode(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buf
|
|||
|
||||
if (ob->size) hoedown_buffer_putc(ob, '\n');
|
||||
|
||||
if (lang && lang->size) {
|
||||
size_t i, cls = 0;
|
||||
if (state->flags & HOEDOWN_HTML_PRETTIFY) {
|
||||
HOEDOWN_BUFPUTSL(ob, "<pre><code class=\"prettyprint");
|
||||
cls++;
|
||||
} else {
|
||||
HOEDOWN_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);
|
||||
}
|
||||
}
|
||||
|
||||
if (lang) {
|
||||
HOEDOWN_BUFPUTSL(ob, "<pre><code class=\"language-");
|
||||
escape_html(ob, lang->data, lang->size);
|
||||
HOEDOWN_BUFPUTSL(ob, "\">");
|
||||
} else if (state->flags & HOEDOWN_HTML_PRETTIFY) {
|
||||
HOEDOWN_BUFPUTSL(ob, "<pre><code class=\"prettyprint\">");
|
||||
} else {
|
||||
HOEDOWN_BUFPUTSL(ob, "<pre><code>");
|
||||
}
|
||||
|
@ -156,10 +131,7 @@ static int
|
|||
rndr_codespan(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
|
||||
{
|
||||
hoedown_html_renderer_state *state = opaque;
|
||||
if (state->flags & HOEDOWN_HTML_PRETTIFY)
|
||||
HOEDOWN_BUFPUTSL(ob, "<code class=\"prettyprint\">");
|
||||
else
|
||||
HOEDOWN_BUFPUTSL(ob, "<code>");
|
||||
HOEDOWN_BUFPUTSL(ob, "<code>");
|
||||
if (text) escape_html(ob, text->data, text->size);
|
||||
HOEDOWN_BUFPUTSL(ob, "</code>");
|
||||
return 1;
|
||||
|
|
|
@ -21,8 +21,7 @@ typedef enum {
|
|||
HOEDOWN_HTML_TOC = (1 << 6),
|
||||
HOEDOWN_HTML_HARD_WRAP = (1 << 7),
|
||||
HOEDOWN_HTML_USE_XHTML = (1 << 8),
|
||||
HOEDOWN_HTML_ESCAPE = (1 << 9),
|
||||
HOEDOWN_HTML_PRETTIFY = (1 << 10)
|
||||
HOEDOWN_HTML_ESCAPE = (1 << 9)
|
||||
} hoedown_html_render_mode;
|
||||
|
||||
typedef enum {
|
||||
|
|
121
src/markdown.c
121
src/markdown.c
|
@ -1321,10 +1321,11 @@ is_hrule(uint8_t *data, size_t size)
|
|||
return n >= 3;
|
||||
}
|
||||
|
||||
/* check if a line begins with a code fence; return the
|
||||
* width of the code fence */
|
||||
/* check if a line is a code fence; return the
|
||||
* width of the code fence. if passed, width of
|
||||
* the fence rule and character will be returned */
|
||||
static size_t
|
||||
prefix_codefence(uint8_t *data, size_t size)
|
||||
is_codefence(uint8_t *data, size_t size, size_t *width, uint8_t *chr)
|
||||
{
|
||||
size_t i = 0, n = 0;
|
||||
uint8_t c;
|
||||
|
@ -1349,64 +1350,33 @@ prefix_codefence(uint8_t *data, size_t size)
|
|||
if (n < 3)
|
||||
return 0;
|
||||
|
||||
if (width) *width = n;
|
||||
if (chr) *chr = c;
|
||||
return i;
|
||||
}
|
||||
|
||||
/* check if a line is a code fence; return its size if it is */
|
||||
static size_t
|
||||
is_codefence(uint8_t *data, size_t size, hoedown_buffer *syntax)
|
||||
/* expects single line, checks if it's a codefence and extracts language */
|
||||
static int
|
||||
parse_codefence(uint8_t *data, size_t size, hoedown_buffer *lang, size_t *width, uint8_t *chr)
|
||||
{
|
||||
size_t i = 0, syn_len = 0;
|
||||
uint8_t *syn_start;
|
||||
size_t i, w, lang_start;
|
||||
|
||||
i = prefix_codefence(data, size);
|
||||
i = w = is_codefence(data, size, width, chr);
|
||||
if (i == 0)
|
||||
return 0;
|
||||
|
||||
while (i < size && data[i] == ' ')
|
||||
while (i < size && _isspace(data[i]))
|
||||
i++;
|
||||
|
||||
syn_start = data + i;
|
||||
|
||||
if (i < size && data[i] == '{') {
|
||||
i++; syn_start++;
|
||||
|
||||
while (i < size && data[i] != '}' && data[i] != '\n') {
|
||||
syn_len++; i++;
|
||||
}
|
||||
|
||||
if (i == size || data[i] != '}')
|
||||
return 0;
|
||||
|
||||
/* strip all whitespace at the beginning and the end
|
||||
* of the {} block */
|
||||
while (syn_len > 0 && _isspace(syn_start[0])) {
|
||||
syn_start++; syn_len--;
|
||||
}
|
||||
|
||||
while (syn_len > 0 && _isspace(syn_start[syn_len - 1]))
|
||||
syn_len--;
|
||||
lang_start = i;
|
||||
|
||||
while (i < size && !_isspace(data[i]))
|
||||
i++;
|
||||
} else {
|
||||
while (i < size && !_isspace(data[i])) {
|
||||
syn_len++; i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (syntax) {
|
||||
syntax->data = syn_start;
|
||||
syntax->size = syn_len;
|
||||
}
|
||||
lang->data = data + lang_start;
|
||||
lang->size = i - lang_start;
|
||||
|
||||
while (i < size && data[i] != '\n') {
|
||||
if (!_isspace(data[i]))
|
||||
return 0;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return i + 1;
|
||||
return w;
|
||||
}
|
||||
|
||||
/* is_atxheader • returns whether the line is a hash-prefixed header */
|
||||
|
@ -1639,7 +1609,7 @@ parse_paragraph(hoedown_buffer *ob, hoedown_markdown *md, uint8_t *data, size_t
|
|||
|
||||
/* see if a code fence starts here */
|
||||
if ((md->ext_flags & HOEDOWN_EXT_FENCED_CODE) != 0 &&
|
||||
is_codefence(data + i, size - i, NULL) != 0) {
|
||||
is_codefence(data + i, size - i, NULL, NULL)) {
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
|
@ -1703,45 +1673,38 @@ parse_paragraph(hoedown_buffer *ob, hoedown_markdown *md, uint8_t *data, size_t
|
|||
static size_t
|
||||
parse_fencedcode(hoedown_buffer *ob, hoedown_markdown *md, uint8_t *data, size_t size)
|
||||
{
|
||||
size_t beg, end;
|
||||
hoedown_buffer *work = 0;
|
||||
size_t i = 0, text_start, line_start;
|
||||
size_t w, w2;
|
||||
size_t width, width2;
|
||||
uint8_t chr, chr2;
|
||||
hoedown_buffer text = { 0, 0, 0, 0 };
|
||||
hoedown_buffer lang = { 0, 0, 0, 0 };
|
||||
|
||||
beg = is_codefence(data, size, &lang);
|
||||
if (beg == 0) return 0;
|
||||
// parse codefence line
|
||||
while (i < size && data[i] != '\n') i++;
|
||||
w = parse_codefence(data, i, &lang, &width, &chr);
|
||||
if (!w) return 0;
|
||||
|
||||
work = newbuf(md, BUFFER_BLOCK);
|
||||
// search for end
|
||||
i++;
|
||||
text_start = i;
|
||||
for (; (line_start = i) < size; i++) {
|
||||
while (i < size && data[i] != '\n') i++;
|
||||
|
||||
while (beg < size) {
|
||||
size_t fence_end;
|
||||
hoedown_buffer fence_trail = { 0, 0, 0, 0 };
|
||||
|
||||
fence_end = is_codefence(data + beg, size - beg, &fence_trail);
|
||||
if (fence_end != 0 && fence_trail.size == 0) {
|
||||
beg += fence_end;
|
||||
w2 = is_codefence(data + line_start, i - line_start, &width2, &chr2);
|
||||
if (w == w2 && width == width2 && chr == chr2 &&
|
||||
is_empty(data + (line_start+w), i - (line_start+w)))
|
||||
break;
|
||||
}
|
||||
|
||||
for (end = beg + 1; end < size && data[end - 1] != '\n'; end++);
|
||||
|
||||
if (beg < end) {
|
||||
/* verbatim copy to the working buffer,
|
||||
escaping entities */
|
||||
if (is_empty(data + beg, end - beg))
|
||||
hoedown_buffer_putc(work, '\n');
|
||||
else hoedown_buffer_put(work, data + beg, end - beg);
|
||||
}
|
||||
beg = end;
|
||||
}
|
||||
text.data = data + text_start;
|
||||
text.size = line_start - text_start;
|
||||
|
||||
if (work->size && work->data[work->size - 1] != '\n')
|
||||
hoedown_buffer_putc(work, '\n');
|
||||
|
||||
// call callback
|
||||
if (md->md.blockcode)
|
||||
md->md.blockcode(ob, work, lang.size ? &lang : NULL, md->md.opaque);
|
||||
md->md.blockcode(ob, text.size ? &text : NULL, lang.size ? &lang : NULL, md->md.opaque);
|
||||
|
||||
popbuf(md, BUFFER_BLOCK);
|
||||
return beg;
|
||||
if (data[i] == '\n') i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
static size_t
|
||||
|
@ -1842,7 +1805,7 @@ parse_listitem(hoedown_buffer *ob, hoedown_markdown *md, uint8_t *data, size_t s
|
|||
pre = i;
|
||||
|
||||
if (md->ext_flags & HOEDOWN_EXT_FENCED_CODE) {
|
||||
if (is_codefence(data + beg + i, end - beg - i, NULL) != 0)
|
||||
if (is_codefence(data + beg + i, end - beg - i, NULL, NULL))
|
||||
in_fence = !in_fence;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue