From 5ada504d5667a6f17ee2631dd471b073b332dd33 Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Mon, 26 Oct 2020 23:22:29 -0600 Subject: build spec in gemtext too --- .build.yml | 13 ++- .gitignore | 1 + LICENSE.md | 2 +- Makefile | 25 ++++- README.md | 2 +- etc/gemtext.lua | 297 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ etc/template.gmi | 1 + 7 files changed, 330 insertions(+), 11 deletions(-) create mode 100644 etc/gemtext.lua create mode 100644 etc/template.gmi diff --git a/.build.yml b/.build.yml index fe0e2ed..cf489ae 100644 --- a/.build.yml +++ b/.build.yml @@ -15,19 +15,24 @@ tasks: make - compress: | tar czf spec-html.tar.gz crowbar-spec/*.html + tar czf spec-gmi.tar.gz crowbar-spec/*.gmi - test-page-count: | cd crowbar-spec make check - upload: | - upload() { - rsync --rsh="ssh -o StrictHostKeyChecking=no" -rlt8hP --del $@ services@boringcactus.com:/var/www/html/crowbar-lang.org/ + upload-to() { + dest=$1 + shift + rsync --rsh="ssh -o StrictHostKeyChecking=no" -rlt8hP --del $@ services@boringcactus.com:$dest } cd crowbar-spec - upload *.html spec.pdf + upload-to /var/www/html/crowbar-lang.org/ *.html spec.pdf + upload-to /var/www/gmi/crowbar-lang.org/ *.gmi spec.pdf - notify: | cd crowbar-spec message="crowbar spec updated: $(git log -1 --no-decorate --oneline)" - echo "$message" | ssh -o StrictHostKeyChecking=no services@boringcactus.com 'sh -c "cat > ~/irc/chat.freenode.net/#crowbar-lang/in"' + echo "/NOTICE #crowbar-lang :$message" | ssh -o StrictHostKeyChecking=no services@boringcactus.com 'sh -c "cat > ~/irc/chat.freenode.net/#crowbar-lang/in"' artifacts: - crowbar-spec/spec.pdf - spec-html.tar.gz + - spec-gmi.tar.gz diff --git a/.gitignore b/.gitignore index 17a66eb..055b012 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /*.html +/*.gmi /spec.pdf diff --git a/LICENSE.md b/LICENSE.md index 1d968be..20ffc56 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -3,4 +3,4 @@ title: License --- [![Creative Commons BY-SA License](https://i.creativecommons.org/l/by-sa/4.0/80x15.png)](http://creativecommons.org/licenses/by-sa/4.0/) -This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/"). +This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/). diff --git a/Makefile b/Makefile index 258580a..7bd231c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .POSIX: .SUFFIXES: -.SUFFIXES: .md .html +.SUFFIXES: .md .html .gmi # commands GIT = git @@ -10,9 +10,12 @@ PDFINFO = pdfinfo # input files SRC = index.md vs-c.md tagged-unions.md types.md safety.md errors.md syntax.md LICENSE.md HTML = $(SRC:.md=.html) +GMI = $(SRC:.md=.gmi) + +all: spec.pdf $(GMI) spec.pdf: $(HTML) - if $(GIT) describe --tags --exact-match 2>/dev/null; \ + @if $(GIT) describe --tags --exact-match 2>/dev/null; \ then \ metadata="subtitle=$$($(GIT) describe --tags --exact-match)"; \ else \ @@ -21,11 +24,23 @@ spec.pdf: $(HTML) $(PANDOC) --defaults=etc/pdf.yml -M "$$metadata" -o $@ $(HTML) .md.html: - offset=`echo $(SRC) | awk '{for (i=1; i<=NF; i++) if ($$i == "$<") print (i-1) }'`; \ + @offset=`echo $(SRC) | awk '{for (i=1; i<=NF; i++) if ($$i == "$<") print (i-1) }'`; \ $(PANDOC) --defaults=etc/md.yml --number-offset=$$offset -o $@ $< -clean: - rm -f $(HTML) spec.pdf +.md.gmi: + @offset=`echo $(SRC) | awk '{for (i=1; i<=NF; i++) if ($$i == "$<") print (i-1) }'`; \ + $(PANDOC) --defaults=etc/md.yml --write=etc/gemtext.lua --template=etc/template.gmi --number-offset=$$offset -o $@ $< + +clean: clean-pdf clean-html clean-gmi + +clean-pdf: + rm -f spec.pdf + +clean-html: + rm -f $(HTML) + +clean-gmi: + rm -f $(GMI) check: spec.pdf test $$($(PDFINFO) spec.pdf | grep Pages | awk '{ print $$2 }') -le 200 diff --git a/README.md b/README.md index 4fecfad..58dde4f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ project home: -read the spec: +read the spec: reference compiler: diff --git a/etc/gemtext.lua b/etc/gemtext.lua new file mode 100644 index 0000000..5fdff59 --- /dev/null +++ b/etc/gemtext.lua @@ -0,0 +1,297 @@ +-- Invoke with: pandoc -t gemtext.lua + +-- Tables to store links and footnotes, so they can be included correctly. +local links = {} +local notes = {} + +-- Blocksep is used to separate block elements. +function Blocksep() + return "\n" +end + +-- This function is called once for the whole document. Parameters: +-- body is a string, metadata is a table, variables is a table. +-- This gives you a fragment. You could use the metadata table to +-- fill variables in a custom lua template. Or, pass `--template=...` +-- to pandoc, and pandoc will do the template processing as usual. +function Doc(body, metadata, variables) + local buffer = {} + local function add(s) + table.insert(buffer, s) + end + add(body) + if #notes > 0 then + add('') + for _,note in pairs(notes) do + add(note) + end + end + return table.concat(buffer, '\n') +end + +-- The functions that follow render corresponding pandoc elements. +-- s is always a string, attr is always a table of attributes, and +-- items is always an array of strings (the items in a list). +-- Comments indicate the types of other variables. + +function Str(s) + return s +end + +function Space() + return " " +end + +function SoftBreak() + return " " +end + +function LineBreak() + return "\n" +end + +function Emph(s) + return "_" .. s .. "_" +end + +function Strong(s) + return "**" .. s .. "**" +end + +function Subscript(s) + return "_" .. s +end + +function Superscript(s) + return "^" .. s +end + +function SmallCaps(s) + return s +end + +function Strikeout(s) + return '~~' .. s .. '~~' +end + +function Link(s, tgt, tit, attr) + if tgt:match("%.html$") and not tgt:match("^https?://") then + tgt = tgt:gsub("%.html$", ".gmi") + end + table.insert(links, "=> " .. tgt .. " " .. s) + return s +end + +function Image(s, src, tit, attr) + table.insert(links, "=> " .. src .. " [IMG] " .. s) + return s +end + +function Code(s, attr) + return "`" .. s .. "`" +end + +function InlineMath(s) + return "\\(" .. s .. "\\)" +end + +function DisplayMath(s) + return "\\[" .. s .. "\\]" +end + +function SingleQuoted(s) + return "‘" .. s .. "’" +end + +function DoubleQuoted(s) + return "“" .. s .. "”" +end + +function Note(s) + local num = #notes + 1 + local num_fn = string.gsub(num, '0', '⁰') + :gsub('1', '¹') + :gsub('2', '²') + :gsub('3', '³') + :gsub('4', '⁴') + :gsub('5', '⁵') + :gsub('6', '⁶') + :gsub('7', '⁷') + :gsub('8', '⁸') + :gsub('9', '⁹') + -- add a list item with the note to the note table. + table.insert(notes, num_fn .. ' ' .. s) + -- return the footnote reference, linked to the note. + return num_fn +end + +function Span(s, attr) + return s +end + +function RawInline(format, str) + if format == "gemtext" then + return str + else + return '' + end +end + +function Cite(s, cs) + local ids = {} + for _,cit in ipairs(cs) do + table.insert(ids, cit.citationId) + end + return s .. ids:concat(",") +end + +function Plain(s) + return s +end + +function Para(s) + local finished = s .. "\n" + if #links > 0 then + local link_text = links[1]:match('=> [^ ]+ (.+)') + if link_text == s and #links == 1 then + finished = links[1] .. "\n" + else + finished = finished .. table.concat(links, "\n") .. "\n" + end + end + links = {} + return finished +end + +-- lev is an integer, the header level. +function Header(lev, s, attr) + return string.rep("#", lev) .. " " .. s .. "\n" +end + +function BlockQuote(s) + return "> " .. s:gsub("\n", "\n> "):gsub("\n> $", "\n") +end + +function HorizontalRule() + return "-----\n" +end + +function LineBlock(ls) + return table.concat(ls, '\n') .. "\n" +end + +function CodeBlock(s, attr) + return "```\n" .. s .. "\n```\n" +end + +function BulletList(items) + local buffer = {} + for _, item in pairs(items) do + local finished = false + if #links > 0 then + local link_text = links[1]:match('=> [^ ]+ (.+)') + if link_text == item then + table.insert(buffer, links[1]) + table.remove(links, 1) + finished = true + end + end + if not finished then + table.insert(buffer, "* " .. item) + for _,link in pairs(links) do + table.insert(buffer, link) + end + links = {} + end + end + return table.concat(buffer, "\n") .. "\n" +end + +function OrderedList(items) + local buffer = {} + for i, item in pairs(items) do + table.insert(buffer, i .. ". " .. item) + end + return table.concat(buffer, "\n") .. "\n" +end + +function DefinitionList(items) + local buffer = {} + for _,item in pairs(items) do + local k, v = next(item) + table.insert(buffer, k .. ":\n" .. table.concat(v, "\n")) + end + return table.concat(buffer, "\n") .. "\n" +end + +function CaptionedImage(src, tit, caption, attr) + return '=> ' .. src .. ' [IMG] ' .. caption .. '\n' +end + +-- Caption is a string, aligns is an array of strings, +-- widths is an array of floats, headers is an array of +-- strings, rows is an array of arrays of strings. +function Table(caption, aligns, widths, headers, rows) + local buffer = {} + local function add(s) + table.insert(buffer, s) + end + add("") + if caption ~= "" then + add("") + end + if widths and widths[1] ~= 0 then + for _, w in pairs(widths) do + add('') + end + end + local header_row = {} + local empty_header = true + for i, h in pairs(headers) do + table.insert(header_row,'') + empty_header = empty_header and h == "" + end + if empty_header then + head = "" + else + add('') + for _,h in pairs(header_row) do + add(h) + end + add('') + end + local class = "even" + for _, row in pairs(rows) do + class = (class == "even" and "odd") or "even" + add('') + for i,c in pairs(row) do + add('') + end + add('') + end + add('
" .. caption .. "
' .. h .. '
' .. c .. '
') + return table.concat(buffer,'\n') .. "\n" +end + +function RawBlock(format, str) + if format == "gemtext" then + return str + else + return '' + end +end + +function Div(s, attr) + return s +end + +-- The following code will produce runtime warnings when you haven't defined +-- all of the functions you need for the custom writer, so it's useful +-- to include when you're working on a writer. +local meta = {} +meta.__index = + function(_, key) + io.stderr:write(string.format("WARNING: Undefined function '%s'\n",key)) + return function() return "" end + end +setmetatable(_G, meta) diff --git a/etc/template.gmi b/etc/template.gmi new file mode 100644 index 0000000..36d66c2 --- /dev/null +++ b/etc/template.gmi @@ -0,0 +1 @@ +$body$ -- cgit v1.2.3