diff options
-rw-r--r-- | .md.md | 5 | ||||
-rw-r--r-- | INSTALL.md | 10 | ||||
-rw-r--r-- | MeTaDaTa.md | 4 | ||||
-rw-r--r-- | README | 12 | ||||
-rw-r--r-- | README.md.md | 1 | ||||
-rwxr-xr-x | SuckIt | 162 | ||||
-rwxr-xr-x | SuckItClean | 13 | ||||
-rwxr-xr-x | SuckItCron | 4 | ||||
-rwxr-xr-x | SuckItFos | 60 | ||||
-rwxr-xr-x | SuckItPm | 63 | ||||
-rw-r--r-- | TODO.md | 101 | ||||
-rw-r--r-- | about/index.md | 8 | ||||
-rw-r--r-- | default.template | 137 | ||||
-rw-r--r-- | empty.md | 1 | ||||
-rwxr-xr-x | feed-icon-14x14.png | bin | 0 -> 689 bytes | |||
-rwxr-xr-x | feed-icon-28x28.png | bin | 0 -> 1737 bytes | |||
-rw-r--r-- | help.md | 43 | ||||
-rw-r--r-- | menu.template | 2 | ||||
-rw-r--r-- | nYAW.png | bin | 12273 -> 16624 bytes | |||
-rw-r--r-- | nYAW.xcf | bin | 20267 -> 25929 bytes | |||
-rwxr-xr-x | notYetAnotherWiki.lua | 1018 | ||||
-rw-r--r-- | testing/.md.md | 1 | ||||
-rw-r--r-- | testing/MeTaDaTa.md | 3 | ||||
-rw-r--r-- | testing/index.md | 114 | ||||
-rw-r--r-- | testing/index.md.md | 1 |
25 files changed, 1349 insertions, 414 deletions
@@ -0,0 +1,5 @@ | |||
1 | favicon=nYAW_icon.png | ||
2 | logo=nYAW.png | ||
3 | sourcecode=https://sledjhamr.org/cgit/notYetAnotherWiki/ | ||
4 | pagehistory=https://sledjhamr.org/cgit/notYetAnotherWiki/log | ||
5 | feedatom=https://sledjhamr.org/cgit/notYetAnotherWiki/atom | ||
@@ -1,13 +1,7 @@ | |||
1 | --- | 1 | # Install |
2 | pagetitle: "INSTALL" | ||
3 | author: onefang | ||
4 | pagehistory: https://sledjhamr.org/cgit/notYetAnotherWiki/log/INSTALL.md | ||
5 | --- | ||
6 | 2 | ||
7 | notYetAnotherWiki uses [lcmark](https://github.com/jgm/lcmark) to parse [CommonMark](https://commonmark.org/) into HTML. You can probably install it using luarocks. lua-yaml is the YAML parsing library I test with. | 3 | notYetAnotherWiki uses [lunamark](https://github.com/jgm/lunamark) to parse [CommonMark](https://commonmark.org/) into HTML. You can probably install it using luarocks. lua-yaml is the YAML parsing library I test with. |
8 | 4 | ||
9 | You also need luajit installed. | 5 | You also need luajit installed. |
10 | 6 | ||
11 | Copy the notYetAnotherWiki.lua script to some place where you can run it from, /usr/local/bin is good. Make sure it is executable. | 7 | Copy the notYetAnotherWiki.lua script to some place where you can run it from, /usr/local/bin is good. Make sure it is executable. |
12 | |||
13 | Similar with the dumpTable.lua script, only it's a Lua library, so put it some place Lua can find it. /usr/local/share/lua is good. No need to be executable. | ||
diff --git a/MeTaDaTa.md b/MeTaDaTa.md deleted file mode 100644 index ab7b673..0000000 --- a/MeTaDaTa.md +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | --- | ||
2 | feedatom: https://sledjhamr.org/cgit/notYetAnotherWiki/atom | ||
3 | sourcecode: https://sledjhamr.org/cgit/notYetAnotherWiki/ | ||
4 | --- | ||
@@ -1,8 +1,4 @@ | |||
1 | --- | 1 | # notYetAnotherWiki |
2 | pagetitle: "notYetAnotherWiki" | ||
3 | author: onefang | ||
4 | pagehistory: https://sledjhamr.org/cgit/notYetAnotherWiki/log/index.md | ||
5 | --- | ||
6 | 2 | ||
7 | notYetAnotherWiki is not another wiki, at least not yet. It'll be much | 3 | notYetAnotherWiki is not another wiki, at least not yet. It'll be much |
8 | more than that, eventually. | 4 | more than that, eventually. |
@@ -63,13 +59,13 @@ the one system. They can chat about it, on the one system. | |||
63 | 59 | ||
64 | ## What does it do already? | 60 | ## What does it do already? |
65 | 61 | ||
66 | Currently it'll scan the current directory and subdirectories looking for | 62 | Currently it'll scan the current folder and sub folders looking for |
67 | .md files in CommonMark syntax. This should cover some MarkDown | 63 | .md files in CommonMark syntax. This should cover some MarkDown |
68 | variations. Then it produces .HTML files converted from these .md files, | 64 | variations. Then it produces .HTML files converted from these .md files, |
69 | and links them all together into a web site. | 65 | and links them all together into a web site. |
70 | 66 | ||
71 | Any .md file that is just the beginning metadata block doesn't get | 67 | Any .md file that is just the beginning metadata block doesn't get |
72 | rendered into HTML, but is global metadata for this directory and subs, | 68 | rendered into HTML, but is global metadata for this folder and subs, |
73 | though the subs can override this with their own metadata.md files. | 69 | though the subs can override this with their own metadata.md files. |
74 | 70 | ||
75 | git is used to store the .md files, and provides edit history. Added on | 71 | git is used to store the .md files, and provides edit history. Added on |
@@ -77,7 +73,7 @@ the footer is links to cgit, which is used to store the files in git on | |||
77 | your server. This provides acces to the source code, history, and ATOM | 73 | your server. This provides acces to the source code, history, and ATOM |
78 | feed for the site. | 74 | feed for the site. |
79 | 75 | ||
80 | It can also scan an external directory and merge that with the current | 76 | It can also scan an external folder and merge that with the current |
81 | one, but this isn't tested yet. | 77 | one, but this isn't tested yet. |
82 | 78 | ||
83 | ## other stuff | 79 | ## other stuff |
diff --git a/README.md.md b/README.md.md new file mode 100644 index 0000000..31ea1e7 --- /dev/null +++ b/README.md.md | |||
@@ -0,0 +1 @@ | |||
title=nYAW | |||
@@ -0,0 +1,162 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | TIMEFORMAT=" took %lR using %P%% CPU" | ||
4 | time { | ||
5 | pushd /opt/nyaw | ||
6 | |||
7 | #rm -fr Foswiki/* | ||
8 | cp -r /opt/nyaw_EMPTY/Foswiki . | ||
9 | #rm -fr PmWiki/* | ||
10 | cp -r /opt/nyaw_EMPTY/PmWiki . | ||
11 | #rm -fr unsorted | ||
12 | mkdir -p unsorted | ||
13 | cp -r /opt/nyaw_EMPTY/unsorted . | ||
14 | #rm -fr users/* | ||
15 | mkdir -p users | ||
16 | cp -r /opt/nyaw_EMPTY/users . | ||
17 | |||
18 | # Copy across things like images that where uploaded. | ||
19 | mkdir -p /opt/nyaw/Foswiki/pub/ | ||
20 | # TODO - Should rsync this instead. | ||
21 | cp -r /opt/Foswiki/pub/Main /opt/nyaw/Foswiki/pub/ | ||
22 | filter=" | ||
23 | -name _default -prune -o \ | ||
24 | -name _empty -prune -o \ | ||
25 | -name System -prune -o \ | ||
26 | -name Trash -prune -o \ | ||
27 | -name TWiki -prune -o \ | ||
28 | " | ||
29 | ogURL="https://fos.wiki.devuan.org" | ||
30 | ogWiki="Foswiki" | ||
31 | time find /opt/Foswiki/data ${filter} \ | ||
32 | -name "*.txt" -type f,l -printf "%P\n" | while read line | ||
33 | do | ||
34 | base=`echo "${line}" | cut -d '/' -f 1` | ||
35 | file=`echo "${line}" | cut -d '/' -f 2- | rev | cut -b 5- | rev` | ||
36 | if [[ ! ${file} =~ (AdminGroup|AdminUser|AdminUserLeftBar|CommentPluginExamples|EditorGroup|GroupTemplate|GroupViewTemplate|NobodyGroup|PatternSkinUserViewTemplate|ProjectContributor|RegistrationAgent|SitePreferences|UnprocessedRegistrations|UnprocessedRegistrationsLog|UserHomepageHeader|UserList|UserListByDateJoined|UserListByLocation|UserList|UserListHeader|WebAtom|WebChanges|WebCreateNewTopic|WebHome|WebIndex|WebLeftBar|WebLeftBarExample|WebNotify|WebPreferences|WebRss|WebSearch|WebSearchAdvanced|WebTopicList|WikiGroups|WikiUsers)$ ]]; then | ||
37 | doit='false' | ||
38 | if [ ! -s ${ogWiki}/${base}/${file}.HTM ]; then | ||
39 | echo "NEW /opt/Foswiki/data/${base}/${file}.txt" | ||
40 | doit='true' | ||
41 | elif [ /opt/Foswiki/data/${base}/${file}.txt -nt ${ogWiki}/${base}/${file}.HTM ]; then | ||
42 | echo "NEWER /opt/Foswiki/data/${base}/${file}.txt" | ||
43 | date --rfc-3339=seconds -ur /opt/Foswiki/data/${base}/${file}.txt | ||
44 | date --rfc-3339=seconds -ur ${ogWiki}/${base}/${file}.HTM | ||
45 | doit='true' | ||
46 | fi | ||
47 | if [[ ${doit} == "true" ]]; then | ||
48 | realURL=${ogWiki}/${base}/${file} | ||
49 | time=`date --rfc-3339=seconds -ur /opt/Foswiki/data/${base}/${file}.txt | cut -d '+' -f 1` | ||
50 | mkdir -p ${ogWiki}/${base} | ||
51 | mkdir -p ${ogWiki}/${base}/`dirname ${file}` | ||
52 | echo -e "ogWiki=${ogWiki}\nogURL=${ogURL}\nrealURL=${realURL}\nogBase=${base}\nogFile=${file}\ntimestamp=${time}\n" > ${ogWiki}/${base}/${file}.md.md | ||
53 | echo "downloading ${ogURL}/${base}/${file}?cover=print" | ||
54 | # Doesn't help with redownloads, coz natch a dynamic site isn't cached. But I can at least comment out the curl command during testing to save time. | ||
55 | curl --silent --no-progress-meter ${ogURL}/${base}/${file}?cover=print -o ${ogWiki}/${base}/${file}.HTM | ||
56 | # Attempt to separate user profiles from user content. Doesn't work when people turn their profiles into content. | ||
57 | dest="" | ||
58 | if [[ "${base}" == "Main" ]]; then | ||
59 | dest="unsorted" | ||
60 | if [ -L users/${file}_fos.md ]; then | ||
61 | dest='users' | ||
62 | fi | ||
63 | mkdir -p `dirname users/${file}` | ||
64 | sed -i -E ${ogWiki}/${base}/${file}.HTM -e "s%<a href=\"/System/UserForm\">UserForm</a>%%w users/${file}_fos.SED" | ||
65 | if [ -s users/${file}_fos.SED ]; then | ||
66 | dest="users" | ||
67 | fi | ||
68 | rm users/${file}_fos.SED >/dev/null 2>&1 | ||
69 | rm -d `dirname users/${file}` >/dev/null 2>&1 | ||
70 | fi | ||
71 | # "Devuan" is only two pages that get sorted. "Sandbox" is a mixture of standard examples, stuff that was copied to PmWiki, and other things that should get unsorted. | ||
72 | # Skipping anything with "<a href="/Main/UnknownUser">UnknownUser</a></span></div>". | ||
73 | if [[ "${base}" == "Sandbox" ]]; then | ||
74 | dest="unsorted" | ||
75 | mkdir -p `dirname users/${file}` | ||
76 | sed -i -E ${ogWiki}/${base}/${file}.HTM -e "s%<a href=\"/Main/UnknownUser\">UnknownUser</a></span></div>%%w users/${file}_fos.SED" | ||
77 | if [ -s users/${file}_fos.SED ]; then | ||
78 | dest="" | ||
79 | fi | ||
80 | rm users/${file}_fos.SED >/dev/null 2>&1 | ||
81 | rm -d `dirname users/${file}` >/dev/null 2>&1 | ||
82 | fi | ||
83 | |||
84 | if [[ "${dest}" != "" ]]; then | ||
85 | mkdir -p `dirname ${dest}/${file}` | ||
86 | realURL=${dest}/${file} | ||
87 | echo -e "ogWiki=${ogWiki}\nogURL=${ogURL}\nrealURL=${realURL}_fos\nogBase=${base}\nogFile=${file}\ntimestamp=${time}\n" > ${ogWiki}/${base}/${file}.md.md | ||
88 | touch ${ogWiki}/${base}/${file}.md | ||
89 | ln -sfr ${ogWiki}/${base}/${file}.md ${dest}/${file}_fos.md | ||
90 | ln -sfr ${ogWiki}/${base}/${file}.md.md ${dest}/${file}_fos.md.md | ||
91 | rm ${ogWiki}/${base}/${file}.md | ||
92 | fi | ||
93 | fi | ||
94 | fi | ||
95 | done | ||
96 | |||
97 | |||
98 | # Copy across things like images that where uploaded. | ||
99 | cp -r /opt/pmwiki/uploads /opt/nyaw/PmWiki/ | ||
100 | filter=" | ||
101 | -not -name "*~" -a \ | ||
102 | -not -name ".flock" -a \ | ||
103 | -not -name ".htaccess" -a \ | ||
104 | -not -name ".lastmod" -a \ | ||
105 | -not -name ".pageindex" -a \ | ||
106 | " | ||
107 | ogURL="https://wiki.devuan.org" | ||
108 | ogWiki="PmWiki" | ||
109 | time find /opt/pmwiki/wiki.d ${filter} \ | ||
110 | -name "*.*" -type f,l -printf "%P\n" | while read line | ||
111 | do | ||
112 | base=`echo "${line}" | cut -d '.' -f 1` | ||
113 | file=`echo "${line}" | cut -d '.' -f 2` | ||
114 | if [[ "${base}" != "Site" ]]; then | ||
115 | doit='false' | ||
116 | if [ ! -s ${ogWiki}/${base}/${file}.HTM ]; then | ||
117 | echo "NEW /opt/pmwiki/wiki.d/${base}.${file} ${ogWiki}/${base}/${file}.HTM" | ||
118 | doit='true' | ||
119 | elif [ /opt/pmwiki/wiki.d/${base}.${file} -nt ${ogWiki}/${base}/${file}.HTM ]; then | ||
120 | echo "NEWER /opt/pmwiki/wiki.d/${base}.${file}" | ||
121 | date --rfc-3339=seconds -ur /opt/pmwiki/wiki.d/${base}.${file} | ||
122 | date --rfc-3339=seconds -ur ${ogWiki}/${base}/${file}.HTM | ||
123 | doit='true' | ||
124 | fi | ||
125 | if [[ ${doit} == "true" ]]; then | ||
126 | realURL=${ogWiki}/${base}/${file} | ||
127 | time=`date --rfc-3339=seconds -ur /opt/pmwiki/wiki.d/${base}.${file} | cut -d '+' -f 1` | ||
128 | mkdir -p ${ogWiki}/${base} | ||
129 | echo -e "ogWiki=${ogWiki}\nogURL=${ogURL}\nrealURL=${realURL}\nogBase=${base}\nogFile=${file}\ntimestamp=${time}\n" > ${ogWiki}/${base}/${file}.md.md | ||
130 | # echo "downloading ${ogURL}/?n=${base}.${file}?action=markdown" | ||
131 | # curl --no-progress-meter ${ogURL}/?n=${base}.${file}?action=markdown -o ${ogWiki}/${base}/${file}.MARKDOWN | ||
132 | echo "downloading ${ogURL}/?n=${base}.${file}?action=print" | ||
133 | curl --no-progress-meter ${ogURL}/?n=${base}.${file}?action=print -o ${ogWiki}/${base}/${file}.HTM | ||
134 | # Seems there's no way to tell user profiles apart from user content. Unless I can find a list of users somewhere. Don't think there is one. | ||
135 | if [[ "${base}" == "Profiles" ]]; then | ||
136 | dest="unsorted" | ||
137 | if [ -L users/${file}_pm.md ]; then | ||
138 | dest='users' | ||
139 | fi | ||
140 | realURL=${dest}/${file} | ||
141 | echo -e "ogWiki=${ogWiki}\nogURL=${ogURL}\nrealURL=${realURL}_pm\nogBase=${base}\nogFile=${file}\ntimestamp=${time}\n" > ${ogWiki}/${base}/${file}.md.md | ||
142 | touch ${ogWiki}/${base}/${file}.md | ||
143 | ln -sfr ${ogWiki}/${base}/${file}.md ${dest}/${file}_pm.md | ||
144 | ln -sfr ${ogWiki}/${base}/${file}.md.md ${dest}/${file}_pm.md.md | ||
145 | rm ${ogWiki}/${base}/${file}.md | ||
146 | fi | ||
147 | fi | ||
148 | |||
149 | # TODO - groups are PmWiki/Onefang and PmWiki/Tiki | ||
150 | |||
151 | # pandoc -f markdown -t commonmark_x --self-contained ${ogWiki}//${base}/${file}.MD >${ogWiki}/${base}/${file}.md | ||
152 | # pandoc -f html -t commonmark_x --self-contained ${ogWiki}//${base}/${file}.HTM >${ogWiki}/${base}/${file}.md | ||
153 | fi | ||
154 | done | ||
155 | |||
156 | |||
157 | time notYetAnotherWiki.lua | ||
158 | # No idea why yet, but needs a second run to sort out everything. Shouldn't take long anyway. | ||
159 | time notYetAnotherWiki.lua | ||
160 | |||
161 | popd | ||
162 | } | ||
diff --git a/SuckItClean b/SuckItClean new file mode 100755 index 0000000..1b8a025 --- /dev/null +++ b/SuckItClean | |||
@@ -0,0 +1,13 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | TIMEFORMAT=" took %lR using %P%% CPU" | ||
4 | time { | ||
5 | pushd /opt/nyaw | ||
6 | |||
7 | rm -fr Foswiki/* | ||
8 | rm -fr PmWiki/* | ||
9 | rm -fr unsorted | ||
10 | rm -fr users/* | ||
11 | popd | ||
12 | ./SuckIt | ||
13 | } | ||
diff --git a/SuckItCron b/SuckItCron new file mode 100755 index 0000000..e817948 --- /dev/null +++ b/SuckItCron | |||
@@ -0,0 +1,4 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | cd /opt/notYetAnotherWiki | ||
4 | ./SuckIt >/dev/null 2>&1 | ||
diff --git a/SuckItFos b/SuckItFos deleted file mode 100755 index f21decc..0000000 --- a/SuckItFos +++ /dev/null | |||
@@ -1,60 +0,0 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | URL="https://fos.wiki.devuan.org" | ||
4 | |||
5 | filter=" | ||
6 | -name _default -prune -o \ | ||
7 | -name _empty -prune -o \ | ||
8 | -name System -prune -o \ | ||
9 | -name Trash -prune -o \ | ||
10 | -name TWiki -prune -o \ | ||
11 | " | ||
12 | |||
13 | pushd /opt/merged | ||
14 | |||
15 | find /opt/Foswiki/data ${filter} \ | ||
16 | -name "*.txt" -type f,l -printf "%P\n" | while read line | ||
17 | do | ||
18 | base=`echo "${line}" | cut -d '/' -f 1` | ||
19 | file=`echo "${line}" | cut -d '/' -f 2- | rev | cut -b 5- | rev` | ||
20 | mkdir -p Foswiki/$base | ||
21 | mkdir -p Foswiki/${base}/`dirname ${file}` | ||
22 | mkdir -p combined/$base | ||
23 | mkdir -p combined/${base}/`dirname ${file}` | ||
24 | echo "Converting ${URL}/${base}/${file} -> Foswiki/${base}/${file}.md" | ||
25 | # pandoc -f html -t markdown --self-contained ${URL}/${base}/${file} >Foswiki/${base}/${file}.md | ||
26 | # TODO - try curl, to see what is actually downloaded, and maybe not download unchanged pages. curl to .HTM | ||
27 | # Doesn't help with redownloads, coz natch a dynamic site isn't cached. But I can at least comment out the curl command during testing to save time. | ||
28 | curl --silent --no-progress-meter ${URL}/${base}/${file} -o Foswiki/${base}/${file}.HTM | ||
29 | pandoc -f html -t commonmark_x --self-contained Foswiki//${base}/${file}.HTM >Foswiki/${base}/${file}.md | ||
30 | ln -frs Foswiki/${base}/${file}.md combined/${base}/${file}.md | ||
31 | cp Foswiki/${base}/${file}.md Foswiki/${base}/${file}.md_ORIGINAL | ||
32 | |||
33 | # csplit -ks Foswiki/${base}/${file}.md '%::: foswikiTopic%' '/::: foswikiContentFooter/' | ||
34 | # if [ -f xx00 ]; then | ||
35 | # rm Foswiki/${base}/${file}.md | ||
36 | # mv xx00 Foswiki/${base}/${file}.md | ||
37 | # fi | ||
38 | |||
39 | # Attempt to clean things up, badly. | ||
40 | sed -i -E Foswiki/${base}/${file}.md \ | ||
41 | -e 's/\$/\$dlr\$/g' \ | ||
42 | -e 's/\{#.*\}//g' \ | ||
43 | -e 's/\{\.foswiki.*\}//g' \ | ||
44 | -e 's/\{\.foswiki.*//g' \ | ||
45 | -e 's/\{\.foswikiNewLink rel=“nofollow”\}//g' \ | ||
46 | -e 's/\{\.foswikiNewLink$//g' \ | ||
47 | -e 's/^\.foswiki.*\}//g' \ | ||
48 | -e 's/\{\.pattern.*\}//g' \ | ||
49 | -e 's/\{\.pattern.*//g' \ | ||
50 | -e 's/\{rel="nofollow"\}//g' \ | ||
51 | -e 's/^rel="nofollow"\}//g' \ | ||
52 | -e 's/rel=“nofollow”\}$//g' \ | ||
53 | -e '/^:::/d' | ||
54 | |||
55 | echo "<hr/><p><a href=\"${URL}/${base}/${file}\">Original page</a> where you can edit it.</p>" >> Foswiki/${base}/${file}.md | ||
56 | done | ||
57 | |||
58 | notYetAnotherWiki.lua | ||
59 | |||
60 | popd | ||
diff --git a/SuckItPm b/SuckItPm deleted file mode 100755 index 6a30373..0000000 --- a/SuckItPm +++ /dev/null | |||
@@ -1,63 +0,0 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | URL="https://wiki.devuan.org" | ||
4 | |||
5 | filter=" | ||
6 | -not -name "*~" -a \ | ||
7 | -not -name ".flock" -a \ | ||
8 | -not -name ".htaccess" -a \ | ||
9 | -not -name ".lastmod" -a \ | ||
10 | -not -name ".pageindex" -a \ | ||
11 | " | ||
12 | |||
13 | pushd /opt/merged | ||
14 | |||
15 | find /opt/pmwiki/wiki.d ${filter} \ | ||
16 | -name "*.*" -type f,l -printf "%P\n" | while read line | ||
17 | do | ||
18 | base=`echo "${line}" | cut -d '.' -f 1` | ||
19 | file=`echo "${line}" | cut -d '.' -f 2` | ||
20 | mkdir -p PmWiki/$base | ||
21 | mkdir -p combined/$base | ||
22 | echo "Converting ${URL}/?n=${base}.${file} -> PmWiki/${base}/${file}.md" | ||
23 | # pandoc -f html -t markdown --self-contained ${URL}/?n=${base}.${file} >PmWiki/${base}/${file}.md | ||
24 | # TODO - try curl, to see what is actually downloaded, and maybe not download unchanged pages. curl to .HTM | ||
25 | # Doesn't help with redownloads, coz natch a dynamic site isn't cached. But I can at least comment out the curl command during testing to save time. | ||
26 | curl --no-progress-meter ${URL}/?n=${base}.${file} -o PmWiki/${base}/${file}.HTM | ||
27 | pandoc -f html -t commonmark_x --self-contained PmWiki//${base}/${file}.HTM >PmWiki/${base}/${file}.md | ||
28 | ln -frs PmWiki/${base}/${file}.md combined/${base}/${file}.md | ||
29 | cp PmWiki/${base}/${file}.md PmWiki/${base}/${file}.md_ORIGINAL | ||
30 | |||
31 | # csplit -ks PmWiki/${base}/${file}.md '/trailstart/' '/trailend/' | ||
32 | csplit -ks PmWiki/${base}/${file}.md '%::: {#wikitext}%' | ||
33 | if [ -f xx00 ]; then | ||
34 | rm PmWiki/${base}/${file}.md | ||
35 | mv xx00 PmWiki/${base}/${file}.md | ||
36 | fi | ||
37 | |||
38 | # Attempt to clean things up, badly. | ||
39 | sed -i -E PmWiki/${base}/${file}.md \ | ||
40 | -e 's/\$/\$dlr\$/g' \ | ||
41 | -e 's/\{#.*\}//g' \ | ||
42 | -e '/\{\.wikilink\}/d' \ | ||
43 | -e '/\[Site$/d' \ | ||
44 | -e '/^:::/d' \ | ||
45 | -e '/^Page last modified on /d' \ | ||
46 | -e '/^\[\]/d' \ | ||
47 | -e 's/\{rel=".*\}//g' \ | ||
48 | -e 's/\{rel="nofollow"$//g' \ | ||
49 | -e 's/^rel="nofollow"\}//g' \ | ||
50 | -e 's/^target="_blank"\}//g' \ | ||
51 | -e 's/\{\.createlinktext.*\}//g' \ | ||
52 | -e 's/\{\.createlinktext$//g' \ | ||
53 | -e 's/\{\.createlink.*\}//g' \ | ||
54 | -e 's/\{\.createlink$//g' \ | ||
55 | -e 's/\{\.urllink.*\}//g' \ | ||
56 | -e 's/\{\.urllink$//g' | ||
57 | |||
58 | echo "<hr/><p><a href=\"${URL}/?n=${base}.${file}\">Original page</a> where you can edit it.</p>" >> PmWiki/${base}/${file}.md | ||
59 | done | ||
60 | |||
61 | notYetAnotherWiki.lua | ||
62 | |||
63 | popd | ||
@@ -1,37 +1,100 @@ | |||
1 | --- | 1 | # TODO |
2 | pagetitle: "TODO" | 2 | |
3 | author: onefang | 3 | Make it perphekd! |
4 | pagehistory: https://sledjhamr.org/cgit/notYetAnotherWiki/log/TODO.md | 4 | |
5 | --- | ||
6 | ## Do these | 5 | ## Do these |
7 | 6 | ||
8 | Deal with complex directory trees. | 7 | Convert it to polygLua. |
9 | - /testing/even should display as even/deeper on the testing page, coz even/ has no files, but even/deeper does. | 8 | |
10 | - Scanning /usr/share/doc on my super desktop with looots of software installed will be fun. | 9 | It's all a bit too fragile, fix what I can. Too many messes colliding. |
10 | |||
11 | Flock it. | ||
12 | |||
13 | Some sort of search system. | ||
14 | |||
15 | A member system, and edit / manage system for their pages. | ||
16 | |||
17 | Fix up linky conversion. DONE, mostly. | ||
18 | |||
19 | - Need to deal with real file name versus title. Also symlink name not matching what it points to. | ||
20 | |||
21 | Use the default.template that comes with nYAW if none is availaable. | ||
22 | |||
23 | "collapsing headings" I guess that means click on a heading to hide / show the content under that heading. | ||
24 | |||
25 | - 🙈 | ||
26 | - Should do that for the main content and the menu TOC. | ||
27 | - Also allow editing just a section, a section being the bits between one heading and the next. | ||
28 | - + 📝 ✒️✏️🖊️🖋 🖌️🖍️ | ||
29 | - + When someone starts editing, create pagename_draft.md and .HTML, and update those when they want to see a preview. | ||
30 | - + Or pagename-heading_draft.md | ||
31 | - + Use that draft.md file as a lock on editing that file / section. | ||
32 | - + Have the hourly cron job remove any stale ones. | ||
33 | |||
34 | Add ATOM feed for single page. Alas cgit only seems to have ATOM feed on the whole repo, not individual files. | ||
35 | |||
36 | - However, once timestamps are sorted, I can use that code to generate RSS and ATOM feeds, and create page histories using diffs. | ||
37 | - Instead of an hourly cron job to update everything, see if I can hook | ||
38 | into Fos and Pm edit form's save function. So when they save in the | ||
39 | original wiki, the nyaw version gets updated, diffed, and ATOMed / RSSed. | ||
40 | - + Actually a BFI method might do the trick, stick with doing a full scan | ||
41 | and only updating the stuff that needs it, likely that's only the page that just got saved. | ||
42 | - git commit can have an arbitrary author / committer, so I can use that to make sure the person that actually made the change gets author / committer. | ||
43 | - + There's also the email thing, but I don't want to spread email addresses around, not even sure we have them anyway. | ||
44 | - Should also see if gitea can handle that, and if they want wiki content saved to git. | ||
45 | |||
46 | Syntax highlighting in code blocks. The highlight package looks promising, already had it installed on my desktop. | ||
11 | 47 | ||
12 | Check the timestamps on the files, only update if source is newer than destination. Meh, it's already 600 times faster than the pandoc version. | 48 | ## Some ideas |
13 | - One quirk to watch for is if a URL path changes, the docs that have that URL need to be redone. | ||
14 | - pandoc is a lot slower though, so do this for sure when dealing with that. | ||
15 | - When scraping the web sites, they tend to be dynamically generated with no useful timestamp on them. | ||
16 | 49 | ||
17 | Add atom feed for single page. Alas cgit only seems to have ATOM feed on the whole repo, not individual files. | 50 | Mostly from something chomwitt wrote - |
18 | 51 | ||
52 | - "validation", not sure exactly what that would validate. | ||
53 | - I'll just quote some of the rest - | ||
54 | |||
55 | ~~~ | ||
56 | !!! co-editing | ||
57 | The toolbar should contain tools that facilitate : | ||
58 | * intergration (to other workflows) | ||
59 | ** for example search-completion to other workflows names-tags. | ||
60 | ~~~ | ||
61 | |||
62 | - Allow default.template files in sub folders. | ||
63 | - Might be useful to automatically convert anything looking like a URL into a linky. | ||
64 | |||
65 | Automate symlinks. | ||
66 | |||
67 | - any .md.md file should be linked along with it's matching .md file if it's outside of Foswiki/ and PmWiki/. | ||
19 | 68 | ||
20 | 69 | ||
21 | ## Try out | 70 | ## Try out |
22 | 71 | ||
23 | htmx | 72 | lua-lpeg-patterns might be useful |
73 | |||
74 | lua-luxio might be the wheel I'm reinventing? | ||
75 | |||
76 | lua-wsapi-fcgi | ||
24 | 77 | ||
25 | pandoc replacements | 78 | https://inclusive-components.design/tooltips-toggletips/ has some ideas about the "tooltip" HTML attribute, and what to do about it. A rabbit hole that ends in javascript, but might be useful up to that point. |
26 | - cmark-gfm | 79 | |
80 | htmx | ||
27 | 81 | ||
28 | cgit has Lua | 82 | cgit has Lua |
29 | 83 | ||
84 | lua-gall for git stuff | ||
85 | |||
86 | lua-lace for access control | ||
87 | |||
88 | lua-unbound | ||
30 | 89 | ||
31 | 90 | ||
32 | ## User system | 91 | ## Member system |
92 | |||
93 | Reuse the member system from SledjChisl. | ||
33 | 94 | ||
34 | levels - | 95 | levels - |
96 | |||
97 | - everyone | ||
35 | - banned | 98 | - banned |
36 | - reader | 99 | - reader |
37 | - member | 100 | - member |
@@ -41,6 +104,8 @@ levels - | |||
41 | - shell | 104 | - shell |
42 | - root | 105 | - root |
43 | 106 | ||
107 | Everyone can read the pages, no need for an account. | ||
108 | |||
44 | Banned people can't do squat, except maybe pester an admin once to start the unbanning process. | 109 | Banned people can't do squat, except maybe pester an admin once to start the unbanning process. |
45 | 110 | ||
46 | When first registered, accounts are set to reader level. | 111 | When first registered, accounts are set to reader level. |
@@ -67,6 +132,6 @@ site, including configuration and modules. Likely this is the person | |||
67 | that set the system up in the first place. | 132 | that set the system up in the first place. |
68 | 133 | ||
69 | Admin should have access to everything that shell level has, but there's always things need tweaking at some lower level. | 134 | Admin should have access to everything that shell level has, but there's always things need tweaking at some lower level. |
70 | Built in file browser might do the trick. Would be useful for content creators to to organise the content. Naturally should obey the permisisons. | 135 | Built in file browser might do the trick. Would be useful for content creators to organise the content. Naturally should obey the permissions. |
71 | 136 | ||
72 | root level is whoever controls the server things are running on. They can do anything at all. | 137 | root level is whoever controls the server things are running on. They can do anything at all. |
diff --git a/about/index.md b/about/index.md index aa3be9f..3f15be7 100644 --- a/about/index.md +++ b/about/index.md | |||
@@ -1,9 +1,5 @@ | |||
1 | --- | 1 | # notYetAnotherWiki is not another wiki, at least not yet. It'll be much more than that, eventually. |
2 | pagetitle: "notYetAnotherWiki is not another wiki, at least not yet. It'll be much more than that, eventually." | ||
3 | author: onefang | ||
4 | pagehistory: https://sledjhamr.org/cgit/notYetAnotherWiki/log/About/index.md | ||
5 | --- | ||
6 | 2 | ||
7 | This is a new directory, an entire PR department can hang out here. | 3 | This is a new folder, an entire PR department can hang out here. |
8 | 4 | ||
9 | This would just be a duplicate of README, but for testing purposes. | 5 | This would just be a duplicate of README, but for testing purposes. |
diff --git a/default.template b/default.template index eed4c59..baefad1 100644 --- a/default.template +++ b/default.template | |||
@@ -2,49 +2,118 @@ | |||
2 | <html> | 2 | <html> |
3 | <head> | 3 | <head> |
4 | <meta charset="utf-8"> | 4 | <meta charset="utf-8"> |
5 | <meta name="generator" contents="lcmark"> | ||
6 | <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> | 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> |
7 | <title>$pagetitle$</title> | 6 | <title>$title$</title> |
8 | <link rel="icon" type="image/png" href="$favicon$" /> | 7 | <link rel="icon" type="image/png" href="$favicon$" /> |
9 | <style> | 8 | <style> |
10 | html {font-family: sans-serif;} | 9 | a:hover {color: red;} |
11 | 10 | body { | |
11 | height: 100vh; width: 100vw; | ||
12 | margin: 0; padding: 0; border: none; | ||
13 | background-image: linear-gradient($onefangPurple$, $karenPurple$); | ||
14 | color: white; | ||
15 | font-family: sans-serif; | ||
16 | } | ||
17 | menu {list-style-type: none;} | ||
12 | pre { | 18 | pre { |
13 | background-color: $onefangPurple$; | 19 | background-image: linear-gradient(to right, $PinkFloyd$, $onefangPurple$); |
14 | overflow-x: auto; | 20 | width: fit-content; max-width: 99%; overflow-x: auto; |
15 | width: 92vw; | 21 | margin: 2px; border: 2px solid grey; |
16 | margin: 1px; | 22 | } |
23 | table, td, th {border-collapse: collapse; border: 2px solid grey;} | ||
24 | |||
25 | .toolTip {background: darkcyan; font-size: 1.42em;} | ||
26 | |||
27 | .boxWrapper { | ||
28 | height: 100%; width: 100%; | ||
29 | margin: 0; padding: 0; border: none; | ||
30 | display: grid; | ||
31 | // grid-template-areas: | ||
32 | // "logo tools tools tools" | ||
33 | // "logo head head head" | ||
34 | // "menu body body body" | ||
35 | // "history foot foot foot" | ||
36 | // "nyaw nyaw nyaw nyaw"; | ||
37 | grid-template-columns: 1.4fr 8fr auto auto; | ||
38 | grid-template-rows: auto auto 1fr auto auto; | ||
39 | overflow-x: auto; overflow-y: auto; | ||
17 | } | 40 | } |
41 | .boxLogo {grid-area: logo; grid-column: 1 / 1; grid-row: 1 / 2; height: min-content;} | ||
42 | .boxTools {grid-area: tools; grid-column: 2 / 4; grid-row: 1 / 1; height: min-content;} | ||
43 | .boxHead {grid-area: head; grid-column: 2 / 4; grid-row: 2 / 2; height: min-content; text-align: right;} | ||
18 | 44 | ||
19 | menu { | 45 | .boxMenu {grid-area: menu; grid-column: 1 / 1; grid-row: 3 / 3; height: min-content; vertical-align: top; padding: 4px; overflow-x: auto; overflow-y: auto;} |
20 | list-style-type: none; | 46 | .boxBody {grid-area: body; grid-column: 2 / 4; grid-row: 3 / 3; vertical-align: top; |
47 | height: 100%; width: 100%; | ||
48 | background: black; color: white; | ||
21 | } | 49 | } |
50 | .boxBody a:active {color: red;} | ||
51 | .boxBody a:link {color: orange;} | ||
52 | .boxBody a:visited {color: $onefangGreen$;} | ||
53 | .boxBody a:hover {color: red;} | ||
54 | |||
55 | .boxHistory {grid-area: history; grid-column: 1 / 1; grid-row: 4 / 4; height: min-content;} | ||
56 | .boxFoot {grid-area: foot; grid-column: 2 / 4; grid-row: 4 / 4; height: min-content; text-align: right;} | ||
57 | .boxnyaw {grid-area: nyaw; grid-column: 1 / 4; grid-row: 5 / 5; height: min-content; text-align: right; font-size: 0.55em;} | ||
22 | 58 | ||
59 | #modeToggleBody {display: none;} | ||
60 | #modeToggleMenu {display: none;} | ||
61 | #modeBtn {color: white; display: inline-block;} | ||
62 | #modeToggleBody:checked ~ .modeBtn {color: black;} | ||
63 | // #modeToggleBody:checked ~ body background-image: linear-gradient($karenPurple$, $onefangPurple$);{} | ||
64 | // #modeToggleBody:checked ~ pre {background-image: linear-gradient(to right, $onefangPurple$, $PinkFloyd$);} | ||
65 | |||
66 | #modeToggleMenu:checked ~ .boxLogo {display: none;} | ||
67 | #modeToggleMenu:checked ~ .boxHead {display: none;} | ||
68 | // #modeToggleMenu:checked ~ .boxTools {display: none;} | ||
69 | // #modeToggleMenu:checked ~ .boxMenu {display: none; width: 0px; max-width: 0px; } | ||
70 | |||
71 | #modeToggleBody:checked ~ .boxBody {background: white; color: black;} | ||
72 | #modeToggleBody:checked ~ .boxBody a:active {color: $devuanDevuanalink$;} | ||
73 | #modeToggleBody:checked ~ .boxBody a:link {color: $devuanDevuanlink$;} | ||
74 | #modeToggleBody:checked ~ .boxBody a:visited {color: $devuanDevuanvlink$;} | ||
75 | #modeToggleBody:checked ~ .boxBody a:hover {color: $devuanDevuanhlink$;} | ||
76 | |||
77 | #modeToggleMenu:checked ~ .boxHistory {display: none;} | ||
78 | #modeToggleMenu:checked ~ .boxFoot {display: none;} | ||
79 | #modeToggleMenu:checked ~ .boxnyaw {display: none;} | ||
23 | </style> | 80 | </style> |
24 | </head> | 81 | </head> |
25 | <body bgcolor="black" text="white" alink="yellow" link="yellowgreen" vlink="red"> | 82 | <body alink="red" link="orange" vlink="$onefangGreen$"> |
26 | <table style="background-color: $karenPurple$; width: 98vw; margin: 1; line-style: none; border-style: none; border-spacing: 0;"> | 83 | <div class="boxWrapper"> |
27 | <tr> | 84 | <input type="checkbox" id="modeToggleMenu"/> |
28 | <td><img src="$logo$" alt="alt text" title="Not (Yet) (Another / A) Wiki."/></td> | 85 | <input type="checkbox" id="modeToggleBody"/> |
29 | <td style="text-align: right;">$header$ plus login and register buttons </td> | 86 | <div class="boxLogo" id="top"><header><nav> |
30 | </tr> | 87 | <a href="$home$"><img src="$logo$" alt="not (Yet) (Another / A) Wiki."/></a> |
31 | <tr> | 88 | </nav></header></div> |
32 | <td rowspan=2 style="white-space:nowrap; vertical-align:top;">$menu$</td> | 89 | <div class="boxTools"><header><nav> |
33 | <td><p>👣 $trail$</p></td> | 90 | <a href="/help.HTML"><b class="toolTip" title="🍔 hides / shows non content, reverse hamburger menu. |
34 | </tr> | 91 | 🕶 switches between dark and light themes. |
35 | <tr> | 92 | 📚 shows the list of all pages. |
36 | <td style="background-color: black; width: fit-content;"> | 93 | 🔮 a folder of unsorted pages. |
37 | <main class="contentBox" style="overflow-y: auto; overflow-x: hidden;"> | 94 | 👥 shows the list of users. |
38 | <h1>$pagetitle$</h1> | 95 | 🪵 will be for logging in, when I have written that bit. |
39 | Author: $author$ | 96 | 🔍 will be the search, when I have written that bit. |
40 | $body$ | 97 | 👣 is a trail of the steps to get here.">❓</b></a> |
41 | </main> | 98 | <b class="toolTip"><label for="modeToggleMenu" class='modeBtn'>🍔</label></b> |
42 | </td> | 99 | <b class="toolTip"><label for="modeToggleBody" class='modeBtn'>🕶</label></b> |
43 | </tr> | 100 | <a href="/everything.HTML"><b class="toolTip">📚</b></a> |
44 | <tr> | 101 | <a href="/unsorted/" ><b class="toolTip">🔮</b></a> |
45 | <td>$history$</td> | 102 | <a href="/users/" ><b class="toolTip">👥</b></a> |
46 | <td style="text-align: right;">$footer$</td> | 103 | <b class="toolTip">🪵</b> |
47 | </tr> | 104 | <b class="toolTip">🔍</b> |
48 | </table> | 105 | <b> 👣 $trail$ </b> |
106 | </nav></header></div> | ||
107 | <div class="boxHead"><header><nav><b>$header$</b> </nav></header></div> | ||
108 | |||
109 | <div class="boxMenu"><nav><p><b>$menu$</b></p></nav></div> | ||
110 | <div class="boxBody"><main>$body$<br/></main></div> | ||
111 | |||
112 | <div class="boxHistory"><footer>$history$</footer></div> | ||
113 | <div class="boxFoot"><footer>$footer$</footer></div> | ||
114 | <div class="boxnyaw"><footer> | ||
115 | <p>Powered by <a href="https://sledjhamr.org/notYetAnotherWiki/">notYetAnotherWiki</a> v 0.0 No cookies or scripts where harmed in the making of this web site. May contain low fat CSS.</p> | ||
116 | </footer></div> | ||
117 | </div> | ||
49 | </body> | 118 | </body> |
50 | </html> | 119 | </html> |
diff --git a/empty.md b/empty.md new file mode 100644 index 0000000..b68450f --- /dev/null +++ b/empty.md | |||
@@ -0,0 +1 @@ | |||
Nothing to see here, yet. | |||
diff --git a/feed-icon-14x14.png b/feed-icon-14x14.png new file mode 100755 index 0000000..b3c949d --- /dev/null +++ b/feed-icon-14x14.png | |||
Binary files differ | |||
diff --git a/feed-icon-28x28.png b/feed-icon-28x28.png new file mode 100755 index 0000000..d64c669 --- /dev/null +++ b/feed-icon-28x28.png | |||
Binary files differ | |||
@@ -0,0 +1,43 @@ | |||
1 | # How to use this wiki | ||
2 | |||
3 | On the top left, is the logo, beside that is a toolbar of icons - | ||
4 | |||
5 | - ❓ hover over this for help. | ||
6 | - 🍔 hides or shows everything but the content and these icons, the reverse hamburger menu. | ||
7 | - 🕶 switches between dark and light themes. | ||
8 | - 📚 shows the list of all pages. | ||
9 | - 🔮 a folder of unsorted pages. | ||
10 | - 👥 shows the list of users. | ||
11 | - 🪵 will be for logging in, when I have written that bit. | ||
12 | - 🔍 will be the search, when I have written that bit. | ||
13 | |||
14 | 👣 is a trail of breadcrumbs, though I'm using a footsteps icon | ||
15 | for this. Showing the footsteps you have followed to get to the current | ||
16 | folder. | ||
17 | |||
18 | On the top right of the pages is links to the sub folders of the current | ||
19 | folder the current page is in. | ||
20 | |||
21 | Down the left side is links to the pages in the current folder. Most of | ||
22 | them will be symlinks to the converted pages from the Foswiki and PmWiki | ||
23 | sub folders. Some will be links ☝ to external sites. For the | ||
24 | current page, links to the headings are also shown, those headings have | ||
25 | their own icon 🔼to go back to the top. | ||
26 | |||
27 | The bit you are reading is the badly converted content of the current | ||
28 | page. At the bottom of each converted page is a link to the original, | ||
29 | and if you are logged into that other system, you might be able to edit | ||
30 | the page. Note that unconverted pages don't have these links to the | ||
31 | originals. | ||
32 | |||
33 | At the bottom is links to things like page history, web site source code, | ||
34 | and the software I'm writing to do all of this. Or should be some day. | ||
35 | |||
36 | |||
37 | |||
38 | # Under the hood | ||
39 | |||
40 | Internally this wiki is made of the root folder and it's sub folders | ||
41 | representing the structure of the wiki content. Each folder has it's own | ||
42 | pages. Symlinks are used to copy or move pages around, with special | ||
43 | folders for the original stuff from the other wikis. | ||
diff --git a/menu.template b/menu.template index 7cf0ba2..3abcd81 100644 --- a/menu.template +++ b/menu.template | |||
@@ -4,7 +4,7 @@ | |||
4 | <meta charset="utf-8"> | 4 | <meta charset="utf-8"> |
5 | <meta name="generator" contents="lcmark"> | 5 | <meta name="generator" contents="lcmark"> |
6 | <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> | 6 | <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> |
7 | <title>$pagetitle$</title> | 7 | <title>$title$</title> |
8 | <link rel="icon" type="image/png" href="$favicon$" /> | 8 | <link rel="icon" type="image/png" href="$favicon$" /> |
9 | <style> | 9 | <style> |
10 | html { | 10 | html { |
Binary files differ | |||
Binary files differ | |||
diff --git a/notYetAnotherWiki.lua b/notYetAnotherWiki.lua index da88a52..f53691b 100755 --- a/notYetAnotherWiki.lua +++ b/notYetAnotherWiki.lua | |||
@@ -1,37 +1,74 @@ | |||
1 | #!/usr/bin/env luajit | 1 | #!/usr/bin/env luajit |
2 | 2 | ||
3 | -- Read the README file for what this is all about. If there is no README or similar, then you can find the link to the source below. | 3 | --[[ Read the README file for what this is all about. |
4 | If there is no README or similar, then you can find the link to the source below. | ||
4 | 5 | ||
5 | local lcmark = require("lcmark") -- https://github.com/jgm/lcmark | 6 | Normally I define functions and globals at the top, but here I'm interleaving them. |
7 | ]] | ||
6 | 8 | ||
9 | local Lunamark = require("lunamark") -- https://github.com/jgm/lunamark | ||
10 | local Lpeg = require("lpeg") -- https://www.inf.puc-rio.br/~roberto/lpeg/lpeg.html Lunamark uses this, so we can to. | ||
11 | local RE = require("re") -- Part of lpeg. https://www.inf.puc-rio.br/~roberto/lpeg/re.html | ||
7 | 12 | ||
8 | 13 | ||
14 | --------------------------------------------------------------------------------- | ||
9 | -- Some global data. | 15 | -- Some global data. |
10 | local globalData = { | 16 | |
11 | ['_'] = ' ', ['dlr'] = '$', | 17 | local GlobalMetaData = { |
12 | ['devuanCinnabarDark'] = '#310202', ['devuanCinnabarLight'] = '#510505', | 18 | dlr = '$', perc = '%', dot = '.', |
13 | ['devuanDarkPurpyDark'] = '#33313b', ['devuanDarkPurpyLight'] = '#3c3a45', | 19 | devuanCinnabarDark = '#310202', devuanCinnabarLight = '#510505', |
14 | ['devuanDeepSeaDark'] = '#132f40', ['devuanDeepSeaLight'] = '#1a4562', | 20 | devuanDarkPurpyDark = '#33313b', devuanDarkPurpyLight = '#3c3a45', |
15 | ['devuanSaphireDark'] = '#004489', ['devuanSaphireLight'] = '#00509f', | 21 | devuanDeepSeaDark = '#132f40', devuanDeepSeaLight = '#1a4562', |
16 | ['karenPurple'] = '#8800ff', ['onefangPurple'] = '#cc00ff', | 22 | devuanSaphireDark = '#004489', devuanSaphireLight = '#00509f', |
17 | favicon = 'nYAW_icon.png', logo = 'nYAW.png', header = '', --menu = '', | 23 | devuanDevuanDark = '#000000', devuanDevuanLight = '#ffffff', |
18 | history = '', footer = 'Powered by <a href="https://sledjhamr.org/cgit/notYetAnotherWiki/about/">notYetAnotherWiki</a> version 0.0. ', | 24 | -- HTML link colours. Naturally HTML5 deprecated the simple version, replacing it with less simple CSS. |
25 | -- <body> has alink, link, vlink; CSS has active, link, visited, and hover. | ||
26 | devuanDevuanalink = '#03a4ff', devuanDevuanlink = '#0076b6', devuanDevuanvlink = '#6aa4db', devuanDevuanhlink = '#03a4ff', | ||
27 | devuanSDevuanalink = '#98c3db', devuanSDevuanlink = '#ffffff', devuanSDevuanvlink = '#ffffff', devuanSDevuanhlink = '#98c3db', | ||
28 | karenPurple = '#8800ff', onefangPurple = '#cc00ff', onefangGreen = '#42ff00', | ||
29 | PinkFloyd = '#AA00AA', DeepPurple = '#220022', -- From an ancient site of mine, which went from PinkFloyd to DeepPurple as a background gradient. | ||
30 | favicon = 'nYAW_icon.png', logo = 'nYAW.png', | ||
19 | } | 31 | } |
20 | local Sites, Files, Subs = {}, {}, {} | ||
21 | 32 | ||
33 | local Files, Subs, xLinks = {}, {}, {} | ||
34 | local Context = {} -- Coz can't otherwise pass context through to the deeper Lunamark functions I'm overriding. | ||
35 | |||
36 | local Template = '' | ||
37 | local h = io.open("default.template", 'r') | ||
38 | if nil ~= h then | ||
39 | Template = h:read('*a') | ||
40 | h:close() | ||
41 | else | ||
42 | print('oops! No such file ' .. 'default.template') | ||
43 | end | ||
22 | 44 | ||
23 | 45 | ||
46 | --------------------------------------------------------------------------------- | ||
24 | -- Useful functions, part 0. | 47 | -- Useful functions, part 0. |
25 | 48 | ||
26 | -- A simple table.subtable = subtable wont work, you end up with a reference so that changes to the later get applaid to the former. | 49 | -- A simple table.subtable = subtable wont work, you end up with a reference so that changes to the later get applied to the former. |
27 | local copyTable = function(t, strip) | 50 | local derefiTable = function(t, strip) |
28 | local argh = {} | 51 | local argh = {} |
29 | for l, y in ipairs(t) do if (l ~= y.name) and strip then table.insert(argh, y) end end | 52 | for l, y in ipairs(t) do if (l ~= y.name) and strip then table.insert(argh, y) end end |
30 | return argh | 53 | return argh |
31 | end | 54 | end |
55 | local derefTable = function(t, strip) | ||
56 | local argh = {} | ||
57 | for l, y in pairs(t) do argh[l] = y end | ||
58 | return argh | ||
59 | end | ||
32 | 60 | ||
33 | 61 | ||
34 | -- String together the bits array into a path string. | 62 | local writeString = function(base, body) |
63 | local a, e = io.open(base, 'w') | ||
64 | if nil == a then print('Could not open ' .. base .. ' - ' .. e) else | ||
65 | a:write(body) | ||
66 | a:close() | ||
67 | end | ||
68 | end | ||
69 | |||
70 | |||
71 | -- String together the bits array into a path string. Or the other way around. lol | ||
35 | local stringBits = function(l) | 72 | local stringBits = function(l) |
36 | local bits = {} | 73 | local bits = {} |
37 | local last = 1 | 74 | local last = 1 |
@@ -45,258 +82,885 @@ local stringBits = function(l) | |||
45 | end | 82 | end |
46 | 83 | ||
47 | 84 | ||
85 | -- Put a value into the Files or Subs table, creating things if needed. | ||
86 | local toFile = function(name, key, value) | ||
87 | if nil == Files[name] then | ||
88 | local bits, bit = stringBits(name) | ||
89 | local path = '' | ||
90 | Files[name] = {} | ||
91 | Files[name].headers = {} | ||
92 | Files[name].bits = bits | ||
93 | Files[name].bit = bit | ||
94 | for i, d in ipairs(bits) do | ||
95 | if '' ~= path then path = path .. '/' end | ||
96 | path = path .. d | ||
97 | end | ||
98 | Files[name].path = path | ||
99 | -- Files[name].body = '' | ||
100 | if ("Foswiki" == bits[1]) or ("PmWiki" == bits[1]) then Files[name].ogWiki = bits[1] end | ||
101 | end | ||
102 | if nil ~= key then Files[name][key] = value end | ||
103 | for i, v in ipairs{'metadata', 'bits', } do | ||
104 | if nil == Files[name][v] then Files[name][v] = {} end | ||
105 | end | ||
106 | -- Open the files and do the initial cleanups. | ||
107 | local body = '' | ||
108 | if '.md' ~= string.sub(name, -3, -1) then | ||
109 | h = io.open(name .. '.md', 'r') | ||
110 | if nil ~= h then | ||
111 | -- print('Parsing ' .. name .. '.md') | ||
112 | Context = Files[name] | ||
113 | body = h:read('*a') ; h:close() | ||
114 | -- Deal with my typical double spaced sentence endings, and other things. | ||
115 | local result = RE.compile( [=[{~ | ||
116 | ( | ||
117 | {[.?!]{" "}} -> '%1 ' / -- ' ' gets turned into hex 0xA0 by parse(). So feed it another metadata token that gets translated to . Seems we now skip this issue. | ||
118 | {[\\]{['"|$]}} -> '%2' / -- Do the same for fixing the \' \" \| etc mess pandoc left. | ||
119 | {"[ ]{.foswikiGrayFG}" } -> '' / -- Coz Foswiki sucks. No idea why the next thing didn't catch it. | ||
120 | {"[" {([^]])+} "]{.foswiki" {([^FG}])+} "FG}" } -> "<span style='color: %3;'>%2</span>" / | ||
121 | {"::: {."[A-Za-z_. ]+"}"} -> '' / | ||
122 | {":::"} -> '' / | ||
123 | {"-noComment-"} -> ' -- ' / | ||
124 | {"| bgcolor=#" {([^ ])+} " " } -> "| <span style='background: #%2;'> bgcolor=#%2 </span> " / -- Deal with debdog's color table. | ||
125 | {"[" {([^]])+} ']{style="color: ' {([^}])+} "}" } -> "<span style='color: %3;'>%2</span>" / | ||
126 | {"[" {([^]])+} "]{style='color: " {([^}])+} "}" } -> "<span style='color: %3;'>%2</span>" / | ||
127 | {"{#"[A-Za-z_]+"}"} -> '' / | ||
128 | {"### [[edit](/bin/edit/Main/" {([^%nl])+} } -> '' / | ||
129 | {"#"+ " " {([^%nl])+} } -> header / | ||
130 | . | ||
131 | )* ~}]=], { header = function(a) table.insert(Context.headers, a); return a end } ):match(body) | ||
132 | body = result | ||
133 | -- {"<!--".*"-->"} -> '' / | ||
134 | -- {"[$]"} -> '$dlr$' / -- Replace $, coz otherwise it confuses things later. | ||
135 | body = RE.gsub(body, '{[$]}', '$dlr$') | ||
136 | -- {"[%]"} -> '$perc$' / -- Gotta be done after the %1's above. otherwise screws things up when included above. | ||
137 | -- body = RE.gsub(body, '{[%]}', '$perc$') -- Coz otherwise stray % trip up the capture part. | ||
138 | end | ||
139 | Files[name].body = body | ||
140 | end | ||
141 | end | ||
142 | local toSub = function(name, key, value) | ||
143 | if nil == Subs[name] then | ||
144 | local bits, bit = stringBits(name) | ||
145 | local path = '' | ||
146 | Subs[name] = {} | ||
147 | table.insert(bits, bit) | ||
148 | Subs[name].bits = bits | ||
149 | Subs[name].bit = bit | ||
150 | for i, d in ipairs(bits) do | ||
151 | if '' ~= path then path = path .. '/' end | ||
152 | path = path .. d | ||
153 | end | ||
154 | Subs[name].path = path | ||
155 | end | ||
156 | if nil ~= key then Subs[name][key] = value end | ||
157 | for i, v in ipairs{'metadata', 'bits', 'files', 'subs'} do | ||
158 | if nil == Subs[name][v] then Subs[name][v] = {} end | ||
159 | end | ||
160 | end | ||
161 | |||
162 | |||
48 | 163 | ||
164 | local readMdMd = function(name, metadata) | ||
165 | local h1 = io.open(name .. '.md') | ||
166 | if nil == h1 then | ||
167 | -- print('Could not open ' .. name .. '.md') | ||
168 | return {} | ||
169 | else | ||
170 | for l in h1:lines() do | ||
171 | for k, v in string.gmatch(l, "(%w+)%s*=%s*(.+)") do | ||
172 | if nil == v then | ||
173 | print(name .. ' ' .. k) | ||
174 | else | ||
175 | metadata[k] = v | ||
176 | end | ||
177 | end | ||
178 | end | ||
179 | end | ||
180 | return metadata | ||
181 | end | ||
182 | |||
183 | |||
184 | |||
185 | local commonLinky = function(l, body, u, url, beg, en, beg0, en0, bump) | ||
186 | if nil == url then | ||
187 | -- print('OOPS! unknown linky - @' .. l .. '\t\t\t' .. string.sub(body, beg - 9, en) .. ' ' .. string.sub(body, en + 1, en0)) | ||
188 | else | ||
189 | local md = readMdMd(url, {}) | ||
190 | -- if nil ~= md then | ||
191 | if nil ~= md.realURL then url = md.realURL end | ||
192 | -- end | ||
193 | body = string.sub(body, 1, beg - bump) .. url .. string.sub(body, en0 + 1) | ||
194 | here = here + string.len(url) | ||
195 | end | ||
196 | if 1 == bump then | ||
197 | here = here + 1 | ||
198 | beg, en = RE.find(body, [['https://fos.wiki.devuan.org/']], here) | ||
199 | else | ||
200 | beg, en = RE.find(body, [["'https://wiki.devuan.org/"]], here) | ||
201 | end | ||
202 | return beg, en, body, here | ||
203 | end | ||
204 | |||
205 | |||
206 | |||
207 | --------------------------------------------------------------------------------- | ||
49 | -- Actually start doing things. | 208 | -- Actually start doing things. |
50 | 209 | ||
51 | -- Scan the subdirectories looking for .md files. | 210 | -- Create the base of everything.md here, so it gets picked up as usual in the file scan. |
52 | local directory = arg[1] | 211 | h = io.open('everything.md', 'w') |
53 | if nil == directory then directory = '.' end | 212 | if nil ~= h then |
54 | if '.' ~= directory then | 213 | h:close() |
55 | for l in io.popen('find . -name "*.md" -type f,l -printf "%P\n"'):lines() do | 214 | else |
56 | Files[string.gsub(l, '%.md$', '')] = {} | 215 | print("Can't open everything.md for writing.") |
216 | end | ||
217 | |||
218 | -- Scan the sub folders looking for our files. | ||
219 | local Folder = arg[1] | ||
220 | toSub('') | ||
221 | if nil == Folder then Folder = '.' end | ||
222 | --GlobalMetaData.root = Folder | ||
223 | |||
224 | --[[ Sort out realURL for symlinked .md.md files. | ||
225 | realURL is the generic URL part for this page. By policy it points to whatever is the latest copy / symlink of the original download .md.md. | ||
226 | realURL starts out being the path to the downloaded file and friends. | ||
227 | If we make a symlink during SuckIt, then that gets updated to point to the place the symlink is in. | ||
228 | below we compare timestamps and select the latest version if there's more than one symlink. | ||
229 | For the "page symlinked" problem, this should work if realURL is kept updated. | ||
230 | For the "page copied" problem, this should work if realURL is kept updated, same as symlinked really, coz that's just another copy. | ||
231 | For the "page moved" problem, that'll be the most recent symlink, the old one still has it's symlink pointing to the download .md.md, which gets updated with the current realURL. | ||
232 | So when some external old URL points to someplace a page used to be, it's old symlink points to the up to date download .md.md, and we know where to go to find the page now. | ||
233 | A left over .md.md file should have a redirect .HTML page created for it. | ||
234 | ]] | ||
235 | for l in io.popen('find -L ' .. Folder .. ' -name unsorted -prune -o -name "*.md.md" -xtype l -printf "%P\n"'):lines() do | ||
236 | local metadata = readMdMd(string.sub(l, 1, -4), {}) | ||
237 | if nil == metadata.realURL then | ||
238 | metadata.realURL = string.sub(l, 1, -7) | ||
239 | else | ||
240 | if metadata.realURL ~= string.sub(l, 1, -7) then | ||
241 | metadata.realURL = string.sub(l, 1, -7) | ||
242 | -- If this already exists, compare the timestamps, most recent wins. | ||
243 | local time0 = io.popen('ls -l --time-style=+%s "' .. metadata.realURL .. '.md.md" | cut -d \' \' -f 6'):read('l') | ||
244 | local time1 = io.popen('ls -l --time-style=+%s "' .. l .. '" | cut -d \' \' -f 6'):read('l') | ||
245 | if time0 > time1 then metadata = nil end | ||
246 | else metadata = nil end | ||
247 | end | ||
248 | |||
249 | if nil ~= metadata then | ||
250 | -- DUNNO if this writes to the original file, or overwrites the symlink. | ||
251 | local a, e = io.open(l, 'w') | ||
252 | if nil == a then print('Could not open ' .. l .. ' - ' .. e) else | ||
253 | for k, v in pairs(metadata) do | ||
254 | a:write(k .. '=' .. v .. '\n') | ||
255 | end | ||
256 | a:close() | ||
257 | end | ||
57 | end | 258 | end |
58 | end | 259 | end |
59 | -- Can add in a distant directory to, for putting it's results in the current directory. | 260 | |
60 | for l in io.popen('find ' .. directory .. ' -name "*.md" -type f,l -printf "%P\n"'):lines() do | 261 | -- Clean up unsorted. |
262 | for l in io.popen('find -L ' .. Folder .. ' -name unsorted -prune -o -name "*.md" -a -not -name "*.md.md" -xtype l -printf "%P\n"'):lines() do | ||
263 | local tp = '_fos' | ||
264 | local metadata = readMdMd(l, {}) | ||
265 | if nil ~= metadata then | ||
266 | if "PmWiki" == metadata.ogWiki then tp = '_pm' end | ||
267 | if nil ~= metadata.ogFile then | ||
268 | local unsort = 'unsorted/' .. metadata.ogFile | ||
269 | local a, e = io.open(unsort .. tp .. '.md' , 'r') | ||
270 | if nil ~= a then | ||
271 | a:close() | ||
272 | -- Keep the .md.md symlink, delete the rest. | ||
273 | os.execute('rm ' .. unsort .. tp .. '.HTML') | ||
274 | os.execute('rm ' .. unsort .. tp .. '.md') | ||
275 | a, e = io.open(unsort .. tp .. '.HTML', 'w') | ||
276 | if nil == a then print('Could not open ' .. unsort .. tp .. '.HTML' .. ' - ' .. e) else | ||
277 | local dst = string.sub(l, 1, -4) .. '.HTML' | ||
278 | local cnt = 1 | ||
279 | for j = 1, #metadata.ogFile do | ||
280 | if '/' == string.sub(metadata.ogFile, j, j) then cnt = cnt + 1 end | ||
281 | end | ||
282 | dst = string.rep('../', cnt) .. dst | ||
283 | a:write( | ||
284 | [=[<!DOCTYPE html> | ||
285 | <html> | ||
286 | <head><meta http-equiv="refresh" content="0; url=]=] .. dst .. '"' .. [=[/></head> | ||
287 | <body><p>Click this if you don't get redirected to the real page - <a href="]=] .. dst .. '"' .. [=[>Redirect</a></p></body> | ||
288 | </html> | ||
289 | ]=]) | ||
290 | a:close() | ||
291 | print('REDIRECT ' .. unsort .. tp .. '.HTML \t-> ' .. dst) | ||
292 | end | ||
293 | |||
294 | end | ||
295 | end | ||
296 | end | ||
297 | end | ||
298 | |||
299 | -- Look for copied pages from the other wikis. | ||
300 | for l in io.popen('find -L ' .. Folder .. ' -name "*.HTM" -type f,l -printf "%P\n"'):lines() do | ||
301 | -- Only do this if .HTM is newer than .md, or .md doesn't exist. | ||
302 | local htime = io.popen("date -ur " .. l .. " +%s"):read('l') | ||
303 | local mtime = io.popen("date -ur " .. string.sub(l, 1, -4) .. "md +%s 2>/dev/null"):read('l') | ||
304 | if (nil == mtime) or (htime > mtime) then | ||
305 | print('pandoc converting ' .. l .. ' -> ' .. string.sub(l, 1, -4) .. 'md') | ||
306 | os.execute('cp ' .. l .. ' ' .. l .. '_ORIGINAL0') | ||
307 | -- Open the HTM files and do the initial cleanups, then pandoc them. | ||
308 | h = io.open(l, 'r') | ||
309 | if nil ~= h then | ||
310 | local body = h:read('*a') ; h:close() | ||
311 | writeString(l .. '_ORIGINAL1', body) | ||
312 | if 'Foswiki' == string.sub(l, 1, 7) then | ||
313 | -- Strip out the actual content. | ||
314 | local beg, en = RE.find(body, [['<div id="patternMainContents">']]) if nil ~= beg then body = string.sub(body, en + 1) end | ||
315 | beg, en = RE.find(body, [['<div class="patternContent">']]) if nil ~= beg then body = string.sub(body, en + 1) end | ||
316 | beg, en = RE.find(body, [['<div class="foswikiTopic">']]) if nil ~= beg then | ||
317 | if ' -- ' == string.sub(body, en + 1, en + 4) then | ||
318 | beg, en = RE.find(body, '[%nl]', en + 4) | ||
319 | body = string.sub(body, en + 1) | ||
320 | end | ||
321 | end | ||
322 | beg, en = RE.find(body, [['<div class="patternInfo">']]) if nil ~= beg then body = string.sub(body, 1, beg - 1) end | ||
323 | -- beg, en = RE.find(body, [['<div class="foswikiForm foswikiFormStep">']]) if nil ~= beg then body = string.sub(body, 1, en + 1) end | ||
324 | beg, en = RE.find(body, [['<div class="foswikiAttachments foswikiFormStep" style="overflow:auto">']]) if nil ~= beg then body = string.sub(body, 1, beg - 1) end | ||
325 | beg, en = RE.find(body, [['<div class="foswikiSearchResultsPager">']]) if nil ~= beg then body = string.sub(body, 1, beg - 1) end | ||
326 | -- Some clean ups. | ||
327 | local result = RE.compile( [[{~ | ||
328 | ( | ||
329 | {'class="foswikiCurrentTopicLink"'} -> blank / | ||
330 | {'class="foswikiNewLink"'} -> blank / | ||
331 | {"<span class='foswikiSmall'><a href='/bin/edit/Main/" ([^;action=form])* ";action=form'>edit</a></span>"} -> blank / | ||
332 | {" -- "} -> '-noComment-' / | ||
333 | -- {"-- " ([^%nl])* } -> blank / | ||
334 | {'<div class="foswikiTopic">'} -> blank / | ||
335 | {'rel="nofollow"'} -> blank / {"rel='nofollow'"} -> blank / | ||
336 | {"target='_blank'"} -> blank / | ||
337 | {"</div>" ([%nl])* } -> blank / | ||
338 | -- {'style="' ([^"])+ '"'} -> blank / {"style='" ([^'])+ "'"} -> blank / | ||
339 | . | ||
340 | )* ~}]], { blank = function(a) return '' end } ):match(body) | ||
341 | body = result | ||
342 | -- body = RE.gsub(body, [=[{"<!-- ".*"-->"}]=], '') -- FIXME | ||
343 | local here = 1 | ||
344 | beg, en = RE.find(body, [['https://fos.wiki.devuan.org/']], here) | ||
345 | while nil ~= beg do | ||
346 | here = beg + 1 | ||
347 | local beg0, en0 | ||
348 | local url = nil | ||
349 | if '"' == string.sub(body, beg - 1, beg - 1) then | ||
350 | beg0, en0 = RE.find(body, [['"']], en) | ||
351 | url = string.sub(body, en + 1, en0 - 1) | ||
352 | end | ||
353 | if "'" == string.sub(body, beg - 1, beg - 1) then | ||
354 | beg0, en0 = RE.find(body, [["'"]], en) | ||
355 | url = string.sub(body, en + 1, en0) | ||
356 | end | ||
357 | |||
358 | if nil ~= url then | ||
359 | if ('pub/' == string.sub(url, 1, 4)) then | ||
360 | -- FIXME? - evil hack? | ||
361 | url = 'Foswiki/' .. url | ||
362 | --print('FOSWIKI HTM ' .. url) | ||
363 | else | ||
364 | url = nil | ||
365 | end | ||
366 | end | ||
367 | --print('HTM0 ' .. string.sub(body, beg, en + 84) .. ' \t\t') | ||
368 | beg, en, body, here = commonLinky(l, body, 'https://fos.wiki.devuan.org/', url, beg, en, beg0, en0, 1) | ||
369 | --if nil ~= en then print('HTM1 ' .. string.sub(body, beg, en + 84) .. ' \t\t') end | ||
370 | --[=[ | ||
371 | if nil == url then | ||
372 | print('OOPS! unknown linky - @' .. l .. '\t\t\t' .. string.sub(body, beg - 9, en) .. ' ' .. string.sub(body, en + 1, en0)) | ||
373 | else | ||
374 | -- print(' linky - @' .. l .. '\t\t\t' .. string.sub(body, beg - 9, en) .. ' ' .. string.sub(body, en + 1, en0) .. ' -> ' .. url) | ||
375 | local md = readMdMd(url, {}) | ||
376 | -- if nil ~= md then | ||
377 | if nil ~= md.realURL then url = md.realURL end | ||
378 | -- end | ||
379 | body = string.sub(body, 1, beg - 1) .. url .. string.sub(body, en0 + 1) | ||
380 | here = here + #url | ||
381 | end | ||
382 | beg, en = RE.find(body, [['https://fos.wiki.devuan.org/']], here) | ||
383 | ]=] | ||
384 | end | ||
385 | |||
386 | writeString(l .. '_NEW', body) | ||
387 | elseif 'PmWiki' == string.sub(l, 1, 6) then | ||
388 | local beg, en = RE.find(body, [['<!--PageText-->']]) if nil ~= beg then body = string.sub(body, en + 2) end | ||
389 | beg, en = RE.find(body, [["div id='wikitext'>"]]) if nil ~= beg then body = string.sub(body, en + 2) end | ||
390 | beg, en = RE.find(body, [["<div id='printfoot'>"]]) if nil ~= beg then body = string.sub(body, 1, beg - (2 + 9)) end -- There's a </div> to get rid of to. | ||
391 | beg, en = RE.find(body, [['<!--HTMLFooter-->']]) if nil ~= beg then body = string.sub(body, 1, beg - 2) end | ||
392 | local result = RE.compile( [[{~ | ||
393 | ( | ||
394 | {"class='categorylink'"} -> blank / | ||
395 | {"class='createlink'"} -> blank / | ||
396 | {"class='createlinktext'"} -> blank / | ||
397 | {"class='escaped'"} -> blank / | ||
398 | {"class='diffmarkup'"} -> blank / | ||
399 | {"class='selflink'"} -> blank / | ||
400 | {"class='urllink'"} -> blank / | ||
401 | {"<div class='vspace'></div><hr /> <a class='wikilink' href='https://wiki.devuan.org?n=Profiles." .* ([%nl])* } -> blank / | ||
402 | {"<a class='selflink' href='https://wiki.devuan.org?n=Profiles." .* ([%nl])* } -> blank / | ||
403 | {"<div class='vspace'></div><hr />"} -> blank / | ||
404 | {"<div class='vspace'></div>"} -> blank / | ||
405 | {"class='wikilink'"} -> blank / | ||
406 | {'rel="nofollow"'} -> blank / {"rel='nofollow'"} -> blank / | ||
407 | {"target='_blank'"} -> blank / | ||
408 | -- {'style="' ([^"])+ '"'} -> blank / {"style='" ([^'])+ "'"} -> blank / | ||
409 | {"<span class='hlt " {([a-z])+} "'></span><pre" } -> "<pre class='%2'" / | ||
410 | . | ||
411 | )* ~}]], { blank = function(a) return '' end } ):match(body) | ||
412 | body = result | ||
413 | -- body = RE.gsub(body, [=["<a " {([^ >])+} " >"]=], "<a %1>") | ||
414 | -- DONE? - <span class='hlt html'></span><pre style='background-color: #cc00ff;' class='escaped'> ... lines of HTML code ... </pre> | ||
415 | -- most of the time I'll see <pre class='escaped'> | ||
416 | -- My own looking glass has several. | ||
417 | -- Foswiki <pre class='bash'> | ||
418 | -- CommonMark->HTML ---lua <pre><code class="language-lua"> .............................. </code></pre> | ||
419 | -- Seems to be the spec way of doing it. | ||
420 | -- most of the time I'll see <pre><code> | ||
421 | |||
422 | here = 1 | ||
423 | beg, en = RE.find(body, [["'https://wiki.devuan.org/"]], here) | ||
424 | while nil ~= beg do | ||
425 | here = beg + 1 | ||
426 | local beg0, en0 = RE.find(body, [["'"]], en) | ||
427 | -- FIXME? - This might be working around a bug elsewhere. | ||
428 | if "'" == string.sub(body, en0, en0) then en0 = en0 - 1 end | ||
429 | local url = string.sub(body, en + 1, en0) | ||
430 | if '?n=' == string.sub(url, 1, 3) then | ||
431 | url = string.sub(url, 4):gsub('[%a]+%.([%a-]+)', '%1_pm.HTML') | ||
432 | elseif ("'" == url) or ('uploads/' == string.sub(url, 1, 8)) then | ||
433 | -- FIXME - evil hack? Yep, evil hack, need to know the depth of the source, which isn't here. | ||
434 | url = 'PmWiki/' .. url | ||
435 | else | ||
436 | url = nil | ||
437 | end | ||
438 | --print('HTM0 ' .. string.sub(body, beg, en + 84) .. ' \t\t') | ||
439 | beg, en, body, here = commonLinky(l, body, "'https://wiki.devuan.org/", url, beg, en, beg0, en0, 0) | ||
440 | --if nil ~= en then print('HTM1 ' .. string.sub(body, beg, en + 84) .. ' \t\t') end | ||
441 | end | ||
442 | |||
443 | writeString(l .. '_NEW', body) | ||
444 | end | ||
445 | end | ||
446 | |||
447 | ok, rslt, status = os.execute('pandoc --wrap=preserve -f html -t commonmark_x --self-contained ' .. l .. '_NEW' .. ' >' .. string.sub(l, 1, -4) .. 'md') | ||
448 | end | ||
449 | end | ||
450 | |||
451 | if '.' ~= Folder then | ||
452 | for l in io.popen('find -L . -name "*.md" -type f,l -printf "%P\n"'):lines() do | ||
453 | toFile(string.gsub(l, '%.md$', '')) | ||
454 | end | ||
455 | end | ||
456 | |||
457 | -- Can add in a distant folder to, for putting it's results in the current folder. | ||
458 | for l in io.popen('find -L ' .. Folder .. ' -name "*.md" -type f,l -printf "%P\n"'):lines() do | ||
61 | local n = string.gsub(l, '%.md$', '') | 459 | local n = string.gsub(l, '%.md$', '') |
62 | if nil == Files[n] then Files[n] = {} end | 460 | if nil == Files[n] then toFile(n) end |
63 | end | 461 | end |
64 | 462 | ||
65 | -- Gotta figure out all the files and subs first. File and sub metadata comes along for the ride. | 463 | |
66 | Subs[''] = {files = {}, subs = {}, bits = {}} | 464 | -- Gotta figure out all the files and subs first. File and sub metadata comes along for the ride, coz we need them later. |
465 | local NewMeta = {} | ||
67 | for name, file in pairs(Files) do | 466 | for name, file in pairs(Files) do |
68 | local bitter, path = '', '' | 467 | local bitter, path = '', '' |
69 | local bits, bit = stringBits(name) | 468 | local bits, bit = file.bits, file.bit |
70 | local ln = #bits | 469 | local ln = #bits |
470 | local body, metadata = '', {} | ||
71 | 471 | ||
72 | -- Go through our bits, construct Subs with bits. | 472 | -- Go through our bits, construct Subs with bits. |
73 | Files[name].bits = bits | ||
74 | Files[name].bit = bit | ||
75 | if ln > 0 then bitter = bits[1] end | 473 | if ln > 0 then bitter = bits[1] end |
76 | if '' ~= bitter then Subs[''].subs[bitter] = bitter end -- "bitter end" was entirely by accident, I'm keeping it. B-) | 474 | if '' ~= bitter then Subs[''].subs[bitter] = bitter end -- "bitter end" was entirely by accident, I'm keeping it. B-) |
77 | for i, d in ipairs(bits) do | 475 | for i, d in ipairs(bits) do |
78 | if '' ~= path then path = path .. '/' end | 476 | if '' ~= path then path = path .. '/' end |
79 | path = path .. d | 477 | path = path .. d |
80 | if nil == Subs[path] then Subs[path] = {files = {}, subs = {}} end | 478 | toSub(path) |
81 | if i < ln then Subs[path].subs[bits[i + 1]] = bits[i + 1] end | 479 | if i < ln then |
82 | Subs[path].bits = copyTable(bits, true) | 480 | Subs[path].subs[bits[i + 1]] = bits[i + 1] |
83 | if i < ln then table.remove(Subs[path].bits, #bits) end | 481 | table.remove(Subs[path].bits, #bits) |
482 | end | ||
84 | end | 483 | end |
85 | 484 | ||
86 | -- Start the file parsing here, coz we need it's metadata. | 485 | if '.md' == string.sub(name, -3, -1) then |
87 | print('Parsing ' .. name .. '.md') | 486 | -- This is a metadata only file, no content, stash the matadata. |
88 | local h = io.open(name .. '.md', 'r') | 487 | |
89 | -- TODO - should bail here on error? | 488 | metadata = readMdMd(name, metadata) |
90 | if nil ~= h then file.cm = h:read('*a') ; h:close() else print('oops! No such name ' .. name) end | 489 | if '.md' == name then toSub(path, 'metadata', metadata) |
91 | -- Convert the CommonMark to HTML, including the metadata. | 490 | elseif '/.md' == string.sub(name, -4, -1) then toSub(path, 'metadata', metadata) |
92 | local body, metadata, err = lcmark.convert(file.cm, "html", {smart = true, yaml_metadata = true, columns = 0}) | 491 | -- else toFile(string.sub(name, 1, -4), 'metadata', metadata) |
93 | if nil == body then print('oops! ' .. err) | 492 | else NewMeta[string.sub(name, 1, -4)] = metadata -- Coz we can't add to Files here. |
94 | elseif '' == body then | 493 | end |
95 | -- This is a metadata only file, no content, stash the matadata in it's directory. | ||
96 | Subs[path].metadata = metadata | ||
97 | Files[name] = nil | 494 | Files[name] = nil |
98 | else | ||
99 | -- Ordinary md file, stash it's metadata and parsed body. | ||
100 | file.metadata = metadata | ||
101 | file.body = body | ||
102 | table.insert(Subs[path].files, bit) | ||
103 | end | 495 | end |
104 | end | 496 | end |
105 | 497 | ||
498 | -- FIXED - Lua doesn't like modifying the thing you are pair()ing, like we want to do in the last loop. | ||
499 | for name, file in pairs(NewMeta) do | ||
500 | if nil == Files[name] then toFile(name) end | ||
501 | for k, v in pairs(file) do | ||
502 | if nil == Files[name].metadata[k] then Files[name].metadata[k] = v end | ||
503 | end | ||
504 | end | ||
505 | |||
506 | -- Fix up subs now we have all the file bits. | ||
507 | for name, file in pairs(Files) do | ||
508 | if '.md' ~= string.sub(name, -3, -1) then | ||
509 | table.insert(Subs[file.path].files, file.bit) | ||
510 | end | ||
511 | end | ||
512 | |||
513 | -- Find empty subs. | ||
514 | for name, sub in pairs(Subs) do | ||
515 | if 0 == #sub.files then | ||
516 | print("EMPTY " .. name) | ||
517 | h = io.open(name .. '/index.md', 'w') | ||
518 | if nil ~= h then | ||
519 | h:write('This folder has no files.') | ||
520 | h:close() | ||
521 | else | ||
522 | print("Can't open " .. name .. '/index.md for writing.') | ||
523 | end | ||
524 | end | ||
525 | end | ||
106 | 526 | ||
107 | 527 | ||
528 | --------------------------------------------------------------------------------- | ||
108 | -- These functions assume the above file and sub scan has completed. | 529 | -- These functions assume the above file and sub scan has completed. |
109 | 530 | ||
110 | -- Which page in this directory should we show? | 531 | -- Which page in this folder should we show? |
111 | -- NOTE - only looking for the .md files we scanned for before, any stray HTML, html, HTM, atd htm files will get ignored. | 532 | -- NOTE - only looking for the .md files we scanned for before, any stray HTML, html, HTM, and htm files will get ignored. |
112 | local whichPage = function(f) | 533 | local whichPage = function(f) |
113 | local fl = '' | 534 | local fl = '' |
114 | if (nil ~= Subs[f]) and (nil ~= Subs[f].files) then | 535 | if nil ~= Subs[f] then |
115 | if 1 == #(Subs[f].files) then fl = Subs[f].files[1] .. '.HTML' else | 536 | if nil ~= Subs[f].whichPage then return Subs[f].whichPage end |
116 | -- Standard files to search for. | 537 | if nil ~= Subs[f].files then |
117 | for i, v in ipairs{'about', 'readme', 'index', 'homepage', 'mainpage', 'webhome'} do | 538 | if 1 == #(Subs[f].files) then fl = Subs[f].files[1] else |
118 | for j, w in ipairs(Subs[f].files) do | 539 | -- Standard files to search for. |
119 | if v == string.lower(w) then | 540 | for i, v in ipairs{'about', 'readme', 'index', 'homepage', 'mainpage', 'webhome'} do |
120 | fl = v .. '.HTML' | 541 | for j, w in ipairs(Subs[f].files) do |
121 | break | 542 | if v == string.lower(w) then |
543 | fl = w | ||
544 | break | ||
545 | end | ||
122 | end | 546 | end |
547 | if '' ~= fl then break end | ||
123 | end | 548 | end |
124 | if '' ~= fl then break end | 549 | -- If nothing else, just grab the first one. |
550 | if ('' == fl) and (nil ~= Subs[f].files[1]) then fl = Subs[f].files[1] end | ||
125 | end | 551 | end |
126 | -- If nothing else, just grab the first one. | ||
127 | if ('' == fl) and (nil ~= Subs[f].files[1]) then fl = Subs[f].files[1] end | ||
128 | end | 552 | end |
129 | end | 553 | end |
554 | if '' ~= fl then fl = fl .. '.HTML' ; Subs[f].whichPage = fl end | ||
130 | return fl | 555 | return fl |
131 | end | 556 | end |
132 | 557 | ||
133 | 558 | ||
134 | -- Calculate a link from the source directory to the destination directory. | 559 | -- Figure out the original title and link for the original wiki. |
560 | local whichWiki = function(metadata) | ||
561 | local title, link = '', '' | ||
562 | if 'PmWiki' == metadata.ogWiki then | ||
563 | title = metadata.ogBase .. '.' .. metadata.ogFile | ||
564 | link = metadata.ogURL .. '/?n=' .. metadata.ogBase .. '.' .. metadata.ogFile | ||
565 | end | ||
566 | if 'Foswiki' == metadata.ogWiki then | ||
567 | title = metadata.ogBase .. '/' .. metadata.ogFile | ||
568 | link = metadata.ogURL .. '/' .. metadata.ogBase .. '/' .. metadata.ogFile | ||
569 | end | ||
570 | return title, link | ||
571 | end | ||
572 | |||
573 | |||
574 | -- Calculate a link from the source folder to the destination folder. | ||
135 | local linkFrom = function(source, dest) | 575 | local linkFrom = function(source, dest) |
576 | -- Evil hacks! | ||
577 | if 'Profiles' == dest then dest = 'PmWiki/Profiles' end | ||
578 | if 'Onefang' == dest then dest = 'PmWiki/Onefang' end | ||
579 | if 'Tiki' == dest then dest = 'PmWiki/Tiki' end | ||
580 | |||
581 | if source == dest then return '' end | ||
136 | local depth = 0 | 582 | local depth = 0 |
137 | local link = '' | 583 | local lnk = '' |
138 | if source ~= dest then | 584 | if source ~= dest then |
139 | for i, v in ipairs(Subs[source].bits) do | 585 | if nil == Subs[source] then |
140 | if v ~= Subs[dest].bits[i] then | 586 | -- print('!!!! No idea where to find source ' .. source) |
141 | depth = i | 587 | return 'DUNNO' |
142 | break | 588 | end |
589 | if nil == Subs[dest] then | ||
590 | if dest == Subs[source].bit then | ||
591 | return '' | ||
592 | else | ||
593 | -- print('!!!! No idea where to find dest ' .. dest .. ' from ' .. Subs[source].path .. ' / ' .. Subs[source].bit) | ||
594 | return 'DUNNO' | ||
143 | end | 595 | end |
144 | end | 596 | end |
145 | depth = #(Subs[source].bits) - depth | 597 | local s = Subs[source].bits |
146 | depth = depth + 1 | 598 | local d = Subs[dest].bits |
147 | link = string.rep('../', depth) | 599 | local sl = #s |
148 | if (0 == depth) or (depth > #(Subs[dest].bits)) then | 600 | local dl = #d |
149 | for i, v in ipairs(Subs[dest].bits) do | 601 | |
150 | if i >= depth then | 602 | if 0 == dl then |
151 | if '' ~= link then link = link .. '/' end | 603 | depth = sl |
152 | link = link .. Subs[dest].bits[i] | 604 | else |
605 | for i, v in ipairs(s) do | ||
606 | if (nil == d[i]) or (v ~= d[i]) then | ||
607 | depth = i | ||
608 | break | ||
153 | end | 609 | end |
154 | end | 610 | end |
155 | end | 611 | end |
612 | -- depth is where they DON'T match. | ||
613 | local m = depth - 1 | ||
614 | if 0 > m then m = 0 end | ||
615 | lnk = string.rep('../', sl - m) | ||
616 | if 0 ~= (m + 1) then lnk = lnk .. table.concat(d, '/', m + 1, dl) end | ||
156 | end | 617 | end |
157 | return link | 618 | return lnk |
158 | end | 619 | end |
159 | 620 | ||
160 | 621 | ||
161 | 622 | ||
623 | --------------------------------------------------------------------------------- | ||
162 | -- More of this actually doing things nonsense. | 624 | -- More of this actually doing things nonsense. |
163 | 625 | ||
164 | -- Loop through the files we found and actually create their HTML files. | 626 | -- Create an "everything" page, for URL links to every file.HTML. |
627 | local Bdy = '# All the pages\n\n| page | original page | last edited UTC | \n| --------- | ------- | --------------- | ' | ||
628 | Pages = {} | ||
165 | for name, file in pairs(Files) do | 629 | for name, file in pairs(Files) do |
166 | local path, result = '', '' | 630 | local metadata = derefTable(Files[name].metadata, true) |
167 | local body, metadata = Files[name].body, Files[name].metadata | 631 | if ('everything' ~= name) then |
168 | local bits, bit = Files[name].bits, Files[name].bit | 632 | local ln, fw, pw, ts = 'DUNNO', '', '', '' |
169 | local ln = #bits | 633 | local title, link = whichWiki(metadata) |
170 | 634 | link = string.gsub(link, 'https://', 'HTTPS://') -- Prevent this one from being converted. | |
171 | path = table.concat(bits, '/', 1, ln) | 635 | if 'PmWiki' == metadata.ogWiki then pw = 'PmWiki [' .. title .. '](' .. link .. ')' end |
636 | if 'Foswiki' == metadata.ogWiki then fw = 'Foswiki [' .. title .. '](' .. link .. ')' end | ||
637 | if nil ~= metadata.timestamp then ts = metadata.timestamp end | ||
638 | if nil ~= file.bit then ln = file.bit | ||
639 | end | ||
640 | table.insert(Pages, '\n| [' .. name .. '](<' .. name .. '.HTML>) | ' .. fw .. ' ' .. pw .. ' | ' .. ts .. ' |') | ||
172 | 641 | ||
173 | if '' ~= body then | 642 | -- Track our external links. |
174 | -- Continue the parsing and conversion. Start by turning our parsed body into something the lcmark template system can grock. | 643 | if (nil ~= metadata.ogBase) and (nil ~= metadata.ogFile) then |
175 | local bod, err = lcmark.compile_template(body) | 644 | local n = metadata.ogBase |
176 | if nil == bod then print('oops! ' .. err) else | 645 | if 'PmWiki' == metadata.ogWiki then n = n .. '.' else n = n .. '/' end |
177 | local templateFile = metadata.template | 646 | xLinks[n .. metadata.ogFile] = file.path |
178 | if nil == templateFile then templateFile = 'default' end | ||
179 | file.template = templateFile .. '.template' | ||
180 | end | 647 | end |
648 | end | ||
649 | end | ||
650 | table.sort(Pages, function(a, b) return (string.lower(a) < string.lower(b)) end) | ||
651 | for i, f in ipairs(Pages) do | ||
652 | Bdy = Bdy .. f | ||
653 | end | ||
654 | h = io.open('everything.md', 'a+') | ||
655 | if nil ~= h then | ||
656 | h:write(Bdy) | ||
657 | h:close() | ||
658 | else | ||
659 | print("Can't open everything.md for writing.") | ||
660 | end | ||
661 | toFile('everything', 'body', Bdy) | ||
181 | 662 | ||
182 | -- Copy any metadata found in parent directories. | 663 | |
183 | local pth = '' | 664 | -- Loop through Subs, doing whichPage and inheritance. |
184 | for i, d in ipairs(bits) do | 665 | -- It gets to testing/even/deeper BEFORE it gets to testing/even sometimes. So sort them. |
185 | if '' ~= pth then pth = pth .. '/' end | 666 | SUBS = {} |
186 | pth = pth .. d | 667 | for name, sub in pairs(Subs) do |
187 | if nil ~= Subs[pth] then | 668 | table.insert(SUBS, sub) |
188 | if nil ~= Subs[pth].metadata then | 669 | end |
189 | for m, x in pairs(Subs[pth].metadata) do | 670 | table.sort(SUBS, function(a, b) return (string.lower(a.path) < string.lower(b.path)) end) |
190 | if nil == metadata[m] then | 671 | for n, sub in pairs(SUBS) do |
191 | metadata[m] = x | 672 | local name = sub.path |
192 | end | 673 | sub.whichPage = whichPage(name) |
674 | local metadata = sub.metadata | ||
675 | for i, s in pairs(sub.subs) do | ||
676 | local nm = i | ||
677 | if '' ~= name then nm = name .. '/' .. i end | ||
678 | for k, v in pairs(metadata) do | ||
679 | if nil == Subs[nm].metadata[k] then | ||
680 | if ('favicon' == k) or ('logo' == k) then | ||
681 | Subs[nm].metadata[k] = linkFrom(nm, name) .. v | ||
682 | else | ||
683 | if 'hidden' ~= k then -- Don't inherit hidden. | ||
684 | Subs[nm].metadata[k] = v | ||
193 | end | 685 | end |
194 | end | 686 | end |
195 | end | 687 | end |
196 | end | 688 | end |
197 | -- Root directory needs to be handled separately, for now. | 689 | end |
198 | if nil ~= Subs[''].metadata then | 690 | end |
199 | for m, x in pairs(Subs[''].metadata) do if nil == metadata[m] then metadata[m] = x end end | 691 | |
692 | -- Files inheritance. | ||
693 | for name, file in pairs(Files) do | ||
694 | if '' ~= file.body then | ||
695 | local mdata = Subs[file.path].metadata | ||
696 | for k, v in pairs(mdata) do | ||
697 | if nil == file.metadata[k] then | ||
698 | Files[name].metadata[k] = v | ||
699 | end | ||
200 | end | 700 | end |
701 | end | ||
702 | end | ||
201 | 703 | ||
202 | for m, x in pairs(globalData) do if nil == metadata[m] then metadata[m] = x end end | ||
203 | 704 | ||
204 | -- Inherit these images from most recent parent directory that defines them. | 705 | --------------------------------------------------------------------------------- |
205 | for n, y in ipairs{'favicon', 'logo'} do | 706 | -- Setup the lunarmark stuff. |
206 | local pith = '' | 707 | local LunamarkOpts = { |
207 | if nil ~= metadata[y] then | 708 | layout='compact', |
208 | local pth = '' | 709 | -- This list is copied from the lunamark source code, until I discover a way to discover it. The descriptions are useful to. |
209 | for m, x in ipairs(bits) do | 710 | containers=false, -- Put sections in containers (e.g. div or section tags) |
210 | if '' ~= pth then pth = pth .. '/' end | 711 | slides=false, -- Like containers, but do not nest them |
211 | pth = pth .. x | 712 | startnum=true, -- Start number of an ordered list is significant |
212 | if (nil ~= Subs[pth].metadata) and (nil ~= Subs[pth].metadata[y]) then pith = pth end | 713 | smart=false, -- Smart typography (quotes, dashes, ellipses) |
714 | preserve_tabs=true, -- Don't expand tabs to spaces | ||
715 | notes=true, -- Footnotes | ||
716 | inline_notes=true, -- Inline footnotes | ||
717 | definition_lists=true, -- Definition lists | ||
718 | citations=true, -- Citations | ||
719 | citation_nbsps=true, -- Turn spacing into non-breaking spaces in citations | ||
720 | fenced_code_blocks=true, -- Fenced code blocks | ||
721 | lua_metadata=true, -- Lua metadata | ||
722 | pandoc_title_blocks=true, -- Pandoc style title blocks | ||
723 | hash_enumerators=true, -- may be used as ordered list enumerator | ||
724 | require_blank_before_blockquote=false, | ||
725 | require_blank_before_header=false, | ||
726 | require_blank_before_fenced_code_block=false, | ||
727 | fancy_lists=true, -- Pandoc style fancy lists | ||
728 | task_list=true, -- GitHub-Flavored Markdown task list | ||
729 | strikeout=true, -- Strike-through with double tildes | ||
730 | mark=true, -- Highlight with double equals | ||
731 | subscript=true, -- Subscripted text between tildes | ||
732 | superscript=true, -- Superscripted text between circumflexes | ||
733 | bracketed_spans=true, -- Spans with attributes | ||
734 | fenced_divs=true, -- Divs with attributes | ||
735 | raw_attribute=true, -- Raw pass-through on code elements | ||
736 | fenced_code_attributes=true, -- Fenced code block attributes | ||
737 | link_attributes=true, -- Link attributes | ||
738 | pipe_tables=true, -- PHP Markdown Extra pipe table support | ||
739 | table_captions=true, -- Table caption syntax extension | ||
740 | header_attributes=true, -- Header attributes | ||
741 | line_blocks=true, -- Line blocks | ||
742 | escaped_line_breaks=true, -- Pandoc-style escaped hard line breaks | ||
743 | } | ||
744 | local Writer = Lunamark.writer.html5.new(LunamarkOpts) | ||
745 | -- Can override the various writer functions, there's something for each of the basic HTML elements. | ||
746 | local lunaLinky = function(url) -- Fix up the links. | ||
747 | if ('https://wiki.devuan.org/' ~= url) and ('https://fos.wiki.devuan.org/' ~= url) then | ||
748 | -- TODO - This might be covering up a bug elsewhere. | ||
749 | if '/Main/' == string.sub(url, 1, 6) then | ||
750 | local link = linkFrom(Context.path, 'Foswiki/Main') | ||
751 | if '' == link then | ||
752 | url = string.sub(url, 7) .. '.HTML' | ||
753 | else | ||
754 | url = link .. '/' .. string.sub(url, 7) .. '.HTML' | ||
755 | end | ||
756 | end | ||
757 | if '/System/' == string.sub(url, 1, 8) then | ||
758 | url = 'https://fos.wiki.devuan.org' .. url | ||
759 | end | ||
760 | for i, p in ipairs{'https://wiki.devuan.org/?n=', 'https://wiki.devuan.org?n=', 'PmWiki/uploads/', 'Foswiki/pub/', 'https://fos.wiki.devuan.org/'} do | ||
761 | if p == string.sub(url, 1, #p) then | ||
762 | local ur = string.sub(url, #p + 1) | ||
763 | -- TODO - could probably replace some of this mess with RE.gsub() and friends. Meh, it works. | ||
764 | local f4, f5, tk1 = string.find(ur, '?', 1, true) | ||
765 | if fail ~= f4 then | ||
766 | local u = string.sub(ur, 1, f4 - 1) | ||
767 | ur = u | ||
213 | end | 768 | end |
214 | if ('' == pith) and (nil ~= Subs[''].metadata) and (nil ~= Subs[''].metadata[y]) then pith = pth end | 769 | local md |
215 | if '' == pith then metadata[y] = linkFrom(path, pith) .. globalData[y] | 770 | if ('fos' == string.sub(p, 9, 11)) or ('Fos' == string.sub(p, 1, 3)) then |
216 | else metadata[y] = linkFrom(path, pith) .. metadata[y] | 771 | md = readMdMd('Foswiki/' .. ur .. '.md', {}) |
772 | else | ||
773 | md = readMdMd('PmWiki/' .. string.gsub(ur, '%.', '/', 1) .. '.md', {}) | ||
774 | end | ||
775 | if (nil ~= md) and (nil ~= md.realURL) then url = md.realURL end | ||
776 | |||
777 | if ('https://fos.wiki.devuan.org/bin/' ~= string.sub(url, 1, 32)) and ('https://fos.wiki.devuan.org/System/' ~= string.sub(url, 1, 35)) then | ||
778 | local xlnk = xLinks[string.gsub(ur, '%..*', '', 1)] | ||
779 | if nil == Context.path then | ||
780 | url = string.gsub(ur, '%.', '/', 1) | ||
781 | else | ||
782 | if nil == xlnk then xlnk = string.gsub(string.gsub(ur, '%..*', '', 1), '/.*', '', 1) end | ||
783 | if '' ~= Context.path then xlnk = linkFrom(Context.path, xlnk) end | ||
784 | if '/' == string.sub(xlnk, 1, 1) then xlnk = string.sub(xlnk, 2) end | ||
785 | if ('' ~= xlnk) and ('/' ~= string.sub(xlnk, -1)) then xlnk = xlnk .. '/' end | ||
786 | if 'DUNNO/' == xlnk then print('OOPS! page not found - @' .. Context.path .. ' / ' .. Context.bit .. '\t' .. url .. ' -> ' .. xlnk .. ' ' .. string.gsub(ur, '.*%.', '', 1) .. '.HTML') end | ||
787 | end | ||
788 | -- if (nil ~= md) and (nil ~= md.realURL) then url = md.realURL | ||
789 | -- else | ||
790 | url = xlnk .. string.gsub(ur, '.*%.', '', 1) | ||
791 | -- end | ||
792 | if 'PmWiki/uploads/' == p then | ||
793 | url = '../../' .. p .. string.gsub(ur, '%.', '.', 1) | ||
794 | elseif 'Foswiki/pub/' == p then | ||
795 | url = '../../' .. p .. ur | ||
796 | else | ||
797 | url = url .. '.HTML' | ||
798 | end | ||
217 | end | 799 | end |
218 | end | 800 | end |
219 | end | 801 | end |
802 | end | ||
803 | return url | ||
804 | end | ||
220 | 805 | ||
221 | -- Figure out this pages header links. | 806 | function Writer.header(s, level) |
222 | metadata.header = '' | 807 | local text = Lunamark.util.rope_to_string(s) |
223 | for i, f in pairs(Subs[path].subs) do | 808 | -- FIXME - Work around a bug in Lunamark? |
224 | local pth = path | 809 | text = RE.gsub(text, "{[\\]}", "") |
225 | if '' ~= path then pth = path .. '/' end | 810 | return '<h' .. level .. ' id="' .. RE.gsub(text, '{[ ]}', '_') .. '">' .. text .. ' <a style="font-size: 0.42em;" href="#top">🔼</a></h' .. level .. '>' |
226 | local fl = whichPage(pth .. f) | 811 | end |
227 | -- if '' == fl then | 812 | local OgWriterLink = Writer.link -- So we can call the original from within mine, we are just changing the URL. |
228 | -- metadata.header = metadata.header .. f .. ' ' | 813 | function Writer.link(lab, url, tit) |
229 | -- else | 814 | return OgWriterLink(lab, lunaLinky(url), tit) |
230 | metadata.header = metadata.header .. '<a href="' .. f .. '/' .. fl .. '">' .. f .. '</a> ' | 815 | end |
231 | -- end | 816 | local OgWriterImage = Writer.image |
232 | end | 817 | function Writer.image(lab, url, tit) |
818 | return OgWriterImage(lab, lunaLinky(url), tit) | ||
819 | end | ||
820 | |||
821 | local Parse = Lunamark.reader.markdown.new(Writer, LunamarkOpts) | ||
233 | 822 | ||
234 | -- Figure out this pages menu links. | ||
235 | metadata.menu = '' | ||
236 | if nil ~= Subs[path].files then table.sort(Subs[path].files) end | ||
237 | for i, f in ipairs(Subs[path].files) do | ||
238 | if name == f then | ||
239 | metadata.menu = metadata.menu .. '<p>' .. f .. '</p>' | ||
240 | else | ||
241 | metadata.menu = metadata.menu .. '<p><a href="' .. f .. '.HTML">' .. f .. '</a></p>' | ||
242 | end | ||
243 | end | ||
244 | 823 | ||
824 | --------------------------------------------------------------------------------- | ||
825 | -- Loop through the files we found and actually create their HTML files. | ||
826 | for name, file in pairs(Files) do | ||
827 | local body, metadata = Files[name].body, derefTable(Files[name].metadata, true) | ||
828 | local bits, bit = Files[name].bits, Files[name].bit | ||
829 | local ln = #bits | ||
830 | local result = '' | ||
831 | |||
832 | if '' ~= body then | ||
245 | -- Figure out this pages trail links. | 833 | -- Figure out this pages trail links. |
834 | metadata.home = linkFrom(file.path, '') .. Subs[''].whichPage | ||
246 | metadata.trail = '' | 835 | metadata.trail = '' |
247 | for i, b in ipairs(bits) do | 836 | for i, b in ipairs(bits) do |
837 | local p = table.concat(bits, '/', 1, i) | ||
248 | if i < #bits then | 838 | if i < #bits then |
249 | metadata.trail = metadata.trail .. '<a href="' .. linkFrom(path, table.concat(bits, '/', 1, i)) .. whichPage(b) .. '">' .. b .. '</a> ' | 839 | metadata.trail = metadata.trail .. '<a href="' .. linkFrom(file.path, p) .. Subs[p].whichPage .. '">' .. b .. '</a> 👣 ' |
250 | linkFrom(path, table.concat(bits, '/', 1, i)) | 840 | linkFrom(file.path, table.concat(bits, '/', 1, i)) |
251 | else | 841 | else |
252 | metadata.trail = metadata.trail .. b .. ' ' | 842 | metadata.trail = metadata.trail .. ' ' .. b |
253 | end | 843 | end |
254 | end | 844 | end |
255 | -- if '' == metadata.trail then metadata.trail = '<a href="' .. string.rep('../', ln) .. '/' .. whichPage('') .. '">home</a> ' end | ||
256 | |||
257 | -- Figure out this pages footer links. | ||
258 | if nil ~= metadata.pagehistory then metadata.history = '<p>Page <a href="' .. metadata.pagehistory .. '">history</a></p>' end | ||
259 | if nil ~= metadata.sourcecode then metadata.footer = '<a href="' .. metadata.sourcecode .. '">source code</a> ' .. metadata.footer end | ||
260 | if nil ~= metadata.feedatom then metadata.footer = '<a href="' .. metadata.feedatom .. '">atom feed</a> ' .. metadata.footer end | ||
261 | if metadata.footer ~= globalData.footer then metadata.footer = 'Web site ' .. metadata.footer end | ||
262 | metadata.footer = '<p>' .. metadata.footer .. '</p>' | ||
263 | 845 | ||
264 | -- Apply the template to the body. | 846 | -- Figure out this pages header links. |
265 | metadata.body = lcmark.apply_template(bod, metadata) | 847 | metadata.header = '' |
848 | subs = {} | ||
849 | for i, f in pairs(Subs[file.path].subs) do | ||
850 | table.insert(subs, f) | ||
851 | end | ||
852 | table.sort(subs, function(a, b) return (string.lower(a) < string.lower(b)) end) | ||
853 | for i, f in ipairs(subs) do | ||
854 | local pth = file.path | ||
855 | if '' ~= file.path then pth = file.path .. '/' end | ||
856 | if 'true' ~= Subs[pth .. f].metadata.hidden then | ||
857 | metadata.header = metadata.header .. '<a href="' .. f .. '/' .. whichPage(pth .. f) .. '">' .. f .. '</a> 📂 ' | ||
858 | end | ||
859 | end | ||
266 | 860 | ||
267 | -- Put it all in the template. | 861 | -- Figure out this pages menu links. |
268 | local tm = '' | 862 | metadata.menu = '' |
269 | if nil ~= file.template then | 863 | if nil == metadata.title then metadata.title = bit end |
270 | local h = io.open(file.template, 'r') | 864 | if nil ~= Subs[file.path].files then table.sort(Subs[file.path].files, function(a, b) return (string.lower(a) < string.lower(b)) end) end |
271 | if nil ~= h then | 865 | for i, f in ipairs(Subs[file.path].files) do |
272 | tm = tm .. h:read('*a') | 866 | local title, url = nil, nil |
273 | h:close() | 867 | if '' == file.path then |
868 | title = Files[f].metadata.title | ||
869 | url = Files[f].metadata.URL | ||
274 | else | 870 | else |
275 | print('oops! No such file ' .. file.template) | 871 | title = Files[file.path .. '/' .. f].metadata.title |
872 | url = Files[file.path .. '/' .. f].metadata.URL | ||
276 | end | 873 | end |
277 | 874 | if nil == title then title = f end | |
278 | -- TODO - Um not sure why this is here AND at the top of the loop. Here makes more sense. | 875 | if bit == f then |
279 | local template, err = lcmark.compile_template(tm) | 876 | metadata.menu = metadata.menu .. '<p>' .. title .. '</p>' |
280 | if nil == template then print('oops! ' .. err) else | 877 | for j, g in ipairs(file.headers) do |
281 | result = lcmark.apply_template(template, metadata) | 878 | local beg, en = RE.find(g, [['{']]) |
879 | if nil ~= beg then | ||
880 | g = string.sub(g, 1, beg - 2) | ||
881 | end | ||
882 | local h = string.sub(RE.gsub(g, '{[#]}', ''), 2) | ||
883 | local l = string.len(g) - string.len(h) | ||
884 | g = h | ||
885 | h = RE.gsub(h, '{[ ]}', ' ') | ||
886 | -- FIXME - Work around a bug in Lunamark? | ||
887 | g = RE.gsub(g, '{[\\]}', '') | ||
888 | h = RE.gsub(h, '{[\\]}', '') | ||
889 | -- FIXME - if it's a linky, strip off the URL part. The Wiki audit has such things. | ||
890 | metadata.menu = metadata.menu .. '<p>' .. string.rep(' ', l) .. '<a style="font-size: 0.80em;" href="#' .. RE.gsub(g, '{[ ]}', '_') .. '">' .. h .. '</a></p>' | ||
891 | end | ||
892 | else | ||
893 | if nil ~= url then metadata.menu = metadata.menu .. '<p><a href="' .. url .. '">' .. title .. ' ☝</a></p>' | ||
894 | else | ||
895 | local pth = file.path | ||
896 | if '' ~= pth then pth = pth .. '/' end | ||
897 | -- Don't include any left over .md.md files, so don't do this if f.md doesn't exist. | ||
898 | local a, e = io.open(pth .. f .. '.md' , 'r') | ||
899 | if nil ~= a then | ||
900 | a:close() | ||
901 | metadata.menu = metadata.menu .. '<p><a href="' .. f .. '.HTML">' .. title .. '</a></p>' | ||
902 | end | ||
903 | end | ||
282 | end | 904 | end |
905 | end | ||
906 | |||
907 | -- Figure out this pages footer links. | ||
908 | local temp = '' | ||
909 | metadata.footer = '' | ||
910 | if nil == metadata.pagehistory then | ||
911 | if 'Foswiki' == metadata.ogWiki then metadata.pagehistory = metadata.ogURL .. '/bin/oops/' .. metadata.ogBase .. '/' .. metadata.ogFile .. '?template=oopshistory' end | ||
912 | if 'PmWiki' == metadata.ogWiki then metadata.pagehistory = metadata.ogURL .. '/?n=' .. metadata.ogBase .. '.' .. metadata.ogFile .. '?action=diff' end | ||
283 | else | 913 | else |
284 | result = body | 914 | temp = '/' .. name .. '.md' |
285 | end | 915 | end |
916 | if nil ~= metadata.pagehistory then metadata.history = '<p>Page <a href="' .. metadata.pagehistory .. temp .. '">history</a></p>' else | ||
917 | metadata.history = '' | ||
918 | end | ||
919 | if nil ~= metadata.sourcecode then metadata.footer = '<a href="' .. metadata.sourcecode .. '">source code</a>' end | ||
920 | if nil ~= metadata.feedatom then metadata.footer = '<a href="' .. metadata.feedatom .. '">atom feed<img src="feed-icon-14x14.png"></img></a> ' .. metadata.footer end | ||
921 | if metadata.footer ~= '' then metadata.footer = 'Web site ' .. metadata.footer end | ||
922 | -- Add a link to the original page. | ||
923 | if nil ~= metadata.ogURL then | ||
924 | local title, link = whichWiki(metadata) | ||
925 | link = string.gsub(link, 'https://', 'HTTPS://') -- Prevent this one from being converted. | ||
926 | -- TODO - wrap "edit" in a link to actually edit it. PmWiki "?action=edit" Foswiki "https://fos.wiki.devuan.org/bit/edit/" .. page .. "?t=" .. 10 digit random number? | ||
927 | local edit = 'T' | ||
928 | if 'PmWiki' == metadata.ogWiki then edit = 'Maybe you can <a href="' .. link .. '?action=edit">edit</a> t' end | ||
929 | -- if 'Foswiki' == metadata.ogWiki then edit = '' end | ||
930 | metadata.footer = edit .. 'he <a href="' .. link .. '">original page</a>. ' .. metadata.footer | ||
931 | end | ||
932 | metadata.footer = '<p>' .. metadata.footer .. '</p>' | ||
933 | |||
934 | -- Do our own metadata replacement, it's simple and works better. | ||
935 | local temp = Template | ||
936 | -- Toss the body in first, so the scan can deal with it to. | ||
937 | -- NOTE - this is where we actually parse the markup into HTML. | ||
938 | Context = file | ||
939 | body = RE.gsub(body, '{[%nl]^1[%a]+}[.]^1 ', '%1$dot$ ') -- Coz otherwise stray . trip up the list detection. | ||
940 | local bd, md = Parse(body) -- The md is a table of extracted metadata, not likely to be any, and we wont do anything with it. | ||
941 | bd = RE.gsub(bd, '{[%]}', '$perc$') -- Coz otherwise stray % trip up the capture part. | ||
942 | temp = RE.gsub(temp, '"$body$"', bd) | ||
943 | -- The actual metadata replacement. | ||
944 | result = RE.compile ('{~ ({[$][A-Za-z_]+[$]} -> meta / .)* ~}', | ||
945 | { | ||
946 | meta = function(a) | ||
947 | a = string.sub(a, 2, -2) | ||
948 | local md = metadata[a] | ||
949 | if nil == md then | ||
950 | md = GlobalMetaData[a] | ||
951 | if nil == md then | ||
952 | md = a | ||
953 | end | ||
954 | end | ||
955 | return md | ||
956 | end | ||
957 | } ):match(temp) | ||
286 | 958 | ||
287 | -- Write the file. | 959 | -- Write the file. |
288 | if '' ~= result then | 960 | if '' ~= result then |
289 | local base = name .. '.HTML' | 961 | -- print('From ' .. name .. '.md -> ' .. base) |
290 | print('From ' .. name .. '.md -> ' .. base) | 962 | writeString(name .. '.HTML', result) |
291 | local a, e = io.open(base, 'w') | ||
292 | if nil == a then print('Could not open ' .. base .. ' - ' .. e) else | ||
293 | a:write(result) | ||
294 | a:close() | ||
295 | end | ||
296 | end | 963 | end |
297 | |||
298 | else | ||
299 | print('') | ||
300 | end | 964 | end |
301 | end | 965 | end |
302 | 966 | ||
diff --git a/testing/.md.md b/testing/.md.md new file mode 100644 index 0000000..28c4410 --- /dev/null +++ b/testing/.md.md | |||
@@ -0,0 +1 @@ | |||
logo=Connie_click-me.gif | |||
diff --git a/testing/MeTaDaTa.md b/testing/MeTaDaTa.md deleted file mode 100644 index c4b8e60..0000000 --- a/testing/MeTaDaTa.md +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | --- | ||
2 | logo: Connie_click-me.gif | ||
3 | --- | ||
diff --git a/testing/index.md b/testing/index.md index f926155..581d301 100644 --- a/testing/index.md +++ b/testing/index.md | |||
@@ -1,71 +1,94 @@ | |||
1 | --- | 1 | # G'day world! |
2 | pagetitle: "G'day world!" | 2 | |
3 | author: onefang | 3 | I've been around since the early sixties, but no one ever noticed. You |
4 | pagehistory: https://sledjhamr.org/cgit/notYetAnotherWiki/log/testing/index.md | 4 | really should have tried to pay attention though, I'm awesome. I try to |
5 | --- | 5 | help the world, but that's not what everyone wants me to do. Well, the |
6 | |||
7 | I've been around since the early sixties, but no one ever noticed. You | ||
8 | really should have tried to pay attention though, I'm awesome. I try to | ||
9 | help the world, but that's not what everyone wants me to do.$_$ Well, the | ||
10 | people in charge of this poor defenseless world of ours. | 6 | people in charge of this poor defenseless world of ours. |
11 | 7 | ||
12 | 8 | ||
13 | *** | 9 | *** |
14 | 10 | ||
11 | ## Em'n'Strong | ||
12 | |||
13 | Test *em* _em_ **strong** __strong__ . | ||
14 | |||
15 | # Spaces | 15 | # Spaces |
16 | 16 | ||
17 | Can it *handle* my _usual_ two **space** sentence breaks? Let's test it.$_$ Not by default. | 17 | Can it *handle* my _usual_ two **space** sentence breaks? Let's test it. Not by default. |
18 | 18 | ||
19 | The \\ before a space turns it into a "a literal unicode nonbreaking space character" which looks invisible in the source. \--ascii should output the HTML code far that.$_$ Except doesn't actually work. | 19 | The \\ before a space turns it into a "a literal unicode nonbreaking space character" which looks invisible in the source.\ \--ascii should output the HTML code far that. Except doesn't actually work. |
20 | 20 | ||
21 | Also a \\ at the end of a line turns into a line break, though they get wrapped in paragraph tags.$_$ lol | 21 | Also a \\ at the end of a line turns into a line break, though they get wrapped in paragraph tags. lol \ |
22 | 22 | ||
23 | Take two.$_$ And now for something completely different. It's not consistant, need to manually put in the nbsp a few times above. Ah, it only works for the first one per line. | 23 | Just to double check. That's a single space. |
24 | 24 | ||
25 | \ | 25 | \ \$ \' \" \| % |
26 | |||
27 | I'm 100% sure that % will get treated correctly now. | ||
26 | 28 | ||
27 | ## Strike out | 29 | ## Strike out |
28 | 30 | ||
29 | Test ~~strike~~ --out--.$_$ Needs the extension. | 31 | Test ~~strike~~ --out--. Needs the extension. |
30 | 32 | ||
31 | ### URL | 33 | ### URL |
32 | 34 | ||
33 | [untalenz](https://untalenz.rocks/) | 35 | [untalenz](https://untalenz.rocks/) |
34 | 36 | ||
37 | [nope.example.com](http://nope.example.com/) | ||
38 | |||
35 | https://sledjhamr.org/ | 39 | https://sledjhamr.org/ |
36 | 40 | ||
37 | # Lists | 41 | # Lists |
38 | 42 | ||
39 | 43 | ||
40 | * zero | 44 | * first star |
41 | * 1 | 45 | * second star |
42 | * two | ||
43 | 46 | ||
44 | - zero | 47 | <!-- Separate the lists. --> |
45 | - 1 | ||
46 | - two | ||
47 | 48 | ||
49 | - first dash | ||
50 | - second dash | ||
48 | 51 | ||
49 | No way to say "here is the end of the list" without putting something **else** here?$_$ Ah a comment will work, or anything else. | 52 | No way to say "here is the end of the list" without putting something **else** here? Ah a comment will work, or anything else. |
50 | 53 | ||
54 | 1. one | ||
55 | 2. two | ||
56 | |||
57 | <!-- A comment will work --> | ||
51 | 58 | ||
59 | 0. zero | ||
52 | 1. one | 60 | 1. one |
53 | 2. 2 | 61 | 2. two |
54 | 62 | ||
63 | Autonumbering? Needs the extension. Doesn't matter, they get renumbered anyway if out of order. | ||
55 | 64 | ||
56 | <!-- A comment will work --> | 65 | 0. zero |
66 | #. first hash | ||
67 | #. second hash | ||
57 | 68 | ||
69 | <!-- Separate the lists. --> | ||
58 | 70 | ||
59 | 0. 0 | 71 | #. first hash |
60 | 1. one | 72 | #. second hash |
61 | 2. 2 | 73 | #. third hash |
62 | 74 | ||
63 | Autonumbering? Nope. B-( | 75 | <!-- Separate the lists. --> |
64 | 76 | ||
65 | 0. zero | 77 | 0. zero |
66 | 1 | 78 | 2. two |
67 | two | 79 | 1. one |
80 | |||
81 | Bug. If there's a single word and period at the beginning of a line, it gets turned into a list, or list item. | ||
82 | |||
83 | <!-- Separate the lists. --> | ||
84 | |||
85 | Bug. If there's a single word and period at the beginning of a line, it gets turned into a list, or list item. | ||
86 | |||
87 | ~~~ | ||
88 | Bug. If there's a single word and period at the beginning of a line, it gets turned into a list, or list item. | ||
89 | ~~~ | ||
68 | 90 | ||
91 | The stuff in a code block is in a different font, it's mono. lol | ||
69 | 92 | ||
70 | # images | 93 | # images |
71 | 94 | ||
@@ -84,19 +107,46 @@ Autonumbering? Nope. B-( | |||
84 | 107 | ||
85 | Plus some extra text. | 108 | Plus some extra text. |
86 | 109 | ||
110 | |||
111 | Next code block. | ||
112 | |||
113 | |||
114 | ~~~lua | ||
115 | a simple | ||
116 | indented code block | ||
117 | <a/> | ||
118 | *hi* | ||
119 | |||
120 | - one | ||
121 | |||
122 | Plus some extra text. | ||
123 | ~~~ | ||
124 | |||
125 | |||
126 | Next code block. | ||
127 | |||
87 | ~~~ | 128 | ~~~ |
88 | < | 129 | < |
89 | > | 130 | > |
90 | ~~~ | 131 | ~~~ |
91 | 132 | ||
133 | And a really long one, should turn scrollable. | ||
92 | ~~~lua | 134 | ~~~lua |
93 | -- Show some Lua code here, may even be highlighted right. | 135 | -- Show some Lua code here, may even be highlighted right. |
94 | print("G'day world!") | 136 | print("G'day world!") |
95 | -- Let's see what happens with the HTML output by cmark, then gets rendered by the web browser, inside my CSS styled pre code thingy that cmark produces. For a very very very loooong line. Needs to be much longer. What else can I add to this already quite long line to get it to trigger being overly long? I need even mooooooore??? | 137 | -- Let's see what happens with the HTML output by cmark, then gets rendered by the web browser, inside my CSS styled pre code thingy that cmark produces. For a very very very loooong line. Needs to be much longer. What else can I add to this already quite long line to get it to trigger being overly long? I need even mooooooore??? |
96 | print'The problem here is that I have to use CSS to style these things, coz cmark wont let me at the style stuff as far as I can see. But using CSS web browsers think the nmall box STILL extends all the way to the end of the content, but the scroll works anyway. So it's fucking up the size of the container.' | 138 | print'The problem here is that I have to use CSS to style these things, coz cmark wont let me at the style stuff as far as I can see. But using CSS web browsers think the small box STILL extends all the way to the end of the content, but the scroll works anyway. So it's fucking up the size of the container.' |
97 | ~~~ | 139 | ~~~ |
98 | 140 | ||
99 | > # What is a blockquote? | 141 | > # What is a blockquote? |
100 | > Still don't know. lol | 142 | > Still don't know. lol |
101 | > | 143 | > |
102 | > Just another useless way to eat space I guess.$_$ shrugs | 144 | > Just another useless way to eat space I guess. shrugs |
145 | > Might be why emails sometimes get that symbol dropped in HTML conversions. | ||
146 | |||
147 | |||
148 | |This should be a table. |With two columns and a link | | ||
149 | |-------------------------|-------------------------------| | ||
150 | |cell 0,0 |cell 0,1 | | ||
151 | |cell 1,0 |[linky](https://sledjhamr.org) | | ||
152 | |||
diff --git a/testing/index.md.md b/testing/index.md.md new file mode 100644 index 0000000..c85bb3f --- /dev/null +++ b/testing/index.md.md | |||
@@ -0,0 +1 @@ | |||
title=G'day world! | |||