|
- local _,serial = pcall(require,"serialization")
- local doc = {}
- doc.searchers = {}
- doc.tctab = {
- ["string"] = 31,
- ["table"] = 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.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})
|