Page 1 of 2

Script to create Lua API documentation in html.

PostPosted: Wed Dec 11, 2013 4:30 am
by stratified
hi there,

For the people who don't like the API browser. I wrote a Lua script a while ago to create a html file describing the Octane Lua API. The script will ask for an output file.

create-docs.lua
html documentation creation script
(11.72 KiB) Downloaded 641 times

create-docs_213.lua
html documentation creation script for Standalone v2.13+
(11.7 KiB) Downloaded 930 times


cheers,
Thomas

Re: Script to create Lua API documentation in html.

PostPosted: Wed Dec 11, 2013 5:00 am
by Tugpsx
Output error with script
LuaAPIDocerror.JPG
Lua doc error


Also text in the Output area of the editor doesn't copy to clipboard

Re: Script to create Lua API documentation in html.

PostPosted: Wed Dec 11, 2013 5:41 am
by stratified
Hi there,

I modified the script to dump out an error when doc is nil. This can happend when that file is not writable. Could you try to use a different path in the variable HTML_FILE?

thanks,
Thomas

Code: Select all
--
-- Creates a single html that describes the Lua API. Run this thing from
-- within Octane. It creates a file api.html next to the Octane binary.
--


local HTML_FILE = "/tmp/api.html"

doc, errMsg = io.open(HTML_FILE, "w")
if not doc then error(errMsg) end

local cssStyle =
[[

body
{
    font-family: 'Titillium Web', Verdana, Helvetica, sans-serif;
}
h1
{
    color: #d50708;
}
h2
{
    color: #d50708;
    border-bottom: 1px solid #d50708;

}

h3
{
    color: #3083aa;
    border-bottom: 1px solid #3083aa;
}

a
{
    color: #FF6600;
}

a:hover
{
    color: white;
    background-color: #FF6600;
}

table.funcdoc
{
    padding-top: 10px;
}

table.funcdoc th
{
    color:#4b6a7e;
    padding-right: 40px;
}
]]


local function inArray(array, value)
    for _, val in ipairs(array) do
        if value == val then return true end
    end
    return false
end

-- Inline CSS style

doc:write("<html>")
doc:write("<head>")
doc:write(string.format("<style>%s</style>", cssStyle))
doc:write("</head>")

doc:write("<body>")

-- Logo
doc:write('<div class="logo" style="left: 200px; opacity: 1;">')
doc:write('<img src="http://render.otoy.com/images/octanerender_logo.png" width="58" height="65" alt="Octane Render Logo" class="spinme">')
doc:write('<img src="http://render.otoy.com/images/octanerender_text.png" width="206" height="65" alt="Octane Render">')
doc:write('</div>')

doc:write("<h1>Lua API<h1>")

local modules = octane.help.modules()

-- Module overview.
doc:write("<h2>Modules Overview</h2>")
doc:write("<table class='overview'>")
for name, description in pairs(modules) do
    doc:write(string.format("<tr><td><a href='#%s'>%s</a></td><td>%s</td></tr>", name, name, description))
end
doc:write("</table>")

-- Per Module breakdown.
for moduleName, description in pairs(modules) do
    doc:write(string.format("<h2 id='%s'>Module %s</h2>", moduleName, moduleName))
    doc:write(string.format("<p>%s</p>", description))

    -- Table with functions.
    local modfunctions = octane.help.functions(moduleName)
    doc:write("<h3>Functions</h3>")
    doc:write("<table class='overview'>")
    for _, func in ipairs(modfunctions) do
        local funcdoc = octane.help.functionDoc(octane[moduleName][func])
        local fullName = string.format("octane.%s.%s", moduleName, func)
        doc:write(string.format("<tr><td><a href='#%s'>%s</a></td><td>%s</td></tr>", fullName, fullName, funcdoc.description))
    end
    doc:write("</table>")

    -- Table with the properties.
    local moduleProps = octane.help.properties(moduleName)
    if #moduleProps > 0 then
        doc:write("<h3>Properties</h3>")
        doc:write("<table class='overview'>")
        for idx, propsName in ipairs(moduleProps) do
            local propsDoc = octane.help.propertiesDoc(moduleName, propsName)
            local fullName = string.format("octane.%s.%s", moduleName, propsName)
            doc:write(string.format("<tr><td><a href='#%s'>%s</a></td><td>%s</td></tr>", fullName, fullName, propsDoc.description))
        end
        doc:write("</table>")
    end

    -- Table with the constants.
    local moduleConstants = octane.help.constants(moduleName)
    if #moduleConstants > 0 then
        doc:write("<h3>Constants</h3>")
        doc:write("<table class='overview'>")
        for idx, constantName in ipairs(moduleConstants) do
            local constantInfo = octane.help.constantDoc(moduleName, constantName)
            local fullName     = string.format("octane.%s.%s", moduleName, constantName)
            doc:write(string.format("<tr><td><a href='#%s'>%s</a></td><td>%s</td></tr>", fullName, fullName, constantInfo.description))
        end
        doc:write("</table>")
    end
end

-- Give a breakdown per function.
doc:write("<h2>Function Overview</h2>")
for moduleName, moduleDescription in pairs(modules) do
    local moduleFunctions = octane.help.functions(moduleName)
    for _, functionName in ipairs(moduleFunctions) do

        local fullName = string.format("octane.%s.%s", moduleName, functionName)
        doc:write(string.format("<h3 id='%s'>%s</h3>", fullName, fullName))

        local funcDoc  = octane.help.functionDoc(octane[moduleName][functionName])
        local modProps = octane.help.properties(moduleName)

        doc:write("<span class='funcdoc'>")

        -- Table with the description.
        doc:write("<table class='funcdoc'>")
        doc:write("<tr align='left'><th>Description</th></tr>")
        doc:write(string.format("<tr><td>%s</td></tr>", funcDoc.description))
        doc:write("</table>")

        -- Table with the parameters.
        if #funcDoc.params > 0 then
            doc:write("<table class='funcdoc'>")
            doc:write("<tr align='left'> <th colspan='3'>Parameters</th> </tr>")
            doc:write("<tr align='left'> <th>Name</th> <th>Type</th> <th>Description</th> </tr>")
            for _, param in ipairs(funcDoc.params) do
                if (not inArray(modProps, param.name)) then
                    -- regular param
                    doc:write(string.format("<tr> <td>%s</td> <td>%s</td> <td>%s</td> </tr>",
                                            param["name"], param["type"], param["description"]))
                else
                    -- property
                    doc:write(string.format("<tr> <td><a href='#%s'>%s</a></td> <td>%s</td> <td>%s</td> </tr>",
                                            string.format("octane.%s.%s", moduleName, param.name),
                                            param["name"],
                                            param["type"],
                                            param["description"]))
                end
            end
            doc:write("</table>")
        end

        -- Table with return values.
        if #funcDoc.returns > 0 then
            doc:write("<table class='funcdoc'>")
            doc:write("<tr align='left'> <th colspan='3'>Return Values</th> </tr>")
            doc:write("<tr align='left'> <th>Name</th> <th>Type</th> <th>Description</th> </tr>")
            for _, ret in ipairs(funcDoc.returns) do
                if not inArray(modProps, ret.name) then
                    -- regular return value.
                    doc:write(string.format("<tr> <td>%s</td> <td>%s</td> <td>%s</td> </tr>", ret["name"], ret["type"], ret["description"]))
                else
                    -- property return value.
                    doc:write(string.format("<tr> <td><a href='#%s'>%s</a></td> <td>%s</td> <td>%s</td> </tr>",
                                            string.format("octane.%s.%s", moduleName, ret.name),
                                            ret["name"],
                                            ret["type"],
                                            ret["description"]))
                end
            end
            doc:write("</table>")
        end

        -- Create the synopsis.
        local synopsis = ""
        if #funcDoc.returns > 0 then
            for i=1,#funcDoc.returns-1 do
                synopsis = synopsis..funcDoc.returns[i].name..", "
            end
            synopsis = synopsis..funcDoc.returns[#funcDoc.returns].name.." = "
        end
        synopsis = synopsis..fullName.."( "
        if #funcDoc.params > 0 then
            for i=1,#funcDoc.params-1 do
                synopsis = synopsis..funcDoc.params[i].name..", "
            end
            synopsis = synopsis..funcDoc.params[#funcDoc.params].name
        end
        synopsis = synopsis.." )"

        -- Table with the synopsis.
        doc:write("<table class='funcdoc'>")
        doc:write("<tr align='left'><th>Synopsis</th></tr>")
        doc:write(string.format("<tr align='left'><td>%s</td></tr>", synopsis))
        doc:write("</table>")

        doc:write("</span>")
    end
end


-- Give a breakdown per constant.
doc:write("<h2>Constant Overview</h2>")
for moduleName, moduleDescription in pairs(modules) do
    local constantNames = octane.help.constants(moduleName)
    for _, constantName in ipairs(constantNames) do
        local fullName = string.format("octane.%s.%s", moduleName, constantName)
        doc:write(string.format("<h3 id='%s'>%s</h3>", fullName, fullName))

        local constDoc = octane.help.constantDoc(moduleName, constantName)

        -- Table with the description.
        doc:write("<table class='funcdoc'>")
        doc:write("<tr align='left'><th>Description</th></tr>")
        doc:write(string.format("<tr><td>%s</td></tr>", constDoc.description))
        doc:write("</table>")

        -- Table with the constant values.
        doc:write("<table class='funcdoc'>")
        doc:write("<tr align='left'><th>Values</th></tr>")

        -- Get the names.
        local names = {}
        for name, _ in pairs(constDoc.values) do
            table.insert(names, name)
        end
        -- Sort the names.
        table.sort(names)

        for _, name in ipairs(names) do
            doc:write(string.format("<tr> <td>%s</td> </tr>", name))
        end
        doc:write("</table>")

    end
end

-- Give a breakdown per properties.
doc:write("<h2>Properties Overview</h2>")
for moduleName, moduleDescription in pairs(modules) do
    local moduleProps = octane.help.properties(moduleName)
    for _, propertiesName in ipairs(moduleProps) do

        local fullName = string.format("octane.%s.%s", moduleName, propertiesName)
        doc:write(string.format("<h3 id='%s'>%s</h3>", fullName, fullName))

        local propertiesDoc = octane.help.propertiesDoc(moduleName, propertiesName)

        doc:write("<span class='funcdoc'>")

        -- Table with the description.
        doc:write("<table class='funcdoc'>")
        doc:write("<tr align='left'><th>Description</th></tr>")
        doc:write(string.format("<tr><td>%s</td></tr>", propertiesDoc.description))
        doc:write("</table>")

        local properties = propertiesDoc.properties
        local propNames  = {}
        for name, _ in pairs(properties) do
            table.insert(propNames, name)
        end
        table.sort(propNames)

        -- Table with each proprty
        doc:write("<table class='funcdoc'>")
        doc:write("<tr align='left'> <th colspan='3'>Properties</th> </tr>")
        doc:write("<tr align='left'> <th>Name</th> <th>Description</th> <th>Type</th> <th>Writable</th></tr>")
        for _,name in ipairs(propNames) do
            local info = properties[name]
            doc:write(string.format("<tr> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> </tr>",
                                    name, info.description, info["type"], info.writable))
        end
        doc:write("</table>")

        doc:write("</span>")
    end
end


doc:write("</body>")
doc:write("</html>")

Re: Script to create Lua API documentation in html.

PostPosted: Wed Dec 11, 2013 5:43 am
by stratified
Tugpsx wrote:Also text in the Output area of the editor doesn't copy to clipboard


just noticed that as well, we'll fix it in one of the next releases.

cheers,
Thomas

Re: Script to create Lua API documentation in html.

PostPosted: Wed Dec 11, 2013 6:01 am
by Tugpsx
Can we add an option to clear the output in the editor also. This will help a lot with debugging script outputs

Re: Script to create Lua API documentation in html.

PostPosted: Wed Dec 11, 2013 6:05 am
by Tugpsx
Output works great now. But better yet add an option for it to prompt the user for the location to save the file. End user will appreciate it.

Re: Script to create Lua API documentation in html.

PostPosted: Wed Dec 11, 2013 6:55 am
by stratified
This will show a dialog asking the user where to save the file. It pops up an error if something went wrong.

But then again I guess the people who're interested in Lua could have figured this out themselves ;)

cheers,
Thomas

Code: Select all
--
-- Creates a single html that describes the Lua API. Run this thing from
-- within Octane. It creates a file api.html next to the Octane binary.
--


-- show the user a file chooser
result = octane.gui.showDialog
{
    type      = octane.gui.dialogType.FILE_DIALOG,
    title     = "Choose Lua API html doc output",
    wildcards = "*.html;*.htm",
    save      = true
}

-- try to open the file and show an error dialog if it failed
doc, errMsg = io.open(result.result, "w")
if not doc then
    result = octane.gui.showDialog
    {
        type  = octane.gui.dialogType.ERROR_DIALOG,
        title = "File error",
        text  = errMsg
    }
    -- stop the script
    error(errMsg)
end
   

local cssStyle =
[[

body
{
    font-family: 'Titillium Web', Verdana, Helvetica, sans-serif;
}
h1
{
    color: #d50708;
}
h2
{
    color: #d50708;
    border-bottom: 1px solid #d50708;

}

h3
{
    color: #3083aa;
    border-bottom: 1px solid #3083aa;
}

a
{
    color: #FF6600;
}

a:hover
{
    color: white;
    background-color: #FF6600;
}

table.funcdoc
{
    padding-top: 10px;
}

table.funcdoc th
{
    color:#4b6a7e;
    padding-right: 40px;
}
]]


local function inArray(array, value)
    for _, val in ipairs(array) do
        if value == val then return true end
    end
    return false
end

-- Inline CSS style

doc:write("<html>")
doc:write("<head>")
doc:write(string.format("<style>%s</style>", cssStyle))
doc:write("</head>")

doc:write("<body>")

-- Logo
doc:write('<div class="logo" style="left: 200px; opacity: 1;">')
doc:write('<img src="http://render.otoy.com/images/octanerender_logo.png" width="58" height="65" alt="Octane Render Logo" class="spinme">')
doc:write('<img src="http://render.otoy.com/images/octanerender_text.png" width="206" height="65" alt="Octane Render">')
doc:write('</div>')

doc:write("<h1>Lua API<h1>")

local modules = octane.help.modules()

-- Module overview.
doc:write("<h2>Modules Overview</h2>")
doc:write("<table class='overview'>")
for name, description in pairs(modules) do
    doc:write(string.format("<tr><td><a href='#%s'>%s</a></td><td>%s</td></tr>", name, name, description))
end
doc:write("</table>")

-- Per Module breakdown.
for moduleName, description in pairs(modules) do
    doc:write(string.format("<h2 id='%s'>Module %s</h2>", moduleName, moduleName))
    doc:write(string.format("<p>%s</p>", description))

    -- Table with functions.
    local modfunctions = octane.help.functions(moduleName)
    doc:write("<h3>Functions</h3>")
    doc:write("<table class='overview'>")
    for _, func in ipairs(modfunctions) do
        local funcdoc = octane.help.functionDoc(octane[moduleName][func])
        local fullName = string.format("octane.%s.%s", moduleName, func)
        doc:write(string.format("<tr><td><a href='#%s'>%s</a></td><td>%s</td></tr>", fullName, fullName, funcdoc.description))
    end
    doc:write("</table>")

    -- Table with the properties.
    local moduleProps = octane.help.properties(moduleName)
    if #moduleProps > 0 then
        doc:write("<h3>Properties</h3>")
        doc:write("<table class='overview'>")
        for idx, propsName in ipairs(moduleProps) do
            local propsDoc = octane.help.propertiesDoc(moduleName, propsName)
            local fullName = string.format("octane.%s.%s", moduleName, propsName)
            doc:write(string.format("<tr><td><a href='#%s'>%s</a></td><td>%s</td></tr>", fullName, fullName, propsDoc.description))
        end
        doc:write("</table>")
    end

    -- Table with the constants.
    local moduleConstants = octane.help.constants(moduleName)
    if #moduleConstants > 0 then
        doc:write("<h3>Constants</h3>")
        doc:write("<table class='overview'>")
        for idx, constantName in ipairs(moduleConstants) do
            local constantInfo = octane.help.constantDoc(moduleName, constantName)
            local fullName     = string.format("octane.%s.%s", moduleName, constantName)
            doc:write(string.format("<tr><td><a href='#%s'>%s</a></td><td>%s</td></tr>", fullName, fullName, constantInfo.description))
        end
        doc:write("</table>")
    end
end

-- Give a breakdown per function.
doc:write("<h2>Function Overview</h2>")
for moduleName, moduleDescription in pairs(modules) do
    local moduleFunctions = octane.help.functions(moduleName)
    for _, functionName in ipairs(moduleFunctions) do

        local fullName = string.format("octane.%s.%s", moduleName, functionName)
        doc:write(string.format("<h3 id='%s'>%s</h3>", fullName, fullName))

        local funcDoc  = octane.help.functionDoc(octane[moduleName][functionName])
        local modProps = octane.help.properties(moduleName)

        doc:write("<span class='funcdoc'>")

        -- Table with the description.
        doc:write("<table class='funcdoc'>")
        doc:write("<tr align='left'><th>Description</th></tr>")
        doc:write(string.format("<tr><td>%s</td></tr>", funcDoc.description))
        doc:write("</table>")

        -- Table with the parameters.
        if #funcDoc.params > 0 then
            doc:write("<table class='funcdoc'>")
            doc:write("<tr align='left'> <th colspan='3'>Parameters</th> </tr>")
            doc:write("<tr align='left'> <th>Name</th> <th>Type</th> <th>Description</th> </tr>")
            for _, param in ipairs(funcDoc.params) do
                if (not inArray(modProps, param.name)) then
                    -- regular param
                    doc:write(string.format("<tr> <td>%s</td> <td>%s</td> <td>%s</td> </tr>",
                                            param["name"], param["type"], param["description"]))
                else
                    -- property
                    doc:write(string.format("<tr> <td><a href='#%s'>%s</a></td> <td>%s</td> <td>%s</td> </tr>",
                                            string.format("octane.%s.%s", moduleName, param.name),
                                            param["name"],
                                            param["type"],
                                            param["description"]))
                end
            end
            doc:write("</table>")
        end

        -- Table with return values.
        if #funcDoc.returns > 0 then
            doc:write("<table class='funcdoc'>")
            doc:write("<tr align='left'> <th colspan='3'>Return Values</th> </tr>")
            doc:write("<tr align='left'> <th>Name</th> <th>Type</th> <th>Description</th> </tr>")
            for _, ret in ipairs(funcDoc.returns) do
                if not inArray(modProps, ret.name) then
                    -- regular return value.
                    doc:write(string.format("<tr> <td>%s</td> <td>%s</td> <td>%s</td> </tr>", ret["name"], ret["type"], ret["description"]))
                else
                    -- property return value.
                    doc:write(string.format("<tr> <td><a href='#%s'>%s</a></td> <td>%s</td> <td>%s</td> </tr>",
                                            string.format("octane.%s.%s", moduleName, ret.name),
                                            ret["name"],
                                            ret["type"],
                                            ret["description"]))
                end
            end
            doc:write("</table>")
        end

        -- Create the synopsis.
        local synopsis = ""
        if #funcDoc.returns > 0 then
            for i=1,#funcDoc.returns-1 do
                synopsis = synopsis..funcDoc.returns[i].name..", "
            end
            synopsis = synopsis..funcDoc.returns[#funcDoc.returns].name.." = "
        end
        synopsis = synopsis..fullName.."( "
        if #funcDoc.params > 0 then
            for i=1,#funcDoc.params-1 do
                synopsis = synopsis..funcDoc.params[i].name..", "
            end
            synopsis = synopsis..funcDoc.params[#funcDoc.params].name
        end
        synopsis = synopsis.." )"

        -- Table with the synopsis.
        doc:write("<table class='funcdoc'>")
        doc:write("<tr align='left'><th>Synopsis</th></tr>")
        doc:write(string.format("<tr align='left'><td>%s</td></tr>", synopsis))
        doc:write("</table>")

        doc:write("</span>")
    end
end


-- Give a breakdown per constant.
doc:write("<h2>Constant Overview</h2>")
for moduleName, moduleDescription in pairs(modules) do
    local constantNames = octane.help.constants(moduleName)
    for _, constantName in ipairs(constantNames) do
        local fullName = string.format("octane.%s.%s", moduleName, constantName)
        doc:write(string.format("<h3 id='%s'>%s</h3>", fullName, fullName))

        local constDoc = octane.help.constantDoc(moduleName, constantName)

        -- Table with the description.
        doc:write("<table class='funcdoc'>")
        doc:write("<tr align='left'><th>Description</th></tr>")
        doc:write(string.format("<tr><td>%s</td></tr>", constDoc.description))
        doc:write("</table>")

        -- Table with the constant values.
        doc:write("<table class='funcdoc'>")
        doc:write("<tr align='left'><th>Values</th></tr>")

        -- Get the names.
        local names = {}
        for name, _ in pairs(constDoc.values) do
            table.insert(names, name)
        end
        -- Sort the names.
        table.sort(names)

        for _, name in ipairs(names) do
            doc:write(string.format("<tr> <td>%s</td> </tr>", name))
        end
        doc:write("</table>")

    end
end

-- Give a breakdown per properties.
doc:write("<h2>Properties Overview</h2>")
for moduleName, moduleDescription in pairs(modules) do
    local moduleProps = octane.help.properties(moduleName)
    for _, propertiesName in ipairs(moduleProps) do

        local fullName = string.format("octane.%s.%s", moduleName, propertiesName)
        doc:write(string.format("<h3 id='%s'>%s</h3>", fullName, fullName))

        local propertiesDoc = octane.help.propertiesDoc(moduleName, propertiesName)

        doc:write("<span class='funcdoc'>")

        -- Table with the description.
        doc:write("<table class='funcdoc'>")
        doc:write("<tr align='left'><th>Description</th></tr>")
        doc:write(string.format("<tr><td>%s</td></tr>", propertiesDoc.description))
        doc:write("</table>")

        local properties = propertiesDoc.properties
        local propNames  = {}
        for name, _ in pairs(properties) do
            table.insert(propNames, name)
        end
        table.sort(propNames)

        -- Table with each proprty
        doc:write("<table class='funcdoc'>")
        doc:write("<tr align='left'> <th colspan='3'>Properties</th> </tr>")
        doc:write("<tr align='left'> <th>Name</th> <th>Description</th> <th>Type</th> <th>Writable</th></tr>")
        for _,name in ipairs(propNames) do
            local info = properties[name]
            doc:write(string.format("<tr> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> </tr>",
                                    name, info.description, info["type"], info.writable))
        end
        doc:write("</table>")

        doc:write("</span>")
    end
end


doc:write("</body>")
doc:write("</html>")

Re: Script to create Lua API documentation in html.

PostPosted: Wed Dec 11, 2013 12:30 pm
by matej
Quick question about documentation: where can I get all the parameter info that the octane.node.create() function gets? ie. this:

• table PROPS_NODE_ITEM
Table with properties for the node.


I would like to generate a node graph, basically a shader. But dunno how to assign which is the parent container (node graph) to nodes.

Maybe the next tutorial could be about how to set up a generic node graph shader programatically, with texture loading from disk and all the usual stuff (setting pins, connections, mixing materials or textures...)? :)

Anyway, great work with implementing scripting. Thanks!

EDIT: ah, sorry, I got it. Was at the end of the list. To specify where the node is created, I must use the "graphOwner" param. :)

Re: Script to create Lua API documentation in html.

PostPosted: Wed Dec 11, 2013 7:17 pm
by stratified
matej wrote:Maybe the next tutorial could be about how to set up a generic node graph shader programatically, with texture loading from disk and all the usual stuff (setting pins, connections, mixing materials or textures...)? :)


I'll create a post explaining all this...

cheers,
Thomas

Re: Script to create Lua API documentation in html.

PostPosted: Tue Aug 05, 2014 6:31 pm
by ultrafish
This script is crashing with the current demo version of octane because octane[moduleName] == nil when moduleName == 'benchmark' or 'octane'. The crash happens on lines 122 and 164. I was able to put checks in for myself, but I didn't want to post my code since I'm very new to octane and I thought it might be an issue only with the demo version.

Thanks.