diff options
| Commit | 828ef67391a1a4b4d6d0fc7e466d4678c5decc0d (patch) | |
|---|---|---|
| Author | 2025-03-03 09:48:07 +0200 | |
| Committer | 2025-03-03 09:48:07 +0200 | |
| Files | 6b89eb1fa77b75c560a1b969daa2e3397a3c0e10 /md-parser.awk | |
| csg-828ef67391a1a4b4d6d0fc7e466d4678c5decc0d.tar csg-828ef67391a1a4b4d6d0fc7e466d4678c5decc0d.tar.gz csg-828ef67391a1a4b4d6d0fc7e466d4678c5decc0d.zip | ||
| Parent | 7f2a2075423fa409e5cbc0903260a899bc47fb9a (diff) | |
feat(parser): Rework completion
1 files changed, 160 insertions, 164 deletions
| -rw-r--r-- | md-parser.awk | 324 |
diff --git a/md-parser.awk b/md-parser.awk index 7f3519b..2161482 100644 --- a/md-parser.awk +++ b/md-parser.awk @@ -61,16 +61,51 @@ BEGIN { #== Block markup ==# -# Inline HTML -/^[ \t]?[ \t]?[ \t]?<\/?[0-9A-Za-z]+/ { - # if it isn't inside a list - if (indentation() - 2 * list_level < 4) { - STATE_set(STATE_HTML) - soft_next() +#-- Blockquotes --# +blockquote_level > 0 && empty0 { + STATE_unset(STATE_PARAGRAPH_P1) + if (STATE_thenunset(STATE_CODEBLOCK)) { + PNappnd("</code></pre>") + } + for (P1 = P1 ORS; blockquote_level > 0; --blockquote_level) { + P1 = P1 "</blockquote>" + } +} +/^>[ \t]/ { + STATE_set(STATE_BLOCKQUOTE) + + match($0, /^[> \t]*> /) + blevel = substr($0, RSTART, RLENGTH) + + $0 = substr($0, RSTART + RLENGTH) + gsub(/[ \t]/, "", blevel) + blevel = length(blevel) + + for (;blockquote_level < blevel; ++blockquote_level) { + P1 = P1 "<blockquote>" + } + for (;blockquote_level > blevel; --blockquote_level) { + P2 = P2 "</blockquote>" } } +STATE_isset(STATE_BLOCKQUOTE) && $0 == ">" { + $0 = "" + empty0 = TRUE +} + +#-- Remove list indentation --# +list_level > 0 && !empty0 && !is_blank() { + level = int((indentation() + 2) / 2) + sub("^[ \t]{1," lists_shift[list_level] "}", "") +} + +#-- Inline HTML --# +!STATE_isset(STATE_CODEBLOCK) && /^[ \t]{0,3}<\/?[0-9A-Za-z]+/ { + STATE_set(STATE_HTML) + soft_next() +} STATE_isset(STATE_HTML) { - if (/^[ \t]*$/) { + if (is_blank()) { STATE_unset(STATE_HTML) } else { @@ -78,101 +113,88 @@ STATE_isset(STATE_HTML) { } } -# Fenced code blocks +#-- Fenced code blocks --# STATE_isset(STATE_FENCED_CODEBLOCK) { - if (fenced_class) { - $0 = fenced_class $0 - fenced_class = "" + if (fenced_start) { + $0 = fenced_start $0 + fenced_start = "" soft_next() } - $0 = " " $0 + if (/^```/) { + PNappnd("</code></pre>") + STATE_unset(STATE_CODEBLOCK) + STATE_unset(STATE_FENCED_CODEBLOCK) + next + } } -# Code blocks (ending condition) +#-- Code blocks --# STATE_isset(STATE_CODEBLOCK) { - # If ended codeblock - if ((STATE_isset(STATE_FENCED_CODEBLOCK) && / ```$/) || - ! /^( |\t|[ \t]*$)/ || - (blockquote_level > 0 && empty0)) - { + if (!empty0 && !STATE_isset(STATE_FENCED_CODEBLOCK) && ! /^( |\t)/) { PNappnd("</code></pre>") STATE_unset(STATE_CODEBLOCK) - emptyP1 = 1 - if (STATE_thenunset(STATE_FENCED_CODEBLOCK)) { - next - } } - else if (!STATE_isset(STATE_BLOCKQUOTE)) { - handle_codeblock() + else { + escape_in_codeblock() soft_next() } } -# Blockquotes -blockquote_level > 0 && empty0 { - STATE_unset(STATE_PARAGRAPH_P1) - for (P1 = P1 ORS; blockquote_level > 0; --blockquote_level) { - P1 = P1 "</blockquote>" - } -} -/^>[ \t]/ { - match($0, /^[> \t]*> /) - level = substr($0, RSTART, RLENGTH) - - $0 = substr($0, RSTART + RLENGTH) - gsub(/[ \t]/, "", level) - level = length(level) - - STATE_set(STATE_BLOCKQUOTE) - for (;blockquote_level < level; ++blockquote_level) { - P1 = P1 "<blockquote>" - } - for (;blockquote_level > level; --blockquote_level) { - P2 = P2 "</blockquote>" - } -} -STATE_isset(STATE_BLOCKQUOTE) && $0 == ">" { $0 = "" } - -# Code block (end) -STATE_isset(STATE_CODEBLOCK) { ## when in blockquote - handle_codeblock() - soft_next() -} - -# Link definition -/^\[[^\]]+\]:[ \t]+.*/ { # line starts link definition +#-- Link definition (ignore) --# +/^\[[^\]]+\]:[ \t]+.*/ { next } -# Escapes +#-- Escapes --# /\\[-\\`*_{}\[\]()#+.!^~]/ { # has escaped char while (match($0, /\\[-\\`*_{}\[\]()#+.!^~]/)) { sub_match(escapes[char($0, RSTART + 1)]) } } -# Horizontal rule -/^(---+|- - -( -)*|\*\*\*+|\* \* \*( \*)*|___+|_ _ _( _)*)$/ { +#-- Horizontal rule --# +/^(---+|- -( -)+|\*\*\*+|\* \*( \*)+|___+|_ _( _)+)$/ { STATE_unset(STATE_PARAGRAPH) $0 = "<hr/>" } -# Lists -function end_list() { - STATE_unset(STATE_LIST) +#-- Lists --# +/^[ \t]*[*+-] / { ## Unordered list + level = level + int(indentation() / 2) - if (list_level == 0) return - PNappnd("</li></" (lists[list_level] == "." ? "o" : "u") "l>") - --list_level + match($0, /^[ \t]*[*+-] /) + type = char($0, RSTART + RLENGTH - 2) + shift = RLENGTH + sub_match("") + + start_list(level, type, shift) + level = 0 } +/^[ \t]*[0-9]+\. / { ## Ordered list + level = level + int(indentation() / 2) + + type = "." + match($0, /^[^.]+\. /) + shift = RLENGTH + sub_match("") + + start_list(level, type, shift) + level = 0 +} +level > 0 && list_level > 0 && !is_blank() && emptyP1 { ## Non-list line + while (list_level >= level) { + end_list() + } +} +list_level > 0 { + STATE_unset(STATE_PARAGRAPH) +} + function start_list(level, type, shift) { STATE_set(STATE_LIST) - brand_new = TRUE ## Every two columns we define a new level level = int((level + 2) / 2) - ## If list definition is the first line inside a code block - if (level - list_level >= 3) return ## Make list_level = level - 1 while (list_level < level - 1) { @@ -197,85 +219,55 @@ function start_list(level, type, shift) { P1 = P1 ORS "<li>" } } -/^[ \t]*[*+-] / { ## Unordered list - level = indentation() - - match($0, /^[^*+-]*[*+-] /) - type = char($0, RSTART + RLENGTH - 2) - shift = RLENGTH - sub_match("") - - start_list(level, type, shift) -} -/^[ \t]*[0-9]+\. / { ## Ordered list - level = indentation() - - type = "." - match($0, /^[^.]+\. /) - shift = RLENGTH - sub_match("") - - start_list(level, type, shift) -} -!brand_new && list_level > 0 && /[^ \t]/ { ## Non-list line - level = int((indentation() + 2) / 2) - sub("^[ \t]{1," lists_shift[list_level] "}", "") +function end_list() { + STATE_unset(STATE_LIST) - while (list_level >= level && emptyP1) { - end_list() - } -} -list_level > 0 { - STATE_unset(STATE_PARAGRAPH) - brand_new = FALSE + if (list_level == 0) return + PNappnd("</li></" (lists[list_level] == "." ? "o" : "u") "l>") + --list_level } -# Checklists -STATE_isset(STATE_LIST) && /^\[[x ]\][ \t]/ { +#-- Checklists --# +STATE_isset(STATE_LIST) && level == 0 && /^\[[x ]\][ \t]/ { checked = (char($0, 2) == "x") ? " checked=\"checked\"" : ""; $0 = "<input type=\"checkbox\" disabled=\"disabled\"" checked \ "><label>" substr($0, 5) "</label>" } -# Fenced code blocks +#-- Fenced code blocks (new) --# /^[ \t]*```/ { STATE_set(STATE_FENCED_CODEBLOCK) STATE_set(STATE_CODEBLOCK) match(P1, /```[^ \t]*/) if (RLENGTH > 3) { - fenced_class = " class=\"language-" tolower(substr(P1, RSTART + 3, RLENGTH - 3)) "\"" + fenced_start = " class=\"language-" tolower(substr(P1, RSTART + 3, RLENGTH - 3)) "\"" } else { - fenced_class = "" + fenced_start = "" } - fenced_class = "<pre><code" fenced_class ">" + fenced_start = "<pre><code" fenced_start ">" next } -# Code blocks -function handle_codeblock() { - ## Autoescape & and < +#-- Code blocks (new) --# +/^( |\t)/ && /[^ \t]/ { + STATE_set(STATE_CODEBLOCK) + escape_in_codeblock() + $0 = "<pre><code>" $0 + soft_next() +} +function escape_in_codeblock() { for (i = 1; match(substr($0, i), /&/); i += RSTART) { RSTART += i - 1 sub_match("&") } gsub(/</, "\\<") gsub(/>/, "\\>") - - if (STATE_isset(STATE_FENCED_CODEBLOCK)) { - $0 = substr($0, 5) - } -} -/^( |\t)/ && /[^ \t]/ { ## New codeblock - STATE_set(STATE_CODEBLOCK) - handle_codeblock() - $0 = "<pre><code>" $0 - soft_next() } -# Definition lists +#-- Definition lists --# STATE_isset(STATE_DEFINITION_LIST) { if (!empty0) { STATE_unset(STATE_PARAGRAPH) @@ -319,7 +311,20 @@ STATE_isset(STATE_DEFINITION_LIST) { #== Inline markup ==# -# Automatic links +#-- Autoescape & --# +/&/ { + for (i = 1; match(substr($0, i), /&/); i += RSTART) { + RSTART += i - 1 + if (substr($0, RSTART) ~ /&[A-Za-z0-9#]+;/) { continue } + sub_match("&") + } +} +#-- Autoescape < --# +/ < / { + gsub(/ < /, "\\<") +} + +#-- Automatic links --# /<[^ \t<>]+>/ { ## URL: <uri_scheme:...> while (match($0, /<[A-Za-z][-A-Za-z0-9+.]*:[^ \t<>]+>/)) { @@ -343,25 +348,12 @@ STATE_isset(STATE_DEFINITION_LIST) { } } -# Autoescape & -/&/ { - for (i = 1; match(substr($0, i), /&/); i += RSTART) { - RSTART += i - 1 - if (substr($0, RSTART) ~ /&[A-Za-z0-9#]+;/) { continue } - sub_match("&") - } -} -# Autoescape < -/ < / { - gsub(/ < /, "\\<") -} - -# Line break +#-- Line break --# / $/ { sub(/[ \t]* $/, "</br>") } -# atx-style headers +#-- atx-style headers --# /^[ \t]*#+/ { match($0, /#+/) if (RLENGTH <= 6) { @@ -374,7 +366,7 @@ STATE_isset(STATE_DEFINITION_LIST) { } } -# setex-style headers +#-- setex-style headers --# !emptyP1 && /^[ \t]*(=|-)+[ \t]*$/ { hlevel = 1 + ($0 ~ /-/) P1 = "<h" hlevel ">" substr(P1, 4) "</h" hlevel ">" @@ -382,7 +374,25 @@ STATE_isset(STATE_DEFINITION_LIST) { STATE_unset(STATE_PARAGRAPH) } -# Emphasis +#-- Emphasis --# +{ + ## Make sure <em> is on the inside for long chains + ## E.g. *****a***** will be the same as ****_a_**** + surround("___" , "<strong><em>", "</em></strong>") + surround("\\*\\*\\*", "<strong><em>", "</em></strong>", 3) + + gsurround("__" , "<strong>", "</strong>") + gsurround("_" , "<em>" , "</em>") + gsurround("\\*\\*", "<strong>", "</strong>", 2) + gsurround("\\*" , "<em>" , "</em>", 1) + gsurround("``" , "<code>" , "</code>") + gsurround("`" , "<code>" , "</code>") + + gsurround("~~" , "<s>" , "</s>") + gsurround("~" , "<sub>" , "</sub>") + gsurround("\\^", "<sup>" , "</sup>", 1) +} + function surround(brace, left, right, blen) { if (blen == "") { blen = length(brace) } if (match($0, brace (brace == "``" ? "." : "[^" brace "]") "+" brace)) { @@ -405,31 +415,13 @@ function gsurround(brace, left, right, blen) { } } -{ - ## Make sure <em> is on the inside for long chains - ## E.g. *****a***** will be the same as ****_a_**** - surround("___" , "<strong><em>", "</em></strong>") - surround("\\*\\*\\*", "<strong><em>", "</em></strong>", 3) - - gsurround("__" , "<strong>", "</strong>") - gsurround("_" , "<em>" , "</em>") - gsurround("\\*\\*", "<strong>", "</strong>", 2) - gsurround("\\*" , "<em>" , "</em>", 1) - gsurround("``" , "<code>" , "</code>") - gsurround("`" , "<code>" , "</code>") - - gsurround("~~" , "<s>" , "</s>") - gsurround("~" , "<sub>" , "</sub>") - gsurround("\\^", "<sup>" , "</sup>", 1) -} - -# Footnote references +#-- Footnote references --# /\[\^[^\]]+\]/ { while (match($0, /\[\^[\]]+\]/)) { } } -# Links +#-- Links --# /!?\[[^\]]*\] ?[(\[][^)\]]*[\])]/ { while (match($0, /!?\[[^\]]*\] ?[(\[][^)\]]*[\])]/)) { link = substr($0, RSTART, RLENGTH) @@ -468,11 +460,11 @@ function gsurround(brace, left, right, blen) { } } -# Paragraph +#-- Paragraph --# emptyP1 && !empty0 && STATE_isset(STATE_PARAGRAPH) { $0 = "<p>" $0 } !emptyP1 && empty0 && STATE_isset(STATE_PARAGRAPH_P1) { P1 = P1 "</p>" } -# After all $0 parsing +#== Buffered printing ==# { __buffered_print() } @@ -538,6 +530,7 @@ END { } #== Boolean "constants" ==# + BEGIN { FALSE = 0 TRUE = 1 @@ -599,17 +592,25 @@ function indentation( len) { return len } +function is_blank() { + return ! /[^ \t]/ +} + #== Match handling ==# function save_match() { backup_rstart = RSTART backup_rlength = RLENGTH } + function restore_match() { RSTART = backup_rstart RLENGTH = backup_rlength } +function sub_match(replacement) { + $0 = substr($0, 1, RSTART - 1) replacement substr($0, RSTART + RLENGTH) +} #== Other ==# @@ -629,14 +630,9 @@ function soft_next() { next } -function sub_match(replacement) { - $0 = substr($0, 1, RSTART - 1) replacement substr($0, RSTART + RLENGTH) -} - function char(string, ind) { if (1 > ind || ind > length(string)) { return ""; } return substr(string, ind, 1) } - |
