Last active
January 13, 2022 09:02
-
-
Save wernsey/eb1525876ca5519822ab48e68207970f to your computer and use it in GitHub Desktop.
Awk script to generate HTML documentation from markdown text in source code comments.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/awk -f | |
# | |
# Purpose: Either converts markdown in code comments | |
# to HTML, or is a poem about Hastur. I forget. | |
# | |
# The comments must have the /** */ pattern. Every line in the comment | |
# must start with a *. Like so: | |
# | |
# /** | |
# * Markdown here... | |
# */ | |
# | |
# Configuration options. You can set these in the BEGIN block below, or | |
# pass them to the script through the `-v` command-line option: | |
# - `Title="My Document Title"` to set the <title/> in the <head/> section of the HTML | |
# - `stylesheet = "style.css"` to use a separate file as style sheet. | |
# - `Theme=n` with n=[1-8] to use one of the predefined color themes. | |
# Default = Theme 1. Theme 0 disables all stylesheets. | |
# - `TopLinks=1` to have links to the top of the doc next to headers. | |
# - `classic_underscore=1` words_with_underscores behave like old markdown where the | |
# underscores in the word counts as emphasis. The default behaviour is to have | |
# `words_like_this` not contain any emphasis. | |
# | |
# I've tested it with Gawk, Nawk and Mawk. | |
# Gawk and Nawk worked without issues, but don't use the -W compat | |
# or -W traditional settings with Gawk. | |
# Mawk v1.3.4 worked correctly but v1.3.3 choked on it. | |
# | |
# Extensions: | |
# - A link like [link text][heading-name] gets replaced with <a href="#heading-name">link text</a> | |
# where heading-name corresponds to one of the headings. | |
# - Insert a Table of Contents by using ![toc]. The Table of Contents is collapsed by default, | |
# use ![toc+] to insert a ToC that is expanded by default; ![toc-] for a collapsed ToC. | |
# - Github-style ``` code blocks supported. | |
# - Github-style ~~strikethrough~~ supported. | |
# - GitHub-style task lists `- [x]` are supported for documenting bugs and todo lists in code. | |
# - A couple of ideas from MultiMarkdown: | |
# - [^footnotes] are supported. | |
# - *[abbr]: Abbreviations are supported. | |
# - Space followed by \ before a newline also forces a line break. | |
# - Default behaviour is to have words_like_this not contain emphasis. | |
# Limitations: | |
# - You can't nest <blockquote>s, and they can't contain nested lists | |
# or pre blocks. You can work around this by using HTML directly. | |
# - It takes some liberties with how inline (particularly block-level) HTML is processed and not | |
# all HTML tags supported. HTML forms and <script/> tags are out. | |
# - Paragraphs in lists differ a bit from other markdowns. Use indented blank lines to get | |
# to insert <br> tags to emulate paragraphs. Blank lines stop the list by inserting the | |
# </ul> or </ol> tags. | |
# | |
# References: | |
# - https://tools.ietf.org/html/rfc7764 | |
# - http://daringfireball.net/projects/markdown/syntax | |
# - https://guides.github.com/features/mastering-markdown/ | |
# - http://fletcher.github.io/MultiMarkdown-4/syntax | |
# - http://spec.commonmark.org | |
# | |
# (c) 2016 Werner Stoop | |
# Copying and distribution of this file, with or without modification, | |
# are permitted in any medium without royalty provided the copyright | |
# notice and this notice are preserved. This file is offered as-is, | |
# without any warranty. | |
BEGIN { | |
# Configuration options | |
if(Title=="") Title = "Documentation"; | |
if(Theme=="") Theme = 1; | |
#TopLinks = 1; | |
#classic_underscore = 1; | |
if(MaxWidth=="") MaxWidth="1080px"; | |
Mode = "none"; ToC = ""; ToCLevel = 1; | |
CSS = init_css(Theme); | |
for(i = 0; i < 128; i++) | |
_ord[sprintf("%c", i)] = i; | |
srand(); | |
} | |
Mode == "none" && /\/\*\*/ { | |
Mode = "p"; | |
gsub(/\/\*/,""); | |
} | |
Mode != "none" && /\*\// { | |
gsub(/\*\/.*$/,""); | |
if(match($0, /^[[:space:]]*\*/)) | |
Out = Out filter(substr($0, RSTART+RLENGTH)); | |
if(Mode == "ul" || Mode == "ol") { | |
while(ListLevel > 1) | |
Buf = Buf "\n</" Open[ListLevel--] ">"; | |
Out = Out tag(Mode, Buf "\n"); | |
} else { | |
Buf = trim(scrub(Buf)); | |
if(Buf) | |
Out = Out tag(Mode, Buf); | |
} | |
Mode = "none"; | |
Buf = ""; | |
} | |
Mode != "none" { | |
gsub(/\r/, "", $0); | |
if(match($0,/[[:graph:]]/) && substr($0,RSTART,1)!="*") | |
next; | |
gsub(/^[[:space:]]*\*/, "", $0); | |
} | |
Mode != "none" && /^[[:space:]]*\[[_ [:alnum:]]+\]:/ { | |
linkdesc = ""; lastlink = 0; | |
match($0,/\[.*\]/); | |
LinkRef = tolower(substr($0, RSTART+1, RLENGTH-2)); | |
st = substr($0, RSTART+RLENGTH+2); | |
match(st, /[^[:space:]]+/); | |
url = substr(st, RSTART, RLENGTH); | |
st = substr(st, RSTART+RLENGTH+1); | |
if(match(url, /^<.*>/)) | |
url = substr(url, RSTART+1, RLENGTH-2); | |
if(match(st, /["'(]/)) { | |
delim = substr(st, RSTART, 1); | |
edelim = (delim == "(") ? ")" : delim; | |
if(match(st, delim ".*" edelim)) | |
linkdesc = substr(st, RSTART+1, RLENGTH-2); | |
} | |
LinkUrls[LinkRef] = escape(url); | |
if(!linkdesc) lastlink = 1; | |
LinkDescs[LinkRef] = escape(linkdesc); | |
next; | |
} | |
Mode != "none" && lastlink && /^[[:space:]]*["'(]/ { | |
match($0, /["'(]/); | |
delim = substr($0, RSTART, 1); | |
edelim = (delim == "(") ? ")" : delim; | |
st = substr($0, RSTART); | |
if(match(st, delim ".*" edelim)) | |
LinkDescs[LinkRef] = escape(substr(st,RSTART+1,RLENGTH-2)); | |
lastlink = 0; | |
next; | |
} | |
lastlink { lastlink = 0; } | |
Mode == "p" && /^[[:space:]]*\[\^[_[:alnum:]]+\]:[[:space:]]*/ { | |
match($0, /\[\^[[:alnum:]]+\]:/); | |
name = substr($0, RSTART+2,RLENGTH-4); | |
def = substr($0, RSTART+RLENGTH+1); | |
Footnote[tolower(name)] = scrub(def); | |
next; | |
} | |
Mode == "p" && /^[[:space:]]*\*\[[[:alnum:]]+\]:[[:space:]]*/ { | |
match($0, /\[[[:alnum:]]+\]/); | |
name = substr($0, RSTART+1,RLENGTH-2); | |
def = substr($0, RSTART+RLENGTH+2); | |
Abbrs[toupper(name)] = def; | |
next; | |
} | |
Mode != "none" { Out = Out filter($0); } | |
END { | |
print "<!DOCTYPE html>\n<html><head>" | |
print "<title>" Title "</title>"; | |
if(stylesheet) | |
print "<link rel=\"stylesheet\" href=\"" stylesheet "\">"; | |
else | |
print "<style><!--" CSS "\n--></style>"; | |
print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">"; | |
if(ToC && match(Out, /!\[toc[-+]?\]/)) | |
print "<script type=\"text/javascript\"><!--\n" \ | |
"function toggle_toc(n) {\n" \ | |
" var toc=document.getElementById(\"table-of-contents-\" + n);\n" \ | |
" var btn=document.getElementById(\"btn-text\");\n" \ | |
" toc.style.display=(toc.style.display==\"none\")?\"block\":\"none\";\n" \ | |
" btn.textContent=(toc.style.display==\"none\")?\"[+]\":\"[-]\";\n" \ | |
"}\n" \ | |
"//-->\n</script>"; | |
print "</head><body>"; | |
if(Out) { | |
Out = fix_footnotes(Out); | |
Out = fix_links(Out); | |
Out = fix_abbrs(Out); | |
Out = make_toc(Out); | |
print trim(Out); | |
if(footnotes) { | |
footnotes = fix_links(footnotes); | |
print "<hr><ol class=\"footnotes\">\n" footnotes "</ol>"; | |
} | |
} | |
print "</body></html>" | |
} | |
function escape(st) { | |
gsub(/&/, "\\&", st); | |
gsub(/</, "\\<", st); | |
gsub(/>/, "\\>", st); | |
return st; | |
} | |
function strip_tags(st) { | |
gsub(/<\/?[^>]+>/,"",st); | |
return st; | |
} | |
function trim(st) { | |
sub(/^[[:space:]]+/, "", st); | |
sub(/[[:space:]]+$/, "", st); | |
return st; | |
} | |
function filter(st, res,tmp) { | |
if(Mode == "p") { | |
if(match(st, /^(( )| *\t)/) || match(st, /^[[:space:]]*```/)) { | |
preterm = trim(substr(st, RSTART,RLENGTH)); | |
st = substr(st, RSTART+RLENGTH); | |
if(Buf) res = tag("p", scrub(Buf)); | |
Buf = st; | |
push("pre"); | |
} else if(!trim(prev) && match(st, /^[[:space:]]*[*-][[:space:]]*[*-][[:space:]]*[*-][-*[:space:]]*$/)) { | |
if(Buf) res = tag("p", scrub(Buf)); | |
Buf = ""; | |
res = res "<hr>\n"; | |
} else if(match(st, /^[[:space:]]*===+[[:space:]]*$/)) { | |
Buf = trim(substr(Buf, 1, length(Buf) - length(prev) - 1)); | |
if(Buf) res= tag("p", scrub(Buf)); | |
if(prev) res = res heading(1, scrub(prev)); | |
Buf = ""; | |
} else if(match(st, /^[[:space:]]*---+[[:space:]]*$/)) { | |
Buf = trim(substr(Buf, 1, length(Buf) - length(prev) - 1)); | |
if(Buf) res = tag("p", scrub(Buf)); | |
if(prev) res = res heading(2, scrub(prev)); | |
Buf = ""; | |
} else if(match(st, /^[[:space:]]*#+/)) { | |
sub(/#+[[:space:]]*$/, "", st); | |
match(st, /#+/); | |
ListLevel = RLENGTH; | |
tmp = substr(st, RSTART+RLENGTH); | |
if(Buf) res = tag("p", scrub(Buf)); | |
res = res heading(ListLevel, scrub(trim(tmp))); | |
Buf = ""; | |
} else if(match(st, /^[[:space:]]*>/)) { | |
if(Buf) res = tag("p", scrub(Buf)); | |
Buf = scrub(trim(substr(st, RSTART+RLENGTH))); | |
push("blockquote"); | |
} else if(match(st, /^[[:space:]]*([*+-]|[[:digit:]]+\.)[[:space:]]/)) { | |
if(Buf) res = tag("p", scrub(Buf)); | |
Buf=""; | |
match(st, /^[[:space:]]*/); | |
ListLevel = 1; | |
indent[ListLevel] = RLENGTH; | |
Open[ListLevel]=match(st, /^[[:space:]]*[*+-][[:space:]]*/)?"ul":"ol"; | |
push(Open[ListLevel]); | |
res = res filter(st); | |
} else if(match(st, /^[[:space:]]*$/)) { | |
if(trim(Buf)) { | |
res = tag("p", scrub(trim(Buf))); | |
Buf = ""; | |
} | |
} else | |
Buf = Buf st "\n"; | |
} else if(Mode == "blockquote") { | |
if(match(st, /^[[:space:]]*>[[:space:]]*$/)) | |
Buf = Buf "\n</p><p>"; | |
else if(match(st, /^[[:space:]]*>/)) | |
Buf = Buf "\n" scrub(trim(substr(st, RSTART+RLENGTH))); | |
else if(match(st, /^[[:space:]]*$/)) { | |
res = tag("blockquote", tag("p", trim(Buf))); | |
pop(); | |
res = res filter(st); | |
} else | |
Buf = Buf st; | |
} else if(Mode == "pre") { | |
if(!preterm && match(st, /^(( )| *\t)/) || preterm && !match(st, /^[[:space:]]*```/)) | |
Buf = Buf ((Buf)?"\n":"") substr(st, RSTART+RLENGTH); | |
else { | |
gsub(/\t/," ",Buf); | |
if(length(trim(Buf)) > 0) | |
res = tag("pre", tag("code", escape(Buf))); | |
pop(); | |
if(preterm) sub(/^[[:space:]]*```/,"",st); | |
res = res filter(st); | |
} | |
} else if(Mode == "ul" || Mode == "ol") { | |
if(ListLevel == 0 || match(st, /^[[:space:]]*$/) && (RLENGTH <= indent[1])) { | |
while(ListLevel > 1) | |
Buf = Buf "\n</" Open[ListLevel--] ">"; | |
res = tag(Mode, "\n" Buf "\n"); | |
pop(); | |
} else { | |
if(match(st, /^[[:space:]]*([*+-]|[[:digit:]]+\.)/)) { | |
tmp = substr(st, RLENGTH+1); | |
match(st, /^[[:space:]]*/); | |
if(RLENGTH > indent[ListLevel]) { | |
indent[++ListLevel] = RLENGTH; | |
if(match(st, /^[[:space:]]*[*+-]/)) | |
Open[ListLevel] = "ul"; | |
else | |
Open[ListLevel] = "ol"; | |
Buf = Buf "\n<" Open[ListLevel] ">"; | |
} else while(RLENGTH < indent[ListLevel]) | |
Buf = Buf "\n</" Open[ListLevel--] ">"; | |
if(match(tmp,/^[[:space:]]*\[[xX[:space:]]?\]/)) { | |
st = substr(tmp,RLENGTH+1); | |
tmp = tolower(substr(tmp,RSTART,RLENGTH)); | |
Buf = Buf "<li><input type=\"checkbox\" " (index(tmp,"x")?"checked":"") " disabled>" scrub(st); | |
} else | |
Buf = Buf "<li>" scrub(tmp); | |
} else if(match(st, /^[[:space:]]*$/)){ | |
Buf = Buf "<br>\n"; | |
} else { | |
sub(/^[[:space:]]+/,"",st); | |
Buf = Buf "\n" scrub(st); | |
} | |
} | |
} | |
prev = st; | |
return res; | |
} | |
function scrub(st, mp, ms, me, r, p, tg, a) { | |
sub(/ $/,"<br>\n",st); | |
gsub(/( |[[:space:]]+\\)\n/,"<br>\n",st); | |
while(match(st, /(__?|\*\*?|~~|`+|[&><\\])/)) { | |
a = substr(st, 1, RSTART-1); | |
mp = substr(st, RSTART, RLENGTH); | |
ms = substr(st, RSTART-1,1); | |
me = substr(st, RSTART+RLENGTH, 1); | |
p = RSTART+RLENGTH; | |
if(!classic_underscore && match(mp,/_+/)) { | |
if(match(ms,/[[:alnum:]]/) && match(me,/[[:alnum:]]/)) { | |
tg = substr(st, 1, index(st, mp)); | |
r = r tg; | |
st = substr(st, index(st, mp) + 1); | |
continue; | |
} | |
} | |
st = substr(st, p); | |
r = r a; | |
ms = ""; | |
if(mp == "\\") { | |
if(match(st, /^!?\[/)) { | |
r = r "\\" substr(st, RSTART, RLENGTH); | |
st = substr(st, 2); | |
} else if(match(st, /^(\*\*|__|~~|`+)/)) { | |
r = r substr(st, 1, RLENGTH); | |
st = substr(st, RLENGTH+1); | |
} else { | |
r = r substr(st, 1, 1); | |
st = substr(st, 2); | |
} | |
continue; | |
} else if(mp == "_" || mp == "*") { | |
if(match(me,/[[:space:]]/)) { | |
r = r mp; | |
continue; | |
} | |
p = index(st, mp); | |
while(p && match(substr(st, p-1, 1),/[\\[:space:]]/)) { | |
ms = ms substr(st, 1, p-1) mp; | |
st = substr(st, p + length(mp)); | |
p = index(st, mp); | |
} | |
if(!p) { | |
r = r mp ms; | |
continue; | |
} | |
ms = ms substr(st,1,p-1); | |
r = r itag("em", scrub(ms)); | |
st = substr(st,p+length(mp)); | |
} else if(mp == "__" || mp == "**") { | |
if(match(me,/[[:space:]]/)) { | |
r = r mp; | |
continue; | |
} | |
p = index(st, mp); | |
while(p && match(substr(st, p-1, 1),/[\\[:space:]]/)) { | |
ms = ms substr(st, 1, p-1) mp; | |
st = substr(st, p + length(mp)); | |
p = index(st, mp); | |
} | |
if(!p) { | |
r = r mp ms; | |
continue; | |
} | |
ms = ms substr(st,1,p-1); | |
r = r itag("strong", scrub(ms)); | |
st = substr(st,p+length(mp)); | |
} else if(mp == "~~") { | |
p = index(st, mp); | |
if(!p) { | |
r = r mp; | |
continue; | |
} | |
while(p && substr(st, p-1, 1) == "\\") { | |
ms = ms substr(st, 1, p-1) mp; | |
st = substr(st, p + length(mp)); | |
p = index(st, mp); | |
} | |
ms = ms substr(st,1,p-1); | |
r = r itag("del", scrub(ms)); | |
st = substr(st,p+length(mp)); | |
} else if(match(mp, /`+/)) { | |
p = index(st, mp); | |
if(!p) { | |
r = r mp; | |
continue; | |
} | |
ms = substr(st,1,p-1); | |
r = r itag("code", escape(ms)); | |
st = substr(st,p+length(mp)); | |
} else if(mp == ">") { | |
r = r ">"; | |
} else if(mp == "<") { | |
p = index(st, ">"); | |
if(!p) { | |
r = r "<"; | |
continue; | |
} | |
tg = substr(st, 1, p - 1); | |
if(match(tg,/^[[:alpha:]]+[[:space:]]/)) { | |
a = substr(tg,RSTART+RLENGTH-1); | |
tg = substr(tg,1,RLENGTH-1); | |
} else | |
a = ""; | |
if(match(tolower(tg), "^/?(a|abbr|div|span|blockquote|pre|img|code|p|em|strong|sup|sub|del|ins|s|u|b|i|br|hr|ul|ol|li|table|thead|tfoot|tbody|tr|th|td|caption|column|col|colgroup|figure|figcaption|dl|dd|dt|mark|cite|q|var|samp|small)$")) { | |
r = r "<" tg a ">"; | |
} else if(match(tg, "^[[:alpha:]]+://[[:graph:]]+$")) { | |
if(!a) a = tg; | |
r = r "<a href=\"" tg "\">" a "</a>"; | |
} else if(match(tg, "^[[:graph:]]+@[[:graph:]]+$")) { | |
if(!a) a = tg; | |
r = r "<a href=\"" obfuscate("mailto:" tg) "\">" obfuscate(a) "</a>"; | |
} else { | |
r = r "<"; | |
continue; | |
} | |
st = substr(st, p + 1); | |
} else if(mp == "&") { | |
if(match(st, /^[#[:alnum:]]+;/)) { | |
r = r "&" substr(st, 1, RLENGTH); | |
st = substr(st, RLENGTH+1); | |
} else { | |
r = r "&"; | |
} | |
} | |
} | |
return r st; | |
} | |
function push(newmode) {Stack[StackTop++] = Mode; Mode = newmode;} | |
function pop() {Mode = Stack[--StackTop];Buf = ""; return Mode;} | |
function heading(level, st, res, href) { | |
st = trim(st); | |
if(level > 6) level = 6; | |
href = tolower(st); | |
href = strip_tags(href); | |
gsub(/[^ [:alnum:]]+/, "", href); | |
gsub(/ +/, "-", href); | |
LinkUrls[href] = "#" href; | |
LinkUrls[tolower(st)] = "#" href; | |
res = tag("h" level, st (TopLinks?" <a class=\"top\" title=\"Return to top\" href=\"#\">↑ Top</a>":""), "id=\"" href "\""); | |
for(;ToCLevel < level; ToCLevel++) | |
ToC = ToC "<ul class=\"toc-" level "\">"; | |
for(;ToCLevel > level; ToCLevel--) | |
ToC = ToC "</ul>"; | |
ToC = ToC "<li class=\"toc-" level "\"><a class=\"toc-" level "\" href=\"#" href "\">" st "</a>\n"; | |
ToCLevel = level; | |
return res; | |
} | |
function make_toc(st, r,p,dis,t,n) { | |
if(!ToC) return st; | |
for(;ToCLevel > 1;ToCLevel--) | |
ToC = ToC "</ul>"; | |
p = match(st, /!\[toc[-+]?\]/); | |
while(p) { | |
++n; | |
dis = index(substr(st,RSTART,RLENGTH),"+"); | |
t = "<div>\n<small><a id=\"toc-button\" onclick=\"toggle_toc(" n ")\"><span id=\"btn-text\">" (dis?"[-]":"[+]") "</span> Contents</a></small>\n" \ | |
"<div id=\"table-of-contents-" n "\" style=\"display:" (dis?"block":"none") ";\">\n<ul class=\"toc-1\">" ToC "</ul>\n</div>\n</div>"; | |
r = r substr(st,1,RSTART-1); | |
if(substr(st,RSTART-1,1) != "\\") | |
r = r t; | |
else | |
r = substr(r,1,length(r)-1) substr(st,RSTART,RLENGTH); | |
st = substr(st,RSTART+RLENGTH); | |
p = match(st, /!\[toc[-+]?\]/); | |
} | |
return r st; | |
} | |
function fix_links(st, lt,ld,lr,url,img,res,rx,pos) { | |
do { | |
pos = match(st, /\[[^\]]+\]/); | |
if(!pos)break; | |
img=substr(st,RSTART-1,1)=="!"; | |
if(substr(st, RSTART-(img?2:1),1)=="\\") { | |
res = res substr(st,1,RSTART-(img?3:2)); | |
if(img && substr(st,RSTART,RLENGTH)=="[toc]")res=res "\\"; | |
res = res substr(st,RSTART-(img?1:0),RLENGTH+(img?1:0)); | |
st = substr(st, RSTART + RLENGTH); | |
continue; | |
} | |
res = res substr(st, 1, RSTART-(img?2:1)); | |
rx = substr(st, RSTART, RLENGTH); | |
st = substr(st, RSTART+RLENGTH); | |
if(match(st, /^[[:space:]]*\([^)]+\)/)) { | |
lt = substr(rx, 2, length(rx) - 2); | |
match(st, /\([^)]+\)/); | |
url = substr(st, RSTART+1, RLENGTH-2); | |
st = substr(st, RSTART+RLENGTH); | |
ld = ""; | |
if(match(url,/[[:space:]]+["']/)) { | |
ld = url; | |
url = substr(url, 1, RSTART - 1); | |
match(ld,/["']/); | |
delim = substr(ld, RSTART, 1); | |
if(match(ld,delim ".*" delim)) | |
ld = substr(ld, RSTART+1, RLENGTH-2); | |
} else ld = ""; | |
if(img) | |
res = res "<img src=\"" url "\" title=\"" ld "\" alt=\"" lt "\">"; | |
else | |
res = res "<a href=\"" url "\" title=\"" ld "\">" lt "</a>"; | |
} else if(match(st, /^[[:space:]]*\[[^\]]*\]/)) { | |
lt = substr(rx, 2, length(rx) - 2); | |
match(st, /\[[^\]]*\]/); | |
lr = trim(tolower(substr(st, RSTART+1, RLENGTH-2))); | |
if(!lr) { | |
lr = tolower(trim(lt)); | |
if(LinkDescs[lr]) lt = LinkDescs[lr]; | |
} | |
st = substr(st, RSTART+RLENGTH); | |
url = LinkUrls[lr]; | |
ld = LinkDescs[lr]; | |
if(img) | |
res = res "<img src=\"" url "\" title=\"" ld "\" alt=\"" lt "\">"; | |
else | |
res = res "<a href=\"" url "\" title=\"" ld "\">" lt "</a>"; | |
} else | |
res = res (img?"!":"") rx; | |
} while(pos > 0); | |
return res st; | |
} | |
function fix_footnotes(st, r,p,n,i,d,fn,fc) { | |
p = match(st, /\[\^[^\]]+\]/); | |
while(p) { | |
r = r substr(st,1,RSTART-1); | |
d = substr(st,RSTART+2,RLENGTH-3); | |
n = tolower(d); | |
st = substr(st,RSTART+RLENGTH); | |
if(Footnote[tolower(n)]) { | |
if(!fn[n]) fn[n] = ++fc; | |
d = Footnote[n]; | |
} else { | |
Footnote[n] = scrub(d); | |
if(!fn[n]) fn[n] = ++fc; | |
} | |
footname[fc] = n; | |
d = strip_tags(d); | |
if(length(d) > 20) d = substr(d,1,20) "…"; | |
r = r "<sup title=\"" d "\"><a href=\"#footnote-" fn[n] "\" id=\"footnote-pos-" fn[n] "\" class=\"footnote\">[" fn[n] "]</a></sup>"; | |
p = match(st, /\[\^[^\]]+\]/); | |
} | |
for(i=1;i<=fc;i++) | |
footnotes = footnotes "<li id=\"footnote-" i "\">" Footnote[footname[i]] \ | |
"<a title=\"Return to Document\" class=\"footnote-back\" href=\"#footnote-pos-" i \ | |
"\"> ↶ Back</a></li>\n"; | |
return r st; | |
} | |
function fix_abbrs(str, st,k,r,p) { | |
for(k in Abbrs) { | |
r = ""; | |
st = str; | |
t = escape(Abbrs[toupper(k)]); | |
gsub(/&/,"\\&", t); | |
p = match(st,"[^[:alnum:]]" k "[^[:alnum:]]"); | |
while(p) { | |
r = r substr(st, 1, RSTART); | |
r = r "<abbr title=\"" t "\">" k "</abbr>"; | |
st = substr(st, RSTART+RLENGTH-1); | |
p = match(st,"[^[:alnum:]]" k "[^[:alnum:]]"); | |
} | |
str = r st; | |
} | |
return str; | |
} | |
function tag(t, body, attr) { | |
if(attr) | |
attr = " " trim(attr); | |
# https://www.w3.org/TR/html5/grouping-content.html#the-p-element | |
if(t == "p" && (match(body, /<\/?(div|table|blockquote|dl|ol|ul|h[[:digit:]]|hr|pre)[>[:space:]]/))|| (match(body,/!\[toc\]/) && substr(body, RSTART-1,1) != "\\")) | |
return "<" t attr ">" body "\n"; | |
else | |
return "<" t attr ">" body "</" t ">\n"; | |
} | |
function itag(t, body) { | |
return "<" t ">" body "</" t ">"; | |
} | |
function obfuscate(e, r,i,t,o) { | |
for(i = 1; i <= length(e); i++) { | |
t = substr(e,i,1); | |
r = int(rand() * 100); | |
if(r > 50) | |
o = o sprintf("&#x%02X;", _ord[t]); | |
else if(r > 10) | |
o = o sprintf("&#%d;", _ord[t]); | |
else | |
o = o t; | |
} | |
return o; | |
} | |
function bright(c,a ,r,g,b) { | |
sub(/^#/,"",c); | |
r = 255*a + _hex[toupper(substr(c,1,2))]*(1-a); | |
g = 255*a + _hex[toupper(substr(c,3,2))]*(1-a); | |
b = 255*a + _hex[toupper(substr(c,5,2))]*(1-a); | |
return sprintf("#%02X%02X%02X",r>255?255:r,g>255?255:g,b>255?255:b); | |
} | |
function init_css(Theme, css,ss,hr,c1,c2,c3,c4,c5,bg1,bg2,bg3,bg4,ff,i) { | |
if(Theme == "0") return ""; | |
css["body"] = "color:%color1%;font-family:%font-family%;line-height:1.5em;" \ | |
"padding:1em 2em;width:80%;max-width:%maxwidth%;margin:0 auto;min-height:100%;float:none;"; | |
css["h1"] = "color:%color1%;border-bottom:1px solid %background1%;padding:0.3em 0.1em;"; | |
css["h2"] = "color:%color2%;border-bottom:1px solid %background2%;padding:0.2em 0.1em;"; | |
css["h3"] = "color:%color3%;border-bottom:1px solid %background3%;padding:0.1em 0.1em;"; | |
css["h4,h5,h6"] = "color:%color4%;padding:0.1em 0.1em;"; | |
css["h1,h2,h3,h4,h5,h6"] = "font-weight:normal;line-height:1.2em;"; | |
css["h4"] = "border-bottom:1px solid %background4%"; | |
css["p"] = "margin:0.5em 0.1em;" | |
css["hr"] = "background:%hr%;height:1px;border:0;" | |
css["a"] = "color:%color2%;"; | |
css["a:visited"] = "color:%color2%;"; | |
css["a:active"] = "color:%color4%;"; | |
css["a:hover"] = "color:%color4%;"; | |
css["a.top"] = "font-size:x-small;text-decoration:initial;float:right;"; | |
css["strong,b"] = "color:%color1%"; | |
css["code"] = "color:%color2%;"; | |
css["blockquote"] = "margin-left:1em;color:%color2%;background:%color5%;border-left:0.2em solid %color3%;border-radius:3px;padding:0.25em 0.5em;"; | |
css["pre"] = "color:%color2%;background:%color5%;border-radius:5px;line-height:1.25em;margin:0.25em 0.5em;padding:0.75em;"; | |
css["table"] = "border-collapse:collapse;margin:0.5em;"; | |
css["th,td"] = "padding:0.5em 0.75em;border:1px solid %color4%;"; | |
css["th"] = "color:%color2%;border:1px solid %color3%;border-bottom:2px solid %color3%;"; | |
css["tr:nth-child(odd)"] = "background-color:%color5%;"; | |
css["div"] = "padding:0.5em;"; | |
css["caption"] = "padding:0.5em;font-style:italic;"; | |
css["dl"] = "margin:0.5em;"; | |
css["dt"] = "font-weight:bold;"; | |
css["dd"] = "padding:0.3em;"; | |
css["mark"] = "color:%color2%;background-color:%color5%;"; | |
css["del,s"] = "color:%color4%;"; | |
css["a#toc-button"] = "color:%color3%;background:%color5%;cursor:pointer;font-size:small;padding: 0.3em 0.5em 0.5em 0.5em;font-family:monospace;border-radius:3px;"; | |
css["a#toc-button:hover"] = "color:%color5%;background:%color3%;"; | |
css["div#table-of-contents"] = "padding:0;font-size:smaller;"; | |
css["abbr"] = "cursor:help;"; | |
css["ol.footnotes"] = "font-size:small;color:%color4%"; | |
css["a.footnote"] = "font-size:smaller;text-decoration:initial;"; | |
css["a.footnote-back"] = "text-decoration:initial;font-size:x-small;"; | |
css[".fade"] = "color:%color5%;"; | |
css[".highlight"] = "color:%color2%;background-color:%color5%;"; | |
if(Theme==2){ | |
c1="#303F9F";c2="#0449CC";c3="#2162FA";c4="#4B80FB";c5="#EDF2FF"; | |
ff="\"Trebuchet MS\", Helvetica, sans-serif"; | |
} else if(Theme==3){ | |
c1="#430005";c2="#740009";c3="#A6373F";c4="#c55158";c5="#fbf2f2"; | |
ff="Verdana, Geneva, sans-serif"; | |
} else if(Theme==4){ | |
c1="#083900";c2="#0D6300";c3="#3C8D2F";c4="#50be3f";c5="#f2faf1"; | |
ff="Georgia, serif"; | |
} else if(Theme==5){ | |
c1="#453700";c2="#775F00";c3="#AA9339";c4="#c7b057";c5="#fbf9f2"; | |
ff="Tahoma, Geneva, sans-serif"; | |
} else if(Theme==6){ | |
c1="#315067";c2="#4F9E9C";c3="#77AD93";c4="#95CE94";c5="#F6FFEE"; | |
ff="Verdana, sans-serif;"; | |
} else if(Theme==7){ | |
c1="#35305D";c2="#646379";c3="#7A74A5";c4="#646392";c5="#fafafa"; | |
} else if(Theme==8){ | |
c1="#215FC2";c2="#D49095";c3="#AD90D4";c4="#90D4CF";c5="#F7FDEF"; | |
} else { | |
c1="#092859";c2="#1351b5";c3="#d47034";c4="#DC7435";c5="#F6F8FF"; | |
} | |
if(!ff) ff = "sans-serif" | |
for(i = 0; i<=255; i++)_hex[sprintf("%02X",i)]=i; | |
bg1 = bright(c1,0.5); | |
bg2 = bright(c2,0.5); | |
bg3 = bright(c3,0.5); | |
bg4 = bright(c3,0.75); | |
hr = bright(c1,0.75); | |
for(k in css) | |
ss = ss "\n" k "{" css[k] "}"; | |
gsub(/%maxwidth%/,MaxWidth,ss); | |
gsub(/%color1%/,c1,ss); | |
gsub(/%color2%/,c2,ss); | |
gsub(/%color3%/,c3,ss); | |
gsub(/%color4%/,c4,ss); | |
gsub(/%color5%/,c5,ss); | |
gsub(/%background1%/,bg1,ss); | |
gsub(/%background2%/,bg2,ss); | |
gsub(/%background3%/,bg3,ss); | |
gsub(/%background4%/,bg4,ss); | |
gsub(/%font-family%/,ff,ss); | |
gsub(/%hr%/,hr,ss); | |
return ss; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* `comdown.awk` Demonstration | |
* =========================== | |
* ![toc] | |
* | |
* This file demonstrates how to comment your code with | |
* the `comdown.awk` script. It also serves as a functional test. | |
* | |
* Comments in your code that are to be included in the output must start with | |
* the sequence `/**`. | |
* Other comments and source code are ignored by the script. | |
* | |
Lines that don't start with *s, like this one, are ignored. | |
* | |
* Blank lines in the comment separate paragraphs. | |
* | |
* Two spaces at the end of the line | |
* forces a linebreak. Here is another line<br>break. | |
* | |
* Headings can be written like so: | |
* Heading 1 | |
* ========= | |
* Heading 2 | |
* --------- | |
* | |
* Alternatively: | |
* ``` | |
* # Heading 1 | |
* ## Heading 2 | |
* ### Heading 3 | |
* ``` | |
* # Heading 1 | |
* ## Heading 2 | |
* ### Heading 3 | |
* #### Heading 4 | |
* ##### Heading 5 | |
* ###### Heading 6 | |
* \# symbols after the heading are cleared, so you can also write `## Heading 2 ##` | |
* if you prefer. There is a '\\#' escape sequence. | |
* | |
* Escaping and not escaping ampersands: & & § § § and angle brackets: < > < > `<`. | |
* This is a number of operators that broke escaping "=", "<>" (alternatively "!="), "<", "<=", ">" and ">=". | |
* | |
* Horizontal rules: | |
* | |
* ----- | |
* | |
* * * * * * * * | |
* | |
* Block Level Formatting | |
* ---------------------- | |
* These options are available at the block level. | |
* ### Lists | |
* #### Ordered List #### | |
* 1. Item 1 | |
* 1. Item 1.1 | |
* 1981\. This line started with a number. | |
* 1. Item 1.2; | |
* This item consists of multiple lines | |
* with a forced line break (two spaces at the end of the last line). | |
* 1. Item 2 | |
* * Item 2.1; List styles can be mixed. | |
* * Item 2.2 | |
* | |
* The blank line above contains whitespace, hence a new list is not started | |
* (Paragraphs in lists differ a bit from other markdowns). | |
* * Item 2.3 | |
* 1. Item 3 | |
* 1. Item 3.1 | |
* 1. Item 3.1.1 | |
* 1. Item 3.2 | |
* | |
* #### Unordered List | |
* - Item 1 | |
* + Item 1.1 | |
* + Item 1.2 | |
* - Item 2 | |
* 1. Item 2.1; Again, list styles can be mixed. | |
* 1. Item 2.2 | |
* - Item 3 | |
* * Item 3.1 | |
* * Item 3.2 | |
* | |
* GitHub-style task lists are also supported: | |
* - [ ] Task 1 | |
* - [] Subtask 1a | |
* - [X] Subtask 1b | |
* - [x] Task 2 - **completed.** | |
* - [] Task 3 | |
* 1. [ ] Subtask 3a | |
* 1. [x] Subtask 3b | |
* - [x] ~~Task 4~~ - also completed | |
* | |
* ### Block Quotes | |
* > This is a blockquote. It | |
* may span multiple lines. | |
* > | |
* > Blank lines like the one above separates paragraphs within the quote. | |
* > | |
* > Unfortunately it can't contain nested quotes lists | |
* > and code in this implementation. | |
* | |
* The empty line above ends the quote. | |
* | |
* ### Code Blocks | |
* Code indented with tabs: | |
* //Some code, indented with a single tab: | |
* int main(int argc, char *argv[]) { | |
* return 0; | |
* } | |
* | |
* Code indented with spaces: | |
* //Some code, indented with spaces | |
* | |
* int main(int argc, char *argv[]) { | |
* return 0; | |
* } | |
* This particular implementation doesn't care about blank lines | |
* after the code block. | |
* | |
* GitHub-style code blocks: | |
* ``` | |
* //Some code, wrapped in ``` | |
* | |
* int main(int argc, char *argv[]) { | |
* return 0; | |
* } | |
* ``` | |
* Unfortunately, if you use C/C++ you have to escape your asterisks | |
* like **int foo(int \*x, int \*y)** or this **int main(int argc, char \*argv[])** | |
* unless you use backticks: `int main(int argc, char *argv[])` | |
* | |
* Regression test: The #es in this sample would've caused problems: | |
* | |
* # Compile like so: | |
* mvn package | |
* | |
* # Generate Javadocs | |
* mvn javadoc:javadoc | |
* | |
* This is a diagram: | |
* | |
* +-------+ +--------+ | |
* | | | | | |
* | Foo +-----> Bar | | |
* | Block | | Block | | |
* | | | | | |
* +---^---+ +----+---+ | |
* | | | |
* | | | |
* | +----v---+ | |
* | | | | |
* | | | | |
* +---------+ | | |
* | | | |
* +--------+ | |
* | |
* Hyperlinks | |
* ---------- | |
* * Example hyperlink 1: [This link](http://example.com) is inline | |
* * Example hyperlink 1B: [This link][link1] is not inline; escape charaters in the url. | |
* * Example hyperlink 2: [This link] [link2] and [this one][LINK2] (case insensitive) has a title attribute. | |
* You can also do [link2][]. | |
* * Example hyperlink 3: [This link <&>][link3] has a title attribute on separate line and | |
* escaped characters in the link text. | |
* * Example hyperlink 4: [funny example][funny] in `<angle brackets>` | |
* * Example hyperlink 5: [example 5](http://example.com?x=5&y=10 "Example Title <&>") with inline title attribute and | |
* escaped characters in the link description. | |
* * Links can be placed inline: <http://www.example.com>. | |
* * e-mail addresses get obfuscated: <address@example.com> | |
* * Relative links that refer to specific headings are supported. | |
* For example [Block Level Formatting][block-level-formatting] - replace spaces with -, remove all | |
* other non-alphanumerics and everything lowercase. | |
* Alternatively [Block Level Formatting][Block Level Formatting] or [ Using HTML in Documents ][] | |
* * [This link](http://example.com/some_random_page) has \_underscores\_ where | |
* the usual rules about escaping apply, but [this one][underscores] doesn't. | |
* | |
* Not links: [foo] and this one \[foo](www.example.com). | |
* | |
* [link1]: http://example.com?x=5&y=10 | |
* [link2]: http://example.com/2 (Second Example; Escaped characters: < & >) | |
* [link3]: http://example.com/3 | |
* (Third Example <&>) | |
* [funny]: <http://example.com/funny> (Link in angle brackets) | |
* [underscores]: http://example.com/some_random_page | |
* | |
* Images | |
* ------ | |
* | |
* Image syntax `\![Image Alt Text](example.png)` | |
* Escaping images `\![Image Alt Text](example.png)` and links `\[Link Alt Text](example.com)` | |
* | |
* Images can be encoded as Data URIs: ![Red Dot][reddot] | |
* <sub>The red dot comes from [Wikipedia][datauri]</sub> | |
* | |
* [dataURI]: https://en.wikipedia.org/wiki/Data_URI_scheme "Data URI scheme" | |
* [reddot]: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg== | |
* | |
* Line-Level Formatting | |
* ---------------------- | |
* * \_Emphasized\_ produces _Emphasized_ | |
* * A word *containing_nested_underscores* can be treated in one of two ways depending on | |
* whether the variable `classic_underscore` is in the script. | |
* * A word containing*nested*asterisks will be treated as emphasis. | |
* * \*Emphasized\* produces *Emphasized* | |
* * \__Strongly Emphasized\__ produces __Strongly Emphasized__ | |
* * \**Strongly Emphasized\** produces **Strongly Emphasized** | |
* * \`Code Block\` produces `Code Block` | |
* * \`\`Code Block\`\` produces ``Code Block`` | |
* * \`\`Code Block with embedded backtick: \` \`\` produces ``Code Block with embedded backtick: ` `` | |
* * \~~Strike through\~~ produces ~~Strike through~~ | |
* * _You **can** mix styles within `other` styles_ | |
* * But the backtick code blocks cause asterisks and underscores to be ignored: | |
* `void do_something(Widget *foo, int p, int q, Wotzit *bar, int zoop)` | |
* * Whitespace surrounding the * or _ will cause it to be treated as literal: | |
* * _ this text would not be emphasized _ and neither would this * mmmm * | |
* * ** this text would not be emphasized ** and neither would this __ mmmm __ | |
* | |
* Extensions | |
* ---------- | |
* The special tag `\![toc]` can be used to insert a table of contents in the document. | |
* Leave a blank line below it to ensure the paragraphs are formatted correctly. | |
* | |
* [MultiMarkdown][]-style footnotes are supported: | |
* - Here is a reference to the footnote[^footnote][^<http://example.com>]. | |
* - Here is an inline footnote[^An _inline_ footnote. **Text** _formatting_ ``works`` | |
* here as well; Some characters to escape: < & > and <http://example.com>]. | |
* - Here is a reference to the third footnote[^footnote3]. | |
* | |
* MultiMarkdown's syntax for abbreviations is also supported. | |
* For example HTML, XML and GUI. | |
* ``` | |
* *[HTML]: Hypertext Markup Language | |
* *[XML]: eXstensible Markup Language; Escaped characters: < > & | |
* *[GUI]: Graphical User Interface | |
* ``` | |
* But only whole words: HTML5 and SXML doesn't get the `<abbr/>` tag. | |
* | |
* [^footnote]: This is a footnote; **Text** _formatting_ ``works``. Some characters to escape: < & > | |
* [^footnote3]: This is footnote number 3. This one contains a [hyperlink][link1] | |
* [MultiMarkdown]: http://fletcher.github.io/MultiMarkdown-4/syntax | |
* *[HTML]: Hypertext Markup Language | |
* *[XML]: eXstensible Markup Language; Escaped characters: < > & | |
* *[GUI]: Graphical User Interface | |
* | |
* Another idea borrowed from MultiMarkdown is to have a \ | |
* space followed by a \ at the end of a line force a line break. \ | |
* This is useful because I have the habit of trimming trailing spaces. | |
* | |
* Using HTML in Documents | |
* ----------------------- | |
* ### A HTML Table | |
* <table> | |
* <tr><th>Column A</th><th>Column B</th><th>Column C</th></tr> | |
* <tr><td>Item 1a</td><td>Item 1b</td><td>Item 1c</td></tr> | |
* <tr><td>Item 2a</td><td>Item 2b</td><td>Item 2c</td></tr> | |
* <tr><td>Item 3a</td><td>Item 3b</td><td>Item 3c</td></tr> | |
* <tr><td>Item 4a</td><td>Item 4b</td><td>Item 4c</td></tr> | |
* <tr><td>Item 5a</td><td>Item 5b</td><td>Item 5c</td></tr> | |
* <tr><td>Item 6a</td><td>Item 6b</td><td>Item 6c</td></tr> | |
* </table> | |
* | |
* ### A Definitions List | |
* <dl> | |
* <dt>Item 1</dt> | |
* <dd>A description of item 1.</dd> | |
* <dt>Item 2</dt> | |
* <dd>A description of item 2.</dd> | |
* <dt>Item 3</dt> | |
* <dd>A description of item 3.</dd> | |
* </dl> | |
* | |
* ### Some Other Tags | |
* Some <b>bold text</b>, some <i>italic text</i>, a <q>quote</q>, | |
* a <var class="xxx">variable</var>, <ins>inserted text</ins>, <del>deleted text</del>, | |
* a <mark>marked block</mark>, a <cite>[citation]</cite>. | |
* | |
* A `<div/>` element: | |
* <div class="highlight">A `<div/>` element</div> | |
* | |
* A `<span/>` element: | |
* <span class="highlight">A `<span/>` element</span> | |
* | |
* Not all HTML tags are supported. For example: | |
* <script type="text/javascript">$(function(){alert("GOTCHA!");});</script> | |
* | |
* This is how you work around the limitations of block quotes: | |
* <blockquote> | |
* Block quote. | |
* <blockquote> | |
* Block quote within a block quote. | |
* </blockquote> | |
* <pre><code> | |
* <pre/> block within the blockquote. | |
* </code></pre> | |
* </blockquote> | |
* | |
* Lorem Ipsum | |
* ----------- | |
* | |
* Some Lorem Ipsum from [lipsum.com](http://www.lipsum.com/) to see how the styles work | |
* with large paragraphs: | |
* | |
* Lorem **ipsum** dolor sit amet, consectetur **adipiscing elit**. In interdum ut nulla suscipit | |
* tincidunt. Mauris sollicitudin consectetur elit sit amet iaculis. Aliquam urna neque, | |
* pretium quis eros non, pellentesque tempus augue. Vestibulum ornare, lacus non sagittis | |
* elementum, est ante placerat dolor, vitae tincidunt orci felis id felis. Etiam id nisl | |
* sed turpis pulvinar condimentum. Etiam neque tortor, sollicitudin id metus sed, mollis | |
* maximus enim. Sed risus ante, suscipit quis ex vitae, consectetur ultricies diam. Nulla | |
* sollicitudin quis purus ornare tempor. Sed rhoncus sapien volutpat neque pretium, nec | |
* dapibus nisl iaculis. Praesent ultrices risus eget purus semper pulvinar sed ut ligula. | |
* Nunc ac nisl neque. | |
* | |
* Sed enim enim, fermentum at lectus eu, tincidunt sollicitudin mi. Praesent vel auctor | |
* elit. Etiam ac vulputate nisl. Etiam egestas urna quis velit varius convallis. Vestibulum | |
* sed porta mi. Vestibulum ac dolor eu purus mattis bibendum congue sed nunc. Curabitur sed | |
* venenatis neque. Curabitur et eros ac leo ultrices ultricies vitae ut justo. | |
* | |
* Vestibulum viverra venenatis quam, quis faucibus magna commodo hendrerit. Sed at dui et orci | |
* mattis accumsan. Integer vulputate blandit volutpat. Mauris non sem a velit posuere fringilla. | |
* Phasellus id arcu euismod, blandit lectus a, tempus justo. Aenean efficitur, velit nec aliquet | |
* rhoncus, nisi lectus efficitur diam, non dignissim est metus et sem. Sed ornare lacus eget | |
* convallis semper. Fusce malesuada nunc et mauris facilisis consectetur. Pellentesque | |
* consectetur suscipit mauris, eu lobortis nisi consequat nec. Sed sagittis ac ligula sit amet | |
* scelerisque. Curabitur ipsum risus, imperdiet ut pellentesque eu, hendrerit sed erat. | |
* | |
* Praesent auctor, lacus quis condimentum interdum, leo orci elementum tellus, nec eleifend | |
* mauris tellus non ipsum. Aenean sit amet congue ante. Morbi ultricies pharetra tortor, a | |
* elementum purus congue laoreet. Fusce varius semper enim, non pretium urna ultricies et. | |
* Aliquam laoreet urna non tristique suscipit. Donec sollicitudin sit amet erat id cursus. | |
* Aliquam nisl nisi, maximus et molestie id, viverra tempor neque. Duis et interdum nisi. | |
* Nullam vulputate sed risus et finibus. Etiam eu leo et mi elementum laoreet vestibulum ut | |
* ipsum. Pellentesque bibendum dictum est, sit amet placerat diam aliquet eu. Phasellus | |
* dignissim tristique lacus a semper. Phasellus nec sollicitudin lectus. | |
* | |
* Duis non lectus purus. Sed ornare nulla felis, id suscipit mi suscipit vel. Duis nec ipsum | |
* a arcu posuere vulputate et ut ante. Vivamus vitae erat et tortor varius consequat at sit amet | |
* nulla. In rutrum, lacus et posuere auctor, diam sapien varius diam, id **vehicula enim urna vel | |
* massa**. Aliquam iaculis volutpat nisi, a ultricies eros tristique eu. Suspendisse ac mattis lectus. | |
* Nunc facilisis massa non maximus cursus. Etiam consequat, magna nec sollicitudin luctus, nisi leo | |
* tincidunt ipsum, vitae suscipit arcu arcu id velit. Mauris auctor faucibus scelerisque. | |
*/ | |
/* This comment is not processed because it doesn't start with the ** */ | |
/** Comments on lines by themselves are treated as separate paragraphs. */ | |
//Some text that should not be converted. | |
int main(int argc, char *argv[]) { | |
/** You can put comments anywhere in your code. */ | |
printf("hello, world"); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/awk -f | |
# | |
# Markdown processor in AWK. It is simplified from comdown.awk | |
# | |
# (c) 2016 Werner Stoop | |
# Copying and distribution of this file, with or without modification, | |
# are permitted in any medium without royalty provided the copyright | |
# notice and this notice are preserved. This file is offered as-is, | |
# without any warranty. | |
BEGIN { | |
# Configuration options | |
if(Title=="") Title = "Documentation"; | |
if(Theme=="") Theme = 1; | |
#TopLinks = 1; | |
#classic_underscore = 1; | |
if(MaxWidth=="") MaxWidth="1080px"; | |
Mode = "p"; ToC = ""; ToCLevel = 1; | |
CSS = init_css(Theme); | |
for(i = 0; i < 128; i++) | |
_ord[sprintf("%c", i)] = i; | |
srand(); | |
} | |
/^[[:space:]]*\[[_ [:alnum:]]+\]:/ { | |
linkdesc = ""; lastlink = 0; | |
match($0,/\[.*\]/); | |
LinkRef = tolower(substr($0, RSTART+1, RLENGTH-2)); | |
st = substr($0, RSTART+RLENGTH+2); | |
match(st, /[^[:space:]]+/); | |
url = substr(st, RSTART, RLENGTH); | |
st = substr(st, RSTART+RLENGTH+1); | |
if(match(url, /^<.*>/)) | |
url = substr(url, RSTART+1, RLENGTH-2); | |
if(match(st, /["'(]/)) { | |
delim = substr(st, RSTART, 1); | |
edelim = (delim == "(") ? ")" : delim; | |
if(match(st, delim ".*" edelim)) | |
linkdesc = substr(st, RSTART+1, RLENGTH-2); | |
} | |
LinkUrls[LinkRef] = escape(url); | |
if(!linkdesc) lastlink = 1; | |
LinkDescs[LinkRef] = escape(linkdesc); | |
next; | |
} | |
lastlink && /^[[:space:]]*["'(]/ { | |
match($0, /["'(]/); | |
delim = substr($0, RSTART, 1); | |
edelim = (delim == "(") ? ")" : delim; | |
st = substr($0, RSTART); | |
if(match(st, delim ".*" edelim)) | |
LinkDescs[LinkRef] = escape(substr(st,RSTART+1,RLENGTH-2)); | |
lastlink = 0; | |
next; | |
} | |
lastlink { lastlink = 0; } | |
Mode == "p" && /^[[:space:]]*\[\^[_[:alnum:]]+\]:[[:space:]]*/ { | |
match($0, /\[\^[[:alnum:]]+\]:/); | |
name = substr($0, RSTART+2,RLENGTH-4); | |
def = substr($0, RSTART+RLENGTH+1); | |
Footnote[tolower(name)] = scrub(def); | |
next; | |
} | |
Mode == "p" && /^[[:space:]]*\*\[[[:alnum:]]+\]:[[:space:]]*/ { | |
match($0, /\[[[:alnum:]]+\]/); | |
name = substr($0, RSTART+1,RLENGTH-2); | |
def = substr($0, RSTART+RLENGTH+2); | |
Abbrs[toupper(name)] = def; | |
next; | |
} | |
{ Out = Out filter($0); } | |
END { | |
if(match($0, /^[[:space:]]*\*/)) | |
Out = Out filter(substr($0, RSTART+RLENGTH)); | |
if(Mode == "ul" || Mode == "ol") { | |
while(ListLevel > 1) | |
Buf = Buf "\n</" Open[ListLevel--] ">"; | |
Out = Out tag(Mode, Buf "\n"); | |
} else { | |
Buf = trim(scrub(Buf)); | |
if(Buf) | |
Out = Out tag(Mode, Buf); | |
} | |
Mode = "none"; | |
Buf = ""; | |
print "<!DOCTYPE html>\n<html><head>" | |
print "<title>" Title "</title>"; | |
if(stylesheet) | |
print "<link rel=\"stylesheet\" href=\"" stylesheet "\">"; | |
else | |
print "<style><!--" CSS "\n--></style>"; | |
print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">"; | |
if(ToC && match(Out, /!\[toc[-+]?\]/)) | |
print "<script type=\"text/javascript\"><!--\n" \ | |
"function toggle_toc(n) {\n" \ | |
" var toc=document.getElementById(\"table-of-contents-\" + n);\n" \ | |
" var btn=document.getElementById(\"btn-text\");\n" \ | |
" toc.style.display=(toc.style.display==\"none\")?\"block\":\"none\";\n" \ | |
" btn.textContent=(toc.style.display==\"none\")?\"[+]\":\"[-]\";\n" \ | |
"}\n" \ | |
"//-->\n</script>"; | |
print "</head><body>"; | |
if(Out) { | |
Out = fix_footnotes(Out); | |
Out = fix_links(Out); | |
Out = fix_abbrs(Out); | |
Out = make_toc(Out); | |
print trim(Out); | |
if(footnotes) { | |
footnotes = fix_links(footnotes); | |
print "<hr><ol class=\"footnotes\">\n" footnotes "</ol>"; | |
} | |
} | |
print "</body></html>" | |
} | |
function escape(st) { | |
gsub(/&/, "\\&", st); | |
gsub(/</, "\\<", st); | |
gsub(/>/, "\\>", st); | |
return st; | |
} | |
function strip_tags(st) { | |
gsub(/<\/?[^>]+>/,"",st); | |
return st; | |
} | |
function trim(st) { | |
sub(/^[[:space:]]+/, "", st); | |
sub(/[[:space:]]+$/, "", st); | |
return st; | |
} | |
function filter(st, res,tmp) { | |
if(Mode == "p") { | |
if(match(st, /^(( )| *\t)/) || match(st, /^[[:space:]]*```/)) { | |
preterm = trim(substr(st, RSTART,RLENGTH)); | |
st = substr(st, RSTART+RLENGTH); | |
if(Buf) res = tag("p", scrub(Buf)); | |
Buf = st; | |
push("pre"); | |
} else if(!trim(prev) && match(st, /^[[:space:]]*[*-][[:space:]]*[*-][[:space:]]*[*-][-*[:space:]]*$/)) { | |
if(Buf) res = tag("p", scrub(Buf)); | |
Buf = ""; | |
res = res "<hr>\n"; | |
} else if(match(st, /^[[:space:]]*===+[[:space:]]*$/)) { | |
Buf = trim(substr(Buf, 1, length(Buf) - length(prev) - 1)); | |
if(Buf) res= tag("p", scrub(Buf)); | |
if(prev) res = res heading(1, scrub(prev)); | |
Buf = ""; | |
} else if(match(st, /^[[:space:]]*---+[[:space:]]*$/)) { | |
Buf = trim(substr(Buf, 1, length(Buf) - length(prev) - 1)); | |
if(Buf) res = tag("p", scrub(Buf)); | |
if(prev) res = res heading(2, scrub(prev)); | |
Buf = ""; | |
} else if(match(st, /^[[:space:]]*#+/)) { | |
sub(/#+[[:space:]]*$/, "", st); | |
match(st, /#+/); | |
ListLevel = RLENGTH; | |
tmp = substr(st, RSTART+RLENGTH); | |
if(Buf) res = tag("p", scrub(Buf)); | |
res = res heading(ListLevel, scrub(trim(tmp))); | |
Buf = ""; | |
} else if(match(st, /^[[:space:]]*>/)) { | |
if(Buf) res = tag("p", scrub(Buf)); | |
Buf = scrub(trim(substr(st, RSTART+RLENGTH))); | |
push("blockquote"); | |
} else if(match(st, /^[[:space:]]*([*+-]|[[:digit:]]+\.)[[:space:]]/)) { | |
if(Buf) res = tag("p", scrub(Buf)); | |
Buf=""; | |
match(st, /^[[:space:]]*/); | |
ListLevel = 1; | |
indent[ListLevel] = RLENGTH; | |
Open[ListLevel]=match(st, /^[[:space:]]*[*+-][[:space:]]*/)?"ul":"ol"; | |
push(Open[ListLevel]); | |
res = res filter(st); | |
} else if(match(st, /^[[:space:]]*$/)) { | |
if(trim(Buf)) { | |
res = tag("p", scrub(trim(Buf))); | |
Buf = ""; | |
} | |
} else | |
Buf = Buf st "\n"; | |
} else if(Mode == "blockquote") { | |
if(match(st, /^[[:space:]]*>[[:space:]]*$/)) | |
Buf = Buf "\n</p><p>"; | |
else if(match(st, /^[[:space:]]*>/)) | |
Buf = Buf "\n" scrub(trim(substr(st, RSTART+RLENGTH))); | |
else if(match(st, /^[[:space:]]*$/)) { | |
res = tag("blockquote", tag("p", trim(Buf))); | |
pop(); | |
res = res filter(st); | |
} else | |
Buf = Buf st; | |
} else if(Mode == "pre") { | |
if(!preterm && match(st, /^(( )| *\t)/) || preterm && !match(st, /^[[:space:]]*```/)) | |
Buf = Buf ((Buf)?"\n":"") substr(st, RSTART+RLENGTH); | |
else { | |
gsub(/\t/," ",Buf); | |
if(length(trim(Buf)) > 0) | |
res = tag("pre", tag("code", escape(Buf))); | |
pop(); | |
if(preterm) sub(/^[[:space:]]*```/,"",st); | |
res = res filter(st); | |
} | |
} else if(Mode == "ul" || Mode == "ol") { | |
if(ListLevel == 0 || match(st, /^[[:space:]]*$/) && (RLENGTH < indent[1] || RLENGTH == 0)) { | |
while(ListLevel > 1) | |
Buf = Buf "\n</" Open[ListLevel--] ">"; | |
res = tag(Mode, "\n" Buf "\n"); | |
pop(); | |
} else { | |
if(match(st, /^[[:space:]]*([*+-]|[[:digit:]]+\.)/)) { | |
tmp = substr(st, RLENGTH+1); | |
match(st, /^[[:space:]]*/); | |
if(RLENGTH > indent[ListLevel]) { | |
indent[++ListLevel] = RLENGTH; | |
if(match(st, /^[[:space:]]*[*+-]/)) | |
Open[ListLevel] = "ul"; | |
else | |
Open[ListLevel] = "ol"; | |
Buf = Buf "\n<" Open[ListLevel] ">"; | |
} else while(RLENGTH < indent[ListLevel]) | |
Buf = Buf "\n</" Open[ListLevel--] ">"; | |
if(match(tmp,/^[[:space:]]*\[[xX[:space:]]?\]/)) { | |
st = substr(tmp,RLENGTH+1); | |
tmp = tolower(substr(tmp,RSTART,RLENGTH)); | |
Buf = Buf "<li><input type=\"checkbox\" " (index(tmp,"x")?"checked":"") " disabled>" scrub(st); | |
} else | |
Buf = Buf "<li>" scrub(tmp); | |
} else if(match(st, /^[[:space:]]*$/)){ | |
Buf = Buf "<br>\n"; | |
} else { | |
sub(/^[[:space:]]+/,"",st); | |
Buf = Buf "\n" scrub(st); | |
} | |
} | |
} | |
prev = st; | |
return res; | |
} | |
function scrub(st, mp, ms, me, r, p, tg, a) { | |
sub(/ $/,"<br>\n",st); | |
gsub(/( |[[:space:]]+\\)\n/,"<br>\n",st); | |
while(match(st, /(__?|\*\*?|~~|`+|[&><\\])/)) { | |
a = substr(st, 1, RSTART-1); | |
mp = substr(st, RSTART, RLENGTH); | |
ms = substr(st, RSTART-1,1); | |
me = substr(st, RSTART+RLENGTH, 1); | |
p = RSTART+RLENGTH; | |
if(!classic_underscore && match(mp,/_+/)) { | |
if(match(ms,/[[:alnum:]]/) && match(me,/[[:alnum:]]/)) { | |
tg = substr(st, 1, index(st, mp)); | |
r = r tg; | |
st = substr(st, index(st, mp) + 1); | |
continue; | |
} | |
} | |
st = substr(st, p); | |
r = r a; | |
ms = ""; | |
if(mp == "\\") { | |
if(match(st, /^!?\[/)) { | |
r = r "\\" substr(st, RSTART, RLENGTH); | |
st = substr(st, 2); | |
} else if(match(st, /^(\*\*|__|~~|`+)/)) { | |
r = r substr(st, 1, RLENGTH); | |
st = substr(st, RLENGTH+1); | |
} else { | |
r = r substr(st, 1, 1); | |
st = substr(st, 2); | |
} | |
continue; | |
} else if(mp == "_" || mp == "*") { | |
if(match(me,/[[:space:]]/)) { | |
r = r mp; | |
continue; | |
} | |
p = index(st, mp); | |
while(p && match(substr(st, p-1, 1),/[\\[:space:]]/)) { | |
ms = ms substr(st, 1, p-1) mp; | |
st = substr(st, p + length(mp)); | |
p = index(st, mp); | |
} | |
if(!p) { | |
r = r mp ms; | |
continue; | |
} | |
ms = ms substr(st,1,p-1); | |
r = r itag("em", scrub(ms)); | |
st = substr(st,p+length(mp)); | |
} else if(mp == "__" || mp == "**") { | |
if(match(me,/[[:space:]]/)) { | |
r = r mp; | |
continue; | |
} | |
p = index(st, mp); | |
while(p && match(substr(st, p-1, 1),/[\\[:space:]]/)) { | |
ms = ms substr(st, 1, p-1) mp; | |
st = substr(st, p + length(mp)); | |
p = index(st, mp); | |
} | |
if(!p) { | |
r = r mp ms; | |
continue; | |
} | |
ms = ms substr(st,1,p-1); | |
r = r itag("strong", scrub(ms)); | |
st = substr(st,p+length(mp)); | |
} else if(mp == "~~") { | |
p = index(st, mp); | |
if(!p) { | |
r = r mp; | |
continue; | |
} | |
while(p && substr(st, p-1, 1) == "\\") { | |
ms = ms substr(st, 1, p-1) mp; | |
st = substr(st, p + length(mp)); | |
p = index(st, mp); | |
} | |
ms = ms substr(st,1,p-1); | |
r = r itag("del", scrub(ms)); | |
st = substr(st,p+length(mp)); | |
} else if(match(mp, /`+/)) { | |
p = index(st, mp); | |
if(!p) { | |
r = r mp; | |
continue; | |
} | |
ms = substr(st,1,p-1); | |
r = r itag("code", escape(ms)); | |
st = substr(st,p+length(mp)); | |
} else if(mp == ">") { | |
r = r ">"; | |
} else if(mp == "<") { | |
p = index(st, ">"); | |
if(!p) { | |
r = r "<"; | |
continue; | |
} | |
tg = substr(st, 1, p - 1); | |
if(match(tg,/^[[:alpha:]]+[[:space:]]/)) { | |
a = substr(tg,RSTART+RLENGTH-1); | |
tg = substr(tg,1,RLENGTH-1); | |
} else | |
a = ""; | |
if(match(tolower(tg), "^/?(a|abbr|div|span|blockquote|pre|img|code|p|em|strong|sup|sub|del|ins|s|u|b|i|br|hr|ul|ol|li|table|thead|tfoot|tbody|tr|th|td|caption|column|col|colgroup|figure|figcaption|dl|dd|dt|mark|cite|q|var|samp|small)$")) { | |
r = r "<" tg a ">"; | |
} else if(match(tg, "^[[:alpha:]]+://[[:graph:]]+$")) { | |
if(!a) a = tg; | |
r = r "<a href=\"" tg "\">" a "</a>"; | |
} else if(match(tg, "^[[:graph:]]+@[[:graph:]]+$")) { | |
if(!a) a = tg; | |
r = r "<a href=\"" obfuscate("mailto:" tg) "\">" obfuscate(a) "</a>"; | |
} else { | |
r = r "<"; | |
continue; | |
} | |
st = substr(st, p + 1); | |
} else if(mp == "&") { | |
if(match(st, /^[#[:alnum:]]+;/)) { | |
r = r "&" substr(st, 1, RLENGTH); | |
st = substr(st, RLENGTH+1); | |
} else { | |
r = r "&"; | |
} | |
} | |
} | |
return r st; | |
} | |
function push(newmode) {Stack[StackTop++] = Mode; Mode = newmode;} | |
function pop() {Mode = Stack[--StackTop];Buf = ""; return Mode;} | |
function heading(level, st, res, href) { | |
st = trim(st); | |
if(level > 6) level = 6; | |
href = tolower(st); | |
href = strip_tags(href); | |
gsub(/[^ [:alnum:]]+/, "", href); | |
gsub(/ +/, "-", href); | |
LinkUrls[href] = "#" href; | |
LinkUrls[tolower(st)] = "#" href; | |
res = tag("h" level, st (TopLinks?" <a class=\"top\" title=\"Return to top\" href=\"#\">↑ Top</a>":""), "id=\"" href "\""); | |
for(;ToCLevel < level; ToCLevel++) | |
ToC = ToC "<ul class=\"toc-" level "\">"; | |
for(;ToCLevel > level; ToCLevel--) | |
ToC = ToC "</ul>"; | |
ToC = ToC "<li class=\"toc-" level "\"><a class=\"toc-" level "\" href=\"#" href "\">" st "</a>\n"; | |
ToCLevel = level; | |
return res; | |
} | |
function make_toc(st, r,p,dis,t,n) { | |
if(!ToC) return st; | |
for(;ToCLevel > 1;ToCLevel--) | |
ToC = ToC "</ul>"; | |
p = match(st, /!\[toc[-+]?\]/); | |
while(p) { | |
++n; | |
dis = index(substr(st,RSTART,RLENGTH),"+"); | |
t = "<div>\n<small><a id=\"toc-button\" onclick=\"toggle_toc(" n ")\"><span id=\"btn-text\">" (dis?"[-]":"[+]") "</span> Contents</a></small>\n" \ | |
"<div id=\"table-of-contents-" n "\" style=\"display:" (dis?"block":"none") ";\">\n<ul class=\"toc-1\">" ToC "</ul>\n</div>\n</div>"; | |
r = r substr(st,1,RSTART-1); | |
if(substr(st,RSTART-1,1) != "\\") | |
r = r t; | |
else | |
r = substr(r,1,length(r)-1) substr(st,RSTART,RLENGTH); | |
st = substr(st,RSTART+RLENGTH); | |
p = match(st, /!\[toc[-+]?\]/); | |
} | |
return r st; | |
} | |
function fix_links(st, lt,ld,lr,url,img,res,rx,pos) { | |
do { | |
pos = match(st, /\[[^\]]+\]/); | |
if(!pos)break; | |
img=substr(st,RSTART-1,1)=="!"; | |
if(substr(st, RSTART-(img?2:1),1)=="\\") { | |
res = res substr(st,1,RSTART-(img?3:2)); | |
if(img && substr(st,RSTART,RLENGTH)=="[toc]")res=res "\\"; | |
res = res substr(st,RSTART-(img?1:0),RLENGTH+(img?1:0)); | |
st = substr(st, RSTART + RLENGTH); | |
continue; | |
} | |
res = res substr(st, 1, RSTART-(img?2:1)); | |
rx = substr(st, RSTART, RLENGTH); | |
st = substr(st, RSTART+RLENGTH); | |
if(match(st, /^[[:space:]]*\([^)]+\)/)) { | |
lt = substr(rx, 2, length(rx) - 2); | |
match(st, /\([^)]+\)/); | |
url = substr(st, RSTART+1, RLENGTH-2); | |
st = substr(st, RSTART+RLENGTH); | |
ld = ""; | |
if(match(url,/[[:space:]]+["']/)) { | |
ld = url; | |
url = substr(url, 1, RSTART - 1); | |
match(ld,/["']/); | |
delim = substr(ld, RSTART, 1); | |
if(match(ld,delim ".*" delim)) | |
ld = substr(ld, RSTART+1, RLENGTH-2); | |
} else ld = ""; | |
if(img) | |
res = res "<img src=\"" url "\" title=\"" ld "\" alt=\"" lt "\">"; | |
else | |
res = res "<a href=\"" url "\" title=\"" ld "\">" lt "</a>"; | |
} else if(match(st, /^[[:space:]]*\[[^\]]*\]/)) { | |
lt = substr(rx, 2, length(rx) - 2); | |
match(st, /\[[^\]]*\]/); | |
lr = trim(tolower(substr(st, RSTART+1, RLENGTH-2))); | |
if(!lr) { | |
lr = tolower(trim(lt)); | |
if(LinkDescs[lr]) lt = LinkDescs[lr]; | |
} | |
st = substr(st, RSTART+RLENGTH); | |
url = LinkUrls[lr]; | |
ld = LinkDescs[lr]; | |
if(img) | |
res = res "<img src=\"" url "\" title=\"" ld "\" alt=\"" lt "\">"; | |
else | |
res = res "<a href=\"" url "\" title=\"" ld "\">" lt "</a>"; | |
} else | |
res = res (img?"!":"") rx; | |
} while(pos > 0); | |
return res st; | |
} | |
function fix_footnotes(st, r,p,n,i,d,fn,fc) { | |
p = match(st, /\[\^[^\]]+\]/); | |
while(p) { | |
r = r substr(st,1,RSTART-1); | |
d = substr(st,RSTART+2,RLENGTH-3); | |
n = tolower(d); | |
st = substr(st,RSTART+RLENGTH); | |
if(Footnote[tolower(n)]) { | |
if(!fn[n]) fn[n] = ++fc; | |
d = Footnote[n]; | |
} else { | |
Footnote[n] = scrub(d); | |
if(!fn[n]) fn[n] = ++fc; | |
} | |
footname[fc] = n; | |
d = strip_tags(d); | |
if(length(d) > 20) d = substr(d,1,20) "…"; | |
r = r "<sup title=\"" d "\"><a href=\"#footnote-" fn[n] "\" id=\"footnote-pos-" fn[n] "\" class=\"footnote\">[" fn[n] "]</a></sup>"; | |
p = match(st, /\[\^[^\]]+\]/); | |
} | |
for(i=1;i<=fc;i++) | |
footnotes = footnotes "<li id=\"footnote-" i "\">" Footnote[footname[i]] \ | |
"<a title=\"Return to Document\" class=\"footnote-back\" href=\"#footnote-pos-" i \ | |
"\"> ↶ Back</a></li>\n"; | |
return r st; | |
} | |
function fix_abbrs(str, st,k,r,p) { | |
for(k in Abbrs) { | |
r = ""; | |
st = str; | |
t = escape(Abbrs[toupper(k)]); | |
gsub(/&/,"\\&", t); | |
p = match(st,"[^[:alnum:]]" k "[^[:alnum:]]"); | |
while(p) { | |
r = r substr(st, 1, RSTART); | |
r = r "<abbr title=\"" t "\">" k "</abbr>"; | |
st = substr(st, RSTART+RLENGTH-1); | |
p = match(st,"[^[:alnum:]]" k "[^[:alnum:]]"); | |
} | |
str = r st; | |
} | |
return str; | |
} | |
function tag(t, body, attr) { | |
if(attr) | |
attr = " " trim(attr); | |
# https://www.w3.org/TR/html5/grouping-content.html#the-p-element | |
if(t == "p" && (match(body, /<\/?(div|table|blockquote|dl|ol|ul|h[[:digit:]]|hr|pre)[>[:space:]]/))|| (match(body,/!\[toc\]/) && substr(body, RSTART-1,1) != "\\")) | |
return "<" t attr ">" body "\n"; | |
else | |
return "<" t attr ">" body "</" t ">\n"; | |
} | |
function itag(t, body) { | |
return "<" t ">" body "</" t ">"; | |
} | |
function obfuscate(e, r,i,t,o) { | |
for(i = 1; i <= length(e); i++) { | |
t = substr(e,i,1); | |
r = int(rand() * 100); | |
if(r > 50) | |
o = o sprintf("&#x%02X;", _ord[t]); | |
else if(r > 10) | |
o = o sprintf("&#%d;", _ord[t]); | |
else | |
o = o t; | |
} | |
return o; | |
} | |
function bright(c,a ,r,g,b) { | |
sub(/^#/,"",c); | |
r = 255*a + _hex[toupper(substr(c,1,2))]*(1-a); | |
g = 255*a + _hex[toupper(substr(c,3,2))]*(1-a); | |
b = 255*a + _hex[toupper(substr(c,5,2))]*(1-a); | |
return sprintf("#%02X%02X%02X",r>255?255:r,g>255?255:g,b>255?255:b); | |
} | |
function init_css(Theme, css,ss,hr,c1,c2,c3,c4,c5,bg1,bg2,bg3,bg4,ff,i) { | |
if(Theme == "0") return ""; | |
css["body"] = "color:%color1%;font-family:%font-family%;line-height:1.5em;" \ | |
"padding:1em 2em;width:80%;max-width:%maxwidth%;margin:0 auto;min-height:100%;float:none;"; | |
css["h1"] = "color:%color1%;border-bottom:1px solid %background1%;padding:0.3em 0.1em;"; | |
css["h2"] = "color:%color2%;border-bottom:1px solid %background2%;padding:0.2em 0.1em;"; | |
css["h3"] = "color:%color3%;border-bottom:1px solid %background3%;padding:0.1em 0.1em;"; | |
css["h4,h5,h6"] = "color:%color4%;padding:0.1em 0.1em;"; | |
css["h1,h2,h3,h4,h5,h6"] = "font-weight:normal;line-height:1.2em;"; | |
css["h4"] = "border-bottom:1px solid %background4%"; | |
css["p"] = "margin:0.5em 0.1em;" | |
css["hr"] = "background:%hr%;height:1px;border:0;" | |
css["a"] = "color:%color2%;"; | |
css["a:visited"] = "color:%color2%;"; | |
css["a:active"] = "color:%color4%;"; | |
css["a:hover"] = "color:%color4%;"; | |
css["a.top"] = "font-size:x-small;text-decoration:initial;float:right;"; | |
css["strong,b"] = "color:%color1%"; | |
css["code"] = "color:%color2%;"; | |
css["blockquote"] = "margin-left:1em;color:%color2%;background:%color5%;border-left:0.2em solid %color3%;border-radius:3px;padding:0.25em 0.5em;"; | |
css["pre"] = "color:%color2%;background:%color5%;border-radius:5px;line-height:1.25em;margin:0.25em 0.5em;padding:0.75em;"; | |
css["table"] = "border-collapse:collapse;margin:0.5em;"; | |
css["th,td"] = "padding:0.5em 0.75em;border:1px solid %color4%;"; | |
css["th"] = "color:%color2%;border:1px solid %color3%;border-bottom:2px solid %color3%;"; | |
css["tr:nth-child(odd)"] = "background-color:%color5%;"; | |
css["div"] = "padding:0.5em;"; | |
css["caption"] = "padding:0.5em;font-style:italic;"; | |
css["dl"] = "margin:0.5em;"; | |
css["dt"] = "font-weight:bold;"; | |
css["dd"] = "padding:0.3em;"; | |
css["mark"] = "color:%color2%;background-color:%color5%;"; | |
css["del,s"] = "color:%color4%;"; | |
css["a#toc-button"] = "color:%color3%;background:%color5%;cursor:pointer;font-size:small;padding: 0.3em 0.5em 0.5em 0.5em;font-family:monospace;border-radius:3px;"; | |
css["a#toc-button:hover"] = "color:%color5%;background:%color3%;"; | |
css["div#table-of-contents"] = "padding:0;font-size:smaller;"; | |
css["abbr"] = "cursor:help;"; | |
css["ol.footnotes"] = "font-size:small;color:%color4%"; | |
css["a.footnote"] = "font-size:smaller;text-decoration:initial;"; | |
css["a.footnote-back"] = "text-decoration:initial;font-size:x-small;"; | |
css[".fade"] = "color:%color5%;"; | |
css[".highlight"] = "color:%color2%;background-color:%color5%;"; | |
if(Theme==2){ | |
c1="#303F9F";c2="#0449CC";c3="#2162FA";c4="#4B80FB";c5="#EDF2FF"; | |
ff="\"Trebuchet MS\", Helvetica, sans-serif"; | |
} else if(Theme==3){ | |
c1="#430005";c2="#740009";c3="#A6373F";c4="#c55158";c5="#fbf2f2"; | |
ff="Verdana, Geneva, sans-serif"; | |
} else if(Theme==4){ | |
c1="#083900";c2="#0D6300";c3="#3C8D2F";c4="#50be3f";c5="#f2faf1"; | |
ff="Georgia, serif"; | |
} else if(Theme==5){ | |
c1="#453700";c2="#775F00";c3="#AA9339";c4="#c7b057";c5="#fbf9f2"; | |
ff="Tahoma, Geneva, sans-serif"; | |
} else if(Theme==6){ | |
c1="#315067";c2="#4F9E9C";c3="#77AD93";c4="#95CE94";c5="#F6FFEE"; | |
ff="Verdana, sans-serif;"; | |
} else if(Theme==7){ | |
c1="#35305D";c2="#646379";c3="#7A74A5";c4="#646392";c5="#fafafa"; | |
} else if(Theme==8){ | |
c1="#215FC2";c2="#D49095";c3="#AD90D4";c4="#90D4CF";c5="#F7FDEF"; | |
} else { | |
c1="#092859";c2="#1351b5";c3="#d47034";c4="#DC7435";c5="#F6F8FF"; | |
} | |
if(!ff) ff = "sans-serif" | |
for(i = 0; i<=255; i++)_hex[sprintf("%02X",i)]=i; | |
bg1 = bright(c1,0.5); | |
bg2 = bright(c2,0.5); | |
bg3 = bright(c3,0.5); | |
bg4 = bright(c3,0.75); | |
hr = bright(c1,0.75); | |
for(k in css) | |
ss = ss "\n" k "{" css[k] "}"; | |
gsub(/%maxwidth%/,MaxWidth,ss); | |
gsub(/%color1%/,c1,ss); | |
gsub(/%color2%/,c2,ss); | |
gsub(/%color3%/,c3,ss); | |
gsub(/%color4%/,c4,ss); | |
gsub(/%color5%/,c5,ss); | |
gsub(/%background1%/,bg1,ss); | |
gsub(/%background2%/,bg2,ss); | |
gsub(/%background3%/,bg3,ss); | |
gsub(/%background4%/,bg4,ss); | |
gsub(/%font-family%/,ff,ss); | |
gsub(/%hr%/,hr,ss); | |
return ss; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Like the Un*x `fmt` command, but for markdown. | |
# | |
# It does its best to preserve markdown headings, | |
# lists, pre-formatted code blocks and block quotes. | |
BEGIN { if(!Width) Width = 80; } | |
# Preserve headings | |
/^[[:space:]]*(=|-)+/ { | |
if(Buf) | |
Out = Out Buf "\n" $0 "\n"; | |
else | |
Out = Out $0 "\n"; | |
Buf = ""; | |
next; | |
} | |
# Preformatted text is sent to the output verbatim | |
/^( |\t)+/ && match(last,/^[[:space:]]*$/) { | |
Out = Out $0 "\n"; | |
next; | |
} | |
$0 !~ /^[[:space:]]*$/ && match(last,/^[[:space:]]*$/) { | |
# how much is the current line indented | |
match(str, /^[[:space:]]+/); | |
Indent = substr(str, 1, RLENGTH); | |
} | |
# Blank lines cause blank lines in the output | |
/^[[:space:]]*$/ { | |
# You need to preserve $0 for blank lines in preformatted blocks | |
if(Buf) | |
Out = Out Buf "\n" $0 "\n"; | |
else | |
Out = Out "\n" $0; | |
Buf = ""; | |
last = $0; | |
InList = 0; | |
next; | |
} | |
# Handle every other input line | |
{ last = $0; fmt($0); } | |
# Write output when done | |
END { | |
Out = Out Buf; | |
print Out; | |
} | |
function fmt(str, loc,word,n,indent) { | |
# Get the current line's indentation level. | |
match(str, /^[[:space:]]+/); | |
indent = substr(str, 1, RLENGTH); | |
# Trim leading whitespace | |
str = substr(str, RLENGTH+1); | |
# Lines starting with list item characters | |
# force a line break in the output | |
if(match(str,/^([*+-]|[[:digit:]]\.)/)) { | |
if(Buf) Out = Out Buf "\n"; | |
Buf = ""; | |
# Preserve the indentation in the global Indent | |
# if it is a list that is going to be split. | |
Indent = indent; | |
InList = 1; # remember we're in a list on subsequent calls. | |
} else if(match(str,/^>[[:space:]]+/)) { | |
Indent = indent substr(str, 1, RLENGTH); | |
str = substr(str,RLENGTH+1); | |
} | |
# Current indentation level = global Indent | |
indent = Indent; | |
# This implements the simple algorithm from the wikipedia | |
# https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap | |
# There is a better way. See #Minimum_raggedness on that wiki page. | |
# The C code example on https://www.rosettacode.org/wiki/Word_wrap#C | |
# may actually be easy to port to Awk (the Awk version on that page | |
# implements the greedy algorithm, like I do here). | |
loc = match(str, /[[:space:]]+/); | |
while(loc) { | |
word = substr(str, 1, RSTART-1); | |
n = RSTART+RLENGTH; | |
# Handle forced line breaks | |
if(match(str,/( |[[:space:]]+\\)$/)) { | |
Out = Out str "\n"; | |
n = RSTART+RLENGTH; | |
} else { | |
# If the buffer + the word exceeds the allowed width | |
# then insert a line break. Otherwise, just append the | |
# word to the buffer. | |
# Also, preserve the indentation. | |
if(length(Buf) + length(word) + 1 >= Width) { | |
Out = Out Buf "\n"; | |
if(InList) indent = Indent " "; | |
Buf = indent word; | |
} else if(length(Buf)) | |
Buf = Buf " " word; | |
else | |
Buf = indent word; | |
} | |
str = substr(str, n); | |
loc = match(str, /[[:space:]]+/); | |
} | |
# Append the remainder of str to Buf | |
if(length(str)) { | |
if(length(Buf) + length(str) + 1 >= Width) { | |
Out = Out Buf "\n"; | |
if(InList) indent = Indent " "; | |
Buf = indent str; | |
} else if(length(Buf)) | |
Buf = Buf " " str; | |
else | |
Buf = indent str; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/awk -f | |
# | |
# Extracts the /**-denoted comments from a source file. | |
# | |
# (c) 2016 Werner Stoop | |
# Copying and distribution of this file, with or without modification, | |
# are permitted in any medium without royalty provided the copyright | |
# notice and this notice are preserved. This file is offered as-is, | |
# without any warranty. | |
!in_comment && /\/\*\*/ { | |
in_comment = 1; | |
sub(/\/\*\*/,""); | |
} | |
in_comment && /\*\// { in_comment = 0; } | |
in_comment && /^[[:space:]]*\*/ { | |
sub(/^[[:space:]]*\*/,""); | |
} | |
in_comment { print; } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment