X-Git-Url: http://git.plutz.net/?a=blobdiff_plain;f=markdown.awk;h=6d22e3912e6f5e3580bffb61babf36b077117b39;hb=4c361b1926eed5a426ff4271a027e54e57abe78a;hp=a50f7a2253cf0b3ca52798d819380602e454fcd1;hpb=c4ba9cc2baf2fb79323279203b4e1694100ecabe;p=cgilite diff --git a/markdown.awk b/markdown.awk index a50f7a2..6d22e39 100755 --- a/markdown.awk +++ b/markdown.awk @@ -5,6 +5,20 @@ # Meant to support all features of John Grubers basic Markdown # + a number of common extensions, mostly inspired by Pandoc Markdown +# Copyright 2021 - 2023 Paul Hänsch +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +# IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + # Supported Features / TODO: # ========================== # [x] done [ ] todo [-] not planned ? unsure @@ -38,7 +52,10 @@ # # Extensions - Block elements: # ---------------------------- +# - [x] Automatic
-wrapping (custom) # - ? Heading identifiers (php md, pandoc) +# - [x] Heading attributes (custom) +# - [ ]
terminates section # - [x] Automatic heading identifiers (custom) # - [x] Fenced code blocks (php md, pandoc) # - [x] Fenced code attributes @@ -52,7 +69,7 @@ # - [x] Pipe table (php md, pandoc) # - [x] Line blocks (pandoc) # - [x] Task lists (pandoc, custom) -# - [ ] Definition lists (php md, pandoc) +# - [x] Definition lists (php md, pandoc) # - [-] Numbered example lists (pandoc) # - [-] Metadata blocks (pandoc) # - [x] Metadata blocks (custom) @@ -89,13 +106,13 @@ function HTML ( text ) { return text; } -function URL ( text ) { +function URL ( text, sharp ) { gsub( /&/, "%26", text ); gsub( /"/, "%22", text ); gsub( /'/, "%27", text ); gsub( /`/, "%60", text ); gsub( /\?/, "%3F", text ); - gsub( /#/, "%23", text ); + if (sharp) gsub( /#/, "%23", text ); gsub( /\[/, "%5B", text ); gsub( /\]/, "%5D", text ); gsub( / /, "%20", text ); @@ -104,7 +121,7 @@ function URL ( text ) { return text; } -function inline( line, LOCAL, len, code, href, guard ) { +function inline( line, LOCAL, len, text, code, href, guard ) { nu = "(\\\\\\\\|\\\\[^\\\\]|[^\\\\_]|_[[:alnum:]])*" # not underline (except when escaped) na = "(\\\\\\\\|\\\\[^\\\\]|[^\\\\\\*])*" # not asterisk (except when escaped) ieu = "_([^_[:space:]]|[^_[:space:]]" nu "[^_[:space:]])_" # inner (underline) @@ -131,7 +148,7 @@ function inline( line, LOCAL, len, code, href, guard ) { code = substr( line, len + 1, match( substr(line, len + 1), guard ) - 1) len = 2 * length(guard) + length(code) # strip single surrounding white spaces - code = gensub( / (.*) /, "\\1", "1" , code) + gsub( /^ | $/, "", code) # escape HTML within code span gsub( /&/, "\\&", code ); gsub( //, "\\>", code ); return "" code "" inline( substr( line, len + 1 ) ) @@ -195,16 +212,16 @@ function inline( line, LOCAL, len, code, href, guard ) { title = gensub(/^!\[([^]]*)\]\(([^"\)]+)([ \t]+"([^"]+)")?\)(\{([a-zA-Z \t-]*)\})?/, "\\4", "g", substr(line, 1, len) ); attrib = gensub(/^!\[([^]]*)\]\(([^"\)]+)([ \t]+"([^"]+)")?\)(\{([a-zA-Z \t-]*)\})?/, "\\6", "g", substr(line, 1, len) ); if ( title && attrib ) { - return "\""" \ + return "\""" \ inline( substr( line, len + 1) ); } else if ( title ) { - return "\""" \ + return "\""" \ inline( substr( line, len + 1) ); } else if ( attrib ) { - return "\""" \ + return "\""" \ inline( substr( line, len + 1) ); } else { - return "\""" \ + return "\""" \ inline( substr( line, len + 1) ); } @@ -215,10 +232,10 @@ function inline( line, LOCAL, len, code, href, guard ) { id = gensub(/^!\[([^\n]*)\] ?\[([^\n]*)\].*/, "\\2", 1, substr(line, 1, len) ); if ( ! id ) id = text; if ( rl_href[id] && rl_title[id] ) { - return "\""" \ + return "\""" \ inline( substr( line, len + 1) ); } else if ( rl_href[id] ) { - return "\""" \ + return "\""" \ inline( substr( line, len + 1) ); } else { return "" HTML(substr(line, 1, len)) inline( substr(line, len + 1) ); @@ -306,8 +323,43 @@ function inline( line, LOCAL, len, code, href, guard ) { } } -function _block( block, LOCAL, st, len, hlvl, htxt, guard, code, indent, attrib ) { - gsub( /^\n+|\n+$/, "", block ); +function headline( hlvl, htxt, attrib, LOCAL, sec, n, HL) { + match(hstack, /([0-9]+( [0-9]+){5})$/); split( substr(hstack, RSTART), HL); + + for ( n = hlvl; n <= 6; n++ ) { sec = sec (HL[n]?"
":""); } + HL[hlvl]++; for ( n = hlvl + 1; n <= 6; n++) { HL[n] = 0;} + + hid = ""; for ( n = 2; n <= blvl; n++) { hid = hid BL[n] "/"; } + hid = hid HL[1]; for ( n = 2; n <= hlvl; n++) { hid = hid "." HL[n] ; } + hid = hid ":" URL(htxt, 1); + + sub(/([0-9]+( [0-9]+){5})$/, "", hstack); + hstack = hstack HL[1] " " HL[2] " " HL[3] " " HL[4] " " HL[5] " " HL[6]; + + return sec "
" \ + "" inline( htxt ) \ + "" \ + "\n"; +} + +# Nested Block, resets heading counters +function _nblock( block, LOCAL, sec, n ) { + hstack = hstack " 0 0 0 0 0 0"; + + # Block Level + blvl++; BL[blvl]++; + for ( n = blvl + 1; n in BL; n++) { delete BL[n]; } + + block = _block( block ); + match(hstack, /([0-9]+( [0-9]+){5})$/); split( substr(hstack, RSTART), HL); + sec = ""; for ( n = 1; n <= 6; n++ ) { sec = sec (HL[n]?"
":""); } + + sub("( +[0-9]+){6} *$", "", hstack); blvl--; + return block sec; +} + +function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code, indent, list ) { + gsub( "(^\n+|\n+$)", "", block ); if ( block == "" ) { return ""; @@ -344,8 +396,9 @@ function _block( block, LOCAL, st, len, hlvl, htxt, guard, code, indent, attrib } else if ( match( block, /^> /) ) { match( block, /(^|\n)[[:space:]]*(\n|$)/ ) || match(block, /$/); len = RLENGTH; st = RSTART; - return "
\n" _block( gensub( /(^|\n)> /, "\n", "g", substr(block, 1, st - 1) ) ) "
\n\n" \ - _block( substr(block, st + len) ); + text = substr(block, 1, st - 1); gsub( /(^|\n)> /, "\n", text ); + text = _nblock( text ); gsub( /^\n|\n$/, "", text ) + return "
" text "
\n\n" _block( substr(block, st + len) ); # Pipe Tables (pandoc / php md / gfm ) } else if ( match(block, "^((\\|)?([^\n]+\\|)+[^\n]+(\\|)?)\n" \ @@ -447,7 +500,7 @@ function _block( block, LOCAL, st, len, hlvl, htxt, guard, code, indent, attrib ttext = "\n" for (cnt = 1; cnt <= cols; cnt++) - ttext = ttext "" _block(tarray[cnt]) "" + ttext = ttext "" _nblock(tarray[cnt]) "" ttext = ttext "\n" } @@ -470,20 +523,20 @@ function _block( block, LOCAL, st, len, hlvl, htxt, guard, code, indent, attrib ttext = ttext "" for (cnt = 1; cnt <= cols; cnt++) - ttext = ttext "" _block(tarray[cnt]) "" + ttext = ttext "" _nblock(tarray[cnt]) "" ttext = ttext "\n" } - return "" ttext "
\n" _block(block); + return "" ttext "
\n" _nblock(block); # Line Blocks (pandoc) } else if ( match(block, /^\| [^\n]*(\n|$)(\| [^\n]*(\n|$)|[ \t]+[^\n[:space:]][^\n]*(\n|$))*/) ) { len = RLENGTH; st = RSTART; - code = substr(block, 1, len); - gsub(/\n[[:space:]]+/, " ", code); - gsub(/\n\| /, "\n", code); - gsub(/^\| |\n$/, "", code); - return "
" gensub(/\n/, "
\n", "g", inline( code )) "
\n" \ - _block( substr( block, len + 1) ); + + text = substr(block, 1, len); gsub(/\n[[:space:]]+/, " ", text); + gsub(/\n\| /, "\n", text); gsub(/^\| |\n$/, "", text); + text = inline(text); gsub(/\n/, "
\n", text); + + return "
" text "
\n" _block( substr( block, len + 1) ); # Indented Code Block } else if ( match(block, /^( |\t)( *\t*[^ \t\n]+ *\t*)+(\n|$)(( |\t)[^\n]+(\n|$)|[ \t]*(\n|$))*/) ) { @@ -497,13 +550,13 @@ function _block( block, LOCAL, st, len, hlvl, htxt, guard, code, indent, attrib # Fenced Divs (pandoc, custom) } else if ( match( block, /^(:::+)/ ) ) { guard = substr( block, 1, RLENGTH ); - code = gensub(/^[^\n]+\n/, "", 1, block); + code = block; sub(/^[^\n]+\n/, "", code); attrib = gensub(/^:::+[ \t]*\{?[ \t]*([^\}\n]*)\}?[ \t]*\n.*$/, "\\1", 1, block); gsub(/[^a-zA-Z0-9_-]+/, " ", attrib); gsub(/(^ | $)/, "", attrib); if ( match(code, "(^|\n)" guard "+(\n|$)" ) ) { len = RLENGTH; st = RSTART; - return "
" _block( substr(code, 1, st - 1) ) "
\n" \ + return "
" _nblock( substr(code, 1, st - 1) ) "
\n" \ _block( substr( code, st + len ) ); } else { match( block, /(^|\n)[[:space:]]*(\n|$)/ ) || match( block, /$/ ); @@ -530,60 +583,57 @@ function _block( block, LOCAL, st, len, hlvl, htxt, guard, code, indent, attrib _block( substr(block, st + len) ); } - # Unordered list - } else if ( match( block, "^ ? ? ?[-+*][ \t]+[^\n]+(\n|$)" \ - "(([ \t]*\n)* ? ? ?[-+*][ \t]+[^\n]+(\n|$)" \ - "|([ \t]*\n)*( ? ? ?\t| +)[^\n]+(\n|$)" \ - "|[^\n]+(\n|$))*" ) ) { - list = substr( block, 1, RLENGTH); - block = substr( block, RLENGTH + 1); - indent = length( gensub(/[-+*][ \t]+[^\n]+.*$/, "", 1, list) ); - - gsub("(^|\n) {0," indent "}", "\n", list); - return "\n\n" _block( block ); - - # Ordered list - } else if ( match( block, "^ ? ? ?([0-9]+|#)\\.[ \t]+[^\n]+(\n|$)" \ - "(([ \t]*\n)* ? ? ?([0-9]+|#)\\.[ \t]+[^\n]+(\n|$)" \ - "|([ \t]*\n)*( ? ? ?\t| +)[^\n]+(\n|$)" \ - "|[^\n]+(\n|$))*" ) ) { - list = substr( block, 1, RLENGTH); - block = substr( block, RLENGTH + 1); - indent = length( gensub(/([0-9]+|#)\.[ \t]+[^\n]+.*$/, "", 1, list) ); - - gsub("(^|\n) {0," indent "}", "\n", list); - return "\n
    \n" _list( substr(list, 2) ) "
\n" _block( block ); - - # First Order Heading - } else if ( match( block, /^[^\n]+\n===+(\n|$)/ ) ) { - len = RLENGTH; - HL[1]++; HL[2] = 0; HL[3] = 0; HL[4] = 0; HL[5] = 0; HL[6] = 0; - return "

" \ - inline( gensub( /\n.*$/, "", "g", block ) ) \ - "

\n\n" \ - _block( substr( block, len + 1 ) ); + # First Order Heading H1 + Attrib + } else if ( match( block, /^([^\n]+)([ \t]*\{([^\}\n]+)\})\n===+(\n|$)/ ) ) { + len = RLENGTH; text = attrib = block; + sub(/([ \t]*\{([^\}\n]+)\})\n===+(\n.*)?$/, "", text); + sub(/\}\n===+(\n.*)?$/, "", attrib); sub(/^([^\n]+)[ \t]*\{/, "", attrib); + gsub(/[^a-zA-Z0-9_-]+/, " ", attrib); gsub(/(^ | $)/, "", attrib); - # Second Order Heading - } else if ( match( block, /^[^\n]+\n---+(\n|$)/ ) ) { - len = RLENGTH; - HL[2]++; HL[3] = 0; HL[4] = 0; HL[5] = 0; HL[6] = 0; - return "

" \ - inline( gensub( /\n.*$/, "", "g", block ) ) \ - "

\n\n" \ - _block( substr( block, len + 1) ); - - # Nth Order Heading - } else if ( match( block, /^#{1,6}[ \t]*[^\n]+([ \t]*#*)(\n|$)/ ) ) { - len = RLENGTH; - hlvl = length( gensub( /^(#{1,6}).*$/, "\\1", "g", block ) ); - htxt = gensub(/^#{1,6}[ \t]*(([^ \t\n]+|[ \t]+[^ \t\n#]|[ \t]+#+[^\n#])+)([ \t]*#*)(\n.*)?$/, "\\1", 1, block); - HL[hlvl]++; for ( n = hlvl + 1; n < 7; n++) { HL[n] = 0;} - hid = HL[1]; for ( n = 2; n <= hlvl; n++) { hid = hid "." HL[n] ; } - return "" inline( htxt ) \ - "\n\n" \ - _block( substr( block, len + 1) ); + return headline(1, text, attrib) _block( substr( block, len + 1 ) ); + + # First Order Heading H1 + } else if ( match( block, /^([^\n]+)\n===+(\n|$)/ ) ) { + len = RLENGTH; text = substr(block, 1, len); + sub(/\n===+(\n.*)?$/, "", text); + + return headline(1, text, 0) _block( substr( block, len + 1 ) ); + + # Second Order Heading H2 + Attrib + } else if ( match( block, /^([^\n]+)([ \t]*\{([^\}\n]+)\})\n---+(\n|$)/ ) ) { + len = RLENGTH; text = attrib = block; + sub(/([ \t]*\{([^\}\n]+)\})\n---+(\n.*)?$/, "", text); + sub(/\}\n---+(\n.*)?$/, "", attrib); sub(/^([^\n]+)[ \t]*\{/, "", attrib); + gsub(/[^a-zA-Z0-9_-]+/, " ", attrib); gsub(/(^ | $)/, "", attrib); + + return headline(2, text, attrib) _block( substr( block, len + 1) ); + + # Second Order Heading H2 + } else if ( match( block, /^([^\n]+)\n---+(\n|$)/ ) ) { + len = RLENGTH; text = substr(block, 1, len); + sub(/\n---+(\n.*)?$/, "", text); + + return headline(2, text, 0) _block( substr( block, len + 1) ); + + # Nth Order Heading H1 H2 H3 H4 H5 H6 + Attrib + } else if ( match( block, /^(#{1,6})[ \t]*(([^ \t\n]+|[ \t]+[^ \t\n#]|[ \t]+#+[ \t]*[^ \t\n#])+)[ \t]*#*([ \t]*\{([a-zA-Z \t-]*)\})(\n|$)/ ) ) { + len = RLENGTH; text = attrib = substr(block, 1, len); + match(block, /^#{1,6}/); n = RLENGTH; + + sub(/^(#{1,6})[ \t]*/, "", text); sub(/[ \t]*#*([ \t]*\{([a-zA-Z \t-]*)\})(\n.*)?$/, "", text); + sub(/^(#{1,6})[ \t]*(([^ \t\n]+|[ \t]+[^ \t\n#]|[ \t]+#+[ \t]*[^ \t\n#])+)[ \t]*#*[ \t]*\{/, "", attrib); + sub(/\})(\n.*)?$/, "", attrib); + gsub(/[^a-zA-Z0-9_-]+/, " ", attrib); gsub(/(^ | $)/, "", attrib); + + return headline( n, text, attrib ) _block( substr( block, len + 1) ); + + # Nth Order Heading H1 H2 H3 H4 H5 H6 + } else if ( match( block, /^(#{1,6})[ \t]*(([^ \t\n]+|[ \t]+[^ \t\n#]|[ \t]+#+[ \t]*[^ \t\n#])+)[ \t]*#*(\n|$)/ ) ) { + len = RLENGTH; text = substr(block, 1, len); + match(block, /^#{1,6}/); n = RLENGTH; + sub(/^(#{1,6})[ \t]*/, "", text); sub(/[ \t]*#*(\n.*)?$/, "", text); + + return headline( n, text, 0 ) _block( substr( block, len + 1) ); # block images (wrapped in
) } else if ( match(block, /^!\[([^]]*)\]\(([^"\)]+)([ \t]+"([^"]+)")?\)(\{([a-zA-Z \t-]*)\})?(\n|$)/) ) { @@ -593,25 +643,25 @@ function _block( block, LOCAL, st, len, hlvl, htxt, guard, code, indent, attrib title = gensub(/^!\[([^]]*)\]\(([^"\)]+)([ \t]+"([^"]+)")?\)(\{([a-zA-Z \t-]*)\})?(\n.*)?$/, "\\4", "g", block); attrib = gensub(/^!\[([^]]*)\]\(([^"\)]+)([ \t]+"([^"]+)")?\)(\{([a-zA-Z \t-]*)\})?(\n.*)?$/, "\\6", "g", block); if ( title && attrib ) { - return "
" \ - "\""" \ + return "
" \ + "\""" \ "
" inline(title) "
" \ "
\n\n" \ _block( substr( block, len + 1) ); } else if ( title ) { - return "
" \ - "\""" \ + return "
" \ + "\""" \ "
" inline(title) "
" \ "
\n\n" \ _block( substr( block, len + 1) ); } else if ( attrib ) { - return "
" \ - "\""" \ + return "
" \ + "\""" \ "
\n\n" \ _block( substr( block, len + 1) ); } else { - return "
" \ - "\""" \ + return "
" \ + "\""" \ "
\n\n" \ _block( substr( block, len + 1) ); } @@ -623,14 +673,14 @@ function _block( block, LOCAL, st, len, hlvl, htxt, guard, code, indent, attrib id = gensub(/^!\[([^\n]*)\] ?\[([^\n]*)\](\n.*)?$/, "\\2", 1, block); if ( ! id ) id = text; if ( rl_href[id] && rl_title[id] ) { - return "
" \ - "\""" \ + return "
" \ + "\""" \ "
" inline(rl_title[id]) "
" \ "
\n\n" \ _block( substr( block, len + 1) ); } else if ( rl_href[id] ) { - return "
" \ - "\""" \ + return "
" \ + "\""" \ "
\n\n" \ _block( substr( block, len + 1) ); } else { @@ -641,7 +691,38 @@ function _block( block, LOCAL, st, len, hlvl, htxt, guard, code, indent, attrib } else if ( AllowMacros && match( block, /^<<(([^>]|>[^>])+)>>(\n|$)/) ) { len = RLENGTH; text = gensub(/^<<(([^>]|>[^>])+)>>(\n.*)?$/, "\\1", 1, block); - return macro(text) _block(substr(block, len + 1)); + return macro(text) _block(substr(block, len + 1) ); + + # Definition list + } else if (match( block, "^(([ \t]*\n)*[^:\n \t][^\n]+\n" \ + "([ \t]*\n)* ? ? ?:[ \t][^\n]+(\n|$)" \ + "(([ \t]*\n)* ? ? ?:[ \t][^\n]+(\n|$)" \ + "|[^:\n \t][^\n]+(\n|$)" \ + "|( ? ? ?\t| +)[^\n]+(\n|$)" \ + "|([ \t]*\n)+( ? ? ?\t| +)[^\n]+(\n|$))*)+" \ + )) { + list = substr( block, 1, RLENGTH); block = substr( block, RLENGTH + 1); + return "\n
\n" _dlist( list ) "
\n" _block( block ); + + # Unordered list types + } else if ( text = _startlist( block, "ul", "-", "([+*•]|[0-9]+\\.|#\\.|[0-9]+\\)|#\\))") ) { + return text; + } else if ( text = _startlist( block, "ul", "\\+", "([-*•]|[0-9]+\\.|#\\.|[0-9]+\\)|#\\))") ) { + return text; + } else if ( text = _startlist( block, "ul", "\\*", "([-+•]|[0-9]+\\.|#\\.|[0-9]+\\)|#\\))") ) { + return text; + } else if ( text = _startlist( block, "ul", "•", "([-+*]|[0-9]+\\.|#\\.|[0-9]+\\)|#\\))") ) { + return text; + + # Ordered list types + } else if ( text = _startlist( block, "ol", "[0-9]+\\.", "([-+*•]|#\\.|[0-9]+\\)|#\\))") ) { + return text; + } else if ( text = _startlist( block, "ol", "[0-9]+\\)", "([-+*•]|[0-9]+\\.|#\\.|#\\))") ) { + return text; + } else if ( text = _startlist( block, "ol", "#\\.", "([-+*•]|[0-9]+\\.|[0-9]+\\)|#\\))") ) { + return text; + } else if ( text = _startlist( block, "ol", "#\\)", "([-+*•]|[0-9]+\\.|#\\.|[0-9]+\\))") ) { + return text; # Split paragraphs } else if ( match( block, /(^|\n)[[:space:]]*(\n|$)/) ) { @@ -660,52 +741,78 @@ function _block( block, LOCAL, st, len, hlvl, htxt, guard, code, indent, attrib } } -function _list( block, last, LOCAL, p) { - if ( ! length(block) ) return ""; - gsub(/^([-+*]|[0-9]+\.|#\.)( ? ? ?|\t)/, "", block) +function _startlist(block, type, mark, exclude, LOCAL, st, len, list, indent, text) { + if (match( block, "(^|\n) ? ? ?" mark "[ \t][^\n]+(\n|$)" \ + "(([ \t]*\n)* ? ? ?" mark "[ \t][^\n]+(\n|$)" \ + "|([ \t]*\n)*( ? ? ?\t| +)[^\n]+(\n|$)" \ + "|[^\n \t][^\n]+(\n|$))*" ) ) { + st = RSTART; len = RLENGTH; list = substr( block, st, len); + + sub("^\n", "", list); match(list, "^ ? ? ?"); indent = RLENGTH; + gsub( "(^|\n) {0," indent "}", "\n", list); sub("^\n", "", list); + + text = substr(block, 1, st - 1); block = substr(block, st + len); + if (match(text, /\n[[:space:]]*\n/)) return 0; + if (match(text, "(^|\n) ? ? ?" exclude "[ \t][^\n]+")) return 0; + if (match( list, "\n" exclude "[ \t]" )) { + block = substr(list, RSTART + 1) block; + list = substr(list, 1, RSTART); + } - # slice next list item from input - if ( match( block, /\n([-+*]|[0-9]+\.|#\.)[ \t]+[^\n]+/) ) { - p = substr( block, 1, RSTART); - block = substr( block, RSTART + 1); - } else { - p = block; block = ""; - } - sub( /\n +([-+*]|[0-9]+\.|#\.)/, "\n&", p ); + return _block( text ) "<" type ">\n" _list( list, mark ) "\n" _block( block ); + } else return 0; +} - # if this should be a paragraph item - # either previous item (last) or current item (p) contains blank lines - if (match(last, /\n[[:space:]]*\n/) || match(p, /\n[[:space:]]*\n/) ) { - last = p; p = _block(p); - } else { - last = p; p = _block(p); - sub( /^

/, "", p ); - sub( /<\/p>\n/, "", p ); +function _list (block, mark, p, LOCAL, len, st, text, indent, task) { + if ( match(block, "^([ \t]*\n)*$")) return; + + match(block, "^" mark "[ \t]"); indent = RLENGTH; + sub("^" mark "[ \t]", "", block); + + if (match(block, /\n[ \t]*\n/)) p = 1; + + match( block, "\n" mark "[ \t][^\n]+(\n|$)" ); + st = (RLENGTH == -1) ? length(block) + 1 : RSTART; + text = substr(block, 1, st); block = substr(block, st + 1); + + gsub("\n {0," indent "}", "\n", text); + + task = match( text, /^\[ \]/ ) ? "

  • " : \ + match( text, /^\[-\]/ ) ? "
  • " : \ + match( text, /^\[\/\]/ ) ? "
  • " : \ + match( text, /^\[\?\]/ ) ? "
  • " : \ + match( text, /^\[[xX]\]/) ? "
  • " : "
  • "; + sub(/^\[[-? \/xX]\]/, "", text); + + text = _nblock( text ); + if ( ! p && match( text, "^

    (]|\n$" )) + gsub( "(^

    |

    \n$)", "", text); + + return task text "
  • \n" _list(block, mark, p); +} + +function _dlist (block, LOCAL, len, st, text, indent, p) { + if (match( block, "^([ \t]*\n)*[^:\n \t][^\n]+\n" )) { + len = RLENGTH; text = substr(block, 1, len); + gsub( "(^\n*|\n*$)", "", text ); + return "
    " inline( text ) "
    \n" _dlist( substr(block, len + 1) ); + } else if (match( block, "^([ \t]*\n)* ? ? ?:[ \t][^\n]+(\n|$)" \ + "([^:\n \t][^\n]+(\n|$)" \ + "|( ? ? ?\t| +)[^\n]+(\n|$)" \ + "|([ \t]*\n)+( ? ? ?\t| +)[^\n]+(\n|$))*" \ + )) { + len = RLENGTH; text = substr(block, 1, len); + sub( "^([ \t]*\n)*", "", text); + match(text, "^ ? ? ?:(\t| +)"); indent = RLENGTH; + sub( "^ ? ? ?:(\t| +)", "", text); + gsub( "(^|\n) {0," indent "}", "\n", text ); + + text = _nblock(text); + if (match( text, "^

    (]|\n$" )) + gsub( "(^

    |

    \n$)", "", text); + + return "
    " text "
    \n" _dlist( substr(block, len + 1) ); } - sub( /\n$/, "", p ); - - # Task List (pandoc, custom) - if ( p ~ /^\[ \].*/ ) { return "
  • " \ - substr(p, 4) "
  • \n" _list( block, last ); - } else if ( p ~ /^\[-\].*/ ) { return "
  • " \ - substr(p, 4) "
  • \n" _list( block, last ); - } else if ( p ~ /^\[\?\].*/ ) { return "
  • " \ - substr(p, 4) "
  • \n" _list( block, last ); - } else if ( p ~ /^\[\/\].*/ ) { return "
  • " \ - substr(p, 4) "
  • \n" _list( block, last ); - } else if ( p ~ /^\[[xX]\].*/ ) { return "
  • " \ - substr(p, 4) "
  • \n" _list( block, last ); - } else if ( p ~ /^

    \[ \].*/ ) { return "

  • " \ - substr(p, 7) "

  • \n" _list( block, last ); - } else if ( p ~ /^

    \[-\].*/ ) { return "

  • " \ - substr(p, 7) "

  • \n" _list( block, last ); - } else if ( p ~ /^

    \[\?\].*/ ) { return "

  • " \ - substr(p, 7) "

  • \n" _list( block, last ); - } else if ( p ~ /^

    \[\/\].*/ ) { return "

  • " \ - substr(p, 7) "

  • \n" _list( block, last ); - } else if ( p ~ /^

    \[[xX]\].*/ ) { return "

  • " \ - substr(p, 7) "

  • \n" _list( block, last ); - } else { return "
  • " p "
  • \n" _list( block, last ); } } BEGIN { @@ -713,6 +820,7 @@ BEGIN { file = ""; rl_href[""] = ""; rl_title[""] = ""; if (ENVIRON["MD_HTML"] == "true") { AllowHTML = "true"; } HL[1] = 0; HL[2] = 0; HL[3] = 0; HL[4] = 0; HL[5] = 0; HL[6] = 0; + # hls = "0 0 0 0 0 0"; # Buffering of full file ist necessary, e.g. to find reference links while (getline) { file = file $0 "\n"; } @@ -736,5 +844,5 @@ BEGIN { # for (n in rl_href) { debug(n " | " rl_href[n] " | " rl_title[n] ); } # Run Block Processing -> The Actual Markdown! - printf "%s", _block( file ); + printf "%s", _nblock( file ); }