if not modules then modules = { } end modules ['meta-imp-txt'] = {
    version   = 1.001,
    comment   = "companion to meta-imp-txt.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files",
}

local setmetatableindex = table.setmetatableindex
local settings_to_array = utilities.parsers.settings_to_array

local texget       = tex.get
local texset       = tex.set
local texgetcount  = tex.getcount
local texgetglue   = tex.getglue

local expandmacro  = token.expandmacro or token.expand_macro -- todo

local implement    = interfaces.implement

local scan         = mp.scan
local scannumeric  = scan.numeric
local scaninteger  = scan.integer
local scanboolean  = scan.boolean
local scanstring   = scan.string

local bpfactor     <const> = number.dimenfactors.bp

local context      = context

local parshapes    = { }
local properties   = { }

metapost.registerscript("setparshapeproperty", function()
    local k = scanstring()
    if k == "line" then
        local entry  = properties.shape[scannumeric()]
        local indent = scannumeric() / bpfactor
        local width  = scannumeric() / bpfactor
        entry[1] = indent
        entry[2] = width
    elseif k == "lines" then
        properties.lines = scaninteger()
        properties.shape = setmetatableindex(function(t,k)
            local v = { 0, properties.width or 0 }
            t[k] = v
            return v
        end)
    elseif k == "first" then
        properties[k] = scanboolean()
    elseif k == "inspect" then
        inspect(properties)
    else
        properties[k] = scannumeric() / bpfactor
    end
end)

implement {
    name      = "setparagraphmetashape",
    public    = true,
    protected = true,
    arguments = { "optional", "optional" },      -- array
    actions   = function(list,options)
        if list and list ~= "" then
            list    = settings_to_array(list)    -- array
            options = settings_to_array(options) -- array
            if #list > 0 then
                parshapes  = { }
                properties = { }
                for i=1,#list do
                    properties = { }
                    parshapes[i] = properties
                    expandmacro("spac_shapes_calculate","{"..list[i].."}")
                end
                local t, n = { }, 0
                for i=1,#parshapes do
                    local p = parshapes[i]
                    local s = p.shape
                    if s then
                        for i=1,(p.lines or #s) do
                            n = n + 1
                            t[n] = s[i]
                        end
                    end
                end
                if n > 0 then
                    for i=1,#options do
                        t[options[i]] = true
                    end
                    texset("parshape",t)
                end
            end
        end
    end
}

-- implement {
--     name      = "resetparagraphmetashape",
--     public    = true,
--     protected = true,
--     actions   = function(list)
--         parshapes  = { }
--         properties = { }
--     end
-- }

implement {
    name      = "getshapeparameter",
    public    = true,
    arguments = "string",
    actions   = function(name)
        local index = texgetcount("shapetextindex")
        local value = parshapes[index][name]
        if type(value) == "boolean" then
            value = value and 1 or 0
        end
        context(value or 0) -- so the first check, for "lines" is always ok
    end
}

-- Another experiment: continuing parshapes with alternative definitions:
--
-- left d | right d | left d right d | both d | left d hsize d |
-- copy n | reset | repeat | done

do

    local scanners      = tokens.scanners
    local scanword      = scanners.word
    local scandimension = scanners.dimension
    local scanstring    = scanners.string
    local scancardinal  = scanners.cardinal

    implement {
        name      = "setparagraphshape",
        protected = true,
        actions   = function()
            local t = { }
            local n = 0
            local h = texget("hsize")
            local a = 0
            while true do
                local key = scanword()
              ::AGAIN::
                if key == "left" then
                    local l = scandimension()
                    key = scanword()
                    if key == "right" then
                        n = n + 1 ; t[n] = { l, a + h - l - scandimension() }
                    elseif key == "hsize" then
                        n = n + 1 ; t[n] = { l, a + scandimension() }
                    else
                        n = n + 1 ; t[n] = { l, a + h }
                        goto AGAIN
                    end
                elseif key == "right" then
                    n = n + 1 ; t[n] = { 0, a + h - scandimension() }
                elseif key == "both" then
                    local b = scandimension()
                    n = n + 1 ; t[n] = { b, a + h - b - b }
                elseif key == "copy" then
                    local c = scancardinal()
                    for i=1,c do
                        local m = n + 1
                        t[m] = t[n]
                        n = m
                    end
                elseif key == "done" then
                    -- in case the user ended with "done"
                    scanword()
                    break
                elseif key == "metapost" then
                    local list = settings_to_array(scanstring())    -- array
                    properties = { }
                    parshapes  = { }
                    for i=1,#list do
                        properties = { }
                        parshapes[i] = properties
                        expandmacro("spac_shapes_calculate","{"..list[i].."}")
                    end
                    for i=1,#parshapes do
                        local p = parshapes[i]
                        local s = p.shape
                        if s then
                            for i=1,(p.lines or #s) do
                                local si = s[i]
                                n = n + 1 ; t[n] = { si[1], a + si[2] }
                            end
                        end
                    end
                elseif key == "repeat" then
                    t["repeat"] = true
                elseif key == "delete" then
                    local c = scancardinal()
                    for i=1,c do
                        if n > 0 then
                            t[n] = nil
                            n = n - 1
                        else
                            break
                        end
                    end
                elseif key == "reset" then
                    n = n + 1 ; t[n] = { 0, a + h }
                    break
                elseif key == "absolute" then
                    local s = scanword()
                    local l = texgetglue("leftskip")
                    local r = texgetglue("rightskip")
                    if s == "left" then
                        a = l
                    elseif s == "right" then
                        a = r
                    elseif s == "both" then
                        a = l + r
                    else
                        a = l + r
                        goto AGAIN
                    end
                elseif key == "inspect" then
                    inspect(t)
                else
                    logs.report("system","bad key %a in paragraphshape",key)
                    break
                end
            end
            texset("parshape",t)
        end,
    }

    local NC = context.NC
    local NR = context.NR
    local VL = context.VL

    implement {
        name      = "showparagraphshape",
        protected = true,
        public    = true,
        actions   = function()
            local p = texget("parshape")
            if p then
                -- only english interface (for now)
                context.inleftmargin(
                    {
                        align   = "flushright",
                        strut   = "no",
                        width   = "0pt",
                     -- voffset = "-\\lineheight"
                    }, function()
                        context.starttabulate {
                            before = "",
                            after  = "",
                            unit   = "2pt",
                            rulethickness = ".1pt",
                            format = "|rb{\\smallinfofont}|lb{\\smallinfofont}|"
                        }
                            for i=1,#p do
                                NC() context("%P",p[i][1])
                                VL() context("%P",p[i][2])
                                NC() NR()
                            end
                        context.stoptabulate()
                    end
                )
            end
        end
    }

end
