diff options
| Commit | 82bf8b0ae8efe6fa51e24fb75c4bb9af06a1416e (patch) | |
|---|---|---|
| Author | 2025-03-03 10:22:59 +0200 | |
| Committer | 2025-03-03 10:24:47 +0200 | |
| Files | 5ab7d5d8555be9c13714321827d592d8f2ef35b4 /md-parser.awk | |
| csg-82bf8b0ae8efe6fa51e24fb75c4bb9af06a1416e.tar csg-82bf8b0ae8efe6fa51e24fb75c4bb9af06a1416e.tar.gz csg-82bf8b0ae8efe6fa51e24fb75c4bb9af06a1416e.zip | ||
| Parent | 828ef67391a1a4b4d6d0fc7e466d4678c5decc0d (diff) | |
chore(parser): Add documentation comments
1 files changed, 111 insertions, 30 deletions
| -rw-r--r-- | md-parser.awk | 141 |
diff --git a/md-parser.awk b/md-parser.awk index 2161482..970d2bc 100644 --- a/md-parser.awk +++ b/md-parser.awk @@ -53,17 +53,12 @@ BEGIN { emptyP1 = empty(P1) } -# Output is buffered on multiple lines, held in these variables: -# P2 = last non-empty line before the previous line -# P1 = previous line -# $0 = current line -# N1 = next new line (N1 is always set by the user) - #== Block markup ==# #-- Blockquotes --# blockquote_level > 0 && empty0 { STATE_unset(STATE_PARAGRAPH_P1) + ## Blockquote end also ends codeblock if (STATE_thenunset(STATE_CODEBLOCK)) { PNappnd("</code></pre>") } @@ -74,6 +69,8 @@ blockquote_level > 0 && empty0 { /^>[ \t]/ { STATE_set(STATE_BLOCKQUOTE) + ## blevel is the amount of ">" in the beginning of the line + ## We also remove the leading ">...> " part match($0, /^[> \t]*> /) blevel = substr($0, RSTART, RLENGTH) @@ -115,11 +112,14 @@ STATE_isset(STATE_HTML) { #-- Fenced code blocks --# STATE_isset(STATE_FENCED_CODEBLOCK) { + ## We need to add <pre><code> to the start of the first line inside the fence + ## so we don't introduce leading newlines if (fenced_start) { $0 = fenced_start $0 fenced_start = "" soft_next() } + if (/^```/) { PNappnd("</code></pre>") STATE_unset(STATE_CODEBLOCK) @@ -190,35 +190,49 @@ list_level > 0 { STATE_unset(STATE_PARAGRAPH) } +# start_list(level, type, shift) +# +# Adds a new list or list item, even when that requires closing other lists. Updates lists and list_level. +# +# level - indentation integer +# type - one of ".", "o", "u" +# shift - where does the list contents start indent-wise function start_list(level, type, shift) { STATE_set(STATE_LIST) ## Every two columns we define a new level level = int((level + 2) / 2) - ## Make list_level = level - 1 - while (list_level < level - 1) { - lists[++list_level] = "" + ## When new level is much more indented than current + if (list_level < level - 1) { + list_level = level - 1 } - ## Make list_level = level + ## When new level is less indented than current while (list_level > level) { end_list() } - + ## When list type was changed on the same level if (list_level == level && lists[list_level] != type) { end_list() } + + ## Create a new list if (list_level < level || lists[list_level] != type) { P1 = P1 ORS "<" (type == "." ? "o" : "u") "l><li>" lists[level] = type lists_shift[level] = shift list_level = level } + ## Create a new list item else { PNappnd("</li>") P1 = P1 ORS "<li>" } } + +# end_list() +# +# Closes a list. Also unsets STATE_LIST and decrements list_level. function end_list() { STATE_unset(STATE_LIST) @@ -240,12 +254,10 @@ STATE_isset(STATE_LIST) && level == 0 && /^\[[x ]\][ \t]/ { STATE_set(STATE_CODEBLOCK) match(P1, /```[^ \t]*/) + fenced_start = "" if (RLENGTH > 3) { fenced_start = " class=\"language-" tolower(substr(P1, RSTART + 3, RLENGTH - 3)) "\"" } - else { - fenced_start = "" - } fenced_start = "<pre><code" fenced_start ">" next @@ -258,6 +270,10 @@ STATE_isset(STATE_LIST) && level == 0 && /^\[[x ]\][ \t]/ { $0 = "<pre><code>" $0 soft_next() } + +# escape_in_codeblock() +# +# Escape &, < and > with the appropriate HTML entities. Meant to be used with codeblocks. function escape_in_codeblock() { for (i = 1; match(substr($0, i), /&/); i += RSTART) { RSTART += i - 1 @@ -278,7 +294,8 @@ STATE_isset(STATE_DEFINITION_LIST) { if ((!empty0 && emptyP1 && /^: /) || ( empty0 && !emptyP1 && !def_started && P1 !~ /^<dd>/) || - (!empty0 && !emptyP1 && !def_started && !/^: /)) { + (!empty0 && !emptyP1 && !def_started && !/^: /)) + { STATE_unset(STATE_DEFINITION_LIST) P2 = P2 "</dl>" @@ -315,6 +332,7 @@ STATE_isset(STATE_DEFINITION_LIST) { /&/ { for (i = 1; match(substr($0, i), /&/); i += RSTART) { RSTART += i - 1 + ## Don't escape HTML entities if (substr($0, RSTART) ~ /&[A-Za-z0-9#]+;/) { continue } sub_match("&") } @@ -393,6 +411,11 @@ STATE_isset(STATE_DEFINITION_LIST) { gsurround("\\^", "<sup>" , "</sup>", 1) } +# surround(brace, left, right [, blen]) +# +# Substitute the shortest leftmost "brace ... brace" with "left ... right". +# +# Since brace is used in a regex, you'll need to escape special characters. In such cases, you need to set blen (brace length) to the count of "real" characters. function surround(brace, left, right, blen) { if (blen == "") { blen = length(brace) } if (match($0, brace (brace == "``" ? "." : "[^" brace "]") "+" brace)) { @@ -403,6 +426,10 @@ function surround(brace, left, right, blen) { } return 0 } + +# gsurround(brace, left, right [, blen]) +# +# Same as surround, however it substitutes all non-overlapping occurrences. function gsurround(brace, left, right, blen) { while (surround(brace, left, right, blen)) {} @@ -465,6 +492,12 @@ emptyP1 && !empty0 && STATE_isset(STATE_PARAGRAPH) { $0 = "<p>" $0 } !emptyP1 && empty0 && STATE_isset(STATE_PARAGRAPH_P1) { P1 = P1 "</p>" } #== Buffered printing ==# +# Output is buffered on multiple lines, held in these variables: +# P2 = last non-empty line before the previous line +# P1 = previous line +# $0 = current line +# N1 = next new line (N1 is always set by the user) + { __buffered_print() } @@ -529,6 +562,24 @@ END { if (!empty(N1)) { print N1 } } +# PNappnd(value) +# +# Append value to the previous non-empty line. If P1 is empty, then it's P2, otherwise P1. +function PNappnd(value) { + if (emptyP1) P2 = P2 ORS value + else P1 = P1 ORS value +} + +# soft_next() +# +# Print buffered and then do next. +function soft_next() { + __buffered_print() + + STATE_unset(STATE_PARAGRAPH) + next +} + #== Boolean "constants" ==# BEGIN { @@ -553,19 +604,39 @@ BEGIN { STATE_LIST = 6 STATE_DEFINITION_LIST = 7 } + +# STATE_set(name) +# +# Set the state to TRUE function STATE_set(name) { STATE_unset(STATE_PARAGRAPH) __state[name] = TRUE } -function STATE_assign(name, other) { - __state[name] = __state[other] -} + +# STATE_unset(name) +# +# Set the state to FALSE function STATE_unset(name) { __state[name] = FALSE } + +# STATE_assign(name, other) +# +# Set the value of the first state to the value of the second state. +function STATE_assign(name, other) { + __state[name] = __state[other] +} + +# STATE_isset(name) +# +# Return boolean function STATE_isset(name) { return __state[name] } + +# STATE_thenset(name) +# +# If the state is not set, set it and return TRUE. Otherwise return FALSE. function STATE_thenset(name) { if (!__state[name]) { STATE_set(name) @@ -573,6 +644,10 @@ function STATE_thenset(name) { } return FALSE } + +# STATE_thenunset(name) +# +# If the state is set, unset it and return TRUE. Otherwise return FALSE. function STATE_thenunset(name) { if (__state[name]) { STATE_unset(STATE_PARAGRAPH) @@ -584,6 +659,9 @@ function STATE_thenunset(name) { #== Line information ==# +# indentation() +# +# Return the cound of leading blank characters in $0. function indentation( len) { save_match() match($0, /^[ \t]*/) @@ -592,22 +670,34 @@ function indentation( len) { return len } +# is_blank() +# +# Wether $0 contains only blank characters. function is_blank() { return ! /[^ \t]/ } #== Match handling ==# +# save_match() +# +# Backup RSTART and RLENGTH function save_match() { backup_rstart = RSTART backup_rlength = RLENGTH } +# restore_match() +# +# Restore RSTART and RLENGTH, from save_match's backup. function restore_match() { RSTART = backup_rstart RLENGTH = backup_rlength } +# sub_match(replacement) +# +# Replace the range, specified by RSTART and RLENGTH (from match function) with the given replacement. Replacement is not a regex. function sub_match(replacement) { $0 = substr($0, 1, RSTART - 1) replacement substr($0, RSTART + RLENGTH) } @@ -618,18 +708,9 @@ function empty(value) { return value == "" } -function PNappnd(value) { - if (emptyP1) P2 = P2 ORS value - else P1 = P1 ORS value -} - -function soft_next() { - __buffered_print() - - STATE_unset(STATE_PARAGRAPH) - next -} - +# char(string, ind) +# +# Return a single-character string, which is found at the given index. If the index is invalid, a blank string is returned. function char(string, ind) { if (1 > ind || ind > length(string)) { return ""; |
