User:Esteis/man/xml2man

From Wiki
Jump to navigation Jump to search

A Lua script to compile standalone XML files into man pages. Run it with mtxrun --script ./xml2man.lua somefile.xml

-- Invocation:
--     mtxrun --script ./xml2man.lua somefile.xml

local formatters   = string.formatters
local reporters    = logs.reporters
local xmlserialize = xml.serialize
local xmlcollected = xml.collected
local xmltext      = xml.text
local xmlfirst     = xml.first
local xmlfilter    = xml.filter

-- there is no need for a newhandlers { name = "help", parent = "string" }

local function flagdata(flag)
    local name  = flag.at.name or ""
    local value = flag.at.value or ""
 -- local short = xmlfirst(s,"/short")
 -- local short = xmlserialize(short,xs)
    local short = xmltext(xmlfirst(flag,"/short")) or ""
    return name, value, short
end

local function exampledata(example)
    local command = xmltext(xmlfirst(example,"/command")) or ""
    local comment = xmltext(xmlfirst(example,"/comment")) or ""
    return command, comment
end

local function categorytitle(category)
    return xmltext(xmlfirst(category,"/title")) or ""
end

local exporters = logs.exporters

function exporters.man(specification,...)
    local root = xml.convert(specification.helpinfo or "")
    if not root then
        return
    end
    local xs = xml.gethandlers("string")
    xml.sethandlersfunction(xs,"short",function(e,handler) xmlserialize(e.dt,handler) end)
    xml.sethandlersfunction(xs,"ref",  function(e,handler) handler.handle("--"..e.at.name) end)
    local wantedcategories = select("#",...) == 0 and true or table.tohash { ... }
    local nofcategories = xml.count(root,"/application/flags/category")
    local name    = xmlfilter(root,"/application/metadata/entry[@name='name']/text()")
    local detail  = xmlfilter(root,"/application/metadata/entry[@name='detail']/text()") or name
    local version = xmlfilter(root,"/application/metadata/entry[@name='version']/text()") or "0.00"
    local banner  = specification.banner or detail or name
    --
    local result = { }
    --
    -- .TH "context" "1" "some date" "version" "ConTeXt" 
    -- we use a fake date as I don't want to polute the git repos
    --
    local runner = string.match(name,"^mtx%-(.*)")
    if runner then
        runner = formatters["mtxrun --script %s"](runner)
    else
        runner = name
    end
    --
    result[#result+1] = formatters[ [[.TH "%s" "1" "%s" "version %s" "%s" ]] ](name,os.date("01-01-%Y"),version,detail)
    result[#result+1] = formatters[ [[.SH "NAME" %s]] ] ()
    result[#result+1] = ".PP"
    result[#result+1] = formatters[ [[.SH "SYNOPSIS" ]] ](name)
    result[#result+1] = ".PP"
    result[#result+1] = formatters[ [[.SH \fB%s\fP [ \fIOPTIONS\fP ... ] [ \fIFILENAMES\fP ] ]] ](runner)
    result[#result+1] = formatters[ [[.SH "DESCRIPTION"\n%s\n ]] ](detail)
    --
    for category in xmlcollected(root,"/application/flags/category") do
        if nofcategories > 1 then
            result[#result+1] = formatters['.SH "OPTIONS: %s"'](string.upper(category.at.name or "all"))
        else
            result[#result+1] = '.SH "OPTIONS"'
        end
        local i = 1
        for subcategory in xmlcollected(category,"/subcategory") do
            -- separate subcategories visually
            if i > 1 then
                result[#result+1] = ".TP"
                result[#result+1] = "----"
            end
            i = i+1
            -- print flags in subcategory
            for flag in xmlcollected(subcategory,"/flag") do
                local name, value, short = flagdata(flag)
                if value == "" then
                    result[#result+1] = formatters[".TP\n.B --%s\n%s"](name,short)
                else
                    result[#result+1] = formatters[".TP\n.B --%s=%s\n%s"](name,value,short)
                end
            end
        end
    end
    result[#result+1] = formatters['.SH "AUTHOR"\n%s'](specification.moreinfo)
    return table.concat(result,"\n")
end

-- Main program starts here
if not (arg[1]) then
    print("Please specify the XML file you want to convert to man")
    print("Example invocation:")
    print("    mtxrun --script ./xml2man.lua context.xml")
else
    local t = { }
    outputfile = string.gsub(arg[1], "xml", "man")
    io.input(arg[1])
    io.output(outputfile)
    t.helpinfo = io.read("*all")
    io.write(exporters.man(t))
end

[link title]