模块: Faketex

此模块的文档可以在模块:Faketex/doc创建

local p = {}

local function make_cell(class, text)
    local span = mw.html.create('span')
        :addClass(class)
        :wikitext(text)
    return span:done()
end

local function make_space(em)
    local span = mw.html.create('span')
        :addClass('mspace')
        :css('margin-right', em .. 'em')
    return span:done()
end

local function greek_to_latin(text)
    text = mw.ustring.gsub(text, 'Α', 'A')
    text = mw.ustring.gsub(text, 'Β', 'B')
    text = mw.ustring.gsub(text, 'Ε', 'E')
    text = mw.ustring.gsub(text, 'Ζ', 'Z')
    text = mw.ustring.gsub(text, 'Η', 'H')
    text = mw.ustring.gsub(text, 'Ι', 'I')
    text = mw.ustring.gsub(text, 'Κ', 'K')
    text = mw.ustring.gsub(text, 'Μ', 'M')
    text = mw.ustring.gsub(text, 'Ν', 'N')
    text = mw.ustring.gsub(text, 'Ο', 'O')
    text = mw.ustring.gsub(text, 'Ρ', 'P')
    text = mw.ustring.gsub(text, 'Τ', 'T')
    text = mw.ustring.gsub(text, 'Χ', 'X')
    return text
end

local function text_to_math_symbol(text)
    text = mw.ustring.gsub(text, '-', '−')
    text = mw.ustring.gsub(text, '*', '∗')
    return text
end

local function preprocess_text(text)
    text = mw.ustring.gsub(text, '-', '−')
    text = mw.ustring.gsub(text, '\Alpha%f[^%a]', ' Α')
    text = mw.ustring.gsub(text, '\alpha%f[^%a]', ' α')
    text = mw.ustring.gsub(text, '\Beta%f[^%a]', ' Β')
    text = mw.ustring.gsub(text, '\beta%f[^%a]', ' β')
    text = mw.ustring.gsub(text, '\Gamma%f[^%a]', ' Γ')
    text = mw.ustring.gsub(text, '\gamma%f[^%a]', ' γ')
    text = mw.ustring.gsub(text, '\Delta%f[^%a]', ' Δ')
    text = mw.ustring.gsub(text, '\delta%f[^%a]', ' δ')
    text = mw.ustring.gsub(text, '\Epsilon%f[^%a]', ' Ε')
    text = mw.ustring.gsub(text, '\epsilon%f[^%a]', ' ϵ')
    text = mw.ustring.gsub(text, '\varepsilon%f[^%a]', ' ε')
    text = mw.ustring.gsub(text, '\Zeta%f[^%a]', ' Ζ')
    text = mw.ustring.gsub(text, '\zeta%f[^%a]', ' ζ')
    text = mw.ustring.gsub(text, '\Eta%f[^%a]', ' Η')
    text = mw.ustring.gsub(text, '\eta%f[^%a]', ' η')
    text = mw.ustring.gsub(text, '\Theta%f[^%a]', ' Θ')
    text = mw.ustring.gsub(text, '\theta%f[^%a]', ' θ')
    text = mw.ustring.gsub(text, '\vartheta%f[^%a]', ' ϑ')
    text = mw.ustring.gsub(text, '\Iota%f[^%a]', ' Ι')
    text = mw.ustring.gsub(text, '\iota%f[^%a]', ' ι')
    text = mw.ustring.gsub(text, '\Kappa%f[^%a]', ' Κ')
    text = mw.ustring.gsub(text, '\kappa%f[^%a]', ' κ')
    text = mw.ustring.gsub(text, '\varkappa%f[^%a]', ' ϰ')
    text = mw.ustring.gsub(text, '\Lambda%f[^%a]', ' Λ')
    text = mw.ustring.gsub(text, '\lambda%f[^%a]', ' λ')
    text = mw.ustring.gsub(text, '\Mu%f[^%a]', ' Μ')
    text = mw.ustring.gsub(text, '\mu%f[^%a]', ' μ')
    text = mw.ustring.gsub(text, '\Nu%f[^%a]', ' Ν')
    text = mw.ustring.gsub(text, '\nu%f[^%a]', ' ν')
    text = mw.ustring.gsub(text, '\Xi%f[^%a]', ' Ξ')
    text = mw.ustring.gsub(text, '\xi%f[^%a]', ' ξ')
    text = mw.ustring.gsub(text, '\Omicron%f[^%a]', ' Ο')
    text = mw.ustring.gsub(text, '\omicron%f[^%a]', ' ο')
    text = mw.ustring.gsub(text, '\Pi%f[^%a]', ' Π')
    text = mw.ustring.gsub(text, '\pi%f[^%a]', ' π')
    text = mw.ustring.gsub(text, '\varpi%f[^%a]', ' ϖ')
    text = mw.ustring.gsub(text, '\Rho%f[^%a]', ' Ρ')
    text = mw.ustring.gsub(text, '\rho%f[^%a]', ' ρ')
    text = mw.ustring.gsub(text, '\varrho%f[^%a]', ' ϱ')
    text = mw.ustring.gsub(text, '\Sigma%f[^%a]', ' Σ')
    text = mw.ustring.gsub(text, '\sigma%f[^%a]', ' σ')
    text = mw.ustring.gsub(text, '\varsigma%f[^%a]', ' ς')
    text = mw.ustring.gsub(text, '\Tau%f[^%a]', ' Τ')
    text = mw.ustring.gsub(text, '\tau%f[^%a]', ' τ')
    text = mw.ustring.gsub(text, '\Upsilon%f[^%a]', ' Υ')
    text = mw.ustring.gsub(text, '\upsilon%f[^%a]', ' υ')
    text = mw.ustring.gsub(text, '\Phi%f[^%a]', ' Φ')
    text = mw.ustring.gsub(text, '\phi%f[^%a]', ' ϕ')
    text = mw.ustring.gsub(text, '\varphi%f[^%a]', ' φ')
    text = mw.ustring.gsub(text, '\Chi%f[^%a]', ' Χ')
    text = mw.ustring.gsub(text, '\chi%f[^%a]', ' χ')
    text = mw.ustring.gsub(text, '\Psi%f[^%a]', ' Ψ')
    text = mw.ustring.gsub(text, '\psi%f[^%a]', ' ψ')
    text = mw.ustring.gsub(text, '\Omega%f[^%a]', ' Ω')
    text = mw.ustring.gsub(text, '\omega%f[^%a]', ' ω')
    text = mw.ustring.gsub(text, '\infty%f[^%a]', ' ∞')
    text = mw.ustring.gsub(text, '\([{}])', '%1')
    text = mw.ustring.gsub(text, '[%s]', '')

    return text
end

-- Simulate KaTeX subscripts/superscripts.
-- top is -2.55em for subscripts and -3.063em for superscripts.
local function make_supsub(base, top)
    local vlistr = base:tag('span')
        :addClass('msupsub')
        :tag('span')
        :addClass('vlist-t vlist-t2')
        :tag('span')
        :addClass('vlist-r')

    local outer = vlistr:tag('span')
        :addClass('vlist')
        :css('height', '0.1514em')
        :tag('span')
        :css('top', top)
        :css('margin-right', '0.05em')

    outer:tag('span')
        :addClass('pstrut')
        :css('height', '2.7em')

    local inner = outer:tag('span')
        :addClass('sizing reset-size6 size3 mtight')

    vlistr:tag('span')
        :addClass('vlist-s')

    return inner
end

function p._main(args)
    text = args[1] or args['text']
    if not text then
        return ''
    end

    -- Make <span class="katex">
    local katex = mw.html.create('span')
        :addClass('katex')

    weight = args['font-weight'] or 'inherit'
    katex:css('font-weight', weight)

    -- Make <span class="base">
    local base = katex:tag('span')
        :addClass('base')
    
    if args['sub'] then
        base = make_supsub(base, '-2.55em')
    elseif args['sup'] then
        base = make_supsub(base, '-3.063em')
    end

    -- Process text
    text = preprocess_text(text)

    -- CSS classes
    class_ord = 'mord'
    class_normal = 'mord mathnormal'

    if args['rm'] then
        class_normal = 'mord'
    end

    if args['bb'] then
        class_ord = 'mord mathbb'
        class_normal = 'mord mathbb'
    end

    if args['cal'] then
        class_ord = 'mord mathcal'
        class_normal = 'mord mathcal'
    end

    if args['it'] then
        class_ord = 'mord mathit'
        class_normal = 'mord mathit'
    end

    if args['space-before'] then
        space_before = tonumber(args['space-before'])
        if space_before then
            base:node(make_space(space_before))
        end
    end

    -- Iterate through characters
    -- Todo: deal with spacing properly
    for c in mw.ustring.gmatch(text, '.') do
        if mw.ustring.find(c, '[%d%.∞Α-Ω]') then
            base:node(make_cell(class_ord, greek_to_latin(c)))
        elseif mw.ustring.find(c, '[%a]') then
            base:node(make_cell(class_normal, c))
        elseif mw.ustring.find(c, '[%(%[{]') then
            base:node(make_cell('mopen', c))
        elseif mw.ustring.find(c, '[%)%]}]') then
            base:node(make_cell('mclose', c))
        elseif mw.ustring.find(c, '[+−*∗×⊕⊗]') then
            base:node(make_cell('mbin', text_to_math_symbol(c)))
        elseif mw.ustring.find(c, '[=:]') then
            base:node(make_cell('mrel', c))
        elseif mw.ustring.find(c, '[,;!]') then
            base:node(make_cell('mpunct', c))
            if not args['sub'] and not args['sup'] then
                base:node(make_space(.1667))
            end
        end
    end

    if args['space-after'] then
        space_after = tonumber(args['space-after'])
        if space_after then
            base:node(make_space(space_after))
        end
    end
    
    return tostring(katex:done())
end

function p.main(frame)
    return p._main(require('Module:Arguments').getArgs(frame))
end

return p