Module:FormatTemplate

Fra Slektshistoriewiki
Hopp til navigering Hopp til søk

This module is intended to format templates to make them readable.


It should work by recognizing every beginning that should not be intermingled: [[, {{, {{#, {{{


It will count how many levels deep you've gone.


It will add 4 times that many spaces before each pipe | in a non-[[ element, removing any now present


It will label the beginning and end with a color specific to the type of element even when it can't indent


It will return everything in a nowiki wrapper (excluding the color formatting)

local p={}

local MAXPOSN = 30000 -- usually 50000 was 3 seconds .. not right now though .. local HOLDABLE = {["{"] = true, ["["] = true, ["}"] = true, ["]"] = true} local ACTABLE = {["{"] = true, ["["] = true, ["}"] = true, ["]"] = true, ["|"] = true, [":"] = true} local MARKER = {["{{{"] = "|", ["{{"] = "|", ["{{#"] = ":", ["[["] = "|"} local MATCH = {["{{{"] = "}}}", ["{{#"] = "}}", ["{{"] = "}}", ["[["] = "]]"} local RENDER = {['{{{'] = { -- these are replaced by variables in module

   ['{{{'] = '</nowiki>{{{',
    ['}}}'] = '}}}',
    ['}}'] = '}}',
    [']]'] = ']]'
               }, ['{{#'] = { -- these will receive many different specific translations in module
    ['{{#'] = '{{#',
    ['}}}'] = '}}}',
    ['}}'] = '}}',
    [']]'] = ']]'
               }, ['{{'] = { -- these might eventually be expanded by the module, but not in the first versions (scotty, try and increase the power!)
    ['{{'] = '{{',
    ['}}}'] = '}}}',
    ['}}'] = '}}',
    [']]'] = ']]'
               }, ['[['] = { -- these can be left untouched, I think
    ['[['] = '[[',
    ['}}}'] = '}}}',
    ['}}'] = '}}',
    [']]'] = ']]'
               }}

local debuglog = ""
local text
local getletter -- this module is designed around reading ONCE, tracking state; getletter() gets each letter in text once
local out = ""
local flag = false -- true marks the end of the getletter() stream

function getContent(template)
    local title -- holds the result of the mw.title.xxx call
    if not(template) then
        title=mw.title.getCurrentTitle()
        if not(title) then return "error: failed to getCurrentTitle()" end
        local tdedoc=mw.ustring.match(title.fullText,"Template:(.-)/doc")
        if tdedoc then title=mw.title.new("Template:"..tdedoc) end -- SPECIAL CASE: Invoke in the template documentation processes the template instead
    else title=mw.title.new(page)
         if not (title) then return "error: failed to mw.title.new(" .. template .. ")" end
    end -- if not(template)
    return title.getContent(title) or ""
end

local function scanabort()
	flag = true
	return ":" -- an "actable" to prevent looping
end

function formatTemplate(text,importstack,posn,template) -- note template is just for the error message
    local debug=""
    local letter=""
    local output=""
    local outputtable={}
    posn=tonumber(posn) or 0
    if posn>0 then text=string.sub(text,posn,-1) end --- need to chop off the preceding text so it doesn't gmatch to it
    local stopposn = (string.find(text, "[^{}%[%]|:]", MAXPOSN))
    if stopposn then text= string.sub(text, 1, stopposn) end
    stack = {top = #importstack}
    for i = 0, stack.top do
        stack[i] = {}
        stack[i].feature = importstack[i]
    	stack[i].text = {}
    	stack[i].seg = 1 -- this is NOT ACCURATE, would need to be saved in the transition
    end
    stack.push = function(feature)
    	table.insert(stack[stack.top].text, out)
        stack.top = stack.top + 1
        stack[stack.top] = {}
        stack[stack.top].text = {RENDER[feature][feature]}
        stack[stack.top].seg = 1
        stack[stack.top].feature = feature
        out = ""
    end

    stack.pop = function(feature)
        local spillover = ""
        local pop = stack[stack.top].feature
        if (MATCH[pop] ~= feature and feature == "}}}") then
            feature = "}}"
            spillover = "}"
        end
        out = out .. RENDER[pop][feature]
        if (MATCH[pop] ~= feature) then
            out = out .. "<--- error? "
        end
        table.insert(stack[stack.top].text, out)
        table.insert(stack[stack.top - 1].text, table.concat(stack[stack.top].text))
        stack[stack.top] = nil
        stack.top = stack.top - 1
        out = ""
        return spillover
    end

    stack.field = function (letter)
        local ss = stack[stack.top].feature
        if (stack[stack.top].seg == 1 and letter == MARKER[ss]) then
            out = '' .. out .. '' .. letter
            stack[stack.top].seg = 2
        elseif (ss ~= "[[" and letter=="|") then
            out = out .. "
"..string.rep(" ",4*stack.top).."|" table.insert(stack[stack.top].text, out) stack[stack.top].seg = stack[stack.top].seg + 1 out = "" else out = out .. letter end end stack.write = function() -- out is a simple global variable for repeated concatenations; can't get too big though table.insert(stack[stack.top].text, out) out = "" end template=template or "" getletter = string.gmatch(text,".") out="" repeat local holding = "" repeat letter = letter or "" -- bug that dumps nil letters comes up in the out = out ..letter, NOT while not ACTABLE[letter] ... why? while not ACTABLE[letter] do out = out .. letter letter = getletter() or scanabort() end if HOLDABLE[letter] then holding = letter else stack.field(letter) end letter = "" until holding ~= "" or flag if #out>20 then stack.write() end letter=getletter() or scanabort() -- add the letter to the next feature being parsed if possible if (holding == "[") then -- either [[ or just ignore -- cases based on the next letter after "[" if (letter == "[") then stack.push("[[") letter = "" else out = out .. holding -- single [, treat normally end elseif (holding == "{") then -- cases based on the next letter after "{" if (letter == "{") then letter = getletter() or scanabort() if (letter == "#") then stack.push("{{#") letter = "" elseif (letter == "{") then stack.push("{{{") letter = "" else stack.push("{{") end end elseif (holding == "]") then if (letter == "]") then -- we have a ]] stack.pop("]]") letter = "" else out = out .. holding end elseif (holding == "}") then if (letter == "}") then letter = getletter() if letter == "}" then letter = stack.pop("}}}") else stack.pop("}}") end else out = out .. holding -- lone } is nothing end end until flag if stack.top>0 then out = string.sub(out, 1, -2) .. "<--- end of run --->
run incomplete." stack.write() local stackcrypt = "" for i = stack.top, 1, -1 do table.insert(stack[i-1].text, table.concat(stack[i].text)) stackcrypt = stackcrypt .. stack[i].feature end stackcrypt=string.gsub(stackcrypt,"{","<") stackcrypt=string.gsub(stackcrypt,"%[","(") stackcrypt=string.gsub(stackcrypt,"}",">") stackcrypt=string.gsub(stackcrypt,"%]",")") if string.len(text) >= MAXPOSN then out = out .. "
Note: due to restrictions on Lua time usage, runs are truncated at MAXPOSN characters"
           out = out .. "
To continue this run, preview or enter {{#invoke:FormatTemplate|format|page="..template.."|stack="..stackcrypt.."|position="..#text.."}}" else out = out .. "<br />''If you have an additional segment of template to process, preview or enter <nowiki>{{#invoke:FormatTemplate|format|page="..template.."|stack="..stackcrypt.."|position=0}}" end end output=table.concat(stack[0].text) .. out return output end function p.main(frame,fcn) local args=frame.args local parent=frame.getParent(frame) if parent then pargs=parent.args else pargs={} end page=args.page or pargs.page text = getContent(page) local stackcrypt=args.stack or pargs.stack or "" stackcrypt=mw.ustring.gsub(stackcrypt,"<","{") stackcrypt=mw.ustring.gsub(stackcrypt,"%(","[") stackcrypt=mw.ustring.gsub(stackcrypt,">","}") stackcrypt=mw.ustring.gsub(stackcrypt,"%)","]") local stack={} local posn=args.position or pargs.position or 0 local prowl=mw.ustring.gmatch(stackcrypt,"[^,%s]+") repeat local x=prowl() if x then table.insert(stack,x) end until not x fcn=fcn or args["function"] or pargs["function"] or "" fcn=mw.ustring.match(fcn,"%S+") -- text=text or args.text or pargs.text or args[1] or pargs[1] or "" -- doesn't work - gets interpreted or passed as "UNIQ..QINU", either way unusuable! local nowikisafehouse={} local nowikielementnumber=0 local prowl=mw.ustring.gmatch(text,"<nowiki>(.-)") repeat local nowikimatch=prowl() if not(nowikimatch) then break end nowikielementnumber=nowikielementnumber+1 table.insert(nowikisafehouse,nowikimatch) until false text=mw.ustring.gsub(text,"(.-)","<Module:FormatTemplate internal nowiki token>") -- this is the meat of the formatting if fcn=="format" then text=formatTemplate(text,stack,posn,page) end -- unprotect the nowikis from the template itself - but inactivate them on first display! for nw = 1,nowikielementnumber do text=mw.ustring.gsub(text,"<Module:FormatTemplate internal nowiki token>",""..nowikisafehouse[nw].."</nowiki>",1) end -- preprocess as nowiki-bounded text return frame:preprocess(""..text.."" .. "\n" .. debuglog)

end

function p.format(frame)

   return p.main(frame,"format")

end

return p