Operating system for OpenComputers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
3.8KB

  1. local _,serial = pcall(require,"serialization")
  2. local doc = {}
  3. doc.searchers = {}
  4. doc.tctab = {
  5. ["string"] = 31,
  6. ["table"] = 32,
  7. ["number"] = 33,
  8. ["boolean"] = 35,
  9. ["function"] = 36
  10. }
  11. function doc.parsefile(path) -- string -- table -- parses file from *path* to return a documentation table
  12. local fdoc = {}
  13. local f = io.open(path)
  14. local lines = {}
  15. for l in f:read("*a"):gmatch("[^\n]+") do
  16. if l:find("function") and not l:find("local") then
  17. lines[#lines+1] = l
  18. end
  19. end
  20. for k,v in pairs(lines) do
  21. local name, args, desc = v:match("function%s+(.+)%s*%((.*)%)%s*%-%-%s*(.+)")
  22. if name and args and desc then
  23. local fd = {["description"]=desc or desc,["args"]={},["atypes"]={}}
  24. for word in args:gmatch("[^%s,]+") do
  25. fd.args[#fd.args+1] = {word}
  26. fd.atypes[word] = "unknown"
  27. end
  28. local argtypes, outtypes, description = desc:match("(.-)%-%-(.-)%-%-%s*(.+)")
  29. if argtypes and outtypes and description then
  30. local wc = 1
  31. for word in argtypes:gmatch("%S+") do
  32. fd.args[wc][2] = word
  33. fd.atypes[fd.args[wc][1]] = word
  34. wc = wc + 1
  35. end
  36. local wc = 1
  37. for word in outtypes:gmatch("%S+") do
  38. fd.outtypes = fd.outtypes or {}
  39. fd.outtypes[#fd.outtypes+1] = word
  40. end
  41. fd.description = description
  42. end
  43. fdoc[name] = fd
  44. end
  45. end
  46. return fdoc
  47. end
  48. function doc.format(fdoc) -- table -- string -- returns VT100 formatted documentation from documentation table *fdoc*
  49. local rs = "" -- string to return
  50. for fname,finfo in pairs(fdoc) do
  51. if rs:len() > 0 then rs = rs .. "\n\n" end
  52. local as = "" -- string containing arguments for a given function, with colours for type
  53. for k,v in ipairs(finfo.args) do
  54. local c = doc.tctab[v[2]] or 0
  55. if k > 1 then
  56. as = as .. ", "
  57. end
  58. if v[2] then
  59. as = string.format("%s%s: \27[%im%s\27[0m",as,v[2],c,v[1])
  60. else
  61. as = string.format("%s\27[%im%s\27[0m",as,c,v[1])
  62. end
  63. end
  64. local rv = ""
  65. if finfo.outtypes then
  66. rv = ": "
  67. for k,v in ipairs(finfo.outtypes) do
  68. if k > 1 then
  69. rv = rv .. ", "
  70. end
  71. local c = doc.tctab[v] or 0
  72. rv = string.format("%s\27[%im%s\27[0m",rv,c,v)
  73. end
  74. end
  75. local nd = finfo.description
  76. for k,v in pairs(finfo.atypes) do
  77. local c = doc.tctab[v] or 7
  78. nd=nd:gsub("%*"..k.."%*","\27["..tostring(c).."m"..k.."\27[0m")
  79. end
  80. rs = string.format("%s\27[36m%s\27[0m(%s)%s\n%s",rs,fname,as,rv,nd)
  81. end
  82. return rs
  83. end
  84. 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.
  85. local lib = os.getenv("LIB") or "/boot/lib"
  86. local dt
  87. for d in lib:gmatch("[^\n]+") do
  88. if fs.exists(d.."/"..name) then
  89. dt = doc.parsefile(d.."/"..name)
  90. elseif fs.exists(d.."/"..name..".lua") then
  91. dt = doc.parsefile(d.."/"..name..".lua")
  92. end
  93. end
  94. if not dt then return false, "unable to find documentation for "..tostring(name) end
  95. return doc.format(dt)
  96. end
  97. function doc.searchers.cdoc(topic) -- string -- string string -- Searches for documentation labelled as *topic* in .dict files under /boot/doc/
  98. if not serial then return end
  99. for k,v in ipairs(fs.list("/boot/doc")) do
  100. if v:sub(-5) == ".dict" then
  101. local f=io.open("/boot/doc/"..v,"rb")
  102. for line in f:lines() do
  103. local mname, docs = line:match("^(.-)\t(.+)$")
  104. if mname == topic or mname == topic..".lua" then
  105. return doc.format(serial.unserialize(docs))
  106. end
  107. end
  108. end
  109. end
  110. end
  111. function doc.docs(topic) -- string -- boolean -- Displays the documentation for *topic*, returning true, or errors. Also callable as just doc().
  112. local lib = os.getenv("LIB") or "/boot/lib"
  113. local dt
  114. for k,v in pairs(doc.searchers) do
  115. dt=v(topic)
  116. if dt then
  117. print(dt)
  118. return true
  119. end
  120. end
  121. error("unable to find documentation for "..tostring(name))
  122. end
  123. return setmetatable(doc,{__call=function(_,topic) return doc.docs(topic) end})