Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Main page
Recent changes
Special pages
Random page
Wiki Discord
Contents
Neighbors
Galaxy
> Hexia
> Norvan
> Pashah
> Taffeh
Creatures
> Insects
> Fishes
> Shore-Dwellers
Items
> Dishes
> Furniture
Game Systems
> Dress Up
> Luca Arbor
> Loomix Footprints
> Loomix Vehicle Services
> Loomix Homes
Search
Search
Appearance
Log in
Personal tools
Log in
Editing
Module
:
Docbunto
Module
Discussion
English
Read
Edit source
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit source
View history
General
What links here
Related changes
Page information
Appearance
move to sidebar
hide
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
--- Docbunto, based on [[w:c:dev:Global_Lua_Modules/Docbunto|the version on the dev wiki]]. -- -- Compared to the version on the dev wiki, this version: -- * changes documentation output format to always produce valid HTML and allow CSS styling -- * adds support for object types that link to other modules -- * adds better support for block documentation comments -- * fixes a few bugs -- -- (Note: @export seems buggy in the version on the dev wiki, and may not be -- completely fixed in this version either.) -- -- Documentation from the dev wiki: -- -- Docbunto is an automatic documentation generator for Scribunto modules. -- The module is based on LuaDoc and LDoc. It produces documentation in -- the form of MediaWiki markup, using `@tag`-prefixed comments embedded -- in the source code of a Scribunto module. The taglet parser & doclet -- renderer Docbunto uses are also publicly exposed to other modules. -- -- Docbunto code items are introduced by a block comment (`--[[]]--`), an -- inline comment with three hyphens (`---`), or an inline `@tag` comment. -- The module can use static code analysis to infer variable names, item -- privacy (`local` keyword), tables (`{}` constructor) and functions -- (`function` keyword). MediaWiki and Markdown formatting is supported. -- -- Items are usually rendered in the order they are defined, if they are -- public items, or emulated classes extending the Lua primitives. There -- are many customisation options available to change Docbunto behaviour. -- -- @module docbunto -- @alias p -- @require Module:I18n -- @require Module:Lexer -- @require Module:T -- @require Module:Unindent -- @require Module:Yesno -- @image Docbunto.svg -- @author [[User:8nml|8nml]] -- @attribution [[github:stevedonovan|@stevedonovan]] ([[github:stevedonovan/LDoc|Github]]) -- @release stable -- <nowiki> local p = {} local lib = require('Module:Feature') -- CSS classes local VISIBILITYLEVEL_CLASS = 'docbunto-visibilitylevel' local ITEM_CLASS = 'docbunto-item' local SECTION_CLASS = 'docbunto-section' local ITEM_HEADER_CLASS = 'docbunto-item-header' local ITEM_BODY_CLASS = 'docbunto-item-body' local TAGGROUP_CLASS = 'docbunto-taggroup' local TAGGROUP_HEADER_CLASS = 'docbunto-taggroup-header' local TAGGROUP_TAG_CLASS = 'docbunto-taggroup-tag' local TAG_KEYS_CLASS = 'docbunto-tag-keys' local NEEDS_NEWLINE = '^[{|!};:#*=]' -- tables, dl, ul, ol, headings local function append_description(description, new_line) new_line = lib.trim(new_line) local separator if #description == 0 then separator = '' elseif #new_line == 0 or description:find('\n$') or new_line:find(NEEDS_NEWLINE) then separator = '\n' else separator = ' ' end return description .. separator .. new_line end -- code from the dev wiki: -- (revision: https://dev.fandom.com/wiki/Module:Docbunto?oldid=193112) -- Module dependencies. local title = mw.title.getCurrentTitle() local i18n = require('Module:I18n').loadMessages('Module:Docbunto/i18n') local references = mw.loadData('Module:Docbunto/references') local lexer = require('Module:Lexer') local unindent = require('Module:Unindent') local yesno = require('Module:Yesno') -- Module variables. local DEFAULT_TITLE = title.text:gsub('/doc$', '') local frame, gsub, match -- Docbunto variables & tag tokens. local TAG_MULTI = 'M' local TAG_ID = 'ID' local TAG_SINGLE = 'S' local TAG_TYPE = 'T' local TAG_FLAG = 'N' local TAG_MULTI_LINE = 'ML' local TAG_NAMED_MULTI = 'NM' -- Docbunto processing patterns. local DOCBUNTO_SUMMARY, DOCBUNTO_TYPE local DOCBUNTO_TAG, DOCBUNTO_TAG_VALUE, DOCBUNTO_TAG_MOD_VALUE -- Docbunto private logic. --- @{string.find} optimisation for @{string} functions. -- Resets patterns for each documentation build. -- @function strfind_wrap -- @param {function} strfunc String library function. -- @return {function} Function wrapped in @{string.find} check. -- @local function strfind_wrap(func) return function(...) local arg = {...} if string.find(arg[1], arg[2]) then return func(...); end end end local function isNotEmpty(tbl) return tbl[1] ~= nil end local function count(str, item) local output = 0 local _, pos = str:find(item, pos, true) while pos do output = output + 1 _, pos = str:find(item, pos + 1, true) end return output end --- Pattern configuration function. -- Resets patterns for each documentation build. -- @function configure_patterns -- @param {table} options Configuration options. -- @param {boolean} options.colon Colon mode. -- @local local function configure_patterns(options) -- Setup Unicode or ASCII character encoding (optimisation). gsub = strfind_wrap( options.unicode and mw.ustring.gsub or string.gsub ) match = strfind_wrap( options.unicode and mw.ustring.match or string.match ) DOCBUNTO_SUMMARY = options.iso639_th and '^[^ ]+' or options.unicode and '^[^.։。।෴۔።]+[.։。।෴۔።]?' or '^[^.]+%.?' -- Set up parsing tag patterns with colon mode support. DOCBUNTO_TAG = options.colon and '^%s*(%w+):' or '^%s*@(%w+)' DOCBUNTO_TAG_VALUE = DOCBUNTO_TAG .. '(.*)' DOCBUNTO_TAG_MOD_VALUE = DOCBUNTO_TAG .. '(%b[])(.*)' DOCBUNTO_TYPE = '^{({*[^}]+}*)}%s*' end --- Markdown header converter. -- @function markdown_header -- @param {string} hash Leading hash. -- @param {string} text Header text. -- @return {string} MediaWiki header. -- @local local function markdown_header(hash, text) local symbol = '=' return '\n' .. symbol:rep(#hash) .. ' ' .. text .. ' ' .. symbol:rep(#hash) .. '\n' end --- Item reference formatting. -- @function item_reference -- @param {string} ref Item reference. -- @return {string} Internal MediaWiki link to article item. -- @local local function item_reference(ref) local temp = lib.split(ref, '|') local item = temp[1] local text = temp[2] or temp[1] if references.items[item] then item = references.items[item] elseif item:find('#', 1, true) then item = mw.site.namespaces[828].name .. ':' .. item else item = '#' .. item end return '<code>' .. '[[' .. item .. '|' .. text .. ']]' .. '</code>' end --- Markdown preprocessor to MediaWiki format. -- @function markdown -- @param[opt] {string} str Unprocessed Markdown string. -- @return[opt] {string} MediaWiki-compatible markup with HTML formatting (or nil if `str` is nil). -- @local local function markdown(str) if not str then return nil end if type(str) ~= "string" then str = tostring(str) end -- Bold & italic tags. str = str:gsub('%*%*%*([^\n*]+)%*%*%*', '<b><i>%1<i></b>') str = str:gsub('%*%*([^\n*]+)%*%*', '<b>%1</b>') str = str:gsub('%*([^\n*]+)%*', '<i>%1</i>') -- Self-closing header support. str = str:gsub('%f[^\n%z](#+) *([^\n#]+) *#+%s', markdown_header) -- External and internal links. str = str:gsub('%[([^\n%]]+)%]%(([^\n][^\n)]-)%)', '[%2 %1]') str = str:gsub('%@{([^\n}]+)}', item_reference) -- Programming & scientific notation. --'<code><nowiki>%1</nowiki></code>' str = str:gsub('%f["`]`([^\n`]+)`%f[^"`]', function(m) return '<code>' .. mw.text.nowiki(m) .. '</code>' end) -- '<chem>%1</chem>' str = str:gsub('%$%$\\ce{([^\n}]+)}%$%$', function(m) return frame:extensionTag('chem', m) end) -- '<math display="inline">%1</math>' str = str:gsub('%$%$([^\n$]+)%$%$', function(m) return frame:extensionTag('math', m, {display='inline'}) end) -- Strikethroughs and superscripts. -- (These must be processed after math/chem/code syntax.) str = str:gsub('~~([^\n~]+)~~', '<del>%1</del>') str = str:gsub('%^%(([^)]+)%)', '<sup>%1</sup>') str = str:gsub('%^%s*([^%s%p]+)', '<sup>%1</sup>') return str end local maybe_md --- Enables/disables markdown processing for each documentation build. -- @param {table} options Configuration options. -- @local function configure_markdown(options) maybe_md = options.plain and (function(str) return str and tostring(str) or nil end) or markdown end --- Tag processor function. -- @function process_tag -- @param {string} str Tag string to process. -- @param[opt] {number} line_no The source line number that defines the tag. -- @return {table} Tag object. -- @local local function process_tag(str, line_no) local tag = { lineno=line_no, height=count(str, '\n') + 1 } if str:find(DOCBUNTO_TAG_MOD_VALUE) then tag.category, tag.modifiers, tag.value = str:match(DOCBUNTO_TAG_MOD_VALUE) local modifiers = {} -- remove [] from tag.modifiers before splitting for mod in lib.gsplit(tag.modifiers:sub(2, -2), ',') do local key, val = mod:match('^(.-)%s*=%s*(.*)$') if key then modifiers[key] = val else modifiers[mod] = true end end if modifiers.optchain then modifiers.opt = modifiers.opt or true modifiers.optchain = nil end tag.modifiers = modifiers else tag.category, tag.value = str:match(DOCBUNTO_TAG_VALUE) tag.modifiers = {} end tag.value = lib.trim(tag.value) if p.tags._type_alias[tag.category] then if p.tags._type_alias[tag.category] ~= 'variable' then tag.value = p.tags._type_alias[tag.category] .. ' ' .. tag.value tag.category = 'field' end if tag.value:match('^%S+') ~= '...' then tag.value = tag.value:gsub('^(%S+)', '{%1}') end end tag.category = p.tags._alias[tag.category] or tag.category if tag.category ~= 'usage' and tag.value:find(DOCBUNTO_TYPE) then tag.type = tag.value:match(DOCBUNTO_TYPE) if tag.type:find('^%?') then tag.type = tag.type:sub(2) .. '|nil' end tag.value = tag.value:gsub(DOCBUNTO_TYPE, '') end if p.tags[tag.category] == TAG_FLAG then tag.value = true end return tag end --- Module info extraction utility. -- @function extract_info -- @param {table} documentation Package doclet info. -- @return {table} Information name-value map. -- @local local function extract_info(documentation) local info = {} for _, tag in ipairs(documentation.tags) do if p.tags._module_info[tag.category] then if info[tag.category] then if not info[tag.category]:find('^%* ') then info[tag.category] = '* ' .. info[tag.category] end info[tag.category] = info[tag.category] .. '\n* ' .. tag.value else info[tag.category] = tag.value end end end return info end --- Type extraction utility. -- @function extract_type -- @param {table} item Item documentation data. -- @return {string} Item type. -- @local local function extract_type(item) local item_cat, item_type for _, tag in ipairs(item.tags) do if p.tags[tag.category] == TAG_TYPE then item_cat = tag.category item_type = tag.type break end end return item_cat, item_type end --- Name extraction utility. -- @function extract_name -- @param {table} item Item documentation data. -- @param[opt] {string} project_code String containing full project source code. -- If specified, assumes that `item` is the project and checks -- its return value when looking for a name. -- @return {string} Item name. -- @local local function extract_name(item, project_code) opts = opts or {} local item_name for _, tag in ipairs(item.tags) do if p.tags[tag.category] == TAG_TYPE then item_name = tag.value; break; end end if item_name or not project_code then return item_name end item_name = project_code:match('\nreturn%s+([%w_]+)') -- TODO why alias as p? if item_name == 'p' and not item.tags['alias'] then local implied_alias = { name = 'alias', value = 'p' } item.tags['alias'] = {implied_alias} table.insert(item.tags, implied_alias) end item_name = (item_name and item_name ~= 'p') and item_name or item.filename :gsub('^' .. mw.site.namespaces[828].name .. ':', '') :gsub('^(%u)', mw.ustring.lower) :gsub('/', '.'):gsub(' ', '_') return item_name end --- Source code utility for item name detection. -- @function deduce_name -- @param {string} tokens Stream tokens for first line. -- @param {string} index Stream token index. -- @param {table} opts Configuration options. -- @param[opt] {boolean} opts.lookahead Whether a variable name succeeds the index. -- @param[opt] {boolean} opts.lookbehind Whether a variable name precedes the index. -- @return {string} Item name. -- @local local function deduce_name(tokens, index, opts) -- TODO this should be two different functions local name = '' if opts.lookbehind then for i2 = index, 1, -1 do if tokens[i2].type ~= 'keyword' then name = tokens[i2].data .. name else break end end elseif opts.lookahead then for i2 = index, #tokens do if tokens[i2].type ~= 'keyword' and not tokens[i2].data:find('^%(') then name = name .. tokens[i2].data else break end end end return name end --- Code analysis utility. -- @function code_static_analysis -- @param {table} item Item documentation data. -- @local local function code_static_analysis(item) if not item.head then return end local tokens = item.head item.head = nil -- remove token data so that logging documentation to console is shorter local t, i = tokens[1], 1 local item_name, item_cat local is_local = false while t do -- TODO this seems unnecessary? just handle it in deduce_name if t.type == 'whitespace' then table.remove(tokens, i) -- skips an index, which is fine since there shouldn't be consecutive whitespace tokens end t, i = tokens[i + 1], i + 1 end t, i = tokens[1], 1 while t do if t.data == '=' then item_name = deduce_name(tokens, i - 1, { lookbehind = true }) end if t.data == 'function' then item_cat = 'function' if not tokens[i + 1].data:find('^%(') then item_name = deduce_name(tokens, i + 1, { lookahead = true }) end break end if t.data:find('^{') then item_cat = 'table' break end if t.data == 'local' then is_local = true end t, i = tokens[i + 1], i + 1 end item.name = item.name or item_name or '' item.category = item.category or item_cat if item_name or item_cat then item.has_source = true end item.implied_local = is_local end local function postprocess_tag(tag) if p.tags[tag.category] == TAG_NAMED_MULTI then tag.name = tag.value:match('^%S+') if tag.name then tag.value = tag.value:sub(#tag.name + 1) else tag.name = '?' end end if type(tag.modifiers.name) == 'string' then tag.name = tag.modifiers.name end -- trim tag value (except flag tags) if type(tag.value) == "string" then tag.value = lib.trim(tag.value) end return tag end --- Partitions tags into sub-lists based on category and runs post-processing -- on tag values. -- @function postprocess_tags -- @param {table} item Item documentation data array. -- @local local function postprocess_tags(tags) for _, element in ipairs(tags) do if not tags[element.category] then tags[element.category] = {} end table.insert(tags[element.category], postprocess_tag(element)) end end --- Item export utility. -- @function export_item -- @param {table} documentation Package documentation data. -- @param {string} item_reference Identifier name for item. -- @param {string} item_index Identifier name for item. -- @param {string} item_alias Export alias for item. -- @param {boolean} factory_item Whether the documentation item is a factory function. -- @local local function export_item(documentation, item_reference, item_index, item_alias, factory_item) -- TODO what if exported multiple times? documentation.explicitly_exported[item_reference] = { parent_index = factory_item and item_index or 0, alias = item_alias } end --- Subitem tag correction utility. -- @function correct_subitem_tag -- @param {table} item Item documentation data. -- @local local function correct_subitem_tag(item) local field_tags = item.tags['field'] if item.category ~= 'function' or not field_tags then return end item.tags['param'] = item.tags['param'] or {} local param_tags = item.tags['param'] for _, tag_el in ipairs(field_tags) do tag_el.category = 'param' table.insert(param_tags, tag_el) end item.tags['field'] = nil end --- Item override tag utility. -- @function override_item_tag -- @param {table} item Item documentation data. -- @param {string} name Tag name. -- @param[opt] {string} target Target property name for tag. -- @local local function override_item_tag(item, name, target) if item.tags[name] then item[target or name] = item.tags[name][1].value end end --- Doclet type reference preprocessor. -- Formats types with links to the [[w:c:dev:Lua reference manual|Lua reference manual]] or wiki pages. -- @function preop_type -- @param {table} item Item documentation data. -- @param {table} options Configuration options. -- @local local function type_reference(item, options) if not options.noluaref and item.name == '...' then item.name = '[[' .. 'Lua reference manual#varargs|...]]' end if not item.type then return end item.type = item.type:gsub(' ', '\26') local spaces = '%s\26' local separators = '[;|]' -- TODO should this allow other punctuation? e.g. commas, parens, brackets local types = mw.text.split(item.type, separators) for i, type in ipairs(types) do local t = lib.trim(type, spaces) local data = references.types[t] local name = data and data.name or t if not name:match('%.') and not name:match('^%u') and data then name = i18n:msg('type-' .. name) end if data then if not options.noluaref then types[i] = '[[' .. data.link .. '|' .. name .. ']]' end else local link = t if t:find('#', 1, true) then link = mw.site.namespaces[828].name .. ':' .. link else link = '#' .. link end types[i] = '<code>[[' .. link .. '|' .. name .. ']]</code>' end end item.type = mw.text.listToText(types, i18n:msg('separator-comma'), #types > 2 and i18n:msg('separator-comma-or') or i18n:msg('separator-or')) item.type = item.type:gsub('\26', ' ') end local function isInstanceFunction(item) if item.category ~= 'function' then return false end return not item.tags['static'] end --- Doclet item renderer. -- @function render_item -- @param {table} stream Wikitext documentation stream. -- @param {table} item Item documentation data. -- @param {table} options Configuration options. -- @param[opt] {function} preop Item data preprocessor. -- @return {table} A stream to append children to. -- @local local function render_item(stream, item, options, preop) local item_id = item.alias or item.name or '?' if preop then preop(item, options) end local item_name = item.alias or item.name or '?' type_reference(item, options) local types = {i18n:msg('itemcategory-' .. item.category)} for _, name in ipairs(p.tags._subtype_hierarchy) do if item.tags[name] then table.insert(types, i18n:msg('itemsubcategory-' .. name)) end end table.insert(types, item.type) local item_cat = i18n:msg('parentheses', table.concat(types, i18n:msg('separator-dot'))) if options.strip and item.export and item.hierarchy then item_name = item_name:gsub('^[%w_]+[.[]?', '') end local source_link = item.has_source and i18n:msg('parentheses', '[[' .. options.filepath .. '#L-' .. item.lineno .. '|' .. i18n:msg('link-source') .. ']]') or '' local dl = stream:tag('dl'):addClass(ITEM_CLASS) dl:tag('dt') :addClass(ITEM_HEADER_CLASS) :wikitext('<code id="', item_id, '">', item_name, '</code>', item_cat, item_typ, source_link) local dd = dl:tag('dd'):addClass(ITEM_BODY_CLASS):tag('div'):newline() if #item.description ~= 0 then dd:wikitext(maybe_md(item.description)):newline() end stream:newline() return dd end --- Doclet tag renderer. -- @function render_tag -- @param {table} stream Wikitext documentation stream. -- @param {string} name Item tag name. -- @param {table} tag Item tag data. -- @param {table} options Configuration options. -- @param[opt] {function} preop Item data preprocessor. -- @local local function render_tag(stream, name, tag, options, preop) if preop then preop(tag, options) end local tag_name = i18n:msg('tag-' .. name, tostring(#tag)) local dl = stream:tag('dl'):addClass(TAGGROUP_CLASS) dl:tag('dt') :addClass(TAGGROUP_HEADER_CLASS) :wikitext('<b>', tag_name, '</b>', i18n:msg('separator-semicolon')) local nesting = {dl} for _, tag_el in ipairs(tag) do local nesting_level = tag_el.name and ( tag_el.name == '...' and 1 or (select(2, tag_el.name:gsub('[.[]', '')) + 1) ) or 1 -- handle skipped nesting levels while nesting_level > #nesting do -- create elements to nest in local parent = nesting[#nesting] local newParent = parent:tag('dl'):addClass(TAG_KEYS_CLASS) newParent:tag('dt'):wikitext(i18n:msg('label-keys')) table.insert(nesting, newParent) end -- handle end of nesting local first_in_level = nesting_level > 1 -- never first in level on level 1, since the tag type dt already exists while nesting_level < #nesting do table.remove(nesting) first_in_level = false end local parent = nesting[#nesting] -- create new dl if needed if first_in_level then parent = parent:tag('dl'):addClass(TAG_KEYS_CLASS) parent:tag('dt'):wikitext('Keys:') nesting[#nesting] = parent end local dd = parent:tag('dd'):addClass(TAGGROUP_TAG_CLASS):tag('div'):newline() table.insert(nesting, dd) type_reference(tag_el, options) local extra_data = {} if tag_el.type then table.insert(extra_data, tag_el.type) end if tag_el.modifiers.opt then table.insert(extra_data, i18n:msg('optional')) end if tag_el.source then table.insert(extra_data, i18n:msg('line-number', tag_el.source)) end if isNotEmpty(extra_data) then dd:wikitext(i18n:msg('parentheses', table.concat(extra_data, i18n:msg('separator-colon')))) end dd:newline() if tag_el.name then dd:wikitext('<code>', tag_el.name, '</code>') if #tag_el.value ~= 0 then dd:wikitext(' ') end end dd:wikitext(maybe_md(tag_el.value)):newline() end end --- Doclet function preprocessor. -- Formats item name as a function call with top-level arguments. -- @function preop_function_name -- @param {table} item Item documentation data. -- @param {table} options Configuration options. -- @local local function preop_function_name(item, options) local target = item.alias and 'alias' or 'name' item[target] = item[target] .. '(' if item.tags['param'] then for index, tag in ipairs(item.tags['param']) do if not tag.name:find('[.[]') then item[target] = item[target] .. (index > 1 and ', ' or '') if tag.modifiers.opt then item[target] = item[target] .. '<span style="opacity: 0.65;">[' end item[target] = item[target] .. tag.name if tag.modifiers.opt then item[target] = item[target] .. ']</span>' end end end end item[target] = item[target] .. ')' end --- Doclet usage subitem preprocessor. -- Formats usage example with `<syntaxhighlight>` tag. -- @function preop_usage_highlight -- @param {table} item Item documentation data. -- @param {table} options Configuration options. -- @local local function preop_usage_highlight(items, options) for _, item in ipairs(items) do item.value = unindent(lib.trim(item.value)) local multi_line = item.value:find('\n') local wikitext = item.value:find('^{{.+}}$') item.value = frame:extensionTag('syntaxhighlight', item.value, { lang=(wikitext and 'text' or 'lua'), inline=(multi_line and nil or 1), }) end end --- Doclet error subitem preprocessor. -- Formats line numbers (`{#}`) in error tag values. -- @function preop_error_line -- @param {table} item Item documentation data. local function preop_error_line(items, options) for _, item in ipairs(items) do local line = item.modifiers.line or item.lineno + item.height if line ~= '' then item.source = line end end end -- Docbunto package items. --- Template entrypoint for [[Template:Docbunto]]. -- @function p.main -- @param {table} f Scribunto frame object. -- @return {string} Module documentation output. function p.main(f) local args = require('Module:Arguments').getArgs(f) return p.build(args) end --- Scribunto documentation generator entrypoint. -- @function p.build -- @param[opt] {table} options Configuration options. -- @param[opt] {string} options.file Module page name (without namespace). -- Default: second-level subpage. -- @param[opt] {string} options.content An parameter used for debugging -- this module. Pass in a string containing source code -- to view the documentation it would generate. -- @param[opt] {boolean} options.all Include local items in -- documentation. -- @param[opt] {boolean} options.boilerplate Removal of -- boilerplate (license block comments). -- @param[opt] {string} options.caption Infobox image caption. -- @param[opt] {boolean} options.code Only document Docbunto code -- items - exclude article infobox and lede from -- rendered documentation. Permits article to be -- edited in VisualEditor. -- @param[opt] {boolean} options.colon Format tags with a `:` suffix -- and without the `@` prefix. This bypasses the "doctag -- soup" some authors complain of. -- @param[opt] {string} options.image Infobox image. -- @param[opt] {boolean} options.noluaref Don't link to the -- [[w:c:dev:Lua reference manual|Lua reference manual]] -- for types. -- @param[opt] {boolean} options.plain Disable Markdown formatting -- in documentation. -- @param[opt] {string} options.preface Preface text to insert -- between lede & item documentation, used to provide -- usage and code examples. -- @param[opt] {boolean} options.simple Limit documentation to -- descriptions only. Removes documentation of -- subitem tags such as `@param` and `@field` ([[#Item -- subtags|see list]]). -- @param[opt] {boolean} options.strip Remove table index in -- documentation. function p.build(args) local options = {} options.file = args.file or args[1] or DEFAULT_TITLE options.content = args.content options.all = yesno(args.all, false) options.boilerplate = yesno(args.boilerplate, false) options.caption = args.caption options.code = yesno(args.code, false) options.colon = yesno(args.colon, false) options.image = args.image options.noluaref = yesno(args.noluaref, false) options.plain = yesno(args.plain, false) options.preface = args.preface options.simple = yesno(args.simple, false) options.strip = yesno(args.strip, false) local tagdata = p.taglet(options) local docdata = p.doclet(tagdata, options) return docdata end --- Docbunto taglet parser for Scribunto modules. -- @function p.taglet -- @param[opt] {table} options Configuration options. -- @return {table} Module documentation data. function p.taglet(options) options = options or {} options.file = options.file or DEFAULT_TITLE options.filepath = options.filepath or (mw.site.namespaces[828].name .. ':' .. options.file) local filepath = options.filepath local content if options.content then -- unstrip nowiki for js preview content = lib.unstripNoWiki(options.content) else content = mw.title.new(filepath):getContent() end -- Content checks. if not content then -- @error {string} 'Lua source code not found in $1' error(i18n:msg('no-content', filepath)) end if not content:match('%-%-%-') and not content:match(options.colon and '%s+%w+:' or '%s+@%w+') then -- @error {string} 'documentation markup for Docbunto not found in $1' error(i18n:msg('no-markup', filepath)) end -- Remove leading escapes. content = content:gsub('^%-%-+%s*<[^>]+>\n', '') -- Remove closing pretty comments. content = content:gsub('\n%-%-%-%-%-+(\n[^-]+)', '\n-- %1') -- Remove boilerplate block comments. if options.boilerplate then content = content:gsub('^%-%-%[=*%[\n.-\n%-?%-?%]%=*]%-?%-?%s+', '') content = content:gsub('%s+%-%-%[=*%[\n.-\n%-?%-?%]%=*]%-?%-?$', '') end -- Configure patterns for colon mode and Unicode character encoding. options.unicode = type(content:find('[^%w%c%p%s]+')) == 'number' options.iso639_th = type(content:find('\224\184[\129-\155]')) == 'number' configure_patterns(options) -- Content lexing. local lines = lexer(content) local tokens = {} local dummy_token = { data = '', posFirst = 1, posLast = 1 } local token_closure = 0 for _, line in ipairs(lines) do if #line == 0 then dummy_token.type = token_closure == 0 and 'whitespace' or tokens[#tokens].type table.insert(tokens, mw.clone(dummy_token)) else for _, token in ipairs(line) do if token.data:find('^%[=*%[$') or token.data:find('^%-%-%[=*%[$') then token_closure = 1 end if token.data:find(']=*]') then token_closure = 0 end table.insert(tokens, token) end end end -- Start documentation data. local documentation = {} documentation.filename = filepath documentation.description = '' -- documentation.comments = {} documentation.tags = {} documentation.items = {} documentation.explicitly_exported = {} documentation.exported_items = {} documentation.other_items = {} documentation.private_items = {} local line_no = 0 local item_index = 0 -- Taglet tracking variables. local start_mode = true local comment_mode = false local doctag_mode = false local export_mode = false local special_tag = false local detachable_tag = false local comment_tail = '' local tag_name = '' local new_item = false local new_tag = false local new_item_code = false local code_block = false local pretty_comment = false local comment_brace = false local t, i = tokens[1], 1 local status, err = pcall(function() while t do -- Taglet variable update. new_item = t.data:find('^%-%-%-') or t.data:find('^%-%-%[=*%[') comment_tail = t.data:gsub('^%-%-%[=*%[', ''):gsub('^%-%-+', '') tag_name = comment_tail:match(DOCBUNTO_TAG) tag_name = p.tags._alias[tag_name] or tag_name new_tag = p.tags[tag_name] pretty_comment = t.data:find('[^-]+%-%-+%s*$') or -- what is this matching? t.data:find('</?nowiki>') or t.data:find('</?pre>') comment_brace = t.data:find('^%-%-%[=*%[$') or t.data:find('^%s*%-%-%]=*%]$') or t.data:find('^%s*%]=*%]%-%-$%s*') or t.data:find('^%s*%]=*%]$') pragma_mode = tag_name == 'pragma' export_mode = tag_name == 'export' special_tag = pragma_mode or export_mode detachable_tag = tag_name == 'error' local tags -- FIXME storing this as a variable is silly -- Line counter. if t.posFirst == 1 then line_no = line_no + 1 end -- Data insertion logic. if t.type == 'comment' then if new_item then comment_mode = true end -- Module-level documentation taglet. if start_mode then -- table.insert(documentation.comments, t.data) if comment_mode and not new_tag and not doctag_mode and not comment_brace and not pretty_comment then documentation.description = append_description(documentation.description, comment_tail) end if new_tag and not special_tag then doctag_mode = true table.insert(documentation.tags, process_tag(comment_tail, line_no)) elseif doctag_mode and not comment_brace and not pretty_comment then tags = documentation.tags if p.tags[tags[#tags].category] == TAG_MULTI or p.tags[tags[#tags].category] == TAG_NAMED_MULTI then tags[#tags].value = append_description(tags[#tags].value, comment_tail) elseif p.tags[tags[#tags].category] == TAG_MULTI_LINE then tags[#tags].value = tags[#tags].value .. '\n' .. comment_tail end end end -- Documentation item detection. if not start_mode and (new_item or (new_tag and tokens[i - 1].type ~= 'comment')) and not special_tag and not detachable_tag then table.insert(documentation.items, {}) item_index = item_index + 1 documentation.items[item_index].lineno = line_no documentation.items[item_index].head = {} -- first line of tokens -- documentation.items[item_index].comments = {} documentation.items[item_index].description = '' documentation.items[item_index].tags = {} end if not start_mode and comment_mode and not new_tag and not doctag_mode and not comment_brace and not pretty_comment then documentation.items[item_index].description = append_description( documentation.items[item_index].description, comment_tail) end if not start_mode and new_tag and not special_tag then doctag_mode = true table.insert(documentation.items[item_index].tags, process_tag(comment_tail, line_no)) elseif not start_mode and doctag_mode and not comment_brace and not pretty_comment then tags = documentation.items[item_index].tags if p.tags[tags[#tags].category] == TAG_MULTI or p.tags[tags[#tags].category] == TAG_NAMED_MULTI then tags[#tags].value = append_description(tags[#tags].value, comment_tail) elseif p.tags[tags[#tags].category] == TAG_MULTI_LINE then tags[#tags].value = tags[#tags].value .. '\n' .. comment_tail end end -- if not start_mode and (comment_mode or doctag_mode) then -- table.insert(documentation.items[item_index].comments, t.data) -- end -- Export tag support. -- Note: string-keyed tables are not supported. (E.g., {['my string'] = foo}) if export_mode then -- assume that an @export tag at the start of the line must be exporting the module local factory_mode = t.posFirst ~= 1 if factory_mode then -- NOTE this information doesn't seem to be used documentation.items[item_index].exports = true else documentation.exports = true end -- Lua language constructs that can contain , ; = tokens local BLOCKS = { ['if'] = {terminator='end'}, ['do'] = {terminator='end'}, -- also handles 'while' ['repeat'] = {terminator='until'}, -- the part after 'until' is an expression, so it can't have , ; = without being another block ['for'] = {terminator='end', replace='do'}, ['function'] = {terminator='end'}, ['{'] = {terminator='}'}, ['('] = {terminator=')'}, } -- look ahead, collecting all entries in the next "block" (assumed to be a table) local items = {} local si = i+1 local st = tokens[si] local depth = 0 local blocks = {} -- stack of blocks and {} () local curr_item = {value={}} while st do local subtokens if st.type == 'symbol' then -- break up merged symbols into individual characters (e.g., '{}' or '{},') subtokens = lib.split(st.data, "") else subtokens = {st.data} end for _, sst in ipairs(subtokens) do -- Note: can't have parentheses or other "blocks" around the table if depth == 1 then -- apparently, semicolons are valid table item separators in Lua if sst == ',' or sst == ';' or sst == '}' then table.insert(items, curr_item) curr_item = {value={}} elseif sst == '=' then curr_item.alias = curr_item.value curr_item.value = {} elseif st.type == 'ident' or st.type == 'symbol' then if curr_item.value then table.insert(curr_item.value, sst) end end end if depth > 0 and sst == blocks[depth].terminator then blocks[depth] = nil depth = depth - 1 if depth <= 0 then break end elseif depth > 0 and sst == blocks[depth].replace then blocks[depth] = blocks[depth].replace elseif BLOCKS[sst] then depth = depth + 1 blocks[depth] = BLOCKS[sst] if depth > 1 then -- don't store value if it's a function or table; ideally, we only want identifiers curr_item.value = nil end end end st, si = tokens[si + 1], si + 1 end local sequence_counter = 0 for _, item in ipairs(items) do local item_reference, item_alias if item.value then item_reference = table.concat(item.value) end if item.alias then item_alias = table.concat(item.alias) else sequence_counter = sequence_counter + 1 item_alias = '[' .. sequence_counter .. ']' end -- item_reference will be nil if it's an inline function or table item_reference = item_reference or item_alias if item_reference then export_item(documentation, item_reference, item_index, item_alias, factory_mode) end end end -- Pragma tag support. if pragma_mode then tags = process_tag(comment_tail, line_no) options[tags.value] = yesno((next(tags.modifiers)), true) if options[tags.value] == nil then options[tags.value] = true end end -- Data insertion logic. elseif comment_mode or doctag_mode then if item_index ~= 0 then new_item_code = true end -- Documentation block reset. start_mode = false comment_mode = false doctag_mode = false export_mode = false pragma_mode = false end -- Save item head for static analysis. if item_index ~= 0 and not doctag_mode and not comment_mode and new_item_code then local head = documentation.items[item_index].head if t.posFirst == 1 and isNotEmpty(head) then new_item_code = false else table.insert(head, t) end end t, i = tokens[i + 1], i + 1 end documentation.lineno = line_no -- post-processing -- Package data post-processing. postprocess_tags(documentation.tags) documentation.name = extract_name(documentation, content) documentation.info = extract_info(documentation) documentation.category, documentation.type = extract_type(documentation) or 'module' documentation.description = lib.trim(documentation.description) if #documentation.description ~= 0 then documentation.summary = match(documentation.description, DOCBUNTO_SUMMARY) end documentation.executable = p.tags._code_types[documentation.category] and true or false correct_subitem_tag(documentation) override_item_tag(documentation, 'name') override_item_tag(documentation, 'alias') override_item_tag(documentation, 'summary') override_item_tag(documentation, 'description') override_item_tag(documentation, 'class', 'category') -- Item data post-processing. -- First pass: basic data extraction from tags and static code analysis for _, item in ipairs(documentation.items) do postprocess_tags(item.tags) item.name = extract_name(item) item.category, item.type = extract_type(item) item.description = lib.trim(item.description) if #item.description ~= 0 then item.summary = match(item.description, DOCBUNTO_SUMMARY) end code_static_analysis(item) end -- Second pass: explicit exports and implied locals -- (This loop requires tags to be processed and names to be set for all items before it runs.) for _, item in ipairs(documentation.items) do local export_data = documentation.explicitly_exported[item.name] if export_data then local parent_index = export_data.parent_index local item_alias = export_data.alias if parent_index > 0 then local parent = documentation.items[parent_index] item.alias = parent.tags['factory'][1].value .. (item_alias:find('^%[') and '' or (isInstanceFunction(item) and ':' or '.')) .. item_alias else item.alias = ((documentation.tags['alias'] or {}).value or documentation.name) .. (item_alias:find('^%[') and '' or (documentation.category == 'classmod' and isInstanceFunction(item) and ':' or '.')) .. item_alias end -- TODO is hierarchy even necessary? should it always prioritize alias over base name? item.hierarchy = mw.text.split((item.alias:gsub('["\']?%]', '')), '[.:%[\'""]+') if item.category == 'variable' then item.category = 'member' end else -- never imply local for items explicitly exported with @export if (item.implied_local or item.category == 'variable') and not ( item.tags['private'] or item.tags['local'] or item.category == 'type' or (item.alias or item.name):find('[.[:]') -- functions/tables that belong to the module or a type should not be local ) then local implied_local = process_tag('@local') table.insert(item.tags, implied_local) item.tags['local'] = {implied_local} end end end -- third pass: update package name alias, process override tags (TODO does this really need its own loop?) local package_name, package_alias if documentation.tags['alias'] then package_name = documentation.tags['alias'][1].value package_alias = package_name else package_name = documentation.name package_alias = 'p' end local export_ptn = '^%s([.[])' for _, item in ipairs(documentation.items) do if item.name == package_alias or (item.name and item.name:match('^' .. package_alias .. '[.[]')) then item.alias = item.name:gsub(export_ptn:format(package_alias), documentation.name .. '%1') end if item.name == package_name or (item.name and item.name:find(export_ptn:format(package_name))) or (item.alias and item.alias:find(export_ptn:format(package_name))) then item.export = true -- TODO merge into previous if check? end if item.name and (item.name:find('[.:]') or item.name:find('%[[\'"]')) then item.hierarchy = mw.text.split((item.name:gsub('["\']?%]', '')), '[.:%[\'""]+') end item.category = item.category or ((item.alias or item.name or ''):find('[.[]') and 'member' or 'variable') correct_subitem_tag(item) override_item_tag(item, 'name') override_item_tag(item, 'alias') override_item_tag(item, 'summary') override_item_tag(item, 'description') override_item_tag(item, 'class', 'category') end -- Categorize items: exported, other, or private (local) for _, item in ipairs(documentation.items) do if item.category == 'section' then -- sections default to exported, or private if explicitly marked as such. -- (sections are never "other.") if item.tags['local'] or item.tags['private'] then table.insert(documentation.private_items, item) else table.insert(documentation.exported_items, item) end else if item.export then table.insert(documentation.exported_items, item) elseif item.tags['local'] or item.tags['private'] then table.insert(documentation.private_items, item) else table.insert(documentation.other_items, item) end end end end) if not status then documentation.error = err end return documentation end local function render_visibility_level(root, items, options, header_type) if isNotEmpty(items) then root = root:tag('div'):addClass(VISIBILITYLEVEL_CLASS):newline() root:wikitext('=== ' .. i18n:msg(header_type) .. ' ==='):newline() else return end local codedoc = root -- TODO rename codedoc for _, item in ipairs(items) do local itemdoc if item.category == 'section' then if item.name == 'end' then codedoc = root else codedoc = root:tag('div'):addClass(SECTION_CLASS):newline() codedoc:wikitext('==== ', mw.ustring.gsub(item.alias or maybe_md(item.name) or maybe_md(item.summary), '[.։。।෴۔።]$', ''), ' ===='):newline() if #item.description ~= 0 then codedoc:wikitext(maybe_md(item.description)):newline() end end elseif item.category == 'type' then if item.name == 'end' then codedoc = root else codedoc = root:tag('div'):addClass(SECTION_CLASS):newline() codedoc:wikitext('==== <code>', (item.alias or item.name), '</code> ===='):newline() if #item.description ~= 0 then codedoc:wikitext(maybe_md(item.description)):newline() end end elseif item.category == 'function' then itemdoc = render_item(codedoc, item, options, preop_function_name) if not options.simple and item.tags['param'] then render_tag(itemdoc, 'param', item.tags['param'], options) end if not options.simple and item.tags['error'] then render_tag(itemdoc, 'error', item.tags['error'], options, preop_error_line) end if not options.simple and item.tags['return'] then render_tag(itemdoc, 'return', item.tags['return'], options) end elseif item.category == 'table' or item.category == 'member' or item.category == 'variable' then itemdoc = render_item(codedoc, item, options) if not options.simple and item.tags['field'] then render_tag(itemdoc, 'field', item.tags['field'], options) end end local target = itemdoc or codedoc -- itemdoc doesn't exist for sections (item.category of "section" or "type") if not options.simple and item.tags['note'] then render_tag(target, 'note', item.tags['note'], options) end if not options.simple and item.tags['warning'] then render_tag(target, 'warning', item.tags['warning'], options) end if not options.simple and item.tags['fixme'] then render_tag(target, 'fixme', item.tags['fixme'], options) end if not options.simple and item.tags['todo'] then render_tag(target, 'todo', item.tags['todo'], options) end if not options.simple and item.tags['usage'] then render_tag(target, 'usage', item.tags['usage'], options, preop_usage_highlight) end if not options.simple and item.tags['see'] then render_tag(target, 'see', item.tags['see'], options) end end return root end --- Doclet renderer for Docbunto taglet data. -- @function p.doclet -- @param {table} data Taglet documentation data. -- @param[opt] {table} options Configuration options. -- @return {string} Wikitext documentation output. function p.doclet(data, options) local documentation = mw.html.create('div'):addClass('docbunto') if data.error then documentation:wikitext("Error during documentation parsing: ", data.error):newline():newline() end local namespace = '^' .. mw.site.namespaces[828].name .. ':' local codepage = data.filename:gsub(namespace, '') options = options or {} options.filepath = options.filepath or data.filename -- janky way to pass filepath to `render_item` frame = frame or mw.getCurrentFrame():getParent() or mw.getCurrentFrame() -- parent is nil in dev console -- Enable/disable markdown based on options configure_markdown(options) -- Disable edit sections for automatic documentation pages. if not options.code then documentation:wikitext('__NOEDITSECTION__') end -- Custom infobox for external wikis. if not options.code then local custom, infobox = pcall(require, 'Module:Docbunto/infobox') if custom and type(infobox) == 'function' then documentation:wikitext(infobox(data, codepage, frame, options)):newline() end end -- Documentation lede. if not options.code and #data.description ~= 0 then local intro = maybe_md(data.description:gsub('^(' .. codepage .. ')', '<b>%1</b>')) documentation:wikitext(intro):newline():newline() end -- Custom documentation preface. if options.preface then documentation:wikitext(options.preface):newline():newline() end -- Start code documentation. local function_module = data.tags['param'] or data.tags['return'] if (function_module or isNotEmpty(data.items)) and not options.code or options.preface then documentation:wikitext('== ', i18n:msg('header-documentation'), ' =='):newline() end -- Render documentation items. if function_module then data.category = 'function' if not options.code then data.description = '' end render_visibility_level(documentation, {data}, options, 'header-function') else local header_type = documentation.category == 'classmod' and 'header-class' or 'header-items' render_visibility_level(documentation, data.exported_items, options, header_type) end render_visibility_level(documentation, data.other_items, options, 'header-other') if options.all then render_visibility_level(documentation, data.private_items, options, 'header-private') end -- Render module-level annotations. local header_paren = options.code and '===' or '==' local header_text for _, tag_name in ipairs{'warning', 'fixme', 'note', 'todo', 'see'} do -- TODO add module-level table with this order; maybe add usage? if data.tags[tag_name] then header_text = i18n:msg('tag-' .. tag_name, data.tags[tag_name].value and '1' or '2') header_text = header_paren .. ' ' .. header_text .. ' ' .. header_paren documentation:newline():wikitext(header_text):newline() for _, tag_el in ipairs(data.tags[tag_name]) do documentation:wikitext('* ', maybe_md(tag_el.value)):newline() end end end return documentation end --- Token dictionary for Docbunto tags. -- Maps Docbunto tag names to tag tokens. -- * Multi-line tags use the `'M'` token. -- * Multi-line preformatted tags use the `'ML'` token. -- * Identifier tags use the `'ID'` token. -- * Single-line tags use the `'S'` token. -- * Flags use the `'N'` token. -- * Type tags use the `'T'` token. -- @table p.tags p.tags = { -- Item-level tags, available for global use. ['param'] = 'NM', ['see'] = 'M', ['note'] = 'M', ['usage'] = 'ML', ['description'] = 'M', ['field'] = 'NM', ['return'] = 'M', ['fixme'] = 'M', ['todo'] = 'M', ['warning'] = 'M', ['error'] = 'M'; ['class'] = 'ID', ['name'] = 'ID', ['alias'] = 'ID'; ['summary'] = 'S', ['pragma'] = 'S', ['factory'] = 'S', ['release'] = 'S', ['author'] = 'S', ['copyright'] = 'S', ['license'] = 'S', ['image'] = 'S', ['caption'] = 'S', ['require'] = 'S', ['attribution'] = 'S', ['credit'] = 'S', ['demo'] = 'S'; ['local'] = 'N', ['export'] = 'N', ['private'] = 'N', ['constructor'] = 'N', ['static'] = 'N'; -- Project-level tags, all scoped to a file. ['module'] = 'T', ['script'] = 'T', ['classmod'] = 'T', ['topic'] = 'T', ['submodule'] = 'T', ['example'] = 'T', ['file'] = 'T'; -- Module-level tags, used to register module items. ['function'] = 'T', ['table'] = 'T', ['member'] = 'T', ['variable'] = 'T', ['section'] = 'T', ['type'] = 'T'; } p.tags._alias = { -- Normal aliases. ['about'] = 'summary', ['abstract'] = 'summary', ['brief'] = 'summary', ['bug'] = 'fixme', ['argument'] = 'param', ['credits'] = 'credit', ['code'] = 'usage', ['details'] = 'description', ['discussion'] = 'description', ['exception'] = 'error', ['lfunction'] = 'function', ['package'] = 'module', ['property'] = 'member', ['raise'] = 'error', ['requires'] = 'require', ['returns'] = 'return', ['throws'] = 'error', ['typedef'] = 'type', -- Typed aliases. ['bool'] = 'field', ['func'] = 'field', ['int'] = 'field', ['number'] = 'field', ['string'] = 'field', ['tab'] = 'field', ['vararg'] = 'param', ['tfield'] = 'field', ['tparam'] = 'param', ['treturn'] = 'return' } p.tags._type_alias = { -- Implicit type value alias. ['bool'] = 'boolean', ['func'] = 'function', ['int'] = 'number', ['number'] = 'number', ['string'] = 'string', ['tab'] = 'table', ['vararg'] = '...', -- Pure typed modifier alias. ['tfield'] = 'variable', ['tparam'] = 'variable', ['treturn'] = 'variable' } p.tags._project_level = { -- Contains code. ['module'] = true, ['script'] = true, ['classmod'] = true, ['submodule'] = true, ['file'] = true, -- Contains documentation. ['topic'] = true, ['example'] = true } p.tags._code_types = { ['module'] = true, ['script'] = true, ['classmod'] = true } p.tags._module_info = { ['image'] = true, ['caption'] = true, ['release'] = true, ['author'] = true, ['copyright'] = true, ['license'] = true, ['require'] = true, ['credit'] = true, ['attribution'] = true, ['demo'] = true } p.tags._annotation_tags = { ['warning'] = true, ['fixme'] = true, ['note'] = true, ['todo'] = true, ['see'] = true } p.tags._privacy_tags = { ['private'] = true, ['local'] = true } p.tags._generic_tags = { ['variable'] = true, ['member'] = true } p.tags._subtype_tags = { ['factory'] = true, ['local'] = true, ['private'] = true, ['constructor'] = true, ['static'] = true } p.tags._subtype_hierarchy = { 'private', 'local', 'static', 'factory', 'constructor' } return p
Summary:
Please note that all contributions to The Petit Planet Wiki are considered to be released under the Creative Commons Attribution-ShareAlike (see
Petit Planet Wiki:Copyrights
for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Preview page with this template
Below are commonly used wikitext from
MediaWiki:Edittools
. Click on any to insert them in the edit box.
File Pages
==Summary==
==Licensing==
{{Fairuse}}
{{File|}}
Dynamic Page List
¦
²
«
»
²{¦}²
«»
«/»
«!----»
Array in DPL
¹
^2{
}^2
^2{¹}^2
Parser Functions
{{#if:||}}
{{#if:<condition>|<result if true>|<result if false>}}
{{#ifeq:|||}}
{{#ifeq:<text1>|<text2>|<result if text1=text2>|<result if text1≠text2>}}
{{#expr:}}
{{#expr:<mathematical expression>}}
{{#switch:||#default=}}
{{#switch:<text1>|<text2>=<result if text1=text2>|<text3>=<result if text1=text3>|#default=<result if no valid match>}}
{{#replace:||}}
{{#replace:<text1>|<plain text to find in text1>|<plain text to insert in place of the text found>}}
{{#titleparts:}}
{{#replace:<page name>}}
{{#tag:|}}
{{#tag:<name of html tag>|<content inside html tag>}}
Markup
{{}}
|
[]
[[]]
[[Category:]]
#REDIRECT [[]] [[Category:Redirect Pages]]
<code></code>
<includeonly></includeonly>
<noinclude></noinclude>
<nowiki></nowiki>
<!---->
<br>
§
Notices
{{Stub|}}
{{Stub Dialogue}}
{{Upcoming}}
{{Under Construction}}
{{Placeholder|}}
Magic Words
{{!}}
{{formatnum:}}
{{lc:}}
{{uc:}}
{{PAGENAME}}
{{FULLPAGENAME}}
{{ROOTPAGENAME}}
{{BASEPAGENAME}}
{{SUBPAGENAME}}
{{DISPLAYTITLE:|noreplace}}
__TOC__
__NOTOC__
__EXPECTUNUSEDCATEGORY__
__HIDDENCAT__
HTML Entities
—
,
­
Pages included on this page:
Template:Docbunto
(
edit
)
Template:Documentation/Header
(
edit
)
Template:Documentation/styles.css
(
edit
)
Template:TOC Right
(
edit
)
Module:Arguments
(
edit
)
Module:Arguments/i18n
(
edit
)
Module:Common/i18n
(
edit
)
Module:Config
(
edit
)
Module:Docbunto
(
edit
)
Module:Docbunto/doc
(
edit
)
Module:Docbunto/i18n
(
edit
)
Module:Docbunto/infobox
(
view source
)
Module:Docbunto/references
(
edit
)
Module:Documentation
(
edit
)
Module:Documentation/config
(
edit
)
Module:Documentation/i18n
(
edit
)
Module:Entrypoint
(
edit
)
Module:Exists
(
edit
)
Module:Fallbacklist
(
edit
)
Module:Feature
(
edit
)
Module:I18n
(
edit
)
Module:Languages
(
edit
)
Module:Lexer
(
edit
)
Module:TableTools
(
edit
)
Module:Unindent
(
edit
)
Module:Yesno
(
edit
)
This page is a member of 2 hidden categories:
Category:Pages using DynamicPageList4 parser function
Category:Pages using DynamicPageList4
Search
Search
Editing
Module
:
Docbunto
Add topic