summaryrefslogtreecommitdiff
path: root/garkup.lua
blob: 2469aa8aa2af2935c962d354d7c1f93bf0085366 (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
112
113
114
115
116
local html = require'html'
local prose = require'prose'

local function highlight(code)
	-- todo
	return html.T.pre(code)
end

local function mode_code(S)
	local lang = S:line():match("^```(%w+) ?(.*)")

	local text = ""
	for line in S:lines() do
		if line:match("^```") then
			break
		else
			text = text .. line
		end
	end
	S:emit(highlight(text))
end

local function mode_list(S)
	local items = {}
	for line in S:lines() do
		if line:match("^%*") then
			local content = line:gsub("^%*%s*","")
			table.insert(items, html.T.li(prose(S,content)))
		else
			S:unline(line)
			break
		end
	end
	S:emit(html.T.ul(items))
end

local function mode_heading(S)
	local level, line = S:line():match("^#*()%s*(.*)")
	level = level - 1
	S:emit(html.tag('h'..level, prose(S,line)))
end

local mode_patterns = {
	{ "^```", mode_code },
	{ "^*", mode_list },
	{ "^#", mode_heading },
}

local function match_mode_pattern(S, line)
	for i, row in ipairs(mode_patterns) do
		local pattern, mode = row[1], row[2]
		if line:match(pattern) then return mode end
	end
end

local function mode_paragraphs(S)
	local para = ""
	local function finish()
		if para:match("%S") then
			S:emit(html.T.p(prose(S,para)))
		end
		para = ""
	end

	for line in S:lines() do
		local newmode = match_mode_pattern(S, line)
		if newmode then
			S:unline(line)
			finish()
			return newmode(S)
		elseif line:match("%S") then
			para = para .. line
		else
			finish()
		end
	end
end

local function split_lines(text)
	local lines = {}
	for x in text:gmatch("[^\n]*") do
		table.insert(lines, x.."\n")
	end
	return lines
end

local State = {}
function State.new(input)
	return setmetatable({
		the_lines = split_lines(input)
	}, {__index=State})
end

function State.emit(self, x)
	print(html.html(x))
end
function State.line(self)
	return table.remove(self.the_lines, 1)
end
function State.unline(self, line)
	table.insert(self.the_lines, 1, line)
end
function State.lines(self)
	return State.line, self
end
function State.remaining(self)
	return #self.the_lines > 0
end
function State.toplevel(self)
	while self:remaining() do
		mode_paragraphs(self)
	end
end


State.new(io.read"a"):toplevel()