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',
'09-options.md',
'16-using-cairo.md',
'17-porting-tips.md',
'90-FAQ.md',
'89-NEWS.md',
}
-- 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")
-- Deprecated signals.
new_type("deprecatedsignal", "Deprecated 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 the rules", false, "Type")
-- Extra *matching* properties for rules.
new_type("matchingproperty", "Extra matching properties used in rules", 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.." ".."new_value The new value affected to the property."
end
-- Some also have the old value.
if old_value then
local type = item.params[1] or "unknown"
subs[3] = type.." ".."old_value The property's old value."
end
local new_params = {
name = { name = item.name, value = "property::"..item.name },
description = 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
}
-- Define which interface a method or property implements.
-- @interface container
add_custom_tag {
name = "interface",
hidden = true
}
-- Define when a signal is only emitted on a class rather than on objects.
add_custom_tag {
name = "classsignal",
hidden = true,
}
-- Specify when this an item was deprecated.
-- @deprecatedin 4.4 Optional message.
add_custom_tag {
name = "deprecatedin",
hidden = true,
params = {
{ name = "api_level" },
},
}
-- Specify when this an item was deprecated because it was renamed.
-- @renamedin 4.4 new_name Optional message.
add_custom_tag {
name = "renamedin",
hidden = true,
params = {
{ name = "api_level" },
{ name = "new_name" },
},
}
-- Specify when this an item was deprecated because it was moved.
-- @movedin 4.4 new_class new_name Optional message.
add_custom_tag {
name = "movedin",
hidden = true,
params = {
{ name = "api_level" },
{ name = "new_class" },
{ name = "new_name" },
},
}
-- Specify when an item was added.
-- @introducedin 4.4
add_custom_tag {
name = "introducedin",
hidden = true,
params = {
{ name = "api_level" },
},
}
add_custom_tag {
name = "request",
title = "Requested actions or permissions",
params = {
{ name = "class" },
{ name = "type" },
{ name = "context" },
{ name = "default" },
},
table = {
"Class", "Permission", "Context", "Default", "Description"
},
}
-- 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("ruleslib" , "Declarative_rules", 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/awful/permissions/_common.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',
'../lib/ruled/init.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/awful/ewmh.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 = "signal" , count = true },
propemits = {index = 2, title = "signal" , count = true },
usebeautiful = {index = 3, title = "theme variable" , count = true },
propbeautiful = {index = 4, title = "theme variable" , count = true },
request = {index = 5, title = "permission" , count = true },
classsignal = {index = 6, title = "Class level only", count = false},
}
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"}},
request = { "table class='widget_list' border=1", "table", "tr", "tr", {"Class", "Permission", "Context", "Default", "Description"}},
}
-- 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, showcount=v.count}
end
for tag, value in pairs(item.tags) do
if summarize[tag] then
tgs[summarize[tag].index].count = #value
end
end
local ret, has_show_more = {}, false
for k, v in ipairs(tgs) do
if v.count > 0 then
if v.count > 1 then
v.title = v.title .. "s"
end
ret[#ret+1] = v
has_show_more = v.showcount or has_show_more
end
end
item.extra_summary = #ret > 0 and ret or nil
item.has_show_more = has_show_more
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
-- Replace the "|" in alternative types by "or".
local function pipe_to_or(s)
s = s:gsub("|"," or ")
if s:sub(1,1) == "?" then
s = s:gsub("?","nil or ")
end
return s
end
-- Parse the magic parameters to type 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 = pipe_to_or(t)
-- 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
-- Add parentheses when there is alternative return types.
local function generate_return_tuple(item, group, ldoc)
local tuple = {}
for r in group:iter() do
local type = item:return_type(r);
type = pipe_to_or(type)
if type ~= nil and type ~= "" then
tuple[#tuple+1] = type
end
end
if #tuple == 1 then
return tuple[1]
else
local ret = "("
for i, elem in ldoc.ipairs(tuple) do
ret = ret..elem
if i ~= #tuple then
ret = ret..", "
end
end
ret = ret..")"
return ret
end
end
-- Create a return type string.
local function sanitize_return_type(item, ldoc)
local groups = item.retgroups
item.display_type = ""
if groups then
item.display_type = " -> "
for i,group in ldoc.ipairs(groups) do
item.display_type = item.display_type .. generate_return_tuple(
item,
group,
ldoc
)
if i ~= #groups then
item.display_type = item.display_type .. " or "
end
end
item.display_type = item.display_type .. ""
end
item.compact_signature = true
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,
clientruleproperty = true,
matchingproperty = true,
rulecomponent = true,
}
-- Add the `-> ret_type` annotation.
local display_return_type = {
method = true,
staticfct = true,
}
-- Show return values.
local show_return = {
["function"] = true,
constructorfct = true,
constructorfct2 = true,
staticfct = true,
method = true,
deprecated = true,
}
-- The different type of deprecation.
local is_deprecated = {
deprecated = true,
deprecatedproperty = true,
deprecatedsignal = 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
elseif display_return_type[item.type] then
item.sanitize_type = sanitize_return_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 is_deprecated[item.type] 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