summaryrefslogtreecommitdiff
path: root/prose.lua
blob: 90172ecd988efe1ea6cd5e5136d188fe3fe2e79f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
local html = require'garkup.html'
local T = html.T

local extensions = {}

local function prose(S, text)
	-- this may be a hack
	local replacements = {}
	local SO, SI = "\x0e", "\x0f"
	-- if debugview then SO,SI = "\x1b[7m", "\x1b[0m" end
	local function emplace(s)
		table.insert(replacements, s)
		return SO .. #replacements .. SI
	end

	-- no way to match 'after ws or at start of string'
	-- so, just add ws to start and end of string
	-- this may also be a hack
	text = ' ' .. text .. ' '

	local function simple_sub(delim, tagname)
		return {
			"(%s)"..delim..'(.-)'..delim..'(%W)', -- wo wimple
			function(a,x,b) return a..emplace(T[tagname](x))..b end
		}
	end

	local function extension(str)
		local verb, rest = str:match("^{(%w+);%s*(.*)}$")
		if verb then
			return emplace(extensions[verb](S, rest))
		end
		local verbonly = str:match("^{(%w+)}$")
		if verbonly then
			return emplace(extensions[verbonly](S))
		end
		error("invalid extension syntax: "..str)
	end

	local subs = {
		{ "%b{}", extension },
		simple_sub('%*', 'strong'),
		simple_sub('_', 'em'),
		simple_sub('`', 'code'),
	}

	for i, row in ipairs(subs) do
		local pattern,replacement = row[1], row[2]
		text = text:gsub(pattern,replacement)
	end

	text = text:gsub("^%s*",""):gsub("%s*$","")
	-- print(text)
	local insects = {""}
	local n = 1
	while n <= #text do
		local _, nn, id = text:find('^'..SO:gsub("%[","%%[").."(%d+)"..SI:gsub("%[","%%["), n)
		if nn then
			table.insert(insects, replacements[tonumber(id)])
			table.insert(insects, "")
			n = nn + 1
		else
			local c = text:sub(n,n)
			-- print("'"..c.."'")
			insects[#insects] = insects[#insects] .. c
			n = n + 1
		end
	end

	-- for i,n in ipairs(insects) do print(i,type(n),n) end

	return insects
end

extensions.fn = function(S,text)
	S.footnotes = S.footnotes or {}
	local n = #S.footnotes + 1
	local link_id = "fnref_"..n
	local note_id = "fn_"..n
	S.footnotes[n] = true -- for nested footnotes
	S.footnotes[n] = T.li({id=note_id}, {
		prose(S,text), html.safe"&nbsp;",
		T.a({href="#"..link_id, role="doc-backlink"}, html.safe"&#x21a9;&#xfe0e;")})
	return T.sup({id=link_id}, T.a({href="#"..note_id, role='doc-noteref'}, '('..n..')'))
end

extensions.fns = function(S)
	if not S.footnotes then return "" end
	return {T.hr"", T.ol({class="footnotes"},S.footnotes)}
end

extensions.meta = function(S,text)
	local fn = assert(load(string.format("return {%s}", text),"meta", "t"))
	S.meta = fn()
end

extensions.a = function(S,text)
	local url, ni = text:match("(%S+)%s*()")
	local body = prose(S, text:sub(ni))
	return T.a({href=url},body)
end

setmetatable(extensions, {__index = function(t, k)
	return function(S, text)
		io.stderr:write("warning: unknown extension "..k.."\n")
		return text
	end
end})

return prose