diff options
-rw-r--r-- | .md.md | 5 | ||||
-rw-r--r-- | Connie_click-me.gif | bin | 4259 -> 0 bytes | |||
-rw-r--r-- | INSTALL.md | 11 | ||||
-rw-r--r-- | LICENCE | 31 | ||||
-rw-r--r-- | README | 23 | ||||
-rw-r--r-- | README.md.md | 1 | ||||
-rwxr-xr-x | SuckIt | 162 | ||||
-rwxr-xr-x | SuckItClean | 13 | ||||
-rwxr-xr-x | SuckItCron | 4 | ||||
-rw-r--r-- | TODO.md | 100 | ||||
l--------- | about/Connie_click-me.gif | 1 | ||||
-rw-r--r-- | about/index.md | 25 | ||||
-rw-r--r-- | default.template | 150 | ||||
-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 | 0 -> 16624 bytes | |||
-rw-r--r-- | nYAW.xcf | bin | 0 -> 25929 bytes | |||
-rw-r--r-- | nYAW_icon.png | bin | 0 -> 6315 bytes | |||
-rw-r--r-- | nYAW_icon.xcf | bin | 0 -> 14685 bytes | |||
-rwxr-xr-x | notYetAnotherWiki.lua | 1058 | ||||
-rw-r--r-- | testing/.md.md | 1 | ||||
-rw-r--r--[l---------] | testing/Connie_click-me.gif | bin | 22 -> 4259 bytes | |||
-rw-r--r-- | testing/index.md | 117 | ||||
-rw-r--r-- | testing/index.md.md | 1 |
27 files changed, 1464 insertions, 285 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 | ||
diff --git a/Connie_click-me.gif b/Connie_click-me.gif deleted file mode 100644 index 6f0b361..0000000 --- a/Connie_click-me.gif +++ /dev/null | |||
Binary files differ | |||
@@ -1,13 +1,6 @@ | |||
1 | --- | 1 | # Install |
2 | favicon: cartdave_favicon.png | ||
3 | pagetitle: "INSTALL" | ||
4 | author: onefang | ||
5 | feedatom: https://sledjhamr.org/cgit/notYetAnotherWiki/atom | ||
6 | history: https://sledjhamr.org/cgit/notYetAnotherWiki/log/INSTALL.md | ||
7 | sourcecode: https://sledjhamr.org/cgit/notYetAnotherWiki/ | ||
8 | --- | ||
9 | 2 | ||
10 | 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. |
11 | 4 | ||
12 | You also need luajit installed. | 5 | You also need luajit installed. |
13 | 6 | ||
@@ -0,0 +1,31 @@ | |||
1 | Copyright notice for notYetAnotherWiki: | ||
2 | |||
3 | Copyright (C) 2024 David Walter Seikel AKA onefang | ||
4 | |||
5 | All rights reserved. | ||
6 | |||
7 | Redistribution and use in source and binary forms, with or without | ||
8 | modification, are permitted provided that the following conditions are | ||
9 | met: | ||
10 | |||
11 | 1. Redistributions of source code must retain the above copyright | ||
12 | notice, this list of conditions and the following disclaimer. | ||
13 | |||
14 | 2. Redistributions in binary form must reproduce the above copyright | ||
15 | notice, this list of conditions and the following disclaimer in the | ||
16 | documentation and/or other materials provided with the distribution. | ||
17 | |||
18 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | ||
19 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | ||
20 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | ||
21 | THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
22 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
23 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
24 | USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
27 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
28 | |||
29 | Freedom -1: the author specifically grants themselves the freedom to not | ||
30 | be infected by the viral licence clauses of any code this source code | ||
31 | "links" to. It's my code, I choose my licence terms, no one else does. | ||
@@ -1,11 +1,4 @@ | |||
1 | --- | 1 | # notYetAnotherWiki |
2 | favicon: cartdave_favicon.png | ||
3 | pagetitle: "notYetAnotherWiki" | ||
4 | author: onefang | ||
5 | feedatom: https://sledjhamr.org/cgit/notYetAnotherWiki/atom | ||
6 | history: https://sledjhamr.org/cgit/notYetAnotherWiki/log/index.md | ||
7 | sourcecode: https://sledjhamr.org/cgit/notYetAnotherWiki/ | ||
8 | --- | ||
9 | 2 | ||
10 | 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 |
11 | more than that, eventually. | 4 | more than that, eventually. |
@@ -59,22 +52,30 @@ the useful info that makes it's way into the system one way or another. | |||
59 | Someone comes into your chat system, asking for help, within minutes | 52 | Someone comes into your chat system, asking for help, within minutes |
60 | people are helping out and come up with a working solution. After a few | 53 | people are helping out and come up with a working solution. After a few |
61 | other people turn up with the same problem, the existing conversations | 54 | other people turn up with the same problem, the existing conversations |
62 | are moved to the decumentation section, where the original participants | 55 | are moved to the documentation section, where the original participants |
63 | and others can polish it into proper documentation about solving what has | 56 | and others can polish it into proper documentation about solving what has |
64 | suddenly become a common problem. Every one knows where to find it, on | 57 | suddenly become a common problem. Every one knows where to find it, on |
65 | the one system. They can chat about it, on the one system. | 58 | the one system. They can chat about it, on the one system. |
66 | 59 | ||
67 | ## What does it do already? | 60 | ## What does it do already? |
68 | 61 | ||
69 | Currently it'll scan the current directory and subdirectories looking for | 62 | Currently it'll scan the current folder and sub folders looking for |
70 | .md files in CommonMark syntax. This should cover some MarkDown | 63 | .md files in CommonMark syntax. This should cover some MarkDown |
71 | variations. Then it produces .HTML files converted from these .md files, | 64 | variations. Then it produces .HTML files converted from these .md files, |
72 | and links them all together into a web site. | 65 | and links them all together into a web site. |
73 | 66 | ||
67 | Any .md file that is just the beginning metadata block doesn't get | ||
68 | rendered into HTML, but is global metadata for this folder and subs, | ||
69 | though the subs can override this with their own metadata.md files. | ||
70 | |||
74 | 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 |
75 | the footer is links to cgit, which is used to store the files in git on | 72 | the footer is links to cgit, which is used to store the files in git on |
76 | 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 |
77 | feed for the site. | 74 | feed for the site. |
78 | 75 | ||
79 | 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 |
80 | one, but this isn't tested yet. | 77 | one, but this isn't tested yet. |
78 | |||
79 | ## other stuff | ||
80 | |||
81 | The font femkeklaver.ttf was used for making the nYAW logo. | ||
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 | ||
@@ -1,34 +1,100 @@ | |||
1 | --- | 1 | # TODO |
2 | favicon: cartdave_favicon.png | 2 | |
3 | pagetitle: "TODO" | 3 | Make it perphekd! |
4 | author: onefang | 4 | |
5 | feedatom: https://sledjhamr.org/cgit/notYetAnotherWiki/atom | ||
6 | history: https://sledjhamr.org/cgit/notYetAnotherWiki/log/TODO.md | ||
7 | sourcecode: https://sledjhamr.org/cgit/notYetAnotherWiki/ | ||
8 | --- | ||
9 | ## Do these | 5 | ## Do these |
10 | 6 | ||
11 | 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. | 7 | Convert it to polygLua. |
12 | One quirk to watch for is if a URL path cahnges, the docs that have that URL need to be redone. | 8 | |
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. | ||
47 | |||
48 | ## Some ideas | ||
13 | 49 | ||
14 | 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 - |
15 | 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/. | ||
16 | 68 | ||
17 | 69 | ||
18 | ## Try out | 70 | ## Try out |
19 | 71 | ||
20 | htmx | 72 | lua-lpeg-patterns might be useful |
73 | |||
74 | lua-luxio might be the wheel I'm reinventing? | ||
75 | |||
76 | lua-wsapi-fcgi | ||
21 | 77 | ||
22 | 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. |
23 | cmark-gfm | 79 | |
80 | htmx | ||
24 | 81 | ||
25 | cgit has Lua | 82 | cgit has Lua |
26 | 83 | ||
84 | lua-gall for git stuff | ||
85 | |||
86 | lua-lace for access control | ||
87 | |||
88 | lua-unbound | ||
27 | 89 | ||
28 | 90 | ||
29 | ## User system | 91 | ## Member system |
92 | |||
93 | Reuse the member system from SledjChisl. | ||
30 | 94 | ||
31 | levels - | 95 | levels - |
96 | |||
97 | - everyone | ||
32 | - banned | 98 | - banned |
33 | - reader | 99 | - reader |
34 | - member | 100 | - member |
@@ -38,6 +104,8 @@ levels - | |||
38 | - shell | 104 | - shell |
39 | - root | 105 | - root |
40 | 106 | ||
107 | Everyone can read the pages, no need for an account. | ||
108 | |||
41 | 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. |
42 | 110 | ||
43 | When first registered, accounts are set to reader level. | 111 | When first registered, accounts are set to reader level. |
@@ -64,6 +132,6 @@ site, including configuration and modules. Likely this is the person | |||
64 | that set the system up in the first place. | 132 | that set the system up in the first place. |
65 | 133 | ||
66 | 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. |
67 | 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. |
68 | 136 | ||
69 | 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/Connie_click-me.gif b/about/Connie_click-me.gif deleted file mode 120000 index 35d25cd..0000000 --- a/about/Connie_click-me.gif +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | ../Connie_click-me.gif \ No newline at end of file | ||
diff --git a/about/index.md b/about/index.md index 51b84cc..3f15be7 100644 --- a/about/index.md +++ b/about/index.md | |||
@@ -1,24 +1,5 @@ | |||
1 | --- | 1 | # notYetAnotherWiki is not another wiki, at least not yet. It'll be much more than that, eventually. |
2 | favicon: cartdave_favicon.png | ||
3 | pagetitle: "notYetAnotherWiki is not another wiki, at least not yet. It'll be much more than that, eventually." | ||
4 | author: onefang | ||
5 | feedatom: https://sledjhamr.org/cgit/notYetAnotherWiki/atom | ||
6 | history: https://sledjhamr.org/cgit/notYetAnotherWiki/log/About/index.md | ||
7 | sourcecode: https://sledjhamr.org/cgit/notYetAnotherWiki/ | ||
8 | --- | ||
9 | 2 | ||
10 | 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. |
11 | 4 | ||
12 | notYetAnotherWiki is not another wiki, at least not yet. It'll be much more than that, eventually. | 5 | This would just be a duplicate of README, but for testing purposes. |
13 | |||
14 | So to start with it's not a wiki. It's currently a way to create a web | ||
15 | site with CommonMark wiki markup, using git to update the content. | ||
16 | |||
17 | So it's not a wiki, yet. | ||
18 | |||
19 | Next comes accounts and online editing of content with the web pages. It'll then barely be a wiki. | ||
20 | |||
21 | The missing bit is talk pages, which requires some sort of archiving chat | ||
22 | system built into the thing. Now it's Yet Another Wiki. | ||
23 | |||
24 | Finally comes the magic, so it's "not Yet Another Wiki", it's much more than that. | ||
diff --git a/default.template b/default.template index 4c1ac12..baefad1 100644 --- a/default.template +++ b/default.template | |||
@@ -2,68 +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 | |||
12 | body { | 10 | body { |
13 | background-color: black; | 11 | height: 100vh; width: 100vw; |
14 | color: white !important; | 12 | margin: 0; padding: 0; border: none; |
13 | background-image: linear-gradient($onefangPurple$, $karenPurple$); | ||
14 | color: white; | ||
15 | font-family: sans-serif; | ||
15 | } | 16 | } |
16 | 17 | menu {list-style-type: none;} | |
17 | pre { | 18 | pre { |
18 | background-color: #cc00ff; | 19 | background-image: linear-gradient(to right, $PinkFloyd$, $onefangPurple$); |
19 | overflow: auto; | 20 | width: fit-content; max-width: 99%; overflow-x: auto; |
20 | width: 42%; | 21 | margin: 2px; border: 2px solid grey; |
21 | } | 22 | } |
23 | table, td, th {border-collapse: collapse; border: 2px solid grey;} | ||
24 | |||
25 | .toolTip {background: darkcyan; font-size: 1.42em;} | ||
22 | 26 | ||
23 | menu { | 27 | .boxWrapper { |
24 | list-style-type: none; | 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; | ||
25 | } | 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;} | ||
26 | 44 | ||
27 | .contentBox { | 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;} |
28 | overflow-y: auto; | 46 | .boxBody {grid-area: body; grid-column: 2 / 4; grid-row: 3 / 3; vertical-align: top; |
29 | overflow-x: hidden; | 47 | height: 100%; width: 100%; |
48 | background: black; color: white; | ||
30 | } | 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;} | ||
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;} | ||
31 | </style> | 80 | </style> |
32 | </head> | 81 | </head> |
33 | <body bgcolor="black" text="white" alink="red" link="yellow" vlink="blue"> | 82 | <body alink="red" link="orange" vlink="$onefangGreen$"> |
34 | <table> | 83 | <div class="boxWrapper"> |
35 | <tr> | 84 | <input type="checkbox" id="modeToggleMenu"/> |
36 | <td><img src="Connie_click-me.gif" alt="alt text" title="Not (Yet) (Another / A) Wiki."/></td> | 85 | <input type="checkbox" id="modeToggleBody"/> |
37 | <td>$header$ plus login and register buttons</td> | 86 | <div class="boxLogo" id="top"><header><nav> |
38 | </tr> | 87 | <a href="$home$"><img src="$logo$" alt="not (Yet) (Another / A) Wiki."/></a> |
39 | <td rowspan=0 style="background-color: rebeccapurple; text-align:left; white-space:nowrap; vertical-align:top"> | 88 | </nav></header></div> |
40 | menu for the current directory | 89 | <div class="boxTools"><header><nav> |
41 | $menu$ | 90 | <a href="/help.HTML"><b class="toolTip" title="🍔 hides / shows non content, reverse hamburger menu. |
42 | </td> | 91 | 🕶 switches between dark and light themes. |
43 | <td style="background-color: rebeccapurple"> | 92 | 📚 shows the list of all pages. |
44 | 👣 $trail$ | 93 | 🔮 a folder of unsorted pages. |
45 | </td> | 94 | 👥 shows the list of users. |
46 | </tr> | 95 | 🪵 will be for logging in, when I have written that bit. |
47 | <tr> | 96 | 🔍 will be the search, when I have written that bit. |
48 | <td> | 97 | 👣 is a trail of the steps to get here.">❓</b></a> |
49 | <main class="contentBox"> | 98 | <b class="toolTip"><label for="modeToggleMenu" class='modeBtn'>🍔</label></b> |
50 | <div name="contentFrame"> | 99 | <b class="toolTip"><label for="modeToggleBody" class='modeBtn'>🕶</label></b> |
51 | <h1>$pagetitle$</h1> | 100 | <a href="/everything.HTML"><b class="toolTip">📚</b></a> |
52 | Author: $author$ | 101 | <a href="/unsorted/" ><b class="toolTip">🔮</b></a> |
53 | $body$ | 102 | <a href="/users/" ><b class="toolTip">👥</b></a> |
54 | </div> | 103 | <b class="toolTip">🪵</b> |
55 | </main> | 104 | <b class="toolTip">🔍</b> |
56 | </td> | 105 | <b> 👣 $trail$ </b> |
57 | </tr> | 106 | </nav></header></div> |
58 | <tr> | 107 | <div class="boxHead"><header><nav><b>$header$</b> </nav></header></div> |
59 | <td style="background-color: rebeccapurple"> | 108 | |
60 | <p>Page <a href="$history$">history</a>. Web site <a href="$feedatom$">atom feed</a> and <a href="$sourcecode$">source code</a> Powered by <a href="https://sledjhamr.org/cgit/notYetAnotherWiki/about/">notYetAnotherWiki</a> Version $version$.</p> | 109 | <div class="boxMenu"><nav><p><b>$menu$</b></p></nav></div> |
61 | </td> | 110 | <div class="boxBody"><main>$body$<br/></main></div> |
62 | </tr> | 111 | |
63 | <tr> | 112 | <div class="boxHistory"><footer>$history$</footer></div> |
64 | <td> | 113 | <div class="boxFoot"><footer>$footer$</footer></div> |
65 | </td> | 114 | <div class="boxnyaw"><footer> |
66 | </tr> | 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> |
67 | </table> | 116 | </footer></div> |
117 | </div> | ||
68 | </body> | 118 | </body> |
69 | </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 { |
diff --git a/nYAW.png b/nYAW.png new file mode 100644 index 0000000..3d756a0 --- /dev/null +++ b/nYAW.png | |||
Binary files differ | |||
diff --git a/nYAW.xcf b/nYAW.xcf new file mode 100644 index 0000000..369f57e --- /dev/null +++ b/nYAW.xcf | |||
Binary files differ | |||
diff --git a/nYAW_icon.png b/nYAW_icon.png new file mode 100644 index 0000000..5788080 --- /dev/null +++ b/nYAW_icon.png | |||
Binary files differ | |||
diff --git a/nYAW_icon.xcf b/nYAW_icon.xcf new file mode 100644 index 0000000..512fd0b --- /dev/null +++ b/nYAW_icon.xcf | |||
Binary files differ | |||
diff --git a/notYetAnotherWiki.lua b/notYetAnotherWiki.lua index 0ee0f10..f53691b 100755 --- a/notYetAnotherWiki.lua +++ b/notYetAnotherWiki.lua | |||
@@ -1,189 +1,967 @@ | |||
1 | #!/usr/bin/env luajit | 1 | #!/usr/bin/env luajit |
2 | 2 | ||
3 | local lcmark = require("lcmark") | 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 globalData = {version = '-0.1', header = '', footer = '', menu = '', ['_'] = ' ', ['dlr'] = '$'} | 6 | Normally I define functions and globals at the top, but here I'm interleaving them. |
6 | local site = {} | 7 | ]] |
7 | 8 | ||
8 | local createHTML = function(cm, file) | 9 | local Lunamark = require("lunamark") -- https://github.com/jgm/lunamark |
9 | -- cm = string.gsub(cm, '. ', '. ') | 10 | local Lpeg = require("lpeg") -- https://www.inf.puc-rio.br/~roberto/lpeg/lpeg.html Lunamark uses this, so we can to. |
10 | if (nil ~= file) and ('' ~= file) then io.write('Parsing ' .. file .. ' -> ') end | 11 | local RE = require("re") -- Part of lpeg. https://www.inf.puc-rio.br/~roberto/lpeg/re.html |
11 | local result = '' | 12 | |
12 | local body, metadata, err = lcmark.convert(cm, "html", {smart = true, yaml_metadata = true, columns = 0}) | 13 | |
13 | 14 | --------------------------------------------------------------------------------- | |
14 | if nil == body then print('oops! ' .. err) else | 15 | -- Some global data. |
15 | local bod, err = lcmark.compile_template(body) | 16 | |
16 | if nil == bod then print('oops! ' .. err) else | 17 | local GlobalMetaData = { |
17 | local templateFile = metadata.template | 18 | dlr = '$', perc = '%', dot = '.', |
18 | if nil == file then | 19 | devuanCinnabarDark = '#310202', devuanCinnabarLight = '#510505', |
19 | templateFile = nil | 20 | devuanDarkPurpyDark = '#33313b', devuanDarkPurpyLight = '#3c3a45', |
20 | else | 21 | devuanDeepSeaDark = '#132f40', devuanDeepSeaLight = '#1a4562', |
21 | if nil == templateFile then templateFile = 'default' end | 22 | devuanSaphireDark = '#004489', devuanSaphireLight = '#00509f', |
22 | templateFile = templateFile .. '.template' | 23 | devuanDevuanDark = '#000000', devuanDevuanLight = '#ffffff', |
23 | for k, v in pairs(globalData) do | 24 | -- HTML link colours. Naturally HTML5 deprecated the simple version, replacing it with less simple CSS. |
24 | if nill == metadata[k] then metadata[k] = v else print('metadata already has ' .. k) end | 25 | -- <body> has alink, link, vlink; CSS has active, link, visited, and hover. |
25 | end | 26 | devuanDevuanalink = '#03a4ff', devuanDevuanlink = '#0076b6', devuanDevuanvlink = '#6aa4db', devuanDevuanhlink = '#03a4ff', |
26 | end | 27 | devuanSDevuanalink = '#98c3db', devuanSDevuanlink = '#ffffff', devuanSDevuanvlink = '#ffffff', devuanSDevuanhlink = '#98c3db', |
27 | 28 | karenPurple = '#8800ff', onefangPurple = '#cc00ff', onefangGreen = '#42ff00', | |
28 | if nil ~= file then | 29 | PinkFloyd = '#AA00AA', DeepPurple = '#220022', -- From an ancient site of mine, which went from PinkFloyd to DeepPurple as a background gradient. |
29 | local depth = 0 | 30 | favicon = 'nYAW_icon.png', logo = 'nYAW.png', |
30 | local base = '' | 31 | } |
31 | for p in string.gmatch(file, '(%w+)/') do | 32 | |
32 | depth = depth + 1 | 33 | local Files, Subs, xLinks = {}, {}, {} |
33 | base = p | 34 | local Context = {} -- Coz can't otherwise pass context through to the deeper Lunamark functions I'm overriding. |
34 | end | 35 | |
35 | local path = string.sub(file, 1, #base) | 36 | local Template = '' |
36 | 37 | local h = io.open("default.template", 'r') | |
37 | metadata.header = '' | 38 | if nil ~= h then |
38 | metadata.menu = '' | 39 | Template = h:read('*a') |
39 | local trl = {} | 40 | h:close() |
40 | metadata.trail = '' | 41 | else |
41 | local dir = site[''] | 42 | print('oops! No such file ' .. 'default.template') |
42 | local dr, pdr, tr = '', '', '' | 43 | end |
43 | while nil ~= dir.subs do | 44 | |
44 | local old = dir | 45 | |
45 | for m, x in pairs(dir.subs) do | 46 | --------------------------------------------------------------------------------- |
46 | if x == string.sub(file, 1, #x) then | 47 | -- Useful functions, part 0. |
47 | pdr = pdr .. '/' .. m | 48 | |
48 | tr = tr .. '../' | 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. |
49 | dr = m | 50 | local derefiTable = function(t, strip) |
50 | dir = site[dr] | 51 | local argh = {} |
51 | table.insert(trl, '">' .. m .. '</a> 👣') | 52 | for l, y in ipairs(t) do if (l ~= y.name) and strip then table.insert(argh, y) end end |
52 | break | 53 | return argh |
53 | 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 | ||
60 | |||
61 | |||
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 | ||
72 | local stringBits = function(l) | ||
73 | local bits = {} | ||
74 | local last = 1 | ||
75 | for j = 1, #l do | ||
76 | if '/' == string.sub(l, j, j) then | ||
77 | table.insert(bits, string.sub(l, last, j - 1)) | ||
78 | last = j + 1 | ||
79 | end | ||
80 | end | ||
81 | return bits, string.sub(l, last) | ||
82 | end | ||
83 | |||
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 | |||
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 | ||
54 | end | 176 | end |
55 | if old == dir then break end | ||
56 | end | ||
57 | table.remove(trl) | ||
58 | for m, x in ipairs(trl) do | ||
59 | tr = string.sub(tr, 4) | ||
60 | trl[m] = ' <a href="' .. tr .. x | ||
61 | end | 177 | end |
62 | metadata.trail = table.concat(trl) | 178 | end |
179 | end | ||
180 | return metadata | ||
181 | end | ||
63 | 182 | ||
64 | if nil ~= dir.files then | 183 | |
65 | local l = {} | 184 | |
66 | for m, x in pairs(dir.files) do table.insert(l, {m = m; x = x}) end | 185 | local commonLinky = function(l, body, u, url, beg, en, beg0, en0, bump) |
67 | table.sort(l, function(a, b) return (a.m <= b.m) end) | 186 | if nil == url then |
68 | for m, x in ipairs(l) do | 187 | -- print('OOPS! unknown linky - @' .. l .. '\t\t\t' .. string.sub(body, beg - 9, en) .. ' ' .. string.sub(body, en + 1, en0)) |
69 | metadata.menu = metadata.menu .. '<p><a href="' .. string.sub(x.x, 1 + #pdr) .. '.HTML">' .. x.m .. '</a></p>\n' | 188 | else |
70 | end | 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) | ||
71 | end | 201 | end |
72 | if nil ~= dir.subs then | 202 | return beg, en, body, here |
73 | local l = {} | 203 | end |
74 | for m, x in pairs(dir.subs) do table.insert(l, {m = m; x = x}) end | 204 | |
75 | table.sort(l, function(a, b) return (a.m <= b.m) end) | 205 | |
76 | for m, x in pairs(l) do | 206 | |
77 | metadata.header = metadata.header .. '<a href="' .. string.sub(x.x, 1 + #pdr) .. '">' .. x.m .. '</a> ' | 207 | --------------------------------------------------------------------------------- |
208 | -- Actually start doing things. | ||
209 | |||
210 | -- Create the base of everything.md here, so it gets picked up as usual in the file scan. | ||
211 | h = io.open('everything.md', 'w') | ||
212 | if nil ~= h then | ||
213 | h:close() | ||
214 | else | ||
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 | ||
258 | end | ||
259 | end | ||
260 | |||
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 | ||
78 | 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) | ||
79 | end | 292 | end |
293 | |||
80 | end | 294 | end |
295 | end | ||
296 | end | ||
297 | end | ||
81 | 298 | ||
82 | metadata.body = lcmark.apply_template(bod, metadata) | 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 | ||
83 | 357 | ||
84 | local tm = '' | 358 | if nil ~= url then |
85 | if nil ~= templateFile then | 359 | if ('pub/' == string.sub(url, 1, 4)) then |
86 | local h = io.open(templateFile, 'r') | 360 | -- FIXME? - evil hack? |
87 | if nil ~= h then | 361 | url = 'Foswiki/' .. url |
88 | tm = tm .. h:read('*a') | 362 | --print('FOSWIKI HTM ' .. url) |
89 | h:close() | 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)) | ||
90 | else | 373 | else |
91 | print('oops! No such file ' .. templateFile) | 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 | ]=] | ||
92 | end | 384 | end |
93 | 385 | ||
94 | local template, err = lcmark.compile_template(tm) | 386 | writeString(l .. '_NEW', body) |
95 | if nil == template then print('oops! ' .. err) else | 387 | elseif 'PmWiki' == string.sub(l, 1, 6) then |
96 | result = lcmark.apply_template(template, metadata) | 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 | ||
97 | end | 441 | end |
98 | else | 442 | |
99 | result = body | 443 | writeString(l .. '_NEW', body) |
100 | end | 444 | end |
101 | 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') | ||
102 | end | 448 | end |
449 | end | ||
103 | 450 | ||
104 | if ('' ~= result) and (nil ~= file) then | 451 | if '.' ~= Folder then |
105 | local base = string.gsub(file, '%.md$', '') | 452 | for l in io.popen('find -L . -name "*.md" -type f,l -printf "%P\n"'):lines() do |
106 | print(base .. '.HTML') | 453 | toFile(string.gsub(l, '%.md$', '')) |
107 | local a, e = io.open(base .. '.HTML', 'w') | 454 | end |
108 | if nil == a then print('Could not open ' .. base .. '.HTML - ' .. e) else | 455 | end |
109 | a:write(result) | 456 | |
110 | a:close() | 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 | ||
459 | local n = string.gsub(l, '%.md$', '') | ||
460 | if nil == Files[n] then toFile(n) end | ||
461 | end | ||
462 | |||
463 | |||
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 = {} | ||
466 | for name, file in pairs(Files) do | ||
467 | local bitter, path = '', '' | ||
468 | local bits, bit = file.bits, file.bit | ||
469 | local ln = #bits | ||
470 | local body, metadata = '', {} | ||
471 | |||
472 | -- Go through our bits, construct Subs with bits. | ||
473 | if ln > 0 then bitter = bits[1] end | ||
474 | if '' ~= bitter then Subs[''].subs[bitter] = bitter end -- "bitter end" was entirely by accident, I'm keeping it. B-) | ||
475 | for i, d in ipairs(bits) do | ||
476 | if '' ~= path then path = path .. '/' end | ||
477 | path = path .. d | ||
478 | toSub(path) | ||
479 | if i < ln then | ||
480 | Subs[path].subs[bits[i + 1]] = bits[i + 1] | ||
481 | table.remove(Subs[path].bits, #bits) | ||
111 | end | 482 | end |
112 | else | ||
113 | print('') | ||
114 | end | 483 | end |
115 | return result | 484 | |
485 | if '.md' == string.sub(name, -3, -1) then | ||
486 | -- This is a metadata only file, no content, stash the matadata. | ||
487 | |||
488 | metadata = readMdMd(name, metadata) | ||
489 | if '.md' == name then toSub(path, 'metadata', metadata) | ||
490 | elseif '/.md' == string.sub(name, -4, -1) then toSub(path, 'metadata', metadata) | ||
491 | -- else toFile(string.sub(name, 1, -4), 'metadata', metadata) | ||
492 | else NewMeta[string.sub(name, 1, -4)] = metadata -- Coz we can't add to Files here. | ||
493 | end | ||
494 | Files[name] = nil | ||
495 | end | ||
496 | end | ||
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 | ||
116 | end | 504 | end |
117 | 505 | ||
118 | local directory = arg[1] | 506 | -- Fix up subs now we have all the file bits. |
119 | if nil == directory then directory = '.' end | 507 | for name, file in pairs(Files) do |
120 | local all = {} | 508 | if '.md' ~= string.sub(name, -3, -1) then |
121 | if '.' ~= directory then | 509 | table.insert(Subs[file.path].files, file.bit) |
122 | for l in io.popen('find . -name "*.md" -type f,l -printf "%P\n"'):lines() do | ||
123 | all[l] = l | ||
124 | end | 510 | end |
125 | end | 511 | end |
126 | for l in io.popen('find ' .. directory .. ' -name "*.md" -type f,l -printf "%P\n"'):lines() do | 512 | |
127 | if nil == all[l] then all[l] = l end | 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 | ||
128 | end | 525 | end |
129 | 526 | ||
130 | for i, l in pairs(all) do | ||
131 | local dir = '' | ||
132 | local files, subs = {}, {} | ||
133 | local c, parent = 1, '' | ||
134 | 527 | ||
135 | for p in string.gmatch(l, '(%w+)/') do | 528 | --------------------------------------------------------------------------------- |
136 | if '' == dir then | 529 | -- These functions assume the above file and sub scan has completed. |
137 | dir = p | 530 | |
138 | if nil ~= site[dir] then | 531 | -- Which page in this folder should we show? |
139 | subs = site[dir].subs | 532 | -- NOTE - only looking for the .md files we scanned for before, any stray HTML, html, HTM, and htm files will get ignored. |
140 | files = site[dir].files | 533 | local whichPage = function(f) |
534 | local fl = '' | ||
535 | if nil ~= Subs[f] then | ||
536 | if nil ~= Subs[f].whichPage then return Subs[f].whichPage end | ||
537 | if nil ~= Subs[f].files then | ||
538 | if 1 == #(Subs[f].files) then fl = Subs[f].files[1] else | ||
539 | -- Standard files to search for. | ||
540 | for i, v in ipairs{'about', 'readme', 'index', 'homepage', 'mainpage', 'webhome'} do | ||
541 | for j, w in ipairs(Subs[f].files) do | ||
542 | if v == string.lower(w) then | ||
543 | fl = w | ||
544 | break | ||
545 | end | ||
546 | end | ||
547 | if '' ~= fl then break end | ||
548 | 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 | ||
141 | end | 551 | end |
142 | end | 552 | end |
553 | end | ||
554 | if '' ~= fl then fl = fl .. '.HTML' ; Subs[f].whichPage = fl end | ||
555 | return fl | ||
556 | end | ||
557 | |||
143 | 558 | ||
144 | local path = string.sub(l, 1, -1 - #(string.gsub(l, '.*/', ''))) | 559 | -- Figure out the original title and link for the original wiki. |
145 | if nil ~= site[parent] then | 560 | local whichWiki = function(metadata) |
146 | if nil == site[parent].subs then site[parent].subs = {} end | 561 | local title, link = '', '' |
147 | site[parent].subs[p] = path | 562 | if 'PmWiki' == metadata.ogWiki then |
148 | elseif 1 == c then subs[p] = path | 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. | ||
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 | ||
582 | local depth = 0 | ||
583 | local lnk = '' | ||
584 | if source ~= dest then | ||
585 | if nil == Subs[source] then | ||
586 | -- print('!!!! No idea where to find source ' .. source) | ||
587 | return 'DUNNO' | ||
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' | ||
595 | end | ||
596 | end | ||
597 | local s = Subs[source].bits | ||
598 | local d = Subs[dest].bits | ||
599 | local sl = #s | ||
600 | local dl = #d | ||
601 | |||
602 | if 0 == dl then | ||
603 | depth = sl | ||
149 | else | 604 | else |
150 | if ('' ~= parent) and (dir == parent) then subs[p] = path end | 605 | for i, v in ipairs(s) do |
151 | site[parent] = {subs = {[p] = path}} | 606 | if (nil == d[i]) or (v ~= d[i]) then |
607 | depth = i | ||
608 | break | ||
609 | end | ||
610 | end | ||
152 | end | 611 | end |
153 | c = c + #p + 1 | 612 | -- depth is where they DON'T match. |
154 | parent = p | 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 | ||
155 | end | 617 | end |
618 | return lnk | ||
619 | end | ||
620 | |||
621 | |||
622 | |||
623 | --------------------------------------------------------------------------------- | ||
624 | -- More of this actually doing things nonsense. | ||
156 | 625 | ||
157 | if (1 == c) and (nil ~= site[dir]) then | 626 | -- Create an "everything" page, for URL links to every file.HTML. |
158 | subs = site[dir].subs | 627 | local Bdy = '# All the pages\n\n| page | original page | last edited UTC | \n| --------- | ------- | --------------- | ' |
159 | files = site[dir].files | 628 | Pages = {} |
629 | for name, file in pairs(Files) do | ||
630 | local metadata = derefTable(Files[name].metadata, true) | ||
631 | if ('everything' ~= name) then | ||
632 | local ln, fw, pw, ts = 'DUNNO', '', '', '' | ||
633 | local title, link = whichWiki(metadata) | ||
634 | link = string.gsub(link, 'https://', 'HTTPS://') -- Prevent this one from being converted. | ||
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 .. ' |') | ||
641 | |||
642 | -- Track our external links. | ||
643 | if (nil ~= metadata.ogBase) and (nil ~= metadata.ogFile) then | ||
644 | local n = metadata.ogBase | ||
645 | if 'PmWiki' == metadata.ogWiki then n = n .. '.' else n = n .. '/' end | ||
646 | xLinks[n .. metadata.ogFile] = file.path | ||
647 | end | ||
160 | 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) | ||
161 | 662 | ||
162 | local base = string.gsub(string.sub(l, c, -1), '%.md$', '') | 663 | |
163 | if nil ~= site[parent] then site[parent].files[base] = string.sub(l, 1, -4) | 664 | -- Loop through Subs, doing whichPage and inheritance. |
164 | elseif 1 == c then files[base] = string.sub(l, 1, -4) | 665 | -- It gets to testing/even/deeper BEFORE it gets to testing/even sometimes. So sort them. |
165 | else | 666 | SUBS = {} |
166 | if ('' ~= parent) and (dir == parent) then files[base] = string.sub(l, 1, -4) end | 667 | for name, sub in pairs(Subs) do |
167 | site[parent] = {files = {[base] = string.sub(l, 1, -4)}} | 668 | table.insert(SUBS, sub) |
669 | end | ||
670 | table.sort(SUBS, function(a, b) return (string.lower(a.path) < string.lower(b.path)) end) | ||
671 | for n, sub in pairs(SUBS) do | ||
672 | local name = sub.path | ||
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 | ||
685 | end | ||
686 | end | ||
687 | end | ||
688 | end | ||
168 | end | 689 | end |
690 | end | ||
169 | 691 | ||
170 | -- FIXME - still some minor bug somewhere, this fixes that, but causes other problems. Meh, I can live with excess empty subs tables. | 692 | -- Files inheritance. |
171 | -- if (nil ~= subs) and (0 == #subs) then subs = nil end | 693 | for name, file in pairs(Files) do |
172 | site[dir] = {files = files, subs = subs} | 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 | ||
700 | end | ||
701 | end | ||
173 | end | 702 | end |
174 | 703 | ||
175 | for k, v in pairs(site) do | 704 | |
176 | if nil ~= v.files then | 705 | --------------------------------------------------------------------------------- |
177 | for m, x in pairs(v.files) do | 706 | -- Setup the lunarmark stuff. |
178 | local file = x .. '.md' | 707 | local LunamarkOpts = { |
179 | local h = io.open(file, 'r') | 708 | layout='compact', |
180 | if nil ~= h then | 709 | -- This list is copied from the lunamark source code, until I discover a way to discover it. The descriptions are useful to. |
181 | createHTML(h:read('*a'), file) | 710 | containers=false, -- Put sections in containers (e.g. div or section tags) |
182 | h:close() | 711 | slides=false, -- Like containers, but do not nest them |
712 | startnum=true, -- Start number of an ordered list is significant | ||
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' | ||
183 | else | 753 | else |
184 | print('oops! No such file ' .. file) | 754 | url = link .. '/' .. string.sub(url, 7) .. '.HTML' |
185 | end | 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 | ||
768 | end | ||
769 | local md | ||
770 | if ('fos' == string.sub(p, 9, 11)) or ('Fos' == string.sub(p, 1, 3)) then | ||
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 | ||
186 | 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 | ||
799 | end | ||
800 | end | ||
187 | end | 801 | end |
188 | end | 802 | end |
803 | return url | ||
189 | end | 804 | end |
805 | |||
806 | function Writer.header(s, level) | ||
807 | local text = Lunamark.util.rope_to_string(s) | ||
808 | -- FIXME - Work around a bug in Lunamark? | ||
809 | text = RE.gsub(text, "{[\\]}", "") | ||
810 | return '<h' .. level .. ' id="' .. RE.gsub(text, '{[ ]}', '_') .. '">' .. text .. ' <a style="font-size: 0.42em;" href="#top">🔼</a></h' .. level .. '>' | ||
811 | end | ||
812 | local OgWriterLink = Writer.link -- So we can call the original from within mine, we are just changing the URL. | ||
813 | function Writer.link(lab, url, tit) | ||
814 | return OgWriterLink(lab, lunaLinky(url), tit) | ||
815 | end | ||
816 | local OgWriterImage = Writer.image | ||
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) | ||
822 | |||
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 | ||
833 | -- Figure out this pages trail links. | ||
834 | metadata.home = linkFrom(file.path, '') .. Subs[''].whichPage | ||
835 | metadata.trail = '' | ||
836 | for i, b in ipairs(bits) do | ||
837 | local p = table.concat(bits, '/', 1, i) | ||
838 | if i < #bits then | ||
839 | metadata.trail = metadata.trail .. '<a href="' .. linkFrom(file.path, p) .. Subs[p].whichPage .. '">' .. b .. '</a> 👣 ' | ||
840 | linkFrom(file.path, table.concat(bits, '/', 1, i)) | ||
841 | else | ||
842 | metadata.trail = metadata.trail .. ' ' .. b | ||
843 | end | ||
844 | end | ||
845 | |||
846 | -- Figure out this pages header links. | ||
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 | ||
860 | |||
861 | -- Figure out this pages menu links. | ||
862 | metadata.menu = '' | ||
863 | if nil == metadata.title then metadata.title = bit end | ||
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 | ||
865 | for i, f in ipairs(Subs[file.path].files) do | ||
866 | local title, url = nil, nil | ||
867 | if '' == file.path then | ||
868 | title = Files[f].metadata.title | ||
869 | url = Files[f].metadata.URL | ||
870 | else | ||
871 | title = Files[file.path .. '/' .. f].metadata.title | ||
872 | url = Files[file.path .. '/' .. f].metadata.URL | ||
873 | end | ||
874 | if nil == title then title = f end | ||
875 | if bit == f then | ||
876 | metadata.menu = metadata.menu .. '<p>' .. title .. '</p>' | ||
877 | for j, g in ipairs(file.headers) do | ||
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 | ||
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 | ||
913 | else | ||
914 | temp = '/' .. name .. '.md' | ||
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) | ||
958 | |||
959 | -- Write the file. | ||
960 | if '' ~= result then | ||
961 | -- print('From ' .. name .. '.md -> ' .. base) | ||
962 | writeString(name .. '.HTML', result) | ||
963 | end | ||
964 | end | ||
965 | end | ||
966 | |||
967 | |||
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/Connie_click-me.gif b/testing/Connie_click-me.gif index 35d25cd..6f0b361 120000..100644 --- a/testing/Connie_click-me.gif +++ b/testing/Connie_click-me.gif | |||
Binary files differ | |||
diff --git a/testing/index.md b/testing/index.md index 54808d5..581d301 100644 --- a/testing/index.md +++ b/testing/index.md | |||
@@ -1,74 +1,94 @@ | |||
1 | --- | 1 | # G'day world! |
2 | favicon: cartdave_favicon.png | 2 | |
3 | pagetitle: "G'day world!" | 3 | I've been around since the early sixties, but no one ever noticed. You |
4 | author: onefang | 4 | really should have tried to pay attention though, I'm awesome. I try to |
5 | feedatom: https://sledjhamr.org/cgit/notYetAnotherWiki/atom | 5 | help the world, but that's not what everyone wants me to do. Well, the |
6 | history: https://sledjhamr.org/cgit/notYetAnotherWiki/log/testing/index.md | ||
7 | sourcecode: https://sledjhamr.org/cgit/notYetAnotherWiki/ | ||
8 | --- | ||
9 | |||
10 | I've been around since the early sixties, but no one ever noticed. You | ||
11 | really should have tried to pay attention though, I'm awesome. I try to | ||
12 | help the world, but that's not what everyone wants me to do.$_$ Well, the | ||
13 | people in charge of this poor defenseless world of ours. | 6 | people in charge of this poor defenseless world of ours. |
14 | 7 | ||
15 | 8 | ||
16 | *** | 9 | *** |
17 | 10 | ||
11 | ## Em'n'Strong | ||
12 | |||
13 | Test *em* _em_ **strong** __strong__ . | ||
14 | |||
18 | # Spaces | 15 | # Spaces |
19 | 16 | ||
20 | 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. |
21 | 18 | ||
22 | 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. |
23 | 20 | ||
24 | 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 \ |
25 | 22 | ||
26 | 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. |
27 | 24 | ||
28 | \ | 25 | \ \$ \' \" \| % |
26 | |||
27 | I'm 100% sure that % will get treated correctly now. | ||
29 | 28 | ||
30 | ## Strike out | 29 | ## Strike out |
31 | 30 | ||
32 | Test ~~strike~~ --out--.$_$ Needs the extension. | 31 | Test ~~strike~~ --out--. Needs the extension. |
33 | 32 | ||
34 | ### URL | 33 | ### URL |
35 | 34 | ||
36 | [untalenz](https://untalenz.rocks/) | 35 | [untalenz](https://untalenz.rocks/) |
37 | 36 | ||
37 | [nope.example.com](http://nope.example.com/) | ||
38 | |||
38 | https://sledjhamr.org/ | 39 | https://sledjhamr.org/ |
39 | 40 | ||
40 | # Lists | 41 | # Lists |
41 | 42 | ||
42 | 43 | ||
43 | * zero | 44 | * first star |
44 | * 1 | 45 | * second star |
45 | * two | ||
46 | 46 | ||
47 | - zero | 47 | <!-- Separate the lists. --> |
48 | - 1 | ||
49 | - two | ||
50 | 48 | ||
49 | - first dash | ||
50 | - second dash | ||
51 | 51 | ||
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. | 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. |
53 | 53 | ||
54 | 1. one | ||
55 | 2. two | ||
56 | |||
57 | <!-- A comment will work --> | ||
54 | 58 | ||
59 | 0. zero | ||
55 | 1. one | 60 | 1. one |
56 | 2. 2 | 61 | 2. two |
57 | 62 | ||
63 | Autonumbering? Needs the extension. Doesn't matter, they get renumbered anyway if out of order. | ||
58 | 64 | ||
59 | <!-- A comment will work --> | 65 | 0. zero |
66 | #. first hash | ||
67 | #. second hash | ||
60 | 68 | ||
69 | <!-- Separate the lists. --> | ||
61 | 70 | ||
62 | 0. 0 | 71 | #. first hash |
63 | 1. one | 72 | #. second hash |
64 | 2. 2 | 73 | #. third hash |
65 | 74 | ||
66 | Autonumbering? Nope. B-( | 75 | <!-- Separate the lists. --> |
67 | 76 | ||
68 | 0. zero | 77 | 0. zero |
69 | 1 | 78 | 2. two |
70 | 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 | ~~~ | ||
71 | 90 | ||
91 | The stuff in a code block is in a different font, it's mono. lol | ||
72 | 92 | ||
73 | # images | 93 | # images |
74 | 94 | ||
@@ -87,19 +107,46 @@ Autonumbering? Nope. B-( | |||
87 | 107 | ||
88 | Plus some extra text. | 108 | Plus some extra text. |
89 | 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 | |||
90 | ~~~ | 128 | ~~~ |
91 | < | 129 | < |
92 | > | 130 | > |
93 | ~~~ | 131 | ~~~ |
94 | 132 | ||
133 | And a really long one, should turn scrollable. | ||
95 | ~~~lua | 134 | ~~~lua |
96 | -- Show some Lua code here, may even be highlighted right. | 135 | -- Show some Lua code here, may even be highlighted right. |
97 | print("G'day world!") | 136 | print("G'day world!") |
98 | -- 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??? |
99 | 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.' |
100 | ~~~ | 139 | ~~~ |
101 | 140 | ||
102 | > # What is a blockquote? | 141 | > # What is a blockquote? |
103 | > Still don't know. lol | 142 | > Still don't know. lol |
104 | > | 143 | > |
105 | > 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! | |||