m (Undo revision 372920 by TheSatanicSanta (talk)) |
(Cleanup return value) |
||
(17 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
local util = {} |
local util = {} |
||
+ | local type, pairs, ipairs = type, pairs, ipairs |
||
− | function util.table_print |
+ | function util.table_print(tt, indent, done) |
− | done = done or {} |
+ | done = done or {} |
− | indent = indent or 0 |
+ | indent = indent or 0 |
− | if type(tt) == "table" then |
+ | if type(tt) == "table" then |
− | local sb = {} |
+ | local sb = {} |
− | for key, value in pairs |
+ | for key, value in pairs(tt) do |
− | table.insert(sb, string.rep |
+ | table.insert(sb, string.rep(" ", indent)) -- indent it |
− | if type |
+ | if type(value) == "table" and not done[value] then |
− | + | done[value] = true |
|
− | if type(key) ~= "number" then |
+ | if type(key) ~= "number" then |
− | table.insert(sb, string.format("%s = ", util.to_string |
+ | table.insert(sb, string.format("%s = ", util.to_string(key))) |
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
end |
end |
||
− | table. |
+ | return table.concat(sb) |
⚫ | |||
⚫ | |||
− | + | return tt .. "\n" |
|
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
end |
end |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
end |
end |
||
− | function util.to_string( |
+ | function util.to_string(tbl) |
− | if |
+ | if "nil" == type(tbl) then |
− | return tostring( |
+ | return tostring("nil") |
− | elseif |
+ | elseif "string" == type(tbl) then |
return '"' .. tostring(tbl) .. '"' |
return '"' .. tostring(tbl) .. '"' |
||
− | elseif |
+ | elseif "table" == type(tbl) then |
return util.table_print(tbl) |
return util.table_print(tbl) |
||
else |
else |
||
Line 44: | Line 44: | ||
function util.trim(s) |
function util.trim(s) |
||
− | -- from PiL2 20.4 |
+ | -- from PiL2 20.4 |
− | return (s:gsub("^%s*(.-)%s*$", "%1")) |
+ | return (s:gsub("^%s*(.-)%s*$", "%1")) |
end |
end |
||
− | local function __genOrderedIndex( |
+ | local function __genOrderedIndex(t) |
local orderedIndex = {} |
local orderedIndex = {} |
||
for key in pairs(t) do |
for key in pairs(t) do |
||
− | table.insert( |
+ | table.insert(orderedIndex, key) |
end |
end |
||
− | table.sort( |
+ | table.sort( |
− | + | orderedIndex, |
|
− | + | function(left, right) |
|
+ | if type(left) == "table" then |
||
⚫ | |||
− | + | left = left[1] |
|
− | + | end |
|
+ | if type(right) == "table" then |
||
+ | right = right[1] |
||
+ | end |
||
⚫ | |||
end |
end |
||
⚫ | |||
⚫ | |||
⚫ | |||
return orderedIndex |
return orderedIndex |
||
end |
end |
||
Line 73: | Line 76: | ||
if state == nil then |
if state == nil then |
||
-- the first time, generate the index |
-- the first time, generate the index |
||
− | t.__orderedIndex = __genOrderedIndex( |
+ | t.__orderedIndex = __genOrderedIndex(t) |
key = t.__orderedIndex[1] |
key = t.__orderedIndex[1] |
||
return key, t[key] |
return key, t[key] |
||
Line 79: | Line 82: | ||
-- fetch the next value |
-- fetch the next value |
||
key = nil |
key = nil |
||
− | for i = 1, |
+ | for i = 1, #t.__orderedIndex do |
if t.__orderedIndex[i] == state then |
if t.__orderedIndex[i] == state then |
||
− | key = t.__orderedIndex[i+1] |
+ | key = t.__orderedIndex[i + 1] |
end |
end |
||
end |
end |
||
Line 101: | Line 104: | ||
local langnames = nil |
local langnames = nil |
||
− | local code = function( |
+ | local code = function(title) |
− | + | local subPage = (title or mw.title.getCurrentTitle()).subpageText:lower() |
|
if not langNames then |
if not langNames then |
||
− | langNames = |
+ | langNames = require([[Module:Language/Names]]) |
⚫ | |||
⚫ | |||
⚫ | |||
end |
end |
||
⚫ | |||
⚫ | |||
⚫ | |||
end |
end |
||
function util.pageSuffix() |
function util.pageSuffix() |
||
− | + | local langCode = code() |
|
− | + | if langCode then |
|
− | + | return "/" .. langCode |
|
− | + | end |
|
− | + | return "/en" |
|
end |
end |
||
Line 121: | Line 124: | ||
local keys = {} |
local keys = {} |
||
local n = 0 |
local n = 0 |
||
− | for k,v in pairs(tab) do |
+ | for k, v in pairs(tab) do |
n = n + 1 |
n = n + 1 |
||
keys[n] = k |
keys[n] = k |
||
Line 127: | Line 130: | ||
local out = {} |
local out = {} |
||
n = 0 |
n = 0 |
||
− | for k,v in ipairs(keys) do |
+ | for k, v in ipairs(keys) do |
n = n + 1 |
n = n + 1 |
||
out[n] = tab[v] |
out[n] = tab[v] |
||
Line 136: | Line 139: | ||
-- this is exactly as lua-users wiki defined it. Never mind the odd gsub argument. |
-- this is exactly as lua-users wiki defined it. Never mind the odd gsub argument. |
||
function util.interp(s, tab) |
function util.interp(s, tab) |
||
− | return (s:gsub( |
+ | return (s:gsub( |
+ | "($%b{})", |
||
+ | function(w) |
||
+ | return tab[w:sub(3, -2)] or w |
||
⚫ | |||
⚫ | |||
end |
end |
||
Line 148: | Line 156: | ||
-- returns (true, module) or (false, message) |
-- returns (true, module) or (false, message) |
||
− | function util. |
+ | function util.requireDataLocalized(name) |
-- So many ors because tilesheets somehow calls functions that call this *without a frame* |
-- So many ors because tilesheets somehow calls functions that call this *without a frame* |
||
− | local forceUntranslated = argOr( |
+ | local forceUntranslated = argOr("forceUntranslated", false) |
local moduleName = name |
local moduleName = name |
||
if not forceUntranslated then |
if not forceUntranslated then |
||
Line 156: | Line 164: | ||
end |
end |
||
− | local success, data = |
+ | local success, data = |
− | + | pcall( |
|
− | + | function() |
|
+ | return mw.loadData(moduleName) |
||
+ | end |
||
⚫ | |||
if not success then |
if not success then |
||
− | success, data = |
+ | success, data = |
− | + | pcall( |
|
− | + | function() |
|
+ | return mw.loadData(name) |
||
+ | end |
||
+ | ) |
||
end |
end |
||
+ | |||
⚫ | |||
return success, data |
return success, data |
||
⚫ | |||
− | |||
⚫ | |||
⚫ | |||
end |
end |
||
Line 178: | Line 188: | ||
local args = {} |
local args = {} |
||
if first == mw:getCurrentFrame() then |
if first == mw:getCurrentFrame() then |
||
− | for k,v in pairs(first.args) do |
+ | for k, v in pairs(first.args) do |
− | args[k] = v |
+ | args[k] = v |
end |
end |
||
if first.args.fromParent then |
if first.args.fromParent then |
||
− | for k,v in pairs(first:getParent().args) do |
+ | for k, v in pairs(first:getParent().args) do |
− | args[k] = v |
+ | args[k] = v |
end |
end |
||
end |
end |
||
else |
else |
||
− | args = { |
+ | args = {...} |
end |
end |
||
return func(unpack(args)) |
return func(unpack(args)) |
||
Line 202: | Line 212: | ||
end |
end |
||
local blocktab = { |
local blocktab = { |
||
− | __call = function(left, right) |
+ | __call = function(left, right) |
+ | left.t[#left.t + 1] = right |
||
+ | end, |
||
__index = { |
__index = { |
||
reset = function(this) |
reset = function(this) |
||
Line 210: | Line 222: | ||
classes = function(this) |
classes = function(this) |
||
local c = {} |
local c = {} |
||
− | if this.c then |
+ | if this.c then |
− | + | c = {"format-" .. tostring(this.c, 16)} |
|
⚫ | |||
end |
end |
||
− | + | for k, v in pairs(this.fmt) do |
|
+ | if v then |
||
⚫ | |||
+ | end |
||
+ | end |
||
+ | return table.concat(c, " ") |
||
end, |
end, |
||
text = function(this) |
text = function(this) |
||
− | return table.concat(this.t,"") |
+ | return table.concat(this.t, "") |
end |
end |
||
} |
} |
||
Line 229: | Line 245: | ||
b:reset() |
b:reset() |
||
if oldblock then |
if oldblock then |
||
− | for k,v in pairs(oldblock.fmt) do |
+ | for k, v in pairs(oldblock.fmt) do |
b.fmt[k] = v |
b.fmt[k] = v |
||
end |
end |
||
Line 236: | Line 252: | ||
return b |
return b |
||
end |
end |
||
+ | |||
⚫ | |||
− | local escapes = { |
+ | local escapes = {["#"] = ""} |
− | for i,v in ipairs({"\\", "/", "&", "<", ">"}) do |
+ | for i, v in ipairs({"\\", "/", "&", "<", ">"}) do |
escapes[v] = v |
escapes[v] = v |
||
end |
end |
||
− | setmetatable( |
+ | setmetatable( |
− | + | escapes, |
|
+ | {__index = function(tab, key) |
||
+ | return "\\" + key |
||
+ | end} |
||
+ | ) |
||
+ | |||
local currblock = newblock() |
local currblock = newblock() |
||
− | local blocks = { |
+ | local blocks = {currblock} |
local state = "text" -- text, escape, format |
local state = "text" -- text, escape, format |
||
for w in text:gmatch(".") do |
for w in text:gmatch(".") do |
||
Line 263: | Line 284: | ||
blocks[#blocks + 1] = currblock |
blocks[#blocks + 1] = currblock |
||
currblock.c = tonumber(w, 16) |
currblock.c = tonumber(w, 16) |
||
− | elseif w:match("[l-o]") then |
+ | elseif w:match("[l-o]") then |
currblock = newblock(currblock) |
currblock = newblock(currblock) |
||
blocks[#blocks + 1] = currblock |
blocks[#blocks + 1] = currblock |
||
Line 275: | Line 296: | ||
local outblocks = {} |
local outblocks = {} |
||
− | for i,block in ipairs(blocks) do |
+ | for i, block in ipairs(blocks) do |
local b = mw.html.create("span"):attr("class", block:classes()):wikitext(block:text()) |
local b = mw.html.create("span"):attr("class", block:classes()):wikitext(block:text()) |
||
− | outblocks[#outblocks+1] = b |
+ | outblocks[#outblocks + 1] = b |
end |
end |
||
+ | |||
⚫ | |||
if args.nowrap then |
if args.nowrap then |
||
local strings = {} |
local strings = {} |
||
− | for i, block in ipairs(outblocks) do |
+ | for i, block in ipairs(outblocks) do |
− | + | strings[#strings + 1] = tostring(block) |
|
+ | end |
||
⚫ | |||
else |
else |
||
local out = mw.html.create("span"):addClass("craftingGridText") |
local out = mw.html.create("span"):addClass("craftingGridText") |
||
− | for i, block in ipairs(outblocks) do |
+ | for i, block in ipairs(outblocks) do |
+ | out:node(block) |
||
+ | end |
||
return tostring(out) |
return tostring(out) |
||
end |
end |
||
⚫ | |||
+ | |||
⚫ | |||
+ | local out = {} |
||
+ | for i, s in ipairs(frame.args) do |
||
+ | if not mw.ustring.match(s, "^%s*$") then |
||
+ | out[#out + 1] = s |
||
+ | end |
||
⚫ | |||
⚫ | |||
+ | end |
||
+ | |||
+ | -- This function is CASE-senstive. |
||
+ | -- The title will be parsed and the first letter of the root page |
||
+ | -- will be capitalized automatically. |
||
+ | function util.hasSubPage(f) |
||
+ | local args = f or {} |
||
+ | if args == mw.getCurrentFrame() then |
||
+ | args = f.args or f:getParent().args |
||
+ | end |
||
+ | -- Trim whitespace |
||
+ | args = require( [[Module:ProcessArgs]] ).norm(args) |
||
+ | |||
+ | -- If we are on a language page, account for that |
||
+ | local title = mw.title.new(args[1] or "") or {} |
||
+ | local subpage = args[2] |
||
+ | local result = nil |
||
+ | if code(title) then |
||
+ | local frame = mw.getCurrentFrame() |
||
+ | local args = {title.fullText, 1, -2} |
||
+ | result = frame:callParserFunction("#titleparts", args) == subpage |
||
+ | else |
||
+ | result = title.subpageText == subpage |
||
+ | end |
||
+ | |||
+ | return result and 'true' or '' |
||
end |
end |
||
Latest revision as of 05:19, 26 August 2020
Documentation for this module may be created at Module:Utility functions/doc
local util = {}
local type, pairs, ipairs = type, pairs, ipairs
function util.table_print(tt, indent, done)
done = done or {}
indent = indent or 0
if type(tt) == "table" then
local sb = {}
for key, value in pairs(tt) do
table.insert(sb, string.rep(" ", indent)) -- indent it
if type(value) == "table" and not done[value] then
done[value] = true
if type(key) ~= "number" then
table.insert(sb, string.format("%s = ", util.to_string(key)))
end
table.insert(sb, "{\n")
table.insert(sb, util.table_print(value, indent + 2, done))
table.insert(sb, string.rep(" ", indent)) -- indent it
table.insert(sb, "}\n")
elseif "number" == type(key) then
table.insert(sb, string.format("%s\n", util.to_string(value)))
else
table.insert(sb, string.format('%s = "%s"\n', util.to_string(key), util.to_string(value)))
end
end
return table.concat(sb)
else
return tt .. "\n"
end
end
function util.to_string(tbl)
if "nil" == type(tbl) then
return tostring("nil")
elseif "string" == type(tbl) then
return '"' .. tostring(tbl) .. '"'
elseif "table" == type(tbl) then
return util.table_print(tbl)
else
return tostring(tbl)
end
end
function util.trim(s)
-- from PiL2 20.4
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
local function __genOrderedIndex(t)
local orderedIndex = {}
for key in pairs(t) do
table.insert(orderedIndex, key)
end
table.sort(
orderedIndex,
function(left, right)
if type(left) == "table" then
left = left[1]
end
if type(right) == "table" then
right = right[1]
end
return left < right
end
)
return orderedIndex
end
local function orderedNext(t, state)
-- Equivalent of the next function, but returns the keys in the alphabetic
-- order. We use a temporary ordered key table that is stored in the
-- table being iterated.
--print("orderedNext: state = "..tostring(state) )
if state == nil then
-- the first time, generate the index
t.__orderedIndex = __genOrderedIndex(t)
key = t.__orderedIndex[1]
return key, t[key]
end
-- fetch the next value
key = nil
for i = 1, #t.__orderedIndex do
if t.__orderedIndex[i] == state then
key = t.__orderedIndex[i + 1]
end
end
if key then
return key, t[key]
end
-- no more value to return, cleanup
t.__orderedIndex = nil
return
end
function util.orderedPairs(t)
-- Equivalent of the pairs() function on tables. Allows to iterate
-- in order
return orderedNext, t, nil
end
local langnames = nil
local code = function(title)
local subPage = (title or mw.title.getCurrentTitle()).subpageText:lower()
if not langNames then
langNames = require([[Module:Language/Names]])
end
if langNames[subPage] then
return subPage
end
end
function util.pageSuffix()
local langCode = code()
if langCode then
return "/" .. langCode
end
return "/en"
end
function util.compact(tab)
local keys = {}
local n = 0
for k, v in pairs(tab) do
n = n + 1
keys[n] = k
end
local out = {}
n = 0
for k, v in ipairs(keys) do
n = n + 1
out[n] = tab[v]
end
return out
end
-- this is exactly as lua-users wiki defined it. Never mind the odd gsub argument.
function util.interp(s, tab)
return (s:gsub(
"($%b{})",
function(w)
return tab[w:sub(3, -2)] or w
end
))
end
local function argOr(name, default)
local frame = mw.getCurrentFrame()
if frame == nil then
return default
end
return frame.args[name]
end
-- returns (true, module) or (false, message)
function util.requireDataLocalized(name)
-- So many ors because tilesheets somehow calls functions that call this *without a frame*
local forceUntranslated = argOr("forceUntranslated", false)
local moduleName = name
if not forceUntranslated then
moduleName = moduleName .. util.pageSuffix()
end
local success, data =
pcall(
function()
return mw.loadData(moduleName)
end
)
if not success then
success, data =
pcall(
function()
return mw.loadData(name)
end
)
end
return success, data
end
function util.wrapForInvoke(func)
return function(...)
local first = ...
local args = {}
if first == mw:getCurrentFrame() then
for k, v in pairs(first.args) do
args[k] = v
end
if first.args.fromParent then
for k, v in pairs(first:getParent().args) do
args[k] = v
end
end
else
args = {...}
end
return func(unpack(args))
end
end
function util.minetext(args)
local text = util.table_print(args or {{1}})
if type(args) == "string" then
text = args
else
args = args.args or args
text = args[1]
end
local blocktab = {
__call = function(left, right)
left.t[#left.t + 1] = right
end,
__index = {
reset = function(this)
this.fmt = {l = false, m = false, n = false, o = false}
this.c = false
end,
classes = function(this)
local c = {}
if this.c then
c = {"format-" .. tostring(this.c, 16)}
end
for k, v in pairs(this.fmt) do
if v then
c[#c + 1] = "format-" .. k
end
end
return table.concat(c, " ")
end,
text = function(this)
return table.concat(this.t, "")
end
}
}
local newblock = function(oldblock)
b = {
c = false,
t = {}
}
setmetatable(b, blocktab)
b:reset()
if oldblock then
for k, v in pairs(oldblock.fmt) do
b.fmt[k] = v
end
b.c = oldblock.c
end
return b
end
local escapes = {["#"] = ""}
for i, v in ipairs({"\\", "/", "&", "<", ">"}) do
escapes[v] = v
end
setmetatable(
escapes,
{__index = function(tab, key)
return "\\" + key
end}
)
local currblock = newblock()
local blocks = {currblock}
local state = "text" -- text, escape, format
for w in text:gmatch(".") do
if state == "escape" then
currblock(escapes[w])
state = "text"
elseif state == "text" then
if w == "\\" then
state = "escape"
elseif w == "&" then
state = "format"
else
currblock(w)
end
elseif state == "format" then
if w:match("[0-9a-f]") then
currblock = newblock()
blocks[#blocks + 1] = currblock
currblock.c = tonumber(w, 16)
elseif w:match("[l-o]") then
currblock = newblock(currblock)
blocks[#blocks + 1] = currblock
currblock.fmt[w] = not currblock.fmt[w]
else
currblock("&" .. w)
end
state = "text"
end
end
local outblocks = {}
for i, block in ipairs(blocks) do
local b = mw.html.create("span"):attr("class", block:classes()):wikitext(block:text())
outblocks[#outblocks + 1] = b
end
if args.nowrap then
local strings = {}
for i, block in ipairs(outblocks) do
strings[#strings + 1] = tostring(block)
end
return table.concat(strings, "")
else
local out = mw.html.create("span"):addClass("craftingGridText")
for i, block in ipairs(outblocks) do
out:node(block)
end
return tostring(out)
end
end
function util.join(frame)
local out = {}
for i, s in ipairs(frame.args) do
if not mw.ustring.match(s, "^%s*$") then
out[#out + 1] = s
end
end
return table.concat(out, frame.args.sep)
end
-- This function is CASE-senstive.
-- The title will be parsed and the first letter of the root page
-- will be capitalized automatically.
function util.hasSubPage(f)
local args = f or {}
if args == mw.getCurrentFrame() then
args = f.args or f:getParent().args
end
-- Trim whitespace
args = require( [[Module:ProcessArgs]] ).norm(args)
-- If we are on a language page, account for that
local title = mw.title.new(args[1] or "") or {}
local subpage = args[2]
local result = nil
if code(title) then
local frame = mw.getCurrentFrame()
local args = {title.fullText, 1, -2}
result = frame:callParserFunction("#titleparts", args) == subpage
else
result = title.subpageText == subpage
end
return result and 'true' or ''
end
return util