diff options
| -rw-r--r-- | doc/context/manuals/allkind/mkiv-publications.pdf | bin | 286190 -> 411806 bytes | |||
| -rw-r--r-- | doc/context/manuals/allkind/mkiv-publications.tex | 2 | ||||
| -rw-r--r-- | tex/context/base/back-exp-div.lua | 23 | ||||
| -rw-r--r-- | tex/context/base/back-exp-html.lua | 52 | ||||
| -rw-r--r-- | tex/context/base/back-exp.lua | 2718 | ||||
| -rw-r--r-- | tex/context/base/back-exp.mkiv | 12 | ||||
| -rw-r--r-- | tex/context/base/buff-ver.mkiv | 75 | ||||
| -rw-r--r-- | tex/context/base/cont-new.mkiv | 2 | ||||
| -rw-r--r-- | tex/context/base/context-version.pdf | bin | 4439 -> 4436 bytes | |||
| -rw-r--r-- | tex/context/base/context.mkiv | 2 | ||||
| -rw-r--r-- | tex/context/base/enco-ini.mkiv | 70 | ||||
| -rw-r--r-- | tex/context/base/file-lib.lua | 2 | ||||
| -rw-r--r-- | tex/context/base/file-res.lua | 5 | ||||
| -rw-r--r-- | tex/context/base/font-mis.lua | 2 | ||||
| -rw-r--r-- | tex/context/base/font-otf.lua | 43 | ||||
| -rw-r--r-- | tex/context/base/status-files.pdf | bin | 24916 -> 24987 bytes | |||
| -rw-r--r-- | tex/context/base/status-lua.pdf | bin | 326318 -> 326325 bytes | |||
| -rw-r--r-- | tex/context/base/x-mathml.mkiv | 4 | ||||
| -rw-r--r-- | tex/generic/context/luatex/luatex-fonts-merged.lua | 27 | 
19 files changed, 1736 insertions, 1303 deletions
diff --git a/doc/context/manuals/allkind/mkiv-publications.pdf b/doc/context/manuals/allkind/mkiv-publications.pdf Binary files differindex f0fe7de0c..64a0b702b 100644 --- a/doc/context/manuals/allkind/mkiv-publications.pdf +++ b/doc/context/manuals/allkind/mkiv-publications.pdf diff --git a/doc/context/manuals/allkind/mkiv-publications.tex b/doc/context/manuals/allkind/mkiv-publications.tex index ea1e6359d..85750677e 100644 --- a/doc/context/manuals/allkind/mkiv-publications.tex +++ b/doc/context/manuals/allkind/mkiv-publications.tex @@ -2,6 +2,8 @@  % todo: doi and url +\enablemode[export] +  % criterium: all + sorttype=cite     => citex before rest  % criterium: all + sorttype=database => database order  % criterium: used diff --git a/tex/context/base/back-exp-div.lua b/tex/context/base/back-exp-div.lua new file mode 100644 index 000000000..4e67d7615 --- /dev/null +++ b/tex/context/base/back-exp-div.lua @@ -0,0 +1,23 @@ +return { +    name = "html export", +    version = "1.00", +    comment = "Experimental feature.", +    author = "Hans Hagen", +    copyright = "ConTeXt development team", +    suffix = "html", +    remapping = { +        { +            pattern = "*", +            element = "div", +            extras  = { +                namespace = true, -- okay as we have no attributes with that name +                align     = { +                    flushleft  = "left", +                    flushright = "right", +                    middle     = "center", +                } +            } +        }, +    } +} + diff --git a/tex/context/base/back-exp-html.lua b/tex/context/base/back-exp-html.lua new file mode 100644 index 000000000..e284c42dd --- /dev/null +++ b/tex/context/base/back-exp-html.lua @@ -0,0 +1,52 @@ +return { +    name = "html export", +    version = "1.00", +    comment = "Experimental feature.", +    author = "Hans Hagen", +    copyright = "ConTeXt development team", +    suffix = "html", +    remapping = { +        { +            pattern = "tabulate", +            element = "table", +            class   = "tabulate", +        }, +        { +            pattern = "tabulaterow", +            element = "tr", +            class   = "tabulate.tr", +        }, +        { +            pattern = "tabulatecell", +            element = "td", +            class   = "tabulate.td", +            extras  = { +                align = { +                    flushleft  = "tabulate.td.left", +                    flushright = "tabulate.td.right", +                    middle     = "tabulate.td.center", +                } +            } +        }, +        { +            pattern = "break", +            element = "br", +        }, +        { +            pattern = "section", +            element = "div", +        }, +        { +            pattern = "verbatimblock", +            element = "pre", +        }, +        { +            pattern = "verbatimlines|verbatimline", +            element = "div", +        }, +        { +            pattern = "!(div|table|td|tr|pre)", +            element = "div", +        }, +    } +} diff --git a/tex/context/base/back-exp.lua b/tex/context/base/back-exp.lua index 44c2cd539..d17fce135 100644 --- a/tex/context/base/back-exp.lua +++ b/tex/context/base/back-exp.lua @@ -6,7 +6,12 @@ if not modules then modules = { } end modules ['back-exp'] = {      license   = "see context related readme files"  } --- beware: we run out of the 200 local limit +-- Because we run into the 200 local limit we quite some do .. end wrappers .. not always +-- that nice but it has to be. + +-- Experiments demonstrated that mapping to <div> and classes is messy because we have to +-- package attributes (some 30) into one set of (space seperatated but prefixed classes) +-- which only makes things worse .. so if you want something else, use xslt to get there.  -- language       -> only mainlanguage, local languages should happen through start/stoplanguage  -- tocs/registers -> maybe add a stripper (i.e. just don't flush entries in final tree) @@ -23,7 +28,7 @@ if not modules then modules = { } end modules ['back-exp'] = {  -- todo: move critital formatters out of functions  -- todo: delay loading (apart from basic tag stuff) -local next, type = next, type +local next, type, tonumber = next, type, tonumber  local format, concat, sub, gsub = string.format, table.concat, string.sub, string.gsub  local validstring = string.valid  local lpegmatch = lpeg.match @@ -32,12 +37,15 @@ local insert, remove = table.insert, table.remove  local fromunicode16 = fonts.mappings.fromunicode16  local sortedhash = table.sortedhash  local formatters = string.formatters +local todimen = number.todimen  local trace_export  = false  trackers.register  ("export.trace",         function(v) trace_export  = v end)  local trace_spacing = false  trackers.register  ("export.trace.spacing", function(v) trace_spacing = v end)  local less_state    = false  directives.register("export.lessstate",     function(v) less_state    = v end)  local show_comment  = true   directives.register("export.comment",       function(v) show_comment  = v end) +show_comment = false -- figure out why break comment +  -- maybe we will also support these:  --  -- local css_hyphens       = false  directives.register("export.css.hyphens",      function(v) css_hyphens      = v end) @@ -49,7 +57,13 @@ local report_export     = logs.reporter("backend","export")  local nodes             = nodes  local attributes        = attributes +  local variables         = interfaces.variables +local v_yes             = variables.yes +local v_normal          = variables.normal +local v_flushright      = variables.flushright +local v_middle          = variables.middle +local v_flushleft       = variables.flushleft  local settings_to_array = utilities.parsers.settings_to_array @@ -85,15 +99,14 @@ local line_code         = listcodes.line  local texgetcount       = tex.getcount -local a_characters      = attributes.private('characters') -local a_exportstatus    = attributes.private('exportstatus') - -local a_tagged          = attributes.private('tagged') -local a_taggedpar       = attributes.private("taggedpar") -local a_image           = attributes.private('image') -local a_reference       = attributes.private('reference') - -local a_textblock       = attributes.private("textblock") +local privateattribute  = attributes.private +local a_characters      = privateattribute('characters') +local a_exportstatus    = privateattribute('exportstatus') +local a_tagged          = privateattribute('tagged') +local a_taggedpar       = privateattribute("taggedpar") +local a_image           = privateattribute('image') +local a_reference       = privateattribute('reference') +local a_textblock       = privateattribute("textblock")  local nuts              = nodes.nuts  local tonut             = nuts.tonut @@ -126,7 +139,7 @@ local stoptiming        = statistics.stoptiming  -- todo: more locals (and optimize) -local exportversion     = "0.30" +local exportversion     = "0.31"  local nofcurrentcontent = 0 -- so we don't free (less garbage collection)  local currentcontent    = { } @@ -152,6 +165,8 @@ local treestack         = { }  local nesting           = { }  local currentdepth      = 0 +local wrapups           = { } +  local tree              = { data = { }, fulltag == "root" } -- root  local treeroot          = tree  local treehash          = { } @@ -167,7 +182,8 @@ local somespace         = { [0x20] = true, [" "] = true } -- for testing  local entities          = { ["&"] = "&", [">"] = ">", ["<"] = "<" }  local attribentities    = { ["&"] = "&", [">"] = ">", ["<"] = "<", ['"'] = "quot;" } -local entityremapper    = utf.remapper(entities) +local p_entity          = lpeg.replacer(entities) -- was: entityremapper = utf.remapper(entities) +local p_attribute       = lpeg.replacer(attribentities)  local alignmapping = {      flushright = "right", @@ -176,10 +192,10 @@ local alignmapping = {  }  local numbertoallign = { -    [0] = "justify", ["0"] = "justify", [variables.normal    ] = "justify", -    [1] = "right",   ["1"] = "right",   [variables.flushright] = "right", -    [2] = "center",  ["2"] = "center",  [variables.middle    ] = "center", -    [3] = "left",    ["3"] = "left",    [variables.flushleft ] = "left", +    [0] = "justify", ["0"] = "justify", [v_normal    ] = "justify", +    [1] = "right",   ["1"] = "right",   [v_flushright] = "right", +    [2] = "center",  ["2"] = "center",  [v_middle    ] = "center", +    [3] = "left",    ["3"] = "left",    [v_flushleft ] = "left",  }  local defaultnature = "mixed" -- "inline" @@ -192,10 +208,13 @@ setmetatableindex(used, function(t,k)      end  end) +local f_entity    = formatters["&#x%X;"] +local f_attribute = formatters[" %s=%q"] +  setmetatableindex(specialspaces, function(t,k)      local v = utfchar(k)      t[k] = v -    entities[v] = formatters["&#x%X;"](k) +    entities[v] = f_entity(k)      somespace[k] = true      somespace[v] = true      return v @@ -242,9 +261,17 @@ setmetatableindex(namespaced, function(t,k)      end  end) +-- local function attribute(key,value) +--     if value and value ~= "" then +--         return f_attribute(key,gsub(value,".",attribentities)) +--     else +--         return "" +--     end +-- end +  local function attribute(key,value)      if value and value ~= "" then -        return formatters[' %s="%s"'](key,gsub(value,".",attribentities)) +        return f_attribute(key,lpegmatch(p_attribute,value))      else          return ""      end @@ -261,7 +288,7 @@ end  local listdata = { } -local function hashlistdata() +function wrapups.hashlistdata()      local c = structures.lists.collected      for i=1,#c do          local ci = c[i] @@ -292,86 +319,91 @@ function structurestags.setattributehash(fulltag,key,value) -- public hash      end  end +local usedstyles = { } --- experiment: styles and images --- --- officially we should convert to bp but we round anyway +do -local usedstyles = { } +    -- experiment: styles and images +    -- +    -- officially we should convert to bp but we round anyway --- /* padding      : ; */ --- /* text-justify : inter-word ; */ +    -- /* padding      : ; */ +    -- /* text-justify : inter-word ; */ -local documenttemplate = [[ +local f_document = formatters [ [[  document {      font-size  : %s !important ;      max-width  : %s !important ;      text-align : %s !important ;      hyphens    : %s !important ;  } -]] +]] ] -local styletemplate = [[ +local f_style = formatters [ [[  %s[detail='%s'] {      font-style   : %s ;      font-variant : %s ;      font-weight  : %s ;      font-family  : %s ;      color        : %s ; -}]] +}]] ] -local function allusedstyles(xmlfile) -    local result = { format("/* styles for file %s */",xmlfile) } -    -- -    local bodyfont = finetuning.bodyfont -    local width    = finetuning.width -    local hyphen   = finetuning.hyphen -    local align    = finetuning.align -    -- -    if not bodyfont or bodyfont == "" then -        bodyfont = "12pt" -    elseif type(bodyfont) == "number" then -        bodyfont = number.todimen(bodyfont,"pt","%ipt") or "12pt" -    end -    if not width or width == "" then -        width = "50em" -    elseif type(width) == "number" then -        width = number.todimen(width,"pt","%ipt") or "50em" -    end -    if hyphen == variables.yes then -        hyphen = "manual" -    else -        hyphen = "inherited" -    end -    if align then -        align = numbertoallign[align] -    end -    if not align then -        align = hyphens and "justify" or "inherited" +    function wrapups.allusedstyles(xmlfile) +        local result = { formatters["/* %s for file %s */"]("styles",xmlfile) } +        -- +        local bodyfont = finetuning.bodyfont +        local width    = finetuning.width +        local hyphen   = finetuning.hyphen +        local align    = finetuning.align +        -- +        if not bodyfont or bodyfont == "" then +            bodyfont = "12pt" +        elseif type(bodyfont) == "number" then +            bodyfont = todimen(bodyfont,"pt","%ipt") or "12pt" +        end +        if not width or width == "" then +            width = "50em" +        elseif type(width) == "number" then +            width = todimen(width,"pt","%ipt") or "50em" +        end +        if hyphen == v_yes then +            hyphen = "manual" +        else +            hyphen = "inherited" +        end +        if align then +            align = numbertoallign[align] +        end +        if not align then +            align = hyphens and "justify" or "inherited" +        end +        -- +        result[#result+1] = f_document(bodyfont,width,align,hyphen) +        -- +        local colorspecification = xml.css.colorspecification +        local fontspecification = xml.css.fontspecification +        for element, details in sortedhash(usedstyles) do +            for detail, data in sortedhash(details) do +                local s = fontspecification(data.style) +                local c = colorspecification(data.color) +                result[#result+1] = f_style(element,detail, +                    s.style   or "inherit", +                    s.variant or "inherit", +                    s.weight  or "inherit", +                    s.family  or "inherit", +                    c         or "inherit") +            end +        end +        return concat(result,"\n\n")      end -    -- -    result[#result+1] = format(documenttemplate,bodyfont,width,align,hyphen) -    -- -    local colorspecification = xml.css.colorspecification -    local fontspecification = xml.css.fontspecification -    for element, details in sortedhash(usedstyles) do -        for detail, data in sortedhash(details) do -            local s = fontspecification(data.style) -            local c = colorspecification(data.color) -            result[#result+1] = formatters[styletemplate](element,detail, -                s.style   or "inherit", -                s.variant or "inherit", -                s.weight  or "inherit", -                s.family  or "inherit", -                c         or "inherit") -        end -    end -    return concat(result,"\n\n") +  end  local usedimages = { } -local imagetemplate = [[ +do + +local f_image = formatters [ [[  %s[id="%s"] {      display           : block ;      background-image  : url(%s) ; @@ -379,36 +411,38 @@ local imagetemplate = [[      background-repeat : no-repeat ;      width             : %s ;      height            : %s ; -}]] - -local function allusedimages(xmlfile) -    local result = { format("/* images for file %s */",xmlfile) } -    for element, details in sortedhash(usedimages) do -        for detail, data in sortedhash(details) do -            local name = data.name -            if file.suffix(name) == "pdf" then -                -- temp hack .. we will have a remapper -                name = file.replacesuffix(name,"svg") +}]] ] + +    function wrapups.allusedimages(xmlfile) +        local result = { formatters["/* %s for file %s */"]("images",xmlfile) } +        for element, details in sortedhash(usedimages) do +            for detail, data in sortedhash(details) do +                local name = data.name +                if file.suffix(name) == "pdf" then +                    -- temp hack .. we will have a remapper +                    name = file.replacesuffix(name,"svg") +                end +                result[#result+1] = f_image(element,detail,name,data.width,data.height)              end -            result[#result+1] = formatters[imagetemplate](element,detail,name,data.width,data.height)          end +        return concat(result,"\n\n")      end -    return concat(result,"\n\n") -end -local function uniqueusedimages() -    local unique = { } -    for element, details in next, usedimages do -        for detail, data in next, details do -            local name = data.name -            if file.suffix(name) == "pdf" then -                unique[file.replacesuffix(name,"svg")] = name -            else -                unique[name] = name +    function wrapups.uniqueusedimages() +        local unique = { } +        for element, details in next, usedimages do +            for detail, data in next, details do +                local name = data.name +                if file.suffix(name) == "pdf" then +                    unique[file.replacesuffix(name,"svg")] = name +                else +                    unique[name] = name +                end              end          end +        return unique      end -    return unique +  end  -- @@ -447,198 +481,248 @@ local function makebreaknode(attributes) -- maybe no fulltag      }  end -local fields = { "title", "subtitle", "author", "keywords" } +do -local function checkdocument(root) -    local data = root.data -    if data then -        for i=1,#data do -            local di = data[i] -            local tg = di.tg -            if tg == "noexport" then -                local ud = userdata[di.fulltag] -                local comment = ud and ud.comment -                if comment then -                    di.element = "comment" -                    di.data = { { content = comment } } -                    ud.comment = nil +    local fields = { "title", "subtitle", "author", "keywords" } + +    local function checkdocument(root) +        local data = root.data +        if data then +            for i=1,#data do +                local di = data[i] +                local tg = di.tg +                if tg == "noexport" then +                    local ud = userdata[di.fulltag] +                    if ud then +                        local comment = ud.comment +                        if comment then +                            di.element = "comment" +                            di.data = { { content = comment } } +                            ud.comment = nil +                        else +                            data[i] = false +                        end +                    else +                        data[i] = false +                    end +                elseif di.content then +                    -- okay +                elseif tg == "ignore" then +                    di.element = "" +                    checkdocument(di)                  else -                    data[i] = false -                 -- di.element = "" -                 -- di.data = nil +                    checkdocument(di) -- new, else no noexport handling                  end -            elseif di.content then -                -- okay -            elseif tg == "ignore" then -                di.element = "" -                checkdocument(di) -            else -                checkdocument(di) -- new, else no noexport handling              end          end      end -end -function extras.document(result,element,detail,n,fulltag,di) -    result[#result+1] = format(" language=%q",languagenames[texgetcount("mainlanguagenumber")]) -    if not less_state then -        result[#result+1] = format(" file=%q",tex.jobname) -        result[#result+1] = format(" date=%q",os.date()) -        result[#result+1] = format(" context=%q",environment.version) -        result[#result+1] = format(" version=%q",exportversion) -        result[#result+1] = format(" xmlns:m=%q","http://www.w3.org/1998/Math/MathML") -        local identity = interactions.general.getidentity() -        for i=1,#fields do -            local key   = fields[i] -            local value = identity[key] -            if value and value ~= "" then -                result[#result+1] = formatters[" %s=%q"](key,value) +    function extras.document(result,element,detail,n,fulltag,di) +        result[#result+1] = f_attribute("language",languagenames[texgetcount("mainlanguagenumber")]) +        if not less_state then +            result[#result+1] = f_attribute("file",tex.jobname) +            result[#result+1] = f_attribute("date",os.date()) +            result[#result+1] = f_attribute("context",environment.version) +            result[#result+1] = f_attribute("version",exportversion) +            result[#result+1] = f_attribute("xmlns:m","http://www.w3.org/1998/Math/MathML") +            local identity = interactions.general.getidentity() +            for i=1,#fields do +                local key   = fields[i] +                local value = identity[key] +                if value and value ~= "" then +                    result[#result+1] = f_attribute(key,value) +                end              end          end +        checkdocument(di)      end -    checkdocument(di) +  end -local itemgroups = { } +do -function structurestags.setitemgroup(current,packed,symbol) -    itemgroups[detailedtag("itemgroup",current)] = { -        packed = packed, -        symbol = symbol, -    } -end +    local itemgroups = { } -function extras.itemgroup(result,element,detail,n,fulltag,di) -    local hash = itemgroups[fulltag] -    if hash then -        local v = hash.packed -        if v then -            result[#result+1] = " packed='yes'" -        end -        local v = hash.symbol -        if v then -            result[#result+1] = attribute("symbol",v) +    local f_symbol   = formatters[" symbol='%s'"] +    local s_packed   = " packed='yes'" + +    function structurestags.setitemgroup(current,packed,symbol) +        itemgroups[detailedtag("itemgroup",current)] = { +            packed = packed, +            symbol = symbol, +        } +    end + +    function extras.itemgroup(result,element,detail,n,fulltag,di) +        local hash = itemgroups[fulltag] +        if hash then +            local packed = hash.packed +            if packed then +                result[#result+1] = s_packed +            end +            local symbol = hash.symbol +            if symbol then +                result[#result+1] = f_symbol(symbol) +            end          end      end +  end -local synonyms = { } +do -function structurestags.setsynonym(current,tag) -    synonyms[detailedtag("synonym",current)] = tag -end +    local synonyms = { } +    local sortings = { } + +    local f_tag    = formatters[" tag='%s'"] -function extras.synonym(result,element,detail,n,fulltag,di) -    local tag = synonyms[fulltag] -    if tag then -        result[#result+1] = formatters[" tag='%s'"](tag) +    function structurestags.setsynonym(current,tag) +        synonyms[detailedtag("synonym",current)] = tag      end -end -local sortings = { } +    function extras.synonym(result,element,detail,n,fulltag,di) +        local tag = synonyms[fulltag] +        if tag then +            result[#result+1] = f_tag(tag) +        end +    end -function structurestags.setsorting(current,tag) -    sortings[detailedtag("sorting",current)] = tag -end +    function structurestags.setsorting(current,tag) +        sortings[detailedtag("sorting",current)] = tag +    end -function extras.sorting(result,element,detail,n,fulltag,di) -    local tag = sortings[fulltag] -    if tag then -        result[#result+1] = formatters[" tag='%s'"](tag) +    function extras.sorting(result,element,detail,n,fulltag,di) +        local tag = sortings[fulltag] +        if tag then +            result[#result+1] = f_tag(tag) +        end      end +  end -usedstyles.highlight = { } +do + +    local highlight      = { } +    usedstyles.highlight = highlight + +    function structurestags.sethighlight(current,style,color) -- we assume global styles +        highlight[current] = { +            style = style, -- xml.css.fontspecification(style), +            color = color, -- xml.css.colorspec(color), +        } +    end -function structurestags.sethighlight(current,style,color) -- we assume global styles -    usedstyles.highlight[current] = { -        style = style, -- xml.css.fontspecification(style), -        color = color, -- xml.css.colorspec(color), -    }  end -local descriptions = { } -local symbols      = { } -local linked       = { } +do -function structurestags.setdescription(tag,n) -    local nd = structures.notes.get(tag,n) -- todo: use listdata instead -    if nd then -        local references = nd.references -        descriptions[references and references.internal] = detailedtag("description",tag) +    local descriptions = { } +    local symbols      = { } +    local linked       = { } + +    local f_insert     = formatters[" insert='%s'"] + +    function structurestags.setdescription(tag,n) +        local nd = structures.notes.get(tag,n) -- todo: use listdata instead +        if nd then +            local references = nd.references +            descriptions[references and references.internal] = detailedtag("description",tag) +        end      end -end -function structurestags.setdescriptionsymbol(tag,n) -    local nd = structures.notes.get(tag,n) -- todo: use listdata instead -    if nd then -        local references = nd.references -        symbols[references and references.internal] = detailedtag("descriptionsymbol",tag) +    function structurestags.setdescriptionsymbol(tag,n) +        local nd = structures.notes.get(tag,n) -- todo: use listdata instead +        if nd then +            local references = nd.references +            symbols[references and references.internal] = detailedtag("descriptionsymbol",tag) +        end      end -end -function finalizers.descriptions(tree) -    local n = 0 -    for id, tag in next, descriptions do -        local sym = symbols[id] -        if sym then -            n = n + 1 -            linked[tag] = n -            linked[sym] = n +    function finalizers.descriptions(tree) +        local n = 0 +        for id, tag in next, descriptions do +            local sym = symbols[id] +            if sym then +                n = n + 1 +                linked[tag] = n +                linked[sym] = n +            end          end      end -end -function extras.description(result,element,detail,n,fulltag,di) -    local id = linked[fulltag] -    if id then -        result[#result+1] = formatters[" insert='%s'"](id) -- maybe just fulltag +    function extras.description(result,element,detail,n,fulltag,di) +        local id = linked[fulltag] +        if id then +            result[#result+1] = f_insert(id) -- maybe just fulltag +        end      end -end -function extras.descriptionsymbol(result,element,detail,n,fulltag,di) -    local id = linked[fulltag] -    if id then -        result[#result+1] = formatters[" insert='%s'"](id) +    function extras.descriptionsymbol(result,element,detail,n,fulltag,di) +        local id = linked[fulltag] +        if id then +            result[#result+1] = f_insert(id) +        end      end +  end -usedimages.image = { } +-- -- todo: ignore breaks +-- +-- function extras.verbatimline(result,element,detail,n,fulltag,di) +--     inspect(di) +-- end -function structurestags.setfigure(name,page,width,height) -    usedimages.image[detailedtag("image")] = { -        name   = name, -        page   = page, -        width  = number.todimen(width, "cm","%0.3Fcm"), -        height = number.todimen(height,"cm","%0.3Fcm"), -    } -end +do + +    local image       = { } +    usedimages.image  = image + +    local f_imagespec = formatters[" id='%s' width='%s' height='%s'"] +    local f_imagepage = formatters[" page='%s'"] + +    function structurestags.setfigure(name,page,width,height) +        image[detailedtag("image")] = { +            name   = name, +            page   = page, +            width  = todimen(width, "cm","%0.3Fcm"), +            height = todimen(height,"cm","%0.3Fcm"), +        } +    end -function extras.image(result,element,detail,n,fulltag,di) -    local data = usedimages.image[fulltag] -    if data then -        result[#result+1] = attribute("name",data.name) -        if tonumber(data.page) > 1 then -            result[#result+1] = formatters[" page='%s'"](data.page) +    function extras.image(result,element,detail,n,fulltag,di) +        local data = image[fulltag] +        if data then +            result[#result+1] = attribute("name",data.name) +            local page = tonumber(data.page) +            if page and page > 1 then +                result[#result+1] = f_imagepage(page) +            end +            result[#result+1] = f_imagespec(fulltag,data.width,data.height)          end -        result[#result+1] = formatters[" id='%s' width='%s' height='%s'"](fulltag,data.width,data.height)      end +  end -local combinations = { } +do -function structurestags.setcombination(nx,ny) -    combinations[detailedtag("combination")] = { -        nx = nx, -        ny = ny, -    } -end +    local combinations = { } + +    local f_combispec  = formatters[" nx='%s' ny='%s'"] -function extras.combination(result,element,detail,n,fulltag,di) -    local data = combinations[fulltag] -    if data then -        result[#result+1] = formatters[" nx='%s' ny='%s'"](data.nx,data.ny) +    function structurestags.setcombination(nx,ny) +        combinations[detailedtag("combination")] = { +            nx = nx, +            ny = ny, +        }      end + +    function extras.combination(result,element,detail,n,fulltag,di) +        local data = combinations[fulltag] +        if data then +            result[#result+1] = f_combispec(data.nx,data.ny) +        end +    end +  end  -- quite some code deals with exporting references  -- @@ -680,978 +764,1081 @@ evaluators.special = function(result,var)      end  end -evaluators["special outer with operation"]     = evaluators.special -evaluators["special operation"]                = evaluators.special -evaluators["special operation with arguments"] = evaluators.special +local referencehash = { } -function specials.url(result,var) -    local url = references.checkedurl(var.operation) -    if url then -        result[#result+1] = attribute("url",url) -    end -end +do -function specials.file(result,var) -    local file = references.checkedfile(var.operation) -    if file then -        result[#result+1] = attribute("file",file) +    evaluators["special outer with operation"]     = evaluators.special +    evaluators["special operation"]                = evaluators.special +    evaluators["special operation with arguments"] = evaluators.special + +    local f_location    = formatters[" location='aut:%s'"] +    local f_prefix      = formatters[" prefix='%s'"] +    local f_destination = formatters[" destination='%s'"] +    local f_reference   = formatters[" reference='%s'"] +    local f_url         = formatters[" url='%s'"] +    local f_file        = formatters[" file='%s'"] + +    function specials.url(result,var) +        local url = references.checkedurl(var.operation) +        if url and url ~= "" then +            result[#result+1] = f_url(url) +        end      end -end -function specials.fileorurl(result,var) -    local file, url = references.checkedfileorurl(var.operation,var.operation) -    if url then -        result[#result+1] = attribute("url",url) -    elseif file then -        result[#result+1] = attribute("file",file) +    function specials.file(result,var) +        local file = references.checkedfile(var.operation) +        if file and file ~= "" then +            result[#result+1] = f_file(file) +        end      end -end -function specials.internal(result,var) -    local internal = references.checkedurl(var.operation) -    if internal then -        result[#result+1] = formatters[" location='aut:%s'"](internal) +    function specials.fileorurl(result,var) +        local file, url = references.checkedfileorurl(var.operation,var.operation) +        if url and url ~= "" then +            result[#result+1] = f_url(url) +        elseif file and file ~= "" then +            result[#result+1] = f_file(file) +        end      end -end -local referencehash = { } +    function specials.internal(result,var) +        local internal = references.checkedurl(var.operation) +        if internal then +            result[#result+1] = f_location(internal) +        end +    end -local function adddestination(result,references) -- todo: specials -> exporters and then concat -    if references then -        local reference = references.reference -        if reference and reference ~= "" then -            local prefix = references.prefix -            if prefix and prefix ~= "" then -                result[#result+1] = formatters[" prefix='%s'"](prefix) -            end -            result[#result+1] = formatters[" destination='%s'"](reference) -            for i=1,#references do -                local r = references[i] -                local e = evaluators[r.kind] -                if e then -                    e(result,r) +    local function adddestination(result,references) -- todo: specials -> exporters and then concat +        if references then +            local reference = references.reference +            if reference and reference ~= "" then +                local prefix = references.prefix +                if prefix and prefix ~= "" then +                    result[#result+1] = f_prefix(prefix) +                end +                result[#result+1] = f_destination(reference) +                for i=1,#references do +                    local r = references[i] +                    local e = evaluators[r.kind] +                    if e then +                        e(result,r) +                    end                  end              end          end      end -end -local function addreference(result,references) -    if references then -        local reference = references.reference -        if reference and reference ~= "" then -            local prefix = references.prefix -            if prefix and prefix ~= "" then -                result[#result+1] = formatters[" prefix='%s'"](prefix) +    local function addreference(result,references) +        if references then +            local reference = references.reference +            if reference and reference ~= "" then +                local prefix = references.prefix +                if prefix and prefix ~= "" then +                    result[#result+1] = f_prefix(prefix) +                end +                result[#result+1] = f_reference(reference) +            end +            local internal = references.internal +            if internal and internal ~= "" then +                result[#result+1] = f_location(internal)              end -            result[#result+1] = formatters[" reference='%s'"](reference) -        end -        local internal = references.internal -        if internal and internal ~= "" then -            result[#result+1] = formatters[" location='aut:%s'"](internal)          end      end -end -function extras.link(result,element,detail,n,fulltag,di) -    -- for instance in lists a link has nested elements and no own text -    local reference = referencehash[fulltag] -    if reference then -        adddestination(result,structures.references.get(reference)) -        return true -    else -        local data = di.data -        if data then -            for i=1,#data do -                local di = data[i] -                if di then -                    local fulltag = di.fulltag -                    if fulltag and extras.link(result,element,detail,n,fulltag,di) then -                        return true +    local function link(result,element,detail,n,fulltag,di) +        -- for instance in lists a link has nested elements and no own text +        local reference = referencehash[fulltag] +        if reference then +            adddestination(result,structures.references.get(reference)) +            return true +        else +            local data = di.data +            if data then +                for i=1,#data do +                    local di = data[i] +                    if di then +                        local fulltag = di.fulltag +                        if fulltag and link(result,element,detail,n,fulltag,di) then +                            return true +                        end                      end                  end              end          end      end + +    extras.adddestination = adddestination +    extras.addreference   = addreference +    extras.link           = link +  end  -- no settings, as these are obscure ones -local automathrows   = true  directives.register("backend.export.math.autorows",   function(v) automathrows   = v end) -local automathapply  = true  directives.register("backend.export.math.autoapply",  function(v) automathapply  = v end) -local automathnumber = true  directives.register("backend.export.math.autonumber", function(v) automathnumber = v end) -local automathstrip  = true  directives.register("backend.export.math.autostrip",  function(v) automathstrip  = v end) - -local functions      = mathematics.categories.functions - -local function collapse(di,i,data,ndata,detail,element) -    local collapsing = di.data -    if data then -        di.element = element -        di.detail = nil -        i = i + 1 -        while i <= ndata do -            local dn = data[i] -            if dn.detail == detail then -                collapsing[#collapsing+1] = dn.data[1] -                dn.skip = "ignore" -                i = i + 1 -            else -                break +do + +    local automathrows   = true  directives.register("backend.export.math.autorows",   function(v) automathrows   = v end) +    local automathapply  = true  directives.register("backend.export.math.autoapply",  function(v) automathapply  = v end) +    local automathnumber = true  directives.register("backend.export.math.autonumber", function(v) automathnumber = v end) +    local automathstrip  = true  directives.register("backend.export.math.autostrip",  function(v) automathstrip  = v end) + +    local functions      = mathematics.categories.functions + +    local function collapse(di,i,data,ndata,detail,element) +        local collapsing = di.data +        if data then +            di.element = element +            di.detail = nil +            i = i + 1 +            while i <= ndata do +                local dn = data[i] +                if dn.detail == detail then +                    collapsing[#collapsing+1] = dn.data[1] +                    dn.skip = "ignore" +                    i = i + 1 +                else +                    break +                end              end          end +        return i      end -    return i -end -local function collapse_mn(di,i,data,ndata) -    local collapsing = di.data -    if data then -        i = i + 1 -        while i <= ndata do -            local dn = data[i] -            local tg = dn.tg -            if tg == "mn" then -                collapsing[#collapsing+1] = dn.data[1] -                dn.skip = "ignore" -                i = i + 1 -            elseif tg == "mo" then -                local d = dn.data[1] -                if d == "." then -                    collapsing[#collapsing+1] = d +    local function collapse_mn(di,i,data,ndata) +        local collapsing = di.data +        if data then +            i = i + 1 +            while i <= ndata do +                local dn = data[i] +                local tg = dn.tg +                if tg == "mn" then +                    collapsing[#collapsing+1] = dn.data[1]                      dn.skip = "ignore"                      i = i + 1 +                elseif tg == "mo" then +                    local d = dn.data[1] +                    if d == "." then +                        collapsing[#collapsing+1] = d +                        dn.skip = "ignore" +                        i = i + 1 +                    else +                        break +                    end                  else                      break                  end -            else -                break              end          end +        return i      end -    return i -end --- maybe delay __i__ till we need it +    -- maybe delay __i__ till we need it -local apply_function = { -    { -        element = "mo", -     -- comment = "apply function", -     -- data    = { utfchar(0x2061) }, -        data    = { "⁡" }, -        nature  = "mixed", +    local apply_function = { +        { +            element = "mo", +         -- comment = "apply function", +         -- data    = { utfchar(0x2061) }, +            data    = { "⁡" }, +            nature  = "mixed", +        }      } -} -local functioncontent = { } +    local functioncontent = { } -setmetatableindex(functioncontent,function(t,k) -    local v = { { content = k } } -    t[k] = v -    return v -end) +    setmetatableindex(functioncontent,function(t,k) +        local v = { { content = k } } +        t[k] = v +        return v +    end) -local function checkmath(root) -- we can provide utf.toentities as an option -    local data = root.data -    if data then -        local ndata = #data -        local roottg = root.tg -        if roottg == "msubsup" then -            local nucleus, superscript, subscript -            for i=1,ndata do -                local di = data[i] -                if not di then -                    -- weird -                elseif di.content then -                    -- text -                elseif not nucleus then -                    nucleus = i -                elseif not superscript then -                    superscript = i -                elseif not subscript then -                    subscript = i -                else -                    -- error -                end -            end -            if superscript and subscript then -                local sup, sub = data[superscript], data[subscript] -                data[superscript], data[subscript] = sub, sup -             -- sub.__o__, sup.__o__ = subscript, superscript -                sub.__i__, sup.__i__ = superscript, subscript -            end -        elseif roottg == "mfenced" then -            local new, n = { }, 0 -            local attributes = { } -            root.attributes = attributes -            for i=1,ndata do -                local di = data[i] -                if not di then -                    -- weird -                elseif di.content then -                    n = n + 1 -                    new[n] = di -                else -                    local tg = di.tg -                    if tg == "mleft" then -                        attributes.left   = tostring(di.data[1].data[1].content) -                    elseif tg == "mmiddle" then -                        attributes.middle = tostring(di.data[1].data[1].content) -                    elseif tg == "mright" then -                        attributes.right  = tostring(di.data[1].data[1].content) +    local function checkmath(root) -- we can provide utf.toentities as an option +        local data = root.data +        if data then +            local ndata = #data +            local roottg = root.tg +            if roottg == "msubsup" then +                local nucleus, superscript, subscript +                for i=1,ndata do +                    local di = data[i] +                    if not di then +                        -- weird +                    elseif di.content then +                        -- text +                    elseif not nucleus then +                        nucleus = i +                    elseif not superscript then +                        superscript = i +                    elseif not subscript then +                        subscript = i                      else +                        -- error +                    end +                end +                if superscript and subscript then +                    local sup, sub = data[superscript], data[subscript] +                    data[superscript], data[subscript] = sub, sup +                 -- sub.__o__, sup.__o__ = subscript, superscript +                    sub.__i__, sup.__i__ = superscript, subscript +                end +            elseif roottg == "mfenced" then +                local new, n = { }, 0 +                local attributes = { } +                root.attributes = attributes +                for i=1,ndata do +                    local di = data[i] +                    if not di then +                        -- weird +                    elseif di.content then                          n = n + 1 -                        di.__i__ = n                          new[n] = di +                    else +                        local tg = di.tg +                        if tg == "mleft" then +                            attributes.left   = tostring(di.data[1].data[1].content) +                        elseif tg == "mmiddle" then +                            attributes.middle = tostring(di.data[1].data[1].content) +                        elseif tg == "mright" then +                            attributes.right  = tostring(di.data[1].data[1].content) +                        else +                            n = n + 1 +                            di.__i__ = n +                            new[n] = di +                        end                      end                  end +                root.data = new +                ndata = n              end -            root.data = new -            ndata = n -        end -        if ndata == 0 then -            return -        elseif ndata == 1 then -            local d = data[1] -            if not d then -                return -            elseif d.content then +            if ndata == 0 then                  return -            elseif #root.data == 1 then -                local tg = d.tg -                if automathrows and roottg == "mrow" then -                    -- maybe just always ! check spec first -                    if tg == "mrow" or tg == "mfenced" or tg == "mfrac" or tg == "mroot" or tg == "msqrt"then -                        root.skip = "comment" -                    elseif tg == "mo" then -                        root.skip = "comment" -                    end -                elseif roottg == "mo" then -                    if tg == "mo" then -                        root.skip = "comment" +            elseif ndata == 1 then +                local d = data[1] +                if not d then +                    return +                elseif d.content then +                    return +                elseif #root.data == 1 then +                    local tg = d.tg +                    if automathrows and roottg == "mrow" then +                        -- maybe just always ! check spec first +                        if tg == "mrow" or tg == "mfenced" or tg == "mfrac" or tg == "mroot" or tg == "msqrt"then +                            root.skip = "comment" +                        elseif tg == "mo" then +                            root.skip = "comment" +                        end +                    elseif roottg == "mo" then +                        if tg == "mo" then +                            root.skip = "comment" +                        end                      end                  end              end -        end -        local i = 1 -        while i <= ndata do                   -- -- -- TOO MUCH NESTED CHECKING -- -- -- -            local di = data[i] -            if di and not di.content then -                local tg = di.tg -                local detail = di.detail -                if tg == "math" then -                 -- di.element = "mrow" -- when properties -                    di.skip = "comment" -                    checkmath(di) -                    i = i + 1 -                elseif tg == "mover" or tg == "munder" or tg == "munderover" then -                    if detail == "accent" then -                        di.attributes = { accent = "true" } -                        di.detail = nil -                    end -                    checkmath(di) -                    i = i + 1 -                elseif tg == "mroot" then -                    if #di.data == 1 then -                        -- else firefox complains -                        di.element = "msqrt" -                    end -                    checkmath(di) -                    i = i + 1 -                elseif tg == "break" then -                    di.skip = "comment" -                    i = i + 1 -                elseif tg == "mrow" and detail then -                    di.detail = nil -                    checkmath(di) -                    di = { -                        element    = "maction", -                        nature     = "display", -                        attributes = { actiontype = detail }, -                        data       = { di }, -                        n          = 0, -                    } -                    data[i] = di -                    i = i + 1 -                elseif detail then -                 -- no checkmath(di) here -                    local category = tonumber(detail) or 0 -                    if category == 1 then -- mo -                        i = collapse(di,i,data,ndata,detail,"mo") -                    elseif category == 2 then -- mi -                        i = collapse(di,i,data,ndata,detail,"mi") -                    elseif category == 3 then -- mn -                        i = collapse(di,i,data,ndata,detail,"mn") -                    elseif category == 4 then -- ms -                        i = collapse(di,i,data,ndata,detail,"ms") -                    elseif category >= 1000 then -                        local apply = category >= 2000 -                        if apply then -                            category = category - 1000 +            local i = 1 +            while i <= ndata do                   -- -- -- TOO MUCH NESTED CHECKING -- -- -- +                local di = data[i] +                if di and not di.content then +                    local tg = di.tg +                    local detail = di.detail +                    if tg == "math" then +                     -- di.element = "mrow" -- when properties +                        di.skip = "comment" +                        checkmath(di) +                        i = i + 1 +                    elseif tg == "mover" or tg == "munder" or tg == "munderover" then +                        if detail == "accent" then +                            di.attributes = { accent = "true" } +                            di.detail = nil                          end -                        if tg == "mi" then -- function -                            if roottg == "mrow" then -                                root.skip = "comment" -                                root.element = "function" -                            end +                        checkmath(di) +                        i = i + 1 +                    elseif tg == "mroot" then +                        if #di.data == 1 then +                            -- else firefox complains +                            di.element = "msqrt" +                        end +                        checkmath(di) +                        i = i + 1 +                    elseif tg == "break" then +                        di.skip = "comment" +                        i = i + 1 +                    elseif tg == "mrow" and detail then +                        di.detail = nil +                        checkmath(di) +                        di = { +                            element    = "maction", +                            nature     = "display", +                            attributes = { actiontype = detail }, +                            data       = { di }, +                            n          = 0, +                        } +                        data[i] = di +                        i = i + 1 +                    elseif detail then +                     -- no checkmath(di) here +                        local category = tonumber(detail) or 0 +                        if category == 1 then -- mo +                            i = collapse(di,i,data,ndata,detail,"mo") +                        elseif category == 2 then -- mi                              i = collapse(di,i,data,ndata,detail,"mi") -                            local tag = functions[category] -                            if tag then -                                di.data = functioncontent[tag] -                            end +                        elseif category == 3 then -- mn +                            i = collapse(di,i,data,ndata,detail,"mn") +                        elseif category == 4 then -- ms +                            i = collapse(di,i,data,ndata,detail,"ms") +                        elseif category >= 1000 then +                            local apply = category >= 2000                              if apply then -                                di.after = apply_function -                            elseif automathapply then -- make function -                                local following -                                if i <= ndata then -                                    -- normally not the case -                                    following = data[i] -                                else -                                    local parent = di.__p__ -- == root -                                    if parent.tg == "mrow" then -                                        parent = parent.__p__ -                                    end -                                    local index = parent.__i__ -                                    following = parent.data[index+1] +                                category = category - 1000 +                            end +                            if tg == "mi" then -- function +                                if roottg == "mrow" then +                                    root.skip = "comment" +                                    root.element = "function"                                  end -                                if following then -                                    local tg = following.tg -                                    if tg == "mrow" or tg == "mfenced" then -- we need to figure out the right condition -                                        di.after = apply_function +                                i = collapse(di,i,data,ndata,detail,"mi") +                                local tag = functions[category] +                                if tag then +                                    di.data = functioncontent[tag] +                                end +                                if apply then +                                    di.after = apply_function +                                elseif automathapply then -- make function +                                    local following +                                    if i <= ndata then +                                        -- normally not the case +                                        following = data[i] +                                    else +                                        local parent = di.__p__ -- == root +                                        if parent.tg == "mrow" then +                                            parent = parent.__p__ +                                        end +                                        local index = parent.__i__ +                                        following = parent.data[index+1] +                                    end +                                    if following then +                                        local tg = following.tg +                                        if tg == "mrow" or tg == "mfenced" then -- we need to figure out the right condition +                                            di.after = apply_function +                                        end                                      end                                  end +                            else -- some problem +                                checkmath(di) +                                i = i + 1                              end -                        else -- some problem +                        else                              checkmath(di)                              i = i + 1                          end +                    elseif automathnumber and tg == "mn" then +                        checkmath(di) +                        i = collapse_mn(di,i,data,ndata)                      else                          checkmath(di)                          i = i + 1                      end -                elseif automathnumber and tg == "mn" then -                    checkmath(di) -                    i = collapse_mn(di,i,data,ndata) -                else -                    checkmath(di) +                else -- can be string or boolean +                    if parenttg ~= "mtext" and di == " " then +                        data[i] = false +                    end                      i = i + 1                  end -            else -- can be string or boolean -                if parenttg ~= "mtext" and di == " " then -                    data[i] = false -                end -                i = i + 1              end          end      end -end -function stripmath(di) -    if not di then -        -- -    elseif di.content then -        return di -    else -        local tg = di.tg -        if tg == "mtext" or tg == "ms" then +    function stripmath(di) +        if not di then +            -- +        elseif di.content then              return di          else -            local data = di.data -            local ndata = #data -            local n = 0 -            for i=1,ndata do -                local di = data[i] -                if di and not di.content then -                    di = stripmath(di) -                end -                if di then -                    local content = di.content -                    if not content then -                        n = n + 1 -                        di.__i__ = n -                        data[n] = di -                    elseif content == " " or content == "" then -                        -- skip -                    else -                        n = n + 1 -                        data[n] = di +            local tg = di.tg +            if tg == "mtext" or tg == "ms" then +                return di +            else +                local data = di.data +                local ndata = #data +                local n = 0 +                for i=1,ndata do +                    local di = data[i] +                    if di and not di.content then +                        di = stripmath(di) +                    end +                    if di then +                        local content = di.content +                        if not content then +                            n = n + 1 +                            di.__i__ = n +                            data[n] = di +                        elseif content == " " or content == "" then +                            -- skip +                        else +                            n = n + 1 +                            data[n] = di +                        end                      end                  end -            end -            for i=ndata,n+1,-1 do -                data[i] = nil -            end -            if #data > 0 then -                return di +                for i=ndata,n+1,-1 do +                    data[i] = nil +                end +                if #data > 0 then +                    return di +                end              end          end      end -end -function checks.math(di) -    local hash = attributehash[di.fulltag] -    local mode = (hash and hash.mode) == "display" and "block" or "inline" -    di.attributes = { -        display = mode -    } -    -- can be option if needed: -    if mode == "inline" then -        di.nature = "mixed" -- else spacing problem (maybe inline) -    else -        di.nature = "display" -    end -    if automathstrip then -        stripmath(di) +    function checks.math(di) +        local hash = attributehash[di.fulltag] +        local mode = (hash and hash.mode) == "display" and "block" or "inline" +        di.attributes = { +            display = mode +        } +        -- can be option if needed: +        if mode == "inline" then +            di.nature = "mixed" -- else spacing problem (maybe inline) +        else +            di.nature = "display" +        end +        if automathstrip then +            stripmath(di) +        end +        checkmath(di)      end -    checkmath(di) -end -local a, z, A, Z = 0x61, 0x7A, 0x41, 0x5A +    local a, z, A, Z = 0x61, 0x7A, 0x41, 0x5A -function extras.mi(result,element,detail,n,fulltag,di) -- check with content -    local str = di.data[1].content -    if str and sub(str,1,1) ~= "&" then -- hack but good enough (maybe gsub op eerste) -        for v in utfvalues(str) do -            if (v >= a and v <= z) or (v >= A and v <= Z) then -                local a = di.attributes -                if a then -                    a.mathvariant = "normal" -                else -                    di.attributes = { mathvariant = "normal" } +    function extras.mi(result,element,detail,n,fulltag,di) -- check with content +        local str = di.data[1].content +        if str and sub(str,1,1) ~= "&" then -- hack but good enough (maybe gsub op eerste) +            for v in utfvalues(str) do +                if (v >= a and v <= z) or (v >= A and v <= Z) then +                    local a = di.attributes +                    if a then +                        a.mathvariant = "normal" +                    else +                        di.attributes = { mathvariant = "normal" } +                    end                  end              end          end      end +  end -function extras.section(result,element,detail,n,fulltag,di) -    local data = listdata[fulltag] -    if data then -        addreference(result,data.references) -        return true -    else -        local data = di.data +do + +    local function section(result,element,detail,n,fulltag,di) +        local data = listdata[fulltag]          if data then -            for i=1,#data do -                local di = data[i] -                if di then -                    local ft = di.fulltag -                    if ft and extras.section(result,element,detail,n,ft,di) then -                        return true +            extras.addreference(result,data.references) +            return true +        else +            local data = di.data +            if data then +                for i=1,#data do +                    local di = data[i] +                    if di then +                        local ft = di.fulltag +                        if ft and section(result,element,detail,n,ft,di) then +                            return true +                        end                      end                  end              end          end      end -end -function extras.float(result,element,detail,n,fulltag,di) -    local data = listdata[fulltag] -    if data then -        addreference(result,data.references) -        return true -    else -        local data = di.data +    extras.section = section + +    function extras.float(result,element,detail,n,fulltag,di) +        local data = listdata[fulltag]          if data then -            for i=1,#data do -                local di = data[i] -                if di and extras.section(result,element,detail,n,di.fulltag,di) then -                    return true +            extras.addreference(result,data.references) +            return true +        else +            local data = di.data +            if data then +                for i=1,#data do +                    local di = data[i] +                    if di and section(result,element,detail,n,di.fulltag,di) then +                        return true +                    end                  end              end          end      end +  end -local tabledata = { } +do -function structurestags.settablecell(rows,columns,align) -    if align > 0 or rows > 1 or columns > 1 then -        tabledata[detailedtag("tablecell")] = { -            rows    = rows, -            columns = columns, -            align   = align, -        } -    end -end +    local tabledata    = { } + +    local f_columns    = formatters[" columns='%s'"] +    local f_rows       = formatters[" rows='%s'"] -function extras.tablecell(result,element,detail,n,fulltag,di) -    local hash = tabledata[fulltag] -    if hash then -        local v = hash.columns -        if v and v > 1 then -            result[#result+1] = formatters[" columns='%s'"](v) +    local s_flushright = " align='flushright'" +    local s_middle     = " align='middle'" +    local s_flushleft  = " align='flushleft'" + +    local function hascontent(data) +        for i=1,#data do +            local di = data[i] +            if not di then +                -- +            elseif di.content then +                return true +            else +                local d = di.data +                if d and #d > 0 and hascontent(d) then +                    return true +                end +            end          end -        local v = hash.rows -        if v and v > 1 then -            result[#result+1] = formatters[" rows='%s'"](v) +    end + +    function structurestags.settablecell(rows,columns,align) +        if align > 0 or rows > 1 or columns > 1 then +            tabledata[detailedtag("tablecell")] = { +                rows    = rows, +                columns = columns, +                align   = align, +            }          end -        local v = hash.align -        if not v or v == 0 then -            -- normal -        elseif v == 1 then -- use numbertoalign here -            result[#result+1] = " align='flushright'" -        elseif v == 2 then -            result[#result+1] = " align='middle'" -        elseif v == 3 then -            result[#result+1] = " align='flushleft'" +    end + +    function extras.tablecell(result,element,detail,n,fulltag,di) +        local hash = tabledata[fulltag] +        if hash then +            local columns = hash.columns +            if columns and columns > 1 then +                result[#result+1] = f_columns(columns) +            end +            local rows = hash.rows +            if rows and rows > 1 then +                result[#result+1] = f_rows(rows) +            end +            local align = hash.align +            if not align or align == 0 then +                -- normal +            elseif align == 1 then -- use numbertoalign here +                result[#result+1] = s_flushright +            elseif align == 2 then +                result[#result+1] = s_middle +            elseif align == 3 then +                result[#result+1] = s_flushleft +            end          end      end -end -local tabulatedata = { } +    local tabulatedata = { } -function structurestags.settabulatecell(align) -    if align > 0 then -        tabulatedata[detailedtag("tabulatecell")] = { -            align = align, -        } +    function structurestags.settabulatecell(align) +        if align > 0 then +            tabulatedata[detailedtag("tabulatecell")] = { +                align = align, +            } +        end      end -end -local function hascontent(data) -    for i=1,#data do -        local di = data[i] -        if not di then -            -- -        elseif di.content then -            return true -        else -            local d = di.data -            if d and #d > 0 and hascontent(d) then -                return true +    function extras.tabulate(result,element,detail,n,fulltag,di) +        local data = di.data +        for i=1,#data do +            local di = data[i] +            if di.tg == "tabulaterow" and not hascontent(di.data) then +                di.element = "" -- or simply remove              end          end      end -end -function extras.tabulate(result,element,detail,n,fulltag,di) -    local data = di.data -    for i=1,#data do -        local di = data[i] -        if di.tg == "tabulaterow" and not hascontent(di.data) then -            di.element = "" -- or simply remove +    function extras.tabulatecell(result,element,detail,n,fulltag,di) +        local hash = tabulatedata[fulltag] +        if hash then +            local align = hash.align +            if not align or align == 0 then +                -- normal +            elseif align == 1 then +                result[#result+1] = s_flushleft +            elseif align == 2 then +                result[#result+1] = s_flushright +            elseif align == 3 then +                result[#result+1] = s_middle +            end          end      end -end -function extras.tabulatecell(result,element,detail,n,fulltag,di) -    local hash = tabulatedata[fulltag] -    if hash then -        local v = hash.align -        if not v or v == 0 then -            -- normal -        elseif v == 1 then -            result[#result+1] = " align='flushleft'" -        elseif v == 2 then -            result[#result+1] = " align='flushright'" -        elseif v == 3 then -            result[#result+1] = " align='middle'" -        end -    end  end  -- flusher -local linedone    = false -- can go ... we strip newlines anyway -local inlinedepth = 0 - --- todo: #result -> nofresult - -local function emptytag(result,element,nature,depth,di) -- currently only break but at some point -    local a = di.attributes                             -- we might add detail etc -    if a then -- happens seldom -        if linedone then -            result[#result+1] = formatters["%w<%s"](depth,namespaced[element]) -        else -            result[#result+1] = formatters["\n%w<%s"](depth,namespaced[element]) -        end +do + +    local f_detail                     = formatters[" detail='%s'"] +    local f_index                      = formatters[" n='%s'"] +    local f_spacing                    = formatters["<c n='%s'>%s</c>"] + +    local f_empty_inline               = formatters["<%s/>"] +    local f_empty_mixed                = formatters["%w<%s/>\n"] +    local f_empty_display              = formatters["\n%w<%s/>\n"] +    local f_empty_inline_attr          = formatters["<%s%s/>"] +    local f_empty_mixed_attr           = formatters["%w<%s%s/>"] +    local f_empty_display_attr         = formatters["\n%w<%s%s/>\n"] + +    local f_begin_inline               = formatters["<%s>"] +    local f_begin_mixed                = formatters["%w<%s>"] +    local f_begin_display              = formatters["\n%w<%s>\n"] +    local f_begin_inline_attr          = formatters["<%s%s>"] +    local f_begin_mixed_attr           = formatters["%w<%s%s>"] +    local f_begin_display_attr         = formatters["\n%w<%s%s>\n"] + +    local f_end_inline                 = formatters["</%s>"] +    local f_end_mixed                  = formatters["</%s>\n"] +    local f_end_display                = formatters["%w</%s>\n"] + +    local f_begin_inline_comment       = formatters["<!-- %s --><%s>"] +    local f_begin_mixed_comment        = formatters["%w<!-- %s --><%s>"] +    local f_begin_display_comment      = formatters["\n%w<!-- %s -->\n%w<%s>\n"] +    local f_begin_inline_attr_comment  = formatters["<!-- %s --><%s%s>"] +    local f_begin_mixed_attr_comment   = formatters["%w<!-- %s --><%s%s>"] +    local f_begin_display_attr_comment = formatters["\n%w<!-- %s -->\n%w<%s%s>\n"] + +    local f_comment_begin_inline       = formatters["<!-- begin %s -->"] +    local f_comment_begin_mixed        = formatters["%w<!-- begin %s -->"] +    local f_comment_begin_display      = formatters["\n%w<!-- begin %s -->\n"] + +    local f_comment_end_inline         = formatters["<!-- end %s -->"] +    local f_comment_end_mixed          = formatters["<!-- end %s -->\n"] +    local f_comment_end_display        = formatters["%w<!-- end %s -->\n"] + +    local f_metadata_begin             = formatters["\n%w<metadata>\n"] +    local f_metadata                   = formatters["%w<metavariable name=%q>%s</metavariable>\n"] +    local f_metadata_end               = formatters["%w</metadata>\n"] + +    --- we could share the r tables ... but it's fast enough anyway + +    local function attributes(a) +        local r = { } -- can be shared +        local n = 0          for k, v in next, a do -            result[#result+1] = formatters[" %s=%q"](k,v) -        end -        result[#result+1] = "/>\n" -    else -        if linedone then -            result[#result+1] = formatters["%w<%s/>\n"](depth,namespaced[element]) -        else -            result[#result+1] = formatters["\n%w<%s/>\n"](depth,namespaced[element]) +            n = n + 1 +            r[n] = f_attribute(k,v)          end +        return concat(r,"",1,n) +    end + +    local depth  = 0 +    local inline = 0 + +    local function bpar(result) +        result[#result+1] = "\n<p>" +    end +    local function epar(result) +        result[#result+1] = "</p>\n"      end -    linedone = false -end -local function begintag(result,element,nature,depth,di,skip) -    -- if needed we can use a local result with xresult -    local detail  = di.detail -    local n       = di.n -    local fulltag = di.fulltag -    local comment = di.comment -    if nature == "inline" then -        linedone = false -        inlinedepth = inlinedepth + 1 -        if show_comment and comment then -            result[#result+1] = formatters["<!-- %s -->"](comment) -        end -    elseif nature == "mixed" then -        if inlinedepth > 0 then -            if show_comment and comment then -                result[#result+1] = formatters["<!-- %s -->"](comment) -            end -        elseif linedone then -            result[#result+1] = spaces[depth] -            if show_comment and comment then -                result[#result+1] = formatters["<!-- %s -->"](comment) +    local function emptytag(result,element,nature,di) -- currently only break but at some point +        local a = di.attributes                       -- we might add detail etc +        if a then -- happens seldom +            if nature == "display" then +                result[#result+1] = f_empty_display_attr(depth,namespaced[element],attributes(a)) +            elseif nature == "mixed" then +                result[#result+1] = f_empty_mixed_attr(depth,namespaced[element],attributes(a)) +            else +                result[#result+1] = f_empty_inline_attr(namespaced[element],attributes(a))              end          else -            result[#result+1] = formatters["\n%w"](depth) -            linedone = false -            if show_comment and comment then -                result[#result+1] = formatters["<!-- %s -->\n%w"](comment,depth) +            if nature == "display" then +                result[#result+1] = f_empty_display(depth,namespaced[element]) +            elseif nature == "mixed" then +                result[#result+1] = f_empty_mixed(depth,namespaced[element]) +            else +                result[#result+1] = f_empty_inline(namespaced[element])              end          end -        inlinedepth = inlinedepth + 1 -    else -        if inlinedepth > 0 then -            if show_comment and comment then -                result[#result+1] = formatters["<!-- %s -->"](comment) -            end -        elseif linedone then -            result[#result+1] = spaces[depth] -            if show_comment and comment then -                result[#result+1] = formatters["<!-- %s -->"](comment) +    end + +    local function begintag(result,element,nature,di,skip) +        local detail  = di.detail +        local index   = di.n +        local fulltag = di.fulltag +        local comment = di.comment +        if skip == "comment" then +            if show_comment then +                if nature == "inline" or inline > 0 then +                    result[#result+1] = f_comment_begin_inline(namespaced[element]) +                    inline = inline + 1 +                elseif nature == "mixed" then +                    result[#result+1] = f_comment_begin_mixed(depth,namespaced[element]) +                    depth = depth + 1 +                    inline = 1 +                else +                    result[#result+1] = f_comment_begin_display(depth,namespaced[element]) +                    depth = depth + 1 +                end              end +        elseif skip then +            -- ignore          else -            result[#result+1] = formatters["\n%w"](depth) -- can introduced extra line in mixed+mixed (filtered later on) -            linedone = false -            if show_comment and comment then -                result[#result+1] = formatters["<!-- %s -->\n%w"](comment,depth) +            local n = 0 +            local r = { } -- delay this +            if detail then +                n = n + 1 +                r[n] = f_detail(detail)              end -        end -    end -    if skip == "comment" then -        if show_comment then -            result[#result+1] = formatters["<!-- begin %s -->"](namespaced[element]) -        end -    elseif skip then -        -- ignore -    else -        result[#result+1] = formatters["<%s"](namespaced[element]) -        if detail then -            result[#result+1] = formatters[" detail=%q"](detail) -        end -        if indexing and n then -            result[#result+1] = formatters[" n=%q"](n) -        end -        local extra = extras[element] -        if extra then -            extra(result,element,detail,n,fulltag,di) -        end -        local u = userdata[fulltag] -        if u then -            for k, v in next, u do -                result[#result+1] = formatters[" %s=%q"](k,v) +            if indexing and index then +                n = n + 1 +                r[n] = f_index(index)              end -        end -        local a = di.attributes -        if a then -            for k, v in next, a do -                result[#result+1] = formatters[" %s=%q"](k,v) +            local extra = extras[element] +            if extra then +                extra(r,element,detail,index,fulltag,di) +                n = #r              end -        end -        result[#result+1] = ">" -    end -    if inlinedepth > 0 then -    elseif nature == "display" then -        result[#result+1] = "\n" -        linedone = true -    end -    used[element][detail or ""] = nature -- for template css -    local metadata = tagmetadata[fulltag] -    if metadata then -        if not linedone then -            result[#result+1] = "\n" -            linedone = true -        end -        result[#result+1] = formatters["%w<metadata>\n"](depth) -        for k, v in table.sortedpairs(metadata) do -            v = entityremapper(v) -            result[#result+1] = formatters["%w<metavariable name=%q>%s</metavariable>\n"](depth+1,k,v) -        end -        result[#result+1] = formatters["%w</metadata>\n"](depth) -    end -end - -local function endtag(result,element,nature,depth,skip) -    if nature == "display" then -        if inlinedepth == 0 then -            if not linedone then -                result[#result+1] = "\n" +            local u = userdata[fulltag] +            if u then +                for k, v in next, u do +                    n = n + 1 +                    r[n] = f_attribute(k,v) +                end              end -            if skip == "comment" then -                if show_comment then -                    result[#result+1] = formatters["%w<!-- end %s -->\n"](depth,namespaced[element]) +            local a = di.attributes +            if a then +                for k, v in next, a do +                    n = n + 1 +                    r[n] = f_attribute(k,v)                  end -            elseif skip then -                -- ignore -            else -                result[#result+1] = formatters["%w</%s>\n"](depth,namespaced[element])              end -            linedone = true -        else -            if skip == "comment" then -                if show_comment then -                    result[#result+1] = formatters["<!-- end %s -->"](namespaced[element]) +            if n == 0 then +                if nature == "inline" or inline > 0 then +                    if show_comment and comment then +                        result[#result+1] = f_begin_inline_comment(comment,namespaced[element]) +                    else +                        result[#result+1] = f_begin_inline(namespaced[element]) +                    end +                    inline = inline + 1 +                elseif nature == "mixed" then +                    if show_comment and comment then +                        result[#result+1] = f_begin_mixed_comment(depth,comment,namespaced[element]) +                    else +                        result[#result+1] = f_begin_mixed(depth,namespaced[element]) +                    end +                    depth = depth + 1 +                    inline = 1 +                else +                    if show_comment and comment then +                        result[#result+1] = f_begin_display_comment(depth,comment,depth,namespaced[element]) +                    else +                        result[#result+1] = f_begin_display(depth,namespaced[element]) +                    end +                    depth = depth + 1                  end -            elseif skip then -                -- ignore              else -                result[#result+1] = formatters["</%s>"](namespaced[element]) +                r = concat(r,"",1,n) +                if nature == "inline" or inline > 0 then +                    if show_comment and comment then +                        result[#result+1] = f_begin_inline_attr_comment(comment,namespaced[element],r) +                    else +                        result[#result+1] = f_begin_inline_attr(namespaced[element],r) +                    end +                    inline = inline + 1 +                elseif nature == "mixed" then +                    if show_comment and comment then +                        result[#result+1] = f_begin_mixed_attr_comment(depth,comment,namespaced[element],r) +                    else +                        result[#result+1] = f_begin_mixed_attr(depth,namespaced[element],r) +                    end +                    depth = depth + 1 +                    inline = 1 +                else +                    if show_comment and comment then +                        result[#result+1] = f_begin_display_attr_comment(depth,comment,depth,namespaced[element],r) +                    else +                        result[#result+1] = f_begin_display_attr(depth,namespaced[element],r) +                    end +                    depth = depth + 1 +                end              end          end -    else -        inlinedepth = inlinedepth - 1 -        if skip == "comment" then -            if show_comment then -                result[#result+1] = formatters["<!-- end %s -->"](namespaced[element]) +        used[element][detail or ""] = nature -- for template css +        local metadata = tagmetadata[fulltag] +        if metadata then +            result[#result+1] = f_metadata_begin(depth) +            for k, v in table.sortedpairs(metadata) do +                result[#result+1] = f_medatadata(depth+1,k,lpegmatch(p_entity,v))              end -        elseif skip then -            -- ignore -        else -            result[#result+1] = formatters["</%s>"](namespaced[element]) +            result[#result+1] = f_metadata_end(depth)          end -        linedone = false      end -end -local function flushtree(result,data,nature,depth) -    depth = depth + 1 -    local nofdata = #data -    for i=1,nofdata do -        local di = data[i] -        if not di then -- hm, di can be string -            -- whatever -        elseif di.content then -            -- already has breaks -            local content = entityremapper(di.content) -            if i == nofdata and sub(content,-1) == "\n" then -- move check -                -- can be an end of line in par but can also be the last line -                if trace_spacing then -                    result[#result+1] = formatters["<c n='%s'>%s</c>"](di.parnumber or 0,sub(content,1,-2)) -                else -                    result[#result+1] = sub(content,1,-2) -                end -                result[#result+1] = " " -            else -                if trace_spacing then -                    result[#result+1] = formatters["<c n='%s'>%s</c>"](di.parnumber or 0,content) +    local function endtag(result,element,nature,di,skip) +        if skip == "comment" then +            if show_comment then +                if nature == "display" and (inline == 0 or inline == 1) then +                    depth = depth - 1 +                    result[#result+1] = f_comment_end_display(depth,namespaced[element]) +                    inline = 0 +                elseif nature == "mixed" and (inline == 0 or inline == 1) then +                    depth = depth - 1 +                    result[#result+1] = f_comment_end_mixed(namespaced[element]) +                    inline = 0                  else -                    result[#result+1] = content +                    inline = inline - 1 +                    result[#result+1] = f_comment_end_inline(namespaced[element])                  end              end -            linedone = false -        elseif not di.collapsed then -- ignore collapsed data (is appended, reconstructed par) -            local element = di.element -            if not element then -                -- skip -            elseif element == "break" then -- or element == "pagebreak" -                emptytag(result,element,nature,depth,di) -            elseif element == "" or di.skip == "ignore" then -                -- skip +        elseif skip then +            -- ignore +        else +            if nature == "display" and (inline == 0 or inline == 1) then +                depth = depth - 1 +                result[#result+1] = f_end_display(depth,namespaced[element]) +                inline = 0 +            elseif nature == "mixed" and (inline == 0 or inline == 1) then +                depth = depth - 1 +                result[#result+1] = f_end_mixed(namespaced[element]) +                inline = 0              else -                if di.before then -                    flushtree(result,di.before,nature,depth) -                end -                local natu = di.nature -                local skip = di.skip -                if di.breaknode then -                    emptytag(result,"break","display",depth,di) -                end -                begintag(result,element,natu,depth,di,skip) -                flushtree(result,di.data,natu,depth) -             -- if sub(result[#result],-1) == " " and natu ~= "inline" then -             --     result[#result] = sub(result[#result],1,-2) -             -- end -                endtag(result,element,natu,depth,skip) -                if di.after then -                    flushtree(result,di.after,nature,depth) -                end +                inline = inline - 1 +                result[#result+1] = f_end_inline(namespaced[element])              end          end      end -end -local function breaktree(tree,parent,parentelement) -- also removes double breaks -    local data = tree.data -    if data then +    local function flushtree(result,data,nature)          local nofdata = #data -        local prevelement -        local prevnature -        local prevparnumber -        local newdata = { } -        local nofnewdata = 0          for i=1,nofdata do              local di = data[i] -            if not di then -                -- skip +            if not di then -- hm, di can be string +                -- whatever              elseif di.content then -                local parnumber = di.parnumber -                if prevnature == "inline" and prevparnumber and prevparnumber ~= parnumber then -                    nofnewdata = nofnewdata + 1 +                -- already has breaks +                local content = lpegmatch(p_entity,di.content) +                if i == nofdata and sub(content,-1) == "\n" then -- move check +                    -- can be an end of line in par but can also be the last line +                    if trace_spacing then +                        result[#result+1] = f_spacing(di.parnumber or 0,sub(content,1,-2)) +                    else +                        result[#result+1] = sub(content,1,-2) +                    end +                    result[#result+1] = " " +                else                      if trace_spacing then -                        newdata[nofnewdata] = makebreaknode { type = "a", p = prevparnumber, n = parnumber } +                        result[#result+1] = f_spacing(di.parnumber or 0,content)                      else -                        newdata[nofnewdata] = makebreaknode() +                        result[#result+1] = content                      end                  end -                prevelement = nil -                prevnature = "inline" -                prevparnumber = parnumber -                nofnewdata = nofnewdata + 1 -                newdata[nofnewdata] = di -            elseif not di.collapsed then +            elseif not di.collapsed then -- ignore collapsed data (is appended, reconstructed par)                  local element = di.element -                if element == "break" then -- or element == "pagebreak" -                    if prevelement == "break" then -                        di.element = "" -                    end -                    prevelement = element -                    prevnature = "display" +                if not element then +                    -- skip +                elseif element == "break" then -- or element == "pagebreak" +                    emptytag(result,element,nature,di)                  elseif element == "" or di.skip == "ignore" then                      -- skip                  else +                    if di.before then +                        flushtree(result,di.before,nature) +                    end +                    local natu = di.nature +                    local skip = di.skip +                    if di.breaknode then +                        emptytag(result,"break","display",di) +                    end +                    begintag(result,element,natu,di,skip) +                    flushtree(result,di.data,natu) +                    endtag(result,element,natu,di,skip) +                    if di.after then +                        flushtree(result,di.after,nature) +                    end +                end +            end +        end +    end + +    local function breaktree(tree,parent,parentelement) -- also removes double breaks +        local data = tree.data +        if data then +            local nofdata = #data +            local prevelement +            local prevnature +            local prevparnumber +            local newdata = { } +            local nofnewdata = 0 +            for i=1,nofdata do +                local di = data[i] +                if not di then +                    -- skip +                elseif di.content then +                    local parnumber = di.parnumber +                    if prevnature == "inline" and prevparnumber and prevparnumber ~= parnumber then +                        nofnewdata = nofnewdata + 1 +                        if trace_spacing then +                            newdata[nofnewdata] = makebreaknode { type = "a", p = prevparnumber, n = parnumber } +                        else +                            newdata[nofnewdata] = makebreaknode() +                        end +                    end +                    prevelement = nil +                    prevnature = "inline" +                    prevparnumber = parnumber +                    nofnewdata = nofnewdata + 1 +                    newdata[nofnewdata] = di +                elseif not di.collapsed then +                    local element = di.element +                    if element == "break" then -- or element == "pagebreak" +                        if prevelement == "break" then +                            di.element = "" +                        end +                        prevelement = element +                        prevnature = "display" +                    elseif element == "" or di.skip == "ignore" then +                        -- skip +                    else +                        local nature = di.nature +                        local parnumber = di.parnumber +                        if prevnature == "inline" and nature == "inline" and prevparnumber and prevparnumber ~= parnumber then +                            nofnewdata = nofnewdata + 1 +                            if trace_spacing then +                                newdata[nofnewdata] = makebreaknode { type = "b", p = prevparnumber, n = parnumber } +                            else +                                newdata[nofnewdata] = makebreaknode() +                            end +                        end +                        prevnature = nature +                        prevparnumber = parnumber +                        prevelement = element +                        breaktree(di,tree,element) +                    end +                    nofnewdata = nofnewdata + 1 +                    newdata[nofnewdata] = di +                else                      local nature = di.nature                      local parnumber = di.parnumber                      if prevnature == "inline" and nature == "inline" and prevparnumber and prevparnumber ~= parnumber then                          nofnewdata = nofnewdata + 1                          if trace_spacing then -                            newdata[nofnewdata] = makebreaknode { type = "b", p = prevparnumber, n = parnumber } +                            newdata[nofnewdata] = makebreaknode { type = "c", p = prevparnumber, n = parnumber }                          else                              newdata[nofnewdata] = makebreaknode()                          end                      end                      prevnature = nature                      prevparnumber = parnumber -                    prevelement = element -                    breaktree(di,tree,element) -                end -                nofnewdata = nofnewdata + 1 -                newdata[nofnewdata] = di -            else -                local nature = di.nature -                local parnumber = di.parnumber -                if prevnature == "inline" and nature == "inline" and prevparnumber and prevparnumber ~= parnumber then                      nofnewdata = nofnewdata + 1 -                    if trace_spacing then -                        newdata[nofnewdata] = makebreaknode { type = "c", p = prevparnumber, n = parnumber } -                    else -                        newdata[nofnewdata] = makebreaknode() -                    end +                    newdata[nofnewdata] = di                  end -                prevnature = nature -                prevparnumber = parnumber -                nofnewdata = nofnewdata + 1 -                newdata[nofnewdata] = di              end -        end -        tree.data = newdata -    end -end - --- also tabulaterow reconstruction .. maybe better as a checker --- i.e cell attribute - -local function collapsetree() -    for tag, trees in next, treehash do -        local d = trees[1].data -        if d then -            local nd = #d -            if nd > 0 then -                for i=2,#trees do -                    local currenttree = trees[i] -                    local currentdata = currenttree.data -                    local currentpar = currenttree.parnumber -                    local previouspar = trees[i-1].parnumber -                    currenttree.collapsed = true -                    -- is the next ok? -                    if previouspar == 0 or not (di and di.content) then -                        previouspar = nil -- no need anyway so no further testing needed -                    end -                    for j=1,#currentdata do -                        local cd = currentdata[j] -                        if not cd or cd == "" then -                            -- skip -                        elseif cd.content then -                            if not currentpar then -                                -- add space ? -                            elseif not previouspar then -                                -- add space ? -                            elseif currentpar ~= previouspar then -                                nd = nd + 1 -                                if trace_spacing then -                                    d[nd] = makebreaknode { type = "d", p = previouspar, n = currentpar } -                                else -                                    d[nd] = makebreaknode() +            tree.data = newdata +        end +    end + +    -- also tabulaterow reconstruction .. maybe better as a checker +    -- i.e cell attribute + +    local function collapsetree() +        for tag, trees in next, treehash do +            local d = trees[1].data +            if d then +                local nd = #d +                if nd > 0 then +                    for i=2,#trees do +                        local currenttree = trees[i] +                        local currentdata = currenttree.data +                        local currentpar = currenttree.parnumber +                        local previouspar = trees[i-1].parnumber +                        currenttree.collapsed = true +                        -- is the next ok? +                        if previouspar == 0 or not (di and di.content) then +                            previouspar = nil -- no need anyway so no further testing needed +                        end +                        for j=1,#currentdata do +                            local cd = currentdata[j] +                            if not cd or cd == "" then +                                -- skip +                            elseif cd.content then +                                if not currentpar then +                                    -- add space ? +                                elseif not previouspar then +                                    -- add space ? +                                elseif currentpar ~= previouspar then +                                    nd = nd + 1 +                                    if trace_spacing then +                                        d[nd] = makebreaknode { type = "d", p = previouspar, n = currentpar } +                                    else +                                        d[nd] = makebreaknode() +                                    end                                  end +                                previouspar = currentpar +                                nd = nd + 1 +                                d[nd] = cd +                            else +                                nd = nd + 1 +                                d[nd] = cd                              end -                            previouspar = currentpar -                            nd = nd + 1 -                            d[nd] = cd -                        else -                            nd = nd + 1 -                            d[nd] = cd +                            currentdata[j] = false                          end -                        currentdata[j] = false                      end                  end              end          end      end -end -local function finalizetree(tree) -    for _, finalizer in next, finalizers do -        finalizer(tree) +    local function finalizetree(tree) +        for _, finalizer in next, finalizers do +            finalizer(tree) +        end      end -end -local function indextree(tree) -    local data = tree.data -    if data then -        local n, new = 0, { } -        for i=1,#data do -            local d = data[i] -            if not d then -                -- skip -            elseif d.content then -                n = n + 1 -                new[n] = d -            elseif not d.collapsed then -                n = n + 1 -                d.__i__ = n -                d.__p__ = tree -                indextree(d) -                new[n] = d +    local function indextree(tree) +        local data = tree.data +        if data then +            local n, new = 0, { } +            for i=1,#data do +                local d = data[i] +                if not d then +                    -- skip +                elseif d.content then +                    n = n + 1 +                    new[n] = d +                elseif not d.collapsed then +                    n = n + 1 +                    d.__i__ = n +                    d.__p__ = tree +                    indextree(d) +                    new[n] = d +                end              end +            tree.data = new          end -        tree.data = new      end -end -local function checktree(tree) -    local data = tree.data -    if data then -        for i=1,#data do -            local d = data[i] -            if type(d) == "table" then -                local check = checks[d.tg] -                if check then -                    check(d) +    local function checktree(tree) +        local data = tree.data +        if data then +            for i=1,#data do +                local d = data[i] +                if type(d) == "table" then +                    local check = checks[d.tg] +                    if check then +                        check(d) +                    end +                    checktree(d)                  end -                checktree(d)              end          end      end + +    wrapups.flushtree    = flushtree +    wrapups.breaktree    = breaktree +    wrapups.collapsetree = collapsetree +    wrapups.finalizetree = finalizetree +    wrapups.indextree    = indextree +    wrapups.checktree    = checktree +  end  -- collector code @@ -1889,6 +2076,9 @@ local function collectresults(head,list) -- is last used (we also have currentat                          end                          --                      elseif last then +                        -- we can consider tagging the pars (lines) in the parbuilder but then we loose some +                        -- information unless we inject a special node (but even then we can run into nesting +                        -- issues)                          local ap = getattr(n,a_taggedpar)                          if ap ~= currentparagraph then                              pushcontent(currentparagraph,ap) @@ -2182,6 +2372,8 @@ end  -- encoding='utf-8' +do +  local xmlpreamble = [[  <?xml version='1.0' encoding='UTF-8' standalone='yes' ?> @@ -2192,247 +2384,336 @@ local xmlpreamble = [[  ]] -local function wholepreamble() -    return format(xmlpreamble,tex.jobname,os.date(),environment.version,exportversion) -end +    local flushtree = wrapups.flushtree +    local function wholepreamble() +        return format(xmlpreamble,tex.jobname,os.date(),environment.version,exportversion) +    end -local csspreamble = [[ -<?xml-stylesheet type="text/css" href="%s"?> -]] -local function allusedstylesheets(xmlfile,cssfiles,files) -    local result = { } -    for i=1,#cssfiles do -        local cssfile = cssfiles[i] -        if type(cssfile) ~= "string" or cssfile == variables.yes or cssfile == "" or cssfile == xmlfile then -            cssfile = file.replacesuffix(xmlfile,"css") -        else -            cssfile = file.addsuffix(cssfile,"css") +local f_csspreamble = formatters [ [[ +<?xml-stylesheet type="text/css" href="%s"?> +]] ] + +    local function allusedstylesheets(xmlfile,cssfiles,files) +        local result = { } +        for i=1,#cssfiles do +            local cssfile = cssfiles[i] +            if type(cssfile) ~= "string" or cssfile == v_yes or cssfile == "" or cssfile == xmlfile then +                cssfile = file.replacesuffix(xmlfile,"css") +            else +                cssfile = file.addsuffix(cssfile,"css") +            end +            files[#files+1] = cssfile +            report_export("adding css reference '%s'",cssfile) +            result[#result+1] = f_csspreamble(cssfile)          end -        files[#files+1] = cssfile -        report_export("adding css reference '%s'",cssfile) -        result[#result+1] = format(csspreamble,cssfile) +        return concat(result)      end -    return concat(result) -end -local e_template = [[ +local f_e_template = formatters [ [[  %s {      display: %s ; -}]] +}]] ] -local d_template = [[ +local f_d_template = formatters [ [[  %s[detail=%s] {      display: %s ; -}]] +}]] ] -local displaymapping = { -    inline  = "inline", -    display = "block", -    mixed   = "inline", -} +    local f_category = formatters["/* category: %s */"] -local function allusedelements(xmlfile) -    local result = { format("/* template for file %s */",xmlfile) } -    for element, details in sortedhash(used) do -        result[#result+1] = format("/* category: %s */",element) -        for detail, nature in sortedhash(details) do -            local d = displaymapping[nature or "display"] or "block" -            if detail == "" then -                result[#result+1] = formatters[e_template](element,d) -            else -                result[#result+1] = formatters[d_template](element,detail,d) +    local displaymapping = { +        inline  = "inline", +        display = "block", +        mixed   = "inline", +    } + +    local function allusedelements(xmlfile) +        local result = { formatters["/* %s for file %s */"]("template",xmlfile) } +        for element, details in sortedhash(used) do +            result[#result+1] = f_category(element) +            for detail, nature in sortedhash(details) do +                local d = displaymapping[nature or "display"] or "block" +                if detail == "" then +                    result[#result+1] = f_e_template(element,d) +                else +                    result[#result+1] = f_d_template(element,detail,d) +                end              end          end +        return concat(result,"\n\n")      end -    return concat(result,"\n\n") -end - -local function allcontent(tree) -    local result  = { } -    flushtree(result,tree.data,"display",0) -- we need to collect images -    result = concat(result) -    result = gsub(result,"\n *\n","\n") -    result = gsub(result,"\n +([^< ])","\n%1") -    return result -end --- local xhtmlpreamble = [[ ---     <!DOCTYPE html PUBLIC ---         "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" ---         "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd" ---     > --- ]] - -local function cleanxhtmltree(xmltree) -    if xmltree then -        local xmlwrap = xml.wrap -        for e in xml.collected(xmltree,"/document") do -            e.at["xmlns:xhtml"] = "http://www.w3.org/1999/xhtml" -            break -        end -        -- todo: inject xhtmlpreamble (xmlns should have be enough) -        local wrapper = { tg = "a", ns = "xhtml", at = { href = "unknown" } } -        for e in xml.collected(xmltree,"link") do -            local at = e.at -            local href -            if at.location then -                href = "#" .. gsub(at.location,":","_") -            elseif at.url then -                href = at.url -            elseif at.file then -                href = at.file -            end -            if href then -                wrapper.at.href = href -                xmlwrap(e,wrapper) -            end -        end -        local wrapper = { tg = "a", ns = "xhtml", at = { name = "unknown" } } -        for e in xml.collected(xmltree,"!link[@location]") do -            local location = e.at.location -            if location then -                wrapper.at.name = gsub(location,":","_") -                xmlwrap(e,wrapper) -            end -        end -        return xmltree -    else -        return xml.convert("<?xml version='1.0'?>\n<error>invalid xhtml tree</error>") +    local function allcontent(tree) +        local result  = { } +        flushtree(result,tree.data,"display") -- we need to collect images +        result = concat(result) +        -- no need to lpeg .. fast enough +        result = gsub(result,"\n *\n","\n") +        result = gsub(result,"\n +([^< ])","\n%1") +        return result      end -end -local cssfile, xhtmlfile = nil, nil +    -- local xhtmlpreamble = [[ +    --     <!DOCTYPE html PUBLIC +    --         "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" +    --         "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd" +    --     > +    -- ]] -directives.register("backend.export.css",  function(v) cssfile   = v end) -directives.register("backend.export.xhtml",function(v) xhtmlfile = v end) - -local function stopexport(v) -    starttiming(treehash) -    -- -    finishexport() -    -- -    collapsetree(tree) -    indextree(tree) -    checktree(tree) -    breaktree(tree) -    finalizetree(tree) -    -- -    hashlistdata() -    -- -    if type(v) ~= "string" or v == variables.yes or v == "" then -        v = tex.jobname -    end -    local basename = file.basename(v) -    local xmlfile = file.addsuffix(basename,"export") -    -- -    local imagefilename         = file.addsuffix(file.removesuffix(xmlfile) .. "-images","css") -    local stylefilename         = file.addsuffix(file.removesuffix(xmlfile) .. "-styles","css") -    local templatefilename      = file.replacesuffix(xmlfile,"template") -    local specificationfilename = file.replacesuffix(xmlfile,"specification") -    -- -    if xhtml and not cssfile then -        cssfile = true -    end -    local cssfiles = { } -    if cssfile then -        if cssfile == true then -            cssfiles = { "export-example.css" } +    local function cleanxhtmltree(xmltree) +        if xmltree then +            local xmlwrap = xml.wrap +            for e in xml.collected(xmltree,"/document") do +                e.at["xmlns:xhtml"] = "http://www.w3.org/1999/xhtml" +                break +            end +            -- todo: inject xhtmlpreamble (xmlns should have be enough) +            local wrapper = { tg = "a", ns = "xhtml", at = { href = "unknown" } } +            for e in xml.collected(xmltree,"link") do +                local at = e.at +                local href +                if at.location then +                    href = "#" .. gsub(at.location,":","_") +                elseif at.url then +                    href = at.url +                elseif at.file then +                    href = at.file +                end +                if href then +                    wrapper.at.href = href +                    xmlwrap(e,wrapper) +                end +            end +            local wrapper = { tg = "a", ns = "xhtml", at = { name = "unknown" } } +            for e in xml.collected(xmltree,"!link[@location]") do +                local location = e.at.location +                if location then +                    wrapper.at.name = gsub(location,":","_") +                    xmlwrap(e,wrapper) +                end +            end +            return xmltree          else -            cssfiles = settings_to_array(cssfile or "") +            return xml.convert("<?xml version='1.0'?>\n<error>invalid xhtml tree</error>")          end -        insert(cssfiles,1,imagefilename) -        insert(cssfiles,1,stylefilename)      end -    cssfiles = table.unique(cssfiles) -    -- -    local result = allcontent(tree) -- also does some housekeeping and data collecting -    -- -    local files = { -    } -    local results = concat { -        wholepreamble(), -        allusedstylesheets(xmlfile,cssfiles,files), -- ads to files -        result, -    } -    -- -    files = table.unique(files) -    -- -    report_export("saving xml data in %a",xmlfile) -    io.savedata(xmlfile,results) -    -- -    report_export("saving css image definitions in %a",imagefilename) -    io.savedata(imagefilename,allusedimages(xmlfile)) -    -- -    report_export("saving css style definitions in %a",stylefilename) -    io.savedata(stylefilename,allusedstyles(xmlfile)) -    -- -    report_export("saving css template in %a",templatefilename) -    io.savedata(templatefilename,allusedelements(xmlfile)) -    -- -    if xhtmlfile then -        if type(v) ~= "string" or xhtmlfile == true or xhtmlfile == variables.yes or xhtmlfile == "" or xhtmlfile == xmlfile then -            xhtmlfile = file.replacesuffix(xmlfile,"xhtml") -        else -            xhtmlfile = file.addsuffix(xhtmlfile,"xhtml") -        end -        files[#files+1] = xhtmlfile -        report_export("saving xhtml variant in %a",xhtmlfile) -        local xmltree = cleanxhtmltree(xml.convert(results)) -        xml.save(xmltree,xhtmlfile) -        -- looking at identity is somewhat redundant as we also inherit from interaction -        -- at the tex end -        local identity = interactions.general.getidentity() -        local specification = { -            name       = file.removesuffix(v), -            identifier = os.uuid(), -            images     = uniqueusedimages(), -            root       = xhtmlfile, -            files      = files, -            language   = languagenames[texgetcount("mainlanguagenumber")], -            title      = validstring(finetuning.title) or validstring(identity.title), -            subtitle   = validstring(finetuning.subtitle) or validstring(identity.subtitle), -            author     = validstring(finetuning.author) or validstring(identity.author), -            firstpage  = validstring(finetuning.firstpage), -            lastpage   = validstring(finetuning.lastpage), -        } -        report_export("saving specification in %a (mtxrun --script epub --make %s)",specificationfilename,specificationfilename) -        io.savedata(specificationfilename,table.serialize(specification,true)) + +    local f_namespace = string.formatters["%s.%s"] + +    local function remap(specification,source,target) +     -- local specification = specification or require(specname) +     -- if not specification then +     --     return +     -- end +     -- if type(source) == "string" then +     --     source = xml.load(source) +     -- end +     -- if type(source) ~= "table" then +     --     return +     -- end +        local remapping = specification.remapping +        if not remapping then +            return +        end +        for i=1,#remapping do +            local remap = remapping[i] +            local element   = remap.element +            local class     = remap.class +            local extras    = remap.extras +            local namespace = extras and extras.namespace +            for c in xml.collected(source,remap.pattern) do +                if not c.special then +                    local tg = c.tg +                    local at = c.at +                    local class = { +                        class or (at and at.detail) or tg +                    } +                    if extras and at then +                        for k, v in next, extras do +                            local a = at[k] +                            if a then +                                local va = v[a] +                                if va then +                                    if namespace then +                                        class[#class+1] = f_namespace(tg,va) +                                    else +                                        class[#class+1] = va +                                    end +                                end +                            end +                        end +                    end +                    if #class > 0 then +                        c.at = { class = concat(class," ") } +                    else +                        c.at = { } +                    end +                    if element then +                        c.tg = element +                    end +                end +            end +        end +     -- if target then +     --     xml.save(source,target) +     -- end +     -- return source      end -    stoptiming(treehash) -end -local appendaction = nodes.tasks.appendaction -local enableaction = nodes.tasks.enableaction +    local cssfile, xhtmlfile, alternative = nil, nil, nil -function commands.setupexport(t) -    table.merge(finetuning,t) -    keephyphens = finetuning.hyphen == variables.yes -end +    directives.register("backend.export.css",        function(v) cssfile     = v end) +    directives.register("backend.export.xhtml",      function(v) xhtmlfile   = v end) +    directives.register("backend.export.alternative",function(v) alternative = v end) -local function startexport(v) -    if v and not exporting then -        report_export("enabling export to xml") -     -- not yet known in task-ini -        appendaction("shipouts","normalizers", "nodes.handlers.export") -     -- enableaction("shipouts","nodes.handlers.export") -        enableaction("shipouts","nodes.handlers.accessibility") -        enableaction("math",    "noads.handlers.tags") -     -- appendaction("finalizers","lists","builders.paragraphs.tag") -     -- enableaction("finalizers","builders.paragraphs.tag") -        luatex.registerstopactions(function() stopexport(v) end) -        exporting = true +    local function stopexport(v) +        starttiming(treehash) +        -- +        finishexport() +        -- +        wrapups.collapsetree(tree) +        wrapups.indextree(tree) +        wrapups.checktree(tree) +        wrapups.breaktree(tree) +        wrapups.finalizetree(tree) +        -- +        wrapups.hashlistdata() +        -- +        if type(v) ~= "string" or v == v_yes or v == "" then +            v = tex.jobname +        end +        local basename = file.basename(v) +        local xmlfile = file.addsuffix(basename,"export") +        -- +        local imagefilename         = file.addsuffix(file.removesuffix(xmlfile) .. "-images","css") +        local stylefilename         = file.addsuffix(file.removesuffix(xmlfile) .. "-styles","css") +        local templatefilename      = file.replacesuffix(xmlfile,"template") +        local specificationfilename = file.replacesuffix(xmlfile,"specification") +        -- +        if xhtml and not cssfile then +            cssfile = true +        end +        local cssfiles = { } +        if cssfile then +            if cssfile == true then +                cssfiles = { "export-example.css" } +            else +                cssfiles = settings_to_array(cssfile or "") +            end +            insert(cssfiles,1,imagefilename) +            insert(cssfiles,1,stylefilename) +        end +        cssfiles = table.unique(cssfiles) +        -- +        local result = allcontent(tree) -- also does some housekeeping and data collecting +        -- +        local files = { +        } +        local results = concat { +            wholepreamble(), +            allusedstylesheets(xmlfile,cssfiles,files), -- ads to files +            result, +        } +        -- +        files = table.unique(files) +        -- +        report_export("saving xml data in %a",xmlfile) +        io.savedata(xmlfile,results) +        -- +        report_export("saving css image definitions in %a",imagefilename) +        io.savedata(imagefilename,wrapups.allusedimages(xmlfile)) +        -- +        report_export("saving css style definitions in %a",stylefilename) +        io.savedata(stylefilename,wrapups.allusedstyles(xmlfile)) +        -- +        report_export("saving css template in %a",templatefilename) +        io.savedata(templatefilename,allusedelements(xmlfile)) +        -- +        local xmltree = nil +        if xhtmlfile then +            if type(v) ~= "string" or xhtmlfile == true or xhtmlfile == v_yes or xhtmlfile == "" or xhtmlfile == xmlfile then +                xhtmlfile = file.replacesuffix(xmlfile,"xhtml") +            else +                xhtmlfile = file.addsuffix(xhtmlfile,"xhtml") +            end +            files[#files+1] = xhtmlfile +            report_export("saving xhtml variant in %a",xhtmlfile) +            xmltree = cleanxhtmltree(xml.convert(results)) +            xml.save(xmltree,xhtmlfile) +            -- looking at identity is somewhat redundant as we also inherit from interaction +            -- at the tex end +            local identity = interactions.general.getidentity() +            local specification = { +                name       = file.removesuffix(v), +                identifier = os.uuid(), +                images     = wrapups.uniqueusedimages(), +                root       = xhtmlfile, +                files      = files, +                language   = languagenames[texgetcount("mainlanguagenumber")], +                title      = validstring(finetuning.title) or validstring(identity.title), +                subtitle   = validstring(finetuning.subtitle) or validstring(identity.subtitle), +                author     = validstring(finetuning.author) or validstring(identity.author), +                firstpage  = validstring(finetuning.firstpage), +                lastpage   = validstring(finetuning.lastpage), +            } +            report_export("saving specification in %a (mtxrun --script epub --make %s)",specificationfilename,specificationfilename) +            io.savedata(specificationfilename,table.serialize(specification,true)) +        end +        if type(alternative) == "string" then +            local filename = "back-exp-"..alternative ..".lua" +            local fullname = resolvers.findfile(filename) or "" +            if fullname == "" then +                report_export("no valid alternative %a in %a",alternative,filename) +            else +                specification = dofile(fullname) or false +                if specification then +                    if not xmltree then +                        xmltree = xml.convert(results) +                    end +                    remap(specification,xmltree) +                    local resultfile = file.replacesuffix(xmlfile,specification.suffix or alternative) +                    report_export("saving alternative in %a",resultfile) +                    xml.save(xmltree,resultfile) +                end +            end +        end +        stoptiming(treehash)      end -end -directives.register("backend.export",startexport) -- maybe .name +    local appendaction = nodes.tasks.appendaction +    local enableaction = nodes.tasks.enableaction -statistics.register("xml exporting time", function() -    if exporting then -        return format("%s seconds, version %s", statistics.elapsedtime(treehash),exportversion) +    function commands.setupexport(t) +        table.merge(finetuning,t) +        keephyphens = finetuning.hyphen == v_yes      end -end) + +    local function startexport(v) +        if v and not exporting then +            report_export("enabling export to xml") +         -- not yet known in task-ini +            appendaction("shipouts","normalizers", "nodes.handlers.export") +         -- enableaction("shipouts","nodes.handlers.export") +            enableaction("shipouts","nodes.handlers.accessibility") +            enableaction("math",    "noads.handlers.tags") +         -- appendaction("finalizers","lists","builders.paragraphs.tag") +         -- enableaction("finalizers","builders.paragraphs.tag") +            luatex.registerstopactions(function() stopexport(v) end) +            exporting = true +        end +    end + +    directives.register("backend.export",startexport) -- maybe .name + +    statistics.register("xml exporting time", function() +        if exporting then +            return format("%s seconds, version %s", statistics.elapsedtime(treehash),exportversion) +        end +    end) + +end  -- These are called at the tex end: @@ -2446,4 +2727,3 @@ commands.settagfigure            = structurestags.setfigure  commands.settagcombination       = structurestags.setcombination  commands.settagtablecell         = structurestags.settablecell  commands.settagtabulatecell      = structurestags.settabulatecell - diff --git a/tex/context/base/back-exp.mkiv b/tex/context/base/back-exp.mkiv index 7fd1b5799..4b91636b7 100644 --- a/tex/context/base/back-exp.mkiv +++ b/tex/context/base/back-exp.mkiv @@ -113,9 +113,12 @@      \unexpanded\def\dotagsetnotesymbol{\taggedctxcommand{settagdescriptionsymbol("\currentnote",\currentnotenumber)}}%  \to \everyenableelements -% \appendtoks -%     \unexpanded\def\doverbatimspace{\asciispacechar}% will be done permanently -% \to \everyenableelements +\appendtoks +    \let\specialfixedspace    \explicitfixedspace +    \let\specialobeyedspace   \explicitobeyedspace +    \let\specialstretchedspace\explicitstretchedspace +    \let\specialcontrolspace  \explicitcontrolspace +\to \everyenableelements  % The action: \setupbackend[export=yes] % or filename @@ -137,6 +140,7 @@     \c!author={\directinteractionparameter\c!author},   % \c!firstpage=, % imagename   % \c!lastpage=,  % imagename +   \c!alternative=, % html, div     \c!hyphen=\v!no]  \def\dosynchronizeexport @@ -166,6 +170,8 @@        {\enabledirectives[backend.export.xhtml=\backendparameter\c!xhtml]}%      \doifsomething{\backendparameter\c!css}        {\enabledirectives[backend.export.css={\backendparameter\c!css}]}% +    \doifsomething{\backendparameter\c!alternative} +      {\enabledirectives[backend.export.alternative={\backendparameter\c!alternative}]}%  \to \everysetupbackend  \appendtoks diff --git a/tex/context/base/buff-ver.mkiv b/tex/context/base/buff-ver.mkiv index 7a4f28253..c47a75856 100644 --- a/tex/context/base/buff-ver.mkiv +++ b/tex/context/base/buff-ver.mkiv @@ -45,8 +45,6 @@    {\spaceskip\fontcharwd\font`x\relax     \xspaceskip\spaceskip} -\unexpanded\def\specialcontrolspace{\hskip\zeropoint\fastcontrolspace\hskip\zeropoint} -  \setvalue{\??typinglines\v!no        }{\buff_verbatim_ignore_hyphens}  \setvalue{\??typinglines\v!normal    }{\buff_verbatim_ignore_hyphens}  \setvalue{\??typinglines\v!yes       }{\buff_verbatim_obey_breakpoints} @@ -75,26 +73,23 @@  \unexpanded\def\buff_verbatim_ignore_hyphens    {\language\minusone} % tricky as this affects the pagebuilder -\def\buff_verbatim_initialize_breaks % order matters -  {\spaceskip.5\emwidth\relax -   \let\obeyedspace\specialobeyedspace -   \let\controlspace\specialcontrolspace -   \edef\p_buff_lines{\typeparameter\c!lines}% -   \ifcsname\??typinglines\p_buff_lines\endcsname % sets \obeyedspace, \controlspace, -     \csname\??typinglines\p_buff_lines\endcsname -   \fi -   \edef\p_buff_space{\typeparameter\c!space}% -   \ifcsname\??typingspace\p_buff_space\endcsname % sets \obeyedspace -     \csname\??typingspace\p_buff_space\endcsname -   \fi} -  \def\buff_verbatim_initialize_type_one    {\let\obeylines\ignorelines     \usetypestyleandcolor\c!style\c!color     \setcatcodetable\vrbcatcodes}  \def\buff_verbatim_initialize_type_two -  {\buff_verbatim_initialize_breaks +  {\spaceskip.5\emwidth\relax +   \let\obeyedspace\specialobeyedspace +   \let\controlspace\specialcontrolspace + % \edef\p_buff_lines{\typeparameter\c!lines}% + % \ifcsname\??typinglines\p_buff_lines\endcsname + %   \csname\??typinglines\p_buff_lines\endcsname + % \fi +   \edef\p_buff_space{\typeparameter\c!space}% +   \ifcsname\??typingspace\p_buff_space\endcsname +     \csname\??typingspace\p_buff_space\endcsname +   \fi     \relax\the\everyinitializeverbatim\relax}  \unexpanded\def\doinitializeverbatim % for use elsewhere .. temp hack (see lxml-ini) @@ -106,8 +101,9 @@  \def\buff_verbatim_set_line_margin_indeed    {\hskip\doifoddpageelse{\typingparameter\c!oddmargin}{\typingparameter\c!evenmargin}\relax} -\def\buff_verbatim_check_margins -  {\scratchskip\typingparameter\c!oddmargin\relax +\def\buff_verbatim_initialize_typing_one +  {\switchtobodyfont[\typingparameter\c!bodyfont]% can be low level call +   \scratchskip\typingparameter\c!oddmargin\relax     \ifzeropt\scratchskip \else       \let\buff_verbatim_set_line_margin\buff_verbatim_set_line_margin_indeed     \fi @@ -117,16 +113,23 @@     \fi     \ifx\buff_verbatim_set_line_margin\relax       \doadaptleftskip{\typingparameter\c!margin}% -   \fi} - -\def\buff_verbatim_initialize_typing_one -  {\switchtobodyfont[\typingparameter\c!bodyfont]% can be low level call -   \buff_verbatim_check_margins +   \fi     \usetypingstyleandcolor\c!style\c!color -   \doifsomething{\typingparameter\c!align}{\setupalign[\typingparameter\c!align]}} + % will become: \usealignparameter\typingparameter +   \doifsomething{\typingparameter\c!align}{\setupalign[\typingparameter\c!align]}} % use fast one  \def\buff_verbatim_initialize_typing_two -  {\buff_verbatim_initialize_breaks +  {\spaceskip.5\emwidth\relax +   \let\obeyedspace\specialobeyedspace +   \let\controlspace\specialcontrolspace +   \edef\p_buff_lines{\typingparameter\c!lines}% +   \ifcsname\??typinglines\p_buff_lines\endcsname +     \csname\??typinglines\p_buff_lines\endcsname +   \fi +   \edef\p_buff_space{\typingparameter\c!space}% +   \ifcsname\??typingspace\p_buff_space\endcsname +     \csname\??typingspace\p_buff_space\endcsname +   \fi     \relax\the\everyinitializeverbatim\relax}  %D \macros @@ -371,15 +374,15 @@  %D works all right, but a decent hyphenation support of  %D \type{\tt} text will be implemented soon. -\unexpanded\def\specialfixedspace    {\kern\interwordspace\relax} -\unexpanded\def\specialobeyedspace   {\hskip\interwordspace\relax} % better than spaceskip -\unexpanded\def\specialstretchedspace{\hskip.5\interwordspace\s!plus.125\interwordspace\relax} % \interwordstretch can be zero -\unexpanded\def\specialcontrolspace  {\hskip\zeropoint\hbox{\normalcontrolspace}\hskip\zeropoint\relax} +\unexpanded\def\specialfixedspace     {\kern\interwordspace\relax} +\unexpanded\def\specialobeyedspace    {\hskip\interwordspace\relax} % better than spaceskip +\unexpanded\def\specialstretchedspace {\hskip.5\interwordspace\s!plus.125\interwordspace\relax} % \interwordstretch can be zero +\unexpanded\def\specialcontrolspace   {\normalcontrolspace\allowbreak} % uses fallback -% \unexpanded\def\taggedspecialfixedspace    {\hskip\zeropoint\asciispacechar\hskip\zeropoint} -% \unexpanded\def\taggedspecialobeyedspace   {\hskip\zeropoint\asciispacechar\hskip\zeropoint} -% \unexpanded\def\taggedspecialstretchedspace{\hskip\zeropoint\asciispacechar\hskip\zeropoint} -% \unexpanded\def\taggedspecialcontrolspace  {\hskip\zeropoint\hbox{\normalcontrolspace}\hskip\zeropoint\relax} +\unexpanded\def\explicitfixedspace    {\asciispacechar} +\unexpanded\def\explicitobeyedspace   {\asciispacechar\allowbreak} +\unexpanded\def\explicitstretchedspace{\asciispacechar\hskip\zeropoint\s!plus.125\interwordspace\relax}% +\unexpanded\def\explicitcontrolspace  {\optionalcontrolspace\allowbreak} % uses asciispace  \appendtoks      \unexpanded\def\obeyedspace{\hskip\zeropoint\asciispacechar\hskip\zeropoint}% @@ -856,8 +859,10 @@     \fi     \noindent     \buff_verbatim_set_line_margin -   \the\everyline\strut -   \dostarttagged\t!verbatimline\empty} +   \the\everyline % maybe also after starttagged +   \strut % after starttagged, else break ! +   \dostarttagged\t!verbatimline\empty +   }  \unexpanded\def\buff_verbatim_end_of_line    {\dostoptagged diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv index 15fca6049..b66665f19 100644 --- a/tex/context/base/cont-new.mkiv +++ b/tex/context/base/cont-new.mkiv @@ -11,7 +11,7 @@  %C therefore copyrighted by \PRAGMA. See mreadme.pdf for  %C details. -\newcontextversion{2014.07.11 12:20} +\newcontextversion{2014.07.14 12:38}  %D This file is loaded at runtime, thereby providing an excellent place for  %D hacks, patches, extensions and new features. diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf Binary files differindex 3e3f29803..dce512206 100644 --- a/tex/context/base/context-version.pdf +++ b/tex/context/base/context-version.pdf diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv index 5ce04e804..5026eabe4 100644 --- a/tex/context/base/context.mkiv +++ b/tex/context/base/context.mkiv @@ -28,7 +28,7 @@  %D up and the dependencies are more consistent.  \edef\contextformat {\jobname} -\edef\contextversion{2014.07.11 12:20} +\edef\contextversion{2014.07.14 12:38}  \edef\contextkind   {beta}  %D For those who want to use this: diff --git a/tex/context/base/enco-ini.mkiv b/tex/context/base/enco-ini.mkiv index ab3aa488d..0fae1aade 100644 --- a/tex/context/base/enco-ini.mkiv +++ b/tex/context/base/enco-ini.mkiv @@ -250,9 +250,27 @@  \chardef\textcontrolspace"2423 -\unexpanded\def\fallbackcontrolspace - %{\getglyph{ComputerModernMono}\textcontrolspace} -  {\getglyph{LMTypewriter-Regular}\textcontrolspace} +\installcorenamespace{controlspace} + +% \unexpanded\def\fallbackcontrolspace % beware: non-matching widths +%   {\hbox to \interwordspace{\hss\getglyph{LMTypewriter-Regular}\textcontrolspace\hss}% + +\unexpanded\def\fallbackcontrolspace % beware, current font, we also need to honor color +  {\hbox to \interwordspace \bgroup +     \hss +     \ifcsname\??controlspace\number\interwordspace\endcsname +       \csname\??controlspace\number\interwordspace\endcsname +     \else +       \enco_fast_control_space_define % only regular +     \fi +     \textcontrolspace +     \hss +   \egroup} + +\unexpanded\def\enco_fast_control_space_define +  {\scratchdimen\interwordspace +   \definedfont[LMTypewriter-Regular at \the\dimexpr\currentfontbodyscale\dimexpr\fontbody]% see font-sym.mkiv +   \expandafter\glet\csname\??controlspace\number\scratchdimen\endcsname\lastrawfontcall}  \unexpanded\def\normalcontrolspace    {\iffontchar\font\textcontrolspace @@ -263,29 +281,35 @@  \let\textvisiblespace\normalcontrolspace -\unexpanded\def\fastcontrolspace % no glyph resolving after first (use grouped) -  {\enco_fast_control_space} - -\def\enco_fast_control_space +\unexpanded\def\optionalcontrolspace    {\iffontchar\font\textcontrolspace -     \enco_fast_control_space_nop +     \textcontrolspace     \else -     \enco_fast_control_space_yes -   \fi -   \enco_fast_control_space} - -\newbox\b_enco_control_space - -\def\enco_fast_control_space_nop -  {\let\enco_fast_control_space\textcontrolspace} - -\def\enco_fast_control_space_yes -  {\setbox\b_enco_control_space\hbox{\space}% -   \setbox\b_enco_control_space\hbox to \wd\b_enco_control_space{\hss\fallbackcontrolspace\hss}% -   \let\enco_fast_control_space\flushcontrolspacebox} +     \asciispacechar % used for export ! +   \fi} -\def\flushcontrolspacebox -  {\copy\b_enco_control_space} +% \unexpanded\def\fastcontrolspace % no glyph resolving after first (use grouped) +%   {\enco_fast_control_space} +% +% \def\enco_fast_control_space +%   {\iffontchar\font\textcontrolspace +%      \enco_fast_control_space_nop +%    \else +%      \enco_fast_control_space_yes +%    \fi +%    \enco_fast_control_space} +% +% \newbox\b_enco_control_space +% +% \def\enco_fast_control_space_nop +%   {\let\enco_fast_control_space\textcontrolspace} +% +% \def\enco_fast_control_space_yes +%   {\setbox\b_enco_control_space\fallbackcontrolspace +%    \let\enco_fast_control_space\flushcontrolspacebox} +% +% \def\flushcontrolspacebox +%   {\copy\b_enco_control_space}  % a few defaults (\<whatever>{}), we really need the verbose \empty as it will be  % stringified .. anyhow, we define this at the lua end now but keep it here as a diff --git a/tex/context/base/file-lib.lua b/tex/context/base/file-lib.lua index 7489a317b..2471cdd84 100644 --- a/tex/context/base/file-lib.lua +++ b/tex/context/base/file-lib.lua @@ -44,7 +44,7 @@ function commands.uselibrary(specification) -- todo: reporter          local truename = environment.truefilename          local function found(filename)              local somename  = truename and truename(filename) or filename -            local foundname = getreadfilename("any",".",somename) +            local foundname = getreadfilename("any",".",somename) -- maybe some day also an option not to backtrack .. and ../.. (or block global)              return foundname ~= "" and foundname          end          for i=1,#files do diff --git a/tex/context/base/file-res.lua b/tex/context/base/file-res.lua index 9ae7a6b06..458ef7276 100644 --- a/tex/context/base/file-res.lua +++ b/tex/context/base/file-res.lua @@ -17,7 +17,10 @@ local report_files  = logs.reporter("files","readfile")  resolvers.maxreadlevel = 2 -directives.register("resolvers.maxreadlevel", function(v) resolvers.maxreadlevel = tonumber(v) or resolvers.maxreadlevel end) +directives.register("resolvers.maxreadlevel", function(v) + -- resolvers.maxreadlevel = (v == false and 0) or (v == true and 2) or tonumber(v) or 2 +    resolvers.maxreadlevel = v == false and 0 or tonumber(v) or 2 +end)  local finders, loaders, openers = resolvers.finders, resolvers.loaders, resolvers.openers diff --git a/tex/context/base/font-mis.lua b/tex/context/base/font-mis.lua index 8debcc3bb..de43c08a9 100644 --- a/tex/context/base/font-mis.lua +++ b/tex/context/base/font-mis.lua @@ -22,7 +22,7 @@ local handlers = fonts.handlers  handlers.otf   = handlers.otf or { }  local otf      = handlers.otf -otf.version    = otf.version or 2.756 +otf.version    = otf.version or 2.757  otf.cache      = otf.cache   or containers.define("fonts", "otf", otf.version, true)  function otf.loadcached(filename,format,sub) diff --git a/tex/context/base/font-otf.lua b/tex/context/base/font-otf.lua index ed9cabedc..4eeea2133 100644 --- a/tex/context/base/font-otf.lua +++ b/tex/context/base/font-otf.lua @@ -48,7 +48,7 @@ local otf                = fonts.handlers.otf  otf.glists               = { "gsub", "gpos" } -otf.version              = 2.756 -- beware: also sync font-mis.lua +otf.version              = 2.757 -- beware: also sync font-mis.lua  otf.cache                = containers.define("fonts", "otf", otf.version, true)  local fontdata           = fonts.hashes.identifiers @@ -694,7 +694,7 @@ elseif unicode >= 0x0F0000 and unicode <= 0x0FFFFD then  elseif unicode >= 0x100000 and unicode <= 0x10FFFD then                                  unicode = -1  end -                            local name    = glyph.name or cidnames[index] +                            local name = glyph.name or cidnames[index]                              if not unicode or unicode == -1 then -- or unicode >= criterium then                                  unicode = cidunicodes[index]                              end @@ -704,7 +704,7 @@ end                              end                              if not unicode or unicode == -1 then -- or unicode >= criterium then                                  if not name then -                                    name = format("u%06X",private) +                                    name = format("u%06X.ctx",private)                                  end                                  unicode = private                                  unicodes[name] = private @@ -714,8 +714,20 @@ end                                  private = private + 1                                  nofnames = nofnames + 1                              else +                             -- if unicode > criterium then +                             --     local taken = descriptions[unicode] +                             --     if taken then +                             --         private = private + 1 +                             --         descriptions[private] = taken +                             --         unicodes[taken.name] = private +                             --         indices[taken.index] = private +                             --         if trace_private then +                             --             report_otf("slot %U is moved to %U due to private in font",unicode) +                             --         end +                             --     end +                             -- end                                  if not name then -                                    name = format("u%06X",unicode) +                                    name = format("u%06X.ctx",unicode)                                  end                                  unicodes[name] = unicode                                  nofunicodes = nofunicodes + 1 @@ -763,11 +775,24 @@ end                      private = private + 1                  else                      unicodes[name] = unicode +                    if unicode > criterium then +                        -- \definedfont[file:HANBatang-LVT.ttf] \fontchar{uF0135} \char"F0135 +                        local taken = descriptions[unicode] +                        if taken then +                            private = private + 1 +                            descriptions[private] = taken +                            unicodes[taken.name] = private +                            indices[taken.index] = private +                            if trace_private then +                                report_otf("slot %U is moved to %U due to private in font",unicode) +                            end +                        end +                    end                  end                  indices[index] = unicode -                if not name then -                    name = format("u%06X",unicode) -                end +             -- if not name then +             --     name = format("u%06X",unicode) -- u%06X.ctx +             -- end                  descriptions[unicode] = {                   -- width       = glyph.width,                      boundingbox = glyph.boundingbox, @@ -1498,7 +1523,9 @@ local function check_variants(unicode,the_variants,splitter,unicodes)          for i=1,#glyphs do              local g = glyphs[i]              if done[g] then -                report_otf("skipping cyclic reference %U in math variant %U",g,unicode) +                if i > 1 then +                    report_otf("skipping cyclic reference %U in math variant %U",g,unicode) +                end              else                  if n == 0 then                      n = 1 diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf Binary files differindex 96f2ce099..15032953f 100644 --- a/tex/context/base/status-files.pdf +++ b/tex/context/base/status-files.pdf diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf Binary files differindex d0362cd72..6d2526742 100644 --- a/tex/context/base/status-lua.pdf +++ b/tex/context/base/status-lua.pdf diff --git a/tex/context/base/x-mathml.mkiv b/tex/context/base/x-mathml.mkiv index badccbc4d..5335e5ca0 100644 --- a/tex/context/base/x-mathml.mkiv +++ b/tex/context/base/x-mathml.mkiv @@ -530,11 +530,11 @@      } {          \doifsetupselse {mml:csymbol:#1} {              % full url -            \directsetup{mml:csymbol:#1} +            \fastsetup{mml:csymbol:#1}          } {              % somename (fallback)              \doifsetupselse {mml:csymbol:#2} { -                \directsetup{mml:csymbol:#2} +                \fastsetup{mml:csymbol:#2}              } {                  \xmlval{mmc:cs}{#3}{}% todo              } diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 99a0d35ab..3faa9ff54 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@  -- merged file : luatex-fonts-merged.lua  -- parent file : luatex-fonts.lua --- merge date  : 07/11/14 12:20:35 +-- merge date  : 07/14/14 12:38:06  do -- begin closure to overcome local limits and interference @@ -6681,7 +6681,7 @@ local report_otf=logs.reporter("fonts","otf loading")  local fonts=fonts  local otf=fonts.handlers.otf  otf.glists={ "gsub","gpos" } -otf.version=2.756  +otf.version=2.757   otf.cache=containers.define("fonts","otf",otf.version,true)  local fontdata=fonts.hashes.identifiers  local chardata=characters and characters.data  @@ -7241,7 +7241,7 @@ end                end                if not unicode or unicode==-1 then                   if not name then -                  name=format("u%06X",private) +                  name=format("u%06X.ctx",private)                  end                  unicode=private                  unicodes[name]=private @@ -7252,7 +7252,7 @@ end                  nofnames=nofnames+1                else                  if not name then -                  name=format("u%06X",unicode) +                  name=format("u%06X.ctx",unicode)                  end                  unicodes[name]=unicode                  nofunicodes=nofunicodes+1 @@ -7294,11 +7294,20 @@ end            private=private+1          else            unicodes[name]=unicode +          if unicode>criterium then +            local taken=descriptions[unicode] +            if taken then +              private=private+1 +              descriptions[private]=taken +              unicodes[taken.name]=private +              indices[taken.index]=private +              if trace_private then +                report_otf("slot %U is moved to %U due to private in font",unicode) +              end +            end +          end          end          indices[index]=unicode -        if not name then -          name=format("u%06X",unicode) -        end          descriptions[unicode]={            boundingbox=glyph.boundingbox,            name=name, @@ -7909,7 +7918,9 @@ local function check_variants(unicode,the_variants,splitter,unicodes)      for i=1,#glyphs do        local g=glyphs[i]        if done[g] then -        report_otf("skipping cyclic reference %U in math variant %U",g,unicode) +        if i>1 then +          report_otf("skipping cyclic reference %U in math variant %U",g,unicode) +        end        else          if n==0 then            n=1  | 
