local args = ... -- Configuration file for ldoc project='awesome' title='awesome API documentation' description='API documentation for awesome, a highly configurable X window manager (version @AWESOME_VERSION@).' -- More on it: https://github.com/stevedonovan/LDoc/blob/master/doc/doc.md#markdown-support format='discount' dir='../doc' -- Make the docs prettier pretty='lua' style=true template=true backtick_references=true merge=true use_markdown_titles=true wrap=true full_description = [[ Welcome to the documentation for the awesome window manager. Below you find an overview of the individual parts which links to the full documentation. If you are a new user, you may want to read @{07-my-first-awesome.md} to get started. In @{05-awesomerc.md}, the default configuration is explained. If you already used awesome in the past, @{89-NEWS.md} and @{17-porting-tips.md} should be useful for you. ]] topics={ '00-authors.md', '01-readme.md', '02-contributing.md', '03-declarative-layout.md', '04-new-widgets.md', '05-awesomerc.md', '06-appearance.md', '07-my-first-awesome.md', '16-using-cairo.md', '17-porting-tips.md', '90-FAQ.md', '89-NEWS.md', } -- Setup @client to be an alias for "@tparam client.object" tparam_alias('client', 'client.object') tparam_alias('tag', 'tag') -- Should be default, but is not. Sets up "@tab" => "@tparam table". tparam_alias('tab', 'table') tparam_alias('screen', 'screen') tparam_alias('screen_or_idx', 'screen|int') -- The first stereotype are the constructors. new_type("constructorfct", "Constructors", false, "Parameters") new_type("constructorfct2", "ldoc_skip", false, "Parameters") -- Hack to get the functions on top of the signals and properties new_type("function", "Functions", false, "Parameters") -- For "classes", use an explicit type for static functions. This allows -- @function and its implicit cousin to be banned in the CI. new_type("staticfct", "Static module functions", false, "Parameters") -- Documentation for objects properties new_type("property", "Object properties", false, "Type constraints") -- Documentation for objects deprecated properties new_type("deprecatedproperty", "Deprecated object properties", false, "Type constraints") -- Use a custom type for the methods to bypass the faulty ldoc built-in detection. -- (yes, the space after Methods *is* on purpose to avoid clashing with ldoc -- internal "methods" concept) new_type("method", "Object methods ", false, "Parameters") -- New type for signals new_type("signal", "Signals", false, "Arguments") -- New type for signals connections new_type("signalhandler", "Request handlers", false, "Arguments") -- Allow objects to define a set of beautiful properties affecting them new_type("beautiful", "Theme variables", false, "Type constraints") -- Put deprecated methods in their own section new_type("deprecated", "Deprecated functions", false, "Parameters") -- For the legacy stateless layout related functions new_type("legacylayout", "Layout related functions", false, "Parameters") -- Have a category for the client layouts new_type("clientlayout", "Client layouts", false, "Parameters") -- Source functions for the taglist/tasklist/layoutlist new_type("sourcefunction", "List source functions", false) -- Document some callback prototypes new_type("callback", "Callback functions prototype", false, "Parameters") -- gears.matcher / awful.rules sources new_type("rulesources", "Rule sources", false, "Parameters") -- gears.matcher / awful.rules rule components new_type("rulecomponent", "Rule components", false, "Type") -- Filter functions for the taglist/tasklist/layoutlist new_type("filterfunction", "List filters", false) -- Extra client properties available only in awful.rules/spawn constructs new_type("clientruleproperty", "Extra properties available in awful.rules and awful.spawn", false, "Type") -- Simulate the default "params" parser format, except the optional "[]" section -- needs a space. local function parse_custom_tags(text, params) text = text:gmatch("[ ]*(.*)$")() local raw_extra = "" if text:sub(1,1) == '[' then local count = 1 -- Find the matching ']' for i=2, text:len() do local char = text:sub(i,i) if char == '[' then count = count + 1 elseif char == ']' then count = count - 1 end raw_extra = raw_extra..char if count == 0 then text = text:sub(i+2) break end end end -- Split the remaining text into words. local words, values, description = {}, {}, {} for word in text:gmatch("[^ \n\r]*") do if word ~= "" then words[#words+1] = word end end for idx, word in ipairs(words) do if idx <= #params then local name = params[idx].name values[name] = { name = name, title = params[idx].title or name, value = word } else description[#description+1] = word values.description = values.description and values.description.." "..word or word end end return values end -- Mimic the template classes. local function default_format_callback(self, params, _, md) local ret = "" if self.table then -- All columns are mandatory for _, p in ipairs(self.params) do local content = params[p.name] and params[p.name].value or "" ret = ret..""..(p.markdown and md("`"..content.."`") or content).."" end return ret .. ""..md(params.description).."" else if params.name then ret = ''.. md("`"..params.name.value.."`").. " " end if params.type then ret = ret .. '('.. md("`"..params.type.value.."`").. ")" end return ret.." "..md(params.description) end end -- Generate a format function. local function default_format(self, callback) return function(raw, item, md) return (callback or default_format_callback)( self, parse_custom_tags(raw, self.params or {}), item, md ) end end local named_tags, item_id = {}, 1 -- Add a new @something which can be used in any types. -- @tparam table args -- @tparam string args.name The name. -- @tparam string args.hidden Show in the doc or for internal use only. -- @tparam table args.table Show the items in a table rather than a list. The -- content is the list of header names. -- @tparam table args.params The parameters (table with name, tilte, format). -- @tparam boolean[opt=true] args.auto_subtags Create the usage and tparams subtags. local add_custom_tag add_custom_tag = function(args) local name = args.name args.name, args[1] = nil, name custom_tags = custom_tags or {} local f = args.format args.format = default_format(args, f) custom_tags[#custom_tags+1] = args named_tags[name] = args -- Auto create @name_tparams and @name_usage for each custom tags. if args.auto_subtags ~= false then add_custom_tag { name = name.."tparam", auto_params = true, parent = args, auto_subtags = false, params = { { name = "type" }, { name = "name" }, } } add_custom_tag { name = name.."usage", auto_usage = true, parent = args, auto_subtags = false, } end end -- When a type will request a permission. -- @emits class signal Message[...] add_custom_tag { name = "emits", title = "Emit signals", hidden = false, params = { { name = "name" } } } -- Avoid repetitive boilerplate code for property signals. -- Add true if the signal has the value or false if it doesn't. -- @propemits true/false true/false description[...] add_custom_tag { name = "propemits", title = "Emit signals:", hidden = false, params = {{name = "new_value"}, {name = "old_value"}}, format = function(self, params, item, md) -- Add an automatic fallback description. local description = params.description ~= "" and params.description or "When the `"..item.name.."` value changes." local new_value = params.new_value.value == "true" local old_value = params.old_value.value == "true" -- Add the sub-tags. local subs = {} item.auto_params["propemitstparam_override"] = subs -- The first argument is always the object which changes. subs[1] = item.module.name.." self ".." The object which changed (".. "useful when connecting many object to the same callback)." -- Most signals also have the new value. if new_value then local type = item.params[1] or "unknown" subs[2] = type.." ".."v The new value." end -- Some also have the old value. if old_value then local type = item.params[1] or "unknown" subs[3] = type.." ".."v The new value." end local new_params = { name = { name = name, value = "property::"..item.name }, description = params.description } return default_format_callback(self, new_params, item, md) end } -- List the beautiful variables used by the method or property fallbacks. -- @usebeautiful beautiful.varname usage[...] add_custom_tag { name = "usebeautiful", title = "Consumed theme variables", hidden = false, table = { "Variable", "Usage" }, params = { { name = "name", markdown = true, } } } -- For all properties which have a standard `@beautiful` variable for them -- @propbeautiful fallback1 fallback2 fallback3 fallback4 add_custom_tag { name = "propbeautiful", title = "Consumed theme variables", params = { { name = "fallback1" }, { name = "fallback2" }, { name = "fallback3" }, { name = "fallback4" }, }, table = { "Variable", "Usage" }, format = function(self, p, item, md) local modname = item.module.name:gmatch("[^.]+$")() local last = "beautiful."..(modname.."_"..item.name):gsub("[.]", "_") local ret = ""..md("`"..last.."`").."Fallback when "..md("`"..item.name.."`").. " isn't set." for _, fallback in ipairs({p.fallback1, p.fallback2, p.fallback3, p.fallback4 }) do ret = ret .. "".. ""..md("`"..fallback.value.."`").."Fallback when "..md("`"..last.."`").. " isn't set." last = fallback.value end return ret end } -- Define the base class where a method/property is implemented. -- @baseclass my_module.my_submodule.my_baseclass add_custom_tag { name = "baseclass", hidden = true } -- More fitting section names kind_names={topic='Documentation', module='Libraries', script='Sample files'} -- Sort modules alphabetically sort_modules=true -- Add more project level (left side index) types. new_type("coreclassmod", "Core_components" , true) new_type("inputmodule" , "Input handling" , true) new_type("widgetmod" , "Widgets" , true) new_type("containermod", "Widget_containers", true) new_type("layoutmod" , "Widget_layouts" , true) new_type("popupmod" , "Popups_and_bars" , true) new_type("utillib" , "Utility_libraries", true) new_type("themelib" , "Theme_related_libraries", true) file = { -- C parts of libraries '../dbus.c', '../luaa.c', '../mouse.c', '../mousegrabber.c', '../root.c', '../selection.c', '../spawn.c', '../xkb.c', '../common/luaobject.c', '../objects/client.c', '../objects/drawable.c', '../objects/screen.c', '../objects/tag.c', '../objects/window.c', -- LUA libraries '../lib/', -- Auto generated scripts '../script_files/', exclude = { -- exclude these modules, as they do not contain any written -- documentation '../lib/awful/autofocus.lua', '../lib/awful/dbus.lua', '../lib/awful/_compat.lua', '../lib/awful/init.lua', '../lib/awful/remote.lua', '../lib/awful/screen/dpi.lua', '../lib/awful/startup_notification.lua', '../lib/awful/mouse/drag_to_tag.lua', '../lib/gears/init.lua', '../lib/wibox/layout/init.lua', '../lib/wibox/container/init.lua', '../lib/naughty/constants.lua', '../lib/naughty/dbus.lua', '../lib/beautiful/gtk.lua', -- Ignore some parts of the widget library '../lib/awful/widget/init.lua', '../lib/naughty/layout/init.lua', '../lib/naughty/widget/init.lua', '../lib/naughty/container/init.lua', '../lib/naughty/list/init.lua', '../lib/naughty/widget/_default.lua', -- Ignore components that provide no value to users and have confusing -- names '../objects/button.c', '../objects/key.c', -- Deprecated classes for one years or more don't deserve entries -- in the index '../lib/awful/widget/graph.lua', '../lib/awful/widget/progressbar.lua', '../lib/awful/widget/textclock.lua', '../lib/awful/wibox.lua', '../lib/wibox/layout/constraint.lua', '../lib/wibox/layout/margin.lua', '../lib/wibox/layout/mirror.lua', '../lib/wibox/layout/rotate.lua', '../lib/wibox/layout/scroll.lua', '../lib/wibox/widget/background.lua', } } -- Wrap the module name for the CSS highlight. local function wrap_modname(str, item) if (not item.module) or str:sub(1, #item.module.name+1) ~= item.module.name.."." then return str end return ""..item.module.name.."." .. str:sub(#item.module.name+2, 9999) end local named_args = { [ "(args)" ] = true, [ "([args])" ] = true, [ "([args=nil])" ] = true, [ "([args={}])" ] = true } -- Sections which are hidden by default, but visible when clicked. local summarize = { emits = {index = 1, title = "Signals" }, propemits = {index = 2, title = "Signals" }, usebeautiful = {index = 3, title = "Theme variables"}, propbeautiful = {index = 4, title = "Theme variables"} } local delimiter_for_tag = { usebeautiful = { "table class='widget_list' border=1", "table", "tr", "tr", {"Theme variable", "Usage"}}, propbeautiful = { "table class='widget_list' border=1", "table", "tr", "tr", {"Theme variable", "Usage"}}, } -- Use the first word of the subtag content to map it to its tag. local function sort_subtags(item, tag, subtag, values) local ret = {} for _, value in ipairs(values) do local parsed = parse_custom_tags(value, {{name = "maps_to"}}) ret[parsed.maps_to.value] = ret[parsed.maps_to.value] or {} ret[parsed.maps_to.value][#ret[parsed.maps_to.value]+1] = parsed.description end return ret end -- Gather a summary of the tags hidden by default . local function generate_summary(item) local tgs = {} for k, v in pairs(summarize) do tgs[v.index] = {title=v.title, count=0} end for tag, value in pairs(item.tags) do if summarize[tag] then tgs[summarize[tag].index].count = tgs[summarize[tag].index].count + 1 end end local ret = {} for k, v in ipairs(tgs) do if v.count > 0 then ret[#ret+1] = v end end item.extra_summary = #ret > 0 and ret or nil end -- We have custom types, sub-types and different rendering. -- -- To avoid added too much business logic in the template, handle this now. -- Note that this works because the name handler is called when doing the table -- of content, which is before any custom types is used. local function init_custom_types(item) if item.is_init then return end generate_summary(item) -- Give each item an unique identifier so the JavaScript can locate them. item.uid, item_id = item_id, item_id + 1 item.delims, item.auto_usage, item.auto_params = {}, {}, {} local to_rm = {} for tag, values in pairs(item.tags) do -- Remove the sub-tags so they don't get rendered as top level ones. if named_tags[tag] and named_tags[tag].auto_usage then item.auto_usage[tag] = sort_subtags( item, named_tags[tag].parent, named_tags[tag], values ) to_rm[#to_rm+1] = tag elseif named_tags[tag] and named_tags[tag].auto_params then item.auto_params[tag] = sort_subtags( item, named_tags[tag].parent, named_tags[tag], values ) to_rm[#to_rm+1] = tag end end -- Remove from the top-level tag list. for _, rm in ipairs(to_rm) do item.tags[rm] = nil end -- Set the item base class. if item.tags["baseclass"] then item.baseclass = item.tags["baseclass"][1] end if not item.baseclass and item.module then item.baseclass = item.module.name end -- Some methods and properties can be inherited from parent classes. -- in those case, they need the explicit `@baseclass` tag. item.inherited = item.baseclass and item.module and item.module.name ~= item.baseclass function item.get_delim(tag) if delimiter_for_tag[tag] then return delimiter_for_tag[tag][1], delimiter_for_tag[tag][2], delimiter_for_tag[tag][3], delimiter_for_tag[tag][4], delimiter_for_tag[tag][5] else return "ul", "ul", "li", "li", nil end end -- Allow the template to fetch the right sub-tags. function item.get_auto_params(tag, value) -- Makes auto-generated subtags easier to implement. if item.auto_params[tag.."tparam_override"] then return item.auto_params[tag.."tparam_override"], named_tags[tag.."tparam"] end if not item.auto_params[tag.."tparam"] then return nil, nil end local parsed = parse_custom_tags(value, named_tags[tag].params) if parsed.name and item.auto_params[tag.."tparam"][parsed.name.value] then return item.auto_params[tag.."tparam"][parsed.name.value], named_tags[tag.."tparam"] end return nil, nil end item.is_init = true end -- Wrap the arguments for the CSS highlight. local function wrap_args(item) if not item.args then return "" end -- Display named args with `{}` and ordered args with `()` if named_args[item.args] then return "{[args]}" end local new_args = item.args:sub(2, item.args:len()-1) return " ("..new_args..")" end -- Mimics the ldoc built-in method style, but better. -- -- This custom renderer exists because using ldoc built-in method detection -- turned out to be too unreliable and upstream is dead. local function render_methods(item) local ret = item.name -- Some methods will have it depending on the weather. Most wont. if not ret:find(":") then ret = ":"..ret end return ret .. " " .. wrap_args(item) end -- Parse the magic parameters to type concention in something the template eats. local function sanitize_type(item, ldoc) for parm in ldoc.modules.iter(item.params) do local t = item:type_of_param(parm) -- Remove the value. t = t:gsub("(\\[[^\\]]])","") t = t:gsub("?","") -- Add " or " between alternatives t = t:gsub("|"," or ") -- Fallback. t = t == "" and parm or t t = t == "" and "N/A" or t item.display_type = ""..t.."" -- There is no value in repeating the type a second time. if item.params.map[parm] == "" then item.hide_params = true end if t ~= "N/A" then return end end -- It has to be set, otherwise the table will have different col count. item.display_type = "N/A" end local no_prefix = { property = true, signal = true, clientruleproperty = true, deprecatedproperty = true, } -- These modules merge the doc of their `awful` siblings. local coreclassmap = { tag = "tag and awful.tag", screen = "screen and awful.screen", client = "client and awful.client", mouse = "mouse and awful.mouse", } -- Add the full module name in front. local add_mod = { ["function"] = true, constructorfct = true, constructorfct2 = true, staticfct = true, deprecated = true, field = true, } -- Add the arguments. local add_args = { constructorfct = true, constructorfct2 = true, staticfct = true, } -- Add a type column to the summary and type field in the description. local display_type = { property = true, beautiful = true, field = true, deprecatedproperty = true, } -- Show return values. local show_return = { ["function"] = true, constructorfct = true, constructorfct2 = true, staticfct = true, method = true, deprecated = true, } custom_display_name_handler = function(item, default_handler) init_custom_types(item) local ret = default_handler(item) -- Edit the input so the template is notified. if display_type[item.type] then -- Punch a hole in the sandbox and inject the `ldoc` object. item.sanitize_type = sanitize_type end -- LDoc hardcode the "Returns" section for "function" only, fix that. if show_return[item.type] and item.tags["return"] then item.ret = item.tags["return"] item:build_return_groups() end -- Remove the "namespace" from the signals and properties if no_prefix[item.type] then local name = item.name:match("%.([^.]+)$") return name ~= "" and name or item.name end -- Handle the left sidebar modules. if item.type == "coreclassmod" and coreclassmap[item.name] then return coreclassmap[item.name] end -- Undocumented API to make the libraries and classmod "function" section -- more consistent. Right now some have their full awful.foo.bar while other -- have "just" `bar`. Given we use constructors from metatables, we have no -- choice but to use the full function name. It also makes copy/paste easier. if add_mod[item.type] then if (not ret:find(".", 1, true)) and (not ret:find(":", 1, true)) then ret = item.module.name .. "." .. ret elseif item.type == "field" and ret:sub(1, #item.module.name) ~= item.module.name then ret = item.module.name .. "." .. ret end end if item.type == "deprecated" or item.type == "deprecatedproperty" then return ret .. " [deprecated]" end if item.type == "method" then ret = render_methods(item) end -- Get rid of the "module:" in front of method names. It is either wrong or -- just redundant. ret = ret:gsub("([^:]*)(:[^:])","%2") -- Undocumented API to get rid of `module.rounded_rect` rather than -- `gears.shape.rounded_rect` if ret:sub(1, 7) == "module." and module then return ret:gsub("^module", item.module.name) end -- It isn't there by default. if add_args[item.type] then ret = ret .. " " .. wrap_args(item) end -- Beautify. ret = wrap_modname(ret, item) return ret end -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80