Модуль:FtlMarking: различия между версиями

Материал из Space Station 14 Вики
мНет описания правки
мНет описания правки
Строка 53: Строка 53:
     if attr_str == "" then return nil end
     if attr_str == "" then return nil end
     local params = {}
     local params = {}
    local function unquote_val(v)
        if not v then return v end
        v = trim(v)
        v = mw.ustring.gsub(v, "^"(.-)"$", "%1")
        v = mw.ustring.gsub(v, '^"(.-)"$', "%1")
        return v
    end
     for k, v in mw.ustring.gmatch(attr_str, "([%w_%-%:]+)%s*=%s*\"(.-)\"") do
     for k, v in mw.ustring.gmatch(attr_str, "([%w_%-%:]+)%s*=%s*\"(.-)\"") do
         params[mw.ustring.lower(k)] = v
         params[mw.ustring.lower(k)] = unquote_val(v)
     end
     end
     attr_str = mw.ustring.gsub(attr_str, "([%w_%-%:]+)%s*=%s*\"(.-)\"", "")
     attr_str = mw.ustring.gsub(attr_str, "([%w_%-%:]+)%s*=%s*\"(.-)\"", "")
     for k, v in mw.ustring.gmatch(attr_str, "([%w_%-%:]+)%s*=%s*([^%s%]]+)") do
     for k, v in mw.ustring.gmatch(attr_str, "([%w_%-%:]+)%s*=%s*([^%s%]]+)") do
         params[mw.ustring.lower(k)] = v
         params[mw.ustring.lower(k)] = unquote_val(v)
     end
     end
     attr_str = mw.ustring.gsub(attr_str, "([%w_%-%:]+)%s*=%s*([^%s%]]+)", "")
     attr_str = mw.ustring.gsub(attr_str, "([%w_%-%:]+)%s*=%s*([^%s%]]+)", "")
     local unnamed = mw.ustring.match(attr_str, "%s*\"(.-)\"")
 
     local unnamed = mw.ustring.match(attr_str, "%s*"(.-)"") or mw.ustring.match(attr_str, "%s*\"(.-)\"")
     if unnamed then
     if unnamed then
         params._value = unnamed
         params._value = unquote_val(unnamed)
        attr_str = mw.ustring.gsub(attr_str, "%s*"(.-)"", "", 1)
         attr_str = mw.ustring.gsub(attr_str, "%s*\"(.-)\"", "", 1)
         attr_str = mw.ustring.gsub(attr_str, "%s*\"(.-)\"", "", 1)
     end
     end
     if not params._value then
     if not params._value then
         local v = mw.ustring.match(attr_str, "%s*([^%s%]]+)")
         local v = mw.ustring.match(attr_str, "%s*([^%s%]]+)")
         if v then params._value = v end
         if v then params._value = unquote_val(v) end
     end
     end
     return params
     return params
end
end

Версия от 11:40, 5 февраля 2026

Для документации этого модуля может быть создана страница Модуль:FtlMarking/doc

local p = {}

local function apply_tag(tag, params, inner)
    local t = mw.ustring.lower(tag or "")
    if t == "bold" then
        return "<b>" .. inner .. "</b>"
    elseif t == "italic" then
        return "<i>" .. inner .. "</i>"
    elseif t == "bolditalic" then
        return "<i><b>" .. inner .. "</b></i>"
    elseif t == "bullet" then
        return "· " .. inner
    elseif t == "color" then
        local color = params and params._value or ""
        return '<span style="color:' .. color .. ';">' .. inner .. '</span>'
    elseif t == "head" then
        local level = params and tonumber(params._value) or 1
        level = math.max(1, math.min(3, level))
        local defaultSize = 100
        local size = math.ceil(defaultSize * 2 / math.sqrt(level))
        return '<span style="font-weight:bold; font-size:' .. size .. '%;">' .. inner .. '</span>'
    elseif t == "font" then
        local family = params and params._value or nil
        local size = params and tonumber(params.size) or nil
        local style_parts = {}
        if family and family ~= "" then
            table.insert(style_parts, "font-family:" .. family)
        end
        if size and size ~= "" then
            table.insert(style_parts, "font-size:" .. size .. "px")
        end
        if #style_parts == 0 then
            return '<span>' .. inner .. '</span>'
        else
            return '<span style="' .. table.concat(style_parts, "; ") .. ';">' .. inner .. '</span>'
        end
    else
        return inner
    end
end

local function trim(s)
    if not s then return s end
    s = mw.ustring.gsub(s, "^%s+", "")
    s = mw.ustring.gsub(s, "%s+$", "")
    return s
end

local function parse_attrs(attr_str)
    if not attr_str then return nil end
    attr_str = mw.ustring.gsub(attr_str, "^%s*&#61;%s*", "")
    attr_str = trim(attr_str)
    if attr_str == "" then return nil end
    local params = {}

    local function unquote_val(v)
        if not v then return v end
        v = trim(v)
        v = mw.ustring.gsub(v, "^&#34;(.-)&#34;$", "%1")
        v = mw.ustring.gsub(v, '^"(.-)"$', "%1")
        return v
    end

    for k, v in mw.ustring.gmatch(attr_str, "([%w_%-%:]+)%s*&#61;%s*\"(.-)\"") do
        params[mw.ustring.lower(k)] = unquote_val(v)
    end
    attr_str = mw.ustring.gsub(attr_str, "([%w_%-%:]+)%s*&#61;%s*\"(.-)\"", "")

    for k, v in mw.ustring.gmatch(attr_str, "([%w_%-%:]+)%s*&#61;%s*([^%s%]]+)") do
        params[mw.ustring.lower(k)] = unquote_val(v)
    end
    attr_str = mw.ustring.gsub(attr_str, "([%w_%-%:]+)%s*&#61;%s*([^%s%]]+)", "")

    local unnamed = mw.ustring.match(attr_str, "%s*&#34;(.-)&#34;") or mw.ustring.match(attr_str, "%s*\"(.-)\"")
    if unnamed then
        params._value = unquote_val(unnamed)
        attr_str = mw.ustring.gsub(attr_str, "%s*&#34;(.-)&#34;", "", 1)
        attr_str = mw.ustring.gsub(attr_str, "%s*\"(.-)\"", "", 1)
    end

    if not params._value then
        local v = mw.ustring.match(attr_str, "%s*([^%s%]]+)")
        if v then params._value = unquote_val(v) end
    end

    return params
end

local function convert_lists(s)
    if not s or s == "" then return s end
    local lines = mw.text.split(s, "\n")
    local first_non_empty = nil
    local first_non_empty_unescaped = nil

    for i, line in ipairs(lines) do
        if line and line:match("%S") then
            first_non_empty = line
            first_non_empty_unescaped = mw.ustring.gsub(line, "&#32;", " ")
            break
        end
    end

    local enable_numeric = false
    if first_non_empty_unescaped and mw.ustring.match(first_non_empty_unescaped, "^%s*%d+%.") then
        enable_numeric = true
    end

    local out_lines = {}
    for _, line in ipairs(lines) do
        local processed = line
        local handled = false
        local line_unescaped = mw.ustring.gsub(line, "&#32;", " ")

        if enable_numeric then
            local leading, num, rest = mw.ustring.match(line_unescaped, "^(%s*)(%d+)%.%s*(.*)$")
            if num then
                local indent = mw.ustring.len(leading or "")
                local level = math.floor(indent / 2)
                local hashes = string.rep('#', 1 + level)
                processed = hashes .. (rest ~= "" and (" " .. rest) or "")
                table.insert(out_lines, processed)
                handled = true
            end
        end

        if not handled then
            local leading, rest = mw.ustring.match(line_unescaped, "^(%s*)%-%s+(.*)$")
            if rest then
                local indent = mw.ustring.len(leading or "")
                local level = math.floor(indent / 2)
                local stars = string.rep('*', 1 + level)
                processed = stars .. (rest ~= "" and (" " .. rest) or "")
                table.insert(out_lines, processed)
                handled = true
            end
        end

        if not handled then
            table.insert(out_lines, processed)
        end
    end

    return table.concat(out_lines, "\n")
end

local function transform(s)
    s = s or ""
    s = mw.ustring.gsub(s, "%[tooltip([^%]]*)%]", function(raw_attrs)
        local params = parse_attrs(raw_attrs)
        local tip = ""
        local visible = ""
        if params then
            if params.tooltip then tip = params.tooltip end
            if params.text then visible = params.text end
            if visible == "" and params._value then visible = params._value end
            if tip == "" and params._value and visible ~= params._value then tip = params._value end
        end
        visible = mw.ustring.gsub(visible, "|", "&#124;")
        tip = mw.ustring.gsub(tip, "|", "&#124;")
        return "{{tooltip|" .. (visible or "") .. "||" .. (tip or "") .. "}}"
    end)
    while true do
        local c_s, c_e, c_tag = mw.ustring.find(s, "%[/([%w_]+)%]")
        if not c_s then break end
        local last_o_s, last_o_e = nil, nil
        local search_pos = 1
        while true do
            local a, b = mw.ustring.find(s, "%[" .. c_tag .. "[^%]]*%]", search_pos)
            if not a or a > c_s then break end
            last_o_s, last_o_e = a, b
            search_pos = b + 1
        end
        if not last_o_s then
            s = mw.ustring.sub(s, 1, c_s - 1) .. mw.ustring.sub(s, c_e + 1)
        else
            local inner = mw.ustring.sub(s, last_o_e + 1, c_s - 1)
            local _, _, raw_attrs = mw.ustring.find(s, "%[" .. c_tag .. "([^%]]*)%]", last_o_s)
            local params = parse_attrs(raw_attrs)
            local replacement = apply_tag(c_tag, params, inner)
            s = mw.ustring.sub(s, 1, last_o_s - 1) .. replacement .. mw.ustring.sub(s, c_e + 1)
        end
    end
    s = mw.ustring.gsub(s, "%[/?[%w_]+[^%]]*%]", "")
    s = convert_lists(s)
    return s
end

local function process_nowiki_equals(str)
    str = str:gsub('#', '&#35;')
             :gsub('=', '&#61;')
             :gsub(' ', '&#32;')
             :gsub('{', '&#123;')
             :gsub('"', '&#34;')
             :gsub("'", '&#10;')
             :gsub('*', '&#42;')
    return str
end

function p.main(frame)
    local args = frame.args or {}
    local text = args[1] or args.text or ""
    text = mw.text.unstripNoWiki(text)
    text = process_nowiki_equals(text)
    return frame:preprocess(transform(text))
end

return p