mirror of
https://git.shadowkat.net/izaya/OC-PsychOS2.git
synced 2024-11-25 12:42:10 -05:00
155 lines
4.6 KiB
Lua
155 lines
4.6 KiB
Lua
local _,serial = pcall(require,"serialization")
|
|
local doc = {}
|
|
doc.searchers = {}
|
|
doc.tctab = {
|
|
["string"] = 31,
|
|
["table"] = 32,
|
|
["userdata"] = 32,
|
|
["number"] = 33,
|
|
["boolean"] = 35,
|
|
["function"] = 36
|
|
}
|
|
|
|
function doc.parsefile(path) -- string -- table -- parses file from *path* to return a documentation table
|
|
local fdoc = {}
|
|
local f = io.open(path)
|
|
local lines = {}
|
|
for l in f:read("*a"):gmatch("[^\n]+") do
|
|
if l:find("function") and not l:find("local") then
|
|
lines[#lines+1] = l
|
|
end
|
|
end
|
|
for k,v in pairs(lines) do
|
|
local name, args, desc = v:match("function%s+(.+)%s*%((.*)%)%s*%-%-%s*(.+)")
|
|
if name and args and desc then
|
|
local fd = {["description"]=desc or desc,["args"]={},["atypes"]={}}
|
|
for word in args:gmatch("[^%s,]+") do
|
|
fd.args[#fd.args+1] = {word}
|
|
fd.atypes[word] = "unknown"
|
|
end
|
|
local argtypes, outtypes, description = desc:match("(.-)%-%-(.-)%-%-%s*(.+)")
|
|
if argtypes and outtypes and description then
|
|
local wc = 1
|
|
for word in argtypes:gmatch("%S+") do
|
|
fd.args[wc][2] = word
|
|
fd.atypes[fd.args[wc][1]] = word
|
|
wc = wc + 1
|
|
end
|
|
local wc = 1
|
|
for word in outtypes:gmatch("%S+") do
|
|
fd.outtypes = fd.outtypes or {}
|
|
fd.outtypes[#fd.outtypes+1] = word
|
|
end
|
|
fd.description = description
|
|
end
|
|
fdoc[name] = fd
|
|
end
|
|
end
|
|
return fdoc
|
|
end
|
|
|
|
function doc.format(fdoc) -- table -- string -- returns VT100 formatted documentation from documentation table *fdoc*
|
|
local rs = "" -- string to return
|
|
for fname,finfo in pairs(fdoc) do
|
|
if rs:len() > 0 then rs = rs .. "\n\n" end
|
|
local as = "" -- string containing arguments for a given function, with colours for type
|
|
for k,v in ipairs(finfo.args) do
|
|
local c = doc.tctab[v[2]] or 0
|
|
if k > 1 then
|
|
as = as .. ", "
|
|
end
|
|
if v[2] then
|
|
as = string.format("%s%s: \27[%im%s\27[0m",as,v[2],c,v[1])
|
|
else
|
|
as = string.format("%s\27[%im%s\27[0m",as,c,v[1])
|
|
end
|
|
end
|
|
local rv = ""
|
|
if finfo.outtypes then
|
|
rv = ": "
|
|
for k,v in ipairs(finfo.outtypes) do
|
|
if k > 1 then
|
|
rv = rv .. ", "
|
|
end
|
|
local c = doc.tctab[v] or 0
|
|
rv = string.format("%s\27[%im%s\27[0m",rv,c,v)
|
|
end
|
|
end
|
|
local nd = finfo.description
|
|
for k,v in pairs(finfo.atypes) do
|
|
local c = doc.tctab[v] or 7
|
|
nd=nd:gsub("%*"..k.."%*","\27["..tostring(c).."m"..k.."\27[0m")
|
|
end
|
|
rs = string.format("%s\27[36m%s\27[0m(%s)%s\n%s",rs,fname,as,rv,nd)
|
|
end
|
|
return rs
|
|
end
|
|
|
|
function doc.searchers.lib(name) -- string -- string string -- Tries to find a documentation from a library with *name*. Returns either a string of documentation, or false and a reason.
|
|
local lib = os.getenv("LIB") or "/boot/lib"
|
|
local dt
|
|
for d in lib:gmatch("[^\n]+") do
|
|
if fs.exists(d.."/"..name) then
|
|
dt = doc.parsefile(d.."/"..name)
|
|
elseif fs.exists(d.."/"..name..".lua") then
|
|
dt = doc.parsefile(d.."/"..name..".lua")
|
|
end
|
|
end
|
|
if not dt then return false, "unable to find documentation for "..tostring(name) end
|
|
return doc.format(dt)
|
|
end
|
|
function doc.searchers.cdoc(topic) -- string -- string string -- Searches for documentation labelled as *topic* in .dict files under /boot/doc/
|
|
if not serial then return end
|
|
for k,v in ipairs(fs.list("/boot/doc")) do
|
|
if v:sub(-5) == ".dict" then
|
|
local f=io.open("/boot/doc/"..v,"rb")
|
|
for line in f:lines() do
|
|
local mname, docs = line:match("^(.-)\t(.+)$")
|
|
if mname == topic or mname == topic..".lua" then
|
|
return doc.format(serial.unserialize(docs))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
function doc.searchers.component(name)
|
|
local dt = {}
|
|
local addr = component.list(name)()
|
|
if addr then
|
|
for fname,_ in pairs(component.methods(addr)) do
|
|
fd = {args={},outtypes={},atypes={}}
|
|
local ds = component.doc(addr,fname)
|
|
local ins, outs, desc = ds:match("%((.-)%)") or "", ds:match("%):(.*)%-%-") or "", ds:match("%-%-(.+)") or ""
|
|
for arg in ins:gmatch("[^,%s%[%]]+") do
|
|
local an,at = arg:match("(.-):(.+)")
|
|
at = at:match("(.-)=") or at
|
|
fd.args[#fd.args+1] = {an,at}
|
|
fd.atypes[an] = at
|
|
end
|
|
for out in outs:gmatch("[^,]+") do
|
|
fd.outtypes[#fd.outtypes+1] = out:match("^%s*(.-)%s*$")
|
|
end
|
|
fd.description = desc or ""
|
|
dt[name.."."..fname] = fd
|
|
end
|
|
else
|
|
return
|
|
end
|
|
return doc.format(dt)
|
|
end
|
|
|
|
function doc.docs(topic) -- string -- boolean -- Displays the documentation for *topic*, returning true, or errors. Also callable as just doc().
|
|
local lib = os.getenv("LIB") or "/boot/lib"
|
|
local dt
|
|
for k,v in pairs(doc.searchers) do
|
|
dt=v(topic)
|
|
if dt then
|
|
print(dt)
|
|
return true
|
|
end
|
|
end
|
|
error("unable to find documentation for "..tostring(name))
|
|
end
|
|
|
|
return setmetatable(doc,{__call=function(_,topic) return doc.docs(topic) end})
|