------------------------------------------------------------------------------- -- eLua doc builder module (for the eluadoc/ directory) module( ..., package.seeall ) local sf = string.format ------------------------------------------------------------------------------- -- Data structure declarations -- List here all the sections for which we're generating the documentation local doc_sections = { "arch_platform", "refman_gen", "refman_ps_lm3s", "refman_ps_str9", "refman_ps_mbed", "refman_ps_mizar32" } -- List here all the components of each section local components = { arch_platform = { "ll", "pio", "spi", "uart", "timers", "pwm", "cpu", "eth", "adc", "i2c", "can" }, refman_gen = { "bit", "pd", "cpu", "pack", "adc", "term", "pio", "uart", "spi", "tmr", "pwm", "net", "can", "rpc", "elua", "i2c" }, refman_ps_lm3s = { "disp" }, refman_ps_str9 = { "pio" }, refman_ps_mbed = { "pio" }, refman_ps_mizar32 = { "lcd", "rtc" }, } ------------------------------------------------------------------------------- -- Generic helpers and doc text formatting functions -- Format a name to a link by changing all the spaces to "_" and -- making all letters lowercase local function name2link( str ) str = str:gsub( " ", "_" ) return str:lower() end -- Returns the part of the string enclosed between two '#' chars -- Used for parsing function sig. local function namefromsig( str ) local _, _, name = str:find( "#(.*)#" ) return name end -- Adds a "." to the end of the string if it's not already present local function dot( str ) -- return str:sub( -1 ) == "." and str or str .. "." return str end --[[ Process the given string as follows: - $string$ becomes string - %string% becomes string - @ref@text@ becomes text - ^ref^text^ also becomes text - $$, %%, @@, ^^ become $, %, @, ^ respectively - the string "eLua" becomes eLua - strings between two tildas (~~) get special code-like formatting - newlines are changed to ' ' if 'keepnl' isn't true - '&' is translated to its corresponding HTML code. - '<<' and '>>" are also translated to the corresponding HTML codes (note the repetition). --]] local function format_string( str, keepnl ) -- replace double "special chars" with "temps" for later use str = str:gsub( "%$%$", "\001" ) str = str:gsub( "%%%%", "\002" ) str = str:gsub( "@@", "\003" ) str = str:gsub( "%^%^", "\004" ) str = str:gsub( "~~", "\005" ) -- Translate 'special' HTML chars to their equivalents local tr_table = { [ "%&" ] = "&", } for char, rep in pairs( tr_table ) do str = str:gsub( char, rep ) end -- some double chars are replaced directly with their HTML codes str = str:gsub( "<<", "<" ) str = str:gsub( ">>", ">" ) -- replace eLua with eLua str = str:gsub( "eLua", "eLua" ) -- $string$ becomes string> str = str:gsub( "%$(.-)%$", "%1" ) -- %string% becomes string str = str:gsub( "%%(.-)%%", "%1" ) -- @ref@text@ becomes text str = str:gsub( "@(.-)@(.-)@", '%2' ) -- ^ref^text^ becomes text str = str:gsub( "%^(.-)%^(.-)%^", '%2' ) -- strings between two tildas (~~) get special code-like formatting -- must keep '\n', so replace it with "temps" for now str = str:gsub( "~(.-)~", function( data ) return '
' .. data:gsub( "\n", "\006" ) .. "" end ) str = str:gsub( "~~", "~" ) -- other "\n" chars should dissapear now if not keepnl then str = str:gsub( "\n", " " ) end -- put back the "temps" str = str:gsub( "\001", "%$" ) str = str:gsub( "\002", "%%" ) str = str:gsub( "\003", "@" ) str = str:gsub( "\004", "%^" ) str = str:gsub( "\005", "~" ) str = str:gsub( "\006", "\n" ) -- all done return str end ------------------------------------------------------------------------------- -- Content generation -- Build the documentation starting from the given file local function build_file( fname ) dofile( fname ) local res = {} for _, lang in pairs( languages ) do res[ lang ] = {} res[ lang ].menu = {} local menu = res[ lang ].menu -- we need english always -- the other languages will be substituted with english if not found local resname = string.format( "data_%s", lang ) local r = _G[ resname ] if not r then if lang == "en" then return false, "data_en must exist in the description" else print( string.format( "'%s': data for language '%s' not found, defaulting to english", fname, lang ) ) r = _G.data_en end end -- process names if not r.menu_name then return false, "menu_names not found" end menu.name = r.menu_name -- process title if not r.title then return false, "title not found" end local page = "$$HEADER$$\n" menu.title = r.title -- process overview if not r.overview then return false, "overview not found" end page = page .. '
' .. format_string( r.overview ) .. "
\n\n" -- process structures if needed if r.structures then local structures = r.structures menu.structs = {} page = page .. '" .. format_string( s.text, true ) .. "
\n"
-- description
page = page .. '' .. format_string( s.desc ) .. "
\n" .. dot( format_string( f.desc ) ) .. "
\n" -- arguments page = page .. "Arguments: " if f.args then local a = f.args if type( a ) == "string" or ( type( a ) == "table" and #a == 1 ) then local text = type( a ) == "string" and a or a[ 1 ] page = page .. dot( format_string( text ) ) .. "
" else page = page .. "\nReturns: " if f.ret then local r = f.ret if type( r ) == "string" or ( type( r ) == "table" and #r == 1 ) then local text = type( r ) == "string" and r or r[ 1 ] page = page .. dot( format_string( text ) ) .. "
" else page = page .. "\n" .. format_string( a.desc ) .. "
\n\n" end end -- footer page = page .. "$$FOOTER$$\n" -- Cleanup: remove "" (which might appear due to formatting) page = page:gsub( "%s-
", "" ) res[ lang ].page = page end return res end ------------------------------------------------------------------------------- -- Menu generation -- Helper function to get strings in all languages when needed local function all_langs( getstr ) local langs = {} for _, lang in pairs( languages ) do langs[ #langs + 1 ] = getstr( lang ) end return langs end -- Transform the data from the menu dictionary (in 'fulldata') for component 'component' and section 'sect' to a menu structure local function gen_menu( fulldata, component, sect ) local relfname = sect .. "_" .. component .. ".html" local res = fulldata[ component ] local themenu = { all_langs( function( x ) return res[ x ].menu.name end ), relfname, {}, all_langs( function( x ) return res[ x ].menu.title end ) } local sub = themenu[ submenu_idx ] -- Overview sub[ #sub + 1 ] = { all_langs( function( x ) return getstr( "Overview", x ) end ), sf( "%s#overview", relfname ) } -- Data structures (if needed) if res.en.menu.structs then sub[ #sub + 1 ] = { all_langs( function( x ) return getstr( "Data structures", x ) end ), sf( "%s#structures", relfname ), {} } local s_sub = sub[ #sub ][ submenu_idx ] for i = 1, #res.en.menu.structs do local v = res.en.menu.structs[ i ] s_sub[ #s_sub + 1 ] = { all_langs( function( x ) return res[ x ].menu.structs[ i ] end ), sf( "%s#%s", relfname, name2link( v ) ) } end end -- Functions --[[ sub[ #sub + 1 ] = { all_langs( function( x ) return getstr( "Functions", x ) end ), sf( "%s#funcs", relfname ), {} } local f_sub = sub[ #sub ][ submenu_idx ] for _, v in pairs( res.en.menu.funcs ) do f_sub[ #f_sub + 1 ] = { all_langs( function( x ) return v end ), sf( "%s#%s", relfname, name2link( v ) ) } end ]] sub[ #sub + 1 ] = { all_langs( function( x ) return getstr( "Functions", x ) end ), sf( "%s#funcs", relfname ) } -- Aux data (if needed) if res.en.menu.auxdata then for i = 1, #res.en.menu.auxdata do local v = res.en.menu.auxdata[ i ] sub[ #sub + 1 ] = { all_langs( function( x ) return res[ x ].menu.auxdata[ i ] end ), sf( "%s#%s", relfname, name2link( v ) ) } end end return themenu end ------------------------------------------------------------------------------- -- Generate documentation from eluadoc for all languages function gen_html_doc() local menu, genfiles = {}, {} for k, v in pairs( components ) do table.sort( v ) end for _, section in pairs( doc_sections ) do -- Generate documentation for each module in turn local fulldata = {} menu[ section ] = {} local ms = menu[ section ] -- First generate HTML documentation for _, modname in pairs( components[ section ] ) do local descfname = string.format( "eluadoc/%s_%s.lua", section, modname ) local res, err = build_file( descfname ) if res then fulldata[ modname ] = res -- Write doc for each language for _, lang in pairs( languages ) do local fname = string.format( "%s/%s_%s.html", lang, section, modname ) local f = io.open( fname, "wb" ) if not f then print( string.format( "Unable to open %s for writing", fname ) ) return else f:write( res[ lang ].page ) f:close() print( ( "Wrote %s" ):format( fname ) ) genfiles[ #genfiles + 1 ] = fname end end else print( string.format( "Error processing module '%s': %s", modname, err ) ) return end end -- Then generate menu data for _, modname in pairs( components[ section ] ) do local submenu= gen_menu( fulldata, modname, section ) ms[ #ms + 1 ] = submenu end end return menu, genfiles end