diff --git a/dumptree.c b/dumptree.c index 2791221..a61bcae 100644 --- a/dumptree.c +++ b/dumptree.c @@ -22,6 +22,7 @@ Pptype(int typ) switch (typ) { case WHITESPACE: return "whitespace"; case CODE : return "code"; + case FENCEDCODE: return "fenced code"; case QUOTE : return "quote"; case MARKUP : return "markup"; case HTML : return "html"; diff --git a/generate.c b/generate.c index 10c3d9f..5ec1c5b 100644 --- a/generate.c +++ b/generate.c @@ -1867,11 +1867,7 @@ printblock(Paragraph *pp, MMIOT *f) Qstring(Begin[align], f); do { - if ( t->is_fenced ) { - text(f); - t = printfenced(t, f); - } - else if ( S(t->text) ) { + if ( S(t->text) ) { if ( t->next && S(t->text) > 2 && T(t->text)[S(t->text)-2] == ' ' && T(t->text)[S(t->text)-1] == ' ' ) { @@ -2060,6 +2056,10 @@ display(Paragraph *p, MMIOT *f) printhtml(p->text, f); break; + case FENCEDCODE: + printfenced(p->text, f); + break; + case CODE: printcode(p->text, p->lang, f); break; diff --git a/markdown.c b/markdown.c index ce8da8e..1fff940 100644 --- a/markdown.c +++ b/markdown.c @@ -632,8 +632,10 @@ codeblock(Paragraph *p) static int -iscodefence(Line *r, int size, line_type kind, mkd_flag_t *flags) +iscodefence(Line *r, Line *orig, mkd_flag_t *flags) { + int kind = 0, size = 2, dle = 0; + if ( !is_flag_set(flags, MKD_FENCEDCODE) || is_flag_set(flags, MKD_STRICT) ) return 0; @@ -644,6 +646,15 @@ iscodefence(Line *r, int size, line_type kind, mkd_flag_t *flags) return 0; + if ( orig ) { + kind = orig->kind; + size = orig->count; + dle = orig->dle; + } + + if ( (dle>>2) != (r->dle>>2) ) + return 0; + if ( kind ) return (r->kind == kind) && (r->count >= size); else @@ -652,19 +663,20 @@ iscodefence(Line *r, int size, line_type kind, mkd_flag_t *flags) static Line * -fencedcodechunk(Line *first, mkd_flag_t *flags) +fencedcodechunk(Line *first, mkd_flag_t *flags, int *yes) { Line *r, *q; /* don't allow zero-length code fences */ - if ( (first->next == 0) || iscodefence(first->next, first->count, first->kind, flags) ) { + if ( (first->next == 0) || iscodefence(first->next, first, flags) ) { first->kind = chk_text; first->is_fenced = 0; if ( first->next) { first->next->kind = chk_text; first->next->is_fenced = 0; } + *yes = 0; return first->next; } @@ -672,7 +684,7 @@ fencedcodechunk(Line *first, mkd_flag_t *flags) * past the closing fence */ for ( r = first->next; r; r = r->next ) { - if ( iscodefence(r, first->count, first->kind, flags) ) { + if ( iscodefence(r, first, flags) ) { if (S(first->text) - first->count > 0) { char *lang_attr = T(first->text) + first->count; @@ -689,9 +701,13 @@ fencedcodechunk(Line *first, mkd_flag_t *flags) S(first->text) = S(r->text) = 0; r->is_fenced = 0; - return r->next; + *yes = 1; + q = r->next; + r->next = 0; + return q; } } + *yes = 0; first->is_fenced = 0; first->kind = chk_text; return first; @@ -742,9 +758,7 @@ textblock(Paragraph *p, int toplevel, mkd_flag_t *flags) Line *t, *next; for ( t = p->text; t ; t = next ) { - if ( iscodefence(t, t->count, 0, flags) ) - next = fencedcodechunk(t, flags); - else if ( ((next = t->next) == 0) || endoftextblock(next, toplevel, flags) ) { + if ( ((next = t->next) == 0) || endoftextblock(next, toplevel, flags) ) { p->align = centered(p->text, t); t->next = 0; return next; @@ -1296,24 +1310,31 @@ compile_document(Line *ptr, MMIOT *f) ptr = consume(addfootnote(ptr, f), &eaten); previous_was_break = 1; } - else if (iscodefence(ptr, 2, 0, &(f->flags))) { - Line *more = ptr; - + else if ( previous_was_break && iscodefence(ptr, 0, &(f->flags)) ) { /* scoop up _everything_ in a fenced code block, including html & footnotes */ + int yes = 0; + Line *last = fencedcodechunk(ptr, &(f->flags), &yes ); - ATTACH(source,more); + if ( yes ) { + int dummy; - { Cache checkpoint = source; - while ( (more = more->next) && !iscodefence(more, ptr->count, ptr->kind, &(f->flags)) ) - ATTACH(source,more); + /* dump out any previously cached text + */ + uncache(&source, &d, f); - if ( more ) - ptr = more; - else { - source = checkpoint; - ptr = ptr->next; - } + p = Pp(&d, ptr, FENCEDCODE); + + ptr = consume(last, &dummy); + previous_was_break = 1; + } + else { + /* unterminated fenced code; treat as regular markdown & cache until the next + * fenced code, htl, or style block + */ + ATTACH(source, ptr); + previous_was_break = 0; + ptr = ptr->next; } } else { @@ -1474,14 +1495,25 @@ compile(Line *ptr, int toplevel, MMIOT *f) ptr = htmlblock(p, tag, &unclosed); if ( ! unclosed ) { p->typ = HTML; + continue; } } - if ( unclosed ) { - ptr = textblock(p, toplevel, &(f->flags) ); - /* tables are a special kind of paragraph */ - if ( actually_a_table(f, p->text) ) - p->typ = TABLE; + + if ( iscodefence(p->text, 0, &(f->flags)) ) { + int yes = 0; + + ptr = fencedcodechunk(p->text, &(f->flags), &yes); + + if ( yes ) { + p->typ = FENCEDCODE; + continue; + } } + + ptr = textblock(p, toplevel, &(f->flags) ); + /* tables are a special kind of paragraph */ + if ( actually_a_table(f, p->text) ) + p->typ = TABLE; } if ( (para||toplevel) && !p->align ) p->align = PARA; diff --git a/markdown.h b/markdown.h index c53b830..ace005f 100644 --- a/markdown.h +++ b/markdown.h @@ -102,7 +102,7 @@ typedef struct paragraph { char *label; /* toc label, uniqued */ char *ident; /* %id% tag for QUOTE */ char *lang; /* lang attribute for CODE */ - enum { WHITESPACE=0, CODE, QUOTE, MARKUP, + enum { WHITESPACE=0, CODE, FENCEDCODE, QUOTE, MARKUP, HTML, STYLE, DL, UL, OL, AL, LISTITEM, HDR, HR, TABLE, SOURCE } typ; enum { IMPLICIT=0, PARA, CENTER} align; diff --git a/tests/codeblock.t b/tests/codeblock.t index 37202c8..16ea529 100644 --- a/tests/codeblock.t +++ b/tests/codeblock.t @@ -50,19 +50,17 @@ code! still code! ~~~' \ - '

code!
+    '
code!
 
 still code!
-
-

' +
' try -ffencedcode 'fenced code block' \ '~~~ code! ~~~' \ - '

code!
-
-

' + '
code!
+
' try -ffencedcode 'fenced code block in list' \ '1. ~~~ @@ -78,9 +76,9 @@ try -ffencedcode 'fenced code block in blockquote' \ '>~~~ code ~~~' \ -'

code
+'
code
 
-

' +
' try -ffencedcode 'unterminated fenced code block' \ '~~~ @@ -94,11 +92,10 @@ try -ffencedcode 'fenced code block with tildes' \ code with tildes ~~~ ~~~~~' \ -'

~~~
+'
~~~
 code with tildes
 ~~~
-
-

' +
' try -ffencedcode 'paragraph with trailing fenced block' \ 'text text text @@ -108,17 +105,16 @@ code code code? ~~~' \ '

text text text text text text -

code code code?
-
-

' +~~~ +code code code? +~~~

' try -ffencedcode 'fenced code blocks with backtick delimiters' \ '``` code ```' \ -'

code
-
-

' +'
code
+
' try -ffencedcode 'fenced code block with mismatched delimters' \ '``` @@ -132,57 +128,50 @@ try -ffencedcode 'fenced code block with lang attribute' \ '```lang code ```' \ -'

code
-
-

' +'
code
+
' try -ffencedcode 'fenced code block with lang-name attribute' \ '```lang-name code ```' \ -'

code
-
-

' +'
code
+
' try -ffencedcode 'fenced code block with lang_name attribute' \ '```lang_name code ```' \ -'

code
-
-

' +'
code
+
' try -ffencedcode 'fenced code block with lang attribute and space' \ '``` lang code ```' \ -'

code
-
-

' +'
code
+
' try -ffencedcode 'fenced code block with lang attribute and multiple spaces' \ '``` lang code ```' \ -'

code
-
-

' +'
code
+
' try -ffencedcode 'fenced code block with lang-name attribute and space' \ '``` lang-name code ```' \ -'

code
-
-

' +'
code
+
' try -ffencedcode 'fenced code block with lang_name attribute and space' \ '``` lang_name code ```' \ -'

code
-
-

' +'
code
+
' try -ffencedcode 'fenced code block with blank line in the middle' \ '``` @@ -190,20 +179,18 @@ hello sailor ```' \ -'

hello
+'
hello
 
 sailor
-
-

' +
' try -ffencedcode 'fenced code block with html in the middle' \ '~~~~

hello, sailor

~~~~' \ -'

<h1>hello, sailor</h1>
-
-

' +'
<h1>hello, sailor</h1>
+
' try -ffencedcode 'fenced code block with trailing spaces in list item' \ '1. ~~~~ @@ -229,9 +216,8 @@ bar ~~~~' \ '

foo

-

bar
-
-

' +
bar
+
' try -ffencedcode 'checkline misparse as fenced code' \ @@ -241,10 +227,9 @@ content ``` ' \ '

label -

content
-
-

' - +class +content +

' summary $0 exit $rc diff --git a/tests/crash.t b/tests/crash.t index 0d47746..aa07f51 100644 --- a/tests/crash.t +++ b/tests/crash.t @@ -76,21 +76,10 @@ RESULT='