From 4f62597d55ef4d85ffb08a4152c39985901b8707 Mon Sep 17 00:00:00 2001
From: =?utf8?q?Paul=20H=C3=A4nsch?= ";
@@ -345,8 +322,7 @@ function inline( line, LOCAL, len, text, code, href, guard, ret ) {
continue;
# Literal HTML entities
- # } else if ( match( line, /^&([a-zA-Z]{2,32}|#[0-9]{1,7}|#[xX][0-9a-fA-F]{1,6});/) ) {
- # mawk does not support repitition ranges
+ # mawk does not support repitition ranges (i.e. "xyz{1,10}")
} else if ( match( line, /^&[a-zA-Z][a-zA-Z][a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?;/) ) {
len = RLENGTH;
ret = ret substr( line, 1, len ); line = substr(line, len + 1);
@@ -360,6 +336,9 @@ function inline( line, LOCAL, len, text, code, href, guard, ret ) {
} else if ( line ~ /^-->( |$)/) { # ignore multidash-arrow
ret = ret "-->"; line = substr(line, 4);
continue;
+ } else if ( line ~ /^<->( |$)/) {
+ ret = ret "↔"; line = substr(line, 4);
+ continue;
} else if ( line ~ /^<-( |$)/) {
ret = ret "←"; line = substr(line, 3);
continue;
@@ -380,8 +359,7 @@ function inline( line, LOCAL, len, text, code, href, guard, ret ) {
return ret;
}
-function headline( hlvl, htxt, attrib, LOCAL, sec, n, HL) {
- # match(hstack, /([0-9]+( [0-9]+){5})$/); split( substr(hstack, RSTART), HL);
+function headline( hlvl, htxt, attrib, LOCAL, sec, n, hid, HL) {
match(hstack, /([0-9]+( [0-9]+)( [0-9]+)( [0-9]+)( [0-9]+)( [0-9]+))$/); split( substr(hstack, RSTART), HL);
for ( n = hlvl; n <= 6; n++ ) { sec = sec (HL[n]?"":""); }
@@ -389,15 +367,14 @@ function headline( hlvl, htxt, attrib, LOCAL, sec, n, HL) {
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);
+ hid = hid ":" HTML(htxt); # anchor for TOC and permalink
- # sub(/([0-9]+( [0-9]+){5})$/, "", hstack);
sub(/([0-9]+( [0-9]+)( [0-9]+)( [0-9]+)( [0-9]+)( [0-9]+))$/, "", hstack);
hstack = hstack HL[1] " " HL[2] " " HL[3] " " HL[4] " " HL[5] " " HL[6];
return sec "
\n";
+ ret = ret "" HTML( substr(code, 1, st - 1) ) "
\n";
block = substr( code, st + len );
continue;
@@ -675,11 +648,10 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
}
# First Order Heading H1 + Attrib
- } else if ( match( block, /^([^\n]+)([ \t]*\{([^\}\n]+)\})\n===+(\n|$)/ ) ) {
+ } else if ( match( block, "^([^\n]+)([ \t]*"rattr")\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);
+ attrib = _attr(attrib);
ret = ret headline(1, text, attrib) ; block = substr( block, len + 1 );
continue;
@@ -693,11 +665,10 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
continue;
# Second Order Heading H2 + Attrib
- } else if ( match( block, /^([^\n]+)([ \t]*\{([^\}\n]+)\})\n---+(\n|$)/ ) ) {
+ } else if ( match( block, "^([^\n]+)([ \t]*"rattr")\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);
+ attrib = _attr(attrib);
ret = ret headline(2, text, attrib) ; block = substr( block, len + 1);
continue;
@@ -711,27 +682,21 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
continue;
# # Nth Order Heading H1 H2 H3 H4 H5 H6 + Attrib
- # } else if ( match( block, /^(##?#?#?#?#?)[ \t]*(([^ \t\n]+|[ \t]+[^ \t\n#]|[ \t]+#+[ \t]*[^ \t\n#])+)[ \t]*#*[ \t]*\{[a-zA-Z \t-]*\}(\n|$)/ ) ) {
- } else if ( match( block, /^##?#?#?#?#?[^#\n]([^\n#]|#[^\t\n# ]|#[\t ]+[^\t\n ])+#*[\t ]*\{[\ta-zA-Z -]*\}(\n|$)/ ) ) {
+ } else if ( match( block, "^##?#?#?#?#?[^#\n]([^\n#]|#[^\t\n# ]|#[\t ]+[^\t\n ])+#*[\t ]*"rattr"(\n|$)" ) ) {
len = RLENGTH; text = attrib = substr(block, 1, len);
match(block, /^##?#?#?#?#?[^#]/); n = RLENGTH - 1;
- # sub(/^(##?#?#?#?#?)[ \t]*/, "", text); # not working in mawk
text = substr(text, n + 1); sub(/^[ \t]*/, "", text);
sub(/[ \t]*#*([ \t]*\{([a-zA-Z \t-]*)\})(\n.*)?$/, "", text);
- sub(/^##?#?#?#?#?[^#\n]([^\n#]|#[^\t\n# ]|#[\t ]+[^\t\n ])+#*[\t ]*\{/, "", attrib);
- sub(/\}(\n.*)?$/, "", attrib);
- gsub(/[^a-zA-Z0-9_-]+/, " ", attrib); gsub(/(^ | $)/, "", attrib);
+ attrib = _attr(attrib);
ret = ret headline( n, text, attrib ); block = substr( block, len + 1);
continue;
# Nth Order Heading H1 H2 H3 H4 H5 H6
- # } else if ( match( block, /^(##?#?#?#?#?)[ \t]*(([^ \t\n]+|[ \t]+[^ \t\n#]|[ \t]+#+[ \t]*[^ \t\n#])+)[ \t]*#*(\n|$)/ ) ) {
} else if ( match( block, /^##?#?#?#?#?[^#\n]([^\n#]|#[^\t\n# ]|#[\t ]+[^\t\n ])+#*(\n|$)/ ) ) {
len = RLENGTH; text = substr(block, 1, len);
match(block, /^##?#?#?#?#?[^#]/); n = RLENGTH - 1;
- # sub(/^(##?#?#?#?#?)[ \t]+/, "", text); # not working in mawk
text = substr(text, n + 1); sub(/^[ \t]*/, "", text);
sub(/[ \t]*#*(\n.*)?$/, "", text);
@@ -739,7 +704,7 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
continue;
# block images (wrapped in " \
+ HTML( substr(code, 1, st - 1) ) "" HTML(text) "" ; block = substr(block, len + 1);
continue;
@@ -844,7 +804,6 @@ function _block( block, LOCAL, st, len, text, title, attrib, href, guard, code,
continue;
# Horizontal rule
- # } else if ( match( block, /(^|\n) ? ? ?((\* *){3,}|(- *){3,}|(_ *){3,})($|\n)/) ) {
} else if ( match( block, /(^|\n) ? ? ?((\* *)(\* *)(\* *)(\* *)*|(- *)(- *)(- *)(- *)*|(_ *)(_ *)(_ *)(_ *)*)($|\n)/) ) {
len = RLENGTH; st = RSTART;
ret = ret _block(substr(block, 1, st - 1)) "
\n"; block = substr(block, st + len);
@@ -866,7 +825,6 @@ function _startlist(block, type, mark, exclude, LOCAL, st, len, list, indent, it
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);
# emulate greedy range matcher for mawk
it = "("; while ( indent > 0 ) { for (k = indent; k > 0; k--) { it = it " "; } it = it "|"; indent--; }
sub(/\|$/, ")?", it); sub(/^\($/, "", it);
@@ -897,7 +855,6 @@ function _list (block, mark, p, LOCAL, len, st, text, indent, it, task) {
st = (RLENGTH == -1) ? length(block) + 1 : RSTART;
text = substr(block, 1, st); block = substr(block, st + 1);
- # gsub("\n {0," indent "}", "\n", text);
# emulate greedy range matcher for mawk
it = "("; while ( indent > 0 ) { for (k = indent; k > 0; k--) { it = it " "; } it = it "|"; indent--; }
sub(/\|$/, ")?", it); sub(/^\($/, "", it);
@@ -931,7 +888,6 @@ function _dlist (block, LOCAL, len, st, text, indent, it, p) {
sub( "^([ \t]*\n)*", "", text);
match(text, "^ ? ? ?:(\t| +)"); indent = RLENGTH;
sub( "^ ? ? ?:(\t| +)", "", text);
- # gsub( "(^|\n) {0," indent "}", "\n", text );
# emulate greedy range matcher for mawk
it = "("; while ( indent > 0 ) { for (k = indent; k > 0; k--) { it = it " "; } it = it "|"; indent--; }
sub(/\|$/, ")?", it); sub(/^\($/, "", it);
@@ -945,12 +901,18 @@ function _dlist (block, LOCAL, len, st, text, indent, it, p) {
}
}
+function _attr (attrib) {
+ if ( sub(/.*\{[ \t.#]*/, "", attrib) ) if ( sub(/[ \t]*\}(\n.*)?$/, "", attrib) ) {
+ gsub(/[ \t.#]+/, " ", attrib);
+ return attrib;
+ } else return "";
+}
+
BEGIN {
# Global Vars
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";
# Universal Patterns
nu = "([^_\\\\]|\\\\.|_[[:alnum:]])" # not underline (except when escaped, or inside a word)
@@ -960,6 +922,8 @@ BEGIN {
iea = "\\*([^*[:space:]]|[^*[:space:]]" na "*[^*[:space:]])\\*" # inner (asterisk)
isa = "\\*\\*([^*[:space:]]|[^*[:space:]]" na "*[^*[:space:]])\\*\\*" # inner (asterisk)
+ rattr = "\\{[ \t]*([.#]?([a-zA-Z0-9]+-)*[a-zA-Z0-9]+[ \t]+)*([.#]?([a-zA-Z0-9]+-)*[a-zA-Z0-9]+)[ \t]*\\}"
+
lix="\\[(\\\\[^\n]|[^]\n\\\\[])*\\]" # link text
lid="(<(\\\\[^\n]|[^\n<>\\\\])*>|(\\\\.|[^()\"'\\\\])+|([^<\n\t ()\\\\]|\\\\[^\n])(\\\\[\n]|[^\n\t \\(\\)\\\\])*)" # link dest
lit="(\"(\\\\.|[^\"\\\\])*\"|'(\\\\.|[^'\\\\])*'|\\((\\\\.|[^\\(\\)\\\\])*\\))" # link text
@@ -974,7 +938,6 @@ BEGIN {
# Fill array of reference links
f = file; rl_id;
re_reflink = "(^|\n) ? ? ?\\[([^]\n]+)\\]: ([^ \t\n]+)(\n?[ \t]+(\"([^\"]+)\"|'([^']+)'|\\(([^)]+)\\)))?(\n|$)";
- # /(^|\n) ? ? ?\[([^]\n]+)\]: ([^ \t\n]+)(\n?[ \t]+("([^"]+)"|'([^']+)'|\(([^)]+)\)))?(\n|$)/
while ( match(f, re_reflink ) ) {
tt = th = ti = substr(f, RSTART, RLENGTH); f = substr(f, RSTART + RLENGTH);
sub("(^|\n) ? ? ?\\[", "", ti); sub("\\]: ([^ \t\n]+)(\n?[ \t]+(\"([^\"]+)\"|'([^']+)'|\\(([^)]+)\\)))?(\n.*)?$", "", ti);
@@ -983,16 +946,11 @@ BEGIN {
sub("(^|\n) ? ? ?\\[([^]\n]+)\\]: ([^ \t\n]+)", "", tt); sub("^\n?[ \t]+", "", tt); sub("(\n.*)?$", "", tt);
} else { tt = ""; }
rl_id = ti; rl_href[rl_id] = th; rl_title[rl_id] = tt;
- # rl_id = gensub( re_reflink, "\\2", 1, substr(f, RSTART, RLENGTH) );
- # rl_href[rl_id] = gensub( re_reflink, "\\3", 1, substr(f, RSTART, RLENGTH) );
- # rl_title[rl_id] = gensub( re_reflink, "\\5", 1, substr(f, RSTART, RLENGTH) );
- # f = substr(f, RSTART + RLENGTH);
rl_title[rl_id] = substr( rl_title[rl_id], 2, length(rl_title[rl_id]) - 2 );
if ( rl_href[rl_id] ~ /<.*>/ ) rl_href[rl_id] = substr( rl_href[rl_id], 2, length(rl_href[rl_id]) - 2 );
}
# Clear reflinks from File
while( gsub(re_reflink, "\n", file ) );
- # for (n in rl_href) { debug(n " | " rl_href[n] " | " rl_title[n] ); }
# Run Block Processing -> The Actual Markdown!
printf "%s", _nblock( file );
diff --git a/tests-markdown.sh b/tests-markdown.sh
index 6df4224..3794321 100755
--- a/tests-markdown.sh
+++ b/tests-markdown.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-runtimes="gawk busybox mawk goawk"
+runtimes="${runtimes:-gawk busybox mawk goawk}"
BR='
'
@@ -93,7 +93,7 @@ assert '[Wikipedia](



fenced code will
+'
' \
@@ -219,45 +219,45 @@ assert '{tv ard function-check}' \
# Headings
assert 'Heading first Order
============' \
-'fenced code will
not be
*formatted*
but ­ <escaped>Heading first Order
+'Heading first Order
Fenced Code Block
+Fenced Code Block
# with verbatim Text
`and an attribute`
The limerick packs laughs anatomical
@@ -963,7 +963,7 @@ For additional examples, regarding permanent installation and configuration in w
Syntax
------
-The wiki syntax is based on John Grubers [Markdown](https://daringfireball.net/projects/markdown/) with extensions borrowed from [Pandoc](https://pandoc.org/MANUAL%202.html#pandocs-markdown) and [PHP Markdown Extra](https://michelf.ca/projects/php-markdown/extra/). The Markdown parser is provided by [Cgilite](/software/cgilite/) and its full documentation can be looked at [here](/software/cgilite/markdown/).
+The wiki syntax is based on John Grubers [Markdown](https://daringfireball.net/projects/markdown/) with extensions borrowed from [Pandoc](https://pandoc.org/MANUAL 2.html#pandocs-markdown) and [PHP Markdown Extra](https://michelf.ca/projects/php-markdown/extra/). The Markdown parser is provided by [Cgilite](/software/cgilite/) and its full documentation can be looked at [here](/software/cgilite/markdown/).
< >
@@ -1017,7 +1017,7 @@ How to write:
- [Macros](dev-macros/)
- [Handlers](dev-handlers/)
- [Parsers](dev-parsers/)' \
-'Shellwiki
+'Shellwiki
Shellwiki is a Wiki and Content Management System with minimal dependencies. It can run on embedded devices, as well as full size web servers. Its goals are:
easy deployment
@@ -1054,7 +1054,7 @@ interface. It aims to be secure and predictable. Extensions can
be written and modified by system administrators.
-toc 2 2Features
+toc 2 2Features
Markdown Wiki Syntax
@@ -1149,7 +1149,7 @@ visitors into handling GDPR "consent" forms.
-Dependencies
+Dependencies
Shellwiki is based on cgilite, which is included in the installation. It is written in posix compliant shell script, and the markdown renderer is written in posix compliant AWK. The entire wiki system can run with nothing more than a busybox. In fact it can be served from the rescue shell in a Debian initrd, or from an OpenWRT router.
Its precise requirements are:
@@ -1172,7 +1172,7 @@ visitors into handling GDPR "consent" forms.
Optional: Sendmail for sending password reminders, etc.
-Installation
+Installation
Also see → installation/
You can try out shellwiki right now using busybox:
@@ -1181,10 +1181,10 @@ visitors into handling GDPR "consent" forms.
~$ _DATA=~/wikidata busybox nc -llp 1080 -e ~/shellwiki/index.cgi
For additional examples, regarding permanent installation and configuration in webservers see installation/.
-Syntax
-The wiki syntax is based on John Grubers Markdown with extensions borrowed from Pandoc and PHP Markdown Extra. The Markdown parser is provided by Cgilite and its full documentation can be looked at here.
+Syntax
+The wiki syntax is based on John Grubers Markdown with extensions borrowed from Pandoc and PHP Markdown Extra. The Markdown parser is provided by Cgilite and its full documentation can be looked at here.
-include --nolink /[wiki]/editorhelp/Macros
+include --nolink /[wiki]/editorhelp/Macros
Also see → macros/
In addition to the Markdown syntax, wiki pages can include Macros, which perform additional functions on a page, like generating an image gallery, including parts of other pages, etc. Macros make Shellwiki truly dynamic and flexible.
@@ -1196,14 +1196,14 @@ visitors into handling GDPR "consent" forms.
Macros are the most easy to write type of extension. See Macros for a full list of available macros.
-Themes
+Themes
Also see → theming/
While Shellwiki supports plugins for theming, it's apearance can mostly be configured by the user. Pages can be configured to use custom CSS files. In addition page headers and footers are themselves wiki pages which can be modified to add menus, custom logos, links, etc. The same goes for error pages.
For an example, see the technical pages for this wiki.
-Multiple Languages
+Multiple Languages
To enable a multilingual setup you must set a default language in your configuration environment:
export LANGUAGE_DEFAULT=en
@@ -1215,12 +1215,12 @@ visitors into handling GDPR "consent" forms.
Header, footer, and error pages will be included from their respective language version, as will all macro includes, etc. Should a page not exist in a given language, the default page will be displayed instead. However, included elements will still be taken from the respective language version, possibly mixing languages between the selected user language and the default.
-Constraints of the current implementation
+Constraints of the current implementation
- There can be only one default language, with no priority of different fallback languages
- Page URLs can currently not be translated. Doing so would require a model for manually assigning translated page names and would not be trivial to use.
-Developer Documentation
+Developer Documentation
How to write:
- Themes
diff --git a/users.sh b/users.sh
index 32299ff..9dfbdfb 100755
--- a/users.sh
+++ b/users.sh
@@ -490,9 +490,9 @@ w_user_update(){
[form #user_update method=POST
[hidden "uid" "$USER_ID"]
[p .username Logged in as $USER_NAME]
- [input type=password name=oldpw placeholder="Current Passphrase"]
- [input type=password name=pw placeholder="New Passphrase" pattern=".{6,}"]
- [input type=password name=pwconfirm placeholder="Confirm New Passphrase" pattern=".{6,}"]
+ [input type=password name=oldpw autocomplete="current-password" placeholder="Current Passphrase"]
+ [input type=password name=pw autocomplete="new-password" placeholder="New Passphrase" pattern=".{6,}"]
+ [input type=password name=pwconfirm autocomplete="new-password" placeholder="Confirm New Passphrase" pattern=".{6,}"]
[submit "action" "user_update" Update Passphrase]
]
EOF
@@ -512,7 +512,7 @@ w_user_register_sendmail(){ # TRANSLATION
[p We will send an activation mail to your email address.
You can continue the signup process when you click on the
activation link in this email.]
- [input type=email name=email placeholder="Email"]
+ [input type=email name=email autocomplete="email" placeholder="Email"]
[submit "action" "user_register" Sign Up]
]
EOF
@@ -520,9 +520,9 @@ w_user_register_sendmail(){ # TRANSLATION
w_user_register_direct(){ # TRANSLATION
cat <<-EOF
[form #user_register .registername method=POST
- [input name=uname placeholder="Choose Username" tooltip="Your username may contain any character but the @ sign. It must be at least 3 characters long, and it must start with a letter." pattern="^\[\\\\p{L}\]\[\\\\p{L}0-9 -~\]{2,127}$" autocomplete=off]
- [input type=password name=pw placeholder="Choose Passphrase" pattern=".{6,}"]
- [input type=password name=pwconfirm placeholder="Confirm Passphrase" pattern=".{6,}"]
+ [input name=uname autocomplete="username" placeholder="Choose Username" tooltip="Your username may contain any character but the @ sign. It must be at least 3 characters long, and it must start with a letter." pattern="^\[\\\\p{L}\]\[\\\\p{L}0-9 -~\]{2,127}$"]
+ [input type=password name=pw autocomplete="new-password" placeholder="Choose Passphrase" pattern=".{6,}"]
+ [input type=password name=pwconfirm autocomplete="new-password" placeholder="Confirm Passphrase" pattern=".{6,}"]
[submit "action" "user_register" Sign Up]
]
EOF
@@ -548,9 +548,9 @@ w_user_confirm_proceed(){ # TRANSLATION
$([ "$EMAIL" != '\' ] && printf \
'[input disabled=disabled value="%s" placeholder="Email"]' "$(UNSTRING "$EMAIL" |HTML)"
)
- [input name=uname placeholder="Choose Username" tooltip="Your username may contain any character but the @ sign. It must be at least 3 characters long, and it must start with a letter." pattern="^\[\\\\p{L}\]\[\\\\p{L}0-9 -~\]{2,127}$" autocomplete=off]
- [input type=password name=pw placeholder="Choose Passphrase" pattern=".{6,}"]
- [input type=password name=pwconfirm placeholder="Confirm Passphrase" pattern=".{6,}"]
+ [input name=uname autocomplete="username" placeholder="Choose Username" tooltip="Your username may contain any character but the @ sign. It must be at least 3 characters long, and it must start with a letter." pattern="^\[\\\\p{L}\]\[\\\\p{L}0-9 -~\]{2,127}$"]
+ [input type=password name=pw autocomplete="new-password" placeholder="Choose Passphrase" pattern=".{6,}"]
+ [input type=password name=pwconfirm autocomplete="new-password" placeholder="Confirm Passphrase" pattern=".{6,}"]
[submit "action" "user_confirm" Finish Registration]
]
EOF
@@ -637,8 +637,8 @@ w_user_invite(){
w_user_login_logon(){ # TRANSLATION
cat <<-EOF
[form #user_login .login method=POST
- [input name=uname placeholder="Username or Email"]
- [input type=password name=pw placeholder="Passphrase"]
+ [input name=uname autocomplete="username" placeholder="Username or Email"]
+ [input type=password name=pw autocomplete="current-password" placeholder="Passphrase"]
[submit "action" "user_login" Login]
]
EOF
--
2.39.5