Summary Files Commits Branches @commit @diff @stats
path: root / md-parser.awk
diff options
context:
space:
mode:
Commit82bf8b0ae8efe6fa51e24fb75c4bb9af06a1416e (patch)
Author
 Syndamia <kamen@syndamia.com>
2025-03-03 10:22:59 +0200
Committer
 Syndamia <kamen@syndamia.com>
2025-03-03 10:24:47 +0200
Files5ab7d5d8555be9c13714321827d592d8f2ef35b4 /md-parser.awk
csg-82bf8b0ae8efe6fa51e24fb75c4bb9af06a1416e.tar
csg-82bf8b0ae8efe6fa51e24fb75c4bb9af06a1416e.tar.gz
csg-82bf8b0ae8efe6fa51e24fb75c4bb9af06a1416e.zip
Parent828ef67391a1a4b4d6d0fc7e466d4678c5decc0d (diff)
chore(parser): Add documentation comments
1 files changed, 111 insertions, 30 deletions
-rw-r--r--md-parser.awk141
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("&amp;")
}
@@ -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 "";