Module:debug
- The following documentation is located at Module:debug/documentation. [edit]
- Useful links: subpage list • links • transclusions • testcases • sandbox
This module is used to debug templates and other modules, and to help track down problems or incorrect usage.
dump
dump(value)
Converts any value (except for functions) into a string representation. The string is formatted as Lua syntax, so you should be able to take the output of this function and insert it back into a Lua module. Tables are processed recursively. Tabs are converted into spaces.
highlight_dump
highlight_dump(value)
Does the same as dump
, except it adds Lua syntax highlighting, and tabs are preserved.
error
{{#invoke:debug|error|message}}
This function is invoked from templates, and simply triggers a script error with a message. This is useful if you want to trigger a script error but don't have the time or knowledge to convert a template to Lua.
track
track(key)
Convenience function which transcludes a tracking subtemplate. The key
is a string or a list of strings: track("key")
or track{ "key1", "key2", "key3", ... }
.
Usually invocations of this functions should look like this: require('Module:debug/track')(key)
or require('Module:debug').track(key)
. Loading this module on the spot instead of ahead of time may prevent unnecessary transclusion list overload.
highlight
This function creates the equivalent of a <source>
or <syntaxhighlight>
tag using the frame:extensionTag()
function from Scribunto. Depending on the arguments, it behaves in two different ways:
highlight(content, options)
- Highlight the given content (which should be a string) using the table of options.
require("Module:debug").highlight('<span class="Latn" lang="en">word</span>', { lang = "html" }) -- generate syntax-highlighted HTML code
highlight(options)
- Returns a highlighting function that uses the given table of options. This is useful when a given set of options are used multiple times in a module. The highlighting function receives a string as argument.
local highlight_HTML = require("Module:debug").highlight{ lang = "html" } -- generate syntax-highlighting function for HTML highlight_HTML('<span class="Latn" lang="en">word</span>') -- generates syntax-highlighted HTML code
The function recognizes two fields in the table of options:
- lang
- Language or file format. (See the full list.) Defaults to
"lua"
. - inline
- Display the code inline, rather than as a block.
local export = {}
local escape
do
local escapes = {
["\a"] = "a", ["\b"] = "b", ["\f"] = "f", ["\n"] = "n", ["\r"] = "r",
["\t"] = "t", ["\v"] = "v", ["\\"] = "\\", ["\""] = '"', ["'"] = "'",
}
local function helper(char)
return escapes[char] and "\\" .. escapes[char]
or ("\\%03d"):format(char:byte())
end
-- Escape control characters, backslash, double quote, and bytes that aren't
-- used in UTF-8.
-- Escape stuff that can't be saved in a MediaWiki page, like invalid UTF-8
-- and NFD character sequences? Hard.
-- Similar to string.format("%q", str), which does not use C-like simple
-- escapes and does not escape bytes that are not used in UTF-8.
escape = function (str)
return (str:gsub("[%c\\\"\192\193\245-\255]", helper))
end
end
export.escape = escape
-- Convert a value to a string
function export.dump(value, prefix, tsort)
local t = type(value)
prefix = prefix or ""
if t == "string" then
return '"' .. escape(value) .. '"'
elseif t == "table" then
local str_table = {}
table.insert(str_table, " {")
for key, val in require("Module:table").sortedPairs(value, tsort) do
table.insert(str_table, " " .. prefix .. "\t[" .. export.dump(key, prefix .. "\t") .. "] = " .. export.dump(val, prefix .. "\t"):gsub("^ ", "") .. ",")
end
table.insert(str_table, " " .. prefix .. "}")
return table.concat(str_table, "\n")
else
return tostring(value)
end
end
function export.highlight_dump(value, prefix, tsort, options)
options = options or {}
local func = options.modified and "modified_dump" or "dump"
local dump = export[func](value, prefix, tsort)
-- Remove spaces at beginnings of lines (which are simply to force a <pre></pre> tag).
dump = dump:gsub("%f[^%z\n] ", "")
return export.highlight(dump)
end
-- Returns true if table contains a table as one of its values
local function containsTable(t)
for key, value in pairs(t) do
if type(value) == "table" then
return true
end
end
return false
end
local function containsTablesWithSize(t, size)
for key, value in pairs(t) do
if type(value) == "table" and require("Module:table").size(value) ~= size then
return false
end
end
return true
end
--[=[
Convert a value to a string.
Like dump below, but if a table has consecutive numbered keys and does not
have a table as one of its values, it will be placed on a single line.
Used by [[Module:User:Erutuon/script recognition]].
]=]
function export.modified_dump(value, prefix, tsort)
local t = type(value)
prefix = prefix or ""
if t == "string" then
return '"' .. value .. '"'
elseif t == "table" then
local str_table = {}
local containsTable = containsTable(value)
local consecutive = require("Module:table").isArray(value)
if consecutive and not containsTable or containsTable and containsTablesWithSize(value, 3) then
table.insert(str_table, "{")
for key, val in require("Module:table").sortedPairs(value, tsort) do
if containsTable then
table.insert(str_table, "\n\t" .. prefix)
else
table.insert(str_table, " ")
end
if type(key) == "string" then
table.insert(str_table, "[" .. export.modified_dump(key) .. "] = ")
end
table.insert(str_table, type(key) == "number" and type(val) == "number" and string.format("0x%05X", val) or export.modified_dump(val))
if not (consecutive and #value == 3) or type(key) == "number" and value[key + 1] then
table.insert(str_table, ",")
end
end
if containsTable then
table.insert(str_table, "\n" .. prefix)
else
table.insert(str_table, " ")
end
table.insert(str_table, "}")
return table.concat(str_table)
end
table.insert(str_table, " {")
for key, val in require("Module:table").sortedPairs(value, tsort) do
table.insert(str_table, " " .. prefix .. "\t[" .. export.modified_dump(key, prefix .. "\t") .. "] = " .. export.modified_dump(val, prefix .. "\t"):gsub("^ ", "") .. ",")
end
table.insert(str_table, " " .. prefix .. "}")
return table.concat(str_table, "\n")
elseif t == "number" and value > 46 then
return string.format("0x%05X", value)
else
return tostring(value)
end
end
export.track = require("Module:debug/track")
-- Trigger a script error from a template
function export.error(frame)
error(frame.args[1] or "(no message specified)")
end
--[[
Convenience function for generating syntaxhighlight tags.
Display defaults to block.
Options is a table. To display inline text with HTML highlighting:
{ inline = true, lang = "html" }
]]
function export.highlight(content, options)
if type(content) == "table" then
options = content
options = {
lang = options.lang or "lua",
inline = options.inline and true
}
return function(content)
return mw.getCurrentFrame():extensionTag("syntaxhighlight", content, options)
end
else
return mw.getCurrentFrame():extensionTag("syntaxhighlight", content, {
lang = options and options.lang or "lua",
inline = options and options.inline and true or nil
})
end
end
function export.track_unrecognized_args(args, template_name)
local function track(code)
export.track(template_name .. "/" .. code)
end
track("unrecognized arg")
local arg_list = {}
for arg, value in pairs(args) do
track("unrecognized arg/" .. arg)
table.insert(arg_list, ("|%s=%s"):format(arg, value))
end
mw.log(
("Unrecognized parameter%s in {{%s}}: %s."):format(
arg_list[2] and "s" or "",
template_name,
table.concat(arg_list, ", ")))
end
do
local placeholder = "_message_"
function export._placeholder_error(frame)
-- A dummy function that throws an error with a placeholder message.
error(placeholder, (frame.args.level or 1) + 6)
end
-- Throw an error via callParserFunction, which generates a real error with traceback, automatic categorization in [[CAT:E]] etc., but the error message is returned as a string. Then, replace the placeholder error message with `message`, which is preprocessed. This is necessary when preprocessing needs to be applied (e.g. when using <pre> tags), since otherwise strip markers and other half-processed text gets displayed instead.
function export.formatted_error(message, level)
local frame = mw.getCurrentFrame()
return (frame:callParserFunction("#invoke", {"debug", "_placeholder_error", level = level})
:gsub(placeholder, frame:preprocess(message)))
end
end
return export