summaryrefslogtreecommitdiff
path: root/init.lua
diff options
context:
space:
mode:
Diffstat (limited to 'init.lua')
-rw-r--r--init.lua143
1 files changed, 143 insertions, 0 deletions
diff --git a/init.lua b/init.lua
new file mode 100644
index 0000000..e393b13
--- /dev/null
+++ b/init.lua
@@ -0,0 +1,143 @@
+local html = require'garkup.html'
+local T = html.T
+local prose = require'garkup.prose'
+
+function empipe(prog, input)
+ local posix = require'posix'
+ local pipe = assert(posix.popen_pipeline({
+ function() io.write(input) end,
+ prog
+ }, "r"))
+ local output = ""
+ repeat
+ local next = assert(posix.unistd.read(pipe.fd, 8192))
+ output = output .. next
+ until #next == 0
+ assert(posix.pclose(pipe))
+ return output
+end
+
+function highlight(code, lang)
+ local highlighted = empipe(
+ {"highlight", "-f", "-S", lang, "--inline-css", "--enclose-pre"},
+ code
+ )
+ return html.safe(highlighted)
+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, lang))
+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, T.li(prose(S,content)))
+ else
+ S:unline(line)
+ break
+ end
+ end
+ S:emit(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(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),
+ output = "",
+ }, {__index=State})
+end
+
+function State.emit(self, x)
+ self.output = self.output..tostring(html.html(x)).."\n"
+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
+ return self.output
+end
+
+local function garkup(text)
+ local S = State.new(text)
+ return S:toplevel(), S
+end
+
+
+-- print(garkup(io.read"a")
+return garkup