diff --git a/docs/common/object.ldoc b/docs/common/object.ldoc
index df7227630..ed21bedac 100644
--- a/docs/common/object.ldoc
+++ b/docs/common/object.ldoc
@@ -3,6 +3,7 @@
-- @tparam string name The name of the signal.
-- @tparam function func The callback that should be disconnected.
-- @method disconnect_signal
+-- @baseclass gears.object
--- Emit a signal.
--
@@ -11,11 +12,13 @@
-- function receives the object as first argument and then any extra
-- arguments that are given to emit_signal().
-- @method emit_signal
+-- @baseclass gears.object
--- Connect to a signal.
-- @tparam string name The name of the signal.
-- @tparam function func The callback to call when the signal is emitted.
-- @method connect_signal
+-- @baseclass gears.object
--- Connect to a signal weakly.
--
@@ -28,3 +31,4 @@
-- @tparam string name The name of the signal.
-- @tparam function func The callback to call when the signal is emitted.
-- @method weak_connect_signal
+-- @baseclass gears.object
diff --git a/docs/common/wibox.ldoc b/docs/common/wibox.ldoc
index a48b75302..44329ec03 100644
--- a/docs/common/wibox.ldoc
+++ b/docs/common/wibox.ldoc
@@ -4,6 +4,7 @@
--
-- * *property::border_width*
--
+-- @baseclass wibox
-- @property border_width
-- @param integer
@@ -29,6 +30,7 @@
--
-- * *property::border_color*
--
+-- @baseclass wibox
-- @property border_color
-- @param string
@@ -38,6 +40,7 @@
--
-- * *property::ontop*
--
+-- @baseclass wibox
-- @property ontop
-- @param boolean
@@ -47,6 +50,7 @@
--
-- * *property::cursor*
--
+-- @baseclass wibox
-- @property cursor
-- @param string
-- @see mouse
@@ -57,6 +61,7 @@
--
-- * *property::visible*
--
+-- @baseclass wibox
-- @property visible
-- @param boolean
@@ -66,6 +71,7 @@
--
-- * *property::opacity*
--
+-- @baseclass wibox
-- @property opacity
-- @tparam number opacity (between 0 and 1)
@@ -75,6 +81,7 @@
--
-- * *property::type*
--
+-- @baseclass wibox
-- @property type
-- @param string
-- @see client.type
@@ -85,6 +92,7 @@
--
-- * *property::x*
--
+-- @baseclass wibox
-- @property x
-- @param integer
@@ -94,6 +102,7 @@
--
-- * *property::y*
--
+-- @baseclass wibox
-- @property y
-- @param integer
@@ -103,6 +112,7 @@
--
-- * *property::width*
--
+-- @baseclass wibox
-- @property width
-- @param width
@@ -112,11 +122,13 @@
--
-- * *property::height*
--
+-- @baseclass wibox
-- @property height
-- @param height
--- The wibox screen.
--
+-- @baseclass wibox
-- @property screen
-- @param screen
@@ -126,10 +138,12 @@
--
-- * *property::drawable*
--
+-- @baseclass wibox
-- @property drawable
-- @tparam drawable drawable
--- The widget that the `wibox` displays.
+-- @baseclass wibox
-- @property widget
-- @param widget
@@ -139,6 +153,7 @@
--
-- * *property::window*
--
+-- @baseclass wibox
-- @property window
-- @param string
-- @see client.window
@@ -149,6 +164,7 @@
--
-- * *property::shape_bounding*
--
+-- @baseclass wibox
-- @property shape_bounding
-- @param surface._native
@@ -158,6 +174,7 @@
--
-- * *property::shape_clip*
--
+-- @baseclass wibox
-- @property shape_clip
-- @param surface._native
@@ -167,6 +184,7 @@
--
-- * *property::shape_input*
--
+-- @baseclass wibox
-- @property shape_input
-- @param surface._native
@@ -177,6 +195,7 @@
--
-- * *property::shape*
--
+-- @baseclass wibox
-- @property shape
-- @tparam gears.shape shape
@@ -192,35 +211,41 @@
--
-- * *property::input_passthrough*
--
+-- @baseclass wibox
-- @property input_passthrough
-- @param[opt=false] boolean
-- @see shape_input
--- Get or set mouse buttons bindings to a wibox.
--
+-- @baseclass wibox
-- @param buttons_table A table of buttons objects, or nothing.
-- @method buttons
--- Get or set wibox geometry. That's the same as accessing or setting the x,
-- y, width or height properties of a wibox.
--
+-- @baseclass wibox
-- @param A table with coordinates to modify.
-- @return A table with wibox coordinates and geometry.
-- @method geometry
--- Get or set wibox struts.
--
+-- @baseclass wibox
-- @param strut A table with new strut, or nothing
-- @return The wibox strut in a table.
-- @method struts
-- @see client.struts
--- The default background color.
+-- @baseclass wibox
-- @beautiful beautiful.bg_normal
-- @param color
-- @see bg
--- The default foreground (text) color.
+-- @baseclass wibox
-- @beautiful beautiful.fg_normal
-- @param color
-- @see fg
@@ -228,9 +253,11 @@
--- Set a declarative widget hierarchy description.
-- See [The declarative layout system](../documentation/03-declarative-layout.md.html)
-- @param args An array containing the widgets disposition
+-- @baseclass wibox
-- @method setup
--- The background of the wibox.
+-- @baseclass wibox
-- @param c The background to use. This must either be a cairo pattern object,
-- nil or a string that gears.color() understands.
-- @property bg
@@ -241,12 +268,14 @@
-- If `image` is a function, it will be called with `(context, cr, width, height)`
-- as arguments. Any other arguments passed to this method will be appended.
-- @param image A background image or a function
+-- @baseclass wibox
-- @property bgimage
-- @see gears.surface
--- The foreground (text) of the wibox.
-- @param c The foreground to use. This must either be a cairo pattern object,
-- nil or a string that gears.color() understands.
+-- @baseclass wibox
-- @property fg
-- @param color
-- @see gears.color
@@ -258,4 +287,5 @@
-- @treturn table A sorted table of widgets positions. The first element is the biggest
-- container while the last is the topmost widget. The table contains *x*, *y*,
-- *width*, *height* and *widget*.
+-- @baseclass wibox
-- @method find_widgets
diff --git a/docs/common/widget.ldoc b/docs/common/widget.ldoc
index d2483aff3..b2a3b0eee 100644
--- a/docs/common/widget.ldoc
+++ b/docs/common/widget.ldoc
@@ -7,10 +7,12 @@
-- @return The parent layout
-- @return The path between self and widget
-- @method index
+-- @baseclass wibox.widget
--- Get or set the children elements.
-- @property children
-- @tparam table children The children.
+-- @baseclass wibox.widget
--- Get all direct and indirect children widgets.
-- This will scan all containers recursively to find widgets
@@ -18,27 +20,33 @@
-- children, contain (directly or indirectly) itself.
-- @property all_children
-- @tparam table children The children.
+-- @baseclass wibox.widget
--- Set a declarative widget hierarchy description.
-- See [The declarative layout system](../documentation/03-declarative-layout.md.html)
-- @param args An array containing the widgets disposition
-- @method setup
+-- @baseclass wibox.widget
--- Force a widget height.
-- @property forced_height
-- @tparam number|nil height The height (`nil` for automatic)
+-- @baseclass wibox.widget
--- Force a widget width.
-- @property forced_width
-- @tparam number|nil width The width (`nil` for automatic)
+-- @baseclass wibox.widget
--- The widget opacity (transparency).
-- @property opacity
-- @tparam[opt=1] number opacity The opacity (between 0 and 1)
+-- @baseclass wibox.widget
--- The widget visibility.
-- @property visible
-- @param boolean
+-- @baseclass wibox.widget
--- The widget buttons.
--
@@ -47,10 +55,12 @@
-- @property buttons
-- @param table
-- @see awful.button
+-- @baseclass wibox.widget
--- Add a new `awful.button` to this widget.
-- @tparam awful.button button The button to add.
-- @function add_button
+-- @baseclass wibox.widget
--- Emit a signal and ensure all parent widgets in the hierarchies also
-- forward the signal. This is useful to track signals when there is a dynamic
@@ -58,6 +68,7 @@
-- @tparam string signal_name
-- @param ... Other arguments
-- @method emit_signal_recursive
+-- @baseclass wibox.widget
--- When the layout (size) change.
-- This signal is emitted when the previous results of `:layout()` and `:fit()`
@@ -65,6 +76,7 @@
-- must return the same result when called with the same arguments.
-- @signal widget::layout_changed
-- @see widget::redraw_needed
+-- @baseclass wibox.widget
--- When the widget content changed.
-- This signal is emitted when the content of the widget changes. The widget will
@@ -72,6 +84,7 @@
-- `:layout()` and `:fit()` would still return the same results as before.
-- @signal widget::redraw_needed
-- @see widget::layout_changed
+-- @baseclass wibox.widget
--- When a mouse button is pressed over the widget.
-- @signal button::press
@@ -101,6 +114,7 @@
-- @tparam number find_widgets_result.widget_height The exact height of the widget
-- in its local coordinate system.
-- @see mouse
+-- @baseclass wibox.widget
--- When a mouse button is released over the widget.
-- @signal button::release
@@ -130,6 +144,7 @@
-- @tparam number find_widgets_result.widget_height The exact height of the widget
-- in its local coordinate system.
-- @see mouse
+-- @baseclass wibox.widget
--- When the mouse enter a widget.
-- @signal mouse::enter
@@ -153,6 +168,7 @@
-- @tparam number find_widgets_result.widget_height The exact height of the widget
-- in its local coordinate system.
-- @see mouse
+-- @baseclass wibox.widget
--- When the mouse leave a widget.
-- @signal mouse::leave
@@ -176,3 +192,4 @@
-- @tparam number find_widgets_result.widget_height The exact height of the widget
-- in its local coordinate system.
-- @see mouse
+-- @baseclass wibox.widget
diff --git a/docs/config.ld b/docs/config.ld
index 76508b46e..2920a6828 100644
--- a/docs/config.ld
+++ b/docs/config.ld
@@ -93,6 +93,257 @@ 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'}
@@ -191,6 +442,141 @@ local named_args = {
[ "([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
@@ -300,6 +686,8 @@ local show_return = {
}
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.
diff --git a/docs/ldoc.css b/docs/ldoc.css
index 3e3956415..04aa7ae88 100644
--- a/docs/ldoc.css
+++ b/docs/ldoc.css
@@ -288,6 +288,7 @@ table.module_list td.summary, table.function_list td.summary {
background-color: white;
width: 100%;
border-left-width: 0px;
+ border-right: none;
}
table.function_list td.shortname {
@@ -334,6 +335,19 @@ table.function_list .function_named_args {
text-decoration-color: #bbd3ff;
}
+table.function_list td.baseclass {
+ background-color: white;
+ color: #a4c7ff;
+ min-width: 200px;
+ border-left: none;
+ border-right: none;
+ text-align: right;
+}
+
+.baseclass {
+ font-size: 85%;
+}
+
dl.function {
margin-right: 15px;
margin-left: 15px;
@@ -429,3 +443,11 @@ pre .url { color: #272fc2; text-decoration: underline; }
background-repeat:no-repeat;
color:transparent;
}
+
+/* Hide some extra documentation noise by default */
+.hide_extra {
+ display: none
+}
+.show_more {
+ display: default
+}
diff --git a/docs/ldoc.ltp b/docs/ldoc.ltp
index eebb6b436..ea1b4a7e4 100644
--- a/docs/ldoc.ltp
+++ b/docs/ldoc.ltp
@@ -9,6 +9,17 @@
# if ldoc.custom_css then -- add custom CSS file if configured.
# end
+
+
@@ -151,6 +162,11 @@
+# if item.inherited then
+ Inherited from $(item.baseclass)
+# end
+
# end -- for items
# last_kind = kind
@@ -197,6 +213,9 @@
# if item.display_type then
($(item.display_type))
# end
+# if item.inherited then
+ · Inherited from $(item.baseclass)
+# end
# if ldoc.prettify_files and ldoc.is_file_prettified[item.module.file.filename] then
line $(item.lineno)
# end
@@ -204,21 +223,6 @@
$(M(ldoc.descript(item),item))
-# if ldoc.custom_tags then
-# for custom in iter(ldoc.custom_tags) do
-# local tag = item.tags[custom[1]]
-# if tag and not custom.hidden then
-# local li,il = use_li(tag)
-
$(custom.title or custom[1]):
-
-# for value in iter(tag) do
- $(li)$(custom.format and custom.format(value) or M(value))$(il)
-# end -- for
-# end -- if tag
-
-# end -- iter tags
-# end
-
# if show_parms and item.params and #item.params > 0 and not item.hide_params then
# local subnames = module.kinds:type_of(item).subnames
# if subnames then
@@ -307,6 +311,43 @@
# end -- if usage
+
+
+ Click to display more
+
+
+
+# if ldoc.custom_tags then
+# for custom in iter(ldoc.custom_tags) do
+# local tag = item.tags[custom[1]]
+# if tag and not custom.hidden then
+# local group_begin, group_end, row_type_begin, row_type_end, group_header = item.get_delim(custom[1])
+
$(custom.title or custom[1]):
+ <$(group_begin)>
+# if group_header then
+
+# for _, g in ldoc.ipairs(group_header) do
+
$(g)
+# end -- for g
+
+# end -- if group_header then
+# for value in iter(tag) do
+ <$(row_type_begin)>$(custom.format and custom.format(value, item, M) or M(value))$(row_type_end)>
+# local sub_values, sub_custom = item.get_auto_params(custom[1], value)
+# if sub_values then
+
+# for _, value in ldoc.ipairs(sub_values) do
+
$(sub_custom.format(value, item, M))
+# end -- for auto_params
+
+# end -- if item.auto_params
+# end -- for
+ $(group_end)>
+# end -- if tag
+# end -- iter tags
+# end -- ldoc.custom_tags
+
+