Modul:module documentation
Qiyofa
Bu modul uchun Modul:module documentation/doc nomli hujjat sahifasini yaratishingiz mumkin
local m_str_utils = require("Module:string utilities")
local codepoint = m_str_utils.codepoint
local concat = table.concat
local insert = table.insert
local u = m_str_utils.char
local export = {}
local function format_doc(str)
local code_blocks = {}
local code_blocks_i = 0
local private_use_start = 0x100000
return (str
-- {} blocks: blocks of code
-- Escape to avoid removing line breaks.
:gsub("%b{}", function(m0)
local next_char = m0:sub(2, 2)
if next_char == "|" then
-- Wikitable; don't try to parse it as code. But we do want to parse special syntax in them (in
-- particular {...} syntax for embedded code snippets), and if we return nil that won't happen.
-- Instead, we call format_doc() recursively on the innards.
return "{" .. format_doc(m0:sub(2, -2)) .. "}"
end
if next_char == "{" and m0:sub(-2, -2) == "}" then return nil end
local text = "<syntaxhighlight lang=lua" .. (m0:match("\n") and "" or " inline") .. ">" .. m0:sub(2, -2):gsub("^ +", "") .. "</syntaxhighlight>"
code_blocks_i = code_blocks_i + 1
code_blocks[code_blocks_i] = text
return u(private_use_start + code_blocks_i)
end)
-- Join continued lines in a paragraph. We don't want to do that if there are two newlines in a row,
-- and not if the second line begins with whitespace or a certain special characters (#, * or : indicating
-- a list item; | indicating a wikitable item; semicolon for bolded items).
:gsub("([^\n])\n[ \t]*([^ \t\n#*:;|])", "%1 %2")
-- Repeat the previous in case of a single-character line (admittedly rare).
:gsub("([^\n])\n[ \t]*([^ \t\n#*:;|])", "%1 %2")
:gsub("\n[ \t]+%f[*#:;]", "\n") -- remove indentation for list items
:gsub("%f[\n,{]\n%f[^\n*#:;]", "\n\n") -- wiki newlines
:gsub("(\n[ *#:]*)(|?[_%w]+=?):", "%1<code><b>%2</b></code>:") -- parameter names
:gsub("``([A-Za-z0-9_%-.]+)``", "<var>%1</var>") -- placeholder variable names between double backquotes
:gsub("`([^`\n]+)`", '<code>%1</code>') -- literal text between backquotes, set using <code>...</code>
:gsub("\244[\128-\191][\128-\191][\128-\191]", function(char)
return code_blocks[codepoint(char) - private_use_start]
end))
end
--[===[
The main entrypoint for {{tl|module documentation}}. The frame object can contain 3 optional arguments:
* |comment_level=: The number of equals signs (=) a given section uses. Default: 2 (i.e. {--[==[ ... (comment block) ]==]})
*: e.g. The value 4 means {--[====[ ... (comment block) ]====]}.
* |section_level=: The header level used for each function/method. Default: 2 (i.e. L2: {== ... ==}).
* |identifier=: A Lua string pattern. Only the comments of functions whose names match this pattern are used. When not given, all function are accepted.
*: This is useful when giving object methods, using a pattern such as {^object_name:}.
]===]
function export.show(frame)
local args = frame:getParent().args or {}
local comment_level = tonumber(args["comment_level"]) or 2
local function make_comment_pattern(typeid)
if typeid then
typeid = "%s*" .. typeid
else
typeid = ""
end
return "%-%-%[" .. ("="):rep(comment_level) .. "%[" .. typeid .. "\n?(.-)\n?]" .. ("="):rep(comment_level) .. "]()"
end
local fn_comment_pattern = make_comment_pattern(nil)
local intro_comment_pattern = make_comment_pattern("intro:")
local metafunc_comment_pattern = make_comment_pattern("func:%s*(([^\n(]+)[^\n)]+%))")
local section_mark = ("="):rep(tonumber(args["section_level"]) or 2)
local pattern_identifier = args["identifier"] or ""
local mod_title = mw.title.getCurrentTitle()
if mod_title.text:match("/documentation$") then return "(<i>The generated documentation is located at the module page.</i>)" end
local mod_text = mod_title:getContent()
if not mod_text then return "(<i>The module page does not exist now.</i>)" end
-- This contains function and intro documentation. Each element is a two-element list of {POSITION, DOCS} specifying
-- the generated documentation for a function and the character position in the file where it was found (for sorting
-- purposes).
local docs
local intro_comment = mod_text:match("^.-" .. intro_comment_pattern)
if intro_comment then
docs = { {1, format_doc(intro_comment) }}
else
docs = {}
end
-- Look for actual functions.
for p0, f, fn in mod_text:gmatch("()\n[ \t]*function +(([^\n(]+)[^\n)]+%))") do
if fn:match(pattern_identifier) then
local c = mod_text:sub(1, p0 - 1):match("^.*" .. fn_comment_pattern .. "%s*$")
insert(docs, {p0, section_mark .. fn .. section_mark .. "\n\n" .. "<syntaxhighlight lang=lua inline>function " ..
f .. "</syntaxhighlight>\n\n" .. format_doc(c or
'<strong class="error">This function lacks documentation. Please add a description of its usages, inputs and outputs, ' ..
"or its difference from similar functions, or make it local to remove it from the function list.</strong>" ..
"[[Category:Templates and modules needing documentation]]")})
end
end
-- Now look for comments with the function declaration inside them (used for metatable functions etc.).
for p0, f, fn, comment in mod_text:gmatch("()" .. metafunc_comment_pattern) do
insert(docs, {p0, section_mark .. fn .. section_mark .. "\n\n" .. "<syntaxhighlight lang=lua inline>function " .. f .. "</syntaxhighlight>\n\n" .. format_doc(comment)})
end
table.sort(docs, function(a, b) return a[1] < b[1] end)
local chunks = {}
for i, decl in ipairs(docs) do
insert(chunks, decl[2])
end
return frame:preprocess(concat(chunks, "\n\n"))
end
return export