Feed The Beast Wiki

Follow the Feed The Beast Wiki on Discord or Mastodon!

READ MORE

Feed The Beast Wiki
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 (tt, indent, done)
+
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 (tt) do
+
for key, value in pairs(tt) do
table.insert(sb, string.rep (" ", indent)) -- indent it
+
table.insert(sb, string.rep(" ", indent)) -- indent it
if type (value) == "table" and not done [value] then
+
if type(value) == "table" and not done[value] then
done [value] = true
+
done[value] = true
if type(key) ~= "number" then
+
if type(key) ~= "number" then
table.insert(sb, string.format("%s = ", util.to_string (key) ))
+
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
 
end
table.insert(sb, "{\n");
+
return table.concat(sb)
 
else
table.insert(sb, util.table_print (value, indent + 2, done))
 
table.insert(sb, string.rep (" ", indent)) -- indent it
+
return tt .. "\n"
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
 
end
return table.concat(sb)
 
else
 
return tt .. "\n"
 
end
 
 
end
 
end
   
function util.to_string( tbl )
+
function util.to_string(tbl)
if "nil" == type( tbl ) then
+
if "nil" == type(tbl) then
return tostring('nil')
+
return tostring("nil")
elseif "string" == type( tbl ) then
+
elseif "string" == type(tbl) then
 
return '"' .. tostring(tbl) .. '"'
 
return '"' .. tostring(tbl) .. '"'
elseif "table" == type( tbl ) then
+
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( t )
+
local function __genOrderedIndex(t)
 
local orderedIndex = {}
 
local orderedIndex = {}
 
for key in pairs(t) do
 
for key in pairs(t) do
table.insert( orderedIndex, key )
+
table.insert(orderedIndex, key)
 
end
 
end
table.sort( orderedIndex, function(left, right)
+
table.sort(
if type(left) == "table" then
+
orderedIndex,
left = left[1]
+
function(left, right)
  +
if type(left) == "table" then
end
 
if type(right) == "table" then
+
left = left[1]
right = right[1]
+
end
  +
if type(right) == "table" then
  +
right = right[1]
  +
end
 
return left < right
 
end
 
end
 
)
return left < right
 
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 )
+
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,table.getn(t.__orderedIndex) do
+
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( title )
+
local code = function(title)
local subPage = ( title or mw.title.getCurrentTitle() ).subpageText:lower()
+
local subPage = (title or mw.title.getCurrentTitle()).subpageText:lower()
 
if not langNames then
 
if not langNames then
langNames = mw.loadData( [[Module:Language/Names]] )
+
langNames = require([[Module:Language/Names]])
 
end
 
if langNames[subPage] then
 
return subPage
 
end
 
end
if langNames[subPage] then
 
return subPage
 
end
 
 
end
 
end
 
function util.pageSuffix()
 
function util.pageSuffix()
local langCode = code()
+
local langCode = code()
if langCode then
+
if langCode then
return '/' .. langCode
+
return "/" .. langCode
end
+
end
return '/en'
+
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('($%b{})', function(w) return tab[w:sub(3, -2)] or w end))
+
return (s:gsub(
  +
"($%b{})",
  +
function(w)
  +
return tab[w:sub(3, -2)] or w
 
end
 
))
 
end
 
end
   
Line 148: Line 156:
   
 
-- returns (true, module) or (false, message)
 
-- returns (true, module) or (false, message)
function util.requireDataLocalised(name)
+
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('forceUntranslated', false)
+
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 = pcall(function()
+
local success, data =
return mw.loadData(moduleName)
+
pcall(
end)
+
function()
  +
return mw.loadData(moduleName)
  +
end
 
)
   
 
if not success then
 
if not success then
success, data = pcall(function()
+
success, data =
return mw.loadData(name)
+
pcall(
end)
+
function()
  +
return mw.loadData(name)
  +
end
  +
)
 
end
 
end
  +
 
 
return success, data
 
return success, data
end
 
 
function util.randomBetweenOneAnd(frame)
 
return math.random(frame.args[1])
 
 
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) left.t[#left.t+1] = right end,
+
__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 c = { "format-" .. tostring(this.c,16) } end
+
if this.c then
for k,v in pairs(this.fmt) do
+
c = {"format-" .. tostring(this.c, 16)}
if v then c[#c+1] = "format-" .. k end
 
 
end
 
end
return table.concat(c," ")
+
for k, v in pairs(this.fmt) do
  +
if v then
 
c[#c + 1] = "format-" .. k
  +
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 = { ["#"] = "&#23;" }
+
local escapes = {["#"] = "&#23;"}
for i,v in ipairs({"\\", "/", "&", "<", ">"}) do
+
for i, v in ipairs({"\\", "/", "&", "<", ">"}) do
 
escapes[v] = v
 
escapes[v] = v
 
end
 
end
setmetatable(escapes, { __index = function(tab, key) return "\\" + key end })
+
setmetatable(
+
escapes,
  +
{__index = function(tab, key)
  +
return "\\" + key
  +
end}
  +
)
  +
 
local currblock = newblock()
 
local currblock = newblock()
local blocks = { currblock }
+
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 strings[#strings+1] = tostring(block) end
+
for i, block in ipairs(outblocks) do
return table.concat(strings,"")
+
strings[#strings + 1] = tostring(block)
  +
end
 
return table.concat(strings, "")
 
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 out:node(block) end
+
for i, block in ipairs(outblocks) do
  +
out:node(block)
  +
end
 
return tostring(out)
 
return tostring(out)
 
end
 
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
 
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 = {["#"] = "&#23;"}
    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