Add support for syntaxes in fenced code blocks
This commit is contained in:
parent
4600469b3b
commit
481b099032
5 changed files with 58 additions and 20 deletions
2
Makefile
2
Makefile
|
@ -26,7 +26,7 @@ all: libupskirt.so upskirt
|
|||
# libraries
|
||||
|
||||
libupskirt.so: libupskirt.so.1
|
||||
ln -s $^ $@
|
||||
ln -f -s $^ $@
|
||||
|
||||
libupskirt.so.1: src/markdown.o src/array.o src/buffer.o
|
||||
$(CC) $(LDFLAGS) -shared -Wl $^ -o $@
|
||||
|
|
|
@ -59,7 +59,7 @@ main(int argc, char **argv)
|
|||
ob = bufnew(OUTPUT_UNIT);
|
||||
|
||||
ups_xhtml_renderer(&renderer, 0);
|
||||
ups_markdown(ob, ib, &renderer, 0);
|
||||
ups_markdown(ob, ib, &renderer, 0xFF);
|
||||
ups_free_renderer(&renderer);
|
||||
|
||||
/* writing the result to stdout */
|
||||
|
|
|
@ -112,11 +112,20 @@ rndr_autolink(struct buf *ob, struct buf *link, enum mkd_autolink type, void *op
|
|||
}
|
||||
|
||||
static void
|
||||
rndr_blockcode(struct buf *ob, struct buf *text, void *opaque)
|
||||
rndr_blockcode(struct buf *ob, struct buf *text, struct buf *syntax, void *opaque)
|
||||
{
|
||||
if (ob->size) bufputc(ob, '\n');
|
||||
BUFPUTSL(ob, "<pre><code>");
|
||||
if (text) lus_attr_escape(ob, text->data, text->size);
|
||||
|
||||
if (syntax && syntax->size) {
|
||||
BUFPUTSL(ob, "<pre lang=\"");
|
||||
bufput(ob, syntax->data, syntax->size);
|
||||
BUFPUTSL(ob, "\"><code>\n");
|
||||
} else
|
||||
BUFPUTSL(ob, "<pre><code>\n");
|
||||
|
||||
if (text)
|
||||
lus_attr_escape(ob, text->data, text->size);
|
||||
|
||||
BUFPUTSL(ob, "</code></pre>\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -945,9 +945,10 @@ is_hrule(char *data, size_t size)
|
|||
|
||||
/* check if a line is a code fence; return its size if it is */
|
||||
static size_t
|
||||
is_codefence(char *data, size_t size)
|
||||
is_codefence(char *data, size_t size, struct buf *syntax)
|
||||
{
|
||||
size_t i = 0, n = 0;
|
||||
size_t i = 0, n = 0, syn;
|
||||
char c;
|
||||
|
||||
/* skipping initial spaces */
|
||||
if (size < 3) return 0;
|
||||
|
@ -956,18 +957,45 @@ is_codefence(char *data, size_t size)
|
|||
if (data[2] == ' ') { i += 1; } } }
|
||||
|
||||
/* looking at the hrule char */
|
||||
if (i + 2 >= size || data[i] != '~')
|
||||
if (i + 2 >= size || !(data[i] == '~' || data[i] == '`'))
|
||||
return 0;
|
||||
|
||||
c = data[i];
|
||||
|
||||
/* the whole line must be the char or whitespace */
|
||||
while (i < size && data[i] != '\n') {
|
||||
if (data[i] == '~') n++;
|
||||
else if (data[i] != ' ' && data[i] != '\t')
|
||||
return 0;
|
||||
i++;
|
||||
while (i < size && data[i] == c) {
|
||||
n++; i++;
|
||||
}
|
||||
|
||||
return n >= 3 ? i + 1 : 0;
|
||||
if (n < 3)
|
||||
return 0;
|
||||
|
||||
if (syntax == NULL) {
|
||||
while (i < size && data[i] != '\n') {
|
||||
if (!isspace(data[i]))
|
||||
return 0;
|
||||
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
syntax->data = data + i;
|
||||
syn = 0;
|
||||
|
||||
while (i < size && data[i] != '\n') {
|
||||
syn++; i++;
|
||||
}
|
||||
|
||||
while (syn > 0 && isspace(syntax->data[syn - 1]))
|
||||
syn--;
|
||||
|
||||
while (syn > 0 && isspace(syntax->data[0])) {
|
||||
syntax->data++; syn--;
|
||||
}
|
||||
|
||||
syntax->size = syn;
|
||||
}
|
||||
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
/* is_headerline • returns whether the line is a setext-style hdr underline */
|
||||
|
@ -1210,14 +1238,15 @@ parse_paragraph(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|||
return end;
|
||||
}
|
||||
|
||||
/* parse_blockquote • hanldes parsing of a block-level code fragment */
|
||||
/* parse_fencedcode • hanldes parsing of a block-level code fragment */
|
||||
static size_t
|
||||
parse_fencedcode(struct buf *ob, struct render *rndr, char *data, size_t size)
|
||||
{
|
||||
size_t beg, end;
|
||||
struct buf *work = 0;
|
||||
struct buf syntax = { 0, 0, 0, 0, 0 };
|
||||
|
||||
beg = is_codefence(data, size);
|
||||
beg = is_codefence(data, size, &syntax);
|
||||
if (beg == 0) return 0;
|
||||
|
||||
if (rndr->work.size < rndr->work.asize) {
|
||||
|
@ -1231,7 +1260,7 @@ parse_fencedcode(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|||
while (beg < size) {
|
||||
size_t fence_end;
|
||||
|
||||
fence_end = is_codefence(data + beg, size - beg);
|
||||
fence_end = is_codefence(data + beg, size - beg, NULL);
|
||||
if (fence_end != 0) {
|
||||
beg += fence_end;
|
||||
break;
|
||||
|
@ -1253,7 +1282,7 @@ parse_fencedcode(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|||
bufputc(work, '\n');
|
||||
|
||||
if (rndr->make.blockcode)
|
||||
rndr->make.blockcode(ob, work, rndr->make.opaque);
|
||||
rndr->make.blockcode(ob, work, syntax.size ? &syntax : NULL, rndr->make.opaque);
|
||||
|
||||
rndr->work.size -= 1;
|
||||
return beg;
|
||||
|
@ -1293,7 +1322,7 @@ parse_blockcode(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|||
work->size -= 1;
|
||||
bufputc(work, '\n');
|
||||
if (rndr->make.blockcode)
|
||||
rndr->make.blockcode(ob, work, rndr->make.opaque);
|
||||
rndr->make.blockcode(ob, work, NULL, rndr->make.opaque);
|
||||
rndr->work.size -= 1;
|
||||
return beg;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ enum mkd_extensions {
|
|||
/* mkd_renderer • functions for rendering parsed data */
|
||||
struct mkd_renderer {
|
||||
/* block level callbacks - NULL skips the block */
|
||||
void (*blockcode)(struct buf *ob, struct buf *text, void *opaque);
|
||||
void (*blockcode)(struct buf *ob, struct buf *text, struct buf *syntax, void *opaque);
|
||||
void (*blockquote)(struct buf *ob, struct buf *text, void *opaque);
|
||||
void (*blockhtml)(struct buf *ob, struct buf *text, void *opaque);
|
||||
void (*header)(struct buf *ob, struct buf *text, int level, void *opaque);
|
||||
|
|
Loading…
Reference in a new issue