Lignum

Doc

May 4th, 2014
154
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.70 KB | None | 0 0
  1. -- The http API is nil when it's not enabled.
  2. if not http then
  3.     printError "The HTTP API must be enabled!"
  4.     return
  5. end
  6.  
  7. local argv = {...}
  8. local argc = #argv
  9.  
  10. local scrWidth,scrHeight = term.getSize()
  11.  
  12. -- Used for code examples. Taken straight from rom/programs/edit.
  13. local keywords = {
  14.     ["and"] = true,
  15.     ["break"] = true,
  16.     ["do"] = true,
  17.     ["else"] = true,
  18.     ["elseif"] = true,
  19.     ["end"] = true,
  20.     ["false"] = true,
  21.     ["for"] = true,
  22.     ["function"] = true,
  23.     ["if"] = true,
  24.     ["in"] = true,
  25.     ["local"] = true,
  26.     ["nil"] = true,
  27.     ["not"] = true,
  28.     ["or"] = true,
  29.     ["repeat"] = true,
  30.     ["return"] = true,
  31.     ["then"] = true,
  32.     ["true"] = true,
  33.     ["until"] = true,
  34.     ["while"] = true
  35. }
  36.  
  37. CC_WIKI_API = "http://computercraft.info/wiki/api.php"
  38.  
  39. -- If the argument count is less than 2, too few arguments were supplied.
  40. if argc < 2 then
  41.     printError "Usage: doc <api/func> <name>"
  42.     return
  43. end
  44.  
  45. -- Capitalise first letter.
  46. argv[2]:gsub("^%l", string.upper)
  47.  
  48. local function trimString(str)
  49.     return str:gsub("^%s*(.-)", "%1")
  50. end
  51.  
  52. local function writeFormatted(str) 
  53.     for word in str:gmatch("%S+") do
  54.         local col, txt = word:gmatch("\\\\(%d+):(.+)//")()
  55.  
  56.         if col ~= nil then
  57.             if term.isColour() then
  58.                 term.setTextColour(tonumber(col))
  59.             end
  60.             txt = txt:gsub("\\\\_//", " ")
  61.             word = txt
  62.         end
  63.  
  64.         if word == "\\\\nl//" then
  65.             print()
  66.         else
  67.             write(word .. " ")
  68.         end
  69.         term.setTextColour(colours.white)
  70.     end
  71. end
  72.  
  73. local function writeToWnd(wnd, str)
  74.     local oldTerm = nil
  75.  
  76.     if term.current then
  77.         oldTerm = term.redirect(wnd)
  78.     else
  79.         term.redirect(wnd)
  80.     end
  81.  
  82.     writeFormatted(str)
  83.  
  84.     if term.restore then
  85.         term.restore()
  86.     else
  87.         term.redirect(oldTerm)
  88.     end
  89. end
  90.  
  91. local function setDefaultColours(buf)
  92.     buf = buf or term
  93.     buf.setBackgroundColour(colours.black)
  94.     buf.setTextColour(colours.white)
  95. end
  96.  
  97. local function setCaptionColours(buf)
  98.     buf = buf or term
  99.     buf.setBackgroundColour(colours.white)
  100.     buf.setTextColour(colours.black)
  101. end
  102.  
  103. local function makePatternFriendly(str)
  104.     local result = str:gsub("%%", "%%%")
  105.     result = result:gsub("%(", "%%(")
  106.     result = result:gsub("%)", "%%)")
  107.     result = result:gsub("%[", "%%[")
  108.     result = result:gsub("%?", "%%?")
  109.     result = result:gsub("%*", "%%*")
  110.     result = result:gsub("%+", "%%+")
  111.     result = result:gsub("%-", "%%-")
  112.     result = result:gsub("%^", "%%^")
  113.     result = result:gsub("%.", "%%.")
  114.     result = result:gsub("%$", "%%$")
  115.     return result
  116. end
  117.  
  118. local function parseCode(code)
  119.     local result = code
  120.     result = result:gsub("\n", " \\\\nl// ")
  121.     result = result:gsub("\r", "")
  122.     result = result:gsub("<br/?>", " \\\\nl// ")
  123.  
  124.     for k,v in pairs(keywords) do
  125.         result = result:gsub("%s-(" .. k .. ")%s+", "\\\\" .. colours.yellow .. ":%1//")
  126.     end
  127.  
  128.     return result
  129. end
  130.  
  131. local function parseExamples(exText)
  132.     local result = ""
  133.     local isFirst = true
  134.  
  135. --  error(makePatternFriendly(exText))
  136.  
  137.     for example in exText:gmatch("{{(.-)}}") do
  138.         local code = example:gmatch("|code=(.+)%s|")()
  139.  
  140.         if code ~= nil then
  141.             if not isFirst then
  142.                 result = result .. "\\\\"
  143.             end
  144.  
  145.             result = result .. parseCode(code)
  146.             isFirst = false
  147.         end
  148.     end
  149.  
  150.     return result
  151. end
  152.  
  153. local function convertMarkup(mrkup, isExample)
  154.     if isExample == nil then isExample = false end
  155.  
  156.     -- Replace the HTML codes with their actual symbols.
  157.     local result = mrkup:gsub("&quot;", "\"")
  158.     result = result:gsub("&gt;", ">")
  159.     result = result:gsub("&lt;", "<")
  160.     result = result:gsub("&amp;", "&")
  161.  
  162.     -- Replace &#[ascii code]; with the proper character (e.g: '&#37;' -> '%').
  163.     for word, byte in result:gmatch("(&#(%d+);)") do
  164.         local corrected = string.char(byte)
  165.         result = result:gsub(word, makePatternFriendly(corrected))
  166.     end
  167.  
  168.     if isExample then
  169.         result = parseExamples(result)
  170.     end
  171.  
  172.     -- Remove HTML tags.
  173.     result = result:gsub("</?.-/?>", "")
  174.  
  175.     -- Replace type references with highlighted text.
  176.     result = result:gsub("{{.-|(.-)}}", "\\\\" .. colours.lime .. ":%1//")
  177.  
  178.     -- Replace links with highlighted text.
  179.     result = result:gsub("%[%[.-|(.-)]]", "\\\\" .. colours.blue .. ":%1//")
  180.     result = result:gsub("%[%[(.-)]]", "\\\\" .. colours.blue .. ":%1//")
  181.  
  182.     -- Replace double quotes with single quotes (''text'' -> 'text').
  183.     result = result:gsub("''(.-)''", "'%1'")
  184.  
  185.     -- Replace spaces in colour highlighting with "\\_//".
  186.     for word in result:gmatch("\\\\%d+:.-//") do
  187.         local newword = word:gsub("%s", "\\\\_//")
  188.         result = result:gsub(makePatternFriendly(word), makePatternFriendly(newword))
  189.     end
  190.  
  191.     result = trimString(result)
  192.     return result
  193. end
  194.  
  195. local function renderGUI(elements, activeElement, wnd)
  196.     wnd.setBackgroundColour(colours.black)
  197.     wnd.clear()
  198.     wnd.redraw()
  199.  
  200.     term.setTextColor(colours.white)
  201.     term.setCursorPos(1, scrHeight)
  202.     term.write("Arrow keys to change category; Enter to quit")
  203.  
  204.     term.setCursorPos(1, 2)
  205.     term.setBackgroundColour(colours.black)
  206.     term.clearLine()
  207.  
  208.     term.setCursorPos(1, 3)
  209.     term.setTextColor(colours.white)
  210.  
  211.     for i=1,scrWidth do
  212.         term.write("-")
  213.     end
  214.  
  215.     local nextTabPos = 1
  216.  
  217.     for i,v in ipairs(elements) do
  218.         if v.isTitle ~= nil and v.isTitle then
  219.             local txt = v.body
  220.             term.setCursorPos(scrWidth / 2 - #txt / 2, 1)
  221.             term.setBackgroundColour(colours.white)
  222.             term.setTextColour(colours.black)
  223.             term.write(txt)
  224.         else
  225.             if v.id == activeElement then
  226.                 local cap = v.caption
  227.                 term.setCursorPos(nextTabPos, 2)
  228.                 term.setBackgroundColour(colours.white)
  229.                 term.setTextColour(colours.black)
  230.                 term.write(cap)
  231.                 nextTabPos = nextTabPos + #cap + 1
  232.  
  233.                 wnd.setCursorPos(1, 1)
  234.  
  235.                 if v.body ~= "" then
  236.                     writeToWnd(wnd, v.body)
  237.                 else
  238.                     writeToWnd(wnd, "\\\\" .. colours.red .. ":N/A//")
  239.                 end
  240.             else
  241.                 local cap = v.caption
  242.                 term.setCursorPos(nextTabPos, 2)
  243.                 term.setBackgroundColour(colours.black)
  244.                 term.setTextColour(colours.white)
  245.                 term.write(cap)
  246.                 nextTabPos = nextTabPos + #cap + 1
  247.             end
  248.         end
  249.     end
  250. end
  251.  
  252. local function enterGUI(elements)
  253.     term.setBackgroundColour(colours.black)
  254.     term.clear()
  255.     term.setCursorPos(1, 1)
  256.  
  257.     local guiActive = true
  258.     local activeElement = 1
  259.  
  260.     local trm = nil
  261.  
  262.     if term.current then
  263.         trm = term.current()
  264.     else
  265.         trm = term
  266.     end
  267.  
  268.     local wnd = window.create(trm, 1, 4, scrWidth, scrHeight - 5)
  269.     wnd.setVisible(true)
  270.     renderGUI(elements, activeElement, wnd)
  271.  
  272.     while guiActive do
  273.         local e,p1,p2,p3 = os.pullEvent()
  274.         local doDraw = true
  275.  
  276.         if e == "key" then
  277.             if p1 == keys.enter then
  278.                 wnd.setVisible(false)
  279.                 term.setBackgroundColour(colours.black)
  280.                 term.clear()
  281.                 term.setCursorPos(1, 1)
  282.  
  283.                 guiActive = false
  284.                 doDraw = false
  285.             elseif p1 == keys.up or p1 == keys.left then
  286.                 activeElement = activeElement - 1
  287.                 if activeElement < 1 then activeElement = 1 end
  288.             elseif p1 == keys.down or p1 == keys.right then
  289.                 activeElement = activeElement + 1
  290.                 if activeElement > #elements - 1 then activeElement = #elements - 1 end
  291.             end
  292.         end
  293.  
  294.         if doDraw then
  295.             renderGUI(elements, activeElement, wnd)
  296.         end
  297.     end
  298. end
  299.  
  300. function printWikiInfo(xml)
  301.     -- Get the content from the first found 'rev' tag.
  302.     local content = xml:gmatch("<rev .->(.-)</rev>")()
  303.  
  304.     if content == nil then
  305.         printError "No such function."
  306.         return
  307.     end
  308.  
  309.     local name = content:gmatch("|name=(.-)%s|")()
  310.     name = convertMarkup(name or "")
  311.  
  312.     local description = content:gmatch("|desc=(.-)%s|")()
  313.     description = convertMarkup(description or "")
  314.  
  315.     local arguments = content:gmatch("|args=(.-)%s|")()
  316.     arguments = convertMarkup(arguments or "")
  317.  
  318.     local returns = content:gmatch("|returns=(.-)%s|")()
  319.     returns = convertMarkup(returns or "")
  320.  
  321.     local examples = content:gmatch("|examples=(.-}})")()
  322.     examples = convertMarkup(examples or "", true)
  323.  
  324.     local elems = {}
  325.     local lastID = 0
  326.     local nextID = 1
  327.  
  328.     if name ~= "" then
  329.         elems[#elems + 1] = {
  330.             id = 0,
  331.             isTitle = true,
  332.             caption = nil,
  333.             body = name
  334.         }
  335.     end
  336.  
  337.     if description ~= "" then
  338.         elems[#elems + 1] = {
  339.             id = nextID,
  340.             caption = "Description",
  341.             body = description
  342.         }
  343.  
  344.         nextID = nextID + 1
  345.     end
  346.  
  347.     if arguments ~= "" then
  348.         elems[#elems + 1] = {
  349.             id = nextID,
  350.             caption = "Arguments",
  351.             body = arguments
  352.         }
  353.  
  354.         nextID = nextID + 1
  355.     end
  356.  
  357.     if returns ~= "" then
  358.         elems[#elems + 1] = {
  359.             id = nextID,
  360.             caption = "Returns",
  361.             body = returns
  362.         }
  363.  
  364.         nextID = nextID + 1
  365.     end
  366.  
  367.     if examples ~= "" then
  368.         elems[#elems + 1] = {
  369.             id = nextID,
  370.             caption = "Examples",
  371.             body = examples
  372.         }
  373.  
  374.         nextID = nextID + 1
  375.     end
  376.  
  377.     enterGUI(elems)
  378. end
  379.  
  380. setDefaultColours()
  381. term.clear()
  382. term.setCursorPos(1, 1)
  383.  
  384. print("...")
  385.  
  386. term.setCursorPos(1, 1)
  387.  
  388. if argv[1] == "func" then
  389.     local headers = {
  390.         ["User-Agent"] = "Doc/1.1"
  391.     }
  392.  
  393.     local req = http.get(CC_WIKI_API .. "?format=xml&action=query&titles=" .. textutils.urlEncode(argv[2]) .. "&prop=revisions&rvprop=content", headers)
  394.  
  395.     if req == nil then
  396.         printError "Failed to connect to the CC Wiki!"
  397.         return
  398.     end
  399.  
  400.     -- If the response code is 404, the page couldn't be found.
  401.     if req.getResponseCode() == 404 then
  402.         printError("There is no documentation available for \"" .. argv[2] .. "\".")  
  403.         return
  404.     end
  405.  
  406.     local contents = req.readAll()
  407.     req.close()
  408.     printWikiInfo(contents)
  409. elseif argv[1] == "api" then
  410.     setCaptionColours()
  411.     print("Functions in \"" .. argv[2] .. "\":")
  412.  
  413.     if _G[argv[2]] == nil then
  414.         setDefaultColours()
  415.         printError "No such API."
  416.         return
  417.     end
  418.  
  419.     local functions = {}
  420.  
  421.     for k,v in pairs(_G[argv[2]]) do
  422.         if type(v) == "function" then
  423.             functions[#functions + 1] = tostring(k)
  424.         end
  425.     end
  426.  
  427.     setDefaultColours()
  428.     textutils.pagedTabulate(functions)
  429. elseif argv[1] == "print" then
  430.     local str = ""
  431.    
  432.     for i=2,argc do
  433.         str = str .. argv[i] .. " "
  434.     end
  435.  
  436.     str = decodeMarkup(str)
  437.     writeFormatted(str)
  438.     print()
  439. end
Advertisement
Add Comment
Please, Sign In to add comment