local M = {}
local cosmo = require("cosmo")
local rep = string.rep
local lpeg = require("lpeg")
local Cs, P, S, lpegmatch = lpeg.Cs, lpeg.P, lpeg.S, lpeg.match
local any = lpeg.P(1)
function M.find_template(name)
local base, ext = name:match("([^%.]*)(.*)")
local fname = base .. ext
local file = io.open(fname, "read")
if not file then
file = io.open("templates/" .. fname, "read")
end
if not file then
local home = os.getenv("HOME")
if home then
file = io.open(home .. "/.lunamark/templates/" .. fname, "read")
end
end
if not file then
local appdata = os.getenv("APPDATA")
if appdata then
file = io.open(appdata .. "/lunamark/templates/" .. fname, "read")
end
end
if file then
local data = file:read("*all")
file:close()
return data
else
return false, "Could not find template '" .. fname .. "'"
end
end
function M.sepby(arg)
local a = arg[1]
if not a then
a = {}
elseif type(a) ~= "table" then
a = {a}
end
for i in ipairs(a) do
if i > 1 then cosmo.yield{_template=2} end
cosmo.yield{it = a[i], _template=1}
end
end
function M.err(msg, exit_code)
io.stderr:write("lunamark: " .. msg .. "\n")
os.exit(exit_code or 1)
end
function M.table_copy(t)
local u = { }
for k, v in pairs(t) do u[k] = v end
return setmetatable(u, getmetatable(t))
end
function M.expand_tabs_in_line(s, tabstop)
local tab = tabstop or 4
local corr = 0
return (s:gsub("()\t", function(p)
local sp = tab - (p - 1 + corr)%tab
corr = corr - 1 + sp
return rep(" ",sp)
end))
end
local function walk(t, f)
local typ = type(t)
if typ == "string" then
f(t)
elseif typ == "table" then
local i = 1
local n
n = t[i]
while n do
walk(n, f)
i = i + 1
n = t[i]
end
elseif typ == "function" then
local ok, val = pcall(t)
if ok then
walk(val,f)
end
else
f(tostring(t))
end
end
M.walk = walk
local function flatten(ary)
local new = {}
for _,v in ipairs(ary) do
if type(v) == "table" then
for _,w in ipairs(flatten(v)) do
new[#new + 1] = w
end
else
new[#new + 1] = v
end
end
return new
end
M.flatten = flatten
local function rope_to_string(rope)
local buffer = {}
walk(rope, function(x) buffer[#buffer + 1] = x end)
return table.concat(buffer)
end
M.rope_to_string = rope_to_string
local function rope_last(rope)
if #rope == 0 then
return nil
else
local l = rope[#rope]
if type(l) == "table" then
return rope_last(l)
else
return l
end
end
end
M.rope_last = rope_last
function M.intersperse(ary, x)
local new = {}
local l = #ary
for i,v in ipairs(ary) do
local n = #new
new[n + 1] = v
if i ~= l then
new[n + 2] = x
end
end
return new
end
function M.map(ary, f)
local new = {}
for i,v in ipairs(ary) do
new[i] = f(v)
end
return new
end
function M.escaper(char_escapes, string_escapes)
local char_escapes_list = ""
for i,_ in pairs(char_escapes) do
char_escapes_list = char_escapes_list .. i
end
local escapable = S(char_escapes_list) / char_escapes
if string_escapes then
for k,v in pairs(string_escapes) do
escapable = P(k) / v + escapable
end
end
local escape_string = Cs((escapable + any)^0)
return function(s)
return lpegmatch(escape_string, s)
end
end
return M