Modul:TemplUtl

Aus ÖsterreichWiki
Version vom 17. Februar 2019, 19:15 Uhr von w>Felix Koenig~dewiki (Änderungen von PerfektesChaos (Diskussion) auf die letzte Version von Mabschaaf zurückgesetzt)
Zur Navigation springen Zur Suche springen

Die Dokumentation für dieses Modul kann unter Modul:TemplUtl/Doku erstellt werden

--[=[ 2014-11-24
TemplUtl
]=]



local fiatTitleRegExp = function ( accept )
    -- Create pattern to detect page name
    -- Precondition:
    --     accept  -- string; trimmed title
    -- Postcondition:
    --     Returns string with pattern
    local r;
    local start = mw.ustring.sub( accept, 1, 1 );
    if mw.ustring.match( start, "%a" ) then
        r = string.format( "[%s%s]%s",
                           mw.ustring.lower( start ),
                           mw.ustring.upper( start ),
                           mw.ustring.sub( accept, 2 ) );
    else
        r = accept;
    end
    if r:match( " " ) then
        r = r:gsub( "%", "%%" )
             :gsub( "[^.?+*()$]+", "%$1" )
             :gsub( "_", " " )
             :gsub( "%s+", "[%s_]+" );
    end
    return r;
end -- fiatTitleRegExp()



local TemplUtl = { };



TemplUtl.feasible = function ( address )
    -- Does this describe an URL beginning?
    -- Precondition:
    --    address  -- string; what to inspect, URL presumed
    -- Postcondition:
    --     Returns true, if URL beginning
    local start, r = address:match( "^%s*((%a*:?)//)" );
    if start then
        if r == "" then
            r = true;
        elseif r:sub( -1, -1 ) == ":" then
            local schemes = ":ftp:ftps:http:https:";
            r = ":" .. r:lower();
            if schemes:find( r, 1, true ) then
                r = true;
            else
                r = false;
            end
        else
            r = false;
        end
    end
    return r;
end -- TemplUtl.feasible()



TemplUtl.feed = function ( area, ahead, at, after )
    -- Detect next free "|" or "}}"
    -- Precondition:
    --     area   -- string; template transclusion
    --     ahead  -- string; opening element, or false
    --     at     -- number; byte position in area where to start
    --     after  -- true, if only to search for "}}"
    -- Postcondition:
    --     Returns
    --          -- number; byte position in area
    --             -- before "|" or "}}", may be at end
    --             -- to continue search; ahead has been closed
    --          -- true, if to be continued at number
    local j    = at;
    local loop = true;
    local c, k, r, s, seek;
    if after then
        seek = "[{}<]";
    else
        seek = "[%[%]|{}<:]";
    end
    while loop do
        j = area:find( seek, j );
        if j then
            c = area:byte( j, j );
            if c == 123 then    -- {
                k = j + 1;
                if area:byte( k, k ) == 123 then
                    k = k + 1;
                    if area:byte( k, k ) == 123 then
                        j, loop = TemplUtl.feed( area, "{{{", k, after );
                    else
                        k = k - 1;
                        j, loop = TemplUtl.feed( area, "{{", k, after );
                    end
                    if not loop then
                        r = j;
                    end
                end
            elseif c == 125 then    -- }
                k = j + 1;
                if area:byte( k, k ) == 125 then
                    if ahead == "{{" then
                        r = k;
                        break;    -- while loop;
                    elseif ahead == "{{{" then
                        k = k + 1;
                        if area:byte( k, k ) == 125 then
                            r = k;
                            break;    -- while loop;
                        end
                    elseif not ahead then
                        r    = j - 1;
                        loop = false;
                    end
                end
            elseif c == 60 then    -- <
                k = j + 3;
                if area:sub( j, k ) == "<!--" then
                    k = area:find( "-->", k );
                    if k then
                        j = k + 2;
                    end
                else
                    local skip;
                    s    = area:sub( j + 1 ):lower();
                    skip = s:match( "^%s*nowiki%s*>" );
                    if skip then
                        local n = skip:len();
                        n, k = s:find( "<%s*/%s*nowiki%s*>", n );
                        if k then
                            j = j + k;
                        else
                            loop = false;
                        end
                    end
                end
            elseif c == 124 then    -- |
                if not r then
                    r = j - 1;
                end
                if not ahead then
                    loop = false;
                end
            elseif c == 91 then    -- [
                k = j + 1;
                if area:byte( k, k ) == 91 then
                    k = k + 1;
                    j, loop = TemplUtl.feed( area, "[[", k, after );
                elseif TemplUtl.feasible( area:sub( k ) ) then
                    k = k + 3;
                    j, loop = TemplUtl.feed( area, "[", k, after );
                end
                if not loop then
                    r = j;
                end
            elseif c == 93 then    -- ]
                if ahead == "[" then
                    r = j;
                    break;    -- while loop
                elseif ahead == "[[" then
                    k = j + 1;
                    if area:byte( k, k ) == 93 then
                        r = k;
                        break;    -- while loop
                    end
                end
            elseif c == 58 then    -- :
                s = area:sub( j + 1,  j + 2 );
                if s == "//" then
                    s = " " .. area:sub( 1,  j + 2 );
                    s = s:match( "%s(%a+://)$" );
                    if s  and  TemplUtl.feasible( s ) then
                        s = area .. " ";
                        s = s:match( "([^%s|]+)%s", j );
                        if s then
                            k = s:find( "}}" );
                            if k then
                                j = j + k + 1;
                            else
                                j = j + s:len();
                            end
                        end
                    end
                end
            end
            j = j + 1;
        else
            loop = false;
        end
    end -- while loop
    if not r then
        r = area:len();
    end
    return r, loop;
end -- TemplUtl.feed()



TemplUtl.feeder = function ( area, at )
    -- Retrieve all parameters
    -- Precondition:
    --     area   -- string; template transclusion
    --     at     -- optional number; byte position in area of "{{"
    -- Postcondition:
    --     Returns  table
    --              [0] template, page, parser function name
    local n = 0;
    local j, k, p, r, r2, s, v;
    if type( at ) == "number" then
        j = at + 2;
    else
        j = 3;
    end
    while true do
        k = TemplUtl.feed( area, false, j );
        s = area:sub( j, k );
        s = s:gsub( "<!--.*-->", "" );
        if n == 0 then
            r = { [ 0 ] = s };
            n = 1;
        else
            p, v = s:match( "^([^=]*)=(.*)$" );
            if p then
                if p:match( "^%s*%d+%s*$" )  then
                    p = tonumber( p );
                else
                    p = mw.text.trim( p );
                end
                v = mw.text.trim( v );
            else
                p = n;
                v = s;
                n = n + 1;
            end
            if r[ p ] then
                if r2 then
                    r2 = r2 .. " * ";
                else
                    r2 = "";
                end
                r2 = string.format( "%s%s '%s'",
                                    r2,
                                    "duplicated parameter",
                                    tostring( p ) );
            end
            r[ p ] = v;
        end
        s = area:sub( k + 1,  k + 2 );
        if s == "}}" then
            break;    -- while true
        elseif s == "" then
            r2 = "template not closed";
            break;    -- while true
        end
        j = k + 2;
    end -- while true
    return r, r2;
end -- TemplUtl.feeder()



TemplUtl.fetch = function ( area, ask )
    -- Find assignment of a named template parameter
    -- Precondition:
    --     area  -- string; template transclusion
    --     ask   -- string; parameter name
    -- Postcondition:
    --     Returns string with trimmed parameter value, or nil
    --     Does not return value if template inside
    local r;
    local scan = string.format( "%s%s%s",
                                "|%s*", ask, "%s*=(.+)$" );
    r = mw.ustring.match( area, scan );
    if r then
        local j = TemplUtl.feed( r, false, 1 );
        r = r:sub( 1, j );
        if r then
            r = mw.text.trim( r );
            if r == "" then
                r = nil;
            end
        end
    end
    return r;
end -- TemplUtl.fetch()



TemplUtl.find = function ( area, access, at, alter )
    -- Find next occurrence of a template
    -- Precondition:
    --     area    -- string; where to search
    --     access  -- string; trimmed (template) title
    --     at      -- optional number; ustring position in area, if not 1
    --     alter   -- optional string; lowercase namespace pattern
    --                                 "" for article
    --                                 no colon (:)
    -- Postcondition:
    --     Returns ustring position of "{{" in area, or false
    -- Requires:
    --     fiatTitleRegExp()
    local r, space, start, suffix;
    local scan = string.format( "{{%s%s%s",
                                "([%w_%s:]*)%s*",
                                fiatTitleRegExp( access ),
                                "%s*([|}<]!?)" );
    if type( at ) == "number" then
        r = at;
    else
        r = 1;
    end
    while true do
        r = mw.ustring.find( area, scan, r );
        if r then
            start, suffix = mw.ustring.match( area, scan, r );
            if start then
                start = mw.text.trim( start );
                if start == "" then
                    break; -- while true
                elseif alter then
                    if not space then
                        space = string.format( "^:?%s:$", alter );
                    end
                    start = mw.ustring.lower( start );
                    if mw.ustring.match( start, space ) then
                        break; -- while true
                    end
                else
                    start = start:match( "^:?(.+):$" );
                    if start then
                        start = mw.ustring.lower( start );
                        if start == "template" then
                            break; -- while true
                        else
                            if not space then
                                space = mw.site.namespaces[ 10 ].name;
                                space = mw.ustring.lower( space );
                            end
                            start = start:gsub( "_", " " )
                                         :gsub( "%s+", " " );
                            if start == space then
                                break; -- while true
                            end
                        end
                    end
                end
            else
                break; -- while true
            end
            r = r + 2;
        else
            r = false;
            break; -- while true
        end
    end -- while true
    return r;
end -- TemplUtl.find()



-- Export
local p = { };

p.TemplUtl = function ()
    return TemplUtl;
end

return p;