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 |