From 16aa5a7c87f18a2483d0d61795899f886781b51c Mon Sep 17 00:00:00 2001
From: Karl Berry
We can use the attributes in the range 127-255 (outside user space). These
-are only used when no attribute is set at the \TEX\ end which normally
-happens in
private attributes are used by the system and public ones are for users. We use dedicated
+ranges of numbers for them. Of course a the
" + end + local function epar(result) + result[#result+1] = "
\n" + end + + 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] = formatters["%w%s>\n"](depth,namespaced[element]) + result[#result+1] = f_empty_inline_attr(namespaced[element],attributes(a)) end - linedone = true else - if skip == "comment" then - if show_comment then - result[#result+1] = formatters[""](namespaced[element]) - end - elseif skip then - -- ignore + 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] = formatters["%s>"](namespaced[element]) + result[#result+1] = f_empty_inline(namespaced[element]) end end - else - inlinedepth = inlinedepth - 1 + end + + local function begintag(result,element,nature,di,skip) + local index = di.n + local fulltag = di.fulltag + local specification = specifications[fulltag] or { } -- we can have a dummy + local comment = di.comment + local detail = specification.detail if skip == "comment" then if show_comment then - result[#result+1] = formatters[""](namespaced[element]) + 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["%s>"](namespaced[element]) - 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["This module implements some methods and creates additional datastructured @@ -37,6 +44,12 @@ from the big character table that we use for all kind of purposes: loaded!
--ldx]]-- +-- todo: in 'char-def.lua' assume defaults: +-- +-- directtions = l +-- cjkwd = a +-- linebreak = al + characters = characters or { } local characters = characters local data = characters.data @@ -54,7 +67,7 @@ end local pattern = (P("0x") + P("U+")) * ((R("09","AF")^1 * P(-1)) / function(s) return tonumber(s,16) end) -patterns.chartonumber = pattern +lpegpatterns.chartonumber = pattern local function chartonumber(k) if type(k) == "string" then @@ -145,6 +158,7 @@ local blocks = allocate { ["bamum"] = { first = 0x0A6A0, last = 0x0A6FF, description = "Bamum" }, ["bamumsupplement"] = { first = 0x16800, last = 0x16A3F, description = "Bamum Supplement" }, ["basiclatin"] = { first = 0x00000, last = 0x0007F, otf="latn", description = "Basic Latin" }, + ["bassavah"] = { first = 0x16AD0, last = 0x16AFF, description = "Bassa Vah" }, ["batak"] = { first = 0x01BC0, last = 0x01BFF, description = "Batak" }, ["bengali"] = { first = 0x00980, last = 0x009FF, otf="beng", description = "Bengali" }, ["blockelements"] = { first = 0x02580, last = 0x0259F, otf="bopo", description = "Block Elements" }, @@ -156,8 +170,9 @@ local blocks = allocate { ["buginese"] = { first = 0x01A00, last = 0x01A1F, otf="bugi", description = "Buginese" }, ["buhid"] = { first = 0x01740, last = 0x0175F, otf="buhd", description = "Buhid" }, ["byzantinemusicalsymbols"] = { first = 0x1D000, last = 0x1D0FF, otf="byzm", description = "Byzantine Musical Symbols" }, - ["commonindicnumberforms"] = { first = 0x0A830, last = 0x0A83F, description = "Common Indic Number Forms" }, ["carian"] = { first = 0x102A0, last = 0x102DF, description = "Carian" }, + ["caucasianalbanian"] = { first = 0x10530, last = 0x1056F, description = "Caucasian Albanian" }, + ["chakma"] = { first = 0x11100, last = 0x1114F, description = "Chakma" }, ["cham"] = { first = 0x0AA00, last = 0x0AA5F, description = "Cham" }, ["cherokee"] = { first = 0x013A0, last = 0x013FF, otf="cher", description = "Cherokee" }, ["cjkcompatibility"] = { first = 0x03300, last = 0x033FF, otf="hang", description = "CJK Compatibility" }, @@ -170,12 +185,17 @@ local blocks = allocate { ["cjkunifiedideographs"] = { first = 0x04E00, last = 0x09FFF, otf="hang", description = "CJK Unified Ideographs", catcode = "letter" }, ["cjkunifiedideographsextensiona"] = { first = 0x03400, last = 0x04DBF, otf="hang", description = "CJK Unified Ideographs Extension A" }, ["cjkunifiedideographsextensionb"] = { first = 0x20000, last = 0x2A6DF, otf="hang", description = "CJK Unified Ideographs Extension B" }, + ["cjkunifiedideographsextensionc"] = { first = 0x2A700, last = 0x2B73F, description = "CJK Unified Ideographs Extension C" }, + ["cjkunifiedideographsextensiond"] = { first = 0x2B740, last = 0x2B81F, description = "CJK Unified Ideographs Extension D" }, ["combiningdiacriticalmarks"] = { first = 0x00300, last = 0x0036F, description = "Combining Diacritical Marks" }, + ["combiningdiacriticalmarksextended"] = { first = 0x01AB0, last = 0x01AFF, description = "Combining Diacritical Marks Extended" }, ["combiningdiacriticalmarksforsymbols"] = { first = 0x020D0, last = 0x020FF, description = "Combining Diacritical Marks for Symbols" }, ["combiningdiacriticalmarkssupplement"] = { first = 0x01DC0, last = 0x01DFF, description = "Combining Diacritical Marks Supplement" }, ["combininghalfmarks"] = { first = 0x0FE20, last = 0x0FE2F, description = "Combining Half Marks" }, + ["commonindicnumberforms"] = { first = 0x0A830, last = 0x0A83F, description = "Common Indic Number Forms" }, ["controlpictures"] = { first = 0x02400, last = 0x0243F, description = "Control Pictures" }, ["coptic"] = { first = 0x02C80, last = 0x02CFF, otf="copt", description = "Coptic" }, + ["copticepactnumbers"] = { first = 0x102E0, last = 0x102FF, description = "Coptic Epact Numbers" }, ["countingrodnumerals"] = { first = 0x1D360, last = 0x1D37F, description = "Counting Rod Numerals" }, ["cuneiform"] = { first = 0x12000, last = 0x123FF, otf="xsux", description = "Cuneiform" }, ["cuneiformnumbersandpunctuation"] = { first = 0x12400, last = 0x1247F, otf="xsux", description = "Cuneiform Numbers and Punctuation" }, @@ -188,161 +208,256 @@ local blocks = allocate { ["deseret"] = { first = 0x10400, last = 0x1044F, otf="dsrt", description = "Deseret" }, ["devanagari"] = { first = 0x00900, last = 0x0097F, otf="deva", description = "Devanagari" }, ["devanagariextended"] = { first = 0x0A8E0, last = 0x0A8FF, description = "Devanagari Extended" }, - ["dingbats"] = { first = 0x02700, last = 0x027BF, description = "Dingbats" }, - ["dominotiles"] = { first = 0x1F030, last = 0x1F09F, description = "Domino Tiles" }, - ["egyptianhieroglyphs"] = { first = 0x13000, last = 0x1342F, description = "Egyptian Hieroglyphs" }, - ["emoticons"] = { first = 0x1F600, last = 0x1F64F, description = "Emoticons" }, - ["enclosedalphanumericsupplement"] = { first = 0x1F100, last = 0x1F1FF, description = "Enclosed Alphanumeric Supplement" }, - ["enclosedalphanumerics"] = { first = 0x02460, last = 0x024FF, description = "Enclosed Alphanumerics" }, - ["enclosedcjklettersandmonths"] = { first = 0x03200, last = 0x032FF, description = "Enclosed CJK Letters and Months" }, - ["enclosedideographicsupplement"] = { first = 0x1F200, last = 0x1F2FF, description = "Enclosed Ideographic Supplement" }, - ["ethiopic"] = { first = 0x01200, last = 0x0137F, otf="ethi", description = "Ethiopic" }, - ["ethiopicextended"] = { first = 0x02D80, last = 0x02DDF, otf="ethi", description = "Ethiopic Extended" }, - ["ethiopicextendeda"] = { first = 0x0AB00, last = 0x0AB2F, description = "Ethiopic Extended-A" }, - ["ethiopicsupplement"] = { first = 0x01380, last = 0x0139F, otf="ethi", description = "Ethiopic Supplement" }, - ["generalpunctuation"] = { first = 0x02000, last = 0x0206F, description = "General Punctuation" }, - ["geometricshapes"] = { first = 0x025A0, last = 0x025FF, description = "Geometric Shapes" }, - ["georgian"] = { first = 0x010A0, last = 0x010FF, otf="geor", description = "Georgian" }, - ["georgiansupplement"] = { first = 0x02D00, last = 0x02D2F, otf="geor", description = "Georgian Supplement" }, - ["glagolitic"] = { first = 0x02C00, last = 0x02C5F, otf="glag", description = "Glagolitic" }, - ["gothic"] = { first = 0x10330, last = 0x1034F, otf="goth", description = "Gothic" }, - ["greekandcoptic"] = { first = 0x00370, last = 0x003FF, otf="grek", description = "Greek and Coptic" }, - ["greekextended"] = { first = 0x01F00, last = 0x01FFF, otf="grek", description = "Greek Extended" }, - ["gujarati"] = { first = 0x00A80, last = 0x00AFF, otf="gujr", description = "Gujarati" }, - ["gurmukhi"] = { first = 0x00A00, last = 0x00A7F, otf="guru", description = "Gurmukhi" }, - ["halfwidthandfullwidthforms"] = { first = 0x0FF00, last = 0x0FFEF, description = "Halfwidth and Fullwidth Forms" }, - ["hangulcompatibilityjamo"] = { first = 0x03130, last = 0x0318F, otf="jamo", description = "Hangul Compatibility Jamo" }, - ["hanguljamo"] = { first = 0x01100, last = 0x011FF, otf="jamo", description = "Hangul Jamo" }, - ["hanguljamoextendeda"] = { first = 0x0A960, last = 0x0A97F, description = "Hangul Jamo Extended-A" }, - ["hanguljamoextendedb"] = { first = 0x0D7B0, last = 0x0D7FF, description = "Hangul Jamo Extended-B" }, - ["hangulsyllables"] = { first = 0x0AC00, last = 0x0D7AF, otf="hang", description = "Hangul Syllables" }, - ["hanunoo"] = { first = 0x01720, last = 0x0173F, otf="hano", description = "Hanunoo" }, - ["hebrew"] = { first = 0x00590, last = 0x005FF, otf="hebr", description = "Hebrew" }, - ["highprivateusesurrogates"] = { first = 0x0DB80, last = 0x0DBFF, description = "High Private Use Surrogates" }, - ["highsurrogates"] = { first = 0x0D800, last = 0x0DB7F, description = "High Surrogates" }, - ["hiragana"] = { first = 0x03040, last = 0x0309F, otf="kana", description = "Hiragana" }, - ["ideographicdescriptioncharacters"] = { first = 0x02FF0, last = 0x02FFF, description = "Ideographic Description Characters" }, - ["imperialaramaic"] = { first = 0x10840, last = 0x1085F, description = "Imperial Aramaic" }, - ["inscriptionalpahlavi"] = { first = 0x10B60, last = 0x10B7F, description = "Inscriptional Pahlavi" }, - ["inscriptionalparthian"] = { first = 0x10B40, last = 0x10B5F, description = "Inscriptional Parthian" }, - ["ipaextensions"] = { first = 0x00250, last = 0x002AF, description = "IPA Extensions" }, - ["javanese"] = { first = 0x0A980, last = 0x0A9DF, description = "Javanese" }, - ["kaithi"] = { first = 0x11080, last = 0x110CF, description = "Kaithi" }, - ["kanasupplement"] = { first = 0x1B000, last = 0x1B0FF, description = "Kana Supplement" }, - ["kanbun"] = { first = 0x03190, last = 0x0319F, description = "Kanbun" }, - ["kangxiradicals"] = { first = 0x02F00, last = 0x02FDF, description = "Kangxi Radicals" }, - ["kannada"] = { first = 0x00C80, last = 0x00CFF, otf="knda", description = "Kannada" }, - ["katakana"] = { first = 0x030A0, last = 0x030FF, otf="kana", description = "Katakana" }, - ["katakanaphoneticextensions"] = { first = 0x031F0, last = 0x031FF, otf="kana", description = "Katakana Phonetic Extensions" }, - ["kayahli"] = { first = 0x0A900, last = 0x0A92F, description = "Kayah Li" }, - ["kharoshthi"] = { first = 0x10A00, last = 0x10A5F, otf="khar", description = "Kharoshthi" }, - ["khmer"] = { first = 0x01780, last = 0x017FF, otf="khmr", description = "Khmer" }, - ["khmersymbols"] = { first = 0x019E0, last = 0x019FF, otf="khmr", description = "Khmer Symbols" }, - ["lao"] = { first = 0x00E80, last = 0x00EFF, otf="lao", description = "Lao" }, - ["latinextendeda"] = { first = 0x00100, last = 0x0017F, otf="latn", description = "Latin Extended-A" }, - ["latinextendedadditional"] = { first = 0x01E00, last = 0x01EFF, otf="latn", description = "Latin Extended Additional" }, - ["latinextendedb"] = { first = 0x00180, last = 0x0024F, otf="latn", description = "Latin Extended-B" }, - ["latinextendedc"] = { first = 0x02C60, last = 0x02C7F, otf="latn", description = "Latin Extended-C" }, - ["latinextendedd"] = { first = 0x0A720, last = 0x0A7FF, otf="latn", description = "Latin Extended-D" }, - ["latinsupplement"] = { first = 0x00080, last = 0x000FF, otf="latn", description = "Latin-1 Supplement" }, - ["lepcha"] = { first = 0x01C00, last = 0x01C4F, description = "Lepcha" }, - ["letterlikesymbols"] = { first = 0x02100, last = 0x0214F, description = "Letterlike Symbols" }, - ["limbu"] = { first = 0x01900, last = 0x0194F, otf="limb", description = "Limbu" }, - ["linearbideograms"] = { first = 0x10080, last = 0x100FF, otf="linb", description = "Linear B Ideograms" }, - ["linearbsyllabary"] = { first = 0x10000, last = 0x1007F, otf="linb", description = "Linear B Syllabary" }, - ["lisu"] = { first = 0x0A4D0, last = 0x0A4FF, description = "Lisu" }, - ["lowsurrogates"] = { first = 0x0DC00, last = 0x0DFFF, description = "Low Surrogates" }, - ["lycian"] = { first = 0x10280, last = 0x1029F, description = "Lycian" }, - ["lydian"] = { first = 0x10920, last = 0x1093F, description = "Lydian" }, - ["mahjongtiles"] = { first = 0x1F000, last = 0x1F02F, description = "Mahjong Tiles" }, - ["malayalam"] = { first = 0x00D00, last = 0x00D7F, otf="mlym", description = "Malayalam" }, - ["mandiac"] = { first = 0x00840, last = 0x0085F, otf="mand", description = "Mandaic" }, - ["mathematicalalphanumericsymbols"] = { first = 0x1D400, last = 0x1D7FF, description = "Mathematical Alphanumeric Symbols" }, - ["mathematicaloperators"] = { first = 0x02200, last = 0x022FF, description = "Mathematical Operators" }, - ["meeteimayek"] = { first = 0x0ABC0, last = 0x0ABFF, description = "Meetei Mayek" }, - ["meeteimayekextensions"] = { first = 0x0AAE0, last = 0x0AAFF, description = "Meetei Mayek Extensions" }, - ["meroiticcursive"] = { first = 0x109A0, last = 0x109FF, description = "Meroitic Cursive" }, - ["meroitichieroglyphs"] = { first = 0x10980, last = 0x1099F, description = "Meroitic Hieroglyphs" }, - ["miao"] = { first = 0x16F00, last = 0x16F9F, description = "Miao" }, - ["miscellaneousmathematicalsymbolsa"] = { first = 0x027C0, last = 0x027EF, description = "Miscellaneous Mathematical Symbols-A" }, - ["miscellaneousmathematicalsymbolsb"] = { first = 0x02980, last = 0x029FF, description = "Miscellaneous Mathematical Symbols-B" }, - ["miscellaneoussymbols"] = { first = 0x02600, last = 0x026FF, description = "Miscellaneous Symbols" }, - ["miscellaneoussymbolsandarrows"] = { first = 0x02B00, last = 0x02BFF, description = "Miscellaneous Symbols and Arrows" }, - ["miscellaneoussymbolsandpictographs"] = { first = 0x1F300, last = 0x1F5FF, description = "Miscellaneous Symbols And Pictographs" }, - ["miscellaneoustechnical"] = { first = 0x02300, last = 0x023FF, description = "Miscellaneous Technical" }, - ["modifiertoneletters"] = { first = 0x0A700, last = 0x0A71F, description = "Modifier Tone Letters" }, - ["mongolian"] = { first = 0x01800, last = 0x018AF, otf="mong", description = "Mongolian" }, - ["musicalsymbols"] = { first = 0x1D100, last = 0x1D1FF, otf="musc", description = "Musical Symbols" }, - ["myanmar"] = { first = 0x01000, last = 0x0109F, otf="mymr", description = "Myanmar" }, - ["myanmarextendeda"] = { first = 0x0AA60, last = 0x0AA7F, description = "Myanmar Extended-A" }, - ["newtailue"] = { first = 0x01980, last = 0x019DF, description = "New Tai Lue" }, - ["nko"] = { first = 0x007C0, last = 0x007FF, otf="nko", description = "NKo" }, - ["numberforms"] = { first = 0x02150, last = 0x0218F, description = "Number Forms" }, - ["ogham"] = { first = 0x01680, last = 0x0169F, otf="ogam", description = "Ogham" }, - ["olchiki"] = { first = 0x01C50, last = 0x01C7F, description = "Ol Chiki" }, - ["olditalic"] = { first = 0x10300, last = 0x1032F, otf="ital", description = "Old Italic" }, - ["oldpersian"] = { first = 0x103A0, last = 0x103DF, otf="xpeo", description = "Old Persian" }, - ["oldsoutharabian"] = { first = 0x10A60, last = 0x10A7F, description = "Old South Arabian" }, - ["odlturkic"] = { first = 0x10C00, last = 0x10C4F, description = "Old Turkic" }, - ["opticalcharacterrecognition"] = { first = 0x02440, last = 0x0245F, description = "Optical Character Recognition" }, - ["oriya"] = { first = 0x00B00, last = 0x00B7F, otf="orya", description = "Oriya" }, - ["osmanya"] = { first = 0x10480, last = 0x104AF, otf="osma", description = "Osmanya" }, - ["phagspa"] = { first = 0x0A840, last = 0x0A87F, otf="phag", description = "Phags-pa" }, - ["phaistosdisc"] = { first = 0x101D0, last = 0x101FF, description = "Phaistos Disc" }, - ["phoenician"] = { first = 0x10900, last = 0x1091F, otf="phnx", description = "Phoenician" }, - ["phoneticextensions"] = { first = 0x01D00, last = 0x01D7F, description = "Phonetic Extensions" }, - ["phoneticextensionssupplement"] = { first = 0x01D80, last = 0x01DBF, description = "Phonetic Extensions Supplement" }, - ["playingcards"] = { first = 0x1F0A0, last = 0x1F0FF, description = "Playing Cards" }, - ["privateusearea"] = { first = 0x0E000, last = 0x0F8FF, description = "Private Use Area" }, - ["rejang"] = { first = 0x0A930, last = 0x0A95F, description = "Rejang" }, - ["ruminumeralsymbols"] = { first = 0x10E60, last = 0x10E7F, description = "Rumi Numeral Symbols" }, - ["runic"] = { first = 0x016A0, last = 0x016FF, otf="runr", description = "Runic" }, - ["samaritan"] = { first = 0x00800, last = 0x0083F, description = "Samaritan" }, - ["saurashtra"] = { first = 0x0A880, last = 0x0A8DF, description = "Saurashtra" }, - ["sharada"] = { first = 0x11180, last = 0x111DF, description = "Sharada" }, - ["shavian"] = { first = 0x10450, last = 0x1047F, otf="shaw", description = "Shavian" }, - ["sinhala"] = { first = 0x00D80, last = 0x00DFF, otf="sinh", description = "Sinhala" }, - ["smallformvariants"] = { first = 0x0FE50, last = 0x0FE6F, description = "Small Form Variants" }, - ["sorasompeng"] = { first = 0x110D0, last = 0x110FF, description = "Sora Sompeng" }, - ["spacingmodifierletters"] = { first = 0x002B0, last = 0x002FF, description = "Spacing Modifier Letters" }, - ["specials"] = { first = 0x0FFF0, last = 0x0FFFF, description = "Specials" }, - ["sundanese"] = { first = 0x01B80, last = 0x01BBF, description = "Sundanese" }, - ["sundanesesupplement"] = { first = 0x01CC0, last = 0x01CCF, description = "Sundanese Supplement" }, - ["superscriptsandsubscripts"] = { first = 0x02070, last = 0x0209F, description = "Superscripts and Subscripts" }, - ["supplementalarrowsa"] = { first = 0x027F0, last = 0x027FF, description = "Supplemental Arrows-A" }, - ["supplementalarrowsb"] = { first = 0x02900, last = 0x0297F, description = "Supplemental Arrows-B" }, - ["supplementalmathematicaloperators"] = { first = 0x02A00, last = 0x02AFF, description = "Supplemental Mathematical Operators" }, - ["supplementalpunctuation"] = { first = 0x02E00, last = 0x02E7F, description = "Supplemental Punctuation" }, - ["supplementaryprivateuseareaa"] = { first = 0xF0000, last = 0xFFFFF, description = "Supplementary Private Use Area-A" }, - ["supplementaryprivateuseareab"] = { first = 0x100000,last = 0x10FFFF, description = "Supplementary Private Use Area-B" }, - ["sylotinagri"] = { first = 0x0A800, last = 0x0A82F, otf="sylo", description = "Syloti Nagri" }, - ["syriac"] = { first = 0x00700, last = 0x0074F, otf="syrc", description = "Syriac" }, - ["tagalog"] = { first = 0x01700, last = 0x0171F, otf="tglg", description = "Tagalog" }, - ["tagbanwa"] = { first = 0x01760, last = 0x0177F, otf="tagb", description = "Tagbanwa" }, - ["tags"] = { first = 0xE0000, last = 0xE007F, description = "Tags" }, - ["taile"] = { first = 0x01950, last = 0x0197F, otf="tale", description = "Tai Le" }, - ["taitham"] = { first = 0x01A20, last = 0x01AAF, description = "Tai Tham" }, - ["taiviet"] = { first = 0x0AA80, last = 0x0AADF, description = "Tai Viet" }, - ["taixuanjingsymbols"] = { first = 0x1D300, last = 0x1D35F, description = "Tai Xuan Jing Symbols" }, - ["takri"] = { first = 0x11680, last = 0x116CF, description = "Takri" }, - ["tamil"] = { first = 0x00B80, last = 0x00BFF, otf="taml", description = "Tamil" }, - ["telugu"] = { first = 0x00C00, last = 0x00C7F, otf="telu", description = "Telugu" }, - ["thaana"] = { first = 0x00780, last = 0x007BF, otf="thaa", description = "Thaana" }, - ["thai"] = { first = 0x00E00, last = 0x00E7F, otf="thai", description = "Thai" }, - ["tibetan"] = { first = 0x00F00, last = 0x00FFF, otf="tibt", description = "Tibetan" }, - ["tifinagh"] = { first = 0x02D30, last = 0x02D7F, otf="tfng", description = "Tifinagh" }, - ["transportandmapsymbols"] = { first = 0x1F680, last = 0x1F6FF, description = "Transport And Map Symbols" }, - ["ugaritic"] = { first = 0x10380, last = 0x1039F, otf="ugar", description = "Ugaritic" }, - ["unifiedcanadianaboriginalsyllabics"] = { first = 0x01400, last = 0x0167F, otf="cans", description = "Unified Canadian Aboriginal Syllabics" }, - ["unifiedcanadianaboriginalsyllabicsextended"] = { first = 0x018B0, last = 0x018FF, description = "Unified Canadian Aboriginal Syllabics Extended" }, - ["vai"] = { first = 0x0A500, last = 0x0A63F, description = "Vai" }, - ["variationselectors"] = { first = 0x0FE00, last = 0x0FE0F, description = "Variation Selectors" }, - ["variationselectorssupplement"] = { first = 0xE0100, last = 0xE01EF, description = "Variation Selectors Supplement" }, - ["vedicextensions"] = { first = 0x01CD0, last = 0x01CFF, description = "Vedic Extensions" }, - ["verticalforms"] = { first = 0x0FE10, last = 0x0FE1F, description = "Vertical Forms" }, - ["yijinghexagramsymbols"] = { first = 0x04DC0, last = 0x04DFF, otf="yi", description = "Yijing Hexagram Symbols" }, - ["yiradicals"] = { first = 0x0A490, last = 0x0A4CF, otf="yi", description = "Yi Radicals" }, - ["yisyllables"] = { first = 0x0A000, last = 0x0A48F, otf="yi", description = "Yi Syllables" }, + ["digitsarabicindic"] = { first = 0x00660, last = 0x00669, math = true }, + -- ["digitsbengali"] = { first = 0x009E6, last = 0x009EF, math = true }, + ["digitsbold"] = { first = 0x1D7CE, last = 0x1D7D8, math = true }, + -- ["digitsdevanagari"] = { first = 0x00966, last = 0x0096F, math = true }, + ["digitsdoublestruck"] = { first = 0x1D7D8, last = 0x1D7E2, math = true }, + -- ["digitsethiopic"] = { first = 0x01369, last = 0x01371, math = true }, + ["digitsextendedarabicindic"] = { first = 0x006F0, last = 0x006F9, math = true }, + -- ["digitsgujarati"] = { first = 0x00AE6, last = 0x00AEF, math = true }, + -- ["digitsgurmukhi"] = { first = 0x00A66, last = 0x00A6F, math = true }, + -- ["digitskannada"] = { first = 0x00CE6, last = 0x00CEF, math = true }, + -- ["digitskhmer"] = { first = 0x017E0, last = 0x017E9, math = true }, + -- ["digitslao"] = { first = 0x00ED0, last = 0x00ED9, math = true }, + ["digitslatin"] = { first = 0x00030, last = 0x00039, math = true }, + -- ["digitsmalayalam"] = { first = 0x00D66, last = 0x00D6F, math = true }, + -- ["digitsmongolian"] = { first = 0x01810, last = 0x01809, math = true }, + ["digitsmonospace"] = { first = 0x1D7F6, last = 0x1D80F, math = true }, + -- ["digitsmyanmar"] = { first = 0x01040, last = 0x01049, math = true }, + ["digitsnormal"] = { first = 0x00030, last = 0x00039, math = true }, + -- ["digitsoriya"] = { first = 0x00B66, last = 0x00B6F, math = true }, + ["digitssansserifbold"] = { first = 0x1D7EC, last = 0x1D805, math = true }, + ["digitssansserifnormal"] = { first = 0x1D7E2, last = 0x1D7EC, math = true }, + -- ["digitstamil"] = { first = 0x00030, last = 0x00039, math = true }, -- no zero + -- ["digitstelugu"] = { first = 0x00C66, last = 0x00C6F, math = true }, + -- ["digitsthai"] = { first = 0x00E50, last = 0x00E59, math = true }, + -- ["digitstibetan"] = { first = 0x00F20, last = 0x00F29, math = true }, + ["dingbats"] = { first = 0x02700, last = 0x027BF, description = "Dingbats" }, + ["dominotiles"] = { first = 0x1F030, last = 0x1F09F, description = "Domino Tiles" }, + ["duployan"] = { first = 0x1BC00, last = 0x1BC9F, description = "Duployan" }, + ["egyptianhieroglyphs"] = { first = 0x13000, last = 0x1342F, description = "Egyptian Hieroglyphs" }, + ["elbasan"] = { first = 0x10500, last = 0x1052F, description = "Elbasan" }, + ["emoticons"] = { first = 0x1F600, last = 0x1F64F, description = "Emoticons" }, + ["enclosedalphanumerics"] = { first = 0x02460, last = 0x024FF, description = "Enclosed Alphanumerics" }, + ["enclosedalphanumericsupplement"] = { first = 0x1F100, last = 0x1F1FF, description = "Enclosed Alphanumeric Supplement" }, + ["enclosedcjklettersandmonths"] = { first = 0x03200, last = 0x032FF, description = "Enclosed CJK Letters and Months" }, + ["enclosedideographicsupplement"] = { first = 0x1F200, last = 0x1F2FF, description = "Enclosed Ideographic Supplement" }, + ["ethiopic"] = { first = 0x01200, last = 0x0137F, otf="ethi", description = "Ethiopic" }, + ["ethiopicextended"] = { first = 0x02D80, last = 0x02DDF, otf="ethi", description = "Ethiopic Extended" }, + ["ethiopicextendeda"] = { first = 0x0AB00, last = 0x0AB2F, description = "Ethiopic Extended-A" }, + ["ethiopicsupplement"] = { first = 0x01380, last = 0x0139F, otf="ethi", description = "Ethiopic Supplement" }, + ["generalpunctuation"] = { first = 0x02000, last = 0x0206F, description = "General Punctuation" }, + ["geometricshapes"] = { first = 0x025A0, last = 0x025FF, description = "Geometric Shapes" }, + ["geometricshapes"] = { first = 0x025A0, last = 0x025FF, math = true }, + ["geometricshapesextended"] = { first = 0x1F780, last = 0x1F7FF, description = "Geometric Shapes Extended" }, + ["georgian"] = { first = 0x010A0, last = 0x010FF, otf="geor", description = "Georgian" }, + ["georgiansupplement"] = { first = 0x02D00, last = 0x02D2F, otf="geor", description = "Georgian Supplement" }, + ["glagolitic"] = { first = 0x02C00, last = 0x02C5F, otf="glag", description = "Glagolitic" }, + ["gothic"] = { first = 0x10330, last = 0x1034F, otf="goth", description = "Gothic" }, + ["grantha"] = { first = 0x11300, last = 0x1137F, description = "Grantha" }, + ["greekandcoptic"] = { first = 0x00370, last = 0x003FF, otf="grek", description = "Greek and Coptic" }, + ["greekextended"] = { first = 0x01F00, last = 0x01FFF, otf="grek", description = "Greek Extended" }, + ["gujarati"] = { first = 0x00A80, last = 0x00AFF, otf="gujr", description = "Gujarati" }, + ["gurmukhi"] = { first = 0x00A00, last = 0x00A7F, otf="guru", description = "Gurmukhi" }, + ["halfwidthandfullwidthforms"] = { first = 0x0FF00, last = 0x0FFEF, description = "Halfwidth and Fullwidth Forms" }, + ["hangulcompatibilityjamo"] = { first = 0x03130, last = 0x0318F, otf="jamo", description = "Hangul Compatibility Jamo" }, + ["hanguljamo"] = { first = 0x01100, last = 0x011FF, otf="jamo", description = "Hangul Jamo" }, + ["hanguljamoextendeda"] = { first = 0x0A960, last = 0x0A97F, description = "Hangul Jamo Extended-A" }, + ["hanguljamoextendedb"] = { first = 0x0D7B0, last = 0x0D7FF, description = "Hangul Jamo Extended-B" }, + ["hangulsyllables"] = { first = 0x0AC00, last = 0x0D7AF, otf="hang", description = "Hangul Syllables" }, + ["hanunoo"] = { first = 0x01720, last = 0x0173F, otf="hano", description = "Hanunoo" }, + ["hebrew"] = { first = 0x00590, last = 0x005FF, otf="hebr", description = "Hebrew" }, + ["highprivateusesurrogates"] = { first = 0x0DB80, last = 0x0DBFF, description = "High Private Use Surrogates" }, + ["highsurrogates"] = { first = 0x0D800, last = 0x0DB7F, description = "High Surrogates" }, + ["hiragana"] = { first = 0x03040, last = 0x0309F, otf="kana", description = "Hiragana" }, + ["ideographicdescriptioncharacters"] = { first = 0x02FF0, last = 0x02FFF, description = "Ideographic Description Characters" }, + ["imperialaramaic"] = { first = 0x10840, last = 0x1085F, description = "Imperial Aramaic" }, + ["inscriptionalpahlavi"] = { first = 0x10B60, last = 0x10B7F, description = "Inscriptional Pahlavi" }, + ["inscriptionalparthian"] = { first = 0x10B40, last = 0x10B5F, description = "Inscriptional Parthian" }, + ["ipaextensions"] = { first = 0x00250, last = 0x002AF, description = "IPA Extensions" }, + ["javanese"] = { first = 0x0A980, last = 0x0A9DF, description = "Javanese" }, + ["kaithi"] = { first = 0x11080, last = 0x110CF, description = "Kaithi" }, + ["kanasupplement"] = { first = 0x1B000, last = 0x1B0FF, description = "Kana Supplement" }, + ["kanbun"] = { first = 0x03190, last = 0x0319F, description = "Kanbun" }, + ["kangxiradicals"] = { first = 0x02F00, last = 0x02FDF, description = "Kangxi Radicals" }, + ["kannada"] = { first = 0x00C80, last = 0x00CFF, otf="knda", description = "Kannada" }, + ["katakana"] = { first = 0x030A0, last = 0x030FF, otf="kana", description = "Katakana" }, + ["katakanaphoneticextensions"] = { first = 0x031F0, last = 0x031FF, otf="kana", description = "Katakana Phonetic Extensions" }, + ["kayahli"] = { first = 0x0A900, last = 0x0A92F, description = "Kayah Li" }, + ["kharoshthi"] = { first = 0x10A00, last = 0x10A5F, otf="khar", description = "Kharoshthi" }, + ["khmer"] = { first = 0x01780, last = 0x017FF, otf="khmr", description = "Khmer" }, + ["khmersymbols"] = { first = 0x019E0, last = 0x019FF, otf="khmr", description = "Khmer Symbols" }, + ["khojki"] = { first = 0x11200, last = 0x1124F, description = "Khojki" }, + ["khudawadi"] = { first = 0x112B0, last = 0x112FF, description = "Khudawadi" }, + ["lao"] = { first = 0x00E80, last = 0x00EFF, otf="lao", description = "Lao" }, + ["latinextendeda"] = { first = 0x00100, last = 0x0017F, otf="latn", description = "Latin Extended-A" }, + ["latinextendedadditional"] = { first = 0x01E00, last = 0x01EFF, otf="latn", description = "Latin Extended Additional" }, + ["latinextendedb"] = { first = 0x00180, last = 0x0024F, otf="latn", description = "Latin Extended-B" }, + ["latinextendedc"] = { first = 0x02C60, last = 0x02C7F, otf="latn", description = "Latin Extended-C" }, + ["latinextendedd"] = { first = 0x0A720, last = 0x0A7FF, otf="latn", description = "Latin Extended-D" }, + ["latinextendede"] = { first = 0x0AB30, last = 0x0AB6F, description = "Latin Extended-E" }, + ["latinsupplement"] = { first = 0x00080, last = 0x000FF, otf="latn", description = "Latin-1 Supplement" }, + ["lepcha"] = { first = 0x01C00, last = 0x01C4F, description = "Lepcha" }, + ["letterlikesymbols"] = { first = 0x02100, last = 0x0214F, description = "Letterlike Symbols" }, + ["letterlikesymbols"] = { first = 0x02100, last = 0x0214F, math = true }, + ["limbu"] = { first = 0x01900, last = 0x0194F, otf="limb", description = "Limbu" }, + ["lineara"] = { first = 0x10600, last = 0x1077F, description = "Linear A" }, + ["linearbideograms"] = { first = 0x10080, last = 0x100FF, otf="linb", description = "Linear B Ideograms" }, + ["linearbsyllabary"] = { first = 0x10000, last = 0x1007F, otf="linb", description = "Linear B Syllabary" }, + ["lisu"] = { first = 0x0A4D0, last = 0x0A4FF, description = "Lisu" }, + ["lowercasebold"] = { first = 0x1D41A, last = 0x1D433, math = true }, + ["lowercaseboldfraktur"] = { first = 0x1D586, last = 0x1D59F, math = true }, + ["lowercasebolditalic"] = { first = 0x1D482, last = 0x1D49B, math = true }, + ["lowercaseboldscript"] = { first = 0x1D4EA, last = 0x1D503, math = true }, + ["lowercasedoublestruck"] = { first = 0x1D552, last = 0x1D56B, math = true }, + ["lowercasefraktur"] = { first = 0x1D51E, last = 0x1D537, math = true }, + ["lowercasegreekbold"] = { first = 0x1D6C2, last = 0x1D6DB, math = true }, + ["lowercasegreekbolditalic"] = { first = 0x1D736, last = 0x1D74F, math = true }, + ["lowercasegreekitalic"] = { first = 0x1D6FC, last = 0x1D715, math = true }, + ["lowercasegreeknormal"] = { first = 0x003B1, last = 0x003CA, math = true }, + ["lowercasegreeksansserifbold"] = { first = 0x1D770, last = 0x1D789, math = true }, + ["lowercasegreeksansserifbolditalic"] = { first = 0x1D7AA, last = 0x1D7C3, math = true }, + ["lowercaseitalic"] = { first = 0x1D44E, last = 0x1D467, math = true }, + ["lowercasemonospace"] = { first = 0x1D68A, last = 0x1D6A3, math = true }, + ["lowercasenormal"] = { first = 0x00061, last = 0x0007A, math = true }, + ["lowercasesansserifbold"] = { first = 0x1D5EE, last = 0x1D607, math = true }, + ["lowercasesansserifbolditalic"] = { first = 0x1D656, last = 0x1D66F, math = true }, + ["lowercasesansserifitalic"] = { first = 0x1D622, last = 0x1D63B, math = true }, + ["lowercasesansserifnormal"] = { first = 0x1D5BA, last = 0x1D5D3, math = true }, + ["lowercasescript"] = { first = 0x1D4B6, last = 0x1D4CF, math = true }, + ["lowsurrogates"] = { first = 0x0DC00, last = 0x0DFFF, description = "Low Surrogates" }, + ["lycian"] = { first = 0x10280, last = 0x1029F, description = "Lycian" }, + ["lydian"] = { first = 0x10920, last = 0x1093F, description = "Lydian" }, + ["mahajani"] = { first = 0x11150, last = 0x1117F, description = "Mahajani" }, + ["mahjongtiles"] = { first = 0x1F000, last = 0x1F02F, description = "Mahjong Tiles" }, + ["malayalam"] = { first = 0x00D00, last = 0x00D7F, otf="mlym", description = "Malayalam" }, + ["mandaic"] = { first = 0x00840, last = 0x0085F, otf="mand", description = "Mandaic" }, + ["manichaean"] = { first = 0x10AC0, last = 0x10AFF, description = "Manichaean" }, + ["mathematicalalphanumericsymbols"] = { first = 0x1D400, last = 0x1D7FF, math = true, description = "Mathematical Alphanumeric Symbols" }, + ["mathematicaloperators"] = { first = 0x02200, last = 0x022FF, math = true, description = "Mathematical Operators" }, + ["meeteimayek"] = { first = 0x0ABC0, last = 0x0ABFF, description = "Meetei Mayek" }, + ["meeteimayekextensions"] = { first = 0x0AAE0, last = 0x0AAFF, description = "Meetei Mayek Extensions" }, + ["mendekikakui"] = { first = 0x1E800, last = 0x1E8DF, description = "Mende Kikakui" }, + ["meroiticcursive"] = { first = 0x109A0, last = 0x109FF, description = "Meroitic Cursive" }, + ["meroitichieroglyphs"] = { first = 0x10980, last = 0x1099F, description = "Meroitic Hieroglyphs" }, + ["miao"] = { first = 0x16F00, last = 0x16F9F, description = "Miao" }, + ["miscellaneousmathematicalsymbolsa"] = { first = 0x027C0, last = 0x027EF, math = true, description = "Miscellaneous Mathematical Symbols-A" }, + ["miscellaneousmathematicalsymbolsb"] = { first = 0x02980, last = 0x029FF, math = true, description = "Miscellaneous Mathematical Symbols-B" }, + ["miscellaneoussymbols"] = { first = 0x02600, last = 0x026FF, math = true, description = "Miscellaneous Symbols" }, + ["miscellaneoussymbolsandarrows"] = { first = 0x02B00, last = 0x02BFF, math = true, description = "Miscellaneous Symbols and Arrows" }, + ["miscellaneoussymbolsandpictographs"] = { first = 0x1F300, last = 0x1F5FF, description = "Miscellaneous Symbols and Pictographs" }, + ["miscellaneoustechnical"] = { first = 0x02300, last = 0x023FF, math = true, description = "Miscellaneous Technical" }, + ["modi"] = { first = 0x11600, last = 0x1165F, description = "Modi" }, + ["modifiertoneletters"] = { first = 0x0A700, last = 0x0A71F, description = "Modifier Tone Letters" }, + ["mongolian"] = { first = 0x01800, last = 0x018AF, otf="mong", description = "Mongolian" }, + ["mro"] = { first = 0x16A40, last = 0x16A6F, description = "Mro" }, + ["musicalsymbols"] = { first = 0x1D100, last = 0x1D1FF, otf="musc", description = "Musical Symbols" }, + ["myanmar"] = { first = 0x01000, last = 0x0109F, otf="mymr", description = "Myanmar" }, + ["myanmarextendeda"] = { first = 0x0AA60, last = 0x0AA7F, description = "Myanmar Extended-A" }, + ["myanmarextendedb"] = { first = 0x0A9E0, last = 0x0A9FF, description = "Myanmar Extended-B" }, + ["nabataean"] = { first = 0x10880, last = 0x108AF, description = "Nabataean" }, + ["newtailue"] = { first = 0x01980, last = 0x019DF, description = "New Tai Lue" }, + ["nko"] = { first = 0x007C0, last = 0x007FF, otf="nko", description = "NKo" }, + ["numberforms"] = { first = 0x02150, last = 0x0218F, description = "Number Forms" }, + ["ogham"] = { first = 0x01680, last = 0x0169F, otf="ogam", description = "Ogham" }, + ["olchiki"] = { first = 0x01C50, last = 0x01C7F, description = "Ol Chiki" }, + ["olditalic"] = { first = 0x10300, last = 0x1032F, otf="ital", description = "Old Italic" }, + ["oldnortharabian"] = { first = 0x10A80, last = 0x10A9F, description = "Old North Arabian" }, + ["oldpermic"] = { first = 0x10350, last = 0x1037F, description = "Old Permic" }, + ["oldpersian"] = { first = 0x103A0, last = 0x103DF, otf="xpeo", description = "Old Persian" }, + ["oldsoutharabian"] = { first = 0x10A60, last = 0x10A7F, description = "Old South Arabian" }, + ["oldturkic"] = { first = 0x10C00, last = 0x10C4F, description = "Old Turkic" }, + ["opticalcharacterrecognition"] = { first = 0x02440, last = 0x0245F, description = "Optical Character Recognition" }, + ["oriya"] = { first = 0x00B00, last = 0x00B7F, otf="orya", description = "Oriya" }, + ["ornamentaldingbats"] = { first = 0x1F650, last = 0x1F67F, description = "Ornamental Dingbats" }, + ["osmanya"] = { first = 0x10480, last = 0x104AF, otf="osma", description = "Osmanya" }, + ["pahawhhmong"] = { first = 0x16B00, last = 0x16B8F, description = "Pahawh Hmong" }, + ["palmyrene"] = { first = 0x10860, last = 0x1087F, description = "Palmyrene" }, + ["paucinhau"] = { first = 0x11AC0, last = 0x11AFF, description = "Pau Cin Hau" }, + ["phagspa"] = { first = 0x0A840, last = 0x0A87F, otf="phag", description = "Phags-pa" }, + ["phaistosdisc"] = { first = 0x101D0, last = 0x101FF, description = "Phaistos Disc" }, + ["phoenician"] = { first = 0x10900, last = 0x1091F, otf="phnx", description = "Phoenician" }, + ["phoneticextensions"] = { first = 0x01D00, last = 0x01D7F, description = "Phonetic Extensions" }, + ["phoneticextensionssupplement"] = { first = 0x01D80, last = 0x01DBF, description = "Phonetic Extensions Supplement" }, + ["playingcards"] = { first = 0x1F0A0, last = 0x1F0FF, description = "Playing Cards" }, + ["privateusearea"] = { first = 0x0E000, last = 0x0F8FF, description = "Private Use Area" }, + ["psalterpahlavi"] = { first = 0x10B80, last = 0x10BAF, description = "Psalter Pahlavi" }, + ["rejang"] = { first = 0x0A930, last = 0x0A95F, description = "Rejang" }, + ["ruminumeralsymbols"] = { first = 0x10E60, last = 0x10E7F, description = "Rumi Numeral Symbols" }, + ["runic"] = { first = 0x016A0, last = 0x016FF, otf="runr", description = "Runic" }, + ["samaritan"] = { first = 0x00800, last = 0x0083F, description = "Samaritan" }, + ["saurashtra"] = { first = 0x0A880, last = 0x0A8DF, description = "Saurashtra" }, + ["sharada"] = { first = 0x11180, last = 0x111DF, description = "Sharada" }, + ["shavian"] = { first = 0x10450, last = 0x1047F, otf="shaw", description = "Shavian" }, + ["shorthandformatcontrols"] = { first = 0x1BCA0, last = 0x1BCAF, description = "Shorthand Format Controls" }, + ["siddham"] = { first = 0x11580, last = 0x115FF, description = "Siddham" }, + ["sinhala"] = { first = 0x00D80, last = 0x00DFF, otf="sinh", description = "Sinhala" }, + ["sinhalaarchaicnumbers"] = { first = 0x111E0, last = 0x111FF, description = "Sinhala Archaic Numbers" }, + ["smallformvariants"] = { first = 0x0FE50, last = 0x0FE6F, description = "Small Form Variants" }, + ["sorasompeng"] = { first = 0x110D0, last = 0x110FF, description = "Sora Sompeng" }, + ["spacingmodifierletters"] = { first = 0x002B0, last = 0x002FF, description = "Spacing Modifier Letters" }, + ["specials"] = { first = 0x0FFF0, last = 0x0FFFF, description = "Specials" }, + ["sundanese"] = { first = 0x01B80, last = 0x01BBF, description = "Sundanese" }, + ["sundanesesupplement"] = { first = 0x01CC0, last = 0x01CCF, description = "Sundanese Supplement" }, + ["superscriptsandsubscripts"] = { first = 0x02070, last = 0x0209F, description = "Superscripts and Subscripts" }, + ["supplementalarrowsa"] = { first = 0x027F0, last = 0x027FF, math = true, description = "Supplemental Arrows-A" }, + ["supplementalarrowsb"] = { first = 0x02900, last = 0x0297F, math = true, description = "Supplemental Arrows-B" }, + ["supplementalarrowsc"] = { first = 0x1F800, last = 0x1F8FF, math = true, description = "Supplemental Arrows-C" }, + ["supplementalmathematicaloperators"] = { first = 0x02A00, last = 0x02AFF, math = true, description = "Supplemental Mathematical Operators" }, + ["supplementalpunctuation"] = { first = 0x02E00, last = 0x02E7F, description = "Supplemental Punctuation" }, + ["supplementaryprivateuseareaa"] = { first = 0xF0000, last = 0xFFFFF, description = "Supplementary Private Use Area-A" }, + ["supplementaryprivateuseareab"] = { first = 0x100000,last = 0x10FFFF, description = "Supplementary Private Use Area-B" }, + ["sylotinagri"] = { first = 0x0A800, last = 0x0A82F, otf="sylo", description = "Syloti Nagri" }, + ["syriac"] = { first = 0x00700, last = 0x0074F, otf="syrc", description = "Syriac" }, + ["tagalog"] = { first = 0x01700, last = 0x0171F, otf="tglg", description = "Tagalog" }, + ["tagbanwa"] = { first = 0x01760, last = 0x0177F, otf="tagb", description = "Tagbanwa" }, + ["tags"] = { first = 0xE0000, last = 0xE007F, description = "Tags" }, + ["taile"] = { first = 0x01950, last = 0x0197F, otf="tale", description = "Tai Le" }, + ["taitham"] = { first = 0x01A20, last = 0x01AAF, description = "Tai Tham" }, + ["taiviet"] = { first = 0x0AA80, last = 0x0AADF, description = "Tai Viet" }, + ["taixuanjingsymbols"] = { first = 0x1D300, last = 0x1D35F, description = "Tai Xuan Jing Symbols" }, + ["takri"] = { first = 0x11680, last = 0x116CF, description = "Takri" }, + ["tamil"] = { first = 0x00B80, last = 0x00BFF, otf="taml", description = "Tamil" }, + ["telugu"] = { first = 0x00C00, last = 0x00C7F, otf="telu", description = "Telugu" }, + ["thaana"] = { first = 0x00780, last = 0x007BF, otf="thaa", description = "Thaana" }, + ["thai"] = { first = 0x00E00, last = 0x00E7F, otf="thai", description = "Thai" }, + ["tibetan"] = { first = 0x00F00, last = 0x00FFF, otf="tibt", description = "Tibetan" }, + ["tifinagh"] = { first = 0x02D30, last = 0x02D7F, otf="tfng", description = "Tifinagh" }, + ["tirhuta"] = { first = 0x11480, last = 0x114DF, description = "Tirhuta" }, + ["transportandmapsymbols"] = { first = 0x1F680, last = 0x1F6FF, description = "Transport and Map Symbols" }, + ["ugaritic"] = { first = 0x10380, last = 0x1039F, otf="ugar", description = "Ugaritic" }, + ["unifiedcanadianaboriginalsyllabics"] = { first = 0x01400, last = 0x0167F, otf="cans", description = "Unified Canadian Aboriginal Syllabics" }, + ["unifiedcanadianaboriginalsyllabicsextended"] = { first = 0x018B0, last = 0x018FF, description = "Unified Canadian Aboriginal Syllabics Extended" }, + ["uppercasebold"] = { first = 0x1D400, last = 0x1D419, math = true }, + ["uppercaseboldfraktur"] = { first = 0x1D56C, last = 0x1D585, math = true }, + ["uppercasebolditalic"] = { first = 0x1D468, last = 0x1D481, math = true }, + ["uppercaseboldscript"] = { first = 0x1D4D0, last = 0x1D4E9, math = true }, + ["uppercasedoublestruck"] = { first = 0x1D538, last = 0x1D551, math = true }, + ["uppercasefraktur"] = { first = 0x1D504, last = 0x1D51D, math = true }, + ["uppercasegreekbold"] = { first = 0x1D6A8, last = 0x1D6C1, math = true }, + ["uppercasegreekbolditalic"] = { first = 0x1D71C, last = 0x1D735, math = true }, + ["uppercasegreekitalic"] = { first = 0x1D6E2, last = 0x1D6FB, math = true }, + ["uppercasegreeknormal"] = { first = 0x00391, last = 0x003AA, math = true }, + ["uppercasegreeksansserifbold"] = { first = 0x1D756, last = 0x1D76F, math = true }, + ["uppercasegreeksansserifbolditalic"] = { first = 0x1D790, last = 0x1D7A9, math = true }, + ["uppercaseitalic"] = { first = 0x1D434, last = 0x1D44D, math = true }, + ["uppercasemonospace"] = { first = 0x1D670, last = 0x1D689, math = true }, + ["uppercasenormal"] = { first = 0x00041, last = 0x0005A, math = true }, + ["uppercasesansserifbold"] = { first = 0x1D5D4, last = 0x1D5ED, math = true }, + ["uppercasesansserifbolditalic"] = { first = 0x1D63C, last = 0x1D655, math = true }, + ["uppercasesansserifitalic"] = { first = 0x1D608, last = 0x1D621, math = true }, + ["uppercasesansserifnormal"] = { first = 0x1D5A0, last = 0x1D5B9, math = true }, + ["uppercasescript"] = { first = 0x1D49C, last = 0x1D4B5, math = true }, + ["vai"] = { first = 0x0A500, last = 0x0A63F, description = "Vai" }, + ["variationselectors"] = { first = 0x0FE00, last = 0x0FE0F, description = "Variation Selectors" }, + ["variationselectorssupplement"] = { first = 0xE0100, last = 0xE01EF, description = "Variation Selectors Supplement" }, + ["vedicextensions"] = { first = 0x01CD0, last = 0x01CFF, description = "Vedic Extensions" }, + ["verticalforms"] = { first = 0x0FE10, last = 0x0FE1F, description = "Vertical Forms" }, + ["warangciti"] = { first = 0x118A0, last = 0x118FF, description = "Warang Citi" }, + ["yijinghexagramsymbols"] = { first = 0x04DC0, last = 0x04DFF, otf="yi", description = "Yijing Hexagram Symbols" }, + ["yiradicals"] = { first = 0x0A490, last = 0x0A4CF, otf="yi", description = "Yi Radicals" }, + ["yisyllables"] = { first = 0x0A000, last = 0x0A48F, otf="yi", description = "Yi Syllables" }, } characters.blocks = blocks @@ -379,13 +494,15 @@ setmetatableindex(otfscripts,function(t,unicode) return "dflt" end) +local splitter = lpeg.splitat(S(":-")) + function characters.getrange(name) -- used in font fallback definitions (name or range) local range = blocks[name] if range then return range.first, range.last, range.description, range.gaps end name = gsub(name,'"',"0x") -- goodie: tex hex notation - local start, stop = match(name,"^(.-)[%-%:](.-)$") + local start, stop = lpegmatch(splitter,name) if start and stop then start, stop = tonumber(start,16) or tonumber(start), tonumber(stop,16) or tonumber(stop) if start and stop then @@ -492,7 +609,68 @@ setmetatableindex(characters.is_punctuation,mti) -- linebreak: todo: hash -- -- normative : BK CR LF CM SG GL CB SP ZW NL WJ JL JV JT H2 H3 --- informative : XX OP CL QU NS EX SY IS PR PO NU AL ID IN HY BB BA SA AI B2 new:CP +-- informative : XX OP CL CP QU NS EX SY IS PR PO NU AL ID IN HY BB BA SA AI B2 HL CJ RI +-- +-- comments taken from standard: + +characters.linebreaks = { + + -- non-tailorable line breaking classes + + ["bk"] = "mandatory break", -- nl, ps : cause a line break (after) + ["cr"] = "carriage return", -- cr : cause a line break (after), except between cr and lf + ["lf"] = "line feed", -- lf : cause a line break (after) + ["cm"] = "combining mark", -- combining marks, control codes : prohibit a line break between the character and the preceding character + ["nl"] = "next line", -- nel : cause a line break (after) + ["sg"] = "surrogate", -- surrogates :do not occur in well-formed text + ["wj"] = "word joiner", -- wj : prohibit line breaks before and after + ["zw"] = "zero width space", -- zwsp : provide a break opportunity + ["gl"] = "non-breaking (glue)", -- cgj, nbsp, zwnbsp : prohibit line breaks before and after + ["sp"] = "space", -- space : enable indirect line breaks + + -- break opportunities + + ["b2"] = "break opportunity before and after", -- em dash : provide a line break opportunity before and after the character + ["ba"] = "break after", -- spaces, hyphens : generally provide a line break opportunity after the character + ["bb"] = "break before", -- punctuation used in dictionaries : generally provide a line break opportunity before the character + ["hy"] = "hyphen", -- hyphen-minus : provide a line break opportunity after the character, except in numeric context + ["cb"] = "contingent break opportunity", -- inline objects : provide a line break opportunity contingent on additional information + + -- characters prohibiting certain breaks + + ["cl"] = "close punctuation", -- “}”, “❳”, “⟫” etc. : prohibit line breaks before + ["cp"] = "close parenthesis", -- “)”, “]” : prohibit line breaks before + ["ex"] = "exclamation/interrogation", -- “!”, “?”, etc. : prohibit line breaks before + ["in"] = "inseparable", -- leaders : allow only indirect line breaks between pairs + ["ns"] = "nonstarter", -- “‼”, “‽”, “⁇”, “⁉”, etc. : allow only indirect line breaks before + ["op"] = "open punctuation", -- “(“, “[“, “{“, etc. : prohibit line breaks after + ["qu"] = "quotation", -- quotation marks : act like they are both opening and closing + + -- numeric context + + ["is"] = "infix numeric separator", -- . , : prevent breaks after any and before numeric + ["nu"] = "numeric", -- digits : form numeric expressions for line breaking purposes + ["po"] = "postfix numeric", -- %, ¢ : do not break following a numeric expression + ["pr"] = "prefix numeric", -- $, £, ¥, etc. : do not break in front of a numeric expression + ["sy"] = "symbols allowing break after", -- / : prevent a break before, and allow a break after + + -- other characters + + ["ai"] = "ambiguous (alphabetic or ideographic)", -- characters with ambiguous east asian width : act like al when the resolved eaw is n; otherwise, act as id + ["al"] = "alphabetic", -- alphabets and regular symbols : are alphabetic characters or symbols that are used with alphabetic characters + ["cj"] = "conditional japanese starter", -- small kana : treat as ns or id for strict or normal breaking. + ["h2"] = "hangul lv syllable", -- hangul : form korean syllable blocks + ["h3"] = "hangul lvt syllable", -- hangul : form korean syllable blocks + ["hl"] = "hebrew letter", -- hebrew : do not break around a following hyphen; otherwise act as alphabetic + ["id"] = "ideographic", -- ideographs : break before or after, except in some numeric context + ["jl"] = "hangul l jamo", -- conjoining jamo : form korean syllable blocks + ["jv"] = "hangul v jamo", -- conjoining jamo : form korean syllable blocks + ["jt"] = "hangul t jamo", -- conjoining jamo : form korean syllable blocks + ["ri"] = "regional indicator", -- regional indicator symbol letter a .. z : keep together, break before and after from others + ["sa"] = "complex context dependent (south east asian)", -- south east asian: thai, lao, khmer : provide a line break opportunity contingent on additional, language-specific context analysis + ["xx"] = "unknown", -- most unassigned, private-use : have as yet unknown line breaking behavior or unassigned code positions + +} -- east asian width: -- @@ -600,10 +778,10 @@ of the officialInstead of using a
Setting the lccodes is also done in a loop over the data table.
---ldx]]-- - -local sfmode = "unset" -- unset, traditional, normal - -function characters.setcodes() - if trace_defining then - report_defining("defining lc and uc codes") - end - local traditional = sfstate == "traditional" or sfstate == "unset" - for code, chr in next, data do - local cc = chr.category - if is_letter[cc] then - local range = chr.range - if range then - for i=range.first,range.last do - texsetcatcode(i,11) -- letter - texsetlccode(i,i,i) -- self self - end - else - local lc, uc = chr.lccode, chr.uccode - if not lc then - chr.lccode, lc = code, code - elseif type(lc) == "table" then - lc = code - end - if not uc then - chr.uccode, uc = code, code - elseif type(uc) == "table" then - uc = code - end - texsetcatcode(code,11) -- letter - texsetlccode(code,lc,uc) - if traditional and cc == "lu" then - texsetsfcode(code,999) - end - end - elseif is_mark[cc] then - texsetlccode(code,code,code) -- for hyphenation - end - end - if traditional then - sfstate = "traditional" - end -end - --- If this is something that is not documentwide and used a lot, then we --- need a more clever approach (trivial but not now). - -local function setuppersfcodes(v,n) - if sfstate ~= "unset" then - report_defining("setting uppercase sf codes to %a",n) - for code, chr in next, data do - if chr.category == "lu" then - texsetsfcode(code,n) - end - end - end - sfstate = v -end - -directives.register("characters.spaceafteruppercase",function(v) - if v == "traditional" then - setuppersfcodes(v,999) - elseif v == "normal" then - setuppersfcodes(v,1000) - end -end) - --- tex - -function commands.chardescription(slot) - local d = data[slot] - if d then - context(d.description) - end -end - --- xml - -characters.activeoffset = 0x10000 -- there will be remapped in that byte range - -function commands.remapentity(chr,slot) - contextsprint(format("{\\catcode%s=13\\xdef%s{\\string%s}}",slot,utfchar(slot),chr)) -end - --- xml.entities = xml.entities or { } --- --- storage.register("xml/entities",xml.entities,"xml.entities") -- this will move to lxml --- --- function characters.setmkiventities() --- local entities = xml.entities --- entities.lt = "<" --- entities.amp = "&" --- entities.gt = ">" --- end --- --- function characters.setmkiientities() --- local entities = xml.entities --- entities.lt = utfchar(characters.activeoffset + utfbyte("<")) --- entities.amp = utfchar(characters.activeoffset + utfbyte("&")) --- entities.gt = utfchar(characters.activeoffset + utfbyte(">")) --- end +-- code moved to char-tex.lua -commands.definecatcodetable = characters.define -commands.setcharactercodes = characters.setcodes +return characters diff --git a/Master/texmf-dist/tex/context/base/char-ini.mkiv b/Master/texmf-dist/tex/context/base/char-ini.mkiv index db52ae7239f..bb4483b7527 100644 --- a/Master/texmf-dist/tex/context/base/char-ini.mkiv +++ b/Master/texmf-dist/tex/context/base/char-ini.mkiv @@ -13,11 +13,10 @@ \writestatus{loading}{ConTeXt Character Support / Initialization} -\registerctxluafile{char-def}{1.001} % let's load this one first -\registerctxluafile{char-ini}{1.001} -\registerctxluafile{char-cjk}{1.001} +\registerctxluafile{char-fio}{1.001} \registerctxluafile{char-map}{1.001} % maybe we will load this someplace else \registerctxluafile{char-tex}{1.001} +\registerctxluafile{char-ent}{1.001} \unprotect @@ -43,7 +42,8 @@ % use \normalUchar when possible .. the next one is nice for documents and it also accepts % 0x prefixed numbers -\def\utfchar#1{\ctxcommand{utfchar(\number#1)}} +\def\utfchar #1{\clf_utfchar \numexpr#1\relax} +\def\safechar#1{\clf_safechar\numexpr#1\relax} \def\checkedchar {\relax\ifmmode\expandafter\checkedmathchar\else\expandafter\checkedtextchar\fi} % #1#2 \def\checkedmathchar#1#2{#2} @@ -65,30 +65,26 @@ % \def\setcclcuc#1#2#3{\global\catcode#1=\lettercatcode\global\lccode#1=#2\global\uccode#1=#3\relax} % \def\setcclcucself#1{\global\catcode#1=\lettercatcode\global\lccode#1=#1\global\uccode#1=#1\relax } -\ctxcommand{setcharactercodes()} - % Is setting up vrb tpa and tpb needed? -\ctxcommand{definecatcodetable( - { % letter catcodes - \number\texcatcodes, - \number\ctxcatcodes, - \number\notcatcodes, - %number\mthcatcodes, - \number\vrbcatcodes, - \number\prtcatcodes, - \number\tpacatcodes, - \number\tpbcatcodes, - \number\txtcatcodes, - }, - { % activate catcodes - \number\ctxcatcodes, - \number\notcatcodes, - \number\prtcatcodes, % new - } -)} - -\def\chardescription#1% - {\ctxcommand{chardescription(\number#1)}} +% move to lua side + +%clf_setcharactercodes + +\clf_setlettercatcodes\texcatcodes +\clf_setlettercatcodes\ctxcatcodes +\clf_setlettercatcodes\notcatcodes +%clf_setlettercatcodes\mthcatcodes +\clf_setlettercatcodes\vrbcatcodes +\clf_setlettercatcodes\prtcatcodes +\clf_setlettercatcodes\tpacatcodes +\clf_setlettercatcodes\tpbcatcodes +\clf_setlettercatcodes\txtcatcodes + +\clf_setactivecatcodes\ctxcatcodes +\clf_setactivecatcodes\notcatcodes +\clf_setactivecatcodes\prtcatcodes + +\def\chardescription#1{\clf_chardescription#1\relax} \protect \endinput diff --git a/Master/texmf-dist/tex/context/base/char-tex.lua b/Master/texmf-dist/tex/context/base/char-tex.lua index 472cae930c3..48dccfe7915 100644 --- a/Master/texmf-dist/tex/context/base/char-tex.lua +++ b/Master/texmf-dist/tex/context/base/char-tex.lua @@ -6,17 +6,118 @@ if not modules then modules = { } end modules ['char-tex'] = { license = "see context related readme files" } -local lpeg = lpeg -local find = string.find +local lpeg = lpeg +local next, type = next, type +local format, find, gmatch = string.format, string.find, string.gmatch +local utfchar, utfbyte = utf.char, utf.byte +local concat, tohash = table.concat, table.tohash local P, C, R, S, V, Cs, Cc = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.V, lpeg.Cs, lpeg.Cc -local U, lpegmatch = lpeg.patterns.utf8, lpeg.match -local allocate, mark = utilities.storage.allocate, utilities.storage.mark +local lpegpatterns = lpeg.patterns +local lpegmatch = lpeg.match +local utfchartabletopattern = lpeg.utfchartabletopattern + +local allocate = utilities.storage.allocate +local mark = utilities.storage.mark + +local context = context +local commands = commands +local implement = interfaces.implement + +local characters = characters +local texcharacters = { } +characters.tex = texcharacters +local utffilters = characters.filters.utf + +local is_character = characters.is_character +local is_letter = characters.is_letter +local is_command = characters.is_command +local is_spacing = characters.is_spacing +local is_mark = characters.is_mark +local is_punctuation = characters.is_punctuation + +local data = characters.data if not data then return end +local blocks = characters.blocks + +local trace_defining = false trackers.register("characters.defining", function(v) characters_defining = v end) + +local report_defining = logs.reporter("characters") + +--[[ldx-- +In order to deal with 8-bit output, we need to find a way to go from
This leaves us problems with characters that are specific to
We get a more efficient variant of this when we integrate +replacements in collapser. This more or less renders the previous +private code redundant. The following code is equivalent but the +first snippet uses the relocated dollars.
-characters = characters or { } -local characters = characters -characters.tex = characters.tex or { } +Instead of using a
Setting the lccodes is also done in a loop over the data table.
+--ldx]]-- + +-- function characters.setcodes() -- we could loop over csletters +-- if trace_defining then +-- report_defining("defining lc and uc codes") +-- end +-- local traditional = sfstate == "traditional" or sfstate == "unset" +-- for code, chr in next, data do +-- local cc = chr.category +-- if is_letter[cc] then +-- local range = chr.range +-- if range then +-- for i=range.first,range.last do +-- texsetlccode(i,i,i) -- self self +-- end +-- else +-- local lc, uc = chr.lccode, chr.uccode +-- if not lc then +-- chr.lccode, lc = code, code +-- elseif type(lc) == "table" then +-- lc = code +-- end +-- if not uc then +-- chr.uccode, uc = code, code +-- elseif type(uc) == "table" then +-- uc = code +-- end +-- texsetlccode(code,lc,uc) +-- if traditional and cc == "lu" then +-- texsetsfcode(code,999) +-- end +-- end +-- elseif is_mark[cc] then +-- texsetlccode(code,code,code) -- for hyphenation +-- end +-- end +-- if traditional then +-- sfstate = "traditional" +-- end +-- end + +-- tex + +implement { + name = "chardescription", + arguments = "integer", + actions = function(slot) + local d = data[slot] + if d then + context(d.description) + end + end, +} + +-- xml + +characters.activeoffset = 0x10000 -- there will be remapped in that byte range + +function commands.remapentity(chr,slot) -- not used + contextsprint(format("{\\catcode%s=13\\xdef%s{\\string%s}}",slot,utfchar(slot),chr)) +end + +-- xml.entities = xml.entities or { } +-- +-- storage.register("xml/entities",xml.entities,"xml.entities") -- this will move to lxml +-- +-- function characters.setmkiventities() +-- local entities = xml.entities +-- entities.lt = "<" +-- entities.amp = "&" +-- entities.gt = ">" +-- end +-- +-- function characters.setmkiientities() +-- local entities = xml.entities +-- entities.lt = utfchar(characters.activeoffset + utfbyte("<")) +-- entities.amp = utfchar(characters.activeoffset + utfbyte("&")) +-- entities.gt = utfchar(characters.activeoffset + utfbyte(">")) +-- end + +implement { name = "setlettercatcodes", scope = "private", actions = characters.setlettercatcodes, arguments = "integer" } +implement { name = "setactivecatcodes", scope = "private", actions = characters.setactivecatcodes, arguments = "integer" } +--------- { name = "setcharactercodes", scope = "private", actions = characters.setcodes } diff --git a/Master/texmf-dist/tex/context/base/char-utf.lua b/Master/texmf-dist/tex/context/base/char-utf.lua index d406b8bfefe..9ed861be097 100644 --- a/Master/texmf-dist/tex/context/base/char-utf.lua +++ b/Master/texmf-dist/tex/context/base/char-utf.lua @@ -6,11 +6,6 @@ if not modules then modules = { } end modules ['char-utf'] = { license = "see context related readme files" } --- todo: trackers --- todo: no longer special characters (high) here, only needed in special cases and --- these don't go through this file anyway --- graphemes: basic symbols - --[[ldx--When a sequence of
In order to deal with 8-bit output, we need to find a way to go from
This leaves us problems with characters that are specific to
The next variant has lazy token collecting, on a 140 page mk.tex this saves +about .25 seconds, which is understandable because we have no graphemes and +not collecting tokens is not only faster but also saves garbage collecting. +
--ldx]]-- -local low = allocate() -local high = allocate() -local escapes = allocate() -local special = "~#$%^&_{}\\|" -- "~#$%{}\\|" - -local private = { - low = low, - high = high, - escapes = escapes, -} - -utffilters.private = private - -local tohigh = lpeg.replacer(low) -- frozen, only for basic tex -local tolow = lpeg.replacer(high) -- frozen, only for basic tex - -lpegpatterns.utftohigh = tohigh -lpegpatterns.utftolow = tolow - -function utffilters.harden(str) - return lpegmatch(tohigh,str) -end - -function utffilters.soften(str) - return lpegmatch(tolow,str) -end +local skippable = { } +local filesuffix = file.suffix -local function set(ch) - local cb - if type(ch) == "number" then - cb, ch = ch, utfchar(ch) - else - cb = utfbyte(ch) +function utffilters.setskippable(suffix,value) + if value == nil then + value = true end - if cb < 256 then - escapes[ch] = "\\" .. ch - low[ch] = utfchar(0x0F0000 + cb) - if ch == "%" then - ch = "%%" -- nasty, but we need this as in replacements (also in lpeg) % is interpreted + if type(suffix) == "table" then + for i=1,#suffix do + skippable[suffix[i]] = value end - high[utfchar(0x0F0000 + cb)] = ch + else + skippable[suffix] = value end end -private.set = set - --- function private.escape (str) return gsub(str,"(.)", escapes) end --- function private.replace(str) return utfgsub(str,"(.)", low ) end --- function private.revert (str) return utfgsub(str,"(.)", high ) end - -private.escape = utf.remapper(escapes) -private.replace = utf.remapper(low) -private.revert = utf.remapper(high) - -for ch in gmatch(special,".") do set(ch) end - ---[[ldx-- -We get a more efficient variant of this when we integrate -replacements in collapser. This more or less renders the previous -private code redundant. The following code is equivalent but the -first snippet uses the relocated dollars.
+-- function utffilters.collapse(str,filename) -- we can make high a seperate pass (never needed with collapse) +-- if skippable[filesuffix(filename)] then +-- return str +-- -- elseif find(filename,"^virtual://") then +-- -- return str +-- -- else +-- -- -- print("\n"..filename) +-- end +-- if str and str ~= "" then +-- local nstr = #str +-- if nstr > 1 then +-- if initialize then -- saves a call +-- initialize() +-- end +-- local tokens, t, first, done, n = { }, 0, false, false, 0 +-- for second in utfcharacters(str) do +-- if done then +-- if first then +-- if second == " " then +-- t = t + 1 +-- tokens[t] = first +-- first = second +-- else +-- -- local crs = high[second] +-- -- if crs then +-- -- t = t + 1 +-- -- tokens[t] = first +-- -- first = crs +-- -- else +-- local cgf = graphemes[first] +-- if cgf and cgf[second] then +-- first = cgf[second] +-- else +-- t = t + 1 +-- tokens[t] = first +-- first = second +-- end +-- -- end +-- end +-- elseif second == " " then +-- first = second +-- else +-- -- local crs = high[second] +-- -- if crs then +-- -- first = crs +-- -- else +-- first = second +-- -- end +-- end +-- elseif second == " " then +-- first = nil +-- n = n + 1 +-- else +-- -- local crs = high[second] +-- -- if crs then +-- -- for s in utfcharacters(str) do +-- -- if n == 1 then +-- -- break +-- -- else +-- -- t = t + 1 +-- -- tokens[t] = s +-- -- n = n - 1 +-- -- end +-- -- end +-- -- if first then +-- -- t = t + 1 +-- -- tokens[t] = first +-- -- end +-- -- first = crs +-- -- done = true +-- -- else +-- local cgf = graphemes[first] +-- if cgf and cgf[second] then +-- for s in utfcharacters(str) do +-- if n == 1 then +-- break +-- else +-- t = t + 1 +-- tokens[t] = s +-- n = n - 1 +-- end +-- end +-- first = cgf[second] +-- done = true +-- else +-- first = second +-- n = n + 1 +-- end +-- -- end +-- end +-- end +-- if done then +-- if first then +-- t = t + 1 +-- tokens[t] = first +-- end +-- return concat(tokens) -- seldom called +-- end +-- elseif nstr > 0 then +-- return high[str] or str -- this will go from here +-- end +-- end +-- return str +-- end -The next variant has lazy token collecting, on a 140 page mk.tex this saves -about .25 seconds, which is understandable because we have no graphemes and -not collecting tokens is not only faster but also saves garbage collecting. -
---ldx]]-- +local p_collapse = nil -- so we can reset if needed -local skippable = table.tohash { "mkiv", "mkvi" } -local filesuffix = file.suffix +local function prepare() + if initialize then + initialize() + end + local tree = utfchartabletopattern(collapsed) + p_collapse = Cs((tree/collapsed + p_utf8character)^0 * P(-1)) -- the P(1) is needed in order to accept non utf +end -function utffilters.collapse(str,filename) -- we can make high a seperate pass (never needed with collapse) - if skippable[filesuffix(filename)] then - return str - -- elseif find(filename,"^virtual://") then - -- return str - -- else - -- -- print("\n"..filename) +function utffilters.collapse(str,filename) + if not p_collapse then + prepare() end - if str and str ~= "" then - local nstr = #str - if nstr > 1 then - if initialize then -- saves a call - initialize() - end - local tokens, t, first, done, n = { }, 0, false, false, 0 - for second in utfcharacters(str) do - if done then - if first then - if second == " " then - t = t + 1 - tokens[t] = first - first = second - else - -- local crs = high[second] - -- if crs then - -- t = t + 1 - -- tokens[t] = first - -- first = crs - -- else - local cgf = graphemes[first] - if cgf and cgf[second] then - first = cgf[second] - else - t = t + 1 - tokens[t] = first - first = second - end - -- end - end - elseif second == " " then - first = second - else - -- local crs = high[second] - -- if crs then - -- first = crs - -- else - first = second - -- end - end - elseif second == " " then - first = nil - n = n + 1 - else - -- local crs = high[second] - -- if crs then - -- for s in utfcharacters(str) do - -- if n == 1 then - -- break - -- else - -- t = t + 1 - -- tokens[t] = s - -- n = n - 1 - -- end - -- end - -- if first then - -- t = t + 1 - -- tokens[t] = first - -- end - -- first = crs - -- done = true - -- else - local cgf = graphemes[first] - if cgf and cgf[second] then - for s in utfcharacters(str) do - if n == 1 then - break - else - t = t + 1 - tokens[t] = s - n = n - 1 - end - end - first = cgf[second] - done = true - else - first = second - n = n + 1 - end - -- end - end - end - if done then - if first then - t = t + 1 - tokens[t] = first - end - return concat(tokens) -- seldom called - end - elseif nstr > 0 then - return high[str] or str - end + if not str or #str == "" or #str == 1 then + return str + elseif filename and skippable[filesuffix(filename)] then -- we could hash the collapsables or do a quicker test + return str + else + return lpegmatch(p_collapse,str) or str end - return str end -- function utffilters.decompose(str) @@ -399,40 +414,231 @@ end -- return str -- end -local tree = lpeg.utfchartabletopattern(table.keys(decomposed)) -local finder = lpeg.finder(tree,false,true) -local replacer = lpeg.replacer(tree,decomposed,false,true) +-- local replacer = nil +-- local finder = nil +-- +-- function utffilters.decompose(str) -- 3 to 4 times faster than the above +-- if not replacer then +-- if initialize then +-- initialize() +-- end +-- local tree = utfchartabletopattern(decomposed) +-- finder = lpeg.finder(tree,false,true) +-- replacer = lpeg.replacer(tree,decomposed,false,true) +-- end +-- if str and str ~= "" and #str > 1 and lpegmatch(finder,str) then +-- return lpegmatch(replacer,str) +-- end +-- return str +-- end + +local p_decompose = nil + +local function prepare() + if initialize then + initialize() + end + local tree = utfchartabletopattern(decomposed) + p_decompose = Cs((tree/decomposed + p_utf8character)^0 * P(-1)) +end -function utffilters.decompose(str) -- 3 to 4 times faster than the above - if str and str ~= "" and #str > 1 and lpegmatch(finder,str) then - return lpegmatch(replacer,str) +function utffilters.decompose(str,filename) -- 3 to 4 times faster than the above + if not p_decompose then + prepare() + end + if str and str ~= "" and #str > 1 then + return lpegmatch(p_decompose,str) + end + if not str or #str == "" or #str < 2 then + return str + elseif filename and skippable[filesuffix(filename)] then + return str + else + return lpegmatch(p_decompose,str) or str end return str end -local sequencers = utilities.sequencers +-- utffilters.addgrapheme(utfchar(318),'l','\string~') +-- utffilters.addgrapheme('c','a','b') + +function utffilters.addgrapheme(result,first,second) -- can be U+ 0x string or utf or number + local result = charfromnumber(result) + local first = charfromnumber(first) + local second = charfromnumber(second) + if not graphemes[first] then + graphemes[first] = { [second] = result } + else + graphemes[first][second] = result + end + local pair = first .. second + if not composed[pair] then + composed[pair] = result + p_composed = nil + end +end + +interfaces.implement { + name = "addgrapheme", + actions = utffilters.addgrapheme, + arguments = { "string", "string", "string" } +} + +-- -- + +local p_reorder = nil + +-- local sorter = function(a,b) return b[2] < a[2] end +-- +-- local function swapper(s,p,t) +-- local old = { } +-- for i=1,#t do +-- old[i] = t[i][1] +-- end +-- old = concat(old) +-- sort(t,sorter) +-- for i=1,#t do +-- t[i] = t[i][1] +-- end +-- local new = concat(t) +-- if old ~= new then +-- print("reordered",old,"->",new) +-- end +-- return p, new +-- end + +-- -- the next one isnto stable for similar weights + +local sorter = function(a,b) + return b[2] < a[2] +end + +local function swapper(s,p,t) + sort(t,sorter) + for i=1,#t do + t[i] = t[i][1] + end + return p, concat(t) +end -if sequencers then +-- -- the next one keeps similar weights in the original order +-- +-- local sorter = function(a,b) +-- local b2, a2 = b[2], a[2] +-- if a2 == b2 then +-- return b[3] > a[3] +-- else +-- return b2 < a2 +-- end +-- end +-- +-- local function swapper(s,p,t) +-- for i=1,#t do +-- t[i][3] = i +-- end +-- sort(t,sorter) +-- for i=1,#t do +-- t[i] = t[i][1] +-- end +-- return p, concat(t) +-- end - local textfileactions = resolvers.openers.helpers.textfileactions +-- at some point exceptions will become an option, for now it's an experiment +-- to overcome bugs (that have become features) in unicode .. or we might decide +-- for an extra ordering key in char-def that takes precedence over combining - sequencers.appendaction (textfileactions,"system","characters.filters.utf.collapse") - sequencers.disableaction(textfileactions,"characters.filters.utf.collapse") +local exceptions = { + -- frozen unicode bug + ["َّ"] = "َّ", -- U+64E .. U+651 => U+651 .. U+64E +} - sequencers.appendaction (textfileactions,"system","characters.filters.utf.decompose") - sequencers.disableaction(textfileactions,"characters.filters.utf.decompose") +local function prepare() + local hash = { } + for k, v in sortedhash(characters.data) do + local combining = v.combining -- v.ordering or v.combining + if combining then + hash[utfchar(k)] = { utfchar(k), combining, 0 } -- slot 3 can be used in sort + end + end + local e = utfchartabletopattern(exceptions) + local p = utfchartabletopattern(hash) + p_reorder = Cs((e/exceptions + Cmt(Ct((p/hash)^2),swapper) + p_utf8character)^0) * P(-1) +end - function characters.filters.utf.enable() - sequencers.enableaction(textfileactions,"characters.filters.utf.collapse") - sequencers.enableaction(textfileactions,"characters.filters.utf.decompose") +function utffilters.reorder(str,filename) + if not p_reorder then + prepare() + end + if not str or #str == "" or #str < 2 then + return str + elseif filename and skippable[filesuffix(filename)] then + return str + else + return lpegmatch(p_reorder,str) or str end + return str +end - directives.register("filters.utf.collapse", function(v) - sequencers[v and "enableaction" or "disableaction"](textfileactions,"characters.filters.utf.collapse") - end) +-- local collapse = utffilters.collapse +-- local decompose = utffilters.decompose +-- local preprocess = utffilters.preprocess +-- +-- local c1, c2, c3 = "a", "̂", "̃" +-- local r2, r3 = "â", "ẫ" +-- local l1 = "ffl" +-- +-- local str = c1..c2..c3 .. " " .. c1..c2 .. " " .. l1 +-- local res = r3 .. " " .. r2 .. " " .. "ffl" +-- +-- local text = io.loaddata("t:/sources/tufte.tex") +-- +-- local function test(n) +-- local data = text .. string.rep(str,100) .. text +-- local okay = text .. string.rep(res,100) .. text +-- local t = os.clock() +-- for i=1,10000 do +-- collapse(data) +-- decompose(data) +-- -- preprocess(data) +-- end +-- print(os.clock()-t,decompose(collapse(data))==okay,decompose(collapse(str))) +-- end +-- +-- test(050) +-- test(150) +-- +-- local old = "foo" .. string.char(0xE1) .. "bar" +-- local new = collapse(old) +-- print(old,new) + +-- local one_old = "فَأَصَّدَّقَ دَّ" local one_new = utffilters.reorder(one_old) +-- local two_old = "فَأَصَّدَّقَ دَّ" local two_new = utffilters.reorder(two_old) +-- +-- print(one_old,two_old,one_old==two_old,false) +-- print(one_new,two_new,one_new==two_new,true) +-- +-- local test = "foo" .. utf.reverse("ؚ" .. "ً" .. "ٌ" .. "ٍ" .. "َ" .. "ُ" .. "ِ" .. "ّ" .. "ْ" ) .. "bar" +-- local done = utffilters.reorder(test) +-- +-- print(test,done,test==done,false) + +local f_default = formatters["[%U] "] +local f_description = formatters["[%s] "] + +local function convert(n) + local d = data[n] + d = d and d.description + if d then + return f_description(d) + else + return f_default(n) + end +end - directives.register("filters.utf.decompose", function(v) - sequencers[v and "enableaction" or "disableaction"](textfileactions,"characters.filters.utf.decompose") - end) +local pattern = Cs((p_utf8byte / convert)^1) +function utffilters.verbose(data) + return data and lpegmatch(pattern,data) or "" end + +return characters diff --git a/Master/texmf-dist/tex/context/base/char-utf.mkiv b/Master/texmf-dist/tex/context/base/char-utf.mkiv index 280e7ef6daf..fe9f402ef23 100644 --- a/Master/texmf-dist/tex/context/base/char-utf.mkiv +++ b/Master/texmf-dist/tex/context/base/char-utf.mkiv @@ -22,24 +22,17 @@ \unprotect +\registerctxluafile{char-def}{1.001} +\registerctxluafile{char-ini}{1.001} \registerctxluafile{char-utf}{1.001} +\registerctxluafile{char-cjk}{1.001} %D We enable collapsing (combining characters) by default, but %D since the source files are rather simple, we postpone the %D initialization till runtime. -% resolvers.filters.install('utf',characters.filters.utf.collapse) - -% \appendtoks -% \ctxlua{ -% local textfileactions = resolvers.openers.helpers.textfileactions -% utilities.sequencers.enableaction(textfileactions,"characters.filters.utf.collapse") -% utilities.sequencers.enableaction(textfileactions,"characters.filters.utf.decompose") -% }% -% \to \everyjob - \appendtoks - \ctxlua{characters.filters.utf.enable()}% + \clf_enableutf % not needed when we create a format so we do it now \to \everyjob %D The next one influences input parsing. @@ -49,6 +42,6 @@ %D \stoptyping \unexpanded\def\definecomposedutf#1 #2 #3 % - {\ctxlua{characters.filters.utf.addgrapheme("#1","#2","#3")}} + {\clf_addgrapheme{#1}{#2}{#3}} \protect diff --git a/Master/texmf-dist/tex/context/base/chem-ini.lua b/Master/texmf-dist/tex/context/base/chem-ini.lua index 10db1a1e44e..f7d10ffa272 100644 --- a/Master/texmf-dist/tex/context/base/chem-ini.lua +++ b/Master/texmf-dist/tex/context/base/chem-ini.lua @@ -32,12 +32,31 @@ function chemistry.molecule(str) return lpegmatch(moleculeparser,str) end -function commands.molecule(str) - if trace_molecules then - local rep = lpegmatch(moleculeparser,str) - report_chemistry("molecule %a becomes %a",str,rep) - context(rep) - else - context(lpegmatch(moleculeparser,str)) - end -end +interfaces.implement { + name = "molecule", + arguments = "string", + actions = function(str) + if trace_molecules then + local rep = lpegmatch(moleculeparser,str) + report_chemistry("molecule %a becomes %a",str,rep) + context(rep) + else + context(lpegmatch(moleculeparser,str)) + end + end, +} + +-- interfaces.implement { +-- name = "molecule", +-- scope = "private", +-- action = function() +-- local str = scanstring() +-- if trace_molecules then +-- local rep = lpegmatch(moleculeparser,str) +-- report_chemistry("molecule %a becomes %a",str,rep) +-- context(rep) +-- else +-- context(lpegmatch(moleculeparser,str)) +-- end +-- end, +-- } diff --git a/Master/texmf-dist/tex/context/base/chem-ini.mkiv b/Master/texmf-dist/tex/context/base/chem-ini.mkiv index 357bceefa66..9a44b4f1aee 100644 --- a/Master/texmf-dist/tex/context/base/chem-ini.mkiv +++ b/Master/texmf-dist/tex/context/base/chem-ini.mkiv @@ -37,7 +37,7 @@ %D \typebuffer \getbuffer \unexpanded\def\molecule#1% - {\ctxcommand{molecule(\!!bs#1\!!es)}} + {\clf_molecule{#1}} %D For old times sake: diff --git a/Master/texmf-dist/tex/context/base/chem-str.lua b/Master/texmf-dist/tex/context/base/chem-str.lua index cd7a2db0690..d724394bb1d 100644 --- a/Master/texmf-dist/tex/context/base/chem-str.lua +++ b/Master/texmf-dist/tex/context/base/chem-str.lua @@ -44,6 +44,8 @@ local P, R, S, C, Cs, Ct, Cc, Cmt = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpe local variables = interfaces and interfaces.variables local commands = commands local context = context +local implement = interfaces.implement + local formatters = string.formatters local texgetcount = tex.getcount @@ -60,11 +62,14 @@ local mpnamedcolor = attributes.colors.mpnamedcolor local topoints = number.topoints local todimen = string.todimen +local trialtypesetting = context.trialtypesetting + chemistry = chemistry or { } local chemistry = chemistry chemistry.instance = "chemistry" chemistry.format = "metafun" +chemistry.method = "double" chemistry.structures = 0 local common_keys = { @@ -422,7 +427,11 @@ local function process(level,spec,text,n,rulethickness,rulecolor,offset,default_ insert(sstack,variant) m = m + 1 ; metacode[m] = syntax.save.direct elseif operation == "restore" then - variant = remove(sstack) + if #sstack > 0 then + variant = remove(sstack) + else + report_chemistry("restore without save") + end local ss = syntax[variant] keys, max = ss.keys, ss.max m = m + 1 ; metacode[m] = syntax.restore.direct @@ -721,7 +730,7 @@ function chemistry.start(settings) width, left, right, sp_width = calculated(width, left, right,bondlength,unit,scale) height, bottom, top, sp_height = calculated(height,bottom,top, bondlength,unit,scale) -- - if width ~= "true" and height ~= "true" and texgetcount("@@trialtypesetting") ~= 0 then + if width ~= "true" and height ~= "true" and trialtypesetting() then if trace_structure then report_chemistry("skipping trial run") end @@ -762,6 +771,7 @@ function chemistry.stop() metapost.graphic { instance = chemistry.instance, format = chemistry.format, + method = chemistry.method, data = mpcode, definitions = f_initialize, } @@ -770,14 +780,12 @@ function chemistry.stop() end end -function chemistry.component(spec,text,settings) +function chemistry.component(spec,text,rulethickness,rulecolor) if metacode then - rulethickness, rulecolor, offset = settings.rulethickness, settings.rulecolor local spec = settings_to_array_with_repeat(spec,true) -- no lower? local text = settings_to_array_with_repeat(text,true) - -- inspect(spec) metacode[#metacode+1] = f_start_component - process(1,spec,text,1,rulethickness,rulecolor) -- offset? + process(1,spec,text,1,rulethickness,rulecolor) metacode[#metacode+1] = f_stop_component end end @@ -790,11 +798,52 @@ end) -- interfaces -commands.undefinechemical = chemistry.undefine -commands.definechemical = chemistry.define -commands.startchemical = chemistry.start -commands.stopchemical = chemistry.stop -commands.chemicalcomponent = chemistry.component +implement { + name = "undefinechemical", + actions = chemistry.undefine, + arguments = "string" +} + +implement { + name = "definechemical", + actions = chemistry.define, + arguments = { "string", "string", "string" } +} + +implement { + name = "startchemical", + actions = chemistry.start, + arguments = { + { + { "width" }, + { "height" }, + { "left" }, + { "right" }, + { "top" }, + { "bottom" }, + { "scale" }, + { "rotation" }, + { "symalign" }, + { "axis" }, + { "framecolor" }, + { "rulethickness" }, + { "offset" }, + { "unit" }, + { "factor" } + } + } +} + +implement { + name = "stopchemical", + actions = chemistry.stop, +} + +implement { + name = "chemicalcomponent", + actions = chemistry.component, + arguments = { "string", "string", "string", "string" } +} -- todo: top / bottom -- maybe add "=" for double and "≡" for triple? @@ -811,7 +860,9 @@ local inline = { ["space"] = "\\chemicalspace", } -function commands.inlinechemical(spec) +local ctx_chemicalinline = context.chemicalinline + +function chemistry.inlinechemical(spec) local spec = settings_to_array_with_repeat(spec,true) for i=1,#spec do local s = spec[i] @@ -819,7 +870,13 @@ function commands.inlinechemical(spec) if inl then context(inl) -- could be a fast context.sprint else - context.chemicalinline(molecule(s)) + ctx_chemicalinline(molecule(s)) end end end + +implement { + name = "inlinechemical", + actions = chemistry.inlinechemical, + arguments = "string" +} diff --git a/Master/texmf-dist/tex/context/base/chem-str.mkiv b/Master/texmf-dist/tex/context/base/chem-str.mkiv index 6aec16f9e09..f18b422f266 100644 --- a/Master/texmf-dist/tex/context/base/chem-str.mkiv +++ b/Master/texmf-dist/tex/context/base/chem-str.mkiv @@ -62,12 +62,12 @@ %D a historical and practical reason (like shared keys with different meaning %D that could clash, e.g.\ align). -\defineMPinstance +\defineMPinstance % not really needed as we set in lua [chemistry] [\s!format=metafun, %\s!extensions=\v!yes, % Should we add extensions and initializations? %\s!initializations=\v!yes, % Would this give EmWidth, etc.? - ] + \c!method=\s!double] \startMPdefinitions{chemistry} input mp-chem.mpiv ; @@ -88,7 +88,7 @@ {\startnointerference \edef\currentdefinedchemical{#1}% \let\chemical\chem_chemical_nested - \ctxcommand{undefinechemical("#1")}% + \clf_undefinechemical{#1}% #2% flush \stopnointerference} @@ -96,7 +96,7 @@ {\dodoubleempty\chem_chemical_nested_indeed} \def\chem_chemical_nested_indeed[#1][#2]% - {\ctxcommand{definechemical("\currentdefinedchemical",\!!bs#1\!!es,\!!bs\detokenize{#2}\!!es)}} + {\clf_definechemical{\currentdefinedchemical}{#1}{\detokenize{#2}}} % chemical symbols @@ -149,39 +149,39 @@ \settrue\indisplaychemical \forgetall \ifsecondargument - \doifassignmentelse{#1} + \doifelseassignment{#1} {\setupcurrentchemical[#1]}% same as \currentchemical {\edef\currentchemical{#1}% \setupcurrentchemical[#2]}% \else\iffirstargument - \doifassignmentelse{#1} + \doifelseassignment{#1} {\setupcurrentchemical[#1]}% same as \currentchemical {\edef\currentchemical{#1}}% \fi\fi \the\everystructurechemical \setbox\b_chem_result\hbox\bgroup - \ctxcommand{startchemical { - width = "\chemicalparameter\c!width", - height = "\chemicalparameter\c!height", - left = "\chemicalparameter\c!left", - right = "\chemicalparameter\c!right", - top = "\chemicalparameter\c!top", - bottom = "\chemicalparameter\c!bottom", - scale = "\chemicalparameter\c!scale", - rotation = "\chemicalparameter\c!rotation", - symalign = "\chemicalparameter\c!symalign", - axis = "\chemicalparameter\c!axis", - framecolor = "\MPcolor{\chemicalparameter\c!framecolor}", - rulethickness = \number\dimexpr\chemicalparameter\c!rulethickness\relax, - offset = \number\dimexpr\chemicalparameter\c!offset\relax, - unit = \number\dimexpr\chemicalparameter\c!unit\relax, - factor = \number\chemicalparameter\c!factor, - } }% + \clf_startchemical + width {\chemicalparameter\c!width}% + height {\chemicalparameter\c!height}% + left {\chemicalparameter\c!left}% + right {\chemicalparameter\c!right}% + top {\chemicalparameter\c!top}% + bottom {\chemicalparameter\c!bottom}% + scale {\chemicalparameter\c!scale}% + rotation {\chemicalparameter\c!rotation}% + symalign {\chemicalparameter\c!symalign}% + axis {\chemicalparameter\c!axis}% + framecolor {\MPcolor{\chemicalparameter\c!framecolor}}% + rulethickness {\number\dimexpr\chemicalparameter\c!rulethickness}% + offset {\number\dimexpr\chemicalparameter\c!offset}% + unit {\number\dimexpr\chemicalparameter\c!unit}% + factor {\number\chemicalparameter\c!factor}% + \relax \startnointerference} \unexpanded\def\stopchemical {\stopnointerference - \ctxcommand{stopchemical()}% + \clf_stopchemical \egroup \d_chem_width \wd\b_chem_result \d_chem_height\ht\b_chem_result @@ -222,17 +222,21 @@ \def\strc_chem_indeed_three[#1][#2][#3]% {\writestatus\m!chemicals{hyperlinked chemicals not yet supported}% todo reference, for the moment ignored - \ctxcommand{chemicalcomponent(\!!bs#2\!!es, \!!bs\detokenize{#3}\!!es, { % maybe also pass first two args this way - rulethickness = "\the\dimexpr\chemicalparameter\c!rulethickness\relax", % todo: scaled points - rulecolor = "\MPcolor{\chemicalparameter\c!rulecolor}" % we can precalculate this for speedup - } ) }% + \clf_chemicalcomponent + {#2}% + {\detokenize{#3}}% + {\the\dimexpr\chemicalparameter\c!rulethickness}% todo: scaled points + {\MPcolor{\chemicalparameter\c!rulecolor}}% % we can precalculate this for speedup + \relax \ignorespaces} \def\strc_chem_indeed_two[#1][#2]% - {\ctxcommand{chemicalcomponent(\!!bs#1\!!es,\!!bs\detokenize{#2}\!!es, { % maybe also pass first two args this way - rulethickness = "\the\dimexpr\chemicalparameter\c!rulethickness\relax", % todo: scaled points - rulecolor = "\MPcolor{\chemicalparameter\c!rulecolor}" % we can precalculate this for speedup - } ) }% + {\clf_chemicalcomponent + {#1}% + {\detokenize{#2}}% + {\the\dimexpr\chemicalparameter\c!rulethickness}% todo: scaled points + {\MPcolor{\chemicalparameter\c!rulecolor}}% % we can precalculate this for speedup + \relax \ignorespaces} \appendtoks @@ -311,8 +315,8 @@ \def\chem_arrow_construct#1#2#3% {\enspace \mathematics{#1% - {\strut\hbox \s!spread 2\emwidth{\hss\ctxcommand{inlinechemical(\!!bs#3\!!es)}\hss}}% {\strut\hbox \s!spread 2em{\hss#3\hss}}}% - {\strut\hbox \s!spread 2\emwidth{\hss\ctxcommand{inlinechemical(\!!bs#2\!!es)}\hss}}}% {\strut\hbox \s!spread 2em{\hss#2\hss}}% + {\strut\hbox \s!spread 2\emwidth{\hss\clf_inlinechemical{#3}\hss}}% {\strut\hbox \s!spread 2em{\hss#3\hss}}}% + {\strut\hbox \s!spread 2\emwidth{\hss\clf_inlinechemical{#2}\hss}}}% {\strut\hbox \s!spread 2em{\hss#2\hss}}% \enspace} % special macros (probably needs some more work) @@ -505,7 +509,7 @@ \begingroup \scratchcounter\normalmathstyle \usechemicalstyleandcolor\c!style\c!color - \hbox{\mathematics{\tf\triggermathstyle\scratchcounter\ctxcommand{inlinechemical(\!!bs#1\!!es)}}}% + \hbox{\mathematics{\tf\triggermathstyle\scratchcounter\clf_inlinechemical{#1}}}% \endgroup} \unexpanded\def\displaychemical @@ -531,7 +535,7 @@ \unexpanded\def\inlinechemical#1% {\dontleavehmode - \hbox{\usechemicalstyleandcolor\c!style\c!color\ctxcommand{inlinechemical(\!!bs#1\!!es)}}} + \hbox{\usechemicalstyleandcolor\c!style\c!color\clf_inlinechemical{#1}}} \unexpanded\def\chemicalbondrule {\hbox{\vrule\s!height.75\exheight\s!depth-\dimexpr.75\exheight-\linewidth\relax\s!width\emwidth\relax}} @@ -720,7 +724,7 @@ \c!rotation=0, % unitless number (interpreted as degrees) \c!symalign=\v!auto, \c!location=, % not yet used (was interaction related in mkii) - \c!offset=.25em, + \c!offset=.25\emwidth, \c!unit=\emwidth, \c!factor=3, \c!color=, diff --git a/Master/texmf-dist/tex/context/base/cldf-bas.lua b/Master/texmf-dist/tex/context/base/cldf-bas.lua index b982fc364e0..1067a17d57e 100644 --- a/Master/texmf-dist/tex/context/base/cldf-bas.lua +++ b/Master/texmf-dist/tex/context/base/cldf-bas.lua @@ -24,10 +24,10 @@ if not modules then modules = { } end modules ['cldf-bas'] = { -- maybe use context.generics -local type = type -local format = string.format -local utfchar = utf.char -local concat = table.concat +local type = type +local format = string.format +local utfchar = utf.char +local concat = table.concat local context = context local generics = context.generics @@ -49,13 +49,23 @@ function context.char(k) -- used as escape too, so don't change to utf elseif n > 0 then context([[\char%s\relax]],concat(k,[[\relax\char]])) end - elseif k then - context([[\char%s\relax]],k) + else + if type(k) == "string" then + k = tonumber(k) + end + if type(k) == "number" then + context([[\char%s\relax]],k) + end end end function context.utfchar(k) - context(utfchar(k)) + if type(k) == "string" then + k = tonumber(k) + end + if type(k) == "number" then + context(utfchar(k)) + end end -- plain variants diff --git a/Master/texmf-dist/tex/context/base/cldf-ini.lua b/Master/texmf-dist/tex/context/base/cldf-ini.lua index 0a0f71266b7..da284ba5ead 100644 --- a/Master/texmf-dist/tex/context/base/cldf-ini.lua +++ b/Master/texmf-dist/tex/context/base/cldf-ini.lua @@ -28,19 +28,27 @@ if not modules then modules = { } end modules ['cldf-ini'] = { -- the the differences between the lua and luajit hashers can lead to quite a slowdown -- in some cases. -local tex = tex +-- context(lpeg.match(lpeg.patterns.texescape,"${}")) +-- context(string.formatters["%!tex!"]("${}")) +-- context("%!tex!","${}") -context = context or { } -local context = context - -local format, gsub, validstring, stripstring = string.format, string.gsub, string.valid, string.strip -local next, type, tostring, tonumber, setmetatable, unpack, select = next, type, tostring, tonumber, setmetatable, unpack, select +local format, validstring, stripstring = string.format, string.valid, string.strip +local next, type, tostring, tonumber, setmetatable, unpack, select, rawset = next, type, tostring, tonumber, setmetatable, unpack, select, rawset local insert, remove, concat = table.insert, table.remove, table.concat local lpegmatch, lpegC, lpegS, lpegP, lpegV, lpegCc, lpegCs, patterns = lpeg.match, lpeg.C, lpeg.S, lpeg.P, lpeg.V, lpeg.Cc, lpeg.Cs, lpeg.patterns -local formatters = string.formatters -- using formatteds is slower in this case +local formatters = string.formatters -- using formatters is slower in this case + +context = context or { } +commands = commands or { } +interfaces = interfaces or { } + +local context = context +local commands = commands +local interfaces = interfaces local loaddata = io.loaddata +local tex = tex local texsprint = tex.sprint local texprint = tex.print local texwrite = tex.write @@ -83,7 +91,7 @@ local storefunction, flushfunction local storenode, flushnode local registerfunction, unregisterfunction, reservefunction, knownfunctions, callfunctiononce -if luafunctions then +-- if luafunctions then local freed, nofused, noffreed = { }, 0, 0 -- maybe use the number of @@trialtypesetting @@ -144,26 +152,123 @@ if luafunctions then end end - registerfunction = function(f) - if type(f) == "string" then - f = loadstring(f) + -- registerfunction = function(f) + -- if type(f) == "string" then + -- f = loadstring(f) + -- end + -- if type(f) ~= "function" then + -- f = function() report_cld("invalid function %A",f) end + -- end + -- if noffreed > 0 then + -- local n = freed[noffreed] + -- freed[noffreed] = nil + -- noffreed = noffreed - 1 + -- luafunctions[n] = f + -- return n + -- else + -- nofused = nofused + 1 + -- luafunctions[nofused] = f + -- return nofused + -- end + -- end + + storage.storedfunctions = storage.storedfunctions or { } + local storedfunctions = storage.storedfunctions + local initex = environment.initex + + storage.register("storage/storedfunctions", storedfunctions, "storage.storedfunctions") + + local f_resolve = nil + local p_resolve = ((1-lpegP("."))^1 / function(s) f_resolve = f_resolve[s] end * lpegP(".")^0)^1 + + function resolvestoredfunction(str) + f_resolve = global + lpegmatch(p_resolve,str) + return f_resolve + end + + local function expose(slot,f,...) -- so we can register yet undefined functions + local func = resolvestoredfunction(f) + if not func then + func = function() report_cld("beware: unknown function %i called: %s",slot,f) end end - if type(f) ~= "function" then - f = function() report_cld("invalid function %A",f) end + luafunctions[slot] = func + return func(...) + end + + if initex then + -- todo: log stored functions + else + local slots = table.sortedkeys(storedfunctions) + local last = #slots + if last > 0 then + -- we restore the references + for i=1,last do + local slot = slots[i] + local data = storedfunctions[slot] + luafunctions[slot] = function(...) + return expose(slot,data,...) + end + end + -- we now know how many are defined + nofused = slots[last] + -- normally there are no holes in the list yet + for i=1,nofused do + if not luafunctions[i] then + noffreed = noffreed + 1 + freed[noffreed] = i + end + end + -- report_cld("%s registered functions, %s freed slots",last,noffreed) end + end + + registerfunction = function(f,direct) -- either f=code or f=namespace,direct=name + local slot, func if noffreed > 0 then - local n = freed[noffreed] + slot = freed[noffreed] freed[noffreed] = nil noffreed = noffreed - 1 - luafunctions[n] = f - return n else nofused = nofused + 1 - luafunctions[nofused] = f - return nofused + slot = nofused + end + if direct then + if initex then + func = function(...) + expose(slot,f,...) + end + if initex then + storedfunctions[slot] = f + end + else + func = resolvestoredfunction(f) + end + if type(func) ~= "function" then + func = function() report_cld("invalid resolve %A",f) end + end + elseif type(f) == "string" then + func = loadstring(f) + if type(func) ~= "function" then + func = function() report_cld("invalid code %A",f) end + end + elseif type(f) == "function" then + func = f + else + func = function() report_cld("invalid function %A",f) end end + luafunctions[slot] = func + return slot end + -- do + -- commands.test = function(str) report_cld("test function: %s", str) end + -- if initex then + -- registerfunction("commands.test") -- number 1 + -- end + -- luafunctions[1]("okay") + -- end + unregisterfunction = function(slot) if luafunctions[slot] then noffreed = noffreed + 1 @@ -197,92 +302,121 @@ if luafunctions then knownfunctions = luafunctions -else + -- The next hack is a convenient way to define scanners at the Lua end and + -- get them available at the TeX end. There is some dirty magic needed to + -- prevent overload during format loading. - local luafunctions, noffunctions = { }, 0 - local luanodes, nofnodes = { }, 0 + -- interfaces.scanners.foo = function() context("[%s]",tokens.scanners.string()) end : \scan_foo - usedstack = function() - return noffunctions + nofnodes, 0 - end + interfaces.storedscanners = interfaces.storedscanners or { } + local storedscanners = interfaces.storedscanners - flushfunction = function(n) - local sn = luafunctions[n] - if not sn then - report_cld("data with id %a cannot be found on stack",n) - elseif not sn() and texgetcount("@@trialtypesetting") == 0 then -- @@trialtypesetting is private! - luafunctions[n] = nil - end - end - - storefunction = function(ti) - noffunctions = noffunctions + 1 - luafunctions[noffunctions] = ti - return noffunctions - end - -- freefunction = function(n) - -- luafunctions[n] = nil - -- end + storage.register("interfaces/storedscanners", storedscanners, "interfaces.storedscanners") - flushnode = function(n) - local sn = luanodes[n] - if not sn then - report_cld("data with id %a cannot be found on stack",n) - elseif texgetcount("@@trialtypesetting") == 0 then -- @@trialtypesetting is private! - writenode(sn) - luanodes[n] = nil + local interfacescanners = table.setmetatablenewindex(function(t,k,v) + if storedscanners[k] then + -- report_cld("warning: scanner %a is already set",k) + -- os.exit() + -- \scan_This module implements a bunch of conversions. Some are more
efficient than their
We also provide an efficient variant for page states.
--ldx]]-- @@ -245,7 +267,7 @@ function pagestates.realpage(name,tag,default) return default end -function commands.setpagestate(settings) +local function setpagestate(settings) local name, tag, data = setstate(settings) if type(tag) == "number" then context(new_latelua(formatters["job.pagestates.extend(%q,%i)"](name,tag))) @@ -254,7 +276,7 @@ function commands.setpagestate(settings) end end -function commands.pagestaterealpage(name,tag) +local function pagestaterealpage(name,tag) local t = collected[name] t = t and (t[tag] or t[tonumber(tag)]) if t then @@ -262,8 +284,32 @@ function commands.pagestaterealpage(name,tag) end end -function commands.setpagestaterealpageno(name,tag) +local function setpagestaterealpageno(name,tag) local t = collected[name] t = t and (t[tag] or t[tonumber(tag)]) texsetcount("realpagestateno",t or texgetcount("realpageno")) end + +implement { + name = "setpagestate", + actions = setpagestate, + arguments = { + { + { "name" }, + { "tag" }, + { "delay" }, + } + } +} + +implement { + name = "pagestaterealpage", + actions = pagestaterealpage, + arguments = { "string", "string" } +} + +implement { + name = "setpagestaterealpageno", + actions = setpagestaterealpageno, + arguments = { "string", "string" } +} diff --git a/Master/texmf-dist/tex/context/base/core-dat.mkiv b/Master/texmf-dist/tex/context/base/core-dat.mkiv index 5aef39d691a..26b1f14b5c0 100644 --- a/Master/texmf-dist/tex/context/base/core-dat.mkiv +++ b/Master/texmf-dist/tex/context/base/core-dat.mkiv @@ -51,26 +51,26 @@ \def\syst_datasets_set_named[#1][#2][#3]% {\begingroup \edef\currentdataset{#1}% - \ctxcommand{setdataset{ - name = "\currentdataset", - tag = \!!bs#2\!!es, - delay = "\datasetparameter\c!delay", - data = \!!bs#3\!!es - }}% + \clf_setdataset + name {\currentdataset}% + tag {#2}% + delay {\datasetparameter\c!delay}% + data {#3}% + \relax \endgroup} \def\syst_datasets_set_indexed[#1][#2][#3]% {\begingroup \edef\currentdataset{#1}% - \ctxcommand{setdataset{ - name = "\currentdataset", - delay = "\datasetparameter\c!delay", - data = \!!bs#2\!!es - }}% + \clf_setdataset + name {\currentdataset}% + delay {\datasetparameter\c!delay}% + data {#2}% + \relax \endgroup} \def\datasetvariable#1#2#3% - {\ctxcommand{datasetvariable("#1","#2","#3")}} + {\clf_datasetvariable{#1}{#2}{#3}} \installcorenamespace{pagestate} @@ -85,17 +85,17 @@ \def\syst_pagestates_set[#1][#2]% {\begingroup \edef\currentpagestate{#1}% - \ctxcommand{setpagestate{ - name = "\currentpagestate", - tag = \!!bs#2\!!es, - delay = "\pagestateparameter\c!delay", - }}% + \clf_setpagestate + name {\currentpagestate}% + tag {#2}% + delay {\pagestateparameter\c!delay}% + \relax \endgroup} \def\pagestaterealpage#1#2% - {\ctxcommand{pagestaterealpage("#1","#2")}} + {\clf_pagestaterealpage{#1}{#2}} \def\setpagestaterealpageno#1#2% - {\ctxcommand{setpagestaterealpageno("#1","#2")}} + {\clf_setpagestaterealpageno{#1}{#2}} \protect diff --git a/Master/texmf-dist/tex/context/base/core-def.mkiv b/Master/texmf-dist/tex/context/base/core-def.mkiv index 99bed6d34d6..acd411faccb 100644 --- a/Master/texmf-dist/tex/context/base/core-def.mkiv +++ b/Master/texmf-dist/tex/context/base/core-def.mkiv @@ -107,17 +107,17 @@ \initializenewlinechar \calculatecurrenttime \syst_files_load - \job_options_get_commandline % expands some commands - \job_options_get_ctxfile % might expand some commands - \job_options_set_filenames + \clf_setdocumentcommandline + \clf_setdocumentctxfile + \clf_setdocumentfilenames \font_preloads_at_every_job \settopskip % brrr \initializemainlanguage \initializepagebackgrounds \initializepagecounters - \job_options_set_modes - \job_options_set_modules - \job_options_set_environments + \clf_setdocumentmodes + \clf_setdocumentmodules + \clf_setdocumentenvironments \to \everyjob \appendtoks diff --git a/Master/texmf-dist/tex/context/base/core-env.lua b/Master/texmf-dist/tex/context/base/core-env.lua index 2cc84299bce..a3a87b7f78e 100644 --- a/Master/texmf-dist/tex/context/base/core-env.lua +++ b/Master/texmf-dist/tex/context/base/core-env.lua @@ -13,19 +13,15 @@ if not modules then modules = { } end modules ['core-env'] = { local P, C, S, Cc, lpegmatch, patterns = lpeg.P, lpeg.C, lpeg.S, lpeg.Cc, lpeg.match, lpeg.patterns -local csname_id = token.csname_id -local create = token.create local texgetcount = tex.getcount local texsetcount = tex.setcount local allocate = utilities.storage.allocate local setmetatableindex = table.setmetatableindex +local setmetatablecall = table.setmetatablecall local context = context -local undefined = csname_id("*undefined*crap*") -local iftrue = create("iftrue")[2] -- inefficient hack - tex.modes = allocate { } tex.systemmodes = allocate { } tex.constants = allocate { } @@ -36,52 +32,204 @@ tex.isdefined = allocate { } local modes = { } local systemmodes = { } -setmetatableindex(tex.modes, function(t,k) - local m = modes[k] - if m then - return m() - else - local n = "mode>" .. k - if csname_id(n) == undefined then - return false +-- if newtoken then -- we keep the old code for historic reasons + + -- undefined: mode == 0 or cmdname = "undefined_cs" + + local create = newtoken.create + + local cache = table.setmetatableindex(function(t,k) + local v = create(k) + t[k] = v + return v + end) + + -- we can have a modes cache too + + local iftrue = cache["iftrue"].mode + local undefined = cache["*undefined*crap*"].mode -- is this ok? + + setmetatableindex(tex.modes, function(t,k) + local m = modes[k] + if m then + return m() else - modes[k] = function() return texgetcount(n) >= 1 end - return texgetcount(n) >= 1 + local n = "mode>" .. k + if cache[n].mode == 0 then + return false + else + modes[k] = function() return texgetcount(n) == 1 end + return texgetcount(n) == 1 -- 2 is prevented + end end - end -end) + end) -setmetatableindex(tex.systemmodes, function(t,k) - local m = systemmodes[k] - if m then - return m() - else - local n = "mode>*" .. k - if csname_id(n) == undefined then - return false + setmetatableindex(tex.systemmodes, function(t,k) + local m = systemmodes[k] + if m then + return m() else - systemmodes[k] = function() return texgetcount(n) >= 1 end - return texgetcount(n) >= 1 + local n = "mode>*" .. k + if cache[n].mode == 0 then + return false + else + systemmodes[k] = function() return texgetcount(n) == 1 end + return texgetcount(n) == 1 -- 2 is prevented + end end + end) + + setmetatableindex(tex.constants, function(t,k) + return cache[k].mode ~= 0 and texgetcount(k) or 0 + end) + + setmetatableindex(tex.conditionals, function(t,k) -- 0 == true + return cache[k].mode ~= 0 and texgetcount(k) == 0 + end) + + table.setmetatableindex(tex.ifs, function(t,k) + -- local mode = cache[k].mode + -- if mode == 0 then + -- return nil + -- else + -- return mode == iftrue + -- end + return cache[k].mode == iftrue + end) + + setmetatableindex(tex.isdefined, function(t,k) + return k and cache[k].mode ~= 0 + end) + + setmetatablecall(tex.isdefined, function(t,k) + return k and cache[k].mode ~= 0 + end) + + local dimencode = cache["scratchdimen" ].command + local countcode = cache["scratchcounter"].command + local tokencode = cache["scratchtoken" ].command + local skipcode = cache["scratchskip" ].command + + local types = { + [dimencode] = "dimen", + [countcode] = "count", + [tokencode] = "token", + [skipcode ] = "skip", + } + + function tex.isdimen(name) + return cache[name].command == dimencode + end + + function tex.iscount(name) + return cache[name].command == countcode end -end) -setmetatableindex(tex.constants, function(t,k) - return csname_id(k) ~= undefined and texgetcount(k) or 0 -end) + function tex.istoken(name) + return cache[name].command == tokencode + end -setmetatableindex(tex.conditionals, function(t,k) -- 0 == true - return csname_id(k) ~= undefined and texgetcount(k) == 0 -end) + function tex.isskip(name) + return cache[name].command == skipcode + end -setmetatableindex(tex.ifs, function(t,k) - -- k = "if" .. k -- better not - return csname_id(k) ~= undefined and create(k)[2] == iftrue -- inefficient, this create, we need a helper -end) + function tex.type(name) + return types[cache[name].command] or "macro" + end -setmetatableindex(tex.isdefined, function(t,k) - return csname_id(k) ~= undefined -end) +-- else +-- +-- local csname_id = token.csname_id +-- local create = token.create +-- +-- local undefined = csname_id("*undefined*crap*") +-- local iftrue = create("iftrue")[2] -- inefficient hack +-- +-- setmetatableindex(tex.modes, function(t,k) +-- local m = modes[k] +-- if m then +-- return m() +-- else +-- local n = "mode>" .. k +-- if csname_id(n) == undefined then +-- return false +-- else +-- modes[k] = function() return texgetcount(n) == 1 end +-- return texgetcount(n) == 1 -- 2 is prevented +-- end +-- end +-- end) +-- +-- setmetatableindex(tex.systemmodes, function(t,k) +-- local m = systemmodes[k] +-- if m then +-- return m() +-- else +-- local n = "mode>*" .. k +-- if csname_id(n) == undefined then +-- return false +-- else +-- systemmodes[k] = function() return texgetcount(n) == 1 end +-- return texgetcount(n) == 1 -- 2 is prevented +-- end +-- end +-- end) +-- +-- setmetatableindex(tex.constants, function(t,k) +-- return csname_id(k) ~= undefined and texgetcount(k) or 0 +-- end) +-- +-- setmetatableindex(tex.conditionals, function(t,k) -- 0 == true +-- return csname_id(k) ~= undefined and texgetcount(k) == 0 +-- end) +-- +-- setmetatableindex(tex.ifs, function(t,k) +-- -- k = "if" .. k -- better not +-- return csname_id(k) ~= undefined and create(k)[2] == iftrue -- inefficient, this create, we need a helper +-- end) +-- +-- setmetatableindex(tex.isdefined, function(t,k) +-- return k and csname_id(k) ~= undefined +-- end) +-- setmetatablecall(tex.isdefined, function(t,k) +-- return k and csname_id(k) ~= undefined +-- end) +-- +-- local lookuptoken = token.lookup +-- +-- local dimencode = lookuptoken("scratchdimen" )[1] +-- local countcode = lookuptoken("scratchcounter")[1] +-- local tokencode = lookuptoken("scratchtoken" )[1] +-- local skipcode = lookuptoken("scratchskip" )[1] +-- +-- local types = { +-- [dimencode] = "dimen", +-- [countcode] = "count", +-- [tokencode] = "token", +-- [skipcode ] = "skip", +-- } +-- +-- function tex.isdimen(name) +-- return lookuptoken(name)[1] == dimencode +-- end +-- +-- function tex.iscount(name) +-- return lookuptoken(name)[1] == countcode +-- end +-- +-- function tex.istoken(name) +-- return lookuptoken(name)[1] == tokencode +-- end +-- +-- function tex.isskip(name) +-- return lookuptoken(name)[1] == skipcode +-- end +-- +-- function tex.type(name) +-- return types[lookuptoken(name)[1]] or "macro" +-- end +-- +-- end function context.setconditional(name,value) if value then @@ -91,27 +239,6 @@ function context.setconditional(name,value) end end - --- todo : global - --- not possible as we let at the tex end to zerocount and plusone --- --- function tex.settrue(name,glob) --- if glob then --- texsetcount("global",name,0) --- else --- texsetcount(name,0) --- end --- end --- --- function tex.setfalse(name,glob) --- if glob then --- texsetcount("global",name,1) --- else --- texsetcount(name,1) --- end --- end - ---- arg = P("{") * C(patterns.nested) * P("}") + Cc("") local sep = S("), ") @@ -126,45 +253,9 @@ local pattern = ( + sep^1 )^1 -function commands.autosetups(str) - lpegmatch(pattern,str) -end - --- new (inefficient) - -local lookuptoken = token.lookup - -local dimencode = lookuptoken("scratchdimen" )[1] -local countcode = lookuptoken("scratchcounter")[1] -local tokencode = lookuptoken("scratchtoken" )[1] -local skipcode = lookuptoken("scratchskip" )[1] - -local types = { - [dimencode] = "dimen", - [countcode] = "count", - [tokencode] = "token", - [skipcode ] = "skip", +interfaces.implement { + name = "autosetups", + actions = function(str) lpegmatch(pattern,str) end, + arguments = "string" } -function tex.isdimen(name) - return lookuptoken(name)[1] == dimencode -end - -function tex.iscount(name) - return lookuptoken(name)[1] == countcode -end - -function tex.istoken(name) - return lookuptoken(name)[1] == tokencode -end - -function tex.isskip(name) - return lookuptoken(name)[1] == skipcode -end - -function tex.type(name) - return types[lookuptoken(name)[1]] or "macro" -end - --- inspect(tex.isdimen("xxxxxxxxxxxxxxx")) --- inspect(tex.isdimen("textwidth")) diff --git a/Master/texmf-dist/tex/context/base/core-env.mkiv b/Master/texmf-dist/tex/context/base/core-env.mkiv index 75b65418f50..bebc1bef08c 100644 --- a/Master/texmf-dist/tex/context/base/core-env.mkiv +++ b/Master/texmf-dist/tex/context/base/core-env.mkiv @@ -46,8 +46,6 @@ \installcorenamespace{modestack} -% todo: check prevent mode, also at the lua end - \setnewconstant\disabledmode \zerocount \setnewconstant\enabledmode \plusone \setnewconstant\preventedmode\plustwo @@ -59,7 +57,7 @@ \def\syst_modes_new#1% {\expandafter\newcount\csname\??mode#1\endcsname} -\unexpanded\def\newmode#1% +\unexpanded\def\newmode#1% so, no change of already set modes ! {\ifcsname\??mode#1\endcsname\else\syst_modes_new{#1}\fi} \unexpanded\def\setmode#1% @@ -113,8 +111,6 @@ \unexpanded\def\globalenablemode {\let\syst_mode_prefix\global\unprotect\syst_modes_enable } \unexpanded\def\globaldisablemode{\let\syst_mode_prefix\global\unprotect\syst_modes_disable} -\let\definemode\disablemode % nicer - \def\syst_modes_prevent[#1]{\protect\rawprocesscommacommand[#1]\syst_modes_prevent_indeed\let\syst_mode_prefix\relax} \def\syst_modes_enable [#1]{\protect\rawprocesscommacommand[#1]\syst_modes_enable_indeed \let\syst_mode_prefix\relax} \def\syst_modes_disable[#1]{\protect\rawprocesscommacommand[#1]\syst_modes_disable_indeed\let\syst_mode_prefix\relax} @@ -135,10 +131,47 @@ \syst_mode_prefix\csname\??mode#1\endcsname\disabledmode \fi} +%D If you do a lot of mode testing, it makes sense to define modes (or disable them +%D explicitly if unset. This makes testing twice as fast. Often one enables modes +%D beforehand, in which case \type {\definemode} would reset the mode. The optional +%D second argument \type {keep} will prevent changing the already set mode but defines +%D it when undefined. + +\unexpanded\def\definemode + {\unprotect + \dodoubleempty\syst_modes_define} + +\def\syst_modes_define[#1][#2]% + {\protect + \edef\m_modes_asked{#2}% + \rawprocesscommacommand[#1]\syst_modes_define_indeed} + +\def\syst_modes_define_indeed#1% + {\ifcsname\??mode#1\endcsname + % already set + \else + \syst_modes_new{#1} + \fi + \ifx\m_modes_asked\v!keep + % not changes, disabled when undefined + \else + \csname\??mode#1\endcsname\ifx\m_modes_asked\v!yes\enabledmode\else\disabledmode\fi + \fi} + % handy for mp \def\booleanmodevalue#1% - {\ifcsname\??mode#1\endcsname\ifcase\csname\??mode#1\endcsname\s!false\else\s!true\fi\else\s!false\fi} + {\ifcsname\??mode#1\endcsname + \ifcase\csname\??mode#1\endcsname + \s!false + \or + \s!true + \else + \s!false + \fi + \else + \s!false + \fi} % check macros @@ -148,6 +181,27 @@ \newconditional\c_checked_mode +% one + +% \def\syst_modes_check_indeed#1% +% {\ifcsname\??mode#1\endcsname +% \ifcase\csname\??mode#1\endcsname\else +% \let\syst_modes_check_step\gobbleoneargument +% \fi +% \fi} +% +% \def\syst_modes_check#1#2#3% +% {\let\syst_modes_check_step\syst_modes_check_indeed +% \rawprocesscommacommand[#3]\syst_modes_check_step +% \ifx\syst_modes_check_step\gobbleoneargument +% \expandafter#1% +% \else +% \expandafter#2% +% \fi} + +% modes .. twice as fast on defined modes .. we could use definers and make it even faster +% if needed + \def\syst_modes_check_indeed#1% {\ifcsname\??mode#1\endcsname \ifcase\csname\??mode#1\endcsname\else @@ -155,7 +209,7 @@ \fi \fi} -\def\syst_modes_check#1#2#3% +\def\syst_modes_check_nop#1#2#3% {\let\syst_modes_check_step\syst_modes_check_indeed \rawprocesscommacommand[#3]\syst_modes_check_step \ifx\syst_modes_check_step\gobbleoneargument @@ -164,10 +218,32 @@ \expandafter#2% \fi} +\def\syst_modes_check_yes#1#2#3% + {\ifcase\csname\??mode#3\endcsname + \expandafter#2% + \or + \expandafter#1% + \else + \expandafter#2% + \fi} + +\def\syst_modes_check#1#2#3% + {\ifcsname\??mode#3\endcsname + \expandafter\syst_modes_check_yes + \else + \expandafter\syst_modes_check_nop + \fi#1#2{#3}} + +% all + \def\syst_modes_check_all_indeed#1% {\ifcsname\??mode#1\endcsname \ifcase\csname\??mode#1\endcsname \let\syst_modes_check_all_step\gobbleoneargument + \or + % enabled + \else + \let\syst_modes_check_all_step\gobbleoneargument \fi \else \let\syst_modes_check_all_step\gobbleoneargument @@ -182,17 +258,20 @@ \expandafter#1% \fi} -\unexpanded\def\doifmodeelse {\syst_modes_check\firstoftwoarguments\secondoftwoarguments} +\unexpanded\def\doifelsemode {\syst_modes_check\firstoftwoarguments\secondoftwoarguments} \unexpanded\def\doifmode {\syst_modes_check\firstofoneargument\gobbleoneargument} \unexpanded\def\doifnotmode {\syst_modes_check\gobbleoneargument\firstofoneargument} \unexpanded\def\startmode [#1]{\syst_modes_check\donothing\syst_modes_stop_yes{#1}} \unexpanded\def\startnotmode [#1]{\syst_modes_check\syst_modes_stop_nop\donothing{#1}} -\unexpanded\def\doifallmodeselse {\syst_modes_check_all\firstoftwoarguments\secondoftwoarguments} +\unexpanded\def\doifelseallmodes {\syst_modes_check_all\firstoftwoarguments\secondoftwoarguments} \unexpanded\def\doifallmodes {\syst_modes_check_all\firstofoneargument\gobbleoneargument} \unexpanded\def\doifnotallmodes {\syst_modes_check_all\gobbleoneargument\firstofoneargument} \unexpanded\def\startallmodes [#1]{\syst_modes_check_all\donothing\syst_modes_stop_all_yes{#1}} \unexpanded\def\startnotallmodes[#1]{\syst_modes_check_all\syst_modes_stop_all_nop\donothing{#1}} +\let\doifmodeelse \doifelsemode +\let\doifallmodeselse \doifelseallmodes + \unexpanded\def\stopmode {} % no relax \unexpanded\def\stopnotmode {} % no relax \unexpanded\def\stopallmodes {} % no relax @@ -272,8 +351,8 @@ \unexpanded\def\startmodeset {\pushmacro\c_syst_modes_set_done - \setfalse\conditionalfalse - \doifnextoptionalcselse\syst_modes_set_start\syst_modes_set_quit} + \setfalse\c_syst_modes_set_done + \doifelsenextoptionalcs\syst_modes_set_start\syst_modes_set_quit} \def\syst_modes_set_start[#1]% {\edef\m_mode_case{#1}% @@ -293,10 +372,10 @@ \def\syst_modes_set_yes#1% {\settrue\c_syst_modes_set_done #1% - \doifnextoptionalcselse\syst_modes_set_start\syst_modes_set_quit} + \doifelsenextoptionalcs\syst_modes_set_start\syst_modes_set_quit} \def\syst_modes_set_nop#1% - {\doifnextoptionalcselse\syst_modes_set_start\syst_modes_set_quit} + {\doifelsenextoptionalcs\syst_modes_set_start\syst_modes_set_quit} \def\syst_modes_set_quit#1\stopmodeset {\popmacro\c_syst_modes_set_done} @@ -314,16 +393,16 @@ \unexpanded\def\startsetups{} % to please dep checker \unexpanded\def\stopsetups {} % to please dep checker -\expanded % will become obsolete - {\def\expandafter\noexpand\csname\e!start\v!setups\endcsname - {\begingroup\noexpand\doifnextoptionalcselse - {\noexpand\dostartsetupsA\expandafter\noexpand\csname\e!stop\v!setups\endcsname} - {\noexpand\dostartsetupsB\expandafter\noexpand\csname\e!stop\v!setups\endcsname}}} - -\letvalue{\e!stop\v!setups}\relax +% \expanded % will become obsolete +% {\def\expandafter\noexpand\csname\e!start\v!setups\endcsname +% {\begingroup\noexpand\doifnextoptionalcselse +% {\noexpand\dostartsetupsA\expandafter\noexpand\csname\e!stop\v!setups\endcsname} +% {\noexpand\dostartsetupsB\expandafter\noexpand\csname\e!stop\v!setups\endcsname}}} +% +% \letvalue{\e!stop\v!setups}\relax -\unexpanded\def\setups{\doifnextbgroupelse\syst_setups_a\syst_setups_b} % {..} or [..] -\unexpanded\def\setup {\doifnextbgroupelse\syst_setups \syst_setups_c} % {..} or [..] +\unexpanded\def\setups{\doifelsenextbgroup\syst_setups_a\syst_setups_b} % {..} or [..] +\unexpanded\def\setup {\doifelsenextbgroup\syst_setups \syst_setups_c} % {..} or [..] \def\syst_setups_a #1{\processcommacommand[#1]\syst_setups} % {..} \def\syst_setups_b[#1]{\processcommacommand[#1]\syst_setups} % [..] @@ -359,6 +438,28 @@ % % \def\syst_setups_normal#1% % {:\ifcsname\??setup:#1\endcsname#1\else\letterpercent\fi\endcsname\empty} % takes one argument +% +% only makes sense with many setups +% +% \def\syst_setups% the grid option will be extended to other main modes +% {\ifgridsnapping +% \expandafter\syst_setups_grid +% \else +% \expandafter\syst_setups_normal +% \fi} +% +% \def\syst_setups_normal#1% the grid option will be extended to other main modes +% {\csname\??setup +% :\ifcsname\??setup:#1\endcsname#1\else\letterpercent\fi +% \endcsname\empty} % takes one argument +% +% \def\syst_setups_grid#1% the grid option will be extended to other main modes +% {\csname\??setup +% \ifcsname\??setup\v!grid:#1\endcsname\v!grid:#1\else:\ifcsname\??setup:#1\endcsname#1\else\letterpercent\fi\fi +% \endcsname\empty} % takes one argument +% +% \let\directsetup\syst_setups +% \let\texsetup \syst_setups % nicer than \directsetup and more en par with xmlsetup and luasetup % We can consider: % @@ -369,6 +470,12 @@ % but it won't work out well with multiple setups (intercepted at the % lua end) that then get only one argument. +% no checking and we assume it being defined: + +\def\fastsetup #1{\csname\??setup:#1\endcsname\empty} +\def\fastsetupwithargument #1#2{\csname\??setup:#2\endcsname{#1}} +\def\fastsetupwithargumentswapped #1{\csname\??setup:#1\endcsname} + % the next one is meant for \c!setups situations, hence the check for % a shortcut @@ -395,11 +502,11 @@ % setups={S1,lua(S2),xml(test{123}),S3} \def\syst_setups_process_local - {\ctxcommand{autosetups("\m_syst_setups_asked")}% + {\clf_autosetups{\m_syst_setups_asked}% \relax} % let's prevent lookahead \def\autosetups#1% - {\ctxcommand{autosetups("#1")}} + {\clf_autosetups{#1}} \edef\setupwithargument#1% saves a few expansions {\noexpand\csname\??setup:\noexpand\ifcsname\??setup:#1\endcsname#1\noexpand\else\letterpercent\noexpand\fi\endcsname} @@ -410,13 +517,15 @@ \let\directsetup\syst_setups \let\texsetup \syst_setups % nicer than \directsetup and more en par with xmlsetup and luasetup -\unexpanded\def\doifsetupselse#1% to be done: grid +\unexpanded\def\doifelsesetups#1% to be done: grid {\ifcsname\??setup:#1\endcsname \expandafter\firstoftwoarguments \else \expandafter\secondoftwoarguments \fi} +\let\doifsetupselse\doifelsesetups + \unexpanded\def\doifsetups#1% to be done: grid {\ifcsname\??setup:#1\endcsname \expandafter\firstofoneargument @@ -487,11 +596,11 @@ % Is doglobal still relevant? Maybe always global? Or never? Anyway, it will become obsolete. -\unexpanded\def\startluasetups {\begingroup\doifnextoptionalcselse\syst_setups_start_lua_a\syst_setups_start_lua_b} \let\stopluasetups \relax -\unexpanded\def\startxmlsetups {\begingroup\doifnextoptionalcselse\syst_setups_start_xml_a\syst_setups_start_xml_b} \let\stopxmlsetups \relax -\unexpanded\def\startrawsetups {\begingroup\doifnextoptionalcselse\syst_setups_start_raw_a\syst_setups_start_raw_b} \let\stoprawsetups \relax -\unexpanded\def\startlocalsetups{\begingroup\doifnextoptionalcselse\syst_setups_start_loc_a\syst_setups_start_loc_b} \let\stoplocalsetups \relax -\unexpanded\def\startsetups {\begingroup\doifnextoptionalcselse\syst_setups_start_tex_a\syst_setups_start_tex_b} \let\stopsetups \relax +\unexpanded\def\startluasetups {\begingroup\doifelsenextoptionalcs\syst_setups_start_lua_a\syst_setups_start_lua_b} \let\stopluasetups \relax +\unexpanded\def\startxmlsetups {\begingroup\doifelsenextoptionalcs\syst_setups_start_xml_a\syst_setups_start_xml_b} \let\stopxmlsetups \relax +\unexpanded\def\startrawsetups {\begingroup\doifelsenextoptionalcs\syst_setups_start_raw_a\syst_setups_start_raw_b} \let\stoprawsetups \relax +\unexpanded\def\startlocalsetups{\begingroup\doifelsenextoptionalcs\syst_setups_start_loc_a\syst_setups_start_loc_b} \let\stoplocalsetups \relax +\unexpanded\def\startsetups {\begingroup\doifelsenextoptionalcs\syst_setups_start_tex_a\syst_setups_start_tex_b} \let\stopsetups \relax \def\syst_setups_start_lua_indeed#1#2#3\stopluasetups {\endgroup\dodoglobal\expandafter\def\csname\??setup#1:#2\expandafter\endcsname\expandafter##\expandafter1\expandafter{#3}} \def\syst_setups_start_xml_indeed#1#2#3\stopxmlsetups {\endgroup\dodoglobal\expandafter\def\csname\??setup#1:#2\expandafter\endcsname\expandafter##\expandafter1\expandafter{#3}} @@ -539,14 +648,14 @@ \def\systemsetups#1{\syst_setups{\systemsetupsprefix#1}} -\def\resetsetups[#1]% see x-fo for usage +\unexpanded\def\resetsetups[#1]% see x-fo for usage {\ifcsname\??setup\ifgridsnapping\v!grid\fi:#1\endcsname \dodoglobal\letbeundefined{\??setup\ifgridsnapping\v!grid\fi:#1}% \else \dodoglobal\letbeundefined{\??setup:#1}% \fi} -\def\showsetupsdefinition[#1]% +\unexpanded\def\showsetupsdefinition[#1]% {\showvalue{\??setup:#1}} % temp hack for debugging %D \macros @@ -633,6 +742,8 @@ \expandafter\secondoftwoarguments \fi} +\let\doifvariableelse\doifelsevariable + \unexpanded\def\doifvariable#1#2% {\ifcsname\??variables#1:#2\endcsname \expandafter\firstofoneargument @@ -647,18 +758,52 @@ \expandafter\firstofoneargument \fi} +%D A few more (we could use a public test variable so that we only need +%D to expand once, assuming expandable variables): + +\letvalue{\??variables:}\empty + +\unexpanded\def\doifelseemptyvariable#1#2% + {\edef\m_syst_string_one{\csname\??variables\ifcsname\??variables#1:#2\endcsname#1:#2\else:\fi\endcsname}% + \ifx\m_syst_string_one\empty + \expandafter\firstoffourarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doifemptyvariableelse\doifelseemptyvariable + +\unexpanded\def\doifemptyvariable#1#2% + {\edef\m_syst_string_one{\csname\??variables\ifcsname\??variables#1:#2\endcsname#1:#2\else:\fi\endcsname}% + \ifx\m_syst_string_one\empty + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +\unexpanded\def\doifnotemptyvariable#1#2% + {\edef\m_syst_string_one{\csname\??variables\ifcsname\??variables#1:#2\endcsname#1:#2\else:\fi\endcsname}% + \ifx\m_syst_string_one\empty + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + + \def\getvariabledefault#1#2% #3% can be command, so no ifcsname here {\executeifdefined{\??variables#1:#2}}% {#3} \unexpanded\def\setupenv {\dotripleargument\syst_variables_set[\getrawparameters][\s!environment]} -\unexpanded\def\doifenvelse{\doifelsevariable \s!environment} +\unexpanded\def\doifelseenv{\doifelsevariable \s!environment} \unexpanded\def\doifenv {\doifvariable \s!environment} \unexpanded\def\doifnotenv {\doifnotvariable \s!environment} \def\env {\getvariable \s!environment} \def\envvar {\getvariabledefault\s!environment} +\let\doifenvelse\doifelseenv + %D \macros %D {defineselector,setupselector,select,directselect} %D diff --git a/Master/texmf-dist/tex/context/base/core-ini.mkiv b/Master/texmf-dist/tex/context/base/core-ini.mkiv index 711c43f9465..c338f6f814e 100644 --- a/Master/texmf-dist/tex/context/base/core-ini.mkiv +++ b/Master/texmf-dist/tex/context/base/core-ini.mkiv @@ -172,6 +172,9 @@ \newif \ifdoingblocks \newif \ifgridsnapping +\newconstant\pageduplexmode % 0 single 1 double 2 mix +\newconstant\pagebodymode % 0 not 1 normal pagebody 2 spread + %D \macros %D {ifproductionrun} %D diff --git a/Master/texmf-dist/tex/context/base/core-sys.lua b/Master/texmf-dist/tex/context/base/core-sys.lua index 22b0e457c7b..cf74d68f461 100644 --- a/Master/texmf-dist/tex/context/base/core-sys.lua +++ b/Master/texmf-dist/tex/context/base/core-sys.lua @@ -9,46 +9,13 @@ if not modules then modules = { } end modules ['core-sys'] = { local lower, format, gsub = string.lower, string.format, string.gsub local suffixonly, basename, removesuffix = file.suffix, file.basename, file.removesuffix -local environment = environment +local environment = environment +local context = context +local implement = interfaces.implement local report_files = logs.reporter("system","files") --- function commands.updatefilenames(jobname,fulljobname,inputfilename,outputfilename) --- -- --- environment.jobname = jobname --- -- --- local jobfilename = gsub(fulljobname or jobname or inputfilename or tex.jobname or "","%./","") --- -- --- environment.jobfilename = jobfilename --- environment.jobfilesuffix = lower(suffixonly(environment.jobfilename)) --- -- --- local inputfilename = gsub(inputfilename or "","%./","") --- environment.inputfilename = inputfilename --- environment.inputfilebarename = removesuffix(basename(inputfilename)) --- -- --- local inputfilerealsuffix = suffixonly(inputfilename) --- environment.inputfilerealsuffix = inputfilerealsuffix --- -- --- local inputfilesuffix = inputfilerealsuffix == "" and "tex" or lower(inputfilerealsuffix) --- environment.inputfilesuffix = inputfilesuffix --- -- --- local outputfilename = outputfilename or environment.inputfilebarename or "" --- environment.outputfilename = outputfilename --- -- --- local runpath = resolvers.cleanpath(lfs.currentdir()) --- environment.runpath = runpath --- -- --- statistics.register("running on path", function() --- return environment.runpath --- end) --- -- --- statistics.register("job file properties", function() --- return format("jobname %a, input %a, suffix %a",jobfilename,inputfilename,inputfilesuffix) --- end) --- -- --- end - -function environment.initializefilenames() -- commands.updatefilenames(jobname,fulljobname,input,result) +function environment.initializefilenames() local arguments = environment.arguments @@ -90,6 +57,17 @@ function environment.initializefilenames() -- commands.updatefilenames(jobname,f function environment.initializefilenames() end end +-- we could set a macro (but will that work when we're expanding? needs testing!) + +implement { name = "operatingsystem", actions = function() context(os.platform) end } +implement { name = "jobfilename", actions = function() context(environment.jobfilename) end } +implement { name = "jobfilesuffix", actions = function() context(environment.jobfilesuffix) end } +implement { name = "inputfilebarename", actions = function() context(environment.inputfilebarename) end } +implement { name = "inputfilerealsuffix", actions = function() context(environment.inputfilerealsuffix) end } +implement { name = "inputfilesuffix", actions = function() context(environment.inputfilesuffix) end } +implement { name = "inputfilename", actions = function() context(environment.inputfilename) end } +implement { name = "outputfilename", actions = function() context(environment.outputfilename) end } + statistics.register("result saved in file", function() -- suffix will be fetched from backend local outputfilename = environment.outputfilename or environment.jobname or tex.jobname or "These helpers extend the basic table with extra ligatures, texligatures and extra kerns. This saves quite some lookups later.
@@ -449,7 +476,7 @@ local addthem = function(rawdata,ligatures) local descriptions = rawdata.descriptions local resources = rawdata.resources local unicodes = resources.unicodes - local names = resources.names + -- local names = resources.names for ligname, ligdata in next, ligatures do local one = descriptions[unicodes[ligname]] if one then @@ -608,8 +635,8 @@ local function copytotfm(data) local filename = constructors.checkedfilename(resources) local fontname = metadata.fontname or metadata.fullname local fullname = metadata.fullname or metadata.fontname - local endash = unicodes['space'] - local emdash = unicodes['emdash'] + local endash = 0x0020 -- space + local emdash = 0x2014 local spacer = "space" local spaceunits = 500 -- @@ -669,7 +696,7 @@ local function copytotfm(data) parameters.x_height = charxheight else -- same as otf - local x = unicodes['x'] + local x = 0x0078 -- x if x then local x = descriptions[x] if x then @@ -729,7 +756,34 @@ function afm.setfeatures(tfmdata,features) end end -local function checkfeatures(specification) +local function addtables(data) + local resources = data.resources + local lookuptags = resources.lookuptags + local unicodes = resources.unicodes + if not lookuptags then + lookuptags = { } + resources.lookuptags = lookuptags + end + setmetatableindex(lookuptags,function(t,k) + local v = type(k) == "number" and ("lookup " .. k) or k + t[k] = v + return v + end) + if not unicodes then + unicodes = { } + resources.unicodes = unicodes + setmetatableindex(unicodes,function(t,k) + setmetatableindex(unicodes,nil) + for u, d in next, data.descriptions do + local n = d.name + if n then + t[n] = u + end + end + return rawget(t,k) + end) + end + constructors.addcoreunicodes(unicodes) -- do we really need this? end local function afmtotfm(specification) @@ -759,6 +813,7 @@ local function afmtotfm(specification) if not tfmdata then local rawdata = afm.load(afmname) if rawdata and next(rawdata) then + addtables(rawdata) adddimensions(rawdata) tfmdata = copytotfm(rawdata) if tfmdata and next(tfmdata) then @@ -808,6 +863,7 @@ those that make sense for this format. local function prepareligatures(tfmdata,ligatures,value) if value then local descriptions = tfmdata.descriptions + local hasligatures = false for unicode, character in next, tfmdata.characters do local description = descriptions[unicode] local dligatures = description.ligatures @@ -823,17 +879,20 @@ local function prepareligatures(tfmdata,ligatures,value) type = 0 } end + hasligatures = true end end + tfmdata.properties.hasligatures = hasligatures end end local function preparekerns(tfmdata,kerns,value) if value then - local rawdata = tfmdata.shared.rawdata - local resources = rawdata.resources - local unicodes = resources.unicodes + local rawdata = tfmdata.shared.rawdata + local resources = rawdata.resources + local unicodes = resources.unicodes local descriptions = tfmdata.descriptions + local haskerns = false for u, chr in next, tfmdata.characters do local d = descriptions[u] local newkerns = d[kerns] @@ -849,8 +908,10 @@ local function preparekerns(tfmdata,kerns,value) kerns[uk] = v end end + haskerns = true end end + tfmdata.properties.haskerns = haskerns end end diff --git a/Master/texmf-dist/tex/context/base/font-agl.lua b/Master/texmf-dist/tex/context/base/font-agl.lua index 5ee34b0287c..122d1adc2d1 100644 --- a/Master/texmf-dist/tex/context/base/font-agl.lua +++ b/Master/texmf-dist/tex/context/base/font-agl.lua @@ -656,12 +656,18 @@ end -- We load this table only when needed. We could use a loading mechanism -- return the table but there are no more vectors like this so why bother. +-- +-- Well, we currently hav ethis table preloaded anyway. -fonts.encodings = fonts.encodings or { } - -fonts.encodings.agl = { +local agl = { names = names, -- unicode -> name unicodes = unicodes, -- name -> unicode synonyms = synonyms, -- merged into the other two extras = extras, -- merged into the other two } + +fonts = fonts or { } +fonts.encodings = fonts.encodings or { } +fonts.encodings.agl = agl + +return agl diff --git a/Master/texmf-dist/tex/context/base/font-chk.lua b/Master/texmf-dist/tex/context/base/font-chk.lua index 591d59d6558..41205ce5ed7 100644 --- a/Master/texmf-dist/tex/context/base/font-chk.lua +++ b/Master/texmf-dist/tex/context/base/font-chk.lua @@ -17,6 +17,8 @@ local fastcopy = table.fastcopy local report_fonts = logs.reporter("fonts","checking") +local allocate = utilities.storage.allocate + local fonts = fonts fonts.checkers = fonts.checkers or { } @@ -44,6 +46,8 @@ local tasks = nodes.tasks local enableaction = tasks.enableaction local disableaction = tasks.disableaction +local implement = interfaces.implement + local glyph_code = nodes.nodecodes.glyph local nuts = nodes.nuts @@ -88,7 +92,7 @@ end fonts.loggers.onetimemessage = onetimemessage -local mapping = { -- this is just an experiment to illustrate some principles elsewhere +local mapping = allocate { -- this is just an experiment to illustrate some principles elsewhere lu = "placeholder uppercase red", ll = "placeholder lowercase red", lt = "placeholder uppercase red", @@ -113,9 +117,15 @@ local mapping = { -- this is just an experiment to illustrate some principles el so = "placeholder lowercase yellow", } -table.setmetatableindex(mapping,function(t,k) v = "placeholder unknown gray" t[k] = v return v end) +table.setmetatableindex(mapping, + function(t,k) + v = "placeholder unknown gray" + t[k] = v + return v + end +) -local fakes = { +local fakes = allocate { { name = "lowercase", code = ".025 -.175 m .425 -.175 l .425 .525 l .025 .525 l .025 -.175 l .025 0 l .425 0 l .025 -.175 m h S", @@ -153,7 +163,7 @@ local fakes = { }, } -local variants = { +local variants = allocate { { tag = "gray", r = .6, g = .6, b = .6 }, { tag = "red", r = .6, g = 0, b = 0 }, { tag = "green", r = 0, g = .6, b = 0 }, @@ -216,6 +226,28 @@ function commands.getplaceholderchar(name) context(helpers.getprivatenode(fontdata[id],name)) end +local function placeholder(font,char) + local tfmdata = fontdata[font] + local properties = tfmdata.properties + local privates = properties.privates + local category = chardata[char].category + local fakechar = mapping[category] + local p = privates and privates[fakechar] + if not p then + addmissingsymbols(tfmdata) + p = properties.privates[fakechar] + end + if properties.lateprivates then + -- frozen already + return "node", getprivatenode(tfmdata,fakechar) + else + -- good, we have \definefontfeature[default][default][missing=yes] + return "char", p + end +end + +checkers.placeholder = placeholder + function checkers.missing(head) local lastfont, characters, found = nil, nil, nil head = tonut(head) @@ -249,27 +281,15 @@ function checkers.missing(head) end elseif action == "replace" then for i=1,#found do - local n = found[i] - local font = getfont(n) - local char = getchar(n) - local tfmdata = fontdata[font] - local properties = tfmdata.properties - local privates = properties.privates - local category = chardata[char].category - local fakechar = mapping[category] - local p = privates and privates[fakechar] - if not p then - addmissingsymbols(tfmdata) - p = properties.privates[fakechar] - end - if properties.lateprivates then -- .frozen - -- bad, we don't have them at the tex end - local fake = getprivatenode(tfmdata,fakechar) - insert_node_after(head,n,fake) - head = remove_node(head,n,true) + local node = found[i] + local kind, char = placeholder(getfont(node),getchar(node)) + if kind == "node" then + insert_node_after(head,node,tonut(char)) + head = remove_node(head,node,true) + elseif kind == "char" then + setfield(node,"char",char) else - -- good, we have \definefontfeature[default][default][missing=yes] - setfield(n,"char",p) + -- error end end else @@ -278,13 +298,17 @@ function checkers.missing(head) return tonode(head), false end -local relevant = { "missing (will be deleted)", "missing (will be flagged)", "missing" } +local relevant = { + "missing (will be deleted)", + "missing (will be flagged)", + "missing" +} -function checkers.getmissing(id) +local function getmissing(id) if id then - local list = checkers.getmissing(font.current()) + local list = getmissing(font.current()) if list then - local _, list = next(checkers.getmissing(font.current())) + local _, list = next(getmissing(font.current())) return list else return { } @@ -314,6 +338,8 @@ function checkers.getmissing(id) end end +checkers.getmissing = getmissing + local tracked = false trackers.register("fonts.missing", function(v) @@ -329,24 +355,6 @@ trackers.register("fonts.missing", function(v) action = v end) -function commands.checkcharactersinfont() - enableaction("processors","fonts.checkers.missing") - tracked = true -end - -function commands.removemissingcharacters() - enableaction("processors","fonts.checkers.missing") - action = "remove" - tracked = true -end - -function commands.replacemissingcharacters() - enableaction("processors","fonts.checkers.missing") - action = "replace" - otffeatures.defaults.missing = true - tracked = true -end - local report_characters = logs.reporter("fonts","characters") local report_character = logs.reporter("missing") diff --git a/Master/texmf-dist/tex/context/base/font-chk.mkiv b/Master/texmf-dist/tex/context/base/font-chk.mkiv index 4572041c28e..4c8967532e8 100644 --- a/Master/texmf-dist/tex/context/base/font-chk.mkiv +++ b/Master/texmf-dist/tex/context/base/font-chk.mkiv @@ -21,11 +21,9 @@ % % \definefontfeature[default][default][missing=yes] % \enabletrackers[fonts.missing=replace] -% -% or better: -\unexpanded\def\checkcharactersinfont {\ctxcommand{checkcharactersinfont()}} -\unexpanded\def\removemissingcharacters {\ctxcommand{removemissingcharacters()}} -\unexpanded\def\replacemissingcharacters{\ctxcommand{replacemissingcharacters()}} +\unexpanded\def\checkcharactersinfont {\enabletrackers[fonts.missing]} +\unexpanded\def\removemissingcharacters {\enabletrackers[fonts.missing=remove]} +\unexpanded\def\replacemissingcharacters{\enabletrackers[fonts.missing=replace]} \endinput diff --git a/Master/texmf-dist/tex/context/base/font-cid.lua b/Master/texmf-dist/tex/context/base/font-cid.lua index e4b565313b4..0eaacdfbd54 100644 --- a/Master/texmf-dist/tex/context/base/font-cid.lua +++ b/Master/texmf-dist/tex/context/base/font-cid.lua @@ -74,7 +74,7 @@ local function loadcidfile(filename) ordering = ordering, filename = filename, unicodes = unicodes, - names = names + names = names, } end end @@ -112,15 +112,28 @@ function cid.getmap(specification) report_otf("invalid cidinfo specification, table expected") return end - local registry = specification.registry - local ordering = specification.ordering + local registry = specification.registry + local ordering = specification.ordering local supplement = specification.supplement - -- check for already loaded file - local filename = format(registry,ordering,supplement) - local found = cidmap[lower(filename)] + local filename = format(registry,ordering,supplement) + local lowername = lower(filename) + local found = cidmap[lowername] if found then return found end + if ordering == "Identity" then + local found = { + supplement = supplement, + registry = registry, + ordering = ordering, + filename = filename, + unicodes = { }, + names = { }, + } + cidmap[lowername] = found + return found + end + -- check for already loaded file if trace_loading then report_otf("cidmap needed, registry %a, ordering %a, supplement %a",registry,ordering,supplement) end diff --git a/Master/texmf-dist/tex/context/base/font-col.lua b/Master/texmf-dist/tex/context/base/font-col.lua index 187e33311ee..997c57c9f92 100644 --- a/Master/texmf-dist/tex/context/base/font-col.lua +++ b/Master/texmf-dist/tex/context/base/font-col.lua @@ -45,6 +45,8 @@ local currentfont = font.current local fontpatternhassize = fonts.helpers.fontpatternhassize +local implement = interfaces.implement + local list = { } local current = 0 local enabled = false @@ -275,9 +277,38 @@ end -- interface -commands.fontcollectiondefine = collections.define -commands.fontcollectionreset = collections.reset -commands.fontcollectionprepare = collections.prepare -commands.fontcollectionreport = collections.report -commands.fontcollectionregister = collections.registermain -commands.fontcollectionclone = collections.clonevector +implement { + name = "fontcollectiondefine", + actions = collections.define, + arguments = { "string", "string", "string", "string" } +} + +implement { + name = "fontcollectionreset", + actions = collections.reset, + arguments = { "string", "string" } +} + +implement { + name = "fontcollectionprepare", + actions = collections.prepare, + arguments = "string" +} + +implement { + name = "fontcollectionreport", + actions = collections.report, + arguments = "string" +} + +implement { + name = "fontcollectionregister", + actions = collections.registermain, + arguments = "string" +} + +implement { + name = "fontcollectionclone", + actions = collections.clonevector, + arguments = "string" +} diff --git a/Master/texmf-dist/tex/context/base/font-col.mkvi b/Master/texmf-dist/tex/context/base/font-col.mkvi index 34a1b04a808..bc8e8151ed1 100644 --- a/Master/texmf-dist/tex/context/base/font-col.mkvi +++ b/Master/texmf-dist/tex/context/base/font-col.mkvi @@ -34,13 +34,13 @@ \unexpanded\def\resetfontfallback {\dodoubleempty \font_fallbacks_reset } \def\font_fallbacks_define[#name][#font][#ranges][#settings]% - {\ctxcommand{fontcollectiondefine("#name","#font",\!!bs#ranges\!!es,\!!bs#settings\!!es)}} + {\clf_fontcollectiondefine{#name}{#font}{#ranges}{#settings}} \def\font_fallbacks_reset[#name][#font]% - {\ctxcommand{fontcollectionreset("#name","#font")}} + {\clf_fontcollectionreset{#name}{#font}} \def\font_fallbacks_prepare#name% - {\ctxcommand{fontcollectionprepare("#name")}} % add fallbacks to last font + {\clf_fontcollectionprepare{#name}} % add fallbacks to last font % we might as well move the handling to lua but then we need to pass the % fallbacks, skewchar etc. @@ -77,7 +77,7 @@ {\endgroup} \def\font_fallbacks_clone_unique#specification#scale% kind of dododefinefont - {\ctxcommand{fontcollectionreport("defining #specification (relative scale: #scale)")}% brrr + {\clf_fontcollectionreport{defining #specification (relative scale: #scale)}% brrr \setfalse\c_font_auto_size \let\lastfontidentifier\s!dummy \def\v_font_size_relative{#scale}% @@ -89,8 +89,8 @@ \def\font_fallbacks_clone_inherited#font% also a second argument {\font_fallbacks_clone_unique{#font \savedfontspec}} -\def\font_fallbacks_register_main #name{\ctxcommand{fontcollectionregister("#name")}} -\def\font_fallbacks_prepare_clone_vectors#name{\ctxcommand{fontcollectionclone("#name")}} +\def\font_fallbacks_register_main #name{\clf_fontcollectionregister{#name}} +\def\font_fallbacks_prepare_clone_vectors#name{\clf_fontcollectionclone{#name}} % check : only replace when present in replacement font (default: no) % force : force replacent even when basefont has glyph (default: yes) diff --git a/Master/texmf-dist/tex/context/base/font-con.lua b/Master/texmf-dist/tex/context/base/font-con.lua index aca7055235e..72fbb5c0dcc 100644 --- a/Master/texmf-dist/tex/context/base/font-con.lua +++ b/Master/texmf-dist/tex/context/base/font-con.lua @@ -45,6 +45,8 @@ constructors.cache = containers.define("fonts", "constructors", constr constructors.privateoffset = 0xF0000 -- 0x10FFFF +constructors.cacheintex = true -- so we see the original table in fonts.font + -- Some experimental helpers (handy for tracing): -- -- todo: extra: @@ -394,7 +396,8 @@ function constructors.scale(tfmdata,specification) targetparameters.forcedsize = forcedsize -- context specific targetparameters.extrafactor = extrafactor -- context specific -- - local tounicode = resources.tounicode + local tounicode = fonts.mappings.tounicode + -- local defaultwidth = resources.defaultwidth or 0 local defaultheight = resources.defaultheight or 0 local defaultdepth = resources.defaultdepth or 0 @@ -436,6 +439,7 @@ function constructors.scale(tfmdata,specification) target.tounicode = 1 target.cidinfo = properties.cidinfo target.format = properties.format + target.cache = constructors.cacheintex and "yes" or "renew" -- local fontname = properties.fontname or tfmdata.fontname -- for the moment we fall back on local fullname = properties.fullname or tfmdata.fullname -- names in the tfmdata although @@ -453,6 +457,7 @@ function constructors.scale(tfmdata,specification) target.psname = psname target.name = name -- + -- properties.fontname = fontname properties.fullname = fullname properties.filename = filename @@ -500,7 +505,9 @@ function constructors.scale(tfmdata,specification) local autoitalicamount = properties.autoitalicamount local stackmath = not properties.nostackmath local nonames = properties.noglyphnames - local nodemode = properties.mode == "node" + local haskerns = properties.haskerns or properties.mode == "base" -- we can have afm in node mode + local hasligatures = properties.hasligatures or properties.mode == "base" -- we can have afm in node mode + local realdimensions = properties.realdimensions -- if changed and not next(changed) then changed = false @@ -594,43 +601,45 @@ function constructors.scale(tfmdata,specification) -- we can have a dumb mode (basemode without math etc) that skips most -- for unicode, character in next, characters do - local chr, description, index, touni + local chr, description, index if changed then - -- basemode hack (we try to catch missing tounicodes, e.g. needed for ssty in math cambria) local c = changed[unicode] if c then - local ligatures = character.ligatures -- the original ligatures (as we cannot rely on remapping) description = descriptions[c] or descriptions[unicode] or character character = characters[c] or character index = description.index or c - if tounicode then - touni = tounicode[index] -- nb: index! - if not touni then -- goodie - local d = descriptions[unicode] or characters[unicode] - local i = d.index or unicode - touni = tounicode[i] -- nb: index! - end - end - if ligatures and not character.ligatures then - character.ligatures = ligatures -- the original targets (for now at least.. see libertine smallcaps) - end else description = descriptions[unicode] or character index = description.index or unicode - if tounicode then - touni = tounicode[index] -- nb: index! - end end else description = descriptions[unicode] or character index = description.index or unicode - if tounicode then - touni = tounicode[index] -- nb: index! - end end local width = description.width local height = description.height local depth = description.depth + if realdimensions then + -- this is mostly for checking issues + if not height or height == 0 then + local bb = description.boundingbox + local ht = bb[4] + if ht ~= 0 then + height = ht + end + if not depth or depth == 0 then + local dp = -bb[2] + if dp ~= 0 then + depth = dp + end + end + elseif not depth or depth == 0 then + local dp = -description.boundingbox[2] + if dp ~= 0 then + depth = dp + end + end + end if width then width = hdelta*width else width = scaledwidth end if height then height = vdelta*height else height = scaledheight end -- if depth then depth = vdelta*depth else depth = scaleddepth end @@ -669,8 +678,10 @@ function constructors.scale(tfmdata,specification) } end end - if touni then - chr.tounicode = touni + local isunicode = description.unicode + if isunicode then + chr.unicode = isunicode + chr.tounicode = tounicode(isunicode) end if hasquality then -- we could move these calculations elsewhere (saves calculations) @@ -767,7 +778,7 @@ function constructors.scale(tfmdata,specification) end end end - if not nodemode then + if haskerns then local vk = character.kerns if vk then local s = sharedkerns[vk] @@ -778,6 +789,8 @@ function constructors.scale(tfmdata,specification) end chr.kerns = s end + end + if hasligatures then local vl = character.ligatures if vl then if true then @@ -965,6 +978,8 @@ function constructors.finalize(tfmdata) tfmdata.slant = nil tfmdata.units_per_em = nil -- + tfmdata.cache = nil + -- properties.finalized = true -- return tfmdata @@ -1362,3 +1377,50 @@ function constructors.applymanipulators(what,tfmdata,features,trace,report) end end end + +function constructors.addcoreunicodes(unicodes) -- maybe make this a metatable if used at all + if not unicodes then + unicodes = { } + end + unicodes.space = 0x0020 + unicodes.hyphen = 0x002D + unicodes.zwj = 0x200D + unicodes.zwnj = 0x200C + return unicodes +end + +-- -- keep for a while: old tounicode code +-- +-- if changed then +-- -- basemode hack (we try to catch missing tounicodes, e.g. needed for ssty in math cambria) +-- local c = changed[unicode] +-- if c then +-- -- local ligatures = character.ligatures -- the original ligatures (as we cannot rely on remapping) +-- description = descriptions[c] or descriptions[unicode] or character +-- character = characters[c] or character +-- index = description.index or c +-- if tounicode then +-- touni = tounicode[index] -- nb: index! +-- if not touni then -- goodie +-- local d = descriptions[unicode] or characters[unicode] +-- local i = d.index or unicode +-- touni = tounicode[i] -- nb: index! +-- end +-- end +-- -- if ligatures and not character.ligatures then +-- -- character.ligatures = ligatures -- the original targets (for now at least.. see libertine smallcaps) +-- -- end +-- else +-- description = descriptions[unicode] or character +-- index = description.index or unicode +-- if tounicode then +-- touni = tounicode[index] -- nb: index! +-- end +-- end +-- else +-- description = descriptions[unicode] or character +-- index = description.index or unicode +-- if tounicode then +-- touni = tounicode[index] -- nb: index! +-- end +-- end diff --git a/Master/texmf-dist/tex/context/base/font-ctx.lua b/Master/texmf-dist/tex/context/base/font-ctx.lua index 2bfcf38598a..2c96e9ac2be 100644 --- a/Master/texmf-dist/tex/context/base/font-ctx.lua +++ b/Master/texmf-dist/tex/context/base/font-ctx.lua @@ -21,6 +21,7 @@ local settings_to_hash, hash_to_string = utilities.parsers.settings_to_hash, uti local formatcolumns = utilities.formatters.formatcolumns local mergehashes = utilities.parsers.mergehashes local formatters = string.formatters +local basename = file.basename local tostring, next, type, rawget, tonumber = tostring, next, type, rawget, tonumber local utfchar, utfbyte = utf.char, utf.byte @@ -44,6 +45,8 @@ local report_mapfiles = logs.reporter("fonts","mapfiles") local setmetatableindex = table.setmetatableindex +local implement = interfaces.implement + local fonts = fonts local handlers = fonts.handlers local otf = handlers.otf -- brrr @@ -57,6 +60,10 @@ local helpers = fonts.helpers local hashes = fonts.hashes local currentfont = font.current +local encodings = fonts.encodings +----- aglunicodes = encodings.agl.unicodes +local aglunicodes = nil -- delayed loading + local nuts = nodes.nuts local tonut = nuts.tonut @@ -78,18 +85,22 @@ local texdefinefont = tex.definefont local texsp = tex.sp local fontdata = hashes.identifiers -local characters = hashes.chardata +local characters = hashes.characters local descriptions = hashes.descriptions local properties = hashes.properties local resources = hashes.resources +local unicodes = hashes.unicodes local csnames = hashes.csnames -local marks = hashes.markdata local lastmathids = hashes.lastmathids local exheights = hashes.exheights local emwidths = hashes.emwidths +local parameters = hashes.parameters local designsizefilename = fontgoodies.designsizes.filename +local context_char = context.char +local context_getvalue = context.getvalue + local otffeatures = otf.features local otftables = otf.tables @@ -134,10 +145,12 @@ end -- this will move elsewhere ... -function fonts.helpers.name(tfmdata) - return file.basename(type(tfmdata) == "number" and properties[tfmdata].name or tfmdata.properties.name) +local function getfontname(tfmdata) + return basename(type(tfmdata) == "number" and properties[tfmdata].name or tfmdata.properties.name) end +fonts.helpers.name = getfontname + if _LUAVERSION < 5.2 then utilities.strings.formatters.add(formatters,"font:name", [["'"..fontname(%s).."'"]], "local fontname = fonts.helpers.name") @@ -213,7 +226,6 @@ function constructors.trytosharefont(target,tfmdata) end end - directives.register("fonts.checksharing",function(v) if not v then report_defining("font sharing in backend is disabled") @@ -221,19 +233,6 @@ directives.register("fonts.checksharing",function(v) constructors.sharefonts = v end) -local limited = false - -directives.register("system.inputmode", function(v) - if not limited then - local i_limiter = io.i_limiter(v) - if i_limiter then - fontloader.open = i_limiter.protect(fontloader.open) - fontloader.info = i_limiter.protect(fontloader.info) - limited = true - end - end -end) - function definers.resetnullfont() -- resetting is needed because tikz misuses nullfont local parameters = fonts.nulldata.parameters @@ -251,7 +250,17 @@ function definers.resetnullfont() definers.resetnullfont = function() end end -commands.resetnullfont = definers.resetnullfont +implement { + name = "resetnullfont", + onlyonce = true, + actions = function() + for i=1,7 do + -- we have no direct method yet + context([[\fontdimen%s\nullfont\zeropoint]],i) + end + definers.resetnullfont() + end +} -- this cannot be a feature initializer as there is no auto namespace -- so we never enter the loop then; we can store the defaults in the tma @@ -878,7 +887,10 @@ end specifiers.splitcontext = splitcontext function specifiers.contexttostring(name,kind,separator,yes,no,strict,omit) -- not used - return hash_to_string(mergedtable(handlers[kind].features.defaults or {},setups[name] or {}),separator,yes,no,strict,omit) + return hash_to_string( + mergedtable(handlers[kind].features.defaults or {},setups[name] or {}), + separator, yes, no, strict, omit or { "number" } + ) end local function starred(features) -- no longer fallbacks here @@ -900,11 +912,11 @@ local separator = S(";,") local equal = P("=") local spaces = space^0 local sometext = C((1-equal-space-separator)^1) -local truevalue = P("+") * spaces * sometext * Cc(true) -- "yes" -local falsevalue = P("-") * spaces * sometext * Cc(false) -- "no" +local truevalue = P("+") * spaces * sometext * Cc(true) +local falsevalue = P("-") * spaces * sometext * Cc(false) +local somevalue = sometext * spaces * Cc(true) local keyvalue = sometext * spaces * equal * spaces * sometext -local somevalue = sometext * spaces * Cc(true) -- "yes" -local pattern = Cf(Ct("") * (space + separator + Cg(keyvalue + falsevalue + truevalue + somevalue))^0, rawset) +local pattern = Cf(Ct("") * (space + separator + Cg(falsevalue + truevalue + keyvalue + somevalue))^0, rawset) local function colonized(specification) specification.features.normal = normalize_features(lpegmatch(pattern,specification.detail)) @@ -956,14 +968,30 @@ local getspecification = definers.getspecification do -- else too many locals - local ctx_setdefaultfontname = context.fntsetdefname - local ctx_setsomefontname = context.fntsetsomename - local ctx_setemptyfontsize = context.fntsetnopsize - local ctx_setsomefontsize = context.fntsetsomesize - local ctx_letvaluerelax = context.letvaluerelax + ----- ctx_setdefaultfontname = context.fntsetdefname + ----- ctx_setsomefontname = context.fntsetsomename + ----- ctx_setemptyfontsize = context.fntsetnopsize + ----- ctx_setsomefontsize = context.fntsetsomesize + ----- ctx_letvaluerelax = context.letvaluerelax + + local starttiming = statistics.starttiming + local stoptiming = statistics.stoptiming + + local scanners = tokens.scanners + local scanstring = scanners.string + local scaninteger = scanners.integer + local scanboolean = scanners.boolean + + local setmacro = tokens.setters.macro - function commands.definefont_one(str) - statistics.starttiming(fonts) + local scanners = interfaces.scanners + + -- function commands.definefont_one(str) + + scanners.definefont_one = function() + local str = scanstring() + + starttiming(fonts) if trace_defining then report_defining("memory usage before: %s",statistics.memused()) report_defining("start stage one: %s",str) @@ -972,29 +1000,31 @@ do -- else too many locals local lookup, name, sub, method, detail = getspecification(fullname) if not name then report_defining("strange definition %a",str) - ctx_setdefaultfontname() + -- ctx_setdefaultfontname() elseif name == "unknown" then - ctx_setdefaultfontname() + -- ctx_setdefaultfontname() else - ctx_setsomefontname(name) + -- ctx_setsomefontname(name) + setmacro("somefontname",name,"global") end -- we can also use a count for the size if size and size ~= "" then local mode, size = lpegmatch(sizepattern,size) if size and mode then texsetcount("scaledfontmode",mode) - ctx_setsomefontsize(size) + -- ctx_setsomefontsize(size) + setmacro("somefontsize",size) else texsetcount("scaledfontmode",0) - ctx_setemptyfontsize() + -- ctx_setemptyfontsize() end elseif true then -- so we don't need to check in tex texsetcount("scaledfontmode",2) - ctx_setemptyfontsize() + -- ctx_setemptyfontsize() else texsetcount("scaledfontmode",0) - ctx_setemptyfontsize() + -- ctx_setemptyfontsize() end specification = definers.makespecification(str,lookup,name,sub,method,detail,size) if trace_defining then @@ -1011,8 +1041,29 @@ do -- else too many locals return (gsub(cs,".->", "")) end - function commands.definefont_two(global,cs,str,size,inheritancemode,classfeatures,fontfeatures,classfallbacks,fontfallbacks, - mathsize,textsize,relativeid,classgoodies,goodies,classdesignsize,fontdesignsize,scaledfontmode) + -- function commands.definefont_two(global,cs,str,size,inheritancemode,classfeatures,fontfeatures,classfallbacks,fontfallbacks, + -- mathsize,textsize,relativeid,classgoodies,goodies,classdesignsize,fontdesignsize,scaledfontmode) + + scanners.definefont_two = function() + + local global = scanboolean() -- \ifx\fontclass\empty\s!false\else\s!true\fi + local cs = scanstring () -- {#csname}% + local str = scanstring () -- \somefontfile + local size = scaninteger() -- \d_font_scaled_font_size + local inheritancemode = scaninteger() -- \c_font_feature_inheritance_mode + local classfeatures = scanstring () -- \m_font_class_features + local fontfeatures = scanstring () -- \m_font_features + local classfallbacks = scanstring () -- \m_font_class_fallbacks + local fontfallbacks = scanstring () -- \m_font_fallbacks + local mathsize = scaninteger() -- \fontface + local textsize = scaninteger() -- \d_font_scaled_text_face + local relativeid = scaninteger() -- \relativefontid + local classgoodies = scanstring () -- \m_font_class_goodies + local goodies = scanstring () -- \m_font_goodies + local classdesignsize = scanstring () -- \m_font_class_designsize + local fontdesignsize = scanstring () -- \m_font_designsize + local scaledfontmode = scaninteger() -- \scaledfontmode + if trace_defining then report_defining("start stage two: %s (size %s)",str,size) end @@ -1112,7 +1163,8 @@ do -- else too many locals if not tfmdata then report_defining("unable to define %a as %a",name,nice_cs(cs)) lastfontid = -1 - ctx_letvaluerelax(cs) -- otherwise the current definition takes the previous one + texsetcount("scaledfontsize",0) + -- ctx_letvaluerelax(cs) -- otherwise the current definition takes the previous one elseif type(tfmdata) == "number" then if trace_defining then report_defining("reusing %s, id %a, target %a, features %a / %a, fallbacks %a / %a, goodies %a / %a, designsize %a / %a", @@ -1122,7 +1174,8 @@ do -- else too many locals texdefinefont(global,cs,tfmdata) -- resolved (when designsize is used): local size = fontdata[tfmdata].parameters.size or 0 - ctx_setsomefontsize(size .. "sp") + -- ctx_setsomefontsize(size .. "sp") + setmacro("somefontsize",size.."sp") texsetcount("scaledfontsize",size) lastfontid = tfmdata else @@ -1149,7 +1202,8 @@ do -- else too many locals end -- resolved (when designsize is used): local size = tfmdata.parameters.size or 655360 - ctx_setsomefontsize(size .. "sp") + setmacro("somefontsize",size.."sp") + -- ctx_setsomefontsize(size .. "sp") texsetcount("scaledfontsize",size) lastfontid = id end @@ -1167,16 +1221,18 @@ do -- else too many locals lastmathids[mathsize] = lastfontid end -- - statistics.stoptiming(fonts) + stoptiming(fonts) end + -- + function definers.define(specification) -- local name = specification.name if not name or name == "" then return -1 else - statistics.starttiming(fonts) + starttiming(fonts) -- -- following calls expect a few properties to be set: -- @@ -1232,26 +1288,25 @@ do -- else too many locals constructors.finalize(tfmdata) return id, tfmdata end - statistics.stoptiming(fonts) + stoptiming(fonts) end end -end - --- local id, cs = fonts.definers.internal { } --- local id, cs = fonts.definers.internal { number = 2 } --- local id, cs = fonts.definers.internal { name = "dejavusans" } - -do + -- local id, cs = fonts.definers.internal { } + -- local id, cs = fonts.definers.internal { number = 2 } + -- local id, cs = fonts.definers.internal { name = "dejavusans" } local n = 0 function definers.internal(specification,cs) specification = specification or { } local name = specification.name - local size = specification.size and number.todimen(specification.size) or texgetdimen("bodyfontsize") + local size = tonumber(specification.size) local number = tonumber(specification.number) local id = nil + if not size then + size = texgetdimen("bodyfontsize") + end if number then id = number elseif name and name ~= "" then @@ -1275,6 +1330,17 @@ do return id, csnames[id] end + -- here + + local infofont = 0 + + function fonts.infofont() + if infofont == 0 then + infofont = definers.define { name = "dejavusansmono", size = tex.sp("6pt") } + end + return infofont + end + end local enable_auto_r_scale = false @@ -1306,7 +1372,7 @@ function constructors.calculatescale(tfmdata,scaledpoints,relativeid,specificati end end end - scaledpoints, delta = calculatescale(tfmdata,scaledpoints) + local scaledpoints, delta = calculatescale(tfmdata,scaledpoints) -- if enable_auto_r_scale and relativeid then -- for the moment this is rather context specific (we need to hash rscale then) -- local relativedata = fontdata[relativeid] -- local rfmdata = relativedata and relativedata.unscaled and relativedata.unscaled @@ -1395,10 +1461,10 @@ end local mappings = fonts.mappings local loaded = { -- prevent loading (happens in cont-sys files) - ["original-base.map" ] = true, - ["original-ams-base.map" ] = true, - ["original-ams-euler.map"] = true, - ["original-public-lm.map"] = true, + -- ["original-base.map" ] = true, + -- ["original-ams-base.map" ] = true, + -- ["original-ams-euler.map"] = true, + -- ["original-public-lm.map"] = true, } function mappings.loadfile(name) @@ -1436,20 +1502,178 @@ end mappings.reset() -- resets the default file +implement { + name = "loadmapfile", + actions = mappings.loadfile, + arguments = "string" +} + +implement { + name = "loadmapline", + actions = mappings.loadline, + arguments = "string" +} + +implement { + name = "resetmapfiles", + actions = mappings.reset, + arguments = "string" +} + -- we need an 'do after the banner hook' -- => commands local function nametoslot(name) local t = type(name) + local s = nil if t == "string" then - return resources[true].unicodes[name] + local slot = unicodes[true][name] + if slot then + return slot + end + if not aglunicodes then + aglunicodes = encodings.agl.unicodes + end + slot = aglunicodes[name] + if characters[true][slot] then + return slot + else + -- not in font + end elseif t == "number" then - return n + if characters[true][name] then + return slot + else + -- not in font + end end end -helpers.nametoslot = nametoslot +local function indextoslot(index) + local r = resources[true] + if r then + local indices = r.indices + if not indices then + indices = { } + local c = characters[true] + for unicode, data in next, c do + local di = data.index + if di then + indices[di] = unicode + end + end + r.indices = indices + end + return indices[tonumber(index)] + end +end + +do -- else too many locals + + local entities = characters.entities + local lowered = { } -- delayed initialization + + setmetatableindex(lowered,function(t,k) + for k, v in next, entities do + local l = lower(k) + if not entities[l] then + lowered[l] = v + end + end + setmetatableindex(lowered,nil) + return lowered[k] + end) + + local methods = { + -- entity + e = function(name) + return entities[name] or lowered[name] or name + end, + -- hexadecimal unicode + x = function(name) + local n = tonumber(name,16) + return n and utfchar(n) or name + end, + -- decimal unicode + d = function(name) + local n = tonumber(name) + return n and utfchar(n) or name + end, + -- hexadecimal index (slot) + s = function(name) + local n = tonumber(name,16) + local n = n and indextoslot(n) + return n and utfchar(n) or name + end, + -- decimal index + i = function(name) + local n = tonumber(name) + local n = n and indextoslot(n) + return n and utfchar(n) or name + end, + -- name + n = function(name) + local n = nametoslot(name) + return n and utfchar(n) or name + end, + -- char + c = function(name) + return name + end, + } + + -- -- nicer: + -- + -- setmetatableindex(methods,function(t,k) return methods.c end) + -- + -- local splitter = (C(1) * P(":") + Cc("c")) * C(P(1)^1) / function(method,name) + -- return methods[method](name) + -- end + -- + -- -- more efficient: + + local splitter = C(1) * P(":") * C(P(1)^1) / function(method,name) + local action = methods[method] + return action and action(name) or name + end + + local function tochar(str) + local t = type(str) + if t == "number" then + return utfchar(str) + elseif t == "string" then + return lpegmatch(splitter,str) or str + else + return str + end + end + + helpers.nametoslot = nametoslot + helpers.indextoslot = indextoslot + helpers.tochar = tochar + + -- interfaces: + + implement { + name = "fontchar", + actions = { nametoslot, context_char }, + arguments = "string", + } + + implement { + name = "fontcharbyindex", + actions = { indextoslot, context_char }, + arguments = "integer", + } + + implement { + name = "tochar", + actions = { tochar, context }, + arguments = "string", + } + +end -- this will change ... @@ -1573,15 +1797,21 @@ function fonts.definetypeface(name,t) local boldwidth = t.boldwidth or t.width or p.boldwidth or p.width or "normal" Shape = Shapes[shape] or "Serif" ctx_startfontclass { name } - ctx_definefontsynonym( { format("%s", Shape) }, { format("spec:%s-%s-regular-%s", fontname, normalweight, normalwidth) } ) - ctx_definefontsynonym( { format("%sBold", Shape) }, { format("spec:%s-%s-regular-%s", fontname, boldweight, boldwidth ) } ) - ctx_definefontsynonym( { format("%sBoldItalic", Shape) }, { format("spec:%s-%s-italic-%s", fontname, boldweight, boldwidth ) } ) - ctx_definefontsynonym( { format("%sItalic", Shape) }, { format("spec:%s-%s-italic-%s", fontname, normalweight, normalwidth) } ) + ctx_definefontsynonym( { formatters["%s"] (Shape) }, { formatters["spec:%s-%s-regular-%s"] (fontname, normalweight, normalwidth) } ) + ctx_definefontsynonym( { formatters["%sBold"] (Shape) }, { formatters["spec:%s-%s-regular-%s"] (fontname, boldweight, boldwidth ) } ) + ctx_definefontsynonym( { formatters["%sBoldItalic"](Shape) }, { formatters["spec:%s-%s-italic-%s"] (fontname, boldweight, boldwidth ) } ) + ctx_definefontsynonym( { formatters["%sItalic"] (Shape) }, { formatters["spec:%s-%s-italic-%s"] (fontname, normalweight, normalwidth) } ) ctx_stopfontclass() local settings = sequenced({ features= t.features },",") ctx_dofastdefinetypeface(name, shortcut, shape, size, settings) end +implement { + name = "definetypeface", + actions = fonts.definetypeface, + arguments = { "string", "string" } +} + function fonts.current() -- todo: also handle name return fontdata[currentfont()] or fontdata[0] end @@ -1590,101 +1820,6 @@ function fonts.currentid() return currentfont() or 0 end --- interfaces - -local context_char = context.char -local context_getvalue = context.getvalue - -local commands_doifelse = commands.doifelse - -function commands.fontchar(n) - n = nametoslot(n) - if n then - context_char(n) - end -end - -function commands.doifelsecurrentfonthasfeature(name) -- can be made faster with a supportedfeatures hash - local f = fontdata[currentfont()] - f = f and f.shared - f = f and f.rawdata - f = f and f.resources - f = f and f.features - commands_doifelse(f and (f.gpos[name] or f.gsub[name])) -end - -local p, f = 1, formatters["%0.1fpt"] -- normally this value is changed only once - -local stripper = lpeg.patterns.stripzeros - -function commands.nbfs(amount,precision) - if precision ~= p then - p = precision - f = formatters["%0." .. p .. "fpt"] - end - context(lpegmatch(stripper,f(amount/65536))) -end - -function commands.featureattribute(tag) - context(contextnumber(tag)) -end - -function commands.setfontfeature(tag) - texsetattribute(0,contextnumber(tag)) -end - -function commands.resetfontfeature() - texsetattribute(0,0) -end - --- function commands.addfs(tag) withset(tag, 1) end --- function commands.subfs(tag) withset(tag,-1) end --- function commands.addff(tag) withfnt(tag, 2) end -- on top of font features --- function commands.subff(tag) withfnt(tag,-2) end -- on top of font features - -function commands.cleanfontname (name) context(names.cleanname(name)) end - -function commands.fontlookupinitialize (name) names.lookup(name) end -function commands.fontlookupnoffound () context(names.noflookups()) end -function commands.fontlookupgetkeyofindex(key,index) context(names.getlookupkey(key,index)) end -function commands.fontlookupgetkey (key) context(names.getlookupkey(key)) end - --- this might move to a runtime module: - -function commands.showchardata(n) - local tfmdata = fontdata[currentfont()] - if tfmdata then - if type(n) == "string" then - n = utfbyte(n) - end - local chr = tfmdata.characters[n] - if chr then - report_status("%s @ %s => %U => %c => %s",tfmdata.properties.fullname,tfmdata.parameters.size,n,n,serialize(chr,false)) - end - end -end - -function commands.showfontparameters(tfmdata) - -- this will become more clever - local tfmdata = tfmdata or fontdata[currentfont()] - if tfmdata then - local parameters = tfmdata.parameters - local mathparameters = tfmdata.mathparameters - local properties = tfmdata.properties - local hasparameters = parameters and next(parameters) - local hasmathparameters = mathparameters and next(mathparameters) - if hasparameters then - report_status("%s @ %s => text parameters => %s",properties.fullname,parameters.size,serialize(parameters,false)) - end - if hasmathparameters then - report_status("%s @ %s => math parameters => %s",properties.fullname,parameters.size,serialize(mathparameters,false)) - end - if not hasparameters and not hasmathparameters then - report_status("%s @ %s => no text parameters and/or math parameters",properties.fullname,parameters.size) - end - end -end - -- for the moment here, this will become a chain of extras that is -- hooked into the ctx registration (or scaler or ...) @@ -1866,79 +2001,152 @@ end -- end -- end -function commands.setfontofid(id) - context_getvalue(csnames[id]) -end +do --- more interfacing: + local scanners = tokens.scanners + local scanstring = scanners.string + local scaninteger = scanners.integer + local scandimen = scanners.dimen + local scanboolean = scanners.boolean -commands.definefontfeature = presetcontext + local setmacro = tokens.setters.macro -local cache = { } + local scanners = interfaces.scanners -local hows = { - ["+"] = "add", - ["-"] = "subtract", - ["="] = "replace", -} + function constructors.currentfonthasfeature(n) + local f = fontdata[currentfont()] + if not f then return end f = f.shared + if not f then return end f = f.rawdata + if not f then return end f = f.resources + if not f then return end f = f.features + return f and (f.gpos[n] or f.gsub[n]) + end -function commands.feature(how,parent,name,font) -- 0/1 test temporary for testing - if not how or how == 0 then - if trace_features and texgetattribute(0) ~= 0 then - report_cummulative("font %!font:name!, reset",fontdata[font or true]) - end - texsetattribute(0,0) - elseif how == true or how == 1 then - local hash = "feature > " .. parent - local done = cache[hash] - if trace_features and done then - report_cummulative("font %!font:name!, revive %a : %!font:features!",fontdata[font or true],parent,setups[numbers[done]]) - end - texsetattribute(0,done or 0) - else - local full = parent .. how .. name - local hash = "feature > " .. full - local done = cache[hash] - if not done then - local n = setups[full] - if n then - -- already defined - else - n = mergecontextfeatures(parent,name,how,full) + implement { + name = "doifelsecurrentfonthasfeature", + actions = { currentfonthasfeature, commands.doifelse }, + arguments = "string" + } + + -- local p, f = 1, formatters["%0.1fpt"] -- normally this value is changed only once + -- + -- local stripper = lpeg.patterns.stripzeros + -- + -- function commands.nbfs(amount,precision) + -- if precision ~= p then + -- p = precision + -- f = formatters["%0." .. p .. "fpt"] + -- end + -- context(lpegmatch(stripper,f(amount/65536))) + -- end + + local f = formatters["%0.2fpt"] -- normally this value is changed only once + + local stripper = lpeg.patterns.stripzeros + + scanners.nbfs = function() + context(lpegmatch(stripper,f(scandimen()/65536))) + end + + commands.featureattribute = function(tag) context(contextnumber(tag)) end + commands.setfontfeature = function(tag) texsetattribute(0,contextnumber(tag)) end + commands.resetfontfeature = function() texsetattribute(0,0) end + commands.setfontofid = function(id) context_getvalue(csnames[id]) end + commands.definefontfeature = presetcontext + + scanners.featureattribute = function() context(contextnumber(scanstring())) end + scanners.setfontfeature = function() texsetattribute(0,contextnumber(scanstring())) end + scanners.resetfontfeature = function() texsetattribute(0,0) end + scanners.setfontofid = function() context_getvalue(csnames[scaninteger()]) end + scanners.definefontfeature = function() presetcontext(scanstring(),scanstring(),scanstring()) end + + local cache = { } + + local hows = { + ["+"] = "add", + ["-"] = "subtract", + ["="] = "replace", + } + + local function setfeature(how,parent,name,font) -- 0/1 test temporary for testing + if not how or how == 0 then + if trace_features and texgetattribute(0) ~= 0 then + report_cummulative("font %!font:name!, reset",fontdata[font or true]) + end + texsetattribute(0,0) + elseif how == true or how == 1 then + local hash = "feature > " .. parent + local done = cache[hash] + if trace_features and done then + report_cummulative("font %!font:name!, revive %a : %!font:features!",fontdata[font or true],parent,setups[numbers[done]]) end - done = registercontextfeature(hash,full,how) - cache[hash] = done - if trace_features then - report_cummulative("font %!font:name!, %s %a : %!font:features!",fontdata[font or true],hows[how],full,setups[numbers[done]]) + texsetattribute(0,done or 0) + else + local full = parent .. how .. name + local hash = "feature > " .. full + local done = cache[hash] + if not done then + local n = setups[full] + if n then + -- already defined + else + n = mergecontextfeatures(parent,name,how,full) + end + done = registercontextfeature(hash,full,how) + cache[hash] = done + if trace_features then + report_cummulative("font %!font:name!, %s %a : %!font:features!",fontdata[font or true],hows[how],full,setups[numbers[done]]) + end end + texsetattribute(0,done) end - texsetattribute(0,done) end -end -function commands.featurelist(...) - context(fonts.specifiers.contexttostring(...)) -end + local function resetfeature() + if trace_features and texgetattribute(0) ~= 0 then + report_cummulative("font %!font:name!, reset",fontdata[true]) + end + texsetattribute(0,0) + end -function commands.registerlanguagefeatures() - local specifications = languages.data.specifications - for i=1,#specifications do - local specification = specifications[i] - local language = specification.opentype - if language then - local script = specification.opentypescript or specification.script - if script then - local context = specification.context - if type(context) == "table" then - for i=1,#context do - definecontext(context[i], { language = language, script = script}) + local function registerlanguagefeatures() + local specifications = languages.data.specifications + for i=1,#specifications do + local specification = specifications[i] + local language = specification.opentype + if language then + local script = specification.opentypescript or specification.script + if script then + local context = specification.context + if type(context) == "table" then + for i=1,#context do + definecontext(context[i], { language = language, script = script}) + end + elseif type(context) == "string" then + definecontext(context, { language = language, script = script}) end - elseif type(context) == "string" then - definecontext(context, { language = language, script = script}) end end end end + + implement { name = "resetfeature", actions = resetfeature } + implement { name = "addfeature", actions = setfeature, arguments = { "'+'", "string", "string" } } + implement { name = "subtractfeature", actions = setfeature, arguments = { "'-'", "string", "string" } } + implement { name = "replacefeature", actions = setfeature, arguments = { "'='", "string", "string" } } + implement { name = "revivefeature", actions = setfeature, arguments = { true, "string" } } + + implement { + name = "featurelist", + actions = { fonts.specifiers.contexttostring, context }, + arguments = { "string", "'otf'", "string", "'yes'", "'no'", true } + } + + implement { + name = "registerlanguagefeatures", + actions = registerlanguagefeatures, + } + end -- a fontkern plug: @@ -1956,11 +2164,11 @@ end) directives.register("nodes.injections.fontkern", function(v) setfield(kern,"subtype",v and 0 or 1) end) --- here +-- here (todo: closure) local trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end) -local otffeatures = constructors.newfeatures("otf") +----- otffeatures = constructors.newfeatures("otf") local registerotffeature = otffeatures.register local analyzers = fonts.analyzers @@ -1979,7 +2187,7 @@ local glyph_code = nodes.nodecodes.glyph local states = analyzers.states -local names = { +local colornames = { [states.init] = "font:1", [states.medi] = "font:2", [states.fina] = "font:3", @@ -2000,7 +2208,7 @@ local function markstates(head) for glyph in traverse_by_id(glyph_code,head) do local a = getprop(glyph,a_state) if a then - local name = names[a] + local name = colornames[a] if name then local color = m_color[name] if color then @@ -2055,11 +2263,130 @@ function methods.nocolor(head,font,attr) return head, true end -function commands.purefontname(name) +local function purefontname(name) if type(name) == "number" then - name = fonts.helpers.name(name) + name = getfontname(name) end if type(name) == "string" then - context(file.basename(name)) + return basename(name) + end +end + +implement { + name = "purefontname", + actions = { purefontname, context }, + arguments = "string", +} + +local list = storage.shared.bodyfontsizes or { } +storage.shared.bodyfontsizes = list + +implement { + name = "registerbodyfontsize", + arguments = "string", + actions = function(size) + list[size] = true + end +} + +implement { + name = "getbodyfontsizes", + arguments = "string", + actions = function(separator) + context(concat(sortedkeys(list),separator)) + end +} + +implement { + name = "processbodyfontsizes", + arguments = "string", + actions = function(command) + local keys = sortedkeys(list) + if command then + local action = context[command] + for i=1,#keys do + action(keys[i]) + end + else + context(concat(keys,",")) + end + end +} + +implement { + name = "cleanfontname", + actions = { names.cleanname, context }, + arguments = "string" +} + +implement { + name = "fontlookupinitialize", + actions = names.lookup, + arguments = "string", +} + +implement { + name = "fontlookupnoffound", + actions = { names.noflookups, context }, +} + +implement { + name = "fontlookupgetkeyofindex", + actions = { names.getlookupkey, context }, + arguments = { "string", "integer"} +} + +implement { + name = "fontlookupgetkey", + actions = { names.getlookupkey, context }, + arguments = "string" +} + +-- this might move to a runtime module: + +function commands.showchardata(n) + local tfmdata = fontdata[currentfont()] + if tfmdata then + if type(n) == "string" then + n = utfbyte(n) + end + local chr = tfmdata.characters[n] + if chr then + report_status("%s @ %s => %U => %c => %s",tfmdata.properties.fullname,tfmdata.parameters.size,n,n,serialize(chr,false)) + end end end + +function commands.showfontparameters(tfmdata) + -- this will become more clever + local tfmdata = tfmdata or fontdata[currentfont()] + if tfmdata then + local parameters = tfmdata.parameters + local mathparameters = tfmdata.mathparameters + local properties = tfmdata.properties + local hasparameters = parameters and next(parameters) + local hasmathparameters = mathparameters and next(mathparameters) + if hasparameters then + report_status("%s @ %s => text parameters => %s",properties.fullname,parameters.size,serialize(parameters,false)) + end + if hasmathparameters then + report_status("%s @ %s => math parameters => %s",properties.fullname,parameters.size,serialize(mathparameters,false)) + end + if not hasparameters and not hasmathparameters then + report_status("%s @ %s => no text parameters and/or math parameters",properties.fullname,parameters.size) + end + end +end + +implement { + name = "currentdesignsize", + actions = function() + context(parameters[currentfont()].designsize) + end +} + +implement { + name = "doifelsefontpresent", + actions = { names.exists, commands.doifelse }, + arguments = "string" +} diff --git a/Master/texmf-dist/tex/context/base/font-def.lua b/Master/texmf-dist/tex/context/base/font-def.lua index e5c5d990ce2..fdded3c369c 100644 --- a/Master/texmf-dist/tex/context/base/font-def.lua +++ b/Master/texmf-dist/tex/context/base/font-def.lua @@ -433,8 +433,8 @@ function definers.read(specification,size,id) -- id can be optional, name can al elseif trace_defining and type(tfmdata) == "table" then local properties = tfmdata.properties or { } local parameters = tfmdata.parameters or { } - report_defining("using %s font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a", - properties.format, id, properties.name, parameters.size, properties.encodingbytes, + report_defining("using %a font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a", + properties.format or "unknown", id, properties.name, parameters.size, properties.encodingbytes, properties.encodingname, properties.fullname, file.basename(properties.filename)) end statistics.stoptiming(fonts) diff --git a/Master/texmf-dist/tex/context/base/font-enc.lua b/Master/texmf-dist/tex/context/base/font-enc.lua index 5305f0736a6..2e8b722de39 100644 --- a/Master/texmf-dist/tex/context/base/font-enc.lua +++ b/Master/texmf-dist/tex/context/base/font-enc.lua @@ -8,6 +8,7 @@ if not modules then modules = { } end modules ['font-enc'] = { -- this module is obsolete +local next = next local match, gmatch, gsub = string.match, string.gmatch, string.gsub local setmetatableindex = table.setmetatableindex @@ -125,7 +126,12 @@ function encodings.make_unicode_vector() end end for name, code in next, characters.synonyms do - vector[code], hash[name] = name, code + if not vector[code] then + vector[code] = name + end + if not hash[name] then + hash[name] = code + end end return containers.write(encodings.cache, 'unicode', { name='unicode', tag='unicode', vector=vector, hash=hash }) end diff --git a/Master/texmf-dist/tex/context/base/font-enh.lua b/Master/texmf-dist/tex/context/base/font-enh.lua index 2bf0741f535..3439a434ab4 100644 --- a/Master/texmf-dist/tex/context/base/font-enh.lua +++ b/Master/texmf-dist/tex/context/base/font-enh.lua @@ -114,24 +114,24 @@ local registerotffeature = otffeatures.register -- unicodes = { -- a1 = 0x2701, -local tosixteen = fonts.mappings.tounicode16 +----- tosixteen = fonts.mappings.tounicode16 local function initializeunicoding(tfmdata) local goodies = tfmdata.goodies local newcoding = nil - local tounicode = false + -- local tounicode = false for i=1,#goodies do local remapping = goodies[i].remapping if remapping and remapping.unicodes then - newcoding = remapping.unicodes -- names to unicodes - tounicode = remapping.tounicode + newcoding = remapping.unicodes -- names to unicodes + -- tounicode = remapping.tounicode -- not used end end if newcoding then local characters = tfmdata.characters local descriptions = tfmdata.descriptions local oldcoding = tfmdata.resources.unicodes - local tounicodes = tfmdata.resources.tounicode -- index to unicode + -- local tounicodes = tfmdata.resources.tounicode -- index to unicode local originals = { } for name, newcode in next, newcoding do local oldcode = oldcoding[name] @@ -153,15 +153,15 @@ local function initializeunicoding(tfmdata) else oldcoding[name] = newcode end - if tounicode then - local description = descriptions[newcode] - if description then - local index = description.index - if not tounicodes[index] then - tounicodes[index] = tosixteen(newcode) -- shared (we could have a metatable) - end - end - end + -- if tounicode then + -- local description = descriptions[newcode] + -- if description then + -- local index = description.index + -- if not tounicodes[index] then + -- tounicodes[index] = tosixteen(newcode) -- shared (we could have a metatable) + -- end + -- end + -- end if trace_unicoding then if oldcode then report_unicoding("aliasing glyph %a from %U to %U",name,oldcode,newcode) diff --git a/Master/texmf-dist/tex/context/base/font-ext.lua b/Master/texmf-dist/tex/context/base/font-ext.lua index ede2151d6b5..b7817c140b0 100644 --- a/Master/texmf-dist/tex/context/base/font-ext.lua +++ b/Master/texmf-dist/tex/context/base/font-ext.lua @@ -7,19 +7,17 @@ if not modules then modules = { } end modules ['font-ext'] = { } local next, type, byte = next, type, string.byte -local gmatch, concat, format = string.gmatch, table.concat, string.format -local utfchar = utf.char -local commands, context = commands, context -local fonts, utilities = fonts, utilities +local context = context +local fonts = fonts +local utilities = utilities -local trace_protrusion = false trackers.register("fonts.protrusion", function(v) trace_protrusion = v end) -local trace_expansion = false trackers.register("fonts.expansion", function(v) trace_expansion = v end) +local trace_protrusion = false trackers.register("fonts.protrusion", function(v) trace_protrusion = v end) +local trace_expansion = false trackers.register("fonts.expansion", function(v) trace_expansion = v end) local report_expansions = logs.reporter("fonts","expansions") local report_protrusions = logs.reporter("fonts","protrusions") - --- todo: byte(..) => 0xHHHH +local report_opbd = logs.reporter("fonts","otf opbd") --[[ldx--When we implement functions that deal with features, most of them @@ -42,6 +40,8 @@ local getparameters = utilities.parsers.getparameters local setmetatableindex = table.setmetatableindex +local implement = interfaces.implement + -- -- -- -- -- -- -- shared -- -- -- -- -- -- @@ -79,10 +79,6 @@ expansions.vectors = vectors classes.preset = { stretch = 2, shrink = 2, step = .5, factor = 1 } -function commands.setupfontexpansion(class,settings) - getparameters(classes,class,'preset',settings) -end - classes['quality'] = { stretch = 2, shrink = 2, step = .5, vector = 'default', factor = 1 } @@ -172,7 +168,11 @@ registerafmfeature { fonts.goodies.register("expansions", function(...) return fonts.goodies.report("expansions", trace_expansion, ...) end) -local report_opbd = logs.reporter("fonts","otf opbd") +implement { + name = "setupfontexpansion", + arguments = { "string", "string" }, + actions = function(class,settings) getparameters(classes,class,'preset',settings) end +} -- -- -- -- -- -- -- protrusion @@ -191,10 +191,6 @@ local vectors = protrusions.vectors classes.preset = { factor = 1, left = 1, right = 1 } -function commands.setupfontprotrusion(class,settings) - getparameters(classes,class,'preset',settings) -end - classes['pure'] = { vector = 'pure', factor = 1 } @@ -328,8 +324,10 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd) local characters = tfmdata.characters local descriptions = tfmdata.descriptions local properties = tfmdata.properties + local resources = tfmdata.resources local rawdata = tfmdata.shared.rawdata local lookuphash = rawdata.lookuphash + local lookuptags = resources.lookuptags local script = properties.script local language = properties.language local done, factor, left, right = false, 1, 1, 1 @@ -349,14 +347,14 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd) local data = lookuphash[lookup] if data then if trace_protrusion then - report_protrusions("setting left using lfbd lookup %a",lookup) + report_protrusions("setting left using lfbd lookup %a",lookuptags[lookup]) end for k, v in next, data do -- local p = - v[3] / descriptions[k].width-- or 1 ~= 0 too but the same local p = - (v[1] / 1000) * factor * left characters[k].left_protruding = p if trace_protrusion then - report_protrusions("lfbd -> %s -> %C -> %0.03f (% t)",lookup,k,p,v) + report_protrusions("lfbd -> %s -> %C -> %0.03f (% t)",lookuptags[lookup],k,p,v) end end done = true @@ -372,14 +370,14 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd) local data = lookuphash[lookup] if data then if trace_protrusion then - report_protrusions("setting right using rtbd lookup %a",lookup) + report_protrusions("setting right using rtbd lookup %a",lookuptags[lookup]) end for k, v in next, data do -- local p = v[3] / descriptions[k].width -- or 3 local p = (v[1] / 1000) * factor * right characters[k].right_protruding = p if trace_protrusion then - report_protrusions("rtbd -> %s -> %C -> %0.03f (% t)",lookup,k,p,v) + report_protrusions("rtbd -> %s -> %C -> %0.03f (% t)",lookuptags[lookup],k,p,v) end end end @@ -487,6 +485,12 @@ registerafmfeature { fonts.goodies.register("protrusions", function(...) return fonts.goodies.report("protrusions", trace_protrusion, ...) end) +implement { + name = "setupfontprotrusion", + arguments = { "string", "string" }, + actions = function(class,settings) getparameters(classes,class,'preset',settings) end +} + -- -- -- local function initializenostackmath(tfmdata,value) @@ -502,6 +506,19 @@ registerotffeature { } } +local function initializerealdimensions(tfmdata,value) + tfmdata.properties.realdimensions = value and true +end + +registerotffeature { + name = "realdimensions", + description = "accept negative dimenions", + initializers = { + base = initializerealdimensions, + node = initializerealdimensions, + } +} + local function initializeitlc(tfmdata,value) -- hm, always value if value then -- the magic 40 and it formula come from Dohyun Kim but we might need another guess @@ -887,11 +904,17 @@ registerotffeature { -- a handy helper (might change or be moved to another namespace) -local new_special = nodes.pool.special -local new_glyph = nodes.pool.glyph +local nodepool = nodes.pool + +local new_special = nodepool.special +local new_glyph = nodepool.glyph +local new_rule = nodepool.rule local hpack_node = node.hpack -function fonts.helpers.addprivate(tfmdata,name,characterdata) +local helpers = fonts.helpers +local currentfont = font.current + +function helpers.addprivate(tfmdata,name,characterdata) local properties = tfmdata.properties local privates = properties.privates local lastprivate = properties.lastprivate @@ -915,19 +938,19 @@ function fonts.helpers.addprivate(tfmdata,name,characterdata) return lastprivate end -function fonts.helpers.getprivatenode(tfmdata,name) +local function getprivatenode(tfmdata,name) local properties = tfmdata.properties local privates = properties and properties.privates if privates then local p = privates[name] if p then - local char = tfmdata.characters[p] + local char = tfmdata.characters[p] local commands = char.commands if commands then - local fake = hpack_node(new_special(commands[1][2])) - fake.width = char.width + local fake = hpack_node(new_special(commands[1][2])) + fake.width = char.width fake.height = char.height - fake.depth = char.depth + fake.depth = char.depth return fake else -- todo: set current attribibutes @@ -937,12 +960,18 @@ function fonts.helpers.getprivatenode(tfmdata,name) end end -function fonts.helpers.hasprivate(tfmdata,name) +helpers.getprivatenode = getprivatenode + +function helpers.hasprivate(tfmdata,name) local properties = tfmdata.properties local privates = properties and properties.privates return privates and privates[name] or false end -function commands.getprivatechar(name) - context(fonts.helpers.getprivatenode(fontdata[font.current()],name)) -end +implement { + name = "getprivatechar", + arguments = "string", + actions = function(name) + context(getprivatenode(fontdata[currentfont()],name)) + end +} diff --git a/Master/texmf-dist/tex/context/base/font-fbk.lua b/Master/texmf-dist/tex/context/base/font-fbk.lua index 48e2167e656..22644f04674 100644 --- a/Master/texmf-dist/tex/context/base/font-fbk.lua +++ b/Master/texmf-dist/tex/context/base/font-fbk.lua @@ -19,18 +19,20 @@ local trace_combining_define = false trackers.register("fonts.composing.defi trackers.register("fonts.combining", "fonts.composing.define") -- for old times sake (and manuals) trackers.register("fonts.combining.all", "fonts.composing.*") -- for old times sake (and manuals) -local report_combining = logs.reporter("fonts","combining") +local report_combining = logs.reporter("fonts","combining") -local force_combining = false -- just for demo purposes (see mk) +local force_combining = false -- just for demo purposes (see mk) -local allocate = utilities.storage.allocate +local allocate = utilities.storage.allocate local fonts = fonts local handlers = fonts.handlers local constructors = fonts.constructors -local registerotffeature = handlers.otf.features.register -local registerafmfeature = handlers.afm.features.register +local otf = handlers.otf +local afm = handlers.afm +local registerotffeature = otf.features.register +local registerafmfeature = afm.features.register local unicodecharacters = characters.data local unicodefallbacks = characters.fallbacks @@ -302,3 +304,32 @@ end -- {'special', 'pdf: /Fm\XX\space Do'}, -- {'special', 'pdf: Q'}, -- {'special', 'pdf: Q'}, + +-- new and experimental + +local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } } +local noflags = { } + +local char_specification = { + type = "ligature", + features = everywhere, + data = characters.splits.char, + order = { "char-ligatures" }, + flags = noflags, + prepend = true, +} + +local compat_specification = { + type = "ligature", + features = everywhere, + data = characters.splits.compat, + order = { "compat-ligatures" }, + flags = noflags, + prepend = true, +} + +otf.addfeature("char-ligatures", char_specification) -- xlig (extra) +otf.addfeature("compat-ligatures",compat_specification) -- plig (pseudo) + +registerotffeature { name = 'char-ligatures', description = 'unicode char specials to ligatures' } +registerotffeature { name = 'compat-ligatures', description = 'unicode compat specials to ligatures' } diff --git a/Master/texmf-dist/tex/context/base/font-fea.mkvi b/Master/texmf-dist/tex/context/base/font-fea.mkvi index 35a9a642a1b..5f6f1b5d5ad 100644 --- a/Master/texmf-dist/tex/context/base/font-fea.mkvi +++ b/Master/texmf-dist/tex/context/base/font-fea.mkvi @@ -123,13 +123,13 @@ {\dotripleargument\font_basics_define_font_feature} \def\font_basics_define_font_feature[#featureset][#parent][#settings]% - {\ctxcommand{definefontfeature("#featureset","#parent","#settings")}} + {\clf_definefontfeature{#featureset}{#parent}{#settings}} \unexpanded\def\fontfeatureslist {\dodoubleargument\font_basics_features_list} \def\font_basics_features_list[#name][#separator]% todo: arg voor type - {\cldcommand{featurelist("#name","otf","\luaescapestring{#separator}","yes","no",true,{"number"})}} + {\clf_featurelist{#name}{\detokenize{#separator}}} \attribute\zerocount\zerocount % first in list, so fast match @@ -143,11 +143,11 @@ % hashing at this end is slower -\unexpanded\def\addfeature {\doifnextoptionalcselse\font_feature_add_yes \font_feature_add_nop } -\unexpanded\def\subtractfeature {\doifnextoptionalcselse\font_feature_subtract_yes \font_feature_subtract_nop } -\unexpanded\def\replacefeature {\doifnextoptionalcselse\font_feature_replace_yes \font_feature_replace_nop } -\unexpanded\def\resetandaddfeature{\doifnextoptionalcselse\font_feature_reset_add_yes\font_feature_reset_add_nop} -\unexpanded\def\feature {\doifnextoptionalcselse\font_feature_yes \font_feature_nop } +\unexpanded\def\addfeature {\doifelsenextoptionalcs\font_feature_add_yes \font_feature_add_nop } +\unexpanded\def\subtractfeature {\doifelsenextoptionalcs\font_feature_subtract_yes \font_feature_subtract_nop } +\unexpanded\def\replacefeature {\doifelsenextoptionalcs\font_feature_replace_yes \font_feature_replace_nop } +\unexpanded\def\resetandaddfeature{\doifelsenextoptionalcs\font_feature_reset_add_yes\font_feature_reset_add_nop} +\unexpanded\def\feature {\doifelsenextoptionalcs\font_feature_yes \font_feature_nop } \unexpanded\def\font_feature_add_yes [#feature]{\edef\m_font_feature_asked{#feature}\font_feature_add} \unexpanded\def\font_feature_add_nop #feature{\edef\m_font_feature_asked{#feature}\font_feature_add} @@ -176,7 +176,7 @@ \fi} \unexpanded\def\font_feature_add_indeed - {\ctxcommand{feature("+","\m_font_feature_list","\m_font_feature_asked")}% + {\clf_addfeature{\m_font_feature_list}{\m_font_feature_asked}% \edef\m_font_feature_list{\m_font_feature_list+\m_font_feature_asked}% also + at the lua end \c_font_feature_state\plusone \let\currentfeature\m_font_feature_asked} @@ -191,7 +191,7 @@ \fi} \unexpanded\def\font_feature_subtract_indeed - {\ctxcommand{feature("-","\m_font_feature_list","\m_font_feature_asked")}% + {\clf_subtractfeature{\m_font_feature_list}{\m_font_feature_asked}% \edef\m_font_feature_list{\m_font_feature_list-\m_font_feature_asked}% also - at the lua end \c_font_feature_state\minusone \let\currentfeature\m_font_feature_asked} @@ -206,7 +206,7 @@ \fi} \unexpanded\def\font_feature_replace_indeed - {\ctxcommand{feature("=","\m_font_feature_list","\m_font_feature_asked")}% + {\clf_replacefeature{\m_font_feature_list}{\m_font_feature_asked}% \edef\m_font_feature_list{\m_font_feature_list=\m_font_feature_asked}% also = at the lua end \c_font_feature_state\zerocount \let\currentfeature\m_font_feature_asked} @@ -220,7 +220,7 @@ {\let\m_font_feature_asked\empty \let\currentfeature \s!current \let\m_font_feature_list \s!current - \ctxcommand{feature(false)}} + \clf_resetfeature} \unexpanded\def\revivefeature {\ifx\currentfeature\s!current \else @@ -228,7 +228,7 @@ \fi} \unexpanded\def\font_feature_revive_indeed - {\ctxcommand{feature(true,"\m_font_feature_list")}} + {\clf_revivefeature{\m_font_feature_list}} \unexpanded\def\font_feature_reset_add {\ifnum\c_font_feature_state=\plusone @@ -240,7 +240,7 @@ \fi} \unexpanded\def\font_feature_reset_add_indeed - {\ctxcommand{feature("+","\s!current","\m_font_feature_asked")}% + {\clf_addfeature{\s!current}{\m_font_feature_asked}% \edef\m_font_feature_list{\s!current+\m_font_feature_asked}% also + at the lua end \c_font_feature_state\plusone \let\currentfeature\m_font_feature_asked} @@ -284,12 +284,12 @@ % just for old times sake: \unexpanded\def\featureattribute#feature% - {\ctxcommand{featureattribute("#feature")}} + {\clf_featureattribute{#feature}} \unexpanded\def\setfontfeature#feature% {\edef\currentfeature{#feature}% \let\m_font_feature_list\currentfeature - \ctxcommand{setfontfeature("\currentfeature")}} + \clf_setfontfeature{\currentfeature}} \let\resetfontfeature\resetfeature @@ -324,11 +324,13 @@ % \doifelsecurrentfonthasfeature{kern}{YES}{NO} \def\doifelsecurrentfonthasfeature#feature% - {\ctxcommand{doifelsecurrentfonthasfeature("#feature")}} + {\clf_doifelsecurrentfonthasfeature{#feature}} + +\let\doifcurrentfonthasfeatureelse\doifelsecurrentfonthasfeature % new: -\ctxcommand{registerlanguagefeatures()} +\clf_registerlanguagefeatures % also new diff --git a/Master/texmf-dist/tex/context/base/font-fil.mkvi b/Master/texmf-dist/tex/context/base/font-fil.mkvi index 158bcda713d..1a20d1cd84a 100644 --- a/Master/texmf-dist/tex/context/base/font-fil.mkvi +++ b/Master/texmf-dist/tex/context/base/font-fil.mkvi @@ -89,11 +89,11 @@ \def\font_basics_define_font_synonym_nop {\expandafter\let\csname\??fontfile\m_font_name\endcsname\m_font_file - \doifnextoptionalcselse\font_basics_define_font_synonym_nop_opt\font_basics_define_font_synonym_nop_nil} + \doifelsenextoptionalcs\font_basics_define_font_synonym_nop_opt\font_basics_define_font_synonym_nop_nil} \def\font_basics_define_font_synonym_yes {\expandafter\let\csname\??fontfile\fontclass\m_font_name\endcsname\m_font_file - \doifnextoptionalcselse\font_basics_define_font_synonym_yes_opt\font_basics_define_font_synonym_yes_nil} + \doifelsenextoptionalcs\font_basics_define_font_synonym_yes_opt\font_basics_define_font_synonym_yes_nil} \def\font_basics_define_font_synonym_nop_opt[#specification]% {\let\p_features \undefined @@ -241,6 +241,8 @@ \doubleexpandafter\secondoftwoarguments \fi\fi} +\let\doiffontsynonymelse\doifelsefontsynonym + %D \macros %D {tracedfontname} %D @@ -290,75 +292,75 @@ % resolve \def\font_helpers_set_features_yes#name% - {\ifcsname\??fontfile\fontclass#name\s!features \endcsname\expandafter\let\expandafter\m_font_features % class + symbolic_name - \csname\??fontfile\fontclass#name\s!features \endcsname\else - \ifcsname\??fontfile #name\s!features \endcsname\expandafter\let\expandafter\m_font_features % symbolic_name - \csname\??fontfile #name\s!features \endcsname\else + {\ifcsname\??fontfile\fontclass#name\s!features \endcsname \edef\m_font_features % class + symbolic_name + {\csname\??fontfile\fontclass#name\s!features \endcsname}\else + \ifcsname\??fontfile #name\s!features \endcsname \edef\m_font_features % symbolic_name + {\csname\??fontfile #name\s!features \endcsname}\else \ifcsname\??fontfile\fontclass #name\endcsname\expandafter\font_helpers_set_features_yes % class + parent_name - \csname\??fontfile\fontclass #name\endcsname\else - \ifcsname\??fontfile #name\endcsname\expandafter\font_helpers_set_features_yes % parent_name - \csname\??fontfile #name\endcsname\else + \csname\??fontfile\fontclass #name\endcsname \else + \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_features_yes % parent_name + \csname\??fontfile #name\endcsname \else \let\m_font_features\empty\fi\fi\fi\fi} \def\font_helpers_set_fallbacks_yes#name% - {\ifcsname\??fontfile\fontclass#name\s!fallbacks\endcsname\expandafter\let\expandafter\m_font_fallbacks - \csname\??fontfile\fontclass#name\s!fallbacks\endcsname\else - \ifcsname\??fontfile #name\s!fallbacks\endcsname\expandafter\let\expandafter\m_font_fallbacks - \csname\??fontfile #name\s!fallbacks\endcsname\else - \ifcsname\??fontfile\fontclass #name\endcsname\expandafter\font_helpers_set_fallbacks_yes - \csname\??fontfile\fontclass #name\endcsname\else - \ifcsname\??fontfile #name\endcsname\expandafter\font_helpers_set_fallbacks_yes - \csname\??fontfile #name\endcsname\else + {\ifcsname\??fontfile\fontclass#name\s!fallbacks\endcsname \edef\m_font_fallbacks + {\csname\??fontfile\fontclass#name\s!fallbacks\endcsname}\else + \ifcsname\??fontfile #name\s!fallbacks\endcsname \edef\m_font_fallbacks + {\csname\??fontfile #name\s!fallbacks\endcsname}\else + \ifcsname\??fontfile\fontclass #name\endcsname \expandafter\font_helpers_set_fallbacks_yes + \csname\??fontfile\fontclass #name\endcsname \else + \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_fallbacks_yes + \csname\??fontfile #name\endcsname \else \let\m_font_fallbacks\empty\fi\fi\fi\fi} \def\font_helpers_set_goodies_yes#name% - {\ifcsname\??fontfile\fontclass#name\s!goodies \endcsname\expandafter\let\expandafter\m_font_goodies - \csname\??fontfile\fontclass#name\s!goodies \endcsname\else - \ifcsname\??fontfile #name\s!goodies \endcsname\expandafter\let\expandafter\m_font_goodies - \csname\??fontfile #name\s!goodies \endcsname\else - \ifcsname\??fontfile\fontclass #name\endcsname\expandafter\font_helpers_set_goodies_yes - \csname\??fontfile\fontclass #name\endcsname\else - \ifcsname\??fontfile #name\endcsname\expandafter\font_helpers_set_goodies_yes - \csname\??fontfile #name\endcsname\else + {\ifcsname\??fontfile\fontclass#name\s!goodies \endcsname \edef\m_font_goodies + {\csname\??fontfile\fontclass#name\s!goodies \endcsname}\else + \ifcsname\??fontfile #name\s!goodies \endcsname \edef\m_font_goodies + {\csname\??fontfile #name\s!goodies \endcsname}\else + \ifcsname\??fontfile\fontclass #name\endcsname \expandafter\font_helpers_set_goodies_yes + \csname\??fontfile\fontclass #name\endcsname \else + \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_goodies_yes + \csname\??fontfile #name\endcsname \else \let\m_font_goodies\empty\fi\fi\fi\fi} \def\font_helpers_set_designsize_yes#name% - {\ifcsname\??fontfile\fontclass#name\s!designsize\endcsname\expandafter\let\expandafter\m_font_designsize - \csname\??fontfile\fontclass#name\s!designsize\endcsname\else - \ifcsname\??fontfile #name\s!designsize\endcsname\expandafter\let\expandafter\m_font_designsize - \csname\??fontfile #name\s!designsize\endcsname\else - \ifcsname\??fontfile\fontclass #name\endcsname\expandafter\font_helpers_set_designsize_yes - \csname\??fontfile\fontclass #name\endcsname\else - \ifcsname\??fontfile #name\endcsname\expandafter\font_helpers_set_designsize_yes - \csname\??fontfile #name\endcsname\else + {\ifcsname\??fontfile\fontclass#name\s!designsize\endcsname \edef\m_font_designsize + {\csname\??fontfile\fontclass#name\s!designsize\endcsname}\else + \ifcsname\??fontfile #name\s!designsize\endcsname \edef\m_font_designsize + {\csname\??fontfile #name\s!designsize\endcsname}\else + \ifcsname\??fontfile\fontclass #name\endcsname \expandafter\font_helpers_set_designsize_yes + \csname\??fontfile\fontclass #name\endcsname \else + \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_designsize_yes + \csname\??fontfile #name\endcsname \else \let\m_font_designsize\empty\fi\fi\fi\fi} \def\font_helpers_set_features_nop#name% - {\ifcsname\??fontfile#name\s!features \endcsname\expandafter\let\expandafter\m_font_features - \csname\??fontfile#name\s!features \endcsname\else - \ifcsname\??fontfile #name\endcsname\expandafter\font_helpers_set_features_nop - \csname\??fontfile #name\endcsname\else + {\ifcsname\??fontfile#name\s!features \endcsname \edef\m_font_features + {\csname\??fontfile#name\s!features \endcsname}\else + \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_features_nop + \csname\??fontfile #name\endcsname \else \let\m_font_features\empty\fi\fi} \def\font_helpers_set_fallbacks_nop#name% - {\ifcsname\??fontfile#name\s!fallbacks\endcsname\expandafter\let\expandafter\m_font_fallbacks - \csname\??fontfile#name\s!fallbacks\endcsname\else - \ifcsname\??fontfile #name\endcsname\expandafter\font_helpers_set_fallbacks_nop - \csname\??fontfile #name\endcsname\else + {\ifcsname\??fontfile#name\s!fallbacks\endcsname \edef\m_font_fallbacks + {\csname\??fontfile#name\s!fallbacks\endcsname}\else + \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_fallbacks_nop + \csname\??fontfile #name\endcsname \else \let\m_font_fallbacks\empty\fi\fi} \def\font_helpers_set_goodies_nop#name% - {\ifcsname\??fontfile#name\s!goodies \endcsname\expandafter\let\expandafter\m_font_goodies - \csname\??fontfile#name\s!goodies \endcsname\else - \ifcsname\??fontfile #name\endcsname\expandafter\font_helpers_set_goodies_nop - \csname\??fontfile #name\endcsname\else + {\ifcsname\??fontfile#name\s!goodies \endcsname \edef\m_font_goodies + {\csname\??fontfile#name\s!goodies \endcsname}\else + \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_goodies_nop + \csname\??fontfile #name\endcsname \else \let\m_font_goodies\empty\fi\fi} \def\font_helpers_set_designsize_nop#name% - {\ifcsname\??fontfile#name\s!designsize\endcsname\expandafter\let\expandafter\m_font_designsize - \csname\??fontfile#name\s!designsize\endcsname\else - \ifcsname\??fontfile #name\endcsname\expandafter\font_helpers_set_designsize_nop - \csname\??fontfile #name\endcsname\else + {\ifcsname\??fontfile#name\s!designsize\endcsname \edef\m_font_designsize + {\csname\??fontfile#name\s!designsize\endcsname}\else + \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_designsize_nop + \csname\??fontfile #name\endcsname \else \let\m_font_designsize\empty\fi\fi} \def\font_helpers_update_font_parameters_yes diff --git a/Master/texmf-dist/tex/context/base/font-gds.lua b/Master/texmf-dist/tex/context/base/font-gds.lua index 9e7cb841e3f..073d9ed57d1 100644 --- a/Master/texmf-dist/tex/context/base/font-gds.lua +++ b/Master/texmf-dist/tex/context/base/font-gds.lua @@ -9,10 +9,12 @@ if not modules then modules = { } end modules ['font-gds'] = { -- depends on ctx local type, next, tonumber = type, next, tonumber -local gmatch, format, lower, find, splitup = string.gmatch, string.format, string.lower, string.find, string.splitup -local texsp = tex.sp +local gmatch, lower, find, splitup = string.gmatch, string.lower, string.find, string.splitup -local fonts, nodes, attributes, node = fonts, nodes, attributes, node +local fonts = fonts +local nodes = nodes +local attributes = attributes +local node = node local trace_goodies = false trackers.register("fonts.goodies", function(v) trace_goodies = v end) local report_goodies = logs.reporter("fonts","goodies") @@ -20,6 +22,11 @@ local report_goodies = logs.reporter("fonts","goodies") local allocate = utilities.storage.allocate local setmetatableindex = table.setmetatableindex +local implement = interfaces.implement + +local texsp = tex.sp +local formatters = string.formatters + local otf = fonts.handlers.otf local afm = fonts.handlers.afm local tfm = fonts.handlers.tfm @@ -429,7 +436,7 @@ local function setextrafeatures(tfmdata) addotffeature(tfmdata.shared.rawdata,feature,specification) registerotffeature { name = feature, - description = format("extra: %s",feature) + description = formatters["extra: %s"](feature) } end end @@ -819,8 +826,17 @@ end -- interface -commands.loadfontgoodies = fontgoodies.load -commands.enablefontcolorschemes = colorschemes.enable +implement { + name = "loadfontgoodies", + actions = fontgoodies.load, + arguments = "string" +} + +implement { + name = "enablefontcolorschemes", + onlyonce = true, + actions = colorschemes.enable +} -- weird place ... depends on math @@ -853,7 +869,7 @@ local function setkeepligatures(tfmdata,value) if letterspacing then local keptligatures = letterspacing.keptligatures if keptligatures then - local unicodes = tfmdata.resources.unicodes + local unicodes = tfmdata.resources.unicodes -- so we accept names local hash = { } for k, v in next, keptligatures do local u = unicodes[k] diff --git a/Master/texmf-dist/tex/context/base/font-gds.mkvi b/Master/texmf-dist/tex/context/base/font-gds.mkvi index 6d979842872..e9c34e807af 100644 --- a/Master/texmf-dist/tex/context/base/font-gds.mkvi +++ b/Master/texmf-dist/tex/context/base/font-gds.mkvi @@ -46,10 +46,10 @@ \definesystemattribute[colorscheme][public] \unexpanded\def\loadfontgoodies[#filename]% - {\ctxcommand{loadfontgoodies("#filename")}} + {\clf_loadfontgoodies{#filename}} \unexpanded\def\setfontcolorscheme % will move to the lua end - {\ctxcommand{enablefontcolorschemes()}% + {\clf_enablefontcolorschemes \unexpanded\xdef\setfontcolorscheme[##1]{\attribute\colorschemeattribute##1\relax}% \setfontcolorscheme} diff --git a/Master/texmf-dist/tex/context/base/font-hsh.lua b/Master/texmf-dist/tex/context/base/font-hsh.lua index 1b0dd08b83c..07acf2138c7 100644 --- a/Master/texmf-dist/tex/context/base/font-hsh.lua +++ b/Master/texmf-dist/tex/context/base/font-hsh.lua @@ -35,6 +35,8 @@ local italics = hashes.italics or allocate() local lastmathids = hashes.lastmathids or allocate() local dynamics = hashes.dynamics or allocate() local unicodes = hashes.unicodes or allocate() +local originals = hashes.originals or allocate() +local modes = hashes.modes or allocate() hashes.characters = characters hashes.descriptions = descriptions @@ -52,6 +54,8 @@ hashes.italics = italics hashes.lastmathids = lastmathids hashes.dynamics = dynamics hashes.unicodes = unicodes +hashes.originals = originals +hashes.modes = modes local nodepool = nodes.pool local dummyglyph = nodepool.register(nodepool.glyph()) @@ -261,21 +265,41 @@ setmetatableindex(dynamics, function(t,k) end end) -setmetatableindex(unicodes, function(t,k) +setmetatableindex(unicodes, function(t,k) -- always a unicode + if k == true then + return unicodes[currentfont()] + else + local resources = resources[k] + local unicodes = resources and resources.unicodes or { } + t[k] = unicodes + return unicodes + end +end) + +setmetatableindex(originals, function(t,k) -- always a unicode if k == true then return originals[currentfont()] else - local resources = resources[k] - local originals = resources and resources.originals or { } - local characters = characters[k] - local unicodes = { } - setmetatableindex(unicodes,function(t,k) - local v = originals[characters[k].index] or k - t[k] = v + local resolved = { } + setmetatableindex(resolved,function(t,name) + local u = unicodes[k][name] + local d = u and descriptions[k][u] + local v = d and d.unicode or u or 0 -- so we return notdef (at least for the moment) + t[name] = u return v end) - t[k] = unicodes - return unicodes + t[k] = resolved + return resolved + end +end) + +setmetatableindex(modes, function(t,k) + if k == true then + return modes[currentfont()] + else + local mode = properties[k].mode or "base" + t[k] = mode + return mode end end) diff --git a/Master/texmf-dist/tex/context/base/font-ini.lua b/Master/texmf-dist/tex/context/base/font-ini.lua index 884b22474c2..c547f89acf9 100644 --- a/Master/texmf-dist/tex/context/base/font-ini.lua +++ b/Master/texmf-dist/tex/context/base/font-ini.lua @@ -29,4 +29,4 @@ fonts.readers = { } fonts.definers = { methods = { } } fonts.loggers = { register = function() end } -fontloader.totable = fontloader.to_table +fontloader.totable = fontloader.to_table -- not used diff --git a/Master/texmf-dist/tex/context/base/font-ini.mkvi b/Master/texmf-dist/tex/context/base/font-ini.mkvi index c1e6d939055..c04952a9e89 100644 --- a/Master/texmf-dist/tex/context/base/font-ini.mkvi +++ b/Master/texmf-dist/tex/context/base/font-ini.mkvi @@ -363,7 +363,7 @@ \let\thedefinedfont\relax % not to be confused with \everydefinefont \unexpanded\def\definedfont - {\doifnextoptionalcselse\font_basics_defined_font_yes\font_basics_defined_font_nop} + {\doifelsenextoptionalcs\font_basics_defined_font_yes\font_basics_defined_font_nop} \def\font_basics_defined_font_yes[#specification]% {\c_font_feature_inheritance_mode\c_font_feature_inheritance_fontonly @@ -419,24 +419,39 @@ %D When we assign for instance 12pt to a \DIMENSION\ register the \type %D {\the}'d value comes out as 12.0pt, which is often not the way users %D specify the bodyfont size. Therefore we use normalized values. They -%D are caches to save overhead in \LUA\ calls. +%D are cached to save overhead in \LUA\ calls. -\setnewconstant\fontdigits\plustwo +% \setnewconstant\fontdigits\plustwo % from now on always 2 \installcorenamespace{fontnormalizedbody} +% \def\normalizebodyfontsize#macro#body% +% {\expandafter\let\expandafter#macro\csname\??fontnormalizedbody\number\fontdigits:\number\dimexpr#body\endcsname +% \ifx#macro\relax +% \normalizebodyfontsize_indeed#macro{#body}% +% \fi} +% +% \def\normalizebodyfontsize_indeed#macro#body% +% {\edef#macro{\ctxcommand{nbfs(\number\dimexpr#body,\number\fontdigits)}}% +% \global\expandafter\let\csname\??fontnormalizedbody\number\fontdigits:\number\dimexpr#body\endcsname#macro} +% +% \def\thenormalizedbodyfontsize#body% +% {\ctxcommand{nbfs(\number\dimexpr#body\relax,\number\fontdigits)}} +% +% caching is less relevant now + \def\normalizebodyfontsize#macro#body% - {\expandafter\let\expandafter#macro\csname\??fontnormalizedbody\number\fontdigits:\number\dimexpr#body\endcsname + {\expandafter\let\expandafter#macro\csname\??fontnormalizedbody\number\dimexpr#body\endcsname \ifx#macro\relax \normalizebodyfontsize_indeed#macro{#body}% \fi} \def\normalizebodyfontsize_indeed#macro#body% - {\edef#macro{\ctxcommand{nbfs(\number\dimexpr#body,\number\fontdigits)}}% - \global\expandafter\let\csname\??fontnormalizedbody\number\fontdigits:\number\dimexpr#body\endcsname#macro} + {\edef#macro{\clf_nbfs\dimexpr#body\relax}% + \global\expandafter\let\csname\??fontnormalizedbody\number\dimexpr#body\endcsname#macro} \def\thenormalizedbodyfontsize#body% - {\ctxcommand{nbfs(\number\dimexpr#body\relax,\number\fontdigits)}} + {\clf_nbfs\dimexpr#body\relax} \edef\normalizedglobalbodyfontsize{\thenormalizedbodyfontsize\bodyfontsize} \edef\normalizedlocalbodyfontsize {\thenormalizedbodyfontsize\bodyfontsize} @@ -723,7 +738,9 @@ \unexpanded\def\font_helpers_low_level_define#specification#csname% {% we can now set more at the lua end - \ctxcommand{definefont_one(\!!bs\luaescapestring{#specification}\!!es)}% the escapestring catches at \somedimen + \global\let\somefontname\defaultfontfile + \let\somefontsize\empty + \clf_definefont_one{\detokenize\expandafter{\normalexpanded{#specification}}}% the escapestring catches at \somedimen % sets \scaledfontmode and \somefontname and \somefontsize \ifcase\fontface\relax % \let\v_font_size_absolute\textface % fontbody @@ -774,39 +791,43 @@ \else \d_font_scaled_text_face\textface \fi - \edef\somefontspec{at \number\d_font_scaled_font_size sp}% probably no longer used, needs checking + \edef\somefontspec{at \number\d_font_scaled_font_size sp}% \edef\somefontfile{\truefontname\somefontname}% \ifx\somefontfile\s!unknown \edef\somefontfile{\defaultfontfile}% \fi - \ifx\somefontfile\s!unknown - \edef\somefontfile{\defaultfontfile}% - \fi \font_helpers_update_font_parameters \font_helpers_update_font_class_parameters % \writestatus{fonts}{low level define: #csname/\somefontfile/\number\d_font_scaled_font_size/\fontface/\number\d_font_scaled_text_face}% - \ctxcommand{definefont_two( - \ifx\fontclass\empty false\else true\fi, - "#csname", - \!!bs\somefontfile\!!es, - \number\d_font_scaled_font_size, - \number\c_font_feature_inheritance_mode, - "\m_font_class_features", - "\m_font_features", - "\m_font_class_fallbacks", - "\m_font_fallbacks", - \fontface, % 1/2/3: text script scriptscript 0/4/5: body x xx - \number\d_font_scaled_text_face, - "\number\relativefontid", % experiment - "\m_font_class_goodies", % experiment (not yet used) - "\m_font_goodies", - "\m_font_class_designsize", - "\m_font_designsize", - \number\scaledfontmode - )}% - \edef\somefontspec{at \number\scaledfontsize sp}% we need the resolved designsize (for fallbacks) - \expandafter\let\expandafter\lastrawfontcall\csname#csname\endcsname - \the\everydefinefont + \clf_definefont_two + \ifx\fontclass\empty\s!false\else\s!true\fi + {#csname}% + {\somefontfile}% + \d_font_scaled_font_size + \c_font_feature_inheritance_mode + {\m_font_class_features}% + {\m_font_features}% + {\m_font_class_fallbacks}% + {\m_font_fallbacks}% + \fontface + \d_font_scaled_text_face + \relativefontid + {\m_font_class_goodies}% + {\m_font_goodies}% + {\m_font_class_designsize}% + {\m_font_designsize}% + \scaledfontmode + \relax + \ifcase\scaledfontsize + %\scaledfontsize\plusone + \let\somefontspec\empty + \let\lastrawfontcall\relax + \expandafter\let\csname#csname\endcsname\relax + \else + \edef\somefontspec{at \number\scaledfontsize sp}% we need the resolved designsize (for fallbacks) + \expandafter\let\expandafter\lastrawfontcall\csname#csname\endcsname + \the\everydefinefont + \fi \c_font_feature_inheritance_mode\c_font_feature_inheritance_default} \def\font_helpers_check_body_scale#fontsize% gets character (x xx a etc) @@ -830,10 +851,10 @@ %D The following macros are used at the \LUA\ end. Watch the \type {\normal} %D hackery: this makes the mkvi parser happy. -\normaldef\fntsetdefname {\global\let\somefontname\defaultfontfile} % do before calling -\normaldef\fntsetsomename{\normalgdef\somefontname} % takes argument -\normaldef\fntsetnopsize {\let\somefontsize\empty} % do before calling -\normaldef\fntsetsomesize{\normaldef\somefontsize} % takes argument +% \normaldef\fntsetdefname {\global\let\somefontname\defaultfontfile} % do before calling +% \normaldef\fntsetnopsize {\let\somefontsize\empty} % do before calling +% \normaldef\fntsetsomename{\normalgdef\somefontname} % takes argument +% \normaldef\fntsetsomesize{\normaldef\somefontsize} % takes argument \newif\ifskipfontcharacteristics \skipfontcharacteristicstrue @@ -878,7 +899,7 @@ \fi} \def\font_basics_define_font_a[#name][#specification][#settings]% [name][spec][1.6 | line=10pt | setup_id] - {\doifsetupselse{#settings}% + {\doifelsesetups{#settings}% {\setuvalue{#name}{\font_basics_define_font_with_setups {#name}{#specification}{#settings}}} {\setuvalue{#name}{\font_basics_define_font_with_parameters{#name}{#specification}{#settings}}}} @@ -900,11 +921,19 @@ \unexpanded\def\definefrozenfont {\dotripleempty\font_basics_define_frozen_font} +% \def\font_basics_define_frozen_font[#name][#specification][#settings]% +% {\begingroup +% \font_basics_define_font[#name][#specification][#settings]% +% \csname#name\endcsname +% \expandafter\expandafter\expandafter\endgroup\expandafter\let\csname#name\endcsname\lastrawfontcall} + \def\font_basics_define_frozen_font[#name][#specification][#settings]% {\begingroup \font_basics_define_font[#name][#specification][#settings]% \csname#name\endcsname - \expandafter\endgroup\expandafter\let\csname#name\endcsname\lastrawfontcall} + \global\let\lastglobalrawfontcall\lastrawfontcall + \endgroup + \expandafter\let\csname#name\endcsname\lastglobalrawfontcall} %D The instance namespace protection makes the switch local so that we can redefine a %D logical name and/or change the size in between. @@ -1158,7 +1187,9 @@ \installcorenamespace{fontenvironmentknown} -\let\bodyfontenvironmentlist\empty % used in font-run (might change) +% \let\bodyfontenvironmentlist\empty % used in font-run (might change) + +\newtoks\bodyfontenvironmentlist \def\font_helpers_register_environment#class#body% {\expandafter\let\csname\??fontenvironmentknown#class#body\endcsname\empty} @@ -1179,6 +1210,12 @@ %D a bodyfont is loaded but changing them afterwards can be sort of tricky as %D values are not consulted afterwards. +\def\processbodyfontenvironmentlist#1% no \unexpanded as then we cannot use it in alignments + {\clf_processbodyfontsizes{\strippedcsname#1}} + +\def\bodyfontenvironmentlist + {\clf_getbodyfontsizes} + \def\font_basics_define_body_font_environment_class[#class][#body][#settings]% {\edef\m_font_body{#body}% \ifx\m_font_body\s!default @@ -1187,7 +1224,8 @@ \else \normalizebodyfontsize\m_font_body_normalized\m_font_body \font_basics_define_body_font_environment_size[#class][\m_font_body_normalized][#settings]% - \addtocommalist\m_font_body_normalized\bodyfontenvironmentlist + %\addtocommalist\m_font_body_normalized\bodyfontenvironmentlist + \clf_registerbodyfontsize{\m_font_body_normalized}% \fi} %D The empty case uses the same code but needs to ignore the current class @@ -1367,19 +1405,19 @@ {\font_basics_define_body_font_a[bwhatever][\s!rm][]} \unexpanded\def\font_basics_define_body_font_a[#whatever]% - {\doifnumberelse{#whatever}% + {\doifelsenumber{#whatever}% \font_basics_define_body_font_body \font_basics_define_body_font_name [#whatever]} \unexpanded\def\font_basics_define_body_font_body[#body][#style][#specification]% - {\doifassignmentelse{#specification} + {\doifelseassignment{#specification} \font_basics_define_body_font_body_assignment \font_basics_define_body_font_body_identifier [#body][#style][#specification]}% \unexpanded\def\font_basics_define_body_font_name[#name][#style][#specification]% - {\doifassignmentelse{#specification} + {\doifelseassignment{#specification} \font_basics_define_body_font_name_assignment \font_basics_define_body_font_name_identifier [#name][#style][#specification]}% @@ -1640,13 +1678,13 @@ \fi} \def\font_helpers_set_font_check_size#option% - {\doifnumberelse{#option}{\font_helpers_check_bodyfont_environment{#option}{#option}}\donothing} + {\doifelsenumber{#option}{\font_helpers_check_bodyfont_environment{#option}{#option}}\donothing} \def\font_helpers_set_font_set_font#method#option% method=1: set, method=2: switch {\doifsomething{#option}{\font_helpers_set_font_set_font_option{#method}{#option}}} \def\font_helpers_set_font_set_font_option#method#option% - {\doifnumberelse{#option}% + {\doifelsenumber{#option}% \font_helpers_set_font_set_font_option_body \font_helpers_set_font_set_font_option_keyword {#method}{#option}{#option}} @@ -1988,8 +2026,29 @@ %D takes a bit more time. Keep in mind that the fontsize is %D represented by a character or empty. -\unexpanded\def\tx {\font_helpers_set_current_font_x_alternative \fontalternative} -\unexpanded\def\txx{\font_helpers_set_current_font_xx_alternative\fontalternative} +% \unexpanded\def\tx {\font_helpers_set_current_font_x_alternative \fontalternative} +% \unexpanded\def\txx{\font_helpers_set_current_font_xx_alternative\fontalternative} + +\unexpanded\def\tx + {\ifmmode + \scriptstyle + \else + \let\fontface\!!plusfour + \let\fontalternative\fontalternative + \font_helpers_synchronize_font + \fi + \currentxfontsize\plusone + \let\tx\txx} + +\unexpanded\def\txx + {\ifmmode + \scriptscriptstyle + \else + \let\fontface\!!plusfive + \let\fontalternative\fontalternative + \font_helpers_synchronize_font + \fi + \currentxfontsize\plustwo} \let\normaltx \tx \let\normaltxx\txx @@ -2082,7 +2141,7 @@ % \newtoks \everyswitchtobodyfont \unexpanded\def\setupbodyfont - {\doifnextoptionalcselse\font_basics_setupbodyfont_yes\font_basics_setupbodyfont_nop} + {\doifelsenextoptionalcs\font_basics_setupbodyfont_yes\font_basics_setupbodyfont_nop} \def\font_basics_setupbodyfont_nop {\restoreglobalbodyfont @@ -2114,6 +2173,13 @@ \unexpanded\def\switchtobodyfont[#specification]% could become an ifx {\doifsomething{#specification}{\font_basics_switchtobodyfont{#specification}}} + +\unexpanded\def\usebodyfontparameter#1% + {\edef\m_font_bodyfont_asked{#1\c!bodyfont}% + \ifx\m_font_bodyfont_asked\empty\else + \font_basics_switchtobodyfont\m_font_bodyfont_asked + \fi} + \def\font_helpers_switch_bodyfont_step {\font_basics_switch_points\m_font_step \font_basics_switch_style \fontstyle} @@ -2169,14 +2235,28 @@ %D Handy for manuals: -\unexpanded\def\fontchar#character% - {\ctxcommand{fontchar("#character")}} -%D The next auxilliary macro is an alternative to \type -%D {\fontname}. +%D The \type {\tochar} commmand takes a specification: +%D +%D \starttabulate[|l|l|l|] +%D \NC e \NC entity \NC e:eacute \NC \NR +%D \NC x \NC hexadecimal unicode \NC x:013D \NC \NR +%D \NC d \NC decimal unicode \NC d:123 \NC \NR +%D \NC s \NC hexadecimal index (slot) \NC s:210D \NC \NR +%D \NC i \NC decimal index \NC i:456 \NC \NR +%D \NC n \NC name \NC n:eight \NC \NR +%D \NC c \NC name \NC c:x \NC \NR +%D \stoptabulate +%D +%D This is an expandable command! + +\unexpanded\def\fontchar #character{\clf_fontchar{#character}} +\unexpanded\def\fontcharbyindex #index{\clf_fontcharbyindex#index\relax} + \def\tochar #specifications{\clf_tochar{#specifications}} % expanded (also used in edef) + +%D The next auxilliary macro is an alternative to \type {\fontname}. -\def\purefontname#font{\ctxcommand{purefontname("\fontname#font")}} -%def\purefontname#font{\ctxcommand{purefontname(\number\fontid#font)}} +\def\purefontname#font{\clf_purefontname{\fontname#font}} %D \macros %D {switchstyleonly} @@ -2191,7 +2271,7 @@ %D \stoptyping \unexpanded\def\switchstyleonly - {\doifnextoptionalcselse\font_basics_switch_style_only_opt\font_basics_switch_style_only_arg} + {\doifelsenextoptionalcs\font_basics_switch_style_only_opt\font_basics_switch_style_only_arg} \def\font_basics_switch_style_only_arg#name% stupid version {\font_helpers_set_current_font_style{\csname\??fontshortstyle\checkedstrippedcsname#name\endcsname}% diff --git a/Master/texmf-dist/tex/context/base/font-inj.lua b/Master/texmf-dist/tex/context/base/font-inj.lua new file mode 100644 index 00000000000..cb9ed891cfc --- /dev/null +++ b/Master/texmf-dist/tex/context/base/font-inj.lua @@ -0,0 +1,1052 @@ +if not modules then modules = { } end modules ['font-inj'] = { + version = 1.001, + comment = "companion to font-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", +} + +-- This property based variant is not faster but looks nicer than the attribute one. We +-- need to use rawget (which is apbout 4 times slower than a direct access but we cannot +-- get/set that one for our purpose! + +if not nodes.properties then return end + +local next, rawget = next, rawget +local utfchar = utf.char +local fastcopy = table.fastcopy + +local trace_injections = false trackers.register("fonts.injections", function(v) trace_injections = v end) + +local report_injections = logs.reporter("fonts","injections") + +local attributes, nodes, node = attributes, nodes, node + +fonts = fonts +local fontdata = fonts.hashes.identifiers + +nodes.injections = nodes.injections or { } +local injections = nodes.injections + +local nodecodes = nodes.nodecodes +local glyph_code = nodecodes.glyph +local disc_code = nodecodes.disc +local kern_code = nodecodes.kern + +local nuts = nodes.nuts +local nodepool = nuts.pool + +local newkern = nodepool.kern + +local tonode = nuts.tonode +local tonut = nuts.tonut + +local getfield = nuts.getfield +local setfield = nuts.setfield +local getnext = nuts.getnext +local getprev = nuts.getprev +local getid = nuts.getid +local getfont = nuts.getfont +local getsubtype = nuts.getsubtype +local getchar = nuts.getchar + +local traverse_id = nuts.traverse_id +local insert_node_before = nuts.insert_before +local insert_node_after = nuts.insert_after +local find_tail = nuts.tail + +local properties = nodes.properties.data + +function injections.installnewkern(nk) + newkern = nk or newkern +end + +local nofregisteredkerns = 0 +local nofregisteredpairs = 0 +local nofregisteredmarks = 0 +local nofregisteredcursives = 0 +----- markanchors = { } -- one base can have more marks +local keepregisteredcounts = false + +function injections.keepcounts() + keepregisteredcounts = true +end + +function injections.resetcounts() + nofregisteredkerns = 0 + nofregisteredpairs = 0 + nofregisteredmarks = 0 + nofregisteredcursives = 0 + keepregisteredcounts = false +end + +-- We need to make sure that a possible metatable will not kick in +-- unexpectedly. + +function injections.reset(n) + local p = rawget(properties,n) + if p and rawget(p,"injections") then + p.injections = nil + end +end + +function injections.copy(target,source) + local sp = rawget(properties,source) + if sp then + local tp = rawget(properties,target) + local si = rawget(sp,"injections") + if si then + si = fastcopy(si) + if tp then + tp.injections = si + else + propertydata[target] = { + injections = si, + } + end + else + if tp then + tp.injections = nil + end + end + end +end + +function injections.setligaindex(n,index) + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") + if i then + i.ligaindex = index + else + p.injections = { + ligaindex = index + } + end + else + properties[n] = { + injections = { + ligaindex = index + } + } + end +end + +function injections.getligaindex(n,default) + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") + if i then + return i.ligaindex or default + end + end + return default +end + +function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext) -- hm: nuts or nodes + local dx = factor*(exit[1]-entry[1]) + local dy = -factor*(exit[2]-entry[2]) + local ws, wn = tfmstart.width, tfmnext.width + nofregisteredcursives = nofregisteredcursives + 1 + if rlmode < 0 then + dx = -(dx + wn) + else + dx = dx - ws + end + -- + local p = rawget(properties,start) + if p then + local i = rawget(p,"injections") + if i then + i.cursiveanchor = true + else + p.injections = { + cursiveanchor = true, + } + end + else + properties[start] = { + injections = { + cursiveanchor = true, + }, + } + end + local p = rawget(properties,nxt) + if p then + local i = rawget(p,"injections") + if i then + i.cursivex = dx + i.cursivey = dy + else + p.injections = { + cursivex = dx, + cursivey = dy, + } + end + else + properties[nxt] = { + injections = { + cursivex = dx, + cursivey = dy, + }, + } + end + return dx, dy, nofregisteredcursives +end + +function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2lflag & tfmchr not used + local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4] + if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then -- okay? + local yoffset = y - h + local leftkern = x -- both kerns are set in a pair kern compared + local rightkern = w - x -- to normal kerns where we set only leftkern + if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then + nofregisteredpairs = nofregisteredpairs + 1 + if rlmode and rlmode < 0 then + leftkern, rightkern = rightkern, leftkern + end + local p = rawget(properties,current) + if p then + local i = rawget(p,"injections") + if i then + if leftkern ~= 0 then + i.leftkern = (i.leftkern or 0) + leftkern + end + if rightkern ~= 0 then + i.rightkern = (i.rightkern or 0) + rightkern + end + if yoffset ~= 0 then + i.yoffset = (i.yoffset or 0) + yoffset + end + elseif leftkern ~= 0 or rightkern ~= 0 then + p.injections = { + leftkern = leftkern, + rightkern = rightkern, + yoffset = yoffset, + } + else + p.injections = { + yoffset = yoffset, + } + end + elseif leftkern ~= 0 or rightkern ~= 0 then + properties[current] = { + injections = { + leftkern = leftkern, + rightkern = rightkern, + yoffset = yoffset, + }, + } + else + properties[current] = { + injections = { + yoffset = yoffset, + }, + } + end + return x, y, w, h, nofregisteredpairs + end + end + return x, y, w, h -- no bound +end + +-- this needs checking for rl < 0 but it is unlikely that a r2l script +-- uses kernclasses between glyphs so we're probably safe (KE has a +-- problematic font where marks interfere with rl < 0 in the previous +-- case) + +function injections.setkern(current,factor,rlmode,x,injection) + local dx = factor * x + if dx ~= 0 then + nofregisteredkerns = nofregisteredkerns + 1 + local p = rawget(properties,current) + if not injection then + injection = "injections" + end + if p then + local i = rawget(p,injection) + if i then + i.leftkern = dx + (i.leftkern or 0) + else + p[injection] = { + leftkern = dx, + } + end + else + properties[current] = { + [injection] = { + leftkern = dx, + }, + } + end + return dx, nofregisteredkerns + else + return 0, 0 + end +end + +function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=baseanchor, ma=markanchor + local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2]) + nofregisteredmarks = nofregisteredmarks + 1 + -- markanchors[nofregisteredmarks] = base + if rlmode >= 0 then + dx = tfmbase.width - dx -- see later commented ox + end + local p = rawget(properties,start) + if p then + local i = rawget(p,"injections") + if i then + i.markx = dx + i.marky = dy + i.markdir = rlmode or 0 + i.markbase = nofregisteredmarks + i.markbasenode = base + else + p.injections = { + markx = dx, + marky = dy, + markdir = rlmode or 0, + markbase = nofregisteredmarks, + markbasenode = base, + } + end + else + properties[start] = { + injections = { + markx = dx, + marky = dy, + markdir = rlmode or 0, + markbase = nofregisteredmarks, + markbasenode = base, + }, + } + end + return dx, dy, nofregisteredmarks +end + +local function dir(n) + return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset" +end + +local function showchar(n,nested) + local char = getchar(n) + report_injections("%wfont %s, char %U, glyph %c",nested and 2 or 0,getfont(n),char,char) +end + +local function show(n,what,nested,symbol) + if n then + local p = rawget(properties,n) + if p then + local i = rawget(p,what) + if i then + local leftkern = i.leftkern or 0 + local rightkern = i.rightkern or 0 + local yoffset = i.yoffset or 0 + local markx = i.markx or 0 + local marky = i.marky or 0 + local markdir = i.markdir or 0 + local markbase = i.markbase or 0 -- will be markbasenode + local cursivex = i.cursivex or 0 + local cursivey = i.cursivey or 0 + local ligaindex = i.ligaindex or 0 + local margin = nested and 4 or 2 + -- + if rightkern ~= 0 or yoffset ~= 0 then + report_injections("%w%s pair: lx %p, rx %p, dy %p",margin,symbol,leftkern,rightkern,yoffset) + elseif leftkern ~= 0 then + report_injections("%w%s kern: dx %p",margin,symbol,leftkern) + end + if markx ~= 0 or marky ~= 0 or markbase ~= 0 then + report_injections("%w%s mark: dx %p, dy %p, dir %s, base %s",margin,symbol,markx,marky,markdir,markbase ~= 0 and "yes" or "no") + end + if cursivex ~= 0 or cursivey ~= 0 then + report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey) + end + if ligaindex ~= 0 then + report_injections("%w%s liga: index %i",margin,symbol,ligaindex) + end + end + end + end +end + +local function showsub(n,what,where) + report_injections("begin subrun: %s",where) + for n in traverse_id(glyph_code,n) do + showchar(n,where) + show(n,what,where," ") + end + report_injections("end subrun") +end + +local function trace(head,where) + report_injections("begin run %s: %s kerns, %s pairs, %s marks and %s cursives registered", + where or "",nofregisteredkerns,nofregisteredpairs,nofregisteredmarks,nofregisteredcursives) + local n = head + while n do + local id = getid(n) + if id == glyph_code then + showchar(n) + show(n,"injections",false," ") + show(n,"preinjections",false,"<") + show(n,"postinjections",false,">") + show(n,"replaceinjections",false,"=") + elseif id == disc_code then + local pre = getfield(n,"pre") + local post = getfield(n,"post") + local replace = getfield(n,"replace") + if pre then + showsub(pre,"preinjections","pre") + end + if post then + showsub(post,"postinjections","post") + end + if replace then + showsub(replace,"replaceinjections","replace") + end + end + n = getnext(n) + end + report_injections("end run") +end + +local function show_result(head) + local current = head + local skipping = false + while current do + local id = getid(current) + if id == glyph_code then + report_injections("char: %C, width %p, xoffset %p, yoffset %p", + getchar(current),getfield(current,"width"),getfield(current,"xoffset"),getfield(current,"yoffset")) + skipping = false + elseif id == kern_code then + report_injections("kern: %p",getfield(current,"kern")) + skipping = false + elseif not skipping then + report_injections() + skipping = true + end + current = getnext(current) + end +end + +-- we could also check for marks here but maybe not all are registered (needs checking) + +local function collect_glyphs_1(head) + local glyphs, nofglyphs = { }, 0 + local marks, nofmarks = { }, 0 + local nf, tm = nil, nil + for n in traverse_id(glyph_code,head) do -- only needed for relevant fonts + if getsubtype(n) < 256 then + local f = getfont(n) + if f ~= nf then + nf = f + tm = fontdata[nf].resources.marks -- other hash in ctx + end + if tm and tm[getchar(n)] then + nofmarks = nofmarks + 1 + marks[nofmarks] = n + else + nofglyphs = nofglyphs + 1 + glyphs[nofglyphs] = n + end + -- yoffsets can influence curs steps + local p = rawget(properties,n) + if p then + local i = rawget(p,"injections") + if i then + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + end + end + end + end + return glyphs, nofglyphs, marks, nofmarks +end + +local function collect_glyphs_2(head) + local glyphs, nofglyphs = { }, 0 + local marks, nofmarks = { }, 0 + local nf, tm = nil, nil + for n in traverse_id(glyph_code,head) do + if getsubtype(n) < 256 then + local f = getfont(n) + if f ~= nf then + nf = f + tm = fontdata[nf].resources.marks -- other hash in ctx + end + if tm and tm[getchar(n)] then + nofmarks = nofmarks + 1 + marks[nofmarks] = n + else + nofglyphs = nofglyphs + 1 + glyphs[nofglyphs] = n + end + end + end + return glyphs, nofglyphs, marks, nofmarks +end + +local function inject_marks(marks,nofmarks) + for i=1,nofmarks do + local n = marks[i] + local pn = rawget(properties,n) + if pn then + pn = rawget(pn,"injections") + if pn then + local p = pn.markbasenode + if p then + local px = getfield(p,"xoffset") + local ox = 0 + local rightkern = nil + local pp = rawget(properties,p) + if pp then + pp = rawget(pp,"injections") + if pp then + rightkern = pp.rightkern + end + end + if rightkern then -- x and w ~= 0 + if pn.markdir < 0 then + -- kern(w-x) glyph(p) kern(x) mark(n) + ox = px - pn.markx - rightkern + -- report_injections("r2l case 1: %p",ox) + else + -- kern(x) glyph(p) kern(w-x) mark(n) + -- ox = px - getfield(p,"width") + pn.markx - pp.leftkern + local leftkern = pp.leftkern + if leftkern then + ox = px - pn.markx + else + ox = px - pn.markx - leftkern + end +-- report_injections("l2r case 1: %p",ox) + end + else + -- we need to deal with fonts that have marks with width + -- if pn.markdir < 0 then + -- ox = px - pn.markx + -- -- report_injections("r2l case 3: %p",ox) + -- else + -- -- ox = px - getfield(p,"width") + pn.markx + ox = px - pn.markx + -- report_injections("l2r case 3: %p",ox) + -- end + local wn = getfield(n,"width") -- in arial marks have widths + if wn ~= 0 then + -- bad: we should center + -- insert_node_before(head,n,newkern(-wn/2)) + -- insert_node_after(head,n,newkern(-wn/2)) + pn.leftkern = -wn/2 + pn.rightkern = -wn/2 + -- wx[n] = { 0, -wn/2, 0, -wn } + end + -- so far + end + setfield(n,"xoffset",ox) + -- + local py = getfield(p,"yoffset") + local oy = 0 + if marks[p] then + oy = py + pn.marky + else + oy = getfield(n,"yoffset") + py + pn.marky + end + setfield(n,"yoffset",oy) + else + -- normally this can't happen (only when in trace mode which is a special case anyway) + -- report_injections("missing mark anchor %i",pn.markbase or 0) + end + end + end + end +end + +local function inject_cursives(glyphs,nofglyphs) + local cursiveanchor, lastanchor = nil, nil + local minc, maxc, last = 0, 0, nil + for i=1,nofglyphs do + local n = glyphs[i] + local pn = rawget(properties,n) + if pn then + pn = rawget(pn,"injections") + end + if pn then + local cursivex = pn.cursivex + if cursivex then + if cursiveanchor then + if cursivex ~= 0 then + pn.leftkern = (pn.leftkern or 0) + cursivex + end + if lastanchor then + if maxc == 0 then + minc = lastanchor + end + maxc = lastanchor + properties[cursiveanchor].cursivedy = pn.cursivey + end + last = n + else + maxc = 0 + end + elseif maxc > 0 then + local ny = getfield(n,"yoffset") + for i=maxc,minc,-1 do + local ti = glyphs[i] + ny = ny + properties[ti].cursivedy + setfield(ti,"yoffset",ny) -- why not add ? + end + maxc = 0 + end + if pn.cursiveanchor then + cursiveanchor = n + lastanchor = i + else + cursiveanchor = nil + lastanchor = nil + if maxc > 0 then + local ny = getfield(n,"yoffset") + for i=maxc,minc,-1 do + local ti = glyphs[i] + ny = ny + properties[ti].cursivedy + setfield(ti,"yoffset",ny) -- why not add ? + end + maxc = 0 + end + end + elseif maxc > 0 then + local ny = getfield(n,"yoffset") + for i=maxc,minc,-1 do + local ti = glyphs[i] + ny = ny + properties[ti].cursivedy + setfield(ti,"yoffset",getfield(ti,"yoffset") + ny) -- ? + end + maxc = 0 + cursiveanchor = nil + lastanchor = nil + end + -- if maxc > 0 and not cursiveanchor then + -- local ny = getfield(n,"yoffset") + -- for i=maxc,minc,-1 do + -- local ti = glyphs[i] + -- ny = ny + properties[ti].cursivedy + -- setfield(ti,"yoffset",ny) -- why not add ? + -- end + -- maxc = 0 + -- end + end + if last and maxc > 0 then + local ny = getfield(last,"yoffset") + for i=maxc,minc,-1 do + local ti = glyphs[i] + ny = ny + properties[ti].cursivedy + setfield(ti,"yoffset",ny) -- why not add ? + end + end +end + +local function inject_kerns(head,glyphs,nofglyphs) + -- todo: pre/post/replace + for i=1,#glyphs do + local n = glyphs[i] + local pn = rawget(properties,n) + if pn then + local i = rawget(pn,"injections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + insert_node_before(head,n,newkern(leftkern)) -- type 0/2 + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,n,newkern(rightkern)) -- type 0/2 + end + end + end + end +end + +local function inject_everything(head,where) + head = tonut(head) + if trace_injections then + trace(head,"everything") + end + local glyphs, nofglyphs, marks, nofmarks + if nofregisteredpairs > 0 then + glyphs, nofglyphs, marks, nofmarks = collect_glyphs_1(head) + else + glyphs, nofglyphs, marks, nofmarks = collect_glyphs_2(head) + end + if nofglyphs > 0 then + if nofregisteredcursives > 0 then + inject_cursives(glyphs,nofglyphs) + end + if nofregisteredmarks > 0 then -- and nofmarks > 0 + inject_marks(marks,nofmarks) + end + inject_kerns(head,glyphs,nofglyphs) + end + if keepregisteredcounts then + keepregisteredcounts = false + else + nofregisteredkerns = 0 + nofregisteredpairs = 0 + nofregisteredmarks = 0 + nofregisteredcursives = 0 + end + return tonode(head), true +end + +local function inject_kerns_only(head,where) + head = tonut(head) + if trace_injections then + trace(head,"kerns") + end + local n = head + local p = nil + while n do + local id = getid(n) + if id == glyph_code then + if getsubtype(n) < 256 then + local pn = rawget(properties,n) + if pn then + if p then + local d = getfield(p,"post") + if d then + local i = rawget(pn,"postinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + local t = find_tail(d) + insert_node_after(d,t,newkern(leftkern)) + end + end + end + local d = getfield(p,"replace") + if d then + local i = rawget(pn,"replaceinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + local t = find_tail(d) + insert_node_after(d,t,newkern(leftkern)) + end + end + else + local i = rawget(pn,"injections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + setfield(p,"replace",newkern(leftkern)) + end + end + end + else + local i = rawget(pn,"injections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + head = insert_node_before(head,n,newkern(leftkern)) + end + end + end + end + else + break + end + p = nil + elseif id == disc_code then + local d = getfield(n,"pre") + if d then + local h = d + for n in traverse_id(glyph_code,d) do + if getsubtype(n) < 256 then + local pn = rawget(properties,n) + if pn then + local i = rawget(pn,"preinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + h = insert_node_before(h,n,newkern(leftkern)) + end + end + end + else + break + end + end + if h ~= d then + setfield(n,"pre",h) + end + end + local d = getfield(n,"post") + if d then + local h = d + for n in traverse_id(glyph_code,d) do + if getsubtype(n) < 256 then + local pn = rawget(properties,n) + if pn then + local i = rawget(pn,"postinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + h = insert_node_before(h,n,newkern(leftkern)) + end + end + end + else + break + end + end + if h ~= d then + setfield(n,"post",h) + end + end + local d = getfield(n,"replace") + if d then + local h = d + for n in traverse_id(glyph_code,d) do + if getsubtype(n) < 256 then + local pn = rawget(properties,n) -- why can it be empty { } + if pn then + local i = rawget(pn,"replaceinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + h = insert_node_before(h,n,newkern(leftkern)) + end + end + end + else + break + end + end + if h ~= d then + setfield(n,"replace",h) + end + end + p = n + else + p = nil + end + n = getnext(n) + end + -- + if keepregisteredcounts then + keepregisteredcounts = false + else + nofregisteredkerns = 0 + end + return tonode(head), true +end + +local function inject_pairs_only(head,where) + head = tonut(head) + if trace_injections then + trace(head,"pairs") + end + -- + local n = head + local p = nil + while n do + local id = getid(n) + if id == glyph_code then + if getsubtype(n) < 256 then + local pn = rawget(properties,n) + if pn then + if p then + local d = getfield(p,"post") + if d then + local i = rawget(pn,"postinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + local t = find_tail(d) + insert_node_after(d,t,newkern(leftkern)) + end + -- local rightkern = i.rightkern + -- if rightkern and rightkern ~= 0 then + -- insert_node_after(head,n,newkern(rightkern)) + -- n = getnext(n) -- to be checked + -- end + end + end + local d = getfield(p,"replace") + if d then + local i = rawget(pn,"replaceinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + local t = find_tail(d) + insert_node_after(d,t,newkern(leftkern)) + end + -- local rightkern = i.rightkern + -- if rightkern and rightkern ~= 0 then + -- insert_node_after(head,n,newkern(rightkern)) + -- n = getnext(n) -- to be checked + -- end + end + else + local i = rawget(pn,"injections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + setfield(p,"replace",newkern(leftkern)) + end + -- local rightkern = i.rightkern + -- if rightkern and rightkern ~= 0 then + -- insert_node_after(head,n,newkern(rightkern)) + -- n = getnext(n) -- to be checked + -- end + end + end + else + -- this is the most common case + local i = rawget(pn,"injections") + if i then + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + insert_node_before(head,n,newkern(leftkern)) + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,n,newkern(rightkern)) + n = getnext(n) -- to be checked + end + end + end + end + else + break + end + p = nil + elseif id == disc_code then + local d = getfield(n,"pre") + if d then + local h = d + for n in traverse_id(glyph_code,d) do + if getsubtype(n) < 256 then + local p = rawget(properties,n) + if p then + local i = rawget(p,"preinjections") + if i then + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + local leftkern = i.leftkern + if leftkern ~= 0 then + h = insert_node_before(h,n,newkern(leftkern)) + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,n,newkern(rightkern)) + n = getnext(n) -- to be checked + end + end + end + else + break + end + end + if h ~= d then + setfield(n,"pre",h) + end + end + local d = getfield(n,"post") + if d then + local h = d + for n in traverse_id(glyph_code,d) do + if getsubtype(n) < 256 then + local p = rawget(properties,n) + if p then + local i = rawget(p,"postinjections") + if i then + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + h = insert_node_before(h,n,newkern(leftkern)) + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,n,newkern(rightkern)) + n = getnext(n) -- to be checked + end + end + end + else + break + end + end + if h ~= d then + setfield(n,"post",h) + end + end + local d = getfield(n,"replace") + if d then + local h = d + for n in traverse_id(glyph_code,d) do + if getsubtype(n) < 256 then + local p = rawget(properties,n) + if p then + local i = rawget(pn,"replaceinjections") + if i then + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + h = insert_node_before(h,n,newkern(leftkern)) + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,n,newkern(rightkern)) + n = getnext(n) -- to be checked + end + end + end + else + break + end + end + if h ~= d then + setfield(n,"replace",h) + end + end + p = n + else + p = nil + end + n = getnext(n) + end + -- + if keepregisteredcounts then + keepregisteredcounts = false + else + nofregisteredpairs = 0 + nofregisteredkerns = 0 + end + return tonode(head), true +end + +function injections.handler(head,where) -- optimize for n=1 ? + if nofregisteredmarks > 0 or nofregisteredcursives > 0 then + return inject_everything(head,where) + elseif nofregisteredpairs > 0 then + return inject_pairs_only(head,where) + elseif nofregisteredkerns > 0 then + return inject_kerns_only(head,where) + else + return head, false + end +end diff --git a/Master/texmf-dist/tex/context/base/font-lib.mkvi b/Master/texmf-dist/tex/context/base/font-lib.mkvi index bfd85245cff..59074b07df2 100644 --- a/Master/texmf-dist/tex/context/base/font-lib.mkvi +++ b/Master/texmf-dist/tex/context/base/font-lib.mkvi @@ -19,7 +19,7 @@ \registerctxluafile{font-log}{1.001} \registerctxluafile{font-con}{1.001} \registerctxluafile{font-enc}{1.001} -%registerctxluafile{font-agl}{1.001} % loaded when needed, saves 100K in format +\registerctxluafile{font-agl}{1.001} % if needed we can comment this and delay loading \registerctxluafile{font-cid}{1.001} % cid maps \registerctxluafile{font-map}{1.001} \registerctxluafile{font-syn}{1.001} @@ -39,12 +39,13 @@ \registerctxluafile{font-otf}{1.001} % otf main \registerctxluafile{font-otb}{1.001} % otf main base -\doiffileelse{font-inj.lua} - {\registerctxluafile{font-inj}{1.001}} % new method (for the moment only local) - {\registerctxluafile{node-inj}{1.001}} % old method +% \doiffileelse{font-inj.lua} +% {\registerctxluafile{font-inj}{1.001}} % new method (for the moment only local) +% {\registerctxluafile{node-inj}{1.001}} % old method -%registerctxluafile{font-ota}{1.001} % otf analyzers -\registerctxluafile{font-otx}{1.001} % otf analyzers +\registerctxluafile{font-inj}{1.001} % the old method (lacks some features) + +\registerctxluafile{font-ota}{1.001} % otf analyzers \registerctxluafile{font-otn}{1.001} % otf main node \registerctxluafile{font-otd}{1.001} % otf dynamics (does an overload) \registerctxluafile{font-otp}{1.001} % otf pack @@ -90,17 +91,16 @@ %D \stoptyping % we can also move the lookups to the fonts.namespace (of commands) +% one can also directly use the clf calls when speed is needed -% these will be renamed but it needs synchronization with WS - -\def\dolookupfontbyspec #1{\ctxcommand{fontlookupinitialize("#1")}} -\def\dolookupnoffound {\ctxcommand{fontlookupnoffound()}} -\def\dolookupgetkeyofindex#1#2{\ctxcommand{fontlookupgetkeyofindex("#1",#2)}} -\def\dolookupgetkey #1{\ctxcommand{fontlookupgetkey("#1")}} -\def\cleanfontname #1{\ctxcommand{cleanfontname("#1")}} +\def\dolookupfontbyspec #1{\clf_fontlookupinitialize{#1}} +\def\dolookupnoffound {\clf_fontlookupnoffound} +\def\dolookupgetkeyofindex#1#2{\clf_fontlookupgetkeyofindex{#1}\numexpr#2\relax} +\def\dolookupgetkey #1{\clf_fontlookupgetkey{#1}} +\def\cleanfontname #1{\clf_cleanfontname{#1}} % new: -\unexpanded\def\setfontofid#1{\ctxcommand{setfontofid(#1)}} +\unexpanded\def\setfontofid#1{\ctf_setfontofid#1\relax} \protect \endinput diff --git a/Master/texmf-dist/tex/context/base/font-map.lua b/Master/texmf-dist/tex/context/base/font-map.lua index f74e13e8161..449a00f2efd 100644 --- a/Master/texmf-dist/tex/context/base/font-map.lua +++ b/Master/texmf-dist/tex/context/base/font-map.lua @@ -6,12 +6,13 @@ if not modules then modules = { } end modules ['font-map'] = { license = "see context related readme files" } -local tonumber = tonumber +local tonumber, next, type = tonumber, next, type local match, format, find, concat, gsub, lower = string.match, string.format, string.find, table.concat, string.gsub, string.lower local P, R, S, C, Ct, Cc, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.match local utfbyte = utf.byte local floor = math.floor +local formatters = string.formatters local trace_loading = false trackers.register("fonts.loading", function(v) trace_loading = v end) local trace_mapping = false trackers.register("fonts.mapping", function(v) trace_unimapping = v end) @@ -22,6 +23,8 @@ local fonts = fonts or { } local mappings = fonts.mappings or { } fonts.mappings = mappings +local allocate = utilities.storage.allocate + --[[ldx--
Eventually this code will disappear because map files are kind of obsolete. Some code may move to runtime or auxiliary modules.
@@ -66,11 +69,14 @@ local function makenameparser(str) end end +local f_single = formatters["%04X"] +local f_double = formatters["%04X%04X"] + local function tounicode16(unicode,name) if unicode < 0x10000 then - return format("%04X",unicode) + return f_single(unicode) elseif unicode < 0x1FFFFFFFFF then - return format("%04X%04X",floor(unicode/1024),unicode%1024+0xDC00) + return f_double(floor(unicode/1024),unicode%1024+0xDC00) else report_fonts("can't convert %a in %a into tounicode",unicode,name) end @@ -79,18 +85,46 @@ end local function tounicode16sequence(unicodes,name) local t = { } for l=1,#unicodes do - local unicode = unicodes[l] - if unicode < 0x10000 then - t[l] = format("%04X",unicode) + local u = unicodes[l] + if u < 0x10000 then + t[l] = f_single(u) elseif unicode < 0x1FFFFFFFFF then - t[l] = format("%04X%04X",floor(unicode/1024),unicode%1024+0xDC00) + t[l] = f_double(floor(u/1024),u%1024+0xDC00) else - report_fonts ("can't convert %a in %a into tounicode",unicode,name) + report_fonts ("can't convert %a in %a into tounicode",u,name) + return end end return concat(t) end +local function tounicode(unicode,name) + if type(unicode) == "table" then + local t = { } + for l=1,#unicode do + local u = unicode[l] + if u < 0x10000 then + t[l] = f_single(u) + elseif u < 0x1FFFFFFFFF then + t[l] = f_double(floor(u/1024),u%1024+0xDC00) + else + report_fonts ("can't convert %a in %a into tounicode",u,name) + return + end + end + return concat(t) + else + if unicode < 0x10000 then + return f_single(unicode) + elseif unicode < 0x1FFFFFFFFF then + return f_double(floor(unicode/1024),unicode%1024+0xDC00) + else + report_fonts("can't convert %a in %a into tounicode",unicode,name) + end + end +end + + local function fromunicode16(str) if #str == 4 then return tonumber(str,16) @@ -136,6 +170,7 @@ end mappings.loadlumtable = loadlumtable mappings.makenameparser = makenameparser +mappings.tounicode = tounicode mappings.tounicode16 = tounicode16 mappings.tounicode16sequence = tounicode16sequence mappings.fromunicode16 = fromunicode16 @@ -149,6 +184,8 @@ local namesplitter = Ct(C((1 - ligseparator - varseparator)^1) * (ligseparator * -- print(string.formatters["%s: [% t]"](name,split)) -- end +-- maybe: ff fi fl ffi ffl => f_f f_i f_l f_f_i f_f_l + -- test("i.f_") -- test("this") -- test("this.that") @@ -156,33 +193,54 @@ local namesplitter = Ct(C((1 - ligseparator - varseparator)^1) * (ligseparator * -- test("such_so_more") -- test("such_so_more.that") +-- to be completed .. for fonts that use unicodes for ligatures which +-- is a actually a bad thing and should be avoided in the first place + +local overloads = allocate { + IJ = { name = "I_J", unicode = { 0x49, 0x4A }, mess = 0x0132 }, + ij = { name = "i_j", unicode = { 0x69, 0x6A }, mess = 0x0133 }, + ff = { name = "f_f", unicode = { 0x66, 0x66 }, mess = 0xFB00 }, + fi = { name = "f_i", unicode = { 0x66, 0x69 }, mess = 0xFB01 }, + fl = { name = "f_l", unicode = { 0x66, 0x6C }, mess = 0xFB02 }, + ffi = { name = "f_f_i", unicode = { 0x66, 0x66, 0x69 }, mess = 0xFB03 }, + ffl = { name = "f_f_l", unicode = { 0x66, 0x66, 0x6C }, mess = 0xFB04 }, + fj = { name = "f_j", unicode = { 0x66, 0x6A } }, + fk = { name = "f_k", unicode = { 0x66, 0x6B } }, +} + +for k, v in next, overloads do + local name = v.name + local mess = v.mess + if name then + overloads[name] = v + end + if mess then + overloads[mess] = v + end +end + +mappings.overloads = overloads + function mappings.addtounicode(data,filename) local resources = data.resources local properties = data.properties local descriptions = data.descriptions local unicodes = resources.unicodes + local lookuptypes = resources.lookuptypes if not unicodes then return end -- we need to move this code - unicodes['space'] = unicodes['space'] or 32 - unicodes['hyphen'] = unicodes['hyphen'] or 45 - unicodes['zwj'] = unicodes['zwj'] or 0x200D - unicodes['zwnj'] = unicodes['zwnj'] or 0x200C - -- the tounicode mapping is sparse and only needed for alternatives + unicodes['space'] = unicodes['space'] or 32 + unicodes['hyphen'] = unicodes['hyphen'] or 45 + unicodes['zwj'] = unicodes['zwj'] or 0x200D + unicodes['zwnj'] = unicodes['zwnj'] or 0x200C local private = fonts.constructors.privateoffset - local unknown = format("%04X",utfbyte("?")) local unicodevector = fonts.encodings.agl.unicodes -- loaded runtime in context - local tounicode = { } - local originals = { } - resources.tounicode = tounicode - resources.originals = originals + ----- namevector = fonts.encodings.agl.names -- loaded runtime in context + local missing = { } local lumunic, uparser, oparser local cidinfo, cidnames, cidcodes, usedmap - if false then -- will become an option - lumunic = loadlumtable(filename) - lumunic = lumunic and lumunic.tounicode - end -- cidinfo = properties.cidinfo usedmap = cidinfo and fonts.cid.getmap(cidinfo) @@ -197,12 +255,16 @@ function mappings.addtounicode(data,filename) for unic, glyph in next, descriptions do local index = glyph.index local name = glyph.name - if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then + local r = overloads[name] + if r then + -- get rid of weird ligatures + -- glyph.name = r.name + glyph.unicode = r.unicode + elseif unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then local unicode = lumunic and lumunic[name] or unicodevector[name] if unicode then - originals[index] = unicode - tounicode[index] = tounicode16(unicode,name) - ns = ns + 1 + glyph.unicode = unicode + ns = ns + 1 end -- cidmap heuristics, beware, there is no guarantee for a match unless -- the chain resolves @@ -211,9 +273,8 @@ function mappings.addtounicode(data,filename) if foundindex then unicode = cidcodes[foundindex] -- name to number if unicode then - originals[index] = unicode - tounicode[index] = tounicode16(unicode,name) - ns = ns + 1 + glyph.unicode = unicode + ns = ns + 1 else local reference = cidnames[foundindex] -- number to name if reference then @@ -221,23 +282,20 @@ function mappings.addtounicode(data,filename) if foundindex then unicode = cidcodes[foundindex] if unicode then - originals[index] = unicode - tounicode[index] = tounicode16(unicode,name) - ns = ns + 1 + glyph.unicode = unicode + ns = ns + 1 end end if not unicode or unicode == "" then local foundcodes, multiple = lpegmatch(uparser,reference) if foundcodes then - originals[index] = foundcodes + glyph.unicode = foundcodes if multiple then - tounicode[index] = tounicode16sequence(foundcodes) - nl = nl + 1 - unicode = true + nl = nl + 1 + unicode = true else - tounicode[index] = tounicode16(foundcodes,name) - ns = ns + 1 - unicode = foundcodes + ns = ns + 1 + unicode = foundcodes end end end @@ -284,11 +342,9 @@ function mappings.addtounicode(data,filename) if n == 0 then -- done then -- nothing elseif n == 1 then - originals[index] = t[1] - tounicode[index] = tounicode16(t[1],name) + glyph.unicode = t[1] else - originals[index] = t - tounicode[index] = tounicode16sequence(t) + glyph.unicode = t end nl = nl + 1 end @@ -296,32 +352,163 @@ function mappings.addtounicode(data,filename) if not unicode or unicode == "" then local foundcodes, multiple = lpegmatch(uparser,name) if foundcodes then + glyph.unicode = foundcodes if multiple then - originals[index] = foundcodes - tounicode[index] = tounicode16sequence(foundcodes,name) - nl = nl + 1 - unicode = true + nl = nl + 1 + unicode = true else - originals[index] = foundcodes - tounicode[index] = tounicode16(foundcodes,name) - ns = ns + 1 - unicode = foundcodes + ns = ns + 1 + unicode = foundcodes end end end - -- if not unicode then - -- originals[index] = 0xFFFD - -- tounicode[index] = "FFFD" + -- check using substitutes and alternates + local r = overloads[unicode] + if r then + unicode = r.unicode + glyph.unicode = unicode + end + -- + if not unicode then + missing[name] = true + end + end + end + if next(missing) then + local guess = { } + -- helper + local function check(gname,code,unicode) + local description = descriptions[code] + -- no need to add a self reference + local variant = description.name + if variant == gname then + return + end + -- the variant already has a unicode (normally that resultrs in a default tounicode to self) + local unic = unicodes[variant] + if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then + -- no default mapping and therefore maybe no tounicode yet + else + return + end + -- the variant already has a tounicode + if descriptions[code].unicode then + return + end + -- add to the list + local g = guess[variant] + -- local r = overloads[unicode] + -- if r then + -- unicode = r.unicode -- end + if g then + g[gname] = unicode + else + guess[variant] = { [gname] = unicode } + end + end + -- + for unicode, description in next, descriptions do + local slookups = description.slookups + if slookups then + local gname = description.name + for tag, data in next, slookups do + local lookuptype = lookuptypes[tag] + if lookuptype == "alternate" then + for i=1,#data do + check(gname,data[i],unicode) + end + elseif lookuptype == "substitution" then + check(gname,data,unicode) + end + end + end + local mlookups = description.mlookups + if mlookups then + local gname = description.name + for tag, list in next, mlookups do + local lookuptype = lookuptypes[tag] + if lookuptype == "alternate" then + for i=1,#list do + local data = list[i] + for i=1,#data do + check(gname,data[i],unicode) + end + end + elseif lookuptype == "substitution" then + for i=1,#list do + check(gname,list[i],unicode) + end + end + end + end + end + -- resolve references + local done = true + while done do + done = false + for k, v in next, guess do + if type(v) ~= "number" then + for kk, vv in next, v do + if vv == -1 or vv >= private or (vv >= 0xE000 and vv <= 0xF8FF) or vv == 0xFFFE or vv == 0xFFFF then + local uu = guess[kk] + if type(uu) == "number" then + guess[k] = uu + done = true + end + else + guess[k] = vv + done = true + end + end + end + end + end + -- wrap up + local orphans = 0 + local guessed = 0 + for k, v in next, guess do + if type(v) == "number" then + descriptions[unicodes[k]].unicode = descriptions[v].unicode or v -- can also be a table + guessed = guessed + 1 + else + local t = nil + local l = lower(k) + local u = unicodes[l] + if not u then + orphans = orphans + 1 + elseif u == -1 or u >= private or (u >= 0xE000 and u <= 0xF8FF) or u == 0xFFFE or u == 0xFFFF then + local unicode = descriptions[u].unicode + if unicode then + descriptions[unicodes[k]].unicode = unicode + guessed = guessed + 1 + else + orphans = orphans + 1 + end + else + orphans = orphans + 1 + end + end + end + if trace_loading and orphans > 0 or guessed > 0 then + report_fonts("%s glyphs with no related unicode, %s guessed, %s orphans",guessed+orphans,guessed,orphans) end end if trace_mapping then for unic, glyph in table.sortedhash(descriptions) do - local name = glyph.name - local index = glyph.index - local toun = tounicode[index] - if toun then - report_fonts("internal slot %U, name %a, unicode %U, tounicode %a",index,name,unic,toun) + local name = glyph.name + local index = glyph.index + local unicode = glyph.unicode + if unicode then + if type(unicode) == "table" then + local unicodes = { } + for i=1,#unicode do + unicodes[i] = formatters("%U",unicode[i]) + end + report_fonts("internal slot %U, name %a, unicode %U, tounicode % t",index,name,unic,unicodes) + else + report_fonts("internal slot %U, name %a, unicode %U, tounicode %U",index,name,unic,unicode) + end else report_fonts("internal slot %U, name %a, unicode %U",index,name,unic) end diff --git a/Master/texmf-dist/tex/context/base/font-mis.lua b/Master/texmf-dist/tex/context/base/font-mis.lua index 7385d6f3116..0ec95ee1b56 100644 --- a/Master/texmf-dist/tex/context/base/font-mis.lua +++ b/Master/texmf-dist/tex/context/base/font-mis.lua @@ -22,9 +22,15 @@ local handlers = fonts.handlers handlers.otf = handlers.otf or { } local otf = handlers.otf -otf.version = otf.version or 2.755 +otf.version = otf.version or 2.803 otf.cache = otf.cache or containers.define("fonts", "otf", otf.version, true) +local fontloader = fontloader +local font_to_table = fontloader.to_table +local open_font = fontloader.open +local get_font_info = fontloader.info +local close_font = fontloader.close + function otf.loadcached(filename,format,sub) -- no recache when version mismatch local name = file.basename(file.removesuffix(filename)) @@ -54,10 +60,10 @@ function fonts.helpers.getfeatures(name,t,script,language) -- maybe per font typ if data and data.resources and data.resources.features then return data.resources.features else - local ff = fontloader.open(filename) + local ff = open_font(filename) if ff then - local data = fontloader.to_table(ff) - fontloader.close(ff) + local data = font_to_table(ff) + close_font(ff) local features = { } for k=1,#featuregroups do local what = featuregroups[k] diff --git a/Master/texmf-dist/tex/context/base/font-nod.lua b/Master/texmf-dist/tex/context/base/font-nod.lua index 8251dc58842..26c736582b1 100644 --- a/Master/texmf-dist/tex/context/base/font-nod.lua +++ b/Master/texmf-dist/tex/context/base/font-nod.lua @@ -11,10 +11,10 @@ if not modules then modules = { } end modules ['font-nod'] = { might become a runtime module instead. This module will be cleaned up! --ldx]]-- -local tonumber, tostring = tonumber, tostring +local tonumber, tostring, rawget = tonumber, tostring, rawget local utfchar = utf.char -local concat = table.concat -local match, gmatch, concat, rep = string.match, string.gmatch, table.concat, string.rep +local concat, fastcopy = table.concat, table.fastcopy +local match, rep = string.match, string.rep local report_nodes = logs.reporter("fonts","tracing") @@ -75,6 +75,7 @@ local copy_node_list = nuts.copy_list local hpack_node_list = nuts.hpack local free_node_list = nuts.flush_list local traverse_nodes = nuts.traverse +local traverse_id = nuts.traverse_id local protect_glyphs = nuts.protect_glyphs local nodepool = nuts.pool @@ -91,6 +92,25 @@ local fontcharacters = hashes.characters local fontproperties = hashes.properties local fontparameters = hashes.parameters +local properties = nodes.properties.data + +-- direct.set_properties_mode(true,false) +-- direct.set_properties_mode(true,true) -- default + +local function freeze(h,where) + -- report_nodes("freezing %s",where) + for n in traverse_nodes(tonut(h)) do -- todo: disc but not traced anyway + local p = properties[n] + if p then + local i = p.injections if i then p.injections = fastcopy(i) end + -- local i = r.preinjections if i then p.preinjections = fastcopy(i) end + -- local i = r.postinjections if i then p.postinjections = fastcopy(i) end + -- local i = r.replaceinjections if i then p.replaceinjections = fastcopy(i) end + -- only injections + end + end +end + function char_tracers.collect(head,list,tag,n) head = tonut(head) n = n or 0 @@ -103,7 +123,7 @@ function char_tracers.collect(head,list,tag,n) ok, fn = false, f end local c = getchar(head) - local i = fontidentifiers[f].indices[c] or 0 + -- local i = fontidentifiers[f].indices[c] or 0 -- zero anyway as indices is nilled if not ok then ok = true n = n + 1 @@ -111,9 +131,28 @@ function char_tracers.collect(head,list,tag,n) list[n][tag] = { } end local l = list[n][tag] - l[#l+1] = { c, f, i } + -- l[#l+1] = { c, f, i } + l[#l+1] = { c, f } elseif id == disc_code then -- skip +-- local replace = getfield(head,"replace") +-- if replace then +-- for n in traverse_id(glyph_code,replace) do +-- l[#l+1] = { c, f } +-- end +-- end +-- local pre = getfield(head,"pre") +-- if pre then +-- for n in traverse_id(glyph_code,pre) do +-- l[#l+1] = { c, f } +-- end +-- end +-- local post = getfield(head,"post") +-- if post then +-- for n in traverse_id(glyph_code,post) do +-- l[#l+1] = { c, f } +-- end +-- end else ok = false end @@ -127,7 +166,8 @@ function char_tracers.equal(ta, tb) else for i=1,#ta do local a, b = ta[i], tb[i] - if a[1] ~= b[1] or a[2] ~= b[2] or a[3] ~= b[3] then + -- if a[1] ~= b[1] or a[2] ~= b[2] or a[3] ~= b[3] then + if a[1] ~= b[1] or a[2] ~= b[2] then return false end end @@ -160,20 +200,20 @@ function char_tracers.unicodes(t,decimal) return concat(tt," ") end -function char_tracers.indices(t,decimal) - local tt = { } - for i=1,#t do - local n = t[i][3] - if n == 0 then - tt[i] = "-" - elseif decimal then - tt[i] = n - else - tt[i] = f_unicode(n) - end - end - return concat(tt," ") -end +-- function char_tracers.indices(t,decimal) +-- local tt = { } +-- for i=1,#t do +-- local n = t[i][3] +-- if n == 0 then +-- tt[i] = "-" +-- elseif decimal then +-- tt[i] = n +-- else +-- tt[i] = f_unicode(n) +-- end +-- end +-- return concat(tt," ") +-- end function char_tracers.start() local npc = handlers.characters -- should accept nuts too @@ -248,7 +288,8 @@ end function step_tracers.glyphs(n,i) local c = collection[i] if c then - local b = hpack_node_list(copy_node_list(c)) -- multiple arguments + local c = copy_node_list(c) + local b = hpack_node_list(c) -- multiple arguments setbox(n,b) end end @@ -311,21 +352,59 @@ function step_tracers.font(command) end end -function step_tracers.codes(i,command) +local colors = { + pre = { "darkred" }, + post = { "darkgreen" }, + replace = { "darkblue" }, +} + +function step_tracers.codes(i,command,space) local c = collection[i] + + local function showchar(c) + if command then + local f, c = getfont(c), getchar(c) + local d = fontdescriptions[f] + local d = d and d[c] + context[command](f,c,d and d.class or "") + else + context("[%s:U+%04X]",getfont(c),getchar(c)) + end + end + + local function showdisc(d,w,what) + if w then + context.startcolor(colors[what]) + context("%s:",what) + for c in traverse_id(glyph_code,w) do + showchar(c) + end + context[space]() + context.stopcolor() + end + end + while c do local id = getid(c) if id == glyph_code then - if command then - local f, c = getfont(c), getchar(c) - local d = fontdescriptions[f] - local d = d and d[c] - context[command](f,c,d and d.class or "") - else - context("[%s:U+%04X]",getfont(c),getchar(c)) - end + showchar(c) elseif id == whatsit_code and (getsubtype(c) == localpar_code or getsubtype(c) == dir_code) then context("[%s]",getfield(c,"dir")) + elseif id == disc_code then + local pre = getfield(c,"pre") + local post = getfield(c,"post") + local replace = getfield(c,"replace") + if pre or post or replace then + context("[") + context[space]() + showdisc(c,pre,"pre") + showdisc(c,post,"post") + showdisc(c,replace,"replace") + context[space]() + context("]") + else + context("[disc]") + end else context("[%s]",nodecodes[id]) end @@ -355,9 +434,11 @@ end function step_tracers.check(head) if collecting then step_tracers.reset() - local n = copy_node_list(tonut(head)) - injections.handler(n,nil,"trace",true) - -- handlers.protectglyphs(n) -- can be option + local h = tonut(head) + local n = copy_node_list(h) + freeze(n,"check") + injections.keepcounts(n) -- one-time + injections.handler(n,"trace") protect_glyphs(n) collection[1] = n end @@ -367,9 +448,11 @@ function step_tracers.register(head) if collecting then local nc = #collection+1 if messages[nc] then - local n = copy_node_list(tonut(head)) - injections.handler(n,nil,"trace",true) - -- handlers.protectglyphs(n) -- can be option + local h = tonut(head) + local n = copy_node_list(h) + freeze(n,"register") + injections.keepcounts(n) -- one-time + injections.handler(n,"trace") protect_glyphs(n) collection[nc] = n end @@ -405,16 +488,18 @@ local function toutf(list,result,nofresult,stopcriterium) if fc then local fcc = fc[c] if fcc then - -- == fromunicode - local u = fcc.tounicode - if u then - for s in gmatch(u,"....") do + local u = fcc.unicode + if not u then + nofresult = nofresult + 1 + result[nofresult] = utfchar(c) + elseif type(u) == "table" then + for i=1,#u do nofresult = nofresult + 1 - result[nofresult] = utfchar(tonumber(s,16)) + result[nofresult] = utfchar(u[i]) end else nofresult = nofresult + 1 - result[nofresult] = utfchar(c) + result[nofresult] = utfchar(u) end else nofresult = nofresult + 1 diff --git a/Master/texmf-dist/tex/context/base/font-odv.lua b/Master/texmf-dist/tex/context/base/font-odv.lua index 079027ffedb..40b1efbb4a9 100644 --- a/Master/texmf-dist/tex/context/base/font-odv.lua +++ b/Master/texmf-dist/tex/context/base/font-odv.lua @@ -181,6 +181,25 @@ end -- we might need to have consonants etc per script and initialize a local table -- pointing to the right one. +-- new, to be checked: +-- +-- U+00978 : DEVANAGARI LETTER MARWARI DDA +-- U+00980 : BENGALI ANJI +-- U+00C00 : TELUGU SIGN COMBINING CANDRABINDU ABOVE +-- U+00C34 : TELUGU LETTER LLLA +-- U+00C81 : KANNADA SIGN CANDRABINDU +-- U+00D01 : MALAYALAM SIGN CANDRABINDU +-- U+00DE6 : SINHALA LITH DIGIT ZERO +-- U+00DE7 : SINHALA LITH DIGIT ONE +-- U+00DE8 : SINHALA LITH DIGIT TWO +-- U+00DE9 : SINHALA LITH DIGIT THREE +-- U+00DEA : SINHALA LITH DIGIT FOUR +-- U+00DEB : SINHALA LITH DIGIT FIVE +-- U+00DEC : SINHALA LITH DIGIT SIX +-- U+00DED : SINHALA LITH DIGIT SEVEN +-- U+00DEE : SINHALA LITH DIGIT EIGHT +-- U+00DEF : SINHALA LITH DIGIT NINE + local consonant = { -- devanagari [0x0915] = true, [0x0916] = true, [0x0917] = true, [0x0918] = true, diff --git a/Master/texmf-dist/tex/context/base/font-ota.lua b/Master/texmf-dist/tex/context/base/font-ota.lua index 8d60ddc0e61..1f1534870a8 100644 --- a/Master/texmf-dist/tex/context/base/font-ota.lua +++ b/Master/texmf-dist/tex/context/base/font-ota.lua @@ -1,4 +1,4 @@ -if not modules then modules = { } end modules ['font-ota'] = { +if not modules then modules = { } end modules ['font-otx'] = { version = 1.001, comment = "companion to font-otf.lua (analysing)", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -6,10 +6,7 @@ if not modules then modules = { } end modules ['font-ota'] = { license = "see context related readme files" } --- this might become scrp-*.lua - --- [attr] : getprop or getattr --- [attr] : setprop or setattr +-- context only local type = type @@ -29,21 +26,35 @@ local methods = allocate() analyzers.initializers = initializers analyzers.methods = methods -analyzers.useunicodemarks = false +---------.useunicodemarks = false local a_state = attributes.private('state') +local nuts = nodes.nuts +local tonut = nuts.tonut + +local getfield = nuts.getfield +local getnext = nuts.getnext +local getprev = nuts.getprev +local getid = nuts.getid +local getprop = nuts.getprop +local setprop = nuts.setprop +local getfont = nuts.getfont +local getsubtype = nuts.getsubtype +local getchar = nuts.getchar + +local traverse_id = nuts.traverse_id +local traverse_node_list = nuts.traverse +local end_of_math = nuts.end_of_math + local nodecodes = nodes.nodecodes local glyph_code = nodecodes.glyph local disc_code = nodecodes.disc local math_code = nodecodes.math -local traverse_id = node.traverse_id -local traverse_node_list = node.traverse -local end_of_math = node.end_of_math - local fontdata = fonts.hashes.identifiers local categories = characters and characters.categories or { } -- sorry, only in context +local chardata = characters and characters.data local otffeatures = fonts.constructors.newfeatures("otf") local registerotffeature = otffeatures.register @@ -90,63 +101,70 @@ local features = { pstf = s_pstf, } -analyzers.states = states -analyzers.features = features +analyzers.states = states +analyzers.features = features +analyzers.useunicodemarks = false -- todo: analyzers per script/lang, cross font, so we need an font id hash -> script -- e.g. latin -> hyphenate, arab -> 1/2/3 analyze -- its own namespace -function analyzers.setstate(head,font) +function analyzers.setstate(head,font) -- we can skip math local useunicodemarks = analyzers.useunicodemarks local tfmdata = fontdata[font] local descriptions = tfmdata.descriptions local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean + current = tonut(current) while current do - local id = current.id - if id == glyph_code and current.font == font then + local id = getid(current) + if id == glyph_code and getfont(current) == font then done = true - local char = current.char + local char = getchar(current) local d = descriptions[char] if d then - if d.class == "mark" or (useunicodemarks and categories[char] == "mn") then + if d.class == "mark" then + done = true + setprop(current,a_state,s_mark) + elseif useunicodemarks and categories[char] == "mn" then done = true - current[a_state] = s_mark + setprop(current,a_state,s_mark) elseif n == 0 then first, last, n = current, current, 1 - current[a_state] = s_init + setprop(current,a_state,s_init) else last, n = current, n+1 - current[a_state] = s_medi + setprop(current,a_state,s_medi) end else -- finish if first and first == last then - last[a_state] = s_isol + setprop(last,a_state,s_isol) elseif last then - last[a_state] = s_fina + setprop(last,a_state,s_fina) end first, last, n = nil, nil, 0 end elseif id == disc_code then - -- always in the middle - current[a_state] = s_medi + -- always in the middle .. it doesn't make much sense to assign a property + -- here ... we might at some point decide to flag the components when present + -- but even then it's kind of bogus + setprop(current,a_state,s_medi) last = current else -- finish if first and first == last then - last[a_state] = s_isol + setprop(last,a_state,s_isol) elseif last then - last[a_state] = s_fina + setprop(last,a_state,s_fina) end first, last, n = nil, nil, 0 if id == math_code then current = end_of_math(current) end end - current = current.next + current = getnext(current) end if first and first == last then - last[a_state] = s_isol + setprop(last,a_state,s_isol) elseif last then - last[a_state] = s_fina + setprop(last,a_state,s_fina) end return head, done end @@ -203,234 +221,194 @@ registerotffeature { -- latin methods.latn = analyzers.setstate - --- This info eventually can go into char-def and we will have a state --- table for generic then (unicode recognized all states but in practice --- only has only --- --- isolated : isol --- final : isol_fina --- medial : isol_fina_medi_init --- --- so in practice, without analyzer it's rather useless info which is --- why having it in char-def makes only sense for special purposes (like) --- like tracing cq. visualizing. - -local tatweel = 0x0640 -local zwnj = 0x200C -local zwj = 0x200D - -local isolated = { -- isol - [0x0600] = true, [0x0601] = true, [0x0602] = true, [0x0603] = true, - [0x0604] = true, - [0x0608] = true, [0x060B] = true, [0x0621] = true, [0x0674] = true, - [0x06DD] = true, - -- mandaic - [0x0856] = true, [0x0858] = true, [0x0857] = true, - -- n'ko - [0x07FA] = true, - -- also here: - [zwnj] = true, -} - -local final = { -- isol_fina - [0x0622] = true, [0x0623] = true, [0x0624] = true, [0x0625] = true, - [0x0627] = true, [0x0629] = true, [0x062F] = true, [0x0630] = true, - [0x0631] = true, [0x0632] = true, [0x0648] = true, [0x0671] = true, - [0x0672] = true, [0x0673] = true, [0x0675] = true, [0x0676] = true, - [0x0677] = true, [0x0688] = true, [0x0689] = true, [0x068A] = true, - [0x068B] = true, [0x068C] = true, [0x068D] = true, [0x068E] = true, - [0x068F] = true, [0x0690] = true, [0x0691] = true, [0x0692] = true, - [0x0693] = true, [0x0694] = true, [0x0695] = true, [0x0696] = true, - [0x0697] = true, [0x0698] = true, [0x0699] = true, [0x06C0] = true, - [0x06C3] = true, [0x06C4] = true, [0x06C5] = true, [0x06C6] = true, - [0x06C7] = true, [0x06C8] = true, [0x06C9] = true, [0x06CA] = true, - [0x06CB] = true, [0x06CD] = true, [0x06CF] = true, [0x06D2] = true, - [0x06D3] = true, [0x06D5] = true, [0x06EE] = true, [0x06EF] = true, - [0x0759] = true, [0x075A] = true, [0x075B] = true, [0x076B] = true, - [0x076C] = true, [0x0771] = true, [0x0773] = true, [0x0774] = true, - [0x0778] = true, [0x0779] = true, - [0x08AA] = true, [0x08AB] = true, [0x08AC] = true, - [0xFEF5] = true, [0xFEF7] = true, [0xFEF9] = true, [0xFEFB] = true, - -- syriac - [0x0710] = true, [0x0715] = true, [0x0716] = true, [0x0717] = true, - [0x0718] = true, [0x0719] = true, [0x0728] = true, [0x072A] = true, - [0x072C] = true, [0x071E] = true, - [0x072F] = true, [0x074D] = true, - -- mandaic - [0x0840] = true, [0x0849] = true, [0x0854] = true, [0x0846] = true, - [0x084F] = true -} - -local medial = { -- isol_fina_medi_init - [0x0626] = true, [0x0628] = true, [0x062A] = true, [0x062B] = true, - [0x062C] = true, [0x062D] = true, [0x062E] = true, [0x0633] = true, - [0x0634] = true, [0x0635] = true, [0x0636] = true, [0x0637] = true, - [0x0638] = true, [0x0639] = true, [0x063A] = true, [0x063B] = true, - [0x063C] = true, [0x063D] = true, [0x063E] = true, [0x063F] = true, - [0x0641] = true, [0x0642] = true, [0x0643] = true, - [0x0644] = true, [0x0645] = true, [0x0646] = true, [0x0647] = true, - [0x0649] = true, [0x064A] = true, [0x066E] = true, [0x066F] = true, - [0x0678] = true, [0x0679] = true, [0x067A] = true, [0x067B] = true, - [0x067C] = true, [0x067D] = true, [0x067E] = true, [0x067F] = true, - [0x0680] = true, [0x0681] = true, [0x0682] = true, [0x0683] = true, - [0x0684] = true, [0x0685] = true, [0x0686] = true, [0x0687] = true, - [0x069A] = true, [0x069B] = true, [0x069C] = true, [0x069D] = true, - [0x069E] = true, [0x069F] = true, [0x06A0] = true, [0x06A1] = true, - [0x06A2] = true, [0x06A3] = true, [0x06A4] = true, [0x06A5] = true, - [0x06A6] = true, [0x06A7] = true, [0x06A8] = true, [0x06A9] = true, - [0x06AA] = true, [0x06AB] = true, [0x06AC] = true, [0x06AD] = true, - [0x06AE] = true, [0x06AF] = true, [0x06B0] = true, [0x06B1] = true, - [0x06B2] = true, [0x06B3] = true, [0x06B4] = true, [0x06B5] = true, - [0x06B6] = true, [0x06B7] = true, [0x06B8] = true, [0x06B9] = true, - [0x06BA] = true, [0x06BB] = true, [0x06BC] = true, [0x06BD] = true, - [0x06BE] = true, [0x06BF] = true, [0x06C1] = true, [0x06C2] = true, - [0x06CC] = true, [0x06CE] = true, [0x06D0] = true, [0x06D1] = true, - [0x06FA] = true, [0x06FB] = true, [0x06FC] = true, [0x06FF] = true, - [0x0750] = true, [0x0751] = true, [0x0752] = true, [0x0753] = true, - [0x0754] = true, [0x0755] = true, [0x0756] = true, [0x0757] = true, - [0x0758] = true, [0x075C] = true, [0x075D] = true, [0x075E] = true, - [0x075F] = true, [0x0760] = true, [0x0761] = true, [0x0762] = true, - [0x0763] = true, [0x0764] = true, [0x0765] = true, [0x0766] = true, - [0x0767] = true, [0x0768] = true, [0x0769] = true, [0x076A] = true, - [0x076D] = true, [0x076E] = true, [0x076F] = true, [0x0770] = true, - [0x0772] = true, [0x0775] = true, [0x0776] = true, [0x0777] = true, - [0x077A] = true, [0x077B] = true, [0x077C] = true, [0x077D] = true, - [0x077E] = true, [0x077F] = true, - [0x08A0] = true, [0x08A2] = true, [0x08A4] = true, [0x08A5] = true, - [0x08A6] = true, [0x0620] = true, [0x08A8] = true, [0x08A9] = true, - [0x08A7] = true, [0x08A3] = true, - -- syriac - [0x0712] = true, [0x0713] = true, [0x0714] = true, [0x071A] = true, - [0x071B] = true, [0x071C] = true, [0x071D] = true, [0x071F] = true, - [0x0720] = true, [0x0721] = true, [0x0722] = true, [0x0723] = true, - [0x0724] = true, [0x0725] = true, [0x0726] = true, [0x0727] = true, - [0x0729] = true, [0x072B] = true, [0x072D] = true, [0x072E] = true, - [0x074E] = true, [0x074F] = true, - -- mandaic - [0x0841] = true, [0x0842] = true, [0x0843] = true, [0x0844] = true, - [0x0845] = true, [0x0847] = true, [0x0848] = true, [0x0855] = true, - [0x0851] = true, [0x084E] = true, [0x084D] = true, [0x084A] = true, - [0x084B] = true, [0x084C] = true, [0x0850] = true, [0x0852] = true, - [0x0853] = true, - -- n'ko - [0x07D7] = true, [0x07E8] = true, [0x07D9] = true, [0x07EA] = true, - [0x07CA] = true, [0x07DB] = true, [0x07CC] = true, [0x07DD] = true, - [0x07CE] = true, [0x07DF] = true, [0x07D4] = true, [0x07E5] = true, - [0x07E9] = true, [0x07E7] = true, [0x07E3] = true, [0x07E2] = true, - [0x07E0] = true, [0x07E1] = true, [0x07DE] = true, [0x07DC] = true, - [0x07D1] = true, [0x07DA] = true, [0x07D8] = true, [0x07D6] = true, - [0x07D2] = true, [0x07D0] = true, [0x07CF] = true, [0x07CD] = true, - [0x07CB] = true, [0x07D3] = true, [0x07E4] = true, [0x07D5] = true, - [0x07E6] = true, - -- also here: - [tatweel]= true, - [zwj] = true, -} +-------.dflt = analyzers.setstate % can be an option or just the default local arab_warned = { } --- todo: gref - local function warning(current,what) - local char = current.char + local char = getchar(current) if not arab_warned[char] then log.report("analyze","arab: character %C has no %a class",char,what) arab_warned[char] = true end end --- potential optimization: local medial_final = table.merged(medial,final) +local mappers = { + l = s_init, -- left + d = s_medi, -- double + c = s_medi, -- joiner + r = s_fina, -- right + u = s_isol, -- nonjoiner +} -local function finish(first,last) - if last then - if first == last then - local fc = first.char - if medial[fc] or final[fc] then - first[a_state] = s_isol - else - warning(first,"isol") - first[a_state] = s_error +local classifiers = { } -- we can also use this trick for devanagari + +local first_arabic, last_arabic = characters.blockrange("arabic") +local first_syriac, last_syriac = characters.blockrange("syriac") +local first_mandiac, last_mandiac = characters.blockrange("mandiac") +local first_nko, last_nko = characters.blockrange("nko") + +table.setmetatableindex(classifiers,function(t,k) + local c = chardata[k] + local v = false + if c then + local arabic = c.arabic + if arabic then + v = mappers[arabic] + if not v then + log.report("analyze","error in mapping arabic %C",k) + -- error + v = false end - else - local lc = last.char - if medial[lc] or final[lc] then - -- if laststate == 1 or laststate == 2 or laststate == 4 then - last[a_state] = s_fina + elseif k >= first_arabic and k <= last_arabic or k >= first_syriac and k <= last_syriac or + k >= first_mandiac and k <= last_mandiac or k >= first_nko and k <= last_nko then + if categories[k] == "mn" then + v = s_mark else - warning(last,"fina") - last[a_state] = s_error + v = s_rest end - end - first, last = nil, nil - elseif first then - -- first and last are either both set so we never com here - local fc = first.char - if medial[fc] or final[fc] then - first[a_state] = s_isol else - warning(first,"isol") - first[a_state] = s_error end - first = nil end - return first, last -end + t[k] = v + return v +end) function methods.arab(head,font,attr) - local useunicodemarks = analyzers.useunicodemarks - local tfmdata = fontdata[font] - local marks = tfmdata.resources.marks - local first, last, current, done = nil, nil, head, false + local first, last = nil, nil + local c_first, c_last = nil, nil + local current, done = head, false + current = tonut(current) while current do - local id = current.id - if id == glyph_code and current.font == font and current.subtype<256 and not current[a_state] then + local id = getid(current) + if id == glyph_code and getfont(current) == font and getsubtype(current)<256 and not getprop(current,a_state) then done = true - local char = current.char - if marks[char] or (useunicodemarks and categories[char] == "mn") then - current[a_state] = s_mark - elseif isolated[char] then -- can be zwj or zwnj too - first, last = finish(first,last) - current[a_state] = s_isol - first, last = nil, nil - elseif not first then - if medial[char] then - current[a_state] = s_init - first, last = first or current, current - elseif final[char] then - current[a_state] = s_isol + local char = getchar(current) + local classifier = classifiers[char] + if not classifier then + if last then + if c_last == s_medi or c_last == s_fina then + setprop(last,a_state,s_fina) + else + warning(last,"fina") + setprop(last,a_state,s_error) + end + first, last = nil, nil + elseif first then + if c_first == s_medi or c_first == s_fina then + setprop(first,a_state,s_isol) + else + warning(first,"isol") + setprop(first,a_state,s_error) + end + first = nil + end + elseif classifier == s_mark then + setprop(current,a_state,s_mark) + elseif classifier == s_isol then + if last then + if c_last == s_medi or c_last == s_fina then + setprop(last,a_state,s_fina) + else + warning(last,"fina") + setprop(last,a_state,s_error) + end first, last = nil, nil - else -- no arab - first, last = finish(first,last) + elseif first then + if c_first == s_medi or c_first == s_fina then + setprop(first,a_state,s_isol) + else + warning(first,"isol") + setprop(first,a_state,s_error) + end + first = nil end - elseif medial[char] then - first, last = first or current, current - current[a_state] = s_medi - elseif final[char] then - if not last[a_state] == s_init then - -- tricky, we need to check what last may be ! - last[a_state] = s_medi + setprop(current,a_state,s_isol) + elseif classifier == s_medi then + if first then + last = current + c_last = classifier + setprop(current,a_state,s_medi) + else + setprop(current,a_state,s_init) + first = current + c_first = classifier + end + elseif classifier == s_fina then + if last then + if getprop(last,a_state) ~= s_init then + setprop(last,a_state,s_medi) + end + setprop(current,a_state,s_fina) + first, last = nil, nil + elseif first then + -- if getprop(first,a_state) ~= s_init then + -- -- needs checking + -- setprop(first,a_state,s_medi) + -- end + setprop(current,a_state,s_fina) + first = nil + else + setprop(current,a_state,s_isol) + end + else -- classifier == s_rest + setprop(current,a_state,s_rest) + if last then + if c_last == s_medi or c_last == s_fina then + setprop(last,a_state,s_fina) + else + warning(last,"fina") + setprop(last,a_state,s_error) + end + first, last = nil, nil + elseif first then + if c_first == s_medi or c_first == s_fina then + setprop(first,a_state,s_isol) + else + warning(first,"isol") + setprop(first,a_state,s_error) + end + first = nil end - current[a_state] = s_fina - first, last = nil, nil - elseif char >= 0x0600 and char <= 0x06FF then -- needs checking - current[a_state] = s_rest - first, last = finish(first,last) - else -- no - first, last = finish(first,last) end else - if first or last then - first, last = finish(first,last) + if last then + if c_last == s_medi or c_last == s_fina then + setprop(last,a_state,s_fina) + else + warning(last,"fina") + setprop(last,a_state,s_error) + end + first, last = nil, nil + elseif first then + if c_first == s_medi or c_first == s_fina then + setprop(first,a_state,s_isol) + else + warning(first,"isol") + setprop(first,a_state,s_error) + end + first = nil end - if id == math_code then + if id == math_code then -- a bit duplicate as we test for glyphs twice current = end_of_math(current) end end - current = current.next + current = getnext(current) end - if first or last then - finish(first,last) + if last then + if c_last == s_medi or c_last == s_fina then + setprop(last,a_state,s_fina) + else + warning(last,"fina") + setprop(last,a_state,s_error) + end + elseif first then + if c_first == s_medi or c_first == s_fina then + setprop(first,a_state,s_isol) + else + warning(first,"isol") + setprop(first,a_state,s_error) + end end return head, done end diff --git a/Master/texmf-dist/tex/context/base/font-otb.lua b/Master/texmf-dist/tex/context/base/font-otb.lua index 2e98d3ecbb9..4e955a19774 100644 --- a/Master/texmf-dist/tex/context/base/font-otb.lua +++ b/Master/texmf-dist/tex/context/base/font-otb.lua @@ -7,7 +7,7 @@ if not modules then modules = { } end modules ['font-otb'] = { } local concat = table.concat local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip -local type, next, tonumber, tostring = type, next, tonumber, tostring +local type, next, tonumber, tostring, rawget = type, next, tonumber, tostring, rawget local lpegmatch = lpeg.match local utfchar = utf.char @@ -63,40 +63,40 @@ local function gref(descriptions,n) end end -local function cref(feature,lookupname) +local function cref(feature,lookuptags,lookupname) if lookupname then - return formatters["feature %a, lookup %a"](feature,lookupname) + return formatters["feature %a, lookup %a"](feature,lookuptags[lookupname]) else return formatters["feature %a"](feature) end end -local function report_alternate(feature,lookupname,descriptions,unicode,replacement,value,comment) +local function report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,comment) report_prepare("%s: base alternate %s => %s (%S => %S)", - cref(feature,lookupname), + cref(feature,lookuptags,lookupname), gref(descriptions,unicode), replacement and gref(descriptions,replacement), value, comment) end -local function report_substitution(feature,lookupname,descriptions,unicode,substitution) +local function report_substitution(feature,lookuptags,lookupname,descriptions,unicode,substitution) report_prepare("%s: base substitution %s => %S", - cref(feature,lookupname), + cref(feature,lookuptags,lookupname), gref(descriptions,unicode), gref(descriptions,substitution)) end -local function report_ligature(feature,lookupname,descriptions,unicode,ligature) +local function report_ligature(feature,lookuptags,lookupname,descriptions,unicode,ligature) report_prepare("%s: base ligature %s => %S", - cref(feature,lookupname), + cref(feature,lookuptags,lookupname), gref(descriptions,ligature), gref(descriptions,unicode)) end -local function report_kern(feature,lookupname,descriptions,unicode,otherunicode,value) +local function report_kern(feature,lookuptags,lookupname,descriptions,unicode,otherunicode,value) report_prepare("%s: base kern %s + %s => %S", - cref(feature,lookupname), + cref(feature,lookuptags,lookupname), gref(descriptions,unicode), gref(descriptions,otherunicode), value) @@ -181,7 +181,7 @@ local function finalize_ligatures(tfmdata,ligatures) local characters = tfmdata.characters local descriptions = tfmdata.descriptions local resources = tfmdata.resources - local unicodes = resources.unicodes + local unicodes = resources.unicodes -- we use rawget in order to avoid bulding the table local private = resources.private local alldone = false while not alldone do @@ -217,12 +217,12 @@ local function finalize_ligatures(tfmdata,ligatures) local secondname = firstname .. "_" .. secondcode if i == size - 1 then target = unicode - if not unicodes[secondname] then + if not rawget(unicodes,secondname) then unicodes[secondname] = unicode -- map final ligature onto intermediates end okay = true else - target = unicodes[secondname] + target = rawget(unicodes,secondname) if not target then break end @@ -258,6 +258,7 @@ local function finalize_ligatures(tfmdata,ligatures) end end resources.private = private + return true end end @@ -265,13 +266,14 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local characters = tfmdata.characters local descriptions = tfmdata.descriptions local resources = tfmdata.resources + local properties = tfmdata.properties local changed = tfmdata.changed - local unicodes = resources.unicodes local lookuphash = resources.lookuphash local lookuptypes = resources.lookuptypes + local lookuptags = resources.lookuptags local ligatures = { } - local alternate = tonumber(value) + local alternate = tonumber(value) or true and 1 local defaultalt = otf.defaultbasealternate local trace_singles = trace_baseinit and trace_singles @@ -279,39 +281,39 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local trace_ligatures = trace_baseinit and trace_ligatures local actions = { - substitution = function(lookupdata,lookupname,description,unicode) + substitution = function(lookupdata,lookuptags,lookupname,description,unicode) if trace_singles then - report_substitution(feature,lookupname,descriptions,unicode,lookupdata) + report_substitution(feature,lookuptags,lookupname,descriptions,unicode,lookupdata) end changed[unicode] = lookupdata end, - alternate = function(lookupdata,lookupname,description,unicode) + alternate = function(lookupdata,lookuptags,lookupname,description,unicode) local replacement = lookupdata[alternate] if replacement then changed[unicode] = replacement if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal") + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,"normal") end elseif defaultalt == "first" then replacement = lookupdata[1] changed[unicode] = replacement if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,defaultalt) end elseif defaultalt == "last" then replacement = lookupdata[#data] if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,defaultalt) end else if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown") + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,"unknown") end end end, - ligature = function(lookupdata,lookupname,description,unicode) + ligature = function(lookupdata,lookuptags,lookupname,description,unicode) if trace_ligatures then - report_ligature(feature,lookupname,descriptions,unicode,lookupdata) + report_ligature(feature,lookuptags,lookupname,descriptions,unicode,lookupdata) end ligatures[#ligatures+1] = { unicode, lookupdata } end, @@ -328,7 +330,7 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local lookuptype = lookuptypes[lookupname] local action = actions[lookuptype] if action then - action(lookupdata,lookupname,description,unicode) + action(lookupdata,lookuptags,lookupname,description,unicode) end end end @@ -343,24 +345,25 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local action = actions[lookuptype] if action then for i=1,#lookuplist do - action(lookuplist[i],lookupname,description,unicode) + action(lookuplist[i],lookuptags,lookupname,description,unicode) end end end end end end - - finalize_ligatures(tfmdata,ligatures) + properties.hasligatures = finalize_ligatures(tfmdata,ligatures) end local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist) -- todo what kind of kerns, currently all local characters = tfmdata.characters local descriptions = tfmdata.descriptions local resources = tfmdata.resources - local unicodes = resources.unicodes + local properties = tfmdata.properties + local lookuptags = resources.lookuptags local sharedkerns = { } local traceindeed = trace_baseinit and trace_kerns + local haskerns = false for unicode, character in next, characters do local description = descriptions[unicode] local rawkerns = description.kerns -- shared @@ -384,13 +387,13 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist newkerns = { [otherunicode] = value } done = true if traceindeed then - report_kern(feature,lookup,descriptions,unicode,otherunicode,value) + report_kern(feature,lookuptags,lookup,descriptions,unicode,otherunicode,value) end elseif not newkerns[otherunicode] then -- first wins newkerns[otherunicode] = value done = true if traceindeed then - report_kern(feature,lookup,descriptions,unicode,otherunicode,value) + report_kern(feature,lookuptags,lookup,descriptions,unicode,otherunicode,value) end end end @@ -399,12 +402,14 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist if done then sharedkerns[rawkerns] = newkerns character.kerns = newkerns -- no empty assignments + haskerns = true else sharedkerns[rawkerns] = false end end end end + properties.haskerns = haskerns end basemethods.independent = { @@ -434,13 +439,13 @@ local function make_1(present,tree,name) end end -local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done,lookupname) +local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done,lookuptags,lookupname) for k, v in next, tree do if k == "ligature" then local character = characters[preceding] if not character then if trace_baseinit then - report_prepare("weird ligature in lookup %a, current %C, preceding %C",lookupname,v,preceding) + report_prepare("weird ligature in lookup %a, current %C, preceding %C",lookuptags[lookupname],v,preceding) end character = makefake(tfmdata,name,present) end @@ -461,7 +466,7 @@ local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,don else local code = present[name] or unicode local name = name .. "_" .. k - make_2(present,tfmdata,characters,v,name,code,k,done,lookupname) + make_2(present,tfmdata,characters,v,name,code,k,done,lookuptags,lookupname) end end end @@ -473,9 +478,10 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local changed = tfmdata.changed local lookuphash = resources.lookuphash local lookuptypes = resources.lookuptypes + local lookuptags = resources.lookuptags local ligatures = { } - local alternate = tonumber(value) + local alternate = tonumber(value) or true and 1 local defaultalt = otf.defaultbasealternate local trace_singles = trace_baseinit and trace_singles @@ -489,36 +495,36 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis for unicode, data in next, lookupdata do if lookuptype == "substitution" then if trace_singles then - report_substitution(feature,lookupname,descriptions,unicode,data) + report_substitution(feature,lookuptags,lookupname,descriptions,unicode,data) end changed[unicode] = data elseif lookuptype == "alternate" then - local replacement = data[alternate] + local replacement = data[alternate] if replacement then changed[unicode] = replacement if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal") + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,"normal") end elseif defaultalt == "first" then replacement = data[1] changed[unicode] = replacement if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,defaultalt) end elseif defaultalt == "last" then replacement = data[#data] if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,defaultalt) end else if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown") + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,"unknown") end end elseif lookuptype == "ligature" then ligatures[#ligatures+1] = { unicode, data, lookupname } if trace_ligatures then - report_ligature(feature,lookupname,descriptions,unicode,data) + report_ligature(feature,lookuptags,lookupname,descriptions,unicode,data) end end end @@ -541,7 +547,7 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis for i=1,nofligatures do local ligature = ligatures[i] local unicode, tree, lookupname = ligature[1], ligature[2], ligature[3] - make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,lookupname) + make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,lookuptags,lookupname) end end @@ -552,11 +558,11 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist local characters = tfmdata.characters local descriptions = tfmdata.descriptions local resources = tfmdata.resources + local properties = tfmdata.properties local lookuphash = resources.lookuphash + local lookuptags = resources.lookuptags local traceindeed = trace_baseinit and trace_kerns - -- check out this sharedkerns trickery - for l=1,#lookuplist do local lookupname = lookuplist[l] local lookupdata = lookuphash[lookupname] @@ -571,7 +577,7 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist for otherunicode, kern in next, data do if not kerns[otherunicode] and kern ~= 0 then kerns[otherunicode] = kern - report_kern(feature,lookup,descriptions,unicode,otherunicode,kern) + report_kern(feature,lookuptags,lookup,descriptions,unicode,otherunicode,kern) end end else @@ -602,7 +608,7 @@ local function featuresinitializer(tfmdata,value) if true then -- value then local starttime = trace_preparing and os.clock() local features = tfmdata.shared.features - local fullname = trace_preparing and tfmdata.properties.fullname + local fullname = tfmdata.properties.fullname or "?" if features then applybasemethod("initializehashes",tfmdata) local collectlookups = otf.collectlookups @@ -648,21 +654,22 @@ local function featuresinitializer(tfmdata,value) if order then for i=1,#order do -- local feature = order[i] - if features[feature] then + local value = features[feature] + if value then local validlookups, lookuplist = collectlookups(rawdata,feature,script,language) if not validlookups then -- skip elseif basesubstitutions and basesubstitutions[feature] then if trace_preparing then - report_prepare("filtering base feature %a for %a",feature,fullname) + report_prepare("filtering base %s feature %a for %a with value %a","sub",feature,fullname,value) end applybasemethod("preparesubstitutions",tfmdata,feature,value,validlookups,lookuplist) registerbasefeature(feature,value) elseif basepositionings and basepositionings[feature] then if trace_preparing then - report_prepare("filtering base feature %a for %a",feature,fullname) + report_prepare("filtering base %a feature %a for %a with value %a","pos",feature,fullname,value) end - applybasemethod("preparepositionings",tfmdata,feature,features[feature],validlookups,lookuplist) + applybasemethod("preparepositionings",tfmdata,feature,value,validlookups,lookuplist) registerbasefeature(feature,value) end end diff --git a/Master/texmf-dist/tex/context/base/font-otf.lua b/Master/texmf-dist/tex/context/base/font-otf.lua index 0a5d1cfea04..85eebaaebd0 100644 --- a/Master/texmf-dist/tex/context/base/font-otf.lua +++ b/Master/texmf-dist/tex/context/base/font-otf.lua @@ -24,7 +24,9 @@ local reversed, concat, remove, sortedkeys = table.reversed, table.concat, table local ioflush = io.flush local fastcopy, tohash, derivetable = table.fastcopy, table.tohash, table.derive local formatters = string.formatters +local P, R, S, C, Ct, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.match +local setmetatableindex = table.setmetatableindex local allocate = utilities.storage.allocate local registertracker = trackers.register local registerdirective = directives.register @@ -33,13 +35,16 @@ local stoptiming = statistics.stoptiming local elapsedtime = statistics.elapsedtime local findbinfile = resolvers.findbinfile -local trace_private = false registertracker("otf.private", function(v) trace_private = v end) -local trace_loading = false registertracker("otf.loading", function(v) trace_loading = v end) -local trace_features = false registertracker("otf.features", function(v) trace_features = v end) -local trace_dynamics = false registertracker("otf.dynamics", function(v) trace_dynamics = v end) -local trace_sequences = false registertracker("otf.sequences", function(v) trace_sequences = v end) -local trace_markwidth = false registertracker("otf.markwidth", function(v) trace_markwidth = v end) -local trace_defining = false registertracker("fonts.defining", function(v) trace_defining = v end) +local trace_private = false registertracker("otf.private", function(v) trace_private = v end) +local trace_loading = false registertracker("otf.loading", function(v) trace_loading = v end) +local trace_features = false registertracker("otf.features", function(v) trace_features = v end) +local trace_dynamics = false registertracker("otf.dynamics", function(v) trace_dynamics = v end) +local trace_sequences = false registertracker("otf.sequences", function(v) trace_sequences = v end) +local trace_markwidth = false registertracker("otf.markwidth", function(v) trace_markwidth = v end) +local trace_defining = false registertracker("fonts.defining", function(v) trace_defining = v end) + +local compact_lookups = true registertracker("otf.compactlookups", function(v) compact_lookups = v end) +local purge_names = true registertracker("otf.purgenames", function(v) purge_names = v end) local report_otf = logs.reporter("fonts","otf loading") @@ -48,13 +53,18 @@ local otf = fonts.handlers.otf otf.glists = { "gsub", "gpos" } -otf.version = 2.755 -- beware: also sync font-mis.lua +otf.version = 2.803 -- beware: also sync font-mis.lua otf.cache = containers.define("fonts", "otf", otf.version, true) -local fontdata = fonts.hashes.identifiers +local hashes = fonts.hashes +local definers = fonts.definers +local readers = fonts.readers +local constructors = fonts.constructors + +local fontdata = hashes and hashes.identifiers local chardata = characters and characters.data -- not used -local otffeatures = fonts.constructors.newfeatures("otf") +local otffeatures = constructors.newfeatures("otf") local registerotffeature = otffeatures.register local enhancers = allocate() @@ -62,13 +72,8 @@ otf.enhancers = enhancers local patches = { } enhancers.patches = patches -local definers = fonts.definers -local readers = fonts.readers -local constructors = fonts.constructors - local forceload = false local cleanup = 0 -- mk: 0=885M 1=765M 2=735M (regular run 730M) -local usemetatables = false -- .4 slower on mk but 30 M less mem so we might change the default -- will be directive local packdata = true local syncspace = true local forcenotdef = false @@ -80,7 +85,12 @@ local applyruntimefixes = fonts.treatments and fonts.treatments.applyfixes local wildcard = "*" local default = "dflt" -local fontloaderfields = fontloader.fields +local fontloader = fontloader +local open_font = fontloader.open +local close_font = fontloader.close +local font_fields = fontloader.fields +local apply_featurefile = fontloader.apply_featurefile + local mainfields = nil local glyphfields = nil -- not used yet @@ -93,11 +103,11 @@ formats.dfont = "truetype" registerdirective("fonts.otf.loader.cleanup", function(v) cleanup = tonumber(v) or (v and 1) or 0 end) registerdirective("fonts.otf.loader.force", function(v) forceload = v end) -registerdirective("fonts.otf.loader.usemetatables", function(v) usemetatables = v end) registerdirective("fonts.otf.loader.pack", function(v) packdata = v end) registerdirective("fonts.otf.loader.syncspace", function(v) syncspace = v end) registerdirective("fonts.otf.loader.forcenotdef", function(v) forcenotdef = v end) registerdirective("fonts.otf.loader.overloadkerns", function(v) overloadkerns = v end) +-----------------("fonts.otf.loader.alldimensions", function(v) alldimensions = v end) function otf.fileformat(filename) local leader = lower(io.loadchunk(filename,4)) @@ -134,7 +144,7 @@ local function load_featurefile(raw,featurefile) if trace_loading then report_otf("using featurefile %a", featurefile) end - fontloader.apply_featurefile(raw, featurefile) + apply_featurefile(raw, featurefile) end end @@ -203,7 +213,6 @@ local valid_fields = table.tohash { "extrema_bound", "familyname", "fontname", - "fontname", "fontstyle_id", "fontstyle_name", "fullname", @@ -256,7 +265,7 @@ local ordered_enhancers = { "analyze glyphs", "analyze math", - "prepare tounicode", -- maybe merge with prepare + -- "prepare tounicode", "reorganize lookups", "reorganize mark classes", @@ -275,10 +284,15 @@ local ordered_enhancers = { "check metadata", "check extra features", -- after metadata + "prepare tounicode", + "check encoding", -- moved "add duplicates", "cleanup tables", + + "compact lookups", + "purge names", } --[[ldx-- @@ -430,12 +444,12 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone report_otf("loading %a, hash %a",filename,hash) local fontdata, messages if sub then - fontdata, messages = fontloader.open(filename,sub) + fontdata, messages = open_font(filename,sub) else - fontdata, messages = fontloader.open(filename) + fontdata, messages = open_font(filename) end if fontdata then - mainfields = mainfields or (fontloaderfields and fontloaderfields(fontdata)) + mainfields = mainfields or (font_fields and font_fields(fontdata)) end if trace_loading and messages and #messages > 0 then if type(messages) == "string" then @@ -480,6 +494,8 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone lookuptypes = { }, }, + warnings = { + }, metadata = { -- raw metadata, not to be used }, @@ -492,7 +508,7 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone }, helpers = { -- might go away tounicodelist = splitter, - tounicodetable = lpeg.Ct(splitter), + tounicodetable = Ct(splitter), }, } starttiming(data) @@ -517,7 +533,7 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone report_otf("preprocessing and caching time %s, packtime %s", elapsedtime(data),packdata and elapsedtime(packtime) or 0) end - fontloader.close(fontdata) -- free memory + close_font(fontdata) -- free memory if cleanup > 3 then collectgarbage("collect") end @@ -535,6 +551,39 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone report_otf("loading from cache using hash %a",hash) end enhance("unpack",data,filename,nil,false) + -- + local resources = data.resources + local lookuptags = resources.lookuptags + local unicodes = resources.unicodes + if not lookuptags then + lookuptags = { } + resources.lookuptags = lookuptags + end + setmetatableindex(lookuptags,function(t,k) + local v = type(k) == "number" and ("lookup " .. k) or k + t[k] = v + return v + end) + if not unicodes then + unicodes = { } + resources.unicodes = unicodes + setmetatableindex(unicodes,function(t,k) + -- use rawget when no table has to be built + setmetatableindex(unicodes,nil) + for u, d in next, data.descriptions do + local n = d.name + if n then + t[n] = u + -- report_otf("accessing known name %a",k) + else + -- report_otf("accessing unknown name %a",k) + end + end + return rawget(t,k) + end) + end + constructors.addcoreunicodes(unicodes) -- do we really need this? + -- if applyruntimefixes then applyruntimefixes(filename,data) end @@ -576,31 +625,29 @@ actions["add dimensions"] = function(data,filename) local defaultheight = resources.defaultheight or 0 local defaultdepth = resources.defaultdepth or 0 local basename = trace_markwidth and file.basename(filename) - if usemetatables then - for _, d in next, descriptions do - local wd = d.width - if not wd then - d.width = defaultwidth - elseif trace_markwidth and wd ~= 0 and d.class == "mark" then - report_otf("mark %a with width %b found in %a",d.name or "This module is a bit more split up that I'd like but since we also want to test @@ -121,7 +134,6 @@ results in different tables.
-- chainmore : multiple substitutions triggered by contextual lookup (e.g. fij -> f + ij) -- -- remark: the 'not implemented yet' variants will be done when we have fonts that use them --- remark: we need to check what to do with discretionaries -- We used to have independent hashes for lookups but as the tags are unique -- we now use only one hash. If needed we can have multiple again but in that @@ -129,16 +141,14 @@ results in different tables. -- Todo: make plugin feature that operates on char/glyphnode arrays -local concat, insert, remove = table.concat, table.insert, table.remove -local gmatch, gsub, find, match, lower, strip = string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip -local type, next, tonumber, tostring = type, next, tonumber, tostring -local lpegmatch = lpeg.match +local type, next, tonumber = type, next, tonumber local random = math.random local formatters = string.formatters local logs, trackers, nodes, attributes = logs, trackers, nodes, attributes -local registertracker = trackers.register +local registertracker = trackers.register +local registerdirective = directives.register local fonts = fonts local otf = fonts.handlers.otf @@ -160,12 +170,25 @@ local trace_steps = false registertracker("otf.steps", function(v local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end) local trace_directions = false registertracker("otf.directions", function(v) trace_directions = v end) +local trace_kernruns = false registertracker("otf.kernruns", function(v) trace_kernruns = v end) +local trace_discruns = false registertracker("otf.discruns", function(v) trace_discruns = v end) +local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end) + +local quit_on_no_replacement = true -- maybe per font +local check_discretionaries = true -- "trace" +local zwnjruns = true + +registerdirective("otf.zwnjruns", function(v) zwnjruns = v end) +registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement = value end) + + local report_direct = logs.reporter("fonts","otf direct") local report_subchain = logs.reporter("fonts","otf subchain") local report_chain = logs.reporter("fonts","otf chain") local report_process = logs.reporter("fonts","otf process") local report_prepare = logs.reporter("fonts","otf prepare") local report_warning = logs.reporter("fonts","otf warning") +local report_run = logs.reporter("fonts","otf run") registertracker("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end) registertracker("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end) @@ -194,12 +217,18 @@ local getfont = nuts.getfont local getsubtype = nuts.getsubtype local getchar = nuts.getchar +local insert_node_before = nuts.insert_before local insert_node_after = nuts.insert_after local delete_node = nuts.delete +local remove_node = nuts.remove local copy_node = nuts.copy +local copy_node_list = nuts.copy_list local find_node_tail = nuts.tail local flush_node_list = nuts.flush_list +local free_node = nuts.free local end_of_math = nuts.end_of_math +local traverse_nodes = nuts.traverse +local traverse_id = nuts.traverse_id local setmetatableindex = table.setmetatableindex @@ -223,26 +252,31 @@ local dir_code = whatcodes.dir local localpar_code = whatcodes.localpar local discretionary_code = disccodes.discretionary +local regular_code = disccodes.regular +local automatic_code = disccodes.automatic local ligature_code = glyphcodes.ligature local privateattribute = attributes.private -- Something is messed up: we have two mark / ligature indices, one at the injection --- end and one here ... this is bases in KE's patches but there is something fishy +-- end and one here ... this is based on KE's patches but there is something fishy -- there as I'm pretty sure that for husayni we need some connection (as it's much -- more complex than an average font) but I need proper examples of all cases, not -- of only some. local a_state = privateattribute('state') -local a_cursbase = privateattribute('cursbase') -- to be checked -local a_ligacomp = privateattribute('ligacomp') -- assigned here (ideally it should be combined) +local a_cursbase = privateattribute('cursbase') -- to be checked, probably can go local injections = nodes.injections local setmark = injections.setmark local setcursive = injections.setcursive local setkern = injections.setkern local setpair = injections.setpair +local resetinjection = injections.reset +local copyinjection = injections.copy +local setligaindex = injections.setligaindex +local getligaindex = injections.getligaindex local cursonce = true @@ -267,6 +301,7 @@ local currentfont = false local lookuptable = false local anchorlookups = false local lookuptypes = false +local lookuptags = false local handlers = { } local rlmode = 0 local featurevalue = false @@ -321,20 +356,20 @@ end local function cref(kind,chainname,chainlookupname,lookupname,index) -- not in the mood to alias f_ if index then - return formatters["feature %a, chain %a, sub %a, lookup %a, index %a"](kind,chainname,chainlookupname,lookupname,index) + return formatters["feature %a, chain %a, sub %a, lookup %a, index %a"](kind,chainname,chainlookupname,lookuptags[lookupname],index) elseif lookupname then - return formatters["feature %a, chain %a, sub %a, lookup %a"](kind,chainname,chainlookupname,lookupname) + return formatters["feature %a, chain %a, sub %a, lookup %a"](kind,chainname,chainlookupname,lookuptags[lookupname]) elseif chainlookupname then - return formatters["feature %a, chain %a, sub %a"](kind,chainname,chainlookupname) + return formatters["feature %a, chain %a, sub %a"](kind,lookuptags[chainname],lookuptags[chainlookupname]) elseif chainname then - return formatters["feature %a, chain %a"](kind,chainname) + return formatters["feature %a, chain %a"](kind,lookuptags[chainname]) else return formatters["feature %a"](kind) end end local function pref(kind,lookupname) - return formatters["feature %a, lookup %a"](kind,lookupname) + return formatters["feature %a, lookup %a"](kind,lookuptags[lookupname]) end -- We can assume that languages that use marks are not hyphenated. We can also assume @@ -351,10 +386,60 @@ local function copy_glyph(g) -- next and prev are untouched ! if components then setfield(g,"components",nil) local n = copy_node(g) + copyinjection(n,g) -- we need to preserve the lig indices setfield(g,"components",components) return n else - return copy_node(g) + local n = copy_node(g) + copyinjection(n,g) -- we need to preserve the lig indices + return n + end +end + +-- temp here (context) + +local function collapse_disc(start,next) + local replace1 = getfield(start,"replace") + local replace2 = getfield(next,"replace") + if replace1 and replace2 then + local pre2 = getfield(next,"pre") + local post2 = getfield(next,"post") + setfield(replace1,"prev",nil) + if pre2 then + local pre1 = getfield(start,"pre") + if pre1 then + flush_node_list(pre1) + end + local pre1 = copy_node_list(replace1) + local tail1 = find_node_tail(pre1) + setfield(tail1,"next",pre2) + setfield(pre2,"prev",tail1) + setfield(start,"pre",pre1) + setfield(next,"pre",nil) + else + setfield(start,"pre",nil) + end + if post2 then + local post1 = getfield(start,"post") + if post1 then + flush_node_list(post1) + end + setfield(start,"post",post2) + else + setfield(start,"post",nil) + end + local tail1 = find_node_tail(replace1) + setfield(tail1,"next",replace2) + setfield(replace2,"prev",tail1) + setfield(start,"replace",replace1) + setfield(next,"replace",nil) + -- + local nextnext = getnext(next) + setfield(nextnext,"prev",start) + setfield(start,"next",nextnext) + free_node(next) + else + -- maybe remove it end end @@ -372,6 +457,7 @@ local function markstoligature(kind,lookupname,head,start,stop,char) if head == start then head = base end + resetinjection(base) setfield(base,"char",char) setfield(base,"subtype",ligature_code) setfield(base,"components",start) @@ -412,24 +498,99 @@ local function getcomponentindex(start) end end --- eventually we will do positioning in an other way (needs addional w/h/d fields) +local a_noligature = attributes.private("noligature") +local prehyphenchar = languages and languages.prehyphenchar +local posthyphenchar = languages and languages.posthyphenchar +----- preexhyphenchar = languages and languages.preexhyphenchar +----- postexhyphenchar = languages and languages.postexhyphenchar + +if prehyphenchar then + + -- okay + +elseif context then + + report_warning("no language support") os.exit() + +else + + local newlang = lang.new + local getpre = lang.prehyphenchar + local getpost = lang.posthyphenchar + -- local getpreex = lang.preexhyphenchar + -- local getpostex = lang.postexhyphenchar + + prehyphenchar = function(l) local l = newlang(l) return l and getpre (l) or -1 end + posthyphenchar = function(l) local l = newlang(l) return l and getpost (l) or -1 end + -- preexhyphenchar = function(l) local l = newlang(l) return l and getpreex (l) or -1 end + -- postexhyphenchar = function(l) local l = newlang(l) return l and getpostex(l) or -1 end + +end + +local function addhyphens(template,pre,post) + -- inserted by hyphenation algorithm + local l = getfield(template,"lang") + local p = prehyphenchar(l) + if p and p > 0 then + local c = copy_node(template) + setfield(c,"char",p) + if pre then + local t = find_node_tail(pre) + setfield(t,"next",c) + setfield(c,"prev",t) + else + pre = c + end + end + local p = posthyphenchar(l) + if p and p > 0 then + local c = copy_node(template) + setfield(c,"char",p) + if post then + -- post has a prev nesting node .. alternatively we could + local prev = getprev(post) + setfield(c,"next",post) + setfield(post,"prev",c) + if prev then + setfield(prev,"next",c) + setfield(c,"prev",prev) + end + else + post = c + end + end + return pre, post +end local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) -- brr head + if getattr(start,a_noligature) == 1 then + -- so we can do: e\noligature{ff}e e\noligature{f}fie (we only look at the first) + return head, start + end if start == stop and getchar(start) == char then + resetinjection(start) setfield(start,"char",char) return head, start end + -- needs testing (side effects): + local components = getfield(base,"components") + if components then + flush_node_list(components) + end + -- local prev = getprev(start) local next = getnext(stop) + local comp = start setfield(start,"prev",nil) setfield(stop,"next",nil) local base = copy_glyph(start) if start == head then head = base end + resetinjection(base) setfield(base,"char",char) setfield(base,"subtype",ligature_code) - setfield(base,"components",start) -- start can have components + setfield(base,"components",comp) -- start can have components .. do we need to flush? if prev then setfield(prev,"next",base) end @@ -452,11 +613,13 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun baseindex = baseindex + componentindex componentindex = getcomponentindex(start) elseif not deletemarks then -- quite fishy - setprop(start,a_ligacomp,baseindex + (getprop(start,a_ligacomp) or componentindex)) + setligaindex(start,baseindex + getligaindex(start,componentindex)) if trace_marks then - logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),getprop(start,a_ligacomp)) + logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),getligaindex(start)) end - head, current = insert_node_after(head,current,copy_node(start)) -- unlikely that mark has components + local n = copy_node(start) + copyinjection(n,start) + head, current = insert_node_after(head,current,n) -- unlikely that mark has components elseif trace_marks then logwarning("%s: delete mark %s",pref(kind,lookupname),gref(char)) end @@ -468,15 +631,79 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun while start and getid(start) == glyph_code do local char = getchar(start) if marks[char] then - setprop(start,a_ligacomp,baseindex + (getprop(start,a_ligacomp) or componentindex)) + setligaindex(start,baseindex + getligaindex(start,componentindex)) if trace_marks then - logwarning("%s: set mark %s, gets index %s",pref(kind,lookupname),gref(char),getprop(start,a_ligacomp)) + logwarning("%s: set mark %s, gets index %s",pref(kind,lookupname),gref(char),getligaindex(start)) end else break end start = getnext(start) end + else + -- discfound ... forget about marks .. probably no scripts that hyphenate and have marks + local discprev = getfield(discfound,"prev") + local discnext = getfield(discfound,"next") + if discprev and discnext then + local subtype = getsubtype(discfound) + if subtype == discretionary_code then + local pre = getfield(discfound,"pre") + local post = getfield(discfound,"post") + local replace = getfield(discfound,"replace") + if not replace then -- todo: signal simple hyphen + local prev = getfield(base,"prev") + local copied = copy_node_list(comp) + setfield(discnext,"prev",nil) -- also blocks funny assignments + setfield(discprev,"next",nil) -- also blocks funny assignments + if pre then + setfield(comp,"next",pre) + setfield(pre,"prev",comp) + end + pre = comp + if post then + local tail = find_node_tail(post) + setfield(tail,"next",discnext) + setfield(discnext,"prev",tail) + setfield(post,"prev",nil) + else + post = discnext + end + setfield(prev,"next",discfound) + setfield(next,"prev",discfound) + setfield(discfound,"next",next) + setfield(discfound,"prev",prev) + setfield(base,"next",nil) + setfield(base,"prev",nil) + setfield(base,"components",copied) + setfield(discfound,"pre",pre) + setfield(discfound,"post",post) + setfield(discfound,"replace",base) + setfield(discfound,"subtype",discretionary_code) + base = prev -- restart + end + elseif discretionary_code == regular_code then + -- local prev = getfield(base,"prev") + -- local next = getfield(base,"next") + local copied = copy_node_list(comp) + setfield(discnext,"prev",nil) -- also blocks funny assignments + setfield(discprev,"next",nil) -- also blocks funny assignments + local pre, post = addhyphens(comp,comp,discnext,subtype) -- takes from components + setfield(prev,"next",discfound) + setfield(next,"prev",discfound) + setfield(discfound,"next",next) + setfield(discfound,"prev",prev) + setfield(base,"next",nil) + setfield(base,"prev",nil) + setfield(base,"components",copied) + setfield(discfound,"pre",pre) + setfield(discfound,"post",post) + setfield(discfound,"replace",base) + setfield(discfound,"subtype",discretionary_code) + base = next -- or restart + else + -- forget about it in generic usage + end + end end return head, base end @@ -485,6 +712,7 @@ function handlers.gsub_single(head,start,kind,lookupname,replacement) if trace_singles then logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(getchar(start)),gref(replacement)) end + resetinjection(start) setfield(start,"char",replacement) return head, start, true end @@ -524,6 +752,7 @@ end local function multiple_glyphs(head,start,multiple,ignoremarks) local nofmultiples = #multiple if nofmultiples > 0 then + resetinjection(start) setfield(start,"char",multiple[1]) if nofmultiples > 1 then local sn = getnext(start) @@ -534,6 +763,7 @@ local function multiple_glyphs(head,start,multiple,ignoremarks) -- local sn = getnext(sn) -- end local n = copy_node(start) -- ignore components + resetinjection(n) setfield(n,"char",multiple[k]) setfield(n,"next",sn) setfield(n,"prev",start) @@ -560,6 +790,7 @@ function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence if trace_alternatives then logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(getchar(start)),choice,gref(choice),comment) end + resetinjection(start) setfield(start,"char",choice) else if trace_alternatives then @@ -577,7 +808,7 @@ function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence) end function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) - local s, stop, discfound = getnext(start), nil, false + local s, stop = getnext(start), nil local startchar = getchar(start) if marks[startchar] then while s do @@ -605,24 +836,30 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) else head, start = markstoligature(kind,lookupname,head,start,stop,lig) end - return head, start, true + return head, start, true, false else -- ok, goto next lookup end end else - local skipmark = sequence.flags[1] + local skipmark = sequence.flags[1] + local discfound = false + local lastdisc = nil while s do local id = getid(s) - if id == glyph_code and getsubtype(s)<256 then - if getfont(s) == currentfont then + if id == glyph_code and getsubtype(s)<256 then -- not needed + if getfont(s) == currentfont then -- also not needed only when mark local char = getchar(s) if skipmark and marks[char] then s = getnext(s) - else - local lg = ligature[char] + else -- ligature is a tree + local lg = ligature[char] -- can there be multiple in a row? maybe in a bad font if lg then - stop = s + if not discfound and lastdisc then + discfound = lastdisc + lastdisc = nil + end + stop = s -- needed for fake so outside then ligature = lg s = getnext(s) else @@ -633,13 +870,13 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) break end elseif id == disc_code then - discfound = true + lastdisc = s s = getnext(s) else break end end - local lig = ligature.ligature + local lig = ligature.ligature -- can't we get rid of this .ligature? if lig then if stop then if trace_ligatures then @@ -651,19 +888,34 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) end else -- weird but happens (in some arabic font) + resetinjection(start) setfield(start,"char",lig) if trace_ligatures then logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig)) end end - return head, start, true + return head, start, true, discfound else - -- weird but happens + -- weird but happens, pseudo ligatures ... just the components end end - return head, start, false + return head, start, false, discfound end +-- function is_gsub_ligature(start,ligature) -- limited case: in disc nodes, only latin, always glyphs +-- local s = getnext(start) +-- while s do +-- local lg = ligature[getchar(s)] +-- if lg then +-- ligature = lg +-- s = getnext(s) +-- else +-- return +-- end +-- end +-- return ligature and ligature.ligature +-- end + --[[ldx--We get hits on a mark, but we're not sure if the it has to be applied so we need to explicitly test for basechar, baselig and basemark entries.
@@ -752,7 +1004,7 @@ function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequ end end end - local index = getprop(start,a_ligacomp) + local index = getligaindex(start) local baseanchors = descriptions[basechar] if baseanchors then baseanchors = baseanchors.anchors @@ -802,10 +1054,10 @@ function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence local markchar = getchar(start) if marks[markchar] then local base = getprev(start) -- [glyph] [basemark] [start=mark] - local slc = getprop(start,a_ligacomp) + local slc = getligaindex(start) if slc then -- a rather messy loop ... needs checking with husayni while base do - local blc = getprop(base,a_ligacomp) + local blc = getligaindex(base) if blc and blc ~= slc then base = getprev(base) else @@ -909,16 +1161,16 @@ function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence) end end -function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence) +function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence,injection) local startchar = getchar(start) - local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar]) + local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,injection) -- ,characters[startchar]) if trace_kerns then logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h) end return head, start, false end -function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence) +function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence,lookuphash,i,injection) -- todo: kerns in disc nodes: pre, post, replace -> loop over disc too -- todo: kerns in components of ligatures local snext = getnext(start) @@ -942,14 +1194,14 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence) local a, b = krn[2], krn[3] if a and #a > 0 then local startchar = getchar(start) - local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) + local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,injection) -- characters[startchar]) if trace_kerns then logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) end end if b and #b > 0 then local startchar = getchar(start) - local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) + local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection) -- characters[nextchar]) if trace_kerns then logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) end @@ -969,7 +1221,7 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence) end done = true elseif krn ~= 0 then - local k = setkern(snext,factor,rlmode,krn) + local k = setkern(snext,factor,rlmode,krn,injection) if trace_kerns then logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar)) end @@ -1032,6 +1284,7 @@ function chainprocs.reversesub(head,start,stop,kind,chainname,currentcontext,loo if trace_singles then logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement)) end + resetinjection(start) setfield(start,"char",replacement) return head, start, true else @@ -1086,8 +1339,7 @@ as less as needed but that would also make the code even more messy. -- end --[[ldx-- -Here we replace start by a single variant, First we delete the rest of the -match.
+Here we replace start by a single variant.
--ldx]]-- function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex) @@ -1095,7 +1347,7 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo local current = start local subtables = currentlookup.subtables if #subtables > 1 then - logwarning("todo: check if we need to loop over the replacements: %s",concat(subtables," ")) + logwarning("todo: check if we need to loop over the replacements: % t",subtables) end while current do if getid(current) == glyph_code then @@ -1116,7 +1368,84 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo if trace_singles then logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement)) end - setfield(current,"char",replacement) + resetinjection(current) + if check_discretionaries then + -- some fonts use a chain lookup to replace e.g. an f in a fi ligature + -- and there can be a disc node in between ... the next code tries to catch + -- this + local next = getnext(current) + local prev = getprev(current) -- todo: just remember it above + local done = false + if next then + if getid(next) == disc_code then + local subtype = getsubtype(next) + if subtype == discretionary_code then + setfield(next,"prev",prev) + setfield(prev,"next",next) + setfield(current,"prev",nil) + setfield(current,"next",nil) + local replace = getfield(next,"replace") + local pre = getfield(next,"pre") + local new = copy_node(current) + setfield(new,"char",replacement) + if replace then + setfield(new,"next",replace) + setfield(replace,"prev",new) + end + if pre then + setfield(current,"next",pre) + setfield(pre,"prev",current) + end + setfield(next,"replace",new) -- also updates tail + setfield(next,"pre",current) -- also updates tail + end + start = next + done = true + local next = getnext(start) + if next and getid(next) == disc_code then + collapse_disc(start,next) + end + end + end + if not done and prev then + if getid(prev) == disc_code then + local subtype = getsubtype(prev) + if subtype == discretionary_code then + setfield(next,"prev",prev) + setfield(prev,"next",next) + setfield(current,"prev",nil) + setfield(current,"next",nil) + local replace = getfield(prev,"replace") + local post = getfield(prev,"post") + local new = copy_node(current) + setfield(new,"char",replacement) + if replace then + local tail = find_node_tail(replace) + setfield(tail,"next",new) + setfield(new,"prev",tail) + else + replace = new + end + if post then + local tail = find_node_tail(post) + setfield(tail,"next",current) + setfield(current,"prev",tail) + else + post = current + end + setfield(prev,"replace",replace) -- also updates tail + setfield(prev,"post",post) -- also updates tail + start = prev + done = true + end + end + end + if not done then + setfield(current,"char",replacement) + end + else + setfield(current,"char",replacement) + end end end return head, start, true @@ -1132,8 +1461,7 @@ end chainmores.gsub_single = chainprocs.gsub_single --[[ldx-- -Here we replace start by a sequence of new glyphs. First we delete the rest of -the match.
+Here we replace start by a sequence of new glyphs.
--ldx]]-- function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) @@ -1197,6 +1525,7 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext if trace_alternatives then logprocess("%s: replacing %s by alternative %a to %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(char),choice,gref(choice),comment) end + resetinjection(start) setfield(start,"char",choice) else if trace_alternatives then @@ -1249,12 +1578,22 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, while s do local id = getid(s) if id == disc_code then - s = getnext(s) - discfound = true + if not discfound then + discfound = s + end + if s == stop then + break -- okay? or before the disc + else + s = getnext(s) + end else local schar = getchar(s) if skipmark and marks[schar] then -- marks +-- if s == stop then -- maybe add this +-- break +-- else s = getnext(s) +-- end else local lg = ligatures[schar] if lg then @@ -1283,7 +1622,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, end end head, start = toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound) - return head, start, true, nofreplacements + return head, start, true, nofreplacements, discfound elseif trace_bugs then if start == stop then logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar)) @@ -1293,7 +1632,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, end end end - return head, start, false, 0 + return head, start, false, 0, false end chainmores.gsub_ligature = chainprocs.gsub_ligature @@ -1392,7 +1731,7 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon end end -- todo: like marks a ligatures hash - local index = getprop(start,a_ligacomp) + local index = getligaindex(start) local baseanchors = descriptions[basechar].anchors if baseanchors then local baseanchors = baseanchors['baselig'] @@ -1443,10 +1782,10 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext end if markanchors then local base = getprev(start) -- [glyph] [basemark] [start=mark] - local slc = getprop(start,a_ligacomp) + local slc = getligaindex(start) if slc then -- a rather messy loop ... needs checking with husayni while base do - local blc = getprop(base,a_ligacomp) + local blc = getligaindex(base) if blc and blc ~= slc then base = getprev(base) else @@ -1565,7 +1904,7 @@ function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lo if kerns then kerns = kerns[startchar] -- needed ? if kerns then - local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar]) + local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns) -- ,characters[startchar]) if trace_kerns then logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h) end @@ -1605,14 +1944,14 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look local a, b = krn[2], krn[3] if a and #a > 0 then local startchar = getchar(start) - local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) + local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a) -- ,characters[startchar]) if trace_kerns then logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) end end if b and #b > 0 then local startchar = getchar(start) - local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) + local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b) -- ,characters[nextchar]) if trace_kerns then logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) end @@ -1666,12 +2005,6 @@ local function show_skip(kind,chainname,char,ck,class) end end -local quit_on_no_replacement = true - -directives.register("otf.chain.quitonnoreplacement",function(value) -- maybe per font - quit_on_no_replacement = value -end) - local function normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash) -- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6] local flags = sequence.flags @@ -1741,7 +2074,36 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end elseif id == disc_code then - last = getnext(last) + if check_discretionaries then + local replace = getfield(last,"replace") + if replace then + -- so far we never entered this branch + while replace do + if seq[n][getchar(replace)] then + n = n + 1 + replace = getnext(replace) + if not replace then + break + elseif n > l then +-- match = false + break + end + else + match = false + break + end + end + if not match then + break + elseif check_discretionaries == "trace" then + report_chain("check disc action in current") + end + else + last = getnext(last) -- no skipping here + end + else + last = getnext(last) -- no skipping here + end else match = false break @@ -1787,7 +2149,39 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end elseif id == disc_code then - -- skip 'm + -- the special case: f i where i becomes dottless i .. + if check_discretionaries then + local replace = getfield(prev,"replace") + if replace then + -- we seldom enter this branch (e.g. on brill efficient) + replace = find_node_tail(replace) + local finish = getprev(replace) + while replace do + if seq[n][getchar(replace)] then + n = n - 1 + replace = getprev(replace) + if not replace or replace == finish then + break + elseif n < 1 then +-- match = false + break + end + else + match = false + break + end + end + if not match then + break + elseif check_discretionaries == "trace" then + report_chain("check disc action in before") + end + else + -- skip 'm + end + else + -- skip 'm + end elseif seq[n][32] then n = n -1 else @@ -1796,7 +2190,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end prev = getprev(prev) elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces - n = n -1 + n = n - 1 else match = false break @@ -1804,6 +2198,8 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end elseif f == 2 then match = seq[1][32] +-- elseif f > 2 then +-- match = false -- KE ? else for n=f-1,1 do if not seq[n][32] then @@ -1848,7 +2244,35 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end elseif id == disc_code then - -- skip 'm + if check_discretionaries then + local replace = getfield(current,"replace") + if replace then + -- so far we never entered this branch + while replace do + if seq[n][getchar(replace)] then + n = n + 1 + replace = getnext(replace) + if not replace then + break + elseif n > s then + break + end + else + match = false + break + end + end + if not match then + break + elseif check_discretionaries == "trace" then + report_chain("check disc action in after") + end + else + -- skip 'm + end + else + -- skip 'm + end elseif seq[n][32] then -- brrr n = n + 1 else @@ -1911,7 +2335,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end else local i = 1 - repeat + while true do if skipped then while true do local char = getchar(start) @@ -1952,12 +2376,14 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end end - if start then + if i > nofchainlookups then + break + elseif start then start = getnext(start) else -- weird end - until i > nofchainlookups + end end else local replacements = ck[7] @@ -2133,6 +2559,186 @@ end -- -- the action -- end +-- assumptions: +-- +-- * languages that use complex disc nodes + +-- optimization comes later ... + +local function kernrun(disc,run) -- we can assume that prev and next are glyphs + if trace_kernruns then + report_run("kern") -- will be more detailed + end + -- + local prev = getprev(disc) -- todo, keep these in the main loop + local next = getnext(disc) -- todo, keep these in the main loop + -- + local pre = getfield(disc,"pre") + if not pre then + -- go on + elseif prev then + local nest = getprev(pre) + setfield(pre,"prev",prev) + setfield(prev,"next",pre) + run(prev,"preinjections") + setfield(pre,"prev",nest) + setfield(prev,"next",disc) + else + run(pre,"preinjections") + end + -- + local post = getfield(disc,"post") + if not post then + -- go on + elseif next then + local tail = find_node_tail(post) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(post,"postinjections",tail) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + else + run(post,"postinjections") + end + -- + local replace = getfield(disc,"replace") + if not replace then + -- this should be already done by discfound + elseif prev and next then + local tail = find_node_tail(replace) + local nest = getprev(replace) + setfield(replace,"prev",prev) + setfield(prev,"next",replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(prev,"replaceinjections",tail) + setfield(replace,"prev",nest) + setfield(prev,"next",disc) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + elseif prev then + local nest = getprev(replace) + setfield(replace,"prev",prev) + setfield(prev,"next",replace) + run(prev,"replaceinjections") + setfield(replace,"prev",nest) + setfield(prev,"next",disc) + elseif next then + local tail = find_node_tail(replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(replace,"replaceinjections",tail) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + else + run(replace,"replaceinjections") + end +end + +-- the if new test might be dangerous as luatex will check / set some tail stuff +-- in a temp node + +local function comprun(disc,run) + if trace_compruns then + report_run("comp: %s",languages.serializediscretionary(disc)) + end + -- + local pre = getfield(disc,"pre") + if pre then + local new, done = run(pre) + if done then + setfield(disc,"pre",new) + end + end + -- + local post = getfield(disc,"post") + if post then + local new, done = run(post) + if done then + setfield(disc,"post",new) + end + end + -- + local replace = getfield(disc,"replace") + if replace then + local new, done = run(replace) + if done then + setfield(disc,"replace",new) + end + end +end + +local function testrun(disc,trun,crun) + local next = getnext(disc) + if next then + local replace = getfield(disc,"replace") + if replace then + local prev = getprev(disc) + if prev then + -- only look ahead + local tail = find_node_tail(replace) + -- local nest = getprev(replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + if trun(replace,next) then + setfield(disc,"replace",nil) -- beware, side effects of nest so first + setfield(prev,"next",replace) + setfield(replace,"prev",prev) + setfield(next,"prev",tail) + setfield(tail,"next",next) + setfield(disc,"prev",nil) + setfield(disc,"next",nil) + flush_node_list(disc) + return replace -- restart + else + setfield(tail,"next",nil) + setfield(next,"prev",disc) + end + else + -- weird case + end + else + -- no need + end + else + -- weird case + end + comprun(disc,crun) + return next +end + +local function discrun(disc,drun,krun) + local next = getnext(disc) + local prev = getprev(disc) + if trace_discruns then + report_run("disc") -- will be more detailed + end + if next and prev then + setfield(prev,"next",next) + -- setfield(next,"prev",prev) + drun(prev) + setfield(prev,"next",disc) + -- setfield(next,"prev",disc) + end + -- + local pre = getfield(disc,"pre") + if not pre then + -- go on + elseif prev then + local nest = getprev(pre) + setfield(pre,"prev",prev) + setfield(prev,"next",pre) + krun(prev,"preinjections") + setfield(pre,"prev",nest) + setfield(prev,"next",disc) + else + run(pre,"preinjections") + end + return next +end + +-- todo: maybe run lr and rl stretches + local function featuresprocessor(head,font,attr) local lookuphash = lookuphashes[font] -- we can also check sequences here @@ -2156,6 +2762,7 @@ local function featuresprocessor(head,font,attr) anchorlookups = resources.lookup_to_anchor lookuptable = resources.lookups lookuptypes = resources.lookuptypes + lookuptags = resources.lookuptags currentfont = font rlmode = 0 @@ -2176,21 +2783,28 @@ local function featuresprocessor(head,font,attr) -- todo: retain prev + -- We don't goto the next node of a disc node is created so that we can then treat + -- the pre, post and replace. It's abit of a hack but works out ok for most cases. + + -- there can be less subtype and attr checking in the comprun etc helpers + for s=1,#datasets do - local dataset = datasets[s] - featurevalue = dataset[1] -- todo: pass to function instead of using a global - - local sequence = dataset[5] -- sequences[s] -- also dataset[5] - local rlparmode = 0 - local topstack = 0 - local success = false - local attribute = dataset[2] - local chain = dataset[3] -- sequence.chain or 0 - local typ = sequence.type - local subtables = sequence.subtables + local dataset = datasets[s] + featurevalue = dataset[1] -- todo: pass to function instead of using a global + local attribute = dataset[2] + local chain = dataset[3] -- sequence.chain or 0 + local kind = dataset[4] + local sequence = dataset[5] -- sequences[s] -- also dataset[5] + local rlparmode = 0 + local topstack = 0 + local success = false + local typ = sequence.type + local gpossing = typ == "gpos_single" or typ == "gpos_pair" + local subtables = sequence.subtables + local handler = handlers[typ] + if chain < 0 then -- this is a limited case, no special treatments like 'init' etc - local handler = handlers[typ] -- we need to get rid of this slide! probably no longer needed in latest luatex local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo while start do @@ -2204,13 +2818,16 @@ local function featuresprocessor(head,font,attr) a = true end if a then + local char = getchar(start) for i=1,#subtables do local lookupname = subtables[i] local lookupcache = lookuphash[lookupname] if lookupcache then - local lookupmatch = lookupcache[getchar(start)] + -- local lookupmatch = lookupcache[getchar(start)] + local lookupmatch = lookupcache[start] if lookupmatch then - head, start, success = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + -- todo: disc? + head, start, success = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i) if success then break end @@ -2231,7 +2848,6 @@ local function featuresprocessor(head,font,attr) end end else - local handler = handlers[typ] local ns = #subtables local start = head -- local ? rlmode = 0 -- to be checked ? @@ -2242,13 +2858,15 @@ local function featuresprocessor(head,font,attr) report_missing_cache(typ,lookupname) else - local function subrun(start) - -- mostly for gsub, gpos would demand a more clever approach + local function c_run(start) -- no need to check for 256 and attr probably also the same local head = start local done = false while start do local id = getid(start) - if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then + if id ~= glyph_code then + -- very unlikely + start = getnext(start) + elseif getfont(start) == font and getsubtype(start) < 256 then local a = getattr(start,0) if a then a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) @@ -2260,7 +2878,7 @@ local function featuresprocessor(head,font,attr) if lookupmatch then -- sequence kan weg local ok - head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) + head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,1) if ok then done = true end @@ -2270,48 +2888,106 @@ local function featuresprocessor(head,font,attr) start = getnext(start) end else - start = getnext(start) + return head, false end end if done then - success = true - return head + success = true -- needed in this subrun? end + return head, done end - local function kerndisc(disc) -- we can assume that prev and next are glyphs - local prev = getprev(disc) - local next = getnext(disc) - if prev and next then - setfield(prev,"next",next) - -- setfield(next,"prev",prev) - local a = getattr(prev,0) - if a then - a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) + local function t_run(start,stop) + while start ~= stop do + local id = getid(start) + if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then + local a = getattr(start,0) + if a then + a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + else + a = not attribute or getprop(start,a_state) == attribute + end + if a then + local lookupmatch = lookupcache[getchar(start)] + if lookupmatch then -- hm, hyphens can match (tlig) so we need to really check + -- if we need more than ligatures we can outline the code and use functions + local s = getnext(start) + local l = nil + while s do + local lg = lookupmatch[getchar(s)] + if lg then + l = lg + s = getnext(s) + else + break + end + end + if l and l.ligature then + return true + end + end + end + start = getnext(start) else - a = not attribute or getprop(prev,a_state) == attribute + break end - if a then - local lookupmatch = lookupcache[getchar(prev)] - if lookupmatch then - -- sequence kan weg - local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) - if ok then - done = true - success = true + end + end + + local function d_run(prev) -- we can assume that prev and next are glyphs + local a = getattr(prev,0) + if a then + a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) + else + a = not attribute or getprop(prev,a_state) == attribute + end + if a then + local lookupmatch = lookupcache[getchar(prev)] + if lookupmatch then + -- sequence kan weg + local h, d, ok = handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,1) + if ok then + done = true + success = true + end + end + end + end + + local function k_run(sub,injection,last) + local a = getattr(sub,0) + if a then + a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute) + else + a = not attribute or getprop(sub,a_state) == attribute + end + if a then + -- sequence kan weg + for n in traverse_nodes(sub) do -- only gpos + if n == last then + break + end + local id = getid(n) + if id == glyph_code then + local lookupmatch = lookupcache[getchar(n)] + if lookupmatch then + local h, d, ok = handler(sub,n,kind,lookupname,lookupmatch,sequence,lookuphash,1,injection) + if ok then + done = true + success = true + end end + else + -- message end end - setfield(prev,"next",disc) - -- setfield(next,"prev",disc) end - return next end while start do local id = getid(start) if id == glyph_code then - if getfont(start) == font and getsubtype(start) < 256 then + if getfont(start) == font and getsubtype(start) < 256 then -- why a 256 test ... local a = getattr(start,0) if a then a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) @@ -2319,44 +2995,46 @@ local function featuresprocessor(head,font,attr) a = not attribute or getprop(start,a_state) == attribute end if a then - local lookupmatch = lookupcache[getchar(start)] + local char = getchar(start) + local lookupmatch = lookupcache[char] if lookupmatch then -- sequence kan weg local ok - head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) + head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,1) if ok then success = true + elseif gpossing and zwnjruns and char == zwnj then + discrun(start,d_run) end + elseif gpossing and zwnjruns and char == zwnj then + discrun(start,d_run) end if start then start = getnext(start) end else - start = getnext(start) + start = getnext(start) end else start = getnext(start) end elseif id == disc_code then - -- mostly for gsub - if getsubtype(start) == discretionary_code then - local pre = getfield(start,"pre") - if pre then - local new = subrun(pre) - if new then setfield(start,"pre",new) end - end - local post = getfield(start,"post") - if post then - local new = subrun(post) - if new then setfield(start,"post",new) end - end - local replace = getfield(start,"replace") - if replace then - local new = subrun(replace) - if new then setfield(start,"replace",new) end - end -elseif typ == "gpos_single" or typ == "gpos_pair" then - kerndisc(start) - end - start = getnext(start) + local discretionary = getsubtype(start) == discretionary_code + if gpossing then + if discretionary then + kernrun(start,k_run) + else + discrun(start,d_run,k_run) + end + start = getnext(start) + elseif discretionary then + if typ == "gsub_ligature" then + start = testrun(start,t_run,c_run) + else + comprun(start,c_run) + start = getnext(start) + end + else + start = getnext(start) + end elseif id == whatsit_code then -- will be function local subtype = getsubtype(start) if subtype == dir_code then @@ -2401,15 +3079,18 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then end end end + else - local function subrun(start) - -- mostly for gsub, gpos would demand a more clever approach + local function c_run(start) local head = start local done = false while start do local id = getid(start) - if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then + if id ~= glyph_code then + -- very unlikely + start = getnext(start) + elseif getfont(start) == font and getsubtype(start) < 256 then local a = getattr(start,0) if a then a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) @@ -2417,15 +3098,17 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then a = not attribute or getprop(start,a_state) == attribute end if a then + local char = getchar(start) for i=1,ns do local lookupname = subtables[i] local lookupcache = lookuphash[lookupname] if lookupcache then - local lookupmatch = lookupcache[getchar(start)] + -- local lookupmatch = lookupcache[getchar(start)] + local lookupmatch = lookupcache[char] if lookupmatch then -- we could move all code inline but that makes things even more unreadable local ok - head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i) if ok then done = true break @@ -2443,50 +3126,127 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then start = getnext(start) end else - start = getnext(start) + return head, false end end if done then success = true - return head end + return head, done end - local function kerndisc(disc) -- we can assume that prev and next are glyphs - local prev = getprev(disc) - local next = getnext(disc) - if prev and next then - setfield(prev,"next",next) - -- setfield(next,"prev",prev) - local a = getattr(prev,0) - if a then - a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) - else - a = not attribute or getprop(prev,a_state) == attribute + local function d_run(prev) + local a = getattr(prev,0) + if a then + a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) + else + a = not attribute or getprop(prev,a_state) == attribute + end + if a then + -- brr prev can be disc + local char = getchar(prev) + for i=1,ns do + local lookupname = subtables[i] + local lookupcache = lookuphash[lookupname] + if lookupcache then + local lookupmatch = lookupcache[char] + if lookupmatch then + -- we could move all code inline but that makes things even more unreadable + local h, d, ok = handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,i) + if ok then + done = true + break + end + end + else + report_missing_cache(typ,lookupname) + end end - if a then - for i=1,ns do - local lookupname = subtables[i] - local lookupcache = lookuphash[lookupname] - if lookupcache then - local lookupmatch = lookupcache[getchar(prev)] - if lookupmatch then - -- we could move all code inline but that makes things even more unreadable - local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) - if ok then - done = true - break + end + end + + local function k_run(sub,injection,last) + local a = getattr(sub,0) + if a then + a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute) + else + a = not attribute or getprop(sub,a_state) == attribute + end + if a then + for n in traverse_nodes(sub) do -- only gpos + if n == last then + break + end + local id = getid(n) + if id == glyph_code then + local char = getchar(n) + for i=1,ns do + local lookupname = subtables[i] + local lookupcache = lookuphash[lookupname] + if lookupcache then + local lookupmatch = lookupcache[char] + if lookupmatch then + local h, d, ok = handler(head,n,kind,lookupname,lookupmatch,sequence,lookuphash,i,injection) + if ok then + done = true + break + end end + else + report_missing_cache(typ,lookupname) end - else - report_missing_cache(typ,lookupname) end + else + -- message end end - setfield(prev,"next",disc) - -- setfield(next,"prev",disc) end - return next + end + + local function t_run(start,stop) + while start ~= stop do + local id = getid(start) + if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then + local a = getattr(start,0) + if a then + a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + else + a = not attribute or getprop(start,a_state) == attribute + end + if a then + local char = getchar(start) + for i=1,ns do + local lookupname = subtables[i] + local lookupcache = lookuphash[lookupname] + if lookupcache then + local lookupmatch = lookupcache[char] + if lookupmatch then + -- if we need more than ligatures we can outline the code and use functions + local s = getnext(start) + local l = nil + while s do + local lg = lookupmatch[getchar(s)] + if lg then + l = lg + s = getnext(s) + else + break + end + end + if l and l.ligature then + return true + end + end + else + report_missing_cache(typ,lookupname) + end + end + end + start = getnext(start) + else + break + end + end end while start do @@ -2504,18 +3264,23 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then local lookupname = subtables[i] local lookupcache = lookuphash[lookupname] if lookupcache then - local lookupmatch = lookupcache[getchar(start)] + local char = getchar(start) + local lookupmatch = lookupcache[char] if lookupmatch then -- we could move all code inline but that makes things even more unreadable local ok - head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i) if ok then success = true break elseif not start then -- don't ask why ... shouldn't happen break + elseif gpossing and zwnjruns and char == zwnj then + discrun(start,d_run) end + elseif gpossing and zwnjruns and char == zwnj then + discrun(start,d_run) end else report_missing_cache(typ,lookupname) @@ -2529,27 +3294,24 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then start = getnext(start) end elseif id == disc_code then - -- mostly for gsub - if getsubtype(start) == discretionary_code then - local pre = getfield(start,"pre") - if pre then - local new = subrun(pre) - if new then setfield(start,"pre",new) end - end - local post = getfield(start,"post") - if post then - local new = subrun(post) - if new then setfield(start,"post",new) end + local discretionary = getsubtype(start) == discretionary_code + if gpossing then + if discretionary then + kernrun(start,k_run) + else + discrun(start,d_run,k_run) end - local replace = getfield(start,"replace") - if replace then - local new = subrun(replace) - if new then setfield(start,"replace",new) end + start = getnext(start) + elseif discretionary then + if typ == "gsub_ligature" then + start = testrun(start,t_run,c_run) + else + comprun(start,c_run) + start = getnext(start) end -elseif typ == "gpos_single" or typ == "gpos_pair" then - kerndisc(start) + else + start = getnext(start) end - start = getnext(start) elseif id == whatsit_code then local subtype = getsubtype(start) if subtype == dir_code then @@ -2600,6 +3362,7 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then if trace_steps then -- ? registerstep(head) end + end head = tonode(head) @@ -2756,6 +3519,7 @@ local function prepare_contextchains(tfmdata) local rawdata = tfmdata.shared.rawdata local resources = rawdata.resources local lookuphash = resources.lookuphash + local lookuptags = resources.lookuptags local lookups = rawdata.lookups if lookups then for lookupname, lookupdata in next, rawdata.lookups do @@ -2769,7 +3533,7 @@ local function prepare_contextchains(tfmdata) report_prepare("unsupported format %a",format) elseif not validformat[lookuptype] then -- todo: dejavu-serif has one (but i need to see what use it has) - report_prepare("unsupported format %a, lookuptype %a, lookupname %a",format,lookuptype,lookupname) + report_prepare("unsupported format %a, lookuptype %a, lookupname %a",format,lookuptype,lookuptags[lookupname]) else local contexts = lookuphash[lookupname] if not contexts then @@ -2825,7 +3589,7 @@ local function prepare_contextchains(tfmdata) -- no rules end else - report_prepare("missing lookuptype for lookupname %a",lookupname) + report_prepare("missing lookuptype for lookupname %a",lookuptags[lookupname]) end end end diff --git a/Master/texmf-dist/tex/context/base/font-otp.lua b/Master/texmf-dist/tex/context/base/font-otp.lua index c80ee86ae61..63e4184c19a 100644 --- a/Master/texmf-dist/tex/context/base/font-otp.lua +++ b/Master/texmf-dist/tex/context/base/font-otp.lua @@ -140,6 +140,11 @@ end -- return b -- end +-- beware: we cannot unpack and repack the same table because then sharing +-- interferes (we could catch this if needed) .. so for now: save, reload +-- and repack in such cases (never needed anyway) .. a tricky aspect is that +-- we then need to sort more thanks to random hashing + local function packdata(data) if data then -- stripdata(data) @@ -750,27 +755,28 @@ local function unpackdata(data) rule.replacements = tv end end - local fore = rule.fore - if fore then - local tv = tables[fore] - if tv then - rule.fore = tv - end - end - local back = rule.back - if back then - local tv = tables[back] - if tv then - rule.back = tv - end - end - local names = rule.names - if names then - local tv = tables[names] - if tv then - rule.names = tv - end - end + -- local fore = rule.fore + -- if fore then + -- local tv = tables[fore] + -- if tv then + -- rule.fore = tv + -- end + -- end + -- local back = rule.back + -- if back then + -- local tv = tables[back] + -- if tv then + -- rule.back = tv + -- end + -- end + -- local names = rule.names + -- if names then + -- local tv = tables[names] + -- if tv then + -- rule.names = tv + -- end + -- end + -- local lookups = rule.lookups if lookups then local tv = tables[lookups] @@ -897,3 +903,4 @@ if otf.enhancers.register then end otf.enhancers.unpack = unpackdata -- used elsewhere +otf.enhancers.pack = packdata -- used elsewhere diff --git a/Master/texmf-dist/tex/context/base/font-ott.lua b/Master/texmf-dist/tex/context/base/font-ott.lua index 1e23090565b..1f9a1ac041a 100644 --- a/Master/texmf-dist/tex/context/base/font-ott.lua +++ b/Master/texmf-dist/tex/context/base/font-ott.lua @@ -858,15 +858,18 @@ function otf.features.normalize(features) if uv then -- report_checks("feature value %a first seen at %a",value,key) else - if type(value) == "string" then + uv = tonumber(value) -- before boolean as there we also handle 0/1 + if uv then + -- we're okay + elseif type(value) == "string" then local b = is_boolean(value) if type(b) == "nil" then - uv = tonumber(value) or lower(value) + uv = lower(value) else uv = b end else - uv = v + uv = value end if not rawget(features,k) then k = rawget(verbosefeatures,k) or k diff --git a/Master/texmf-dist/tex/context/base/font-otx.lua b/Master/texmf-dist/tex/context/base/font-otx.lua deleted file mode 100644 index dc0469e398e..00000000000 --- a/Master/texmf-dist/tex/context/base/font-otx.lua +++ /dev/null @@ -1,419 +0,0 @@ -if not modules then modules = { } end modules ['font-otx'] = { - version = 1.001, - comment = "companion to font-otf.lua (analysing)", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- context only - -local type = type - -if not trackers then trackers = { register = function() end } end - ------ trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end) - -local fonts, nodes, node = fonts, nodes, node - -local allocate = utilities.storage.allocate - -local otf = fonts.handlers.otf - -local analyzers = fonts.analyzers -local initializers = allocate() -local methods = allocate() - -analyzers.initializers = initializers -analyzers.methods = methods ----------.useunicodemarks = false - -local a_state = attributes.private('state') - -local nuts = nodes.nuts -local tonut = nuts.tonut - -local getfield = nuts.getfield -local getnext = nuts.getnext -local getprev = nuts.getprev -local getid = nuts.getid -local getprop = nuts.getprop -local setprop = nuts.setprop -local getfont = nuts.getfont -local getsubtype = nuts.getsubtype -local getchar = nuts.getchar - -local traverse_id = nuts.traverse_id -local traverse_node_list = nuts.traverse -local end_of_math = nuts.end_of_math - -local nodecodes = nodes.nodecodes -local glyph_code = nodecodes.glyph -local disc_code = nodecodes.disc -local math_code = nodecodes.math - -local fontdata = fonts.hashes.identifiers -local categories = characters and characters.categories or { } -- sorry, only in context -local chardata = characters and characters.data - -local otffeatures = fonts.constructors.newfeatures("otf") -local registerotffeature = otffeatures.register - ---[[ldx-- -Analyzers run per script and/or language and are needed in order to -process features right.
---ldx]]-- - --- never use these numbers directly - -local s_init = 1 local s_rphf = 7 -local s_medi = 2 local s_half = 8 -local s_fina = 3 local s_pref = 9 -local s_isol = 4 local s_blwf = 10 -local s_mark = 5 local s_pstf = 11 -local s_rest = 6 - -local states = { - init = s_init, - medi = s_medi, - fina = s_fina, - isol = s_isol, - mark = s_mark, - rest = s_rest, - rphf = s_rphf, - half = s_half, - pref = s_pref, - blwf = s_blwf, - pstf = s_pstf, -} - -local features = { - init = s_init, - medi = s_medi, - fina = s_fina, - isol = s_isol, - -- mark = s_mark, - -- rest = s_rest, - rphf = s_rphf, - half = s_half, - pref = s_pref, - blwf = s_blwf, - pstf = s_pstf, -} - -analyzers.states = states -analyzers.features = features -analyzers.useunicodemarks = false - --- todo: analyzers per script/lang, cross font, so we need an font id hash -> script --- e.g. latin -> hyphenate, arab -> 1/2/3 analyze -- its own namespace - -function analyzers.setstate(head,font) -- we can skip math - local useunicodemarks = analyzers.useunicodemarks - local tfmdata = fontdata[font] - local descriptions = tfmdata.descriptions - local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean - current = tonut(current) - while current do - local id = getid(current) - if id == glyph_code and getfont(current) == font then - done = true - local char = getchar(current) - local d = descriptions[char] - if d then - if d.class == "mark" then - done = true - setprop(current,a_state,s_mark) - elseif useunicodemarks and categories[char] == "mn" then - done = true - setprop(current,a_state,s_mark) - elseif n == 0 then - first, last, n = current, current, 1 - setprop(current,a_state,s_init) - else - last, n = current, n+1 - setprop(current,a_state,s_medi) - end - else -- finish - if first and first == last then - setprop(last,a_state,s_isol) - elseif last then - setprop(last,a_state,s_fina) - end - first, last, n = nil, nil, 0 - end - elseif id == disc_code then - -- always in the middle - setprop(current,a_state,s_medi) - last = current - else -- finish - if first and first == last then - setprop(last,a_state,s_isol) - elseif last then - setprop(last,a_state,s_fina) - end - first, last, n = nil, nil, 0 - if id == math_code then - current = end_of_math(current) - end - end - current = getnext(current) - end - if first and first == last then - setprop(last,a_state,s_isol) - elseif last then - setprop(last,a_state,s_fina) - end - return head, done -end - --- in the future we will use language/script attributes instead of the --- font related value, but then we also need dynamic features which is --- somewhat slower; and .. we need a chain of them - -local function analyzeinitializer(tfmdata,value) -- attr - local script, language = otf.scriptandlanguage(tfmdata) -- attr - local action = initializers[script] - if not action then - -- skip - elseif type(action) == "function" then - return action(tfmdata,value) - else - local action = action[language] - if action then - return action(tfmdata,value) - end - end -end - -local function analyzeprocessor(head,font,attr) - local tfmdata = fontdata[font] - local script, language = otf.scriptandlanguage(tfmdata,attr) - local action = methods[script] - if not action then - -- skip - elseif type(action) == "function" then - return action(head,font,attr) - else - action = action[language] - if action then - return action(head,font,attr) - end - end - return head, false -end - -registerotffeature { - name = "analyze", - description = "analysis of character classes", - default = true, - initializers = { - node = analyzeinitializer, - }, - processors = { - position = 1, - node = analyzeprocessor, - } -} - --- latin - -methods.latn = analyzers.setstate - -local arab_warned = { } - -local function warning(current,what) - local char = getchar(current) - if not arab_warned[char] then - log.report("analyze","arab: character %C has no %a class",char,what) - arab_warned[char] = true - end -end - -local mappers = { - l = s_init, -- left - d = s_medi, -- double - c = s_medi, -- joiner - r = s_fina, -- right - u = s_isol, -- nonjoiner -} - -local classifiers = { } -- we can also use this trick for devanagari - -local first_arabic, last_arabic = characters.blockrange("arabic") -local first_syriac, last_syriac = characters.blockrange("syriac") -local first_mandiac, last_mandiac = characters.blockrange("mandiac") -local first_nko, last_nko = characters.blockrange("nko") - -table.setmetatableindex(classifiers,function(t,k) - local c = chardata[k] - local v = false - if c then - local arabic = c.arabic - if arabic then - v = mappers[arabic] - if not v then - log.report("analyze","error in mapping arabic %C",k) - -- error - v = false - end - elseif k >= first_arabic and k <= last_arabic or k >= first_syriac and k <= last_syriac or - k >= first_mandiac and k <= last_mandiac or k >= first_nko and k <= last_nko then - if categories[k] == "mn" then - v = s_mark - else - v = s_rest - end - else - end - end - t[k] = v - return v -end) - -function methods.arab(head,font,attr) - local first, last = nil, nil - local c_first, c_last = nil, nil - local current, done = head, false - current = tonut(current) - while current do - local id = getid(current) - if id == glyph_code and getfont(current) == font and getsubtype(current)<256 and not getprop(current,a_state) then - done = true - local char = getchar(current) - local classifier = classifiers[char] - if not classifier then - if last then - if c_last == s_medi or c_last == s_fina then - setprop(last,a_state,s_fina) - else - warning(last,"fina") - setprop(last,a_state,s_error) - end - first, last = nil, nil - elseif first then - if c_first == s_medi or c_first == s_fina then - setprop(first,a_state,s_isol) - else - warning(first,"isol") - setprop(first,a_state,s_error) - end - first = nil - end - elseif classifier == s_mark then - setprop(current,a_state,s_mark) - elseif classifier == s_isol then - if last then - if c_last == s_medi or c_last == s_fina then - setprop(last,a_state,s_fina) - else - warning(last,"fina") - setprop(last,a_state,s_error) - end - first, last = nil, nil - elseif first then - if c_first == s_medi or c_first == s_fina then - setprop(first,a_state,s_isol) - else - warning(first,"isol") - setprop(first,a_state,s_error) - end - first = nil - end - setprop(current,a_state,s_isol) - elseif classifier == s_medi then - if first then - last = current - c_last = classifier - setprop(current,a_state,s_medi) - else - setprop(current,a_state,s_init) - first = current - c_first = classifier - end - elseif classifier == s_fina then - if last then - if getprop(last,a_state) ~= s_init then - setprop(last,a_state,s_medi) - end - setprop(current,a_state,s_fina) - first, last = nil, nil - elseif first then - -- if getprop(first,a_state) ~= s_init then - -- -- needs checking - -- setprop(first,a_state,s_medi) - -- end - setprop(current,a_state,s_fina) - first = nil - else - setprop(current,a_state,s_isol) - end - else -- classifier == s_rest - setprop(current,a_state,s_rest) - if last then - if c_last == s_medi or c_last == s_fina then - setprop(last,a_state,s_fina) - else - warning(last,"fina") - setprop(last,a_state,s_error) - end - first, last = nil, nil - elseif first then - if c_first == s_medi or c_first == s_fina then - setprop(first,a_state,s_isol) - else - warning(first,"isol") - setprop(first,a_state,s_error) - end - first = nil - end - end - else - if last then - if c_last == s_medi or c_last == s_fina then - setprop(last,a_state,s_fina) - else - warning(last,"fina") - setprop(last,a_state,s_error) - end - first, last = nil, nil - elseif first then - if c_first == s_medi or c_first == s_fina then - setprop(first,a_state,s_isol) - else - warning(first,"isol") - setprop(first,a_state,s_error) - end - first = nil - end - if id == math_code then -- a bit duplicate as we test for glyphs twice - current = end_of_math(current) - end - end - current = getnext(current) - end - if last then - if c_last == s_medi or c_last == s_fina then - setprop(last,a_state,s_fina) - else - warning(last,"fina") - setprop(last,a_state,s_error) - end - elseif first then - if c_first == s_medi or c_first == s_fina then - setprop(first,a_state,s_isol) - else - warning(first,"isol") - setprop(first,a_state,s_error) - end - end - return head, done -end - -methods.syrc = methods.arab -methods.mand = methods.arab -methods.nko = methods.arab - -directives.register("otf.analyze.useunicodemarks",function(v) - analyzers.useunicodemarks = v -end) diff --git a/Master/texmf-dist/tex/context/base/font-pre.mkiv b/Master/texmf-dist/tex/context/base/font-pre.mkiv index fc6eb289e64..c184a2118db 100644 --- a/Master/texmf-dist/tex/context/base/font-pre.mkiv +++ b/Master/texmf-dist/tex/context/base/font-pre.mkiv @@ -100,14 +100,14 @@ features=no] \definefontfeature - [semetic-complete] + [semitic-complete] [mode=node,analyze=yes,language=dflt,ccmp=yes, init=yes,medi=yes,fina=yes,isol=yes, mark=yes,mkmk=yes,kern=yes,curs=yes, liga=yes,dlig=yes,rlig=yes,clig=yes,calt=yes] \definefontfeature - [semetic-simple] + [semitic-simple] [mode=node,analyze=yes,language=dflt,ccmp=yes, init=yes,medi=yes,fina=yes,isol=yes, mark=yes,mkmk=yes,kern=yes,curs=yes, @@ -115,22 +115,22 @@ \definefontfeature [arabic] - [semetic-complete] + [semitic-complete] [script=arab] \definefontfeature [hebrew] - [semetic-complete] + [semitic-complete] [script=hebr] \definefontfeature [simplearabic] - [semetic-simple] + [semitic-simple] [script=arab] \definefontfeature [simplehebrew] - [semetic-simple] + [semitic-simple] [script=hebr] % \definefont [DevaOne] [file:chandas.ttf*devanagari-one at 12pt] @@ -496,15 +496,16 @@ \definefontsize[\s!a] \definefontsize[\s!b] \definefontsize[\s!c] \definefontsize[\s!d] -\definealternativestyle [\v!mediaeval] [\os] [] -\definealternativestyle [\v!normal] [\tf] [] -\definealternativestyle [\v!bold] [\bf] [] -\definealternativestyle [\v!type] [\tt] [] -\definealternativestyle [\v!mono] [\tt] [] -\definealternativestyle [\v!slanted] [\sl] [] -\definealternativestyle [\v!italic] [\it] [] -\definealternativestyle [\v!boldslanted,\v!slantedbold] [\bs] [] -\definealternativestyle [\v!bolditalic,\v!italicbold] [\bi] [] +\definealternativestyle [\v!mediaeval] [\os] [] +\definealternativestyle [\v!normal] [\tf] [] +\definealternativestyle [\v!bold] [\bf] [] +\definealternativestyle [\v!type] [\tt] [] +\definealternativestyle [\v!mono] [\tt] [] +\definealternativestyle [\v!monobold] [\tt\bf] [] +\definealternativestyle [\v!slanted] [\sl] [] +\definealternativestyle [\v!italic] [\it] [] +\definealternativestyle [\v!boldslanted,\v!slantedbold] [\bs] [] +\definealternativestyle [\v!bolditalic,\v!italicbold] [\bi] [] \definealternativestyle [\v!small,\v!smallnormal] [\setsmallbodyfont\tf] [] \definealternativestyle [\v!smallbold] [\setsmallbodyfont\bf] [] @@ -584,6 +585,7 @@ \definefontfeature[f:smallcaps][smcp=yes] \definefontfeature[f:oldstyle] [onum=yes] \definefontfeature[f:tabular] [tnum=yes] +\definefontfeature[f:superiors][sups=yes] \definealternativestyle [\v!smallcaps] [\setsmallcaps] [\setsmallcaps] \definealternativestyle [\v!oldstyle] [\setoldstyle ] [\setoldstyle ] @@ -591,6 +593,7 @@ \unexpanded\def\setsmallcaps{\doaddfeature{f:smallcaps}} \unexpanded\def\setoldstyle {\doaddfeature{f:oldstyle}} \unexpanded\def\settabular {\doaddfeature{f:tabular}} +\unexpanded\def\setsuperiors{\doaddfeature{f:superiors}} %D \macros %D {tinyfont} @@ -617,6 +620,22 @@ \definefont[infofont][dejavusansmono at 6pt] % todo \the\everybodyfont +%D Optimization (later we overload in math): + +\unexpanded\def\normaltf{\let\fontalternative\s!tf\font_helpers_synchronize_font} +\unexpanded\def\normalbf{\let\fontalternative\s!bf\font_helpers_synchronize_font} +\unexpanded\def\normalit{\let\fontalternative\s!it\font_helpers_synchronize_font} +\unexpanded\def\normalsl{\let\fontalternative\s!sl\font_helpers_synchronize_font} +\unexpanded\def\normalbi{\let\fontalternative\s!bi\font_helpers_synchronize_font} +\unexpanded\def\normalbs{\let\fontalternative\s!bs\font_helpers_synchronize_font} + +\let\tf\normaltf +\let\bf\normalbf +\let\it\normalit +\let\sl\normalsl +\let\bi\normalbi +\let\bs\normalbs + \protect \endinput % LM math vs CM math (analysis by Taco): @@ -652,3 +671,30 @@ % % /lessorequalslant % /greaterorequalslant + +% \unprotect +% +% \definehighlight[\v!italic ][\c!command=\v!no,\c!style=\v!italic] +% \definehighlight[\v!bold ][\c!command=\v!no,\c!style=\v!bold] +% \definehighlight[\v!bolditalic][\c!command=\v!no,\c!style=\v!bolditalic] +% \definehighlight[\v!mono] [\c!command=\v!no,\c!style=\v!mono] +% \definehighlight[\v!monobold] [\c!command=\v!no,\c!style=\v!monobold] +% +% \definehighlight[important] [\c!command=\v!no,\c!style=\v!bold] +% \definehighlight[unimportant] [\c!command=\v!no,\c!color=darkgray] +% \definehighlight[warning] [\c!command=\v!no,\c!style=\v!bold,\c!color=darkblue] +% \definehighlight[error] [\c!command=\v!no,\c!style=\v!bold,\c!color=darkred] +% +% \protect +% +% \starttext +% \highlight[italic] {italic} +% \highlight[bolditalic] {bolditalic} +% \highlight[bold] {bold} +% \highlight[mono] {mono} +% \highlight[monobold] {monobold} +% \highlight[important] {important} +% \highlight[unimportant]{unimportant} +% \highlight[warning] {warning} +% \highlight[error] {error} +% \stoptext diff --git a/Master/texmf-dist/tex/context/base/font-run.mkiv b/Master/texmf-dist/tex/context/base/font-run.mkiv index cb40adedd90..1b8843b94c5 100644 --- a/Master/texmf-dist/tex/context/base/font-run.mkiv +++ b/Master/texmf-dist/tex/context/base/font-run.mkiv @@ -12,8 +12,8 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -%D [This code is hooked into the core macros and saves some -%D format space. It needs a cleanup.] +%D [This code is hooked into the core macros and saves some format +%D space. It needs a cleanup.] \unprotect @@ -100,8 +100,8 @@ &&\tttf\tx\s!text&&\tttf\tx\s!script&&\tttf\tx\s!scriptscript &&\tttf\tx\s!x&&\tttf\tx\s!xx&&\tttf\tx\v!small&&\tttf\tx\v!big &&\tttf\tx\c!interlinespace&\cr - \noalign{\hrule} - \@EA\globalprocesscommalist\@EA[\bodyfontenvironmentlist]\next}} + \noalign{\hrule}% + \processbodyfontenvironmentlist\next}} \ifinsidefloat\else\stopbaselinecorrection\fi} \unexpanded\gdef\showfont diff --git a/Master/texmf-dist/tex/context/base/font-sel.lua b/Master/texmf-dist/tex/context/base/font-sel.lua index 86300c2dbcb..c3431a213ca 100644 --- a/Master/texmf-dist/tex/context/base/font-sel.lua +++ b/Master/texmf-dist/tex/context/base/font-sel.lua @@ -20,6 +20,8 @@ local v_simplefonts = interfaces.variables.simplefonts local v_selectfont = interfaces.variables.selectfont local v_default = interfaces.variables.default +local implement = interfaces.implement + local selectfont = fonts.select or { } fonts.select = selectfont @@ -299,12 +301,12 @@ local mathsettings = { }, } -function commands.defineselectfont(settings) +function selectfont.define(settings) local index = #data + 1 data[index] = settings selectfont.searchfiles(index) selectfont.filterinput(index) - context(index) + return index end local function savefont(data,alternative,entries) @@ -493,6 +495,14 @@ function selectfont.filterinput(index) end end +local ctx_definefontsynonym = context.definefontsynonym +local ctx_resetfontfallback = context.resetfontfallback +local ctx_startfontclass = context.startfontclass +local ctx_stopfontclass = context.stopfontclass +local ctx_loadfontgoodies = context.loadfontgoodies +local ctx_definefontfallback = context.definefontfallback +local ctx_definetypeface = context.definetypeface + local function definefontsynonym(data,alternative,index,fallback) local fontdata = data.fonts and data.fonts[alternative] local style = data.metadata.style @@ -526,20 +536,24 @@ local function definefontsynonym(data,alternative,index,fallback) local designsize = entry["designsize"] or 100 if designsize == 100 or designsize == 110 or designsize == 120 or designsize == 0 or #fontdata == 1 then local filepath, filename = splitbase(entry["filename"]) + if entry["format"] == "ttc" or entry["format"] == "dfont" then + filename = formatters["%s(%s)"](filename, entry["rawname"]) + end registerdesignsizes( fontfile, "default", filename ) break end end if fallback then - context.definefontsynonym( { fontname }, { fontfile }, { features = features } ) + -- can we use + ctx_definefontsynonym( { fontname }, { fontfile }, { features = features } ) else - context.definefontsynonym( { fontname }, { fontfile }, { features = features, fallbacks = fontfile, goodies = goodies } ) + ctx_definefontsynonym( { fontname }, { fontfile }, { features = features, fallbacks = fontfile, goodies = goodies } ) end else if fallback then - context.definefontsynonym( { fontname }, { fontparent }, { features = features } ) + ctx_definefontsynonym( { fontname }, { fontparent }, { features = features } ) else - context.definefontsynonym( { fontname }, { fontparent }, { features = features, fallbacks = fontfile, goodies = goodies } ) + ctx_definefontsynonym( { fontname }, { fontparent }, { features = features, fallbacks = fontfile, goodies = goodies } ) end end end @@ -552,11 +566,11 @@ local function definetypescript(index) local typeface = data.metadata.typeface local style = data.metadata.style if entry and entry["tf"] then - context.startfontclass( { typeface } ) + ctx_startfontclass( { typeface } ) if goodies ~= "" then goodies = utilities.parsers.settings_to_array(goodies) for _, goodie in next, goodies do - context.loadfontgoodies( { goodie } ) + ctx_loadfontgoodies( { goodie } ) end end for alternative, _ in next, alternatives do @@ -564,7 +578,7 @@ local function definetypescript(index) definefontsynonym(data,alternative) end end - context.stopfontclass() + ctx_stopfontclass() else -- regular style not available, loading aborted end @@ -595,20 +609,20 @@ local function definetextfontfallback(data,alternative,index) local synonym = formatters["%s-%s-%s-fallback-%s"](typeface, style, alternative, index) local fallback = formatters["%s-%s-%s"] (typeface, style, alternative) if index == 1 then - context.resetfontfallback( { fallback } ) + ctx_resetfontfallback( { fallback } ) end - context.definefontfallback( { fallback }, { synonym }, { range }, { rscale = rscale, check = check, force = force } ) + ctx_definefontfallback( { fallback }, { synonym }, { range }, { rscale = rscale, check = check, force = force } ) end local function definetextfallback(entry,index) local data = data[index] local typeface = data.metadata.typeface - context.startfontclass( { typeface } ) + ctx_startfontclass( { typeface } ) for alternative, _ in next, alternatives do definefontsynonym (data,alternative,entry,true) definetextfontfallback(data,alternative,entry) end - context.stopfontclass() + ctx_stopfontclass() -- inspect(data) end @@ -624,14 +638,14 @@ local function definemathfontfallback(data,alternative,index) local fontdata = data.fonts and data.fonts[alternative] local fallback = formatters["%s-%s-%s"](typeface, style, alternative) if index == 1 then - context.resetfontfallback( { fallback } ) + ctx_resetfontfallback( { fallback } ) end if fontdata and #fontdata > 0 then for _, entry in next, fontdata do local filename = entry["filename"] local designsize = entry["designsize"] or 100 if designsize == 100 or designsize == 110 or designsize == 120 or designsize == 0 or #fontdata == 1 then - context.definefontfallback( { fallback }, { formatters["file:%s*%s"](filename,features) }, { range }, { rscale = rscale, check = check, force = force, offset = offset } ) + ctx_definefontfallback( { fallback }, { formatters["file:%s*%s"](filename,features) }, { range }, { rscale = rscale, check = check, force = force, offset = offset } ) break end end @@ -642,13 +656,13 @@ local function definemathfallback(entry,index) local data = data[index] local typeface = data.metadata.typeface local style = data.metadata.style - context.startfontclass( { typeface } ) + ctx_startfontclass( { typeface } ) for alternative, _ in next, alternatives do if synonyms[style][alternative] then definemathfontfallback(data,alternative,entry) end end - context.stopfontclass() + ctx_stopfontclass() -- inspect(data) end @@ -676,7 +690,7 @@ local function definetextfont(index) local style = styles[data.metadata.style] local designsize = data.options.opticals == v_yes and "auto" or "default" local scale = data.options.scale ~= "" and data.options.scale or 1 - context.definetypeface( { fontclass }, { shortstyle }, { style }, { "" }, { "default" }, { designsize = designsize, rscale = scale } ) + ctx_definetypeface( { fontclass }, { shortstyle }, { style }, { "" }, { "default" }, { designsize = designsize, rscale = scale } ) end local function definemathfont(index) @@ -688,9 +702,9 @@ local function definemathfont(index) local typescript = cleanname(data.metadata.family) local entries = data.fonts if entries then - context.definetypeface( { fontclass }, { shortstyle }, { style }, { "" }, { "default" }, { rscale = scale } ) + ctx_definetypeface( { fontclass }, { shortstyle }, { style }, { "" }, { "default" }, { rscale = scale } ) else - context.definetypeface( { fontclass }, { shortstyle }, { style }, { typescript }, { "default" }, { rscale = scale } ) + ctx_definetypeface( { fontclass }, { shortstyle }, { style }, { typescript }, { "default" }, { rscale = scale } ) end end @@ -708,5 +722,49 @@ function selectfont.definetypeface(index) -- inspect(data) end -commands.definefontfamily = selectfont.definetypeface -commands.definefallbackfamily = selectfont.registerfallback +local styles = { + { "tf" }, { "bf" }, { "it" }, { "sl" }, { "bi" }, { "bs" }, { "sc" }, +} + +implement { + name = "defineselectfont", + actions = { selectfont.define, context }, + arguments = { + { + { + "metadata", { + { "typeface" }, + { "style" }, + { "family" }, + } + }, + { + "options", { + { "opticals" }, + { "scale" }, + { "goodies" }, + { "alternative" }, + { "range" }, + { "offset" }, + { "check" }, + { "force" }, + } + }, + { "alternatives", styles }, + { "files", styles }, + { "features", styles }, + } + } +} + +implement { + name = "definefontfamily", + actions = selectfont.definetypeface, + arguments = "integer" +} + +implement { + name = "definefallbackfamily", + actions = selectfont.registerfallback, + arguments = { "string", "string", "integer"} +} diff --git a/Master/texmf-dist/tex/context/base/font-sel.mkvi b/Master/texmf-dist/tex/context/base/font-sel.mkvi index 0b9a4bda987..820d211eb69 100644 --- a/Master/texmf-dist/tex/context/base/font-sel.mkvi +++ b/Master/texmf-dist/tex/context/base/font-sel.mkvi @@ -1,6 +1,6 @@ %D \module %D [ file=font-sel, -%D version=2014.03.10, +%D version=2014.07.27, %D title=\CONTEXT\ User Module, %D subtitle=Selectfont, %D author=Wolfgang Schuster, @@ -27,51 +27,49 @@ \fi \setexpandedselectfontparameter\c!style {\expandnamespaceparameter\??selectfontstyle \selectfontparameter\c!style \s!rm }% \setexpandedselectfontparameter\c!alternative{\expandnamespaceparameter\??selectfontalternative\selectfontparameter\c!alternative\v!default}% - \xdef\selectfont_index{\ctxcommand{ - defineselectfont { - metadata = { - typeface = "\selectfontparameter\c!name", - style = "\selectfontparameter\c!style", - family = "\selectfontparameter\c!family", - }, - options = { - opticals = "\selectfontparameter\c!opticalsize", - scale = "\selectfontparameter\c!scale", - goodies = "\selectfontparameter\c!goodies", - alternative = "\selectfontparameter\c!alternative", - range = "\selectfontparameter\c!range", % fallback only - offset = "\selectfontparameter\c!offset", % fallback only - check = "\selectfontparameter\c!check", % fallback only - force = "\selectfontparameter\c!force", % fallback only - }, - alternatives = { - ["tf"] = "\selectfontparameter\s!tf", - ["bf"] = "\selectfontparameter\s!bf", - ["it"] = "\selectfontparameter\s!it", - ["sl"] = "\selectfontparameter\s!sl", - ["bi"] = "\selectfontparameter\s!bi", - ["bs"] = "\selectfontparameter\s!bs", - ["sc"] = "\selectfontparameter\s!sc", - }, - files = { - ["tf"] = "\selectfontparameter\c!regularfont", - ["bf"] = "\selectfontparameter\c!boldfont", - ["it"] = "\selectfontparameter\c!italicfont", - ["sl"] = "\selectfontparameter\c!slantedfont", - ["bi"] = "\selectfontparameter\c!bolditalicfont", - ["bs"] = "\selectfontparameter\c!boldslantedfont", - ["sc"] = "\selectfontparameter\c!smallcapsfont", - }, - features = { - ["tf"] = "\selectfontparameter\c!regularfeatures", - ["bf"] = "\selectfontparameter\c!boldfeatures", - ["it"] = "\selectfontparameter\c!italicfeatures", - ["sl"] = "\selectfontparameter\c!slantedfeatures", - ["bi"] = "\selectfontparameter\c!bolditalicfeatures", - ["bs"] = "\selectfontparameter\c!boldslantedfeatures", - ["sc"] = "\selectfontparameter\c!smallcapsfeatures", - } - }}}% + \xdef\selectfont_index{\clf_defineselectfont + metadata {% + typeface {\selectfontparameter\c!name}% + style {\selectfontparameter\c!style}% + family {\selectfontparameter\c!family}% + } + options {% + opticals {\selectfontparameter\c!opticalsize}% + scale {\selectfontparameter\c!scale}% + goodies {\selectfontparameter\c!goodies}% + alternative {\selectfontparameter\c!alternative}% + range {\selectfontparameter\c!range}% fallback only + offset {\selectfontparameter\c!offset}% fallback only + check {\selectfontparameter\c!check}% fallback only + force {\selectfontparameter\c!force}% fallback only + } + alternatives {% + tf {\selectfontparameter\s!tf}% + bf {\selectfontparameter\s!bf}% + it {\selectfontparameter\s!it}% + sl {\selectfontparameter\s!sl}% + bi {\selectfontparameter\s!bi}% + bs {\selectfontparameter\s!bs}% + sc {\selectfontparameter\s!sc}% + } + files {% + tf {\selectfontparameter\c!regularfont}% + bf {\selectfontparameter\c!boldfont}% + it {\selectfontparameter\c!italicfont}% + sl {\selectfontparameter\c!slantedfont}% + bi {\selectfontparameter\c!bolditalicfont}% + bs {\selectfontparameter\c!boldslantedfont}% + sc {\selectfontparameter\c!smallcapsfont}% + } + features {% + tf {\selectfontparameter\c!regularfeatures}% + bf {\selectfontparameter\c!boldfeatures}% + it {\selectfontparameter\c!italicfeatures}% + sl {\selectfontparameter\c!slantedfeatures}% + bi {\selectfontparameter\c!bolditalicfeatures}% + bs {\selectfontparameter\c!boldslantedfeatures}% + sc {\selectfontparameter\c!smallcapsfeatures}% + }}% \endgroup} %D \macros @@ -104,7 +102,7 @@ {\dodoubleargument\selectfont_preset_define} \def\selectfont_preset_define[#name][#settings]% - {\doifassignmentelse{#settings} + {\doifelseassignment{#settings} {\setvalue{\??selectfontpreset#name}{\setupcurrentselectfont[#settings]}} {\setvalue{\??selectfontpreset#name}{\csname\??selectfontpreset#settings\endcsname}}} @@ -115,18 +113,74 @@ % unknown preset \fi} -%definefontfamilypreset [range:chinese] [\c!range={cjkcompatibilityforms,cjkcompatibilityideographs,cjkcompatibilityideographssupplement,cjkradicalssupplement,cjkstrokes,cjksymbolsandpunctuation,cjkunifiedideographs,cjkunifiedideographsextensiona,cjkunifiedideographsextensionb,halfwidthandfullwidthforms,verticalforms,bopomofo,bopomofoextended}] -%definefontfamilypreset [range:japanese] [\c!range={cjkcompatibilityforms,cjkcompatibilityideographs,cjkcompatibilityideographssupplement,cjkradicalssupplement,cjkstrokes,cjksymbolsandpunctuation,cjkunifiedideographs,cjkunifiedideographsextensiona,cjkunifiedideographsextensionb,halfwidthandfullwidthforms,verticalforms,hiragana,katakana}] -%definefontfamilypreset [range:korean] [\c!range={cjkcompatibilityforms,cjkcompatibilityideographs,cjkcompatibilityideographssupplement,cjkradicalssupplement,cjkstrokes,cjksymbolsandpunctuation,cjkunifiedideographs,cjkunifiedideographsextensiona,cjkunifiedideographsextensionb,halfwidthandfullwidthforms,verticalforms,hangulcompatibilityjamo,hanguljamo,hanguljamoextendeda,hanguljamoextendedb,hangulsyllables}] -%definefontfamilypreset [range:cyrillic] [\c!range={cyrillic,cyrillicextendeda,cyrillicextendedb,cyrillicsupplement}] -%definefontfamilypreset [range:greek] [\c!range={greekandcoptic,greekextended,ancientgreeknumbers}] - -\definefontfamilypreset [range:chinese] [\c!range={0x02E80-0x02EFF,0x03000-0x031EF,0x03300-0x09FFF,0x0F900-0x0FFEF,0x20000-0x2A6DF,0x2F800-0x2FA1F,0x03100-0x0312F,0x031A0-0x031BF}] -\definefontfamilypreset [range:japanese] [\c!range={0x02E80-0x02EFF,0x03000-0x031EF,0x03300-0x09FFF,0x0F900-0x0FFEF,0x20000-0x2A6DF,0x2F800-0x2FA1F,0x03040-0x0309F,0x030A0-0x030FF}] -\definefontfamilypreset [range:korean] [\c!range={0x02E80-0x02EFF,0x03000-0x031EF,0x03300-0x09FFF,0x0F900-0x0FFEF,0x20000-0x2A6DF,0x2F800-0x2FA1F,0x01100-0x011FF,0x03130-0x0318F,0x0A960-0x0D7FF}] -\definefontfamilypreset [range:cyrillic] [\c!range={0x00400-0x0052F,0x02DE0-0x02DFF,0x0A640-0x0A69F}] -\definefontfamilypreset [range:greek] [\c!range={0x00370-0x003FF,0x01F00-0x01FFF,0x10140-0x1018F}] -\definefontfamilypreset [range:hebrew] [\c!range={0x00590-0x005FF,0x0FB00-0x0FB4F}] +\definefontfamilypreset + [range:chinese] + [\c!range={cjkcompatibilityforms, + cjkcompatibilityideographs, + cjkcompatibilityideographssupplement, + cjkradicalssupplement, + cjkstrokes, + cjksymbolsandpunctuation, + cjkunifiedideographs, + cjkunifiedideographsextensiona, + cjkunifiedideographsextensionb, + halfwidthandfullwidthforms, + verticalforms, + bopomofo, + bopomofoextended}] + +\definefontfamilypreset + [range:japanese] + [\crange={cjkcompatibilityforms, + cjkcompatibilityideographs, + cjkcompatibilityideographssupplement, + cjkradicalssupplement, + cjkstrokes, + cjksymbolsandpunctuation, + cjkunifiedideographs, + cjkunifiedideographsextensiona, + cjkunifiedideographsextensionb, + halfwidthandfullwidthforms, + verticalforms, + hiragana, + katakana}] + +\definefontfamilypreset + [range:korean] + [\c!range={cjkcompatibilityforms, + cjkcompatibilityideographs, + cjkcompatibilityideographssupplement, + cjkradicalssupplement, + cjkstrokes, + cjksymbolsandpunctuation, + cjkunifiedideographs, + cjkunifiedideographsextensiona, + cjkunifiedideographsextensionb, + halfwidthandfullwidthforms, + verticalforms, + hangulcompatibilityjamo, + hanguljamo, + hanguljamoextendeda, + hanguljamoextendedb, + hangulsyllables}] + +\definefontfamilypreset + [range:cyrillic] + [\c!range={cyrillic, + cyrillicextendeda, + cyrillicextendedb, + cyrillicsupplement}] + +\definefontfamilypreset + [range:greek] + [\c!range={greekandcoptic, + greekextended, + ancientgreeknumbers}] + +\definefontfamilypreset + [range:hebrew] + [\c!range={hebrew, + alphabeticpresentationforms}] \definefontfamilypreset [math:digitsnormal] [\c!range=digitsnormal] \definefontfamilypreset [math:digitsbold] [\c!range=digitsnormal,\c!offset=digitsbold,\s!tf=style:bold] @@ -226,7 +280,7 @@ %D \stoptyping %D %D When a document contains different languages and the global font lacks some characters -%D for one language, one could set a different font where these characters are taken from. +%D for one language, one could set a different font where these charcters are taken from. %D This fallback font (there can be more than one for a certain style) could be set with %D the \tex{definefallbackfamily} command which takes the same argument as %D the \tex{definefontfamily} command. @@ -271,20 +325,20 @@ {\doquadrupleempty\selectfont_family_define} \def\selectfont_family_define[#typeface][#style][#family][#settings]% - {\doifassignmentelse{#settings} + {\doifelseassignment{#settings} {\selectfont_setparameters[\c!name={#typeface},\c!style={#style},\c!family={#family},#settings]} {\selectfont_setparameters[\c!name={#typeface},\c!style={#style},\c!family={#family},\c!preset={#settings}]}% - \ctxcommand{definefontfamily(\selectfont_index)}} + \clf_definefontfamily\selectfont_index\relax} \unexpanded\def\definefallbackfamily {\doquadrupleempty\selectfont_fallback_define} \def\selectfont_fallback_define[#typeface][#style][#family][#settings]% - {\doifassignmentelse{#settings} + {\doifelseassignment{#settings} {\selectfont_setparameters[\c!name={#typeface},\c!style={#style},\c!family={#family},#settings]} {\selectfont_setparameters[\c!name={#typeface},\c!style={#style},\c!family={#family},\c!preset={#settings}]}% \edef\p_selectfont_style{\expandnamespacevalue\??selectfontstyle{#style}\s!rm}% - \ctxcommand{definefallbackfamily("#typeface","\p_selectfont_style",\selectfont_index)}} + \clf_definefallbackfamily{#typeface}{\p_selectfont_style}\selectfont_index\relax} %D \macros %D {setupfontfamily,setupfallbackfamily} @@ -332,7 +386,8 @@ \unexpanded\def\selectfont_set_default {\selectfont_set_font_family[\v!serif][Latin Modern Roman][\c!opticalsize=\v!yes]% \selectfont_set_font_family[\v!sans] [Latin Modern Sans] [\c!opticalsize=\v!yes]% - \selectfont_set_font_family[\v!mono] [Latin Modern Mono] [\c!opticalsize=\v!yes,\c!features=\s!none]} + \selectfont_set_font_family[\v!mono] [Latin Modern Mono] [\c!opticalsize=\v!yes,\c!features=\s!none]% + \selectfont_set_font_family[\v!math] [Latin Modern Math] [\c!opticalsize=\v!yes]} \unexpanded\def\setupfallbackfamily {\dotripleempty\selectfont_fallback_setup} diff --git a/Master/texmf-dist/tex/context/base/font-set.mkvi b/Master/texmf-dist/tex/context/base/font-set.mkvi index f94d6c86e0c..b29545ace3f 100644 --- a/Master/texmf-dist/tex/context/base/font-set.mkvi +++ b/Master/texmf-dist/tex/context/base/font-set.mkvi @@ -41,13 +41,15 @@ \let\m_font_fallback_name\empty -\def\font_preloads_reset_nullfont % this is needed because some macro packages (tikz) misuse \nullfont - {\dorecurse\plusseven{\fontdimen\recurselevel\nullfont\zeropoint}% keep en eye on this as: - \ctxcommand{resetnullfont()}% in luatex 0.70 this will also do the previous - \globallet\font_preloads_reset_nullfont\relax} +% keep as reference: +% +% \def\font_preloads_reset_nullfont % this is needed because some macro packages (tikz) misuse \nullfont +% {\dorecurse\plusseven{\fontdimen\recurselevel\nullfont\zeropoint}% keep en eye on this as: +% \clf_resetnullfont % in luatex 0.70 this will also do the previous +% \globallet\font_preloads_reset_nullfont\relax} \def\font_preload_check_mode - {\doifmodeelse{lmmath} + {\doifelsemode{lmmath} {\def\m_font_fallback_name{modern-designsize-virtual}}% this will stay {\def\m_font_fallback_name{modern-designsize}}% % this might become 'modern' \glet\font_preload_check_mode\relax} @@ -81,7 +83,8 @@ \glet\fourthstagepreloadfonts \relax \global\everyhbox\emptytoks \global\everyvbox\emptytoks - \font_preloads_reset_nullfont} + % old: \font_preloads_reset_nullfont, new: + \clf_resetnullfont} \appendtoks \font_preloads_reset @@ -90,7 +93,9 @@ \def\font_preloads_reset_checked {\glet\font_preload_default_fonts_tt\relax \glet\font_preload_default_fonts_mm\relax - \glet\font_preloads_third_stage \relax} + \glet\font_preloads_third_stage \relax +% \glet\font_preloads_fourth_stage \relax + } \def\font_preloads_zero_stage_indeed {\definedfont[\s!file:lmmono10-regular sa 1]} @@ -101,7 +106,7 @@ \font_preloads_zero_stage} \unexpanded\def\font_preloads_first_stage % % *nofonts -> *preloadfonts - {\doifmodeelse{*preloadfonts} + {\doifelsemode{*preloadfonts} {\font_preload_default_fonts \writestatus\m!fonts{preloading latin modern fonts (first stage)}} {\writestatus\m!fonts{latin modern fonts are not preloaded}}} @@ -132,7 +137,7 @@ \unexpanded\def\font_preloads_fourth_stage {\begingroup %ifzeropt\fontcharwd\font\number`!\relax - \setbox\scratchbox\hbox{checking fonts}% + \setbox\scratchbox\hbox{c o n t e x t}% \ifzeropt\wd\scratchbox \writeline \writestatus\m!fonts{!! No bodyfont has been defined and no defaults have been}% diff --git a/Master/texmf-dist/tex/context/base/font-sol.lua b/Master/texmf-dist/tex/context/base/font-sol.lua index a41e4a67946..bbb2997f42b 100644 --- a/Master/texmf-dist/tex/context/base/font-sol.lua +++ b/Master/texmf-dist/tex/context/base/font-sol.lua @@ -45,6 +45,8 @@ local v_preroll = variables.preroll local v_random = variables.random local v_split = variables.split +local implement = interfaces.implement + local settings_to_array = utilities.parsers.settings_to_array local settings_to_hash = utilities.parsers.settings_to_hash @@ -907,8 +909,52 @@ end -- interface -commands.definefontsolution = splitters.define -commands.startfontsolution = splitters.start -commands.stopfontsolution = splitters.stop -commands.setfontsolution = splitters.set -commands.resetfontsolution = splitters.reset +implement { + name = "definefontsolution", + actions = splitters.define, + arguments = { + "string", + { + { "goodies" }, + { "solution" }, + { "less" }, + { "more" }, + } + } +} + +implement { + name = "startfontsolution", + actions = splitters.start, + arguments = { + "string", + { + { "method" }, + { "criterium" }, + { "randomseed" }, + } + } +} + +implement { + name = "stopfontsolution", + actions = splitters.stop +} + +implement { + name = "setfontsolution", + actions = splitters.set, + arguments = { + "string", + { + { "method" }, + { "criterium" }, + { "randomseed" }, + } + } +} + +implement { + name = "resetfontsolution", + actions = splitters.reset +} diff --git a/Master/texmf-dist/tex/context/base/font-sol.mkvi b/Master/texmf-dist/tex/context/base/font-sol.mkvi index b40e37ceddf..d065b78ea55 100644 --- a/Master/texmf-dist/tex/context/base/font-sol.mkvi +++ b/Master/texmf-dist/tex/context/base/font-sol.mkvi @@ -85,24 +85,30 @@ \let\setupfontsolutions\setupfontsolution \appendtoks - \ctxcommand{definefontsolution("\currentfontsolution",{ % these are frozen - goodies = "\fontsolutionparameter\s!goodies", - solution = "\fontsolutionparameter\c!solution", - less = "\fontsolutionparameter\c!less", - more = "\fontsolutionparameter\c!more", - })} + \clf_definefontsolution + {\currentfontsolution}% + {% these are frozen + goodies {\fontsolutionparameter\s!goodies}% + solution {\fontsolutionparameter\c!solution}% + less {\fontsolutionparameter\c!less}% + more {\fontsolutionparameter\c!more}% + }% + \relax \to \everydefinefontsolution \unexpanded\def\setfontsolution[#solution]% just one {\edef\currentfontsolution{#solution}% - \ctxcommand{setfontsolution("\currentfontsolution",{ - method = "\fontsolutionparameter\c!method", - criterium = "\fontsolutionparameter\c!criterium", - % randomseed = "\fontsolutionparameter\c!random", - })}} + \clf_setfontsolution + {\currentfontsolution}% + {% + method {\fontsolutionparameter\c!method}% + criterium {\fontsolutionparameter\c!criterium}% + % randomseed {\fontsolutionparameter\c!random}% + }% + \relax} \unexpanded\def\resetfontsolution % resets all - {\ctxcommand{resetfontsolution()}% + {\clf_resetfontsolution \let\currentfontsolution\empty} \unexpanded\def\startfontsolution % [#1] @@ -111,7 +117,7 @@ \unexpanded\def\stopfontsolution {\ifhmode\par\fi - \ctxcommand{stopfontsolution()}% + \clf_stopfontsolution \popmacro\currentfontsolution} % We initialize this module at the \LUA\ end. diff --git a/Master/texmf-dist/tex/context/base/font-sty.mkvi b/Master/texmf-dist/tex/context/base/font-sty.mkvi index 03fa598c2f2..673cf25aecd 100644 --- a/Master/texmf-dist/tex/context/base/font-sty.mkvi +++ b/Master/texmf-dist/tex/context/base/font-sty.mkvi @@ -279,7 +279,7 @@ {\groupedcommand{\font_styles_use_defined{#name}}{}} % or {\font_styles_apply_grouped{#name}} \setvalue{\??styleargument3}#specification% - {\doifassignmentelse{#specification}\font_styles_assignment\font_styles_direct{#specification}} + {\doifelseassignment{#specification}\font_styles_assignment\font_styles_direct{#specification}} \def\font_styles_assignment#specification{\groupedcommand{\font_styles_use_generic{#specification}}{}} \def\font_styles_direct #specification{\groupedcommand{\definedfont[#specification]}{}} @@ -311,7 +311,7 @@ {\font_styles_use_defined{#name}} \setvalue{\??styleenvironment3}#specification% - {\doifassignmentelse{#specification}\font_styles_start_assignment\font_styles_start_direct{#specification}} + {\doifelseassignment{#specification}\font_styles_start_assignment\font_styles_start_direct{#specification}} \def\font_styles_start_assignment#specification{\font_styles_use_generic{#specification}} \def\font_styles_start_direct #specification{\definedfont[#specification]\relax} diff --git a/Master/texmf-dist/tex/context/base/font-sym.mkvi b/Master/texmf-dist/tex/context/base/font-sym.mkvi index c8ca49f7470..a21bea0ba62 100644 --- a/Master/texmf-dist/tex/context/base/font-sym.mkvi +++ b/Master/texmf-dist/tex/context/base/font-sym.mkvi @@ -110,12 +110,14 @@ %D The next macro can be used to make decisions based on the shape: -\def\doifitalicelse#yes#nop% +\def\doifelseitalic#yes#nop% {\ifx\fontalternative\s!sl#yes\else \ifx\fontalternative\s!it#yes\else \ifx\fontalternative\s!bs#yes\else \ifx\fontalternative\s!bi#yes\else#nop\fi\fi\fi\fi} +\let\doifitalicelse\doifelseitalic + %D For an example of usage of the following command, %D see \type {cont-log.tex}. %D @@ -167,15 +169,15 @@ \currentsymbolfont \global\expandafter\let\csname\??symbolfont\askedsymbolfont\endcsname\lastrawfontcall} -\unexpanded\def\getnamedglyphstyled#fontname#character{{\setstyledsymbolicfont{#fontname}\ctxcommand{fontchar("#character")}}} -\unexpanded\def\getnamedglyphdirect#fontname#character{{\setdirectsymbolicfont{#fontname}\ctxcommand{fontchar("#character")}}} -\unexpanded\def\getglyphstyled #fontname#character{{\setstyledsymbolicfont{#fontname}\doifnumberelse{#character}\char\donothing#character}} -\unexpanded\def\getglyphdirect #fontname#character{{\setdirectsymbolicfont{#fontname}\doifnumberelse{#character}\char\donothing#character}} +\unexpanded\def\getnamedglyphstyled#fontname#character{{\setstyledsymbolicfont{#fontname}\clf_fontchar{#character}}} +\unexpanded\def\getnamedglyphdirect#fontname#character{{\setdirectsymbolicfont{#fontname}\clf_fontchar{#character}}} +\unexpanded\def\getglyphstyled #fontname#character{{\setstyledsymbolicfont{#fontname}\doifelsenumber{#character}\char\donothing#character}} +\unexpanded\def\getglyphdirect #fontname#character{{\setdirectsymbolicfont{#fontname}\doifelsenumber{#character}\char\donothing#character}} % this one is wrong: \unexpanded\def\getscaledglyph#scale#name#content% - {{\setscaledstyledsymbolicfont\fontbody{#scale}{#name}\doifnumberelse{#content}\char\donothing#content}} + {{\setscaledstyledsymbolicfont\fontbody{#scale}{#name}\doifelsenumber{#content}\char\donothing#content}} \let\getglyph \getglyphstyled % old \let\getrawglyph \getglyphdirect % old @@ -234,7 +236,7 @@ %D \macros{doiffontcharelse} -\unexpanded\def\doiffontcharelse#specification#unicode% this could be a direct lua call +\unexpanded\def\doifelsefontchar#specification#unicode% this could be a direct lua call {\begingroup \font_basics_define_font_without_parameters{thedefinedfont}{#specification}% \iffontchar\font#unicode\relax @@ -243,4 +245,6 @@ \endgroup\expandafter\secondoftwoarguments \fi} +\let\doiffontcharelse\doifelsefontchar + \protect \endinput diff --git a/Master/texmf-dist/tex/context/base/font-syn.lua b/Master/texmf-dist/tex/context/base/font-syn.lua index 18ed46a2f88..bf46c85730f 100644 --- a/Master/texmf-dist/tex/context/base/font-syn.lua +++ b/Master/texmf-dist/tex/context/base/font-syn.lua @@ -33,7 +33,14 @@ local exists = io.exists local findfile = resolvers.findfile local cleanpath = resolvers.cleanpath -local resolveresolved = resolvers.resolve +local resolveprefix = resolvers.resolve + +local fontloader = fontloader +local font_to_table = fontloader.to_table +local open_font = fontloader.open +local get_font_info = fontloader.info +local close_font = fontloader.close +local font_fields = fontloader.fields local settings_to_hash = utilities.parsers.settings_to_hash_tolerant @@ -50,7 +57,7 @@ using a table that has keys filtered from the font related files. fonts = fonts or { } -- also used elsewhere -local names = font.names or allocate { } +local names = fonts.names or allocate { } fonts.names = names local filters = names.filters or { } @@ -298,10 +305,10 @@ end but to keep the overview, we define them here. --ldx]]-- -filters.otf = fontloader.info -filters.ttf = fontloader.info -filters.ttc = fontloader.info -filters.dfont = fontloader.info +filters.otf = get_font_info +filters.ttf = get_font_info +filters.ttc = get_font_info +filters.dfont = get_font_info -- We had this as temporary solution because we needed a bit more info but in the -- meantime it got an interesting side effect: currently luatex delays loading of e.g. @@ -311,12 +318,12 @@ filters.dfont = fontloader.info -- missing: names, units_per_em, design_range_bottom, design_range_top, design_size, -- pfminfo, top_side_bearing --- function fontloader.fullinfo(...) -- check with taco what we get / could get --- local ff = fontloader.open(...) +-- local function get_full_info(...) -- check with taco what we get / could get +-- local ff = open_font(...) -- if ff then --- local d = ff -- and fontloader.to_table(ff) +-- local d = ff -- and font_to_table(ff) -- d.glyphs, d.subfonts, d.gpos, d.gsub, d.lookups = nil, nil, nil, nil, nil --- fontloader.close(ff) +-- close_font(ff) -- return d -- else -- return nil, "error in loading font" @@ -327,10 +334,10 @@ filters.dfont = fontloader.info -- return these keys/values (and maybe some more) but at least we close the loader which -- might save some memory in the end. --- function fontloader.fullinfo(name) --- local ff = fontloader.open(name) +-- local function get_full_info(name) +-- local ff = open_font(name) -- if ff then --- local fields = table.tohash(fontloader.fields(ff),true) +-- local fields = table.tohash(font_fields(ff),true) -- isn't that one stable -- local d = { -- names = fields.names and ff.names, -- familyname = fields.familyname and ff.familyname, @@ -349,36 +356,68 @@ filters.dfont = fontloader.info -- setmetatableindex(d,function(t,k) -- report_names("warning, trying to access field %a in font table of %a",k,name) -- end) --- fontloader.close(ff) +-- close_font(ff) -- return d -- else -- return nil, "error in loading font" -- end -- end --- As we have lazy loading anyway, this one still is full and with less code than --- the previous one. But this depends on the garbage collector to kick in. +-- more efficient: + +local fields = nil -function fontloader.fullinfo(...) - local ff = fontloader.open(...) +local function get_full_info(name) + local ff = open_font(name) if ff then - local d = { } -- ff is userdata so [1] or # fails on it - setmetatableindex(d,ff) + if not fields then + fields = table.tohash(font_fields(ff),true) + end + -- unfortunately luatex aborts when a field is not available + local d = { + names = fields.names and ff.names, + familyname = fields.familyname and ff.familyname, + fullname = fields.fullname and ff.fullname, + fontname = fields.fontname and ff.fontname, + weight = fields.weight and ff.weight, + italicangle = fields.italicangle and ff.italicangle, + units_per_em = fields.units_per_em and ff.units_per_em, + design_range_bottom = fields.design_range_bottom and ff.design_range_bottom, + design_range_top = fields.design_range_top and ff.design_range_top, + design_size = fields.design_size and ff.design_size, + italicangle = fields.italicangle and ff.italicangle, + pfminfo = fields.pfminfo and ff.pfminfo, + top_side_bearing = fields.top_side_bearing and ff.top_side_bearing, -- not there + } + setmetatableindex(d,function(t,k) + report_names("warning, trying to access field %a in font table of %a",k,name) + end) + close_font(ff) return d else return nil, "error in loading font" end end --- We don't get the design_* values here as for that the fontloader has to load feature --- info and therefore we're not much better off than using 'open'. --- --- if tonumber(status.luatex_version) > 78 or (tonumber(status.luatex_version) == 78 and tonumber(status.luatex_revision) > 0) then --- fontloader.fullinfo = fontloader.info +-- As we have lazy loading anyway, this one still is full and with less code than +-- the previous one. But this depends on the garbage collector to kick in and in the +-- current version that somehow happens not that often (on my machine I end up with +-- soem 3 GB extra before that happens). + +-- local function get_full_info(...) +-- local ff = open_font(...) +-- if ff then +-- local d = { } -- ff is userdata so [1] or # fails on it +-- setmetatableindex(d,ff) +-- return d -- garbage collection will do the close_font(ff) +-- else +-- return nil, "error in loading font" +-- end -- end -filters.otf = fontloader.fullinfo -filters.ttf = fontloader.fullinfo +fontloader.fullinfo = get_full_info +filters .otf = get_full_info +filters .ttf = get_full_info function filters.afm(name) -- we could parse the afm file as well, and then report an error but @@ -408,7 +447,7 @@ function filters.afm(name) end function filters.pfb(name) - return fontloader.info(name) + return get_font_info(name) end --[[ldx-- @@ -1065,15 +1104,15 @@ local function analyzefiles(olddata) resolvers.dowithfilesintree(".*%." .. suffix .. "$", function(method,root,path,name) if method == "file" or method == "tree" then local completename = root .."/" .. path .. "/" .. name - completename = resolveresolved(completename) -- no shortcut + completename = resolveprefix(completename) -- no shortcut identify(completename,name,suffix,name) return true end end, function(blobtype,blobpath,pattern) - blobpath = resolveresolved(blobpath) -- no shortcut + blobpath = resolveprefix(blobpath) -- no shortcut report_names("scanning path %a for %s files",blobpath,suffix) end, function(blobtype,blobpath,pattern,total,checked,done) - blobpath = resolveresolved(blobpath) -- no shortcut + blobpath = resolveprefix(blobpath) -- no shortcut report_names("%s entries found, %s %s files checked, %s okay",total,checked,suffix,done) end) end diff --git a/Master/texmf-dist/tex/context/base/font-tfm.lua b/Master/texmf-dist/tex/context/base/font-tfm.lua index 827d7058696..ab03788516a 100644 --- a/Master/texmf-dist/tex/context/base/font-tfm.lua +++ b/Master/texmf-dist/tex/context/base/font-tfm.lua @@ -70,16 +70,17 @@ local function read_from_tfm(specification) properties.fontname = tfmdata.fontname properties.psname = tfmdata.psname properties.filename = specification.filename + properties.format = fonts.formats.tfm -- better than nothing parameters.size = size - shared.rawdata = { } - shared.features = features - shared.processes = next(features) and tfm.setfeatures(tfmdata,features) or nil -- tfmdata.properties = properties tfmdata.resources = resources tfmdata.parameters = parameters tfmdata.shared = shared -- + shared.rawdata = { } + shared.features = features + shared.processes = next(features) and tfm.setfeatures(tfmdata,features) or nil parameters.slant = parameters.slant or parameters[1] or 0 parameters.space = parameters.space or parameters[2] or 0 parameters.space_stretch = parameters.space_stretch or parameters[3] or 0 @@ -114,6 +115,11 @@ local function read_from_tfm(specification) features.encoding = encoding end end + -- let's play safe: + properties.haskerns = true + properties.haslogatures = true + resources.unicodes = { } + resources.lookuptags = { } -- return tfmdata end diff --git a/Master/texmf-dist/tex/context/base/font-tra.mkiv b/Master/texmf-dist/tex/context/base/font-tra.mkiv index 45d8a728059..b0c3ae55b5a 100644 --- a/Master/texmf-dist/tex/context/base/font-tra.mkiv +++ b/Master/texmf-dist/tex/context/base/font-tra.mkiv @@ -95,7 +95,9 @@ %D \doiffontpresentelse{adam-lindsay-modern-serif}{YES}{NO} %D \stoptyping -\unexpanded\def\doiffontpresentelse#1{\ctxcommand{doifelse(fonts.names.exists("#1"))}} +\unexpanded\def\doifelsefontpresent#1{\clf_doifelsefontpresent{#1}} + +\let\doiffontpresentelse\doifelsefontpresent % experimental, maybe this becomes a module @@ -114,11 +116,14 @@ {\ctxlua{nodes.tracers.steppers.glyphs(\number\otfcollector,#1)}% \unhbox\otfcollector} -\unexpanded\def\otfstepcharcommand#1#2#3% font char class +\unexpanded\def\otfstepspace {\removeunwantedspaces - \hskip.5\emwidth \s!plus .125\emwidth\relax - \doif{#3}{mark}{\underbar}{U+\hexnumber{#2}}:\ruledhbox{\ctxlua{nodes.tracers.fontchar(#1,#2)}}% - \hskip.5\emwidth \s!plus .125\emwidth\relax} + \hskip.5\emwidth \s!plus .125\emwidth \s!minus .125\emwidth\relax} + +\unexpanded\def\otfstepcharcommand#1#2#3% font char class + {\otfstepspace + \doif{#3}{mark}{\underbar}{U+\hexnumber{#2}}:\ruledhbox{\ctxlua{nodes.tracers.fontchar(#1,#2)}}% + \otfstepspace} \unexpanded\def\otfstepfontcommand#1#2#3% id font size {\begingroup @@ -142,7 +147,7 @@ {\ctxlua{nodes.tracers.steppers.font("otfstepfontcommand")}} \unexpanded\def\showotfstepchars#1% - {\ctxlua{nodes.tracers.steppers.codes(#1,"otfstepcharcommand")}} + {\ctxlua{nodes.tracers.steppers.codes(#1,"otfstepcharcommand","otfstepspace")}} \unexpanded\def\showotfstepmessages#1% {\ctxlua{nodes.tracers.steppers.messages(#1,"otfstepmessagecommand",true)}} diff --git a/Master/texmf-dist/tex/context/base/font-uni.mkiv b/Master/texmf-dist/tex/context/base/font-uni.mkiv index 223d27606b7..91a488ff205 100644 --- a/Master/texmf-dist/tex/context/base/font-uni.mkiv +++ b/Master/texmf-dist/tex/context/base/font-uni.mkiv @@ -13,14 +13,14 @@ \writestatus{loading}{ConTeXt Font Macros / Unicode} -%D In \MKIV\ we only provide the \type {\uchar} macro and -%D implement it as just an \UTF\ converter. We expand it so -%D best not use not use it for active characters. +%D In \MKIV\ we only provide the \type {\uchar} macro and implement it as just +%D an \UTF\ converter. We expand it so best not use not use it for active +%D characters. In practice this command is probably never used anyway but we keep +%D if for old styles. \unprotect -%def\uchar#1#2{\ctxcommand{uchar(,)}} -\def\uchar#1#2{\cldcontext{utf.char(\number\numexpr#1*256+#2\relax)}} +\def\uchar#1#2{\clf_uchar\numexpr#1\relax\numexpr#2\relax} \let\uc\uchar diff --git a/Master/texmf-dist/tex/context/base/grph-epd.lua b/Master/texmf-dist/tex/context/base/grph-epd.lua index 4f9d4609765..17f04d593da 100644 --- a/Master/texmf-dist/tex/context/base/grph-epd.lua +++ b/Master/texmf-dist/tex/context/base/grph-epd.lua @@ -22,4 +22,13 @@ function figures.mergegoodies(optionlist) if all or options[variables.layer] then codeinjections.mergeviewerlayers() end + if all or options[variables.bookmark] then + codeinjections.mergebookmarks() + end end + +interfaces.implement { + name = "figure_mergegoodies", + actions = figures.mergegoodies, + arguments = "string" +} diff --git a/Master/texmf-dist/tex/context/base/grph-epd.mkiv b/Master/texmf-dist/tex/context/base/grph-epd.mkiv index 58526fd44dd..2df195589b4 100644 --- a/Master/texmf-dist/tex/context/base/grph-epd.mkiv +++ b/Master/texmf-dist/tex/context/base/grph-epd.mkiv @@ -17,12 +17,12 @@ \registerctxluafile{grph-epd}{1.001} -\def\figurereference{\ctxcommand{figurestatus("reference")}} % might become private +\def\figurereference{\clf_figurestatus{reference}{}} % might become private \defineoverlay[system:graphics:epdf][\directsetup{system:graphics:epdf}] \startsetups system:graphics:epdf - \ctxlua{figures.mergegoodies("\externalfigureparameter\c!interaction")}% + \clf_figure_mergegoodies{\externalfigureparameter\c!interaction}% \reference[\figurereference]{}% todo: dest area \stopsetups @@ -32,7 +32,7 @@ \c!offset=\v!overlay, \c!background={\v!foreground,system:graphics:epdf}] -\def\grph_epdf_add_overlay +\unexpanded\def\grph_epdf_add_overlay {\global\setbox\foundexternalfigure\vbox\bgroup \system_graphics_epdf{\box\foundexternalfigure}% \egroup} diff --git a/Master/texmf-dist/tex/context/base/grph-fig.mkiv b/Master/texmf-dist/tex/context/base/grph-fig.mkiv index 9b9333fa9a1..f5152874d0d 100644 --- a/Master/texmf-dist/tex/context/base/grph-fig.mkiv +++ b/Master/texmf-dist/tex/context/base/grph-fig.mkiv @@ -45,7 +45,7 @@ {\ifsecondargument \grph_buffers_typeset_indeed[#1][#2]% \else\iffirstargument - \doifassignmentelse{#1} + \doifelseassignment{#1} {\grph_buffers_typeset_indeed[\jobname][#1]}% {\grph_buffers_typeset_indeed[#1][]}% \else @@ -53,7 +53,7 @@ \fi\fi} \def\grph_buffers_typeset_indeed[#1][#2]% we could use the via files - {\doifnot{#1}{*}{\xdef\lasttypesetbuffer{\ctxcommand{runbuffer("#1",true)}}}% + {\doifnot{#1}{*}{\xdef\lasttypesetbuffer{\clf_runbuffer{#1}}}% \ifcase\c_grph_buffers_mode % typesetonly \or @@ -94,7 +94,7 @@ \def\grph_typesetting_process_indeed#1#2#3#4% options settings-a filename settings-b {\begingroup - \edef\m_typesetting_name{\cldcontext{job.files.context("#3","#1")}}% + \edef\m_typesetting_name{\clf_runcontextjob{#3}{#1}}% \ifx\m_typesetting_name\empty \else \expanded{\externalfigure[\m_typesetting_name]}[#2,#4]% \fi diff --git a/Master/texmf-dist/tex/context/base/grph-fil.lua b/Master/texmf-dist/tex/context/base/grph-fil.lua index 3449f1779c2..c1532ce25e3 100644 --- a/Master/texmf-dist/tex/context/base/grph-fil.lua +++ b/Master/texmf-dist/tex/context/base/grph-fil.lua @@ -69,3 +69,9 @@ function jobfiles.context(name,options) return file.replacesuffix(name,"pdf") end end + +interfaces.implement { + name = "runcontextjob", + arguments = { "string", "string" }, + actions = { jobfiles.context, context } +} diff --git a/Master/texmf-dist/tex/context/base/grph-inc.lua b/Master/texmf-dist/tex/context/base/grph-inc.lua index d89c52996c7..8a064c8e9c8 100644 --- a/Master/texmf-dist/tex/context/base/grph-inc.lua +++ b/Master/texmf-dist/tex/context/base/grph-inc.lua @@ -6,6 +6,7 @@ if not modules then modules = { } end modules ['grph-inc'] = { license = "see context related readme files" } +-- todo: files are sometimes located twice -- todo: empty filename or only suffix always false (not found) -- lowercase types -- mps tex tmp svg @@ -37,6 +38,8 @@ The TeX-Lua mix is suboptimal. This has to do with the fact that we cannot run TeX code from within Lua. Some more functionality will move to Lua. ]]-- +-- todo: store loaded pages per pdf file someplace + local format, lower, find, match, gsub, gmatch = string.format, string.lower, string.find, string.match, string.gsub, string.gmatch local contains = table.contains local concat, insert, remove = table.concat, table.insert, table.remove @@ -46,7 +49,7 @@ local formatters = string.formatters local longtostring = string.longtostring local expandfilename = dir.expandname -local P, lpegmatch = lpeg.P, lpeg.match +local P, R, S, Cc, C, Cs, Ct, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.Cc, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.match local settings_to_array = utilities.parsers.settings_to_array local settings_to_hash = utilities.parsers.settings_to_hash @@ -56,24 +59,37 @@ local replacetemplate = utilities.templates.replace local images = img +local hasscheme = url.hasscheme +local urlhashed = url.hashed + +local resolveprefix = resolvers.resolve + local texgetbox = tex.getbox local texsetbox = tex.setbox local hpack = node.hpack +local new_latelua = nodes.pool.latelua + local context = context +local implement = interfaces.implement local variables = interfaces.variables + local codeinjections = backends.codeinjections local nodeinjections = backends.nodeinjections -local trace_figures = false trackers.register("graphics.locating", function(v) trace_figures = v end) -local trace_bases = false trackers.register("graphics.bases", function(v) trace_bases = v end) -local trace_programs = false trackers.register("graphics.programs", function(v) trace_programs = v end) -local trace_conversion = false trackers.register("graphics.conversion", function(v) trace_conversion = v end) -local trace_inclusion = false trackers.register("graphics.inclusion", function(v) trace_inclusion = v end) +local trace_figures = false trackers.register ("graphics.locating", function(v) trace_figures = v end) +local trace_bases = false trackers.register ("graphics.bases", function(v) trace_bases = v end) +local trace_programs = false trackers.register ("graphics.programs", function(v) trace_programs = v end) +local trace_conversion = false trackers.register ("graphics.conversion", function(v) trace_conversion = v end) +local trace_inclusion = false trackers.register ("graphics.inclusion", function(v) trace_inclusion = v end) + +local extra_check = false directives.register("graphics.extracheck", function(v) extra_check = v end) local report_inclusion = logs.reporter("graphics","inclusion") +local report_figures = logs.reporter("system","graphics") +local report_figure = logs.reporter("used graphic") local f_hash_part = formatters["%s->%s->%s"] local f_hash_full = formatters["%s->%s->%s->%s->%s->%s->%s"] @@ -85,23 +101,41 @@ local v_high = variables.high local v_global = variables["global"] local v_local = variables["local"] local v_default = variables.default +local v_auto = variables.auto local maxdimen = 2^30-1 function images.check(figure) if figure then - local width = figure.width + local width = figure.width local height = figure.height + if width <= 0 or height <= 0 then + report_inclusion("image %a has bad dimensions (%p,%p), discarding", + figure.filename,width,height) + return false, "bad dimensions" + end + local xres = figure.xres + local yres = figure.yres + local changes = false if height > width then if height > maxdimen then figure.height = maxdimen figure.width = width * maxdimen/height - report_inclusion("limiting natural dimensions of %a (%s)",figure.filename,"height") + changed = true end elseif width > maxdimen then figure.width = maxdimen figure.height = height * maxdimen/width - report_inclusion("limiting natural dimensions of %a (%s)",figure.filename,"width") + changed = true + end + if changed then + report_inclusion("limiting natural dimensions of %a, old %p * %p, new %p * %p", + figure.filename,width,height,figure.width,figure.height) + end + if width >=maxdimen or height >= maxdimen then + report_inclusion("image %a is too large (%p,%p), discarding", + figure.filename,width,height) + return false, "dimensions too large" end return figure end @@ -160,6 +194,7 @@ end figures = figures or { } local figures = figures +figures.images = images figures.boxnumber = figures.boxnumber or 0 figures.defaultsearch = true figures.defaultwidth = 0 @@ -228,10 +263,74 @@ local figures_magics = allocate { { format = "pdf", pattern = (1 - P("%PDF"))^0 * P("%PDF") }, } +local figures_native = allocate { + pdf = true, + jpg = true, + jp2 = true, + png = true, +} + figures.formats = figures_formats -- frozen figures.magics = figures_magics -- frozen figures.order = figures_order -- frozen +-- name checker + +local okay = P("m_k_i_v_") + +local pattern = (R("az","AZ") * P(":"))^-1 * ( -- a-z : | A-Z : + (okay + R("az","09") + S("_/") - P("_")^2)^1 * (P(".") * R("az")^1)^0 * P(-1) + -- a-z | single _ | / + (okay + R("az","09") + S("-/") - P("-")^2)^1 * (P(".") * R("az")^1)^0 * P(-1) + -- a-z | single - | / + (okay + R("AZ","09") + S("_/") - P("_")^2)^1 * (P(".") * R("AZ")^1)^0 * P(-1) + -- A-Z | single _ | / + (okay + R("AZ","09") + S("-/") - P("-")^2)^1 * (P(".") * R("AZ")^1)^0 * P(-1) -- A-Z | single - | / +) * Cc(false) + Cc(true) + +function figures.badname(name) + if not name then + -- bad anyway + elseif not hasscheme(name) then + return lpegmatch(pattern,name) + else + return lpegmatch(pattern,file.basename(name)) + end +end + +local trace_names = false + +trackers.register("graphics.lognames", function(v) + if v and not trace_names then + luatex.registerstopactions(function() + if figures.nofprocessed > 0 then + local report_newline = logs.newline + logs.pushtarget("logfile") + report_newline() + report_figures("start names") + for _, data in table.sortedhash(figures_found) do + report_newline() + report_figure("asked : %s",data.askedname) + if data.found then + report_figure("format : %s",data.format) + report_figure("found : %s",data.foundname) + report_figure("used : %s",data.fullname) + if data.badname then + report_figure("comment : %s","bad name") + elseif data.comment then + report_figure("comment : %s",data.comment) + end + else + report_figure("comment : %s","not found") + end + end + report_newline() + report_figures("stop names") + report_newline() + logs.poptarget() + end + end) + trace_names = true + end +end) + -- We can set the order but only indirectly so that we can check for support. function figures.setorder(list) -- can be table or string @@ -330,6 +429,9 @@ end function figures.registersuffix (suffix, target) register('list', target,suffix ) end function figures.registerpattern(pattern,target) register('pattern',target,pattern) end +implement { name = "registerfiguresuffix", actions = register, arguments = { "'list'", "string", "string" } } +implement { name = "registerfigurepattern", actions = register, arguments = { "'pattern'", "string", "string" } } + local last_locationset = last_locationset or nil local last_pathlist = last_pathlist or nil @@ -367,6 +469,8 @@ function figures.setpaths(locationset,pathlist) end end +implement { name = "setfigurepaths", actions = figures.setpaths, arguments = { "string", "string" } } + -- check conversions and handle it here function figures.hash(data) @@ -452,14 +556,15 @@ end function figures.push(request) statistics.starttiming(figures) - local figuredata = figures.initialize(request) + local figuredata = figures.initialize(request) -- we could use table.sparse but we set them later anyway insert(callstack,figuredata) lastfiguredata = figuredata return figuredata end function figures.pop() - lastfiguredata = remove(callstack) or lastfiguredata + remove(callstack) + lastfiguredata = callstack[#callstack] or lastfiguredata statistics.stoptiming(figures) end @@ -479,17 +584,13 @@ end figures.get = get -function commands.figurevariable(category,tag,default) - context(get(category,tag,default)) -end +implement { name = "figurestatus", actions = { get, context }, arguments = { "'status'", "string", "string" } } +implement { name = "figurerequest", actions = { get, context }, arguments = { "'request'", "string", "string" } } +implement { name = "figureused", actions = { get, context }, arguments = { "'used'", "string", "string" } } -function commands.figurestatus (tag,default) context(get("status", tag,default)) end -function commands.figurerequest(tag,default) context(get("request",tag,default)) end -function commands.figureused (tag,default) context(get("used", tag,default)) end - -function commands.figurefilepath() context(file.dirname (get("used","fullname"))) end -function commands.figurefilename() context(file.nameonly(get("used","fullname"))) end -function commands.figurefiletype() context(file.extname (get("used","fullname"))) end +implement { name = "figurefilepath", actions = { get, file.dirname, context }, arguments = { "'used'", "'fullname'" } } +implement { name = "figurefilename", actions = { get, file.nameonly, context }, arguments = { "'used'", "'fullname'" } } +implement { name = "figurefiletype", actions = { get, file.extname, context }, arguments = { "'used'", "'fullname'" } } -- todo: local path or cache path @@ -510,12 +611,31 @@ local function forbiddenname(filename) end end +local function rejected(specification) + if extra_check then + local fullname = specification.fullname + if fullname and figures_native[file.suffix(fullname)] and not figures.guess(fullname) then + specification.comment = "probably a bad file" + specification.found = false + specification.error = true + report_inclusion("file %a looks bad",fullname) + return true + end + end +end + local function register(askedname,specification) if not specification then - specification = { } + specification = { askedname = askedname, comment = "invalid specification" } elseif forbiddenname(specification.fullname) then - specification = { } - else + specification = { askedname = askedname, comment = "forbidden name" } + elseif specification.internal then + -- no filecheck needed + specification.found = true + if trace_figures then + report_inclusion("format %a internally supported by engine",specification.format) + end + elseif not rejected(specification) then local format = specification.format if format then local conversion = specification.conversion @@ -552,6 +672,9 @@ local function register(askedname,specification) report_inclusion("no converter for %a to %a",format,newformat) end if converter then + -- + -- todo: outline as helper function + -- local oldname = specification.fullname local newpath = file.dirname(oldname) local oldbase = file.basename(oldname) @@ -567,20 +690,23 @@ local function register(askedname,specification) -- local fc = specification.cache or figures.cachepaths.path if fc and fc ~= "" and fc ~= "." then - newpath = fc + newpath = gsub(fc,"%*",newpath) -- so cachedir can be "/data/cache/*" else newbase = defaultprefix .. newbase end - if not file.is_writable(newpath) then - if trace_conversion then - report_inclusion("path %a is not writable, forcing conversion path %a",newpath,".") - end - newpath = "." - end local subpath = specification.subpath or figures.cachepaths.subpath if subpath and subpath ~= "" and subpath ~= "." then newpath = newpath .. "/" .. subpath end + if not lfs.isdir(newpath) then + dir.makedirs(newpath) + if not file.is_writable(newpath) then + if trace_conversion then + report_inclusion("path %a is not writable, forcing conversion path %a",newpath,".") + end + newpath = "." + end + end local prefix = specification.prefix or figures.cachepaths.prefix if prefix and prefix ~= "" then newbase = prefix .. newbase @@ -602,7 +728,6 @@ local function register(askedname,specification) local newbase = newbase .. "." .. newformat -- local newname = file.join(newpath,newbase) - dir.makedirs(newpath) oldname = collapsepath(oldname) newname = collapsepath(newname) local oldtime = lfs.attributes(oldname,'modification') or 0 @@ -626,7 +751,7 @@ local function register(askedname,specification) format = newformat if not figures_suffixes[format] then -- maybe the new format is lowres.png (saves entry in suffixes) - -- so let's do thsi extra check + -- so let's do this extra check local suffix = file.suffix(newformat) if figures_suffixes[suffix] then if trace_figures then @@ -636,29 +761,44 @@ local function register(askedname,specification) end end elseif io.exists(oldname) then - specification.fullname = oldname -- was newname + report_inclusion("file %a is bugged",oldname) + if format and validtypes[format] then + specification.fullname = oldname + end specification.converted = false + specification.bugged = true end end end - local found = figures_suffixes[format] -- validtypes[format] - if not found then - specification.found = false - if trace_figures then - report_inclusion("format %a is not supported",format) - end - else - specification.found = true - if trace_figures then - if validtypes[format] then -- format? + if format then + local found = figures_suffixes[format] -- validtypes[format] + if not found then + specification.found = false + if trace_figures then + report_inclusion("format %a is not supported",format) + end + elseif validtypes[format] then + specification.found = true + if trace_figures then report_inclusion("format %a natively supported by backend",format) - else + end + else + specification.found = true -- else no foo.1 mps conversion + if trace_figures then report_inclusion("format %a supported by output file format",format) end end + else + specification.askedname = askedname + specification.found = false end end - specification.foundname = specification.foundname or specification.fullname + if specification.found then + specification.foundname = specification.foundname or specification.fullname + else + specification.foundname = nil + end + specification.badname = figures.badname(askedname) local askedhash = f_hash_part(askedname,specification.conversion or "default",specification.resolution or "default") figures_found[askedhash] = specification return specification @@ -667,13 +807,16 @@ end local resolve_too = false -- true local internalschemes = { - file = true, + file = true, + tree = true, + dirfile = true, + dirtree = true, } local function locate(request) -- name, format, cache -- not resolvers.cleanpath(request.name) as it fails on a!b.pdf and b~c.pdf -- todo: more restricted cleanpath - local askedname = request.name + local askedname = request.name or "" local askedhash = f_hash_part(askedname,request.conversion or "default",request.resolution or "default") local foundname = figures_found[askedhash] if foundname then @@ -684,11 +827,18 @@ local function locate(request) -- name, format, cache local askedconversion = request.conversion local askedresolution = request.resolution -- - if request.format == "" or request.format == "unknown" then - request.format = nil + local askedformat = request.format + if not askedformat or askedformat == "" or askedformat == "unknown" then + askedformat = file.suffix(askedname) or "" + elseif askedformat == v_auto then + if trace_figures then + report_inclusion("ignoring suffix of %a",askedname) + end + askedformat = "" + askedname = file.removesuffix(askedname) end -- protocol check - local hashed = url.hashed(askedname) + local hashed = urlhashed(askedname) if not hashed then -- go on elseif internalschemes[hashed.scheme] then @@ -697,6 +847,7 @@ local function locate(request) -- name, format, cache askedname = path end else + -- local fname = methodhandler('finders',pathname .. "/" .. wantedfiles[k]) local foundname = resolvers.findbinfile(askedname) if not foundname or not lfs.isfile(foundname) then -- foundname can be dummy if trace_figures then @@ -705,7 +856,6 @@ local function locate(request) -- name, format, cache -- url not found return register(askedname) end - local askedformat = request.format or file.suffix(askedname) or "" local guessedformat = figures.guess(foundname) if askedformat ~= guessedformat then if trace_figures then @@ -728,9 +878,8 @@ local function locate(request) -- name, format, cache end end -- we could use the hashed data instead - local askedpath= file.is_rootbased_path(askedname) + local askedpath = file.is_rootbased_path(askedname) local askedbase = file.basename(askedname) - local askedformat = request.format or file.suffix(askedname) or "" if askedformat ~= "" then askedformat = lower(askedformat) if trace_figures then @@ -750,7 +899,7 @@ local function locate(request) -- name, format, cache end end if format then - local foundname, quitscanning, forcedformat = figures.exists(askedname,format,resolve_too) -- not askedformat + local foundname, quitscanning, forcedformat, internal = figures.exists(askedname,format,resolve_too) -- not askedformat if foundname then return register(askedname, { askedname = askedname, @@ -760,6 +909,7 @@ local function locate(request) -- name, format, cache -- foundname = foundname, -- no conversion = askedconversion, resolution = askedresolution, + internal = internal, }) elseif quitscanning then return register(askedname) @@ -784,7 +934,7 @@ local function locate(request) -- name, format, cache else -- type given for i=1,#figure_paths do - local path = figure_paths[i] + local path = resolveprefix(figure_paths[i]) -- we resolve (e.g. jobfile:) local check = path .. "/" .. askedname -- we pass 'true' as it can be an url as well, as the type -- is given we don't waste much time @@ -792,7 +942,7 @@ local function locate(request) -- name, format, cache if foundname then return register(check, { askedname = askedname, - fullname = check, + fullname = foundname, -- check, format = askedformat, cache = askedcache, conversion = askedconversion, @@ -850,9 +1000,9 @@ local function locate(request) -- name, format, cache -- local name = file.replacesuffix(askedbase,suffix) local name = file.replacesuffix(askedname,suffix) for i=1,#figure_paths do - local path = figure_paths[i] + local path = resolveprefix(figure_paths[i]) -- we resolve (e.g. jobfile:) local check = path .. "/" .. name - local isfile = url.hashed(check).scheme == "file" + local isfile = internalschemes[urlhashed(check).scheme] if not isfile then if trace_figures then report_inclusion("warning: skipping path %a",path) @@ -878,7 +1028,7 @@ local function locate(request) -- name, format, cache report_inclusion("unknown format, using path strategy") end for i=1,#figure_paths do - local path = figure_paths[i] + local path = resolveprefix(figure_paths[i]) -- we resolve (e.g. jobfile:) for j=1,#figures_order do local format = figures_order[j] local list = figures_formats[format].list or { format } @@ -942,7 +1092,7 @@ function identifiers.default(data) du.fullname = fullname -- can be cached ds.fullname = foundname -- original ds.format = l.format - ds.status = (l.found and 10) or 0 + ds.status = (l.bugged and 0) or (l.found and 10) or 0 end return data end @@ -952,8 +1102,8 @@ function figures.identify(data) local list = identifiers.list -- defined at the end for i=1,#list do local identifier = list[i] - data = identifier(data) - if data.status.status > 0 then + local data = identifier(data) + if data and (not data.status and data.status.status > 0) then break end end @@ -969,12 +1119,57 @@ function figures.check(data) return (checkers[data.status.format] or checkers.generic)(data) end +local trace_usage = false +local used_images = { } + +trackers.register("graphics.usage", function(v) + if v and not trace_usage then + luatex.registerstopactions(function() + local found = { } + for _, t in table.sortedhash(figures_found) do + found[#found+1] = t + for k, v in next, t do + if v == false or v == "" then + t[k] = nil + end + end + end + for i=1,#used_images do + local u = used_images[i] + local s = u.status + if s then + s.status = nil -- doesn't say much here + if s.error then + u.used = { } -- better show that it's not used + end + end + for _, t in next, u do + for k, v in next, t do + if v == false or v == "" then + t[k] = nil + end + end + end + end + table.save(file.nameonly(environment.jobname) .. "-figures-usage.lua",{ + found = found, + used = used_images, + } ) + end) + trace_usage = true + end +end) + function figures.include(data) data = data or callstack[#callstack] or lastfiguredata + if trace_usage then + used_images[#used_images+1] = data + end return (includers[data.status.format] or includers.generic)(data) end function figures.scale(data) -- will become lua code + data = data or callstack[#callstack] or lastfiguredata context.doscalefigure() return data end @@ -1011,11 +1206,15 @@ end function existers.generic(askedname,resolve) -- not findbinfile local result - if lfs.isfile(askedname) then + if hasscheme(askedname) then + result = resolvers.findbinfile(askedname) + elseif lfs.isfile(askedname) then result = askedname elseif resolve then - result = resolvers.findbinfile(askedname) or "" - if result == "" then result = false end + result = resolvers.findbinfile(askedname) + end + if not result or result == "" then + result = false end if trace_figures then if result then @@ -1029,11 +1228,11 @@ end function checkers.generic(data) local dr, du, ds = data.request, data.used, data.status - local name = du.fullname or "unknown generic" - local page = du.page or dr.page - local size = dr.size or "crop" + local name = du.fullname or "unknown generic" + local page = du.page or dr.page + local size = dr.size or "crop" local color = dr.color or "natural" - local mask = dr.mask or "none" + local mask = dr.mask or "none" local conversion = dr.conversion local resolution = dr.resolution if not conversion or conversion == "" then @@ -1053,9 +1252,18 @@ function checkers.generic(data) } codeinjections.setfigurecolorspace(data,figure) codeinjections.setfiguremask(data,figure) - figure = figure and images.check(images.scan(figure)) or false + if figure then + local f, comment = images.check(images.scan(figure)) + if not f then + ds.comment = comment + ds.found = false + ds.error = true + end + figure = f + end local f, d = codeinjections.setfigurealternative(data,figure) - figure, data = f or figure, d or data + figure = f or figure + data = d or data figures_loaded[hash] = figure if trace_conversion then report_inclusion("new graphic, using hash %a",hash) @@ -1081,12 +1289,19 @@ function checkers.generic(data) return data end +local nofimages = 0 +local pofimages = { } + +function figures.getrealpage(index) + return pofimages[index] or 0 +end + function includers.generic(data) local dr, du, ds = data.request, data.used, data.status -- here we set the 'natural dimensions' - dr.width = du.width - dr.height = du.height - local hash = figures.hash(data) + dr.width = du.width + dr.height = du.height + local hash = figures.hash(data) local figure = figures_used[hash] -- figures.registerresource { -- filename = du.fullname, @@ -1102,9 +1317,17 @@ function includers.generic(data) figures_used[hash] = figure end if figure then - local nr = figures.boxnumber - -- it looks like we have a leak in attributes here .. todo - local box = hpack(images.node(figure)) -- images.node(figure) not longer valid + local nr = figures.boxnumber + nofimages = nofimages + 1 + ds.pageindex = nofimages + local image = images.node(figure) + local pager = new_latelua(function() + pofimages[nofimages] = pofimages[nofimages] or tex.count.realpageno -- so when reused we register the first one only + end) + image.next = pager + pager.prev = image + local box = hpack(image) -- images.node(figure) not longer valid + indexed[figure.index] = figure box.width, box.height, box.depth = figure.width, figure.height, 0 -- new, hm, tricky, we need to do that in tex (yet) texsetbox(nr,box) @@ -1178,6 +1401,8 @@ includers.mov = includers.nongeneric internalschemes.mprun = true +-- mprun.foo.1 mprun.6 mprun:foo.2 + local function internal(askedname) local spec, mprun, mpnum = match(lower(askedname),"mprun([:%.]?)(.-)%.(%d+)") if spec ~= "" then @@ -1190,7 +1415,7 @@ end function existers.mps(askedname) local mprun, mpnum = internal(askedname) if mpnum then - return askedname + return askedname, true, "mps", true else return existers.generic(askedname) end @@ -1211,7 +1436,7 @@ includers.mps = includers.nongeneric function existers.tex(askedname) askedname = resolvers.findfile(askedname) - return askedname ~= "" and askedname or false + return askedname ~= "" and askedname or false, true, "tex", true end function checkers.tex(data) @@ -1225,7 +1450,7 @@ includers.tex = includers.nongeneric function existers.buffer(askedname) local name = file.nameonly(askedname) local okay = buffers.exists(name) - return okay and name, true -- always quit scanning + return okay and name, true, "buffer", true -- always quit scanning end function checkers.buffer(data) @@ -1252,7 +1477,10 @@ includers.auto = includers.generic -- -- -- cld -- -- -- -existers.cld = existers.tex +function existers.cld(askedname) + askedname = resolvers.findfile(askedname) + return askedname ~= "" and askedname or false, true, "cld", true +end function checkers.cld(data) return checkers_nongeneric(data,function() context.docheckfigurecld(data.used.fullname) end) @@ -1270,20 +1498,38 @@ end -- programs.makeoptions = makeoptions local function runprogram(binary,argument,variables) - local binary = match(binary,"[%S]+") -- to be sure + -- move this check to the runner code + local found = nil + if type(binary) == "table" then + for i=1,#binary do + local b = binary[i] + found = os.which(b) + if found then + binary = b + break + end + end + if not found then + binary = concat(binary, " | ") + end + elseif binary then + found = os.which(match(binary,"[%S]+")) + end if type(argument) == "table" then argument = concat(argument," ") -- for old times sake end - if not os.which(binary) then - report_inclusion("program %a is not installed, not running command: %s",binary,command) + if not found then + report_inclusion("program %a is not installed",binary or "?") elseif not argument or argument == "" then - report_inclusion("nothing to run, unknown program %a",binary) + report_inclusion("nothing to run, no arguments for program %a",binary) else - local command = format([["%s" %s]],binary,replacetemplate(longtostring(argument),variables)) + -- no need to use the full found filename (found) .. we also don't quote the program + -- name any longer as in luatex there is too much messing with these names + local command = format([[%s %s]],binary,replacetemplate(longtostring(argument),variables)) if trace_conversion or trace_programs then report_inclusion("running command: %s",command) end - os.spawn(command) + os.execute(command) end end @@ -1298,13 +1544,15 @@ local epsconverter = converters.eps or { } converters.eps = epsconverter converters.ps = epsconverter +-- todo: colorspace + local epstopdf = { resolutions = { [v_low] = "screen", [v_medium] = "ebook", [v_high] = "prepress", }, - command = os.type == "windows" and "gswin32c" or "gs", + command = os.type == "windows" and { "gswin64c", "gswin32c" } or "gs", -- -dProcessDSCComments=false argument = [[ -q @@ -1315,8 +1563,10 @@ local epstopdf = { -dAutoRotatePages=/None -dPDFSETTINGS=/%presets% -dEPSCrop - -sOutputFile=%newname% - %oldname% + -dCompatibilityLevel=%level% + -sOutputFile="%newname%" + %colorspace% + "%oldname%" -c quit ]], } @@ -1324,14 +1574,66 @@ local epstopdf = { programs.epstopdf = epstopdf programs.gs = epstopdf -function epsconverter.pdf(oldname,newname,resolution) -- the resolution interface might change +local cleanups = { } +local cleaners = { } + +local whitespace = lpeg.patterns.whitespace +local quadruple = Ct((whitespace^0 * lpeg.patterns.number/tonumber * whitespace^0)^4) +local betterbox = P("%%BoundingBox:") * quadruple + * P("%%HiResBoundingBox:") * quadruple + * P("%AI3_Cropmarks:") * quadruple + * P("%%CropBox:") * quadruple + / function(b,h,m,c) + return formatters["%%%%BoundingBox: %i %i %i %i\n%%%%HiResBoundingBox: %F %F %F %F\n%%%%CropBox: %F %F %F %F\n"]( + m[1],m[2],m[3],m[4], + m[1],m[2],m[3],m[4], + m[1],m[2],m[3],m[4] + ) + end +local nocrap = P("%") / "" * ( + (P("AI9_PrivateDataBegin") * P(1)^0) / "%%%%EOF" + + (P("%EOF") * whitespace^0 * P("%AI9_PrintingDataEnd") * P(1)^0) / "%%%%EOF" + + (P("AI7_Thumbnail") * (1-P("%%EndData"))^0 * P("%%EndData")) / "" + ) +local whatever = nocrap + P(1) +local pattern = Cs((betterbox * whatever^1 + whatever)^1) + +directives.register("graphics.conversion.eps.cleanup.ai",function(v) cleanups.ai = v end) + +cleaners.ai = function(name) + local tmpname = name .. ".tmp" + io.savedata(tmpname,lpegmatch(pattern,io.loaddata(name))) + return tmpname +end + +function epsconverter.pdf(oldname,newname,resolution,colorspace) -- the resolution interface might change local epstopdf = programs.epstopdf -- can be changed - local presets = epstopdf.resolutions[resolution or ""] or epstopdf.resolutions.high + local presets = epstopdf.resolutions[resolution or "high"] or epstopdf.resolutions.high + local level = codeinjections.getformatoption("pdf_level") or "1.3" + local tmpname = oldname + if cleanups.ai then + tmpname = cleaners.ai(oldname) + end + if colorspace == "gray" then + colorspace = "-sColorConversionStrategy=Gray -sProcessColorModel=DeviceGray" + -- colorspace = "-sColorConversionStrategy=Gray" + else + colorspace = nil + end runprogram(epstopdf.command, epstopdf.argument, { - newname = newname, - oldname = oldname, - presets = presets, + newname = newname, + oldname = tmpname, + presets = presets, + level = tostring(level), + colorspace = colorspace, } ) + if tmpname ~= oldname then + os.remove(tmpname) + end +end + +epsconverter["gray.pdf"] = function(oldname,newname,resolution) -- the resolution interface might change + epsconverter.pdf(oldname,newname,resolution,"gray") end epsconverter.default = epsconverter.pdf @@ -1339,22 +1641,23 @@ epsconverter.default = epsconverter.pdf local pdfconverter = converters.pdf or { } converters.pdf = pdfconverter -programs.pdftoeps = { - command = "pdftops", - argument = [[-eps "%oldname%" "%newname%]], -} - -pdfconverter.stripped = function(oldname,newname) - local pdftoeps = programs.pdftoeps -- can be changed - local epstopdf = programs.epstopdf -- can be changed - local presets = epstopdf.resolutions[resolution or ""] or epstopdf.resolutions.high - local tmpname = newname .. ".tmp" - runprogram(pdftoeps.command, pdftoeps.argument, { oldname = oldname, newname = tmpname, presets = presets }) - runprogram(epstopdf.command, epstopdf.argument, { oldname = tmpname, newname = newname, presets = presets }) - os.remove(tmpname) -end - -figures.registersuffix("stripped","pdf") +-- programs.pdftoeps = { +-- command = "pdftops", +-- argument = [[-eps "%oldname%" "%newname%"]], +-- } +-- +-- pdfconverter.stripped = function(oldname,newname) +-- local pdftoeps = programs.pdftoeps -- can be changed +-- local epstopdf = programs.epstopdf -- can be changed +-- local presets = epstopdf.resolutions[resolution or ""] or epstopdf.resolutions.high +-- local level = codeinjections.getformatoption("pdf_level") or "1.3" +-- local tmpname = newname .. ".tmp" +-- runprogram(pdftoeps.command, pdftoeps.argument, { oldname = oldname, newname = tmpname, presets = presets, level = level }) +-- runprogram(epstopdf.command, epstopdf.argument, { oldname = tmpname, newname = newname, presets = presets, level = level }) +-- os.remove(tmpname) +-- end +-- +-- figures.registersuffix("stripped","pdf") -- -- -- svg -- -- -- @@ -1431,14 +1734,111 @@ bmpconverter.default = converter -- todo: lowres +-- cmyk conversion + +-- ecirgb_v2.icc +-- ecirgb_v2_iccv4.icc +-- isocoated_v2_300_eci.icc +-- isocoated_v2_eci.icc +-- srgb.icc +-- srgb_v4_icc_preference.icc + +-- [[convert %?colorspace: -colorspace "%colorspace%" ?%]] + +local rgbprofile = "srgb_v4_icc_preference.icc" -- srgb.icc +local cmykprofile = "isocoated_v2_300_eci.icc" -- isocoated_v2_eci.icc + +directives.register("graphics.conversion.rgbprofile", function(v) rgbprofile = type(v) == "string" and v or rgbprofile end) +directives.register("graphics.conversion.cmykprofile",function(v) cmykprofile = type(v) == "string" and v or cmykprofile end) + +local function profiles() + if not lfs.isfile(rgbprofile) then + local found = resolvers.findfile(rgbprofile) + if found and found ~= "" then + rgbprofile = found + else + report_figures("unknown profile %a",rgbprofile) + end + end + if not lfs.isfile(cmykprofile) then + local found = resolvers.findfile(cmykprofile) + if found and found ~= "" then + cmykprofile = found + else + report_figures("unknown profile %a",cmykprofile) + end + end + return rgbprofile, cmykprofile +end + +programs.pngtocmykpdf = { + command = "gm", + argument = [[convert -compress Zip -strip +profile "*" -profile "%rgbprofile%" -profile "%cmykprofile%" -sampling-factor 1x1 "%oldname%" "%newname%"]], +} + +programs.jpgtocmykpdf = { + command = "gm", + argument = [[convert -compress JPEG -strip +profile "*" -profile "%rgbprofile%" -profile "%cmykprofile%" -sampling-factor 1x1 "%oldname%" "%newname%"]], +} + +programs.pngtograypdf = { + command = "gm", + argument = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 "%oldname%" "%newname%"]], +} + +programs.jpgtograypdf = { + command = "gm", + argument = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 "%oldname%" "%newname%"]], +} + +figures.converters.png = { + ["cmyk.pdf"] = function(oldname,newname,resolution) + local rgbprofile, cmykprofile = profiles() + runprogram(programs.pngtocmykpdf.command, programs.pngtocmykpdf.argument, { + -- runprogram(programs.pngtocmykpdf, { + rgbprofile = rgbprofile, + cmykprofile = cmykprofile, + oldname = oldname, + newname = newname, + } ) + end, + ["gray.pdf"] = function(oldname,newname,resolution) + runprogram(programs.pngtograypdf.command, programs.pngtograypdf.argument, { + -- runprogram(programs.pngtograypdf, { + oldname = oldname, + newname = newname, + } ) + end, +} + +figures.converters.jpg = { + ["cmyk.pdf"] = function(oldname,newname,resolution) + local rgbprofile, cmykprofile = profiles() + runprogram(programs.jpgtocmykpdf.command, programs.jpgtocmykpdf.argument, { + -- runprogram(programs.jpgtocmykpdf, { + rgbprofile = rgbprofile, + cmykprofile = cmykprofile, + oldname = oldname, + newname = newname, + } ) + end, + ["gray.pdf"] = function(oldname,newname,resolution) + runprogram(programs.jpgtograypdf.command, programs.jpgtograypdf.argument, { + -- runprogram(programs.jpgtograypdf, { + oldname = oldname, + newname = newname, + } ) + end, +} + -- -- -- bases -- -- -- local bases = allocate() figures.bases = bases -local bases_list = nil -- index => { basename, fullname, xmlroot } -local bases_used = nil -- [basename] => { basename, fullname, xmlroot } -- pointer to list -local bases_found = nil +local bases_list = nil -- index => { basename, fullname, xmlroot } +local bases_used = nil -- [basename] => { basename, fullname, xmlroot } -- pointer to list +local bases_found = nil local bases_enabled = false local function reset() @@ -1473,6 +1873,8 @@ function bases.use(basename) end end +implement { name = "usefigurebase", actions = bases.use, arguments = "string" } + local function bases_find(basename,askedlabel) if trace_bases then report_inclusion("checking for %a in base %a",askedlabel,basename) @@ -1485,7 +1887,7 @@ local function bases_find(basename,askedlabel) if base[2] == nil then -- no yet located for i=1,#figure_paths do - local path = figure_paths[i] + local path = resolveprefix(figure_paths[i]) -- we resolve (e.g. jobfile:) local xmlfile = path .. "/" .. basename if io.exists(xmlfile) then base[2] = xmlfile @@ -1503,10 +1905,10 @@ local function bases_find(basename,askedlabel) page = page + 1 if xml.text(e) == askedlabel then t = { - base = file.replacesuffix(base[2],"pdf"), + base = file.replacesuffix(base[2],"pdf"), format = "pdf", - name = xml.text(e,"../*:file"), -- to be checked - page = page, + name = xml.text(e,"../*:file"), -- to be checked + page = page, } bases_found[askedlabel] = t if trace_bases then @@ -1541,13 +1943,13 @@ function identifiers.base(data) local dr, du, ds = data.request, data.used, data.status local fbl = bases_locate(dr.name or dr.label) if fbl then - du.page = fbl.page - du.format = fbl.format + du.page = fbl.page + du.format = fbl.format du.fullname = fbl.base ds.fullname = fbl.name - ds.format = fbl.format - ds.page = fbl.page - ds.status = 10 + ds.format = fbl.format + ds.page = fbl.page + ds.status = 10 end end return data @@ -1566,7 +1968,15 @@ identifiers.list = { statistics.register("graphics processing time", function() local nofprocessed = figures.nofprocessed if nofprocessed > 0 then - return format("%s seconds including tex, %s processed images", statistics.elapsedtime(figures),nofprocessed) + local nofnames, nofbadnames = 0, 0 + for hash, data in next, figures_found do + nofnames = nofnames + 1 + if data.badname then + nofbadnames = nofbadnames + 1 + end + end + return format("%s seconds including tex, %s processed images, %s unique asked, %s bad names", + statistics.elapsedtime(figures),nofprocessed,nofnames,nofbadnames) else return nil end @@ -1618,8 +2028,59 @@ end -- interfacing -commands.setfigurelookuporder = figures.setorder +implement { + name = "figure_push", + scope = "private", + actions = figures.push, + arguments = { + { + { "name" }, + { "label" }, + { "page" }, + { "size" }, + { "object" }, + { "prefix" }, + { "cache" }, + { "format" }, + { "preset" }, + { "controls" }, + { "resources" }, + { "preview" }, + { "display" }, + { "mask" }, + { "conversion" }, + { "resolution" }, + { "color" }, + { "repeat" }, + { "width", "dimen" }, + { "height", "dimen" }, + } + } +} --- +-- beware, we get a number passed by default + +implement { name = "figure_pop", scope = "private", actions = figures.pop } +implement { name = "figure_done", scope = "private", actions = figures.done } +implement { name = "figure_dummy", scope = "private", actions = figures.dummy } +implement { name = "figure_identify", scope = "private", actions = figures.identify } +implement { name = "figure_scale", scope = "private", actions = figures.scale } +implement { name = "figure_check", scope = "private", actions = figures.check } +implement { name = "figure_include", scope = "private", actions = figures.include } -figures.images = images +implement { + name = "setfigurelookuporder", + actions = figures.setorder, + arguments = "string" +} + +implement { + name = "figure_reset", + scope = "private", + arguments = { "integer", "dimen", "dimen" }, + actions = function(box,width,height) + figures.boxnumber = box + figures.defaultwidth = width + figures.defaultheight = height + end +} diff --git a/Master/texmf-dist/tex/context/base/grph-inc.mkiv b/Master/texmf-dist/tex/context/base/grph-inc.mkiv index e8b63cc4bb9..6b7f2bd6359 100644 --- a/Master/texmf-dist/tex/context/base/grph-inc.mkiv +++ b/Master/texmf-dist/tex/context/base/grph-inc.mkiv @@ -11,6 +11,11 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. +% \enabledirectives[graphics.conversion.eps.cleanup.ai] + +% \setupexternalfigures[directory=dirfile://./test/**] +% \externalfigure[crappname(2).eps][frame=on] + % todo: messages \writestatus{loading}{ConTeXt Graphic Macros / Figure Inclusion} @@ -147,6 +152,11 @@ %D the already set parameters need to be set again or otherwise %D the old values will be used. +%D New: \type {method=auto}: strips suffix and uses \quote {order} which is handy in +%D some of four workflows where sources are used for web and print and where +%D the web tools need a suffix (like gif) which we don't want as we want a high +%D quality format. + \newconditional\c_grph_include_trace_inheritance \installtextracker @@ -174,14 +184,14 @@ \def\grph_include_use[#1][#2][#3][#4]% {\doifelsenothing{#1} {\doifsomething{#2} - {\doifassignmentelse{#3} + {\doifelseassignment{#3} {\grph_include_use_indeed{#2}{#2}{#3}{#4}} {\grph_include_use_indeed{#2}{#2}\empty{#4}}}} {\doifelsenothing{#2} - {\doifassignmentelse{#3} + {\doifelseassignment{#3} {\grph_include_use_indeed{#1}{#1}\empty{#3}} {\grph_include_use_indeed{#1}{#1}{#3}{#4}}} - {\doifassignmentelse{#3} + {\doifelseassignment{#3} {\grph_include_use_indeed{#1}{#2}\empty{#3}} {\grph_include_use_indeed{#1}{#2}{#3}{#4}}}}} @@ -300,56 +310,56 @@ \edef\p_label {\externalfigureparameter\c!label}% % \dostarttagged\t!image\empty - \ctxlua{figures.push { - name = "\p_grph_include_name", - label = "\ifx\p_label\empty\p_grph_include_label\else\p_label\fi", - page = "\externalfigureparameter\c!page", - size = "\externalfigureparameter\c!size", - object = "\externalfigureparameter\c!object", - prefix = "\externalfigureparameter\c!prefix", - cache = "\externalfigureparameter\c!cache", - format = "\externalfigureparameter\c!method", - preset = "\externalfigureparameter\c!prefix", - controls = "\externalfigureparameter\c!controls", - resources = "\externalfigureparameter\c!resources", - preview = "\externalfigureparameter\c!preview", - display = "\externalfigureparameter\c!display", - mask = "\externalfigureparameter\c!mask", - conversion = "\externalfigureparameter\c!conversion", - resolution = "\externalfigureparameter\c!resolution", - color = "\internalspotcolorparent{\externalfigureparameter\c!color}", % hack is needed - ["repeat"] = "\externalfigureparameter\c!repeat", - \ifx\p_width\empty \else - width = \number\dimexpr\p_width, - \fi - \ifx\p_height\empty \else - height = \number\dimexpr\p_height, - \fi - } }% - \ctxlua{figures.identify()}% - % also mode: checkpresense only + \clf_figure_push + name {\p_grph_include_name}% + label {\ifx\p_label\empty\p_grph_include_label\else\p_label\fi}% + page {\externalfigureparameter\c!page}% + size {\externalfigureparameter\c!size}% + object {\externalfigureparameter\c!object}% + prefix {\externalfigureparameter\c!prefix}% + cache {\externalfigureparameter\c!cache}% + format {\externalfigureparameter\c!method}% + preset {\externalfigureparameter\c!prefix}% + controls {\externalfigureparameter\c!controls}% + resources {\externalfigureparameter\c!resources}% + preview {\externalfigureparameter\c!preview}% + display {\externalfigureparameter\c!display}% + mask {\externalfigureparameter\c!mask}% + conversion {\externalfigureparameter\c!conversion}% + resolution {\externalfigureparameter\c!resolution}% + color {\internalspotcolorparent{\externalfigureparameter\c!color}}% hack is needed + repeat {\externalfigureparameter\c!repeat}% + \ifx\p_width\empty \else + width \dimexpr\p_width\relax + \fi + \ifx\p_height\empty \else + height \dimexpr\p_height\relax + \fi + \relax + \clf_figure_identify + \relax \ifconditional\c_grph_include_test_only \ifcase\figurestatus \else - \ctxlua{figures.check()}% - \ctxlua{figures.dummy()}% - \ctxlua{figures.scale()}% - \ctxlua{figures.done()}% + \clf_figure_check + \clf_figure_dummy + \clf_figure_scale + \clf_figure_done \fi \grph_include_set_mode \else \ifcase\figurestatus - \ctxlua{figures.dummy()}% - \ctxlua{figures.scale()}% + \clf_figure_dummy + \clf_figure_scale \else - \ctxlua{figures.check()}% - \ctxlua{figures.include()}% - \ctxlua{figures.scale()}% + \clf_figure_check + \clf_figure_include + \clf_figure_scale \fi - \ctxlua{figures.done()}% + \clf_figure_done \grph_include_set_mode \grph_include_finalize \fi - \ctxlua{figures.pop()}% + \clf_figure_pop \dotagfigure \naturalvbox attr \imageattribute 2 {\box\foundexternalfigure}% \dostoptagged @@ -416,13 +426,13 @@ {\dodoubleargument\grph_include_set_type_synonym} \def\grph_include_set_type_synonym[#1][#2]% - {\ctxlua{figures.registersuffix("#1","#2")}} + {\clf_registerfiguresuffix{#1}{#2}} %D Additional paths can be installed with the regular setup command. The next %D macro picks up the list. \unexpanded\def\setfigurepathlist - {\ctxlua{figures.setpaths("\externalfigureparameter\c!location",\!!bs\externalfigureparameter\c!directory\!!es)}} + {\clf_setfigurepaths{\externalfigureparameter\c!location}{\externalfigureparameter\c!directory}} %D Variables: @@ -432,36 +442,36 @@ \def\defaultfigurewidth {8\lineheight} \def\defaultfigureheight {6\lineheight} -\def\figurestatus {\numexpr\ctxcommand{figurestatus("status",0)}\relax} % number: 0 = not found -\def\figurewidth {\ctxcommand{figurestatus("width",0)}sp} -\def\figureheight {\ctxcommand{figurestatus("height",0)}sp} -\def\figurexscale {\ctxcommand{figurestatus("xscale",1)}} -\def\figureyscale {\ctxcommand{figurestatus("yscale",1)}} - -\def\figuresize {\ctxcommand{figurerequest("size")}} -\def\figurelabel {\ctxcommand{figurerequest("label")}} -\def\figurefileoriginal {\ctxcommand{figurerequest("name")}} -\def\figurefilepage {\ctxcommand{figurerequest("page",1)}} -\def\figurefileoptions {\ctxcommand{figurerequest("options")}} -\def\figurefileconversion{\ctxcommand{figurerequest("conversion")}} -\def\figurefilecache {\ctxcommand{figurerequest("cache")}} -\def\figurefileprefix {\ctxcommand{figurerequest("prefix")}} - -\def\figurenaturalwidth {\ctxcommand{figureused("width", \number\dimexpr\defaultfigurewidth \relax)}sp} -\def\figurenaturalheight {\ctxcommand{figureused("height",\number\dimexpr\defaultfigureheight\relax)}sp} -\def\figurexresolution {\ctxcommand{figureused("xresolution",0)}} -\def\figureyresolution {\ctxcommand{figureused("yresolution",0)}} -\def\figurexsize {\ctxcommand{figureused("xsize",0)}} -\def\figureysize {\ctxcommand{figureused("ysize",0)}} -\def\figurecolordepth {\ctxcommand{figureused("colordepth",0)}} -\def\figuredepth {\ctxcommand{figureused("depth",0)}} - -\def\figurefullname {\ctxcommand{figureused("fullname")}} -\def\noffigurepages {\ctxcommand{figureused("pages",0)}} - -\def\figurefilepath {\ctxcommand{figurefilepath()}} -\def\figurefilename {\ctxcommand{figurefilename()}} -\def\figurefiletype {\ctxcommand{figurefiletype()}} +\def\figurestatus {\numexpr\clf_figurestatus{status}{0}\relax} % number: 0 = not found +\def\figurewidth {\clf_figurestatus{width}{0}sp} +\def\figureheight {\clf_figurestatus{height}{0}sp} +\def\figurexscale {\clf_figurestatus{xscale}{1}} +\def\figureyscale {\clf_figurestatus{yscale}{1}} + +\def\figuresize {\clf_figurerequest{size}{}} +\def\figurelabel {\clf_figurerequest{label}{}} +\def\figurefileoriginal {\clf_figurerequest{name}{}} +\def\figurefilepage {\clf_figurerequest{page}{1}} +\def\figurefileoptions {\clf_figurerequest{options}{}} +\def\figurefileconversion{\clf_figurerequest{conversion}{}} +\def\figurefilecache {\clf_figurerequest{cache}{}} +\def\figurefileprefix {\clf_figurerequest{prefix}{}} + +\def\figurenaturalwidth {\clf_figureused{width}{\number\dimexpr\defaultfigurewidth\relax}sp} +\def\figurenaturalheight {\clf_figureused{height}{\number\dimexpr\defaultfigureheight\relax}sp} +\def\figurexresolution {\clf_figureused{xresolution}{0}} +\def\figureyresolution {\clf_figureused{yresolution}{0}} +\def\figurexsize {\clf_figureused{xsize}{0}} +\def\figureysize {\clf_figureused{ysize}{0}} +\def\figurecolordepth {\clf_figureused{colordepth}{0}} +\def\figuredepth {\clf_figureused{depth}{0}} + +\def\figurefullname {\clf_figureused{fullname}{}} +\def\noffigurepages {\clf_figureused{pages}{0}} + +\def\figurefilepath {\clf_figurefilepath} +\def\figurefilename {\clf_figurefilename} +\def\figurefiletype {\clf_figurefiletype} \let\naturalfigurewidth \figurenaturalwidth \let\naturalfigureheight \figurenaturalheight @@ -500,12 +510,14 @@ \fi} \appendtoks - \ctxlua { % figures.defaultwidth .. maybe a dimen some day - figures.setpaths("\externalfigureparameter\c!location","\externalfigureparameter\c!directory") ; - figures.defaultwidth = \number\dimexpr\defaultfigurewidth \relax ; - figures.defaultheight = \number\dimexpr\defaultfigureheight\relax ; - figures.boxnumber = \number\foundexternalfigure ; - }% + \clf_setfigurepaths + {\externalfigureparameter\c!location}% + {\externalfigureparameter\c!directory}% + \clf_figure_reset + \foundexternalfigure + \defaultfigurewidth + \defaultfigureheight + \relax \to \everyexternalfigureresets \appendtoks @@ -629,7 +641,7 @@ \externalfigure[#1][#2,\c!display=,\c!mask=,\c!object=\v!no]% \stopnointerference} -\unexpanded\def\doiffigureelse#1% +\unexpanded\def\doifelsefigure#1% {\getfiguredimensions[#1]% so data is available ! \ifcase\figurestatus \expandafter\secondoftwoarguments @@ -637,6 +649,8 @@ \expandafter\firstoftwoarguments \fi} +\let\doiffigureelse\doifelsefigure + % No placement, handy for preprocessing: \unexpanded\def\registerexternalfigure @@ -661,14 +675,14 @@ % Figure bases \unexpanded\def\usefigurebase[#1]% - {\ctxlua{figures.bases.use("#1")}} + {\clf_usefigurebase{#1}} \appendtoks \setfigurepathlist % the path may be used elsewhere too (as in x-res-04) \to \everysetupexternalfigure \appendtoks - \ctxcommand{setfigurelookuporder("\externalfigureparameter\c!order")}% + \clf_setfigurelookuporder{\externalfigureparameter\c!order}% \to \everysetupexternalfigure \definecolor[missingfigurecolor][s=.8] @@ -762,7 +776,7 @@ {\writestatus\m!system{the \string\showexternalfigures\space command is not (yet) implemented in mkiv}} \unexpanded\def\overlayfigure#1% - {\externalfigure[#1][\c!width=\overlaywidth,\c!height=\overlayheight]} + {\externalfigure[#1][\c!width=\d_overlay_width,\c!height=\d_overlay_height]} % Bonus: diff --git a/Master/texmf-dist/tex/context/base/grph-raw.lua b/Master/texmf-dist/tex/context/base/grph-raw.lua index 4c5b031ea98..62e96fcc9d7 100644 --- a/Master/texmf-dist/tex/context/base/grph-raw.lua +++ b/Master/texmf-dist/tex/context/base/grph-raw.lua @@ -40,3 +40,18 @@ function figures.bitmapimage(t) report_bitmap("invalid specification") end end + +interfaces.implement { + name = "bitmapimage", + actions = figures.bitmapimage, + arguments = { + { + { "data" }, + { "colorspace" }, + { "width" }, + { "height" }, + { "xresolution" }, + { "yresolution" }, + } + } +} diff --git a/Master/texmf-dist/tex/context/base/grph-raw.mkiv b/Master/texmf-dist/tex/context/base/grph-raw.mkiv index 1c683556412..8978ba2671b 100644 --- a/Master/texmf-dist/tex/context/base/grph-raw.mkiv +++ b/Master/texmf-dist/tex/context/base/grph-raw.mkiv @@ -46,14 +46,14 @@ \unexpanded\def\bitmapimage[#1]#2% {\hbox\bgroup \getdummyparameters[\c!color=rgb,\c!width=,\c!height=,\c!x=,\c!y=,#1]% - \ctxlua{figures.bitmapimage { % we could pass #1 directly ... todo - data = \!!bs#2\!!es, - colorspace = "\directdummyparameter\c!color", - width = "\directdummyparameter\c!width", - height = "\directdummyparameter\c!height", - xresolution = "\directdummyparameter\c!x", - yresolution = "\directdummyparameter\c!y", - }}% + \clf_bitmapimage + data {#2}% + colorspace {\directdummyparameter\c!color}% + width {\directdummyparameter\c!width}% + height {\directdummyparameter\c!height}% + xresolution {\directdummyparameter\c!x}% + yresolution {\directdummyparameter\c!y}% + \relax \egroup} \unexpanded\def\startbitmapimage[#1]#2\stopbitmapimage diff --git a/Master/texmf-dist/tex/context/base/grph-trf.mkiv b/Master/texmf-dist/tex/context/base/grph-trf.mkiv index d907c1b0ca3..fca5c7cf6ef 100644 --- a/Master/texmf-dist/tex/context/base/grph-trf.mkiv +++ b/Master/texmf-dist/tex/context/base/grph-trf.mkiv @@ -108,7 +108,7 @@ \edef\currentscale{#1}% \setupcurrentscale[#2]% \else\iffirstargument - \doifassignmentelse{#1} + \doifelseassignment{#1} {\let\currentscale\empty \setupcurrentscale[#1]} {\edef\currentscale{#1}}% @@ -318,11 +318,11 @@ \def\m_grph_scale_factor_set{\v!max,\v!fit,\v!broad,\v!auto} % can be an \edef \def\grph_scale_by_factor - {\doifinsetelse\p_factor\m_grph_scale_factor_set + {\doifelseinset\p_factor\m_grph_scale_factor_set \grph_scale_by_factor_a - {\doifinsetelse\p_hfactor\m_grph_scale_factor_set + {\doifelseinset\p_hfactor\m_grph_scale_factor_set \grph_scale_by_factor_b - {\doifinsetelse\p_wfactor\m_grph_scale_factor_set + {\doifelseinset\p_wfactor\m_grph_scale_factor_set \grph_scale_by_factor_c \grph_scale_by_factor_d}}} @@ -1080,18 +1080,18 @@ {\boxcursor\box\nextbox} \setvalue{\??rotatepreset\v!left}% - {\edef\p_rotation_rotation{\doifoddpageelse{90}{270}}} + {\edef\p_rotation_rotation{\doifelseoddpage{90}{270}}} \setvalue{\??rotatepreset\v!right}% - {\edef\p_rotation_rotation{\doifoddpageelse{270}{90}}} + {\edef\p_rotation_rotation{\doifelseoddpage{270}{90}}} \setvalue{\??rotatepreset\v!inner}% {\signalrightpage - \doifrightpageelse{\def\p_rotation_rotation{270}}{\def\p_rotation_rotation{90}}} + \doifelserightpage{\def\p_rotation_rotation{270}}{\def\p_rotation_rotation{90}}} \setvalue{\??rotatepreset\v!outer}% {\signalrightpage - \doifrightpageelse{\def\p_rotation_rotation{90}}{\def\p_rotation_rotation{270}}} + \doifelserightpage{\def\p_rotation_rotation{90}}{\def\p_rotation_rotation{270}}} \setvalue{\??rotatepreset\v!default}% {\edef\p_rotation_rotation{\realnumber{\p_rotation_rotation}}}% get rid of leading zeros and spaces diff --git a/Master/texmf-dist/tex/context/base/hand-ini.mkiv b/Master/texmf-dist/tex/context/base/hand-ini.mkiv index 450794d276f..fd18e3221d0 100644 --- a/Master/texmf-dist/tex/context/base/hand-ini.mkiv +++ b/Master/texmf-dist/tex/context/base/hand-ini.mkiv @@ -42,8 +42,8 @@ \unexpanded\def\setupfontexpansion {\dodoubleargument\font_expansion_setup } \unexpanded\def\setupfontprotrusion{\dodoubleargument\font_protrusion_setup} -\def\font_expansion_setup [#1][#2]{\ctxcommand{setupfontexpansion ("#1","#2")}} -\def\font_protrusion_setup[#1][#2]{\ctxcommand{setupfontprotrusion("#1","#2")}} +\def\font_expansion_setup [#1][#2]{\clf_setupfontexpansion {#1}{#2}} +\def\font_protrusion_setup[#1][#2]{\clf_setupfontprotrusion{#1}{#2}} % \setupfontprotrusion[quality-upright][vector=quality] % \setupfontprotrusion[quality-slanted][vector=quality,right=1.5] @@ -51,10 +51,10 @@ \let\pdfadjustspacing\relax \newcount\pdfadjustspacing % a little bit protection \let\pdfprotrudechars\relax \newcount\pdfprotrudechars % a little bit protection -\def\font_expansion_enable {\normalpdfadjustspacing\plustwo } -\def\font_expansion_disable {\normalpdfadjustspacing\zerocount} -\def\font_protruding_enable {\normalpdfprotrudechars\plustwo } -\def\font_protruding_disable{\normalpdfprotrudechars\zerocount} +\def\font_expansion_enable {\normalpdfadjustspacing\plustwo } % these will become normal primitives +\def\font_expansion_disable {\normalpdfadjustspacing\zerocount} % these will become normal primitives +\def\font_protruding_enable {\normalpdfprotrudechars\plustwo } % these will become normal primitives +\def\font_protruding_disable{\normalpdfprotrudechars\zerocount} % these will become normal primitives \appendtoks \font_expansion_disable \to \everyforgetall % Here or not here? \appendtoks \font_protruding_disable \to \everyforgetall % Here or not here? diff --git a/Master/texmf-dist/tex/context/base/java-imp-fld.mkiv b/Master/texmf-dist/tex/context/base/java-imp-fld.mkiv index aaec257f259..cbd53fffb4a 100644 --- a/Master/texmf-dist/tex/context/base/java-imp-fld.mkiv +++ b/Master/texmf-dist/tex/context/base/java-imp-fld.mkiv @@ -30,29 +30,34 @@ %D On into Yes. Also, we've changed the test for the on value %D into !Off as we dón't know what value it gets in the reader. +% Is this still okay? We can have unicode now, can't we? Anyway it's kind of +% messy and unneeded in these unicode times. + \startluasetups javascript:pdfencoding - local verbatim = context.verbatim - verbatim("{\n") - for accent, group in table.sortedhash(characters.tex.accentmapping) do - for character, mapping in table.sortedhash(group) do + local ctx_verbatim = context.verbatim + local utfbyte = utf.byte + local sortedhash = table.sortedhash + + ctx_verbatim("{\n") + for accent, group in sortedhash(characters.tex.accentmapping) do + for character, mapping in sortedhash(group) do if character == "" then character = " " end if accent == '"' then - verbatim(" '\\\\%s%s' : '\\u%04X',\n",accent,character,utf.byte(mapping)) + ctx_verbatim(" '\\\\%s%s' : '\\u%04X',\n",accent,character,utfbyte(mapping)) else - verbatim(' "\\\\%s%s" : "\\u%04X",\n',accent,character,utf.byte(mapping)) + ctx_verbatim(' "\\\\%s%s" : "\\u%04X",\n',accent,character,utfbyte(mapping)) end end end - verbatim(" '\\\\OE' : '\\u0152',\n") - verbatim(" '\\\\oe' : '\\u0153',\n") - verbatim(" '\\\\AE' : '\\u00C6',\n") - verbatim(" '\\\\ae' : '\\u00E6',\n") - verbatim(" '\\\\<<' : '\\u00AB',\n") - verbatim(" '\\\\>>' : '\\u00BB',\n") - verbatim(" '\\\\ss' : '\\u00DF' \n") - verbatim("}\n") + for command, mapping in sortedhash(characters.tex.commandmapping) do + ctx_verbatim(' "\\\\%s" : "\\u%04X",\n',command,utfbyte(mapping)) + end + -- ctx_verbatim(" '\\\\<<' : '\\u00AB',\n") + -- ctx_verbatim(" '\\\\>>' : '\\u00BB',\n") + ctx_verbatim("}\n") + \stopluasetups % maybe make { } tex braces in javascript code so that we can call lua diff --git a/Master/texmf-dist/tex/context/base/java-ini.lua b/Master/texmf-dist/tex/context/base/java-ini.lua index 67337949465..069eb5ab610 100644 --- a/Master/texmf-dist/tex/context/base/java-ini.lua +++ b/Master/texmf-dist/tex/context/base/java-ini.lua @@ -19,7 +19,7 @@ local variables = interfaces.variables local formatters = string.formatters local context = context -local commands = commands +local implement = interfaces.implement local trace_javascript = false trackers.register("backends.javascript", function(v) trace_javascript = v end) @@ -196,7 +196,13 @@ function javascripts.flushpreambles() return t end -local patterns = { "java-imp-%s.mkiv", "java-imp-%s.tex", "java-%s.mkiv", "java-%s.tex" } +local patterns = { + "java-imp-%s.mkiv", + "java-imp-%s.tex", + -- obsolete: + "java-%s.mkiv", + "java-%s.tex" +} local function action(name,foundname) context.startnointerference() @@ -213,7 +219,7 @@ end function javascripts.usescripts(name) if name ~= variables.reset then -- reset is obsolete - commands.uselibrary { + resolvers.uselibrary { name = name, patterns = patterns, action = action, @@ -225,8 +231,38 @@ end -- interface -commands.storejavascriptcode = interactions.javascripts.storecode -commands.storejavascriptpreamble = interactions.javascripts.storepreamble -commands.addtojavascriptpreamble = interactions.javascripts.addtopreamble -commands.usejavascriptpreamble = interactions.javascripts.usepreamblenow -commands.usejavascriptscripts = interactions.javascripts.usescripts +implement { + name = "storejavascriptcode", + actions = javascripts.storecode, + arguments = "string" +} + +implement { + name = "storejavascriptpreamble", + actions = javascripts.storepreamble, + arguments = "string" +} + +implement { + name = "setjavascriptpreamble", + actions = javascripts.setpreamble, + arguments = { "string", "string" } +} + +implement { + name = "addtojavascriptpreamble", + actions = javascripts.addtopreamble, + arguments = { "string", "string" } +} + +implement { + name = "usejavascriptpreamble", + actions = javascripts.usepreamblenow, + arguments = "string" +} + +implement { + name = "usejavascriptscripts", + actions = javascripts.usescripts, + arguments = "string" +} diff --git a/Master/texmf-dist/tex/context/base/java-ini.mkiv b/Master/texmf-dist/tex/context/base/java-ini.mkiv index e4f0bf28b4c..d6fe4dd8a05 100644 --- a/Master/texmf-dist/tex/context/base/java-ini.mkiv +++ b/Master/texmf-dist/tex/context/base/java-ini.mkiv @@ -105,15 +105,17 @@ %D This macro can be used to force inclusion of postponed %D \JAVASCRIPT\ preambles. +\def\m_java_escape_u{\letterbackslash u} + \unexpanded\def\startJScode {\begingroup \obeylualines \obeyluatokens - \def\u{\letterbackslash u}% + \let\u\m_java_escape_u \java_start_code} \def\java_start_code#1\stopJScode - {\normalexpanded{\endgroup\ctxcommand{storejavascriptcode(\!!bs#1\!!es)}}} + {\normalexpanded{\endgroup\clf_storejavascriptcode{#1}}} \let\stopJScode\relax @@ -121,16 +123,16 @@ {\begingroup \obeylualines \obeyluatokens - \def\u{\letterbackslash u}% + \let\u\m_java_escape_u \java_start_preamble} \def\java_start_preamble#1\stopJSpreamble - {\normalexpanded{\endgroup\ctxcommand{storejavascriptpreamble(\!!bs#1\!!es)}}} + {\normalexpanded{\endgroup\clf_storejavascriptpreamble{#1}}} \let\stopJSpreamble\relax -\unexpanded\def\setJSpreamble #1#2{\ctxcommand{storejavascriptpreamble("#1",\!!bs#2\!!es)}} -\unexpanded\def\addtoJSpreamble#1#2{\ctxcommand{addtojavascriptpreamble("#1",\!!bs#2\!!es)}} +\unexpanded\def\setJSpreamble #1#2{\clf_setjavascriptpreamble {#1}{#2}} +\unexpanded\def\addtoJSpreamble#1#2{\clf_addtojavascriptpreamble{#1}{#2}} %D \macros %D {useJSscripts} @@ -147,11 +149,11 @@ %D %D The not so complicated implementation of this macro is: -\def\useJSscripts +\unexpanded\def\useJSscripts {\dodoubleempty\java_use_scripts} \def\java_use_scripts[#1][#2]% - {\ctxcommand{usejavascriptscripts(\!!bs#1\!!es)}% two steps as this one calls tex code - \ctxcommand{usejavascriptpreamble("#2")}} % so this one comes later + {\clf_usejavascriptscripts {#1}% two steps as this one calls tex code + \clf_usejavascriptpreamble{#2}}% so this one comes later \protect \endinput diff --git a/Master/texmf-dist/tex/context/base/l-boolean.lua b/Master/texmf-dist/tex/context/base/l-boolean.lua index 8d11080e7fc..8f18d4c003d 100644 --- a/Master/texmf-dist/tex/context/base/l-boolean.lua +++ b/Master/texmf-dist/tex/context/base/l-boolean.lua @@ -57,11 +57,11 @@ function string.booleanstring(str) end end -function string.is_boolean(str,default) +function string.is_boolean(str,default,strict) if type(str) == "string" then - if str == "true" or str == "yes" or str == "on" or str == "t" or str == "1" then + if str == "true" or str == "yes" or str == "on" or str == "t" or (not strict and str == "1") then return true - elseif str == "false" or str == "no" or str == "off" or str == "f" or str == "0" then + elseif str == "false" or str == "no" or str == "off" or str == "f" or (not strict and str == "0") then return false end end diff --git a/Master/texmf-dist/tex/context/base/l-dir.lua b/Master/texmf-dist/tex/context/base/l-dir.lua index 25721206046..81ac65e506d 100644 --- a/Master/texmf-dist/tex/context/base/l-dir.lua +++ b/Master/texmf-dist/tex/context/base/l-dir.lua @@ -6,10 +6,11 @@ if not modules then modules = { } end modules ['l-dir'] = { license = "see context related readme files" } --- dir.expandname will be merged with cleanpath and collapsepath +-- todo: dir.expandname will be sped up and merged with cleanpath and collapsepath +-- todo: keep track of currentdir (chdir, pushdir, popdir) local type, select = type, select -local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub +local find, gmatch, match, gsub, sub = string.find, string.gmatch, string.match, string.gsub, string.sub local concat, insert, remove, unpack = table.concat, table.insert, table.remove, table.unpack local lpegmatch = lpeg.match @@ -21,8 +22,8 @@ local lfs = lfs local attributes = lfs.attributes local walkdir = lfs.dir -local isdir = lfs.isdir -local isfile = lfs.isfile +local isdir = lfs.isdir -- not robust, will be overloaded anyway +local isfile = lfs.isfile -- not robust, will be overloaded anyway local currentdir = lfs.currentdir local chdir = lfs.chdir local mkdir = lfs.mkdir @@ -31,20 +32,41 @@ local onwindows = os.type == "windows" or find(os.getenv("PATH"),";",1,true) -- in case we load outside luatex -if not isdir then - function isdir(name) - local a = attributes(name) - return a and a.mode == "directory" +if onwindows then + + -- lfs.isdir does not like trailing / + -- lfs.dir accepts trailing / + + local tricky = S("/\\") * P(-1) + + isdir = function(name) + if lpegmatch(tricky,name) then + return attributes(name,"mode") == "directory" + else + return attributes(name.."/.","mode") == "directory" + end + end + + isfile = function(name) + return attributes(name,"mode") == "file" + end + + lfs.isdir = isdir + lfs.isfile = isfile + +else + + isdir = function(name) + return attributes(name,"mode") == "directory" end - lfs.isdir = isdir -end -if not isfile then - function isfile(name) - local a = attributes(name) - return a and a.mode == "file" + isfile = function(name) + return attributes(name,"mode") == "file" end + + lfs.isdir = isdir lfs.isfile = isfile + end -- handy @@ -53,63 +75,104 @@ function dir.current() return (gsub(currentdir(),"\\","/")) end --- optimizing for no find (*) does not save time - ---~ local function globpattern(path,patt,recurse,action) -- fails in recent luatex due to some change in lfs ---~ local ok, scanner ---~ if path == "/" then ---~ ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe ---~ else ---~ ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe ---~ end ---~ if ok and type(scanner) == "function" then ---~ if not find(path,"/$") then path = path .. '/' end ---~ for name in scanner do ---~ local full = path .. name ---~ local mode = attributes(full,'mode') ---~ if mode == 'file' then ---~ if find(full,patt) then ---~ action(full) ---~ end ---~ elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then ---~ globpattern(full,patt,recurse,action) ---~ end ---~ end ---~ end ---~ end - -local lfsisdir = isdir - -local function isdir(path) - path = gsub(path,"[/\\]+$","") - return lfsisdir(path) -end +-- somewhat optimized -lfs.isdir = isdir +local function glob_pattern_function(path,patt,recurse,action) + if isdir(path) then + local usedpath + if path == "/" then + usedpath = "/." + elseif not find(path,"/$") then + usedpath = path .. "/." + path = path .. "/" + else + usedpath = path + end + local dirs + for name in walkdir(usedpath) do + if name ~= "." and name ~= ".." then + local full = path .. name + local mode = attributes(full,'mode') + if mode == 'file' then + if not patt or find(full,patt) then + action(full) + end + elseif recurse and mode == "directory" then + if not dirs then + dirs = { full } + else + dirs[#dirs+1] = full + end + end + end + end + if dirs then + for i=1,#dirs do + glob_pattern_function(dirs[i],patt,recurse,action) + end + end + end +end -local function globpattern(path,patt,recurse,action) - if path == "/" then - path = path .. "." - elseif not find(path,"/$") then - path = path .. '/' +local function glob_pattern_table(path,patt,recurse,result) + if not result then + result = { } end - if isdir(path) then -- lfs.isdir does not like trailing / - for name in walkdir(path) do -- lfs.dir accepts trailing / - local full = path .. name - local mode = attributes(full,'mode') - if mode == 'file' then - if find(full,patt) then - action(full) + if isdir(path) then + local usedpath + if path == "/" then + usedpath = "/." + elseif not find(path,"/$") then + usedpath = path .. "/." + path = path .. "/" + else + usedpath = path + end + local dirs + for name in walkdir(usedpath) do + if name ~= "." and name ~= ".." then + local full = path .. name + local mode = attributes(full,'mode') + if mode == 'file' then + if not patt or find(full,patt) then + result[#result+1] = full + end + elseif recurse and mode == "directory" then + if not dirs then + dirs = { full } + else + dirs[#dirs+1] = full + end end - elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then - globpattern(full,patt,recurse,action) + end + end + if dirs then + for i=1,#dirs do + glob_pattern_table(dirs[i],patt,recurse,result) end end end + return result +end + +local function globpattern(path,patt,recurse,method) + local kind = type(method) + if patt and sub(patt,1,-3) == path then + patt = false + end + if kind == "function" then + return glob_pattern_function(path,patt,recurse,method) + elseif kind == "table" then + return glob_pattern_table(path,patt,recurse,method) + else + return glob_pattern_table(path,patt,recurse,{ }) + end end dir.globpattern = globpattern +-- never or seldom used so far: + local function collectpattern(path,patt,recurse,result) local ok, scanner result = result or { } @@ -119,18 +182,26 @@ local function collectpattern(path,patt,recurse,result) ok, scanner, first = xpcall(function() return walkdir(path) end, function() end) -- kepler safe end if ok and type(scanner) == "function" then - if not find(path,"/$") then path = path .. '/' end + if not find(path,"/$") then + path = path .. '/' + end for name in scanner, first do - local full = path .. name - local attr = attributes(full) - local mode = attr.mode - if mode == 'file' then - if find(full,patt) then + if name == "." then + -- skip + elseif name == ".." then + -- skip + else + local full = path .. name + local attr = attributes(full) + local mode = attr.mode + if mode == 'file' then + if find(full,patt) then + result[name] = attr + end + elseif recurse and mode == "directory" then + attr.list = collectpattern(full,patt,recurse) result[name] = attr end - elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then - attr.list = collectpattern(full,patt,recurse) - result[name] = attr end end end @@ -139,19 +210,14 @@ end dir.collectpattern = collectpattern -local separator +local separator, pattern if onwindows then -- we could sanitize here --- pattern = Ct { --- [1] = (C(P(".") + S("/\\")^1) + C(R("az","AZ") * P(":") * S("/\\")^0) + Cc("./")) * V(2) * V(3), --- [2] = C(((1-S("*?/\\"))^0 * S("/\\"))^0), --- [3] = C(P(1)^0) --- } - local slash = S("/\\") / "/" - pattern = Ct { +-- pattern = Ct { + pattern = { [1] = (Cs(P(".") + slash^1) + Cs(R("az","AZ") * P(":") * slash^0) + Cc("./")) * V(2) * V(3), [2] = Cs(((1-S("*?/\\"))^0 * slash)^0), [3] = Cs(P(1)^0) @@ -159,7 +225,8 @@ if onwindows then -- we could sanitize here else -- assume unix - pattern = Ct { +-- pattern = Ct { + pattern = { [1] = (C(P(".") + P("/")^1) + Cc("./")) * V(2) * V(3), [2] = C(((1-S("*?/"))^0 * P("/"))^0), [3] = C(P(1)^0) @@ -186,12 +253,11 @@ local function glob(str,t) elseif isfile(str) then t(str) else - local split = lpegmatch(pattern,str) -- we could use the file splitter - if split then - local root, path, base = split[1], split[2], split[3] + local root, path, base = lpegmatch(pattern,str) -- we could use the file splitter + if root and path and base then local recurse = find(base,"**",1,true) -- find(base,"%*%*") - local start = root .. path - local result = lpegmatch(filter,start .. base) + local start = root .. path + local result = lpegmatch(filter,start .. base) globpattern(start,result,recurse,t) end end @@ -210,16 +276,12 @@ local function glob(str,t) return { str } end else - local split = lpegmatch(pattern,str) -- we could use the file splitter - if split then - local t = t or { } - local action = action or function(name) t[#t+1] = name end - local root, path, base = split[1], split[2], split[3] - local recurse = find(base,"**",1,true) -- find(base,"%*%*") - local start = root .. path - local result = lpegmatch(filter,start .. base) - globpattern(start,result,recurse,action) - return t + local root, path, base = lpegmatch(pattern,str) -- we could use the file splitter + if root and path and base then + local recurse = find(base,"**",1,true) -- find(base,"%*%*") + local start = root .. path + local result = lpegmatch(filter,start .. base) + return globpattern(start,result,recurse,t) else return { } end @@ -229,11 +291,20 @@ end dir.glob = glob ---~ list = dir.glob("**/*.tif") ---~ list = dir.glob("/**/*.tif") ---~ list = dir.glob("./**/*.tif") ---~ list = dir.glob("oeps/**/*.tif") ---~ list = dir.glob("/oeps/**/*.tif") +-- local c = os.clock() +-- local t = dir.glob("e:/**") +-- local t = dir.glob("t:/sources/**") +-- local t = dir.glob("t:/**") +-- print(os.clock()-c,#t) + +-- for i=1,3000 do print(t[i]) end +-- for i=1,10 do print(t[i]) end + +-- list = dir.glob("**/*.tif") +-- list = dir.glob("/**/*.tif") +-- list = dir.glob("./**/*.tif") +-- list = dir.glob("oeps/**/*.tif") +-- list = dir.glob("/oeps/**/*.tif") local function globfiles(path,recurse,func,files) -- func == pattern or function if type(func) == "string" then @@ -275,10 +346,10 @@ function dir.ls(pattern) return concat(glob(pattern),"\n") end ---~ mkdirs("temp") ---~ mkdirs("a/b/c") ---~ mkdirs(".","/a/b/c") ---~ mkdirs("a","b","c") +-- mkdirs("temp") +-- mkdirs("a/b/c") +-- mkdirs(".","/a/b/c") +-- mkdirs("a","b","c") local make_indeed = true -- false @@ -347,17 +418,17 @@ if onwindows then return pth, (isdir(pth) == true) end - --~ print(dir.mkdirs("","","a","c")) - --~ print(dir.mkdirs("a")) - --~ print(dir.mkdirs("a:")) - --~ print(dir.mkdirs("a:/b/c")) - --~ print(dir.mkdirs("a:b/c")) - --~ print(dir.mkdirs("a:/bbb/c")) - --~ print(dir.mkdirs("/a/b/c")) - --~ print(dir.mkdirs("/aaa/b/c")) - --~ print(dir.mkdirs("//a/b/c")) - --~ print(dir.mkdirs("///a/b/c")) - --~ print(dir.mkdirs("a/bbb//ccc/")) + -- print(dir.mkdirs("","","a","c")) + -- print(dir.mkdirs("a")) + -- print(dir.mkdirs("a:")) + -- print(dir.mkdirs("a:/b/c")) + -- print(dir.mkdirs("a:b/c")) + -- print(dir.mkdirs("a:/bbb/c")) + -- print(dir.mkdirs("/a/b/c")) + -- print(dir.mkdirs("/aaa/b/c")) + -- print(dir.mkdirs("//a/b/c")) + -- print(dir.mkdirs("///a/b/c")) + -- print(dir.mkdirs("a/bbb//ccc/")) else @@ -408,64 +479,75 @@ else return pth, (isdir(pth) == true) end - --~ print(dir.mkdirs("","","a","c")) - --~ print(dir.mkdirs("a")) - --~ print(dir.mkdirs("/a/b/c")) - --~ print(dir.mkdirs("/aaa/b/c")) - --~ print(dir.mkdirs("//a/b/c")) - --~ print(dir.mkdirs("///a/b/c")) - --~ print(dir.mkdirs("a/bbb//ccc/")) + -- print(dir.mkdirs("","","a","c")) + -- print(dir.mkdirs("a")) + -- print(dir.mkdirs("/a/b/c")) + -- print(dir.mkdirs("/aaa/b/c")) + -- print(dir.mkdirs("//a/b/c")) + -- print(dir.mkdirs("///a/b/c")) + -- print(dir.mkdirs("a/bbb//ccc/")) end dir.makedirs = dir.mkdirs --- we can only define it here as it uses dir.current -if onwindows then +do - function dir.expandname(str) -- will be merged with cleanpath and collapsepath - local first, nothing, last = match(str,"^(//)(//*)(.*)$") - if first then - first = dir.current() .. "/" -- dir.current sanitizes - end - if not first then - first, last = match(str,"^(//)/*(.*)$") - end - if not first then - first, last = match(str,"^([a-zA-Z]:)(.*)$") - if first and not find(last,"^/") then - local d = currentdir() - if chdir(first) then - first = dir.current() + -- we can only define it here as it uses dir.chdir and we also need to + -- make sure we use the non sandboxed variant because otherwise we get + -- into a recursive loop due to usage of expandname in the file resolver + + local chdir = sandbox and sandbox.original(chdir) or chdir + + if onwindows then + + local xcurrentdir = dir.current + + function dir.expandname(str) -- will be merged with cleanpath and collapsepath\ + local first, nothing, last = match(str,"^(//)(//*)(.*)$") + if first then + first = xcurrentdir() .. "/" -- xcurrentdir sanitizes + end + if not first then + first, last = match(str,"^(//)/*(.*)$") + end + if not first then + first, last = match(str,"^([a-zA-Z]:)(.*)$") + if first and not find(last,"^/") then + local d = currentdir() -- push / pop + if chdir(first) then + first = xcurrentdir() -- xcurrentdir sanitizes + end + chdir(d) end - chdir(d) + end + if not first then + first, last = xcurrentdir(), str + end + last = gsub(last,"//","/") + last = gsub(last,"/%./","/") + last = gsub(last,"^/*","") + first = gsub(first,"/*$","") + if last == "" or last == "." then + return first + else + return first .. "/" .. last end end - if not first then - first, last = dir.current(), str - end - last = gsub(last,"//","/") - last = gsub(last,"/%./","/") - last = gsub(last,"^/*","") - first = gsub(first,"/*$","") - if last == "" or last == "." then - return first - else - return first .. "/" .. last - end - end -else + else - function dir.expandname(str) -- will be merged with cleanpath and collapsepath - if not find(str,"^/") then - str = currentdir() .. "/" .. str + function dir.expandname(str) -- will be merged with cleanpath and collapsepath + if not find(str,"^/") then + str = currentdir() .. "/" .. str + end + str = gsub(str,"//","/") + str = gsub(str,"/%./","/") + str = gsub(str,"(.)/%.$","%1") + return str end - str = gsub(str,"//","/") - str = gsub(str,"/%./","/") - str = gsub(str,"(.)/%.$","%1") - return str + end end diff --git a/Master/texmf-dist/tex/context/base/l-file.lua b/Master/texmf-dist/tex/context/base/l-file.lua index ebb2b39f4a2..7ed6370f260 100644 --- a/Master/texmf-dist/tex/context/base/l-file.lua +++ b/Master/texmf-dist/tex/context/base/l-file.lua @@ -15,51 +15,53 @@ if not lfs then lfs = optionalrequire("lfs") end -if not lfs then - - lfs = { - getcurrentdir = function() - return "." - end, - attributes = function() - return nil - end, - isfile = function(name) - local f = io.open(name,'rb') - if f then - f:close() - return true - end - end, - isdir = function(name) - print("you need to load lfs") - return false - end - } - -elseif not lfs.isfile then - - local attributes = lfs.attributes - - function lfs.isdir(name) - return attributes(name,"mode") == "directory" - end - - function lfs.isfile(name) - return attributes(name,"mode") == "file" - end - - -- function lfs.isdir(name) - -- local a = attributes(name) - -- return a and a.mode == "directory" - -- end - - -- function lfs.isfile(name) - -- local a = attributes(name) - -- return a and a.mode == "file" - -- end - -end +-- -- see later +-- +-- if not lfs then +-- +-- lfs = { +-- getcurrentdir = function() +-- return "." +-- end, +-- attributes = function() +-- return nil +-- end, +-- isfile = function(name) +-- local f = io.open(name,'rb') +-- if f then +-- f:close() +-- return true +-- end +-- end, +-- isdir = function(name) +-- print("you need to load lfs") +-- return false +-- end +-- } +-- +-- elseif not lfs.isfile then +-- +-- local attributes = lfs.attributes +-- +-- function lfs.isdir(name) +-- return attributes(name,"mode") == "directory" +-- end +-- +-- function lfs.isfile(name) +-- return attributes(name,"mode") == "file" +-- end +-- +-- -- function lfs.isdir(name) +-- -- local a = attributes(name) +-- -- return a and a.mode == "directory" +-- -- end +-- +-- -- function lfs.isfile(name) +-- -- local a = attributes(name) +-- -- return a and a.mode == "file" +-- -- end +-- +-- end local insert, concat = table.insert, table.concat local match, find, gmatch = string.match, string.find, string.gmatch @@ -72,6 +74,28 @@ local checkedsplit = string.checkedsplit local P, R, S, C, Cs, Cp, Cc, Ct = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Cp, lpeg.Cc, lpeg.Ct +-- better this way: + +local tricky = S("/\\") * P(-1) +local attributes = lfs.attributes + +if sandbox then + sandbox.redefine(lfs.isfile,"lfs.isfile") + sandbox.redefine(lfs.isdir, "lfs.isdir") +end + +function lfs.isdir(name) + if lpegmatch(tricky,name) then + return attributes(name,"mode") == "directory" + else + return attributes(name.."/.","mode") == "directory" + end +end + +function lfs.isfile(name) + return attributes(name,"mode") == "file" +end + local colon = P(":") local period = P(".") local periods = P("..") @@ -133,8 +157,8 @@ file.suffix = suffixonly file.suffixesonly = suffixesonly file.suffixes = suffixesonly -file.dirname = pathpart -- obsolete -file.extname = suffixonly -- obsolete +file.dirname = pathpart -- obsolete +file.extname = suffixonly -- obsolete -- actually these are schemes @@ -385,31 +409,90 @@ local deslasher = lpeg.replacer(S("\\/")^1,"/") -- then we still have to deal with urls ... anyhow, multiple // are never a real -- problem but just ugly. -function file.join(...) - local lst = { ... } - local one = lst[1] +-- function file.join(...) +-- local lst = { ... } +-- local one = lst[1] +-- if lpegmatch(isnetwork,one) then +-- local one = lpegmatch(reslasher,one) +-- local two = lpegmatch(deslasher,concat(lst,"/",2)) +-- if lpegmatch(hasroot,two) then +-- return one .. two +-- else +-- return one .. "/" .. two +-- end +-- elseif lpegmatch(isroot,one) then +-- local two = lpegmatch(deslasher,concat(lst,"/",2)) +-- if lpegmatch(hasroot,two) then +-- return two +-- else +-- return "/" .. two +-- end +-- elseif one == "" then +-- return lpegmatch(stripper,concat(lst,"/",2)) +-- else +-- return lpegmatch(deslasher,concat(lst,"/")) +-- end +-- end + +function file.join(one, two, three, ...) + if not two then + return one == "" and one or lpegmatch(stripper,one) + end + if one == "" then + return lpegmatch(stripper,three and concat({ two, three, ... },"/") or two) + end if lpegmatch(isnetwork,one) then local one = lpegmatch(reslasher,one) - local two = lpegmatch(deslasher,concat(lst,"/",2)) + local two = lpegmatch(deslasher,three and concat({ two, three, ... },"/") or two) if lpegmatch(hasroot,two) then return one .. two else return one .. "/" .. two end elseif lpegmatch(isroot,one) then - local two = lpegmatch(deslasher,concat(lst,"/",2)) + local two = lpegmatch(deslasher,three and concat({ two, three, ... },"/") or two) if lpegmatch(hasroot,two) then return two else return "/" .. two end - elseif one == "" then - return lpegmatch(stripper,concat(lst,"/",2)) else - return lpegmatch(deslasher,concat(lst,"/")) + return lpegmatch(deslasher,concat({ one, two, three, ... },"/")) end end +-- or we can use this: +-- +-- function file.join(...) +-- local n = select("#",...) +-- local one = select(1,...) +-- if n == 1 then +-- return one == "" and one or lpegmatch(stripper,one) +-- end +-- if one == "" then +-- return lpegmatch(stripper,n > 2 and concat({ ... },"/",2) or select(2,...)) +-- end +-- if lpegmatch(isnetwork,one) then +-- local one = lpegmatch(reslasher,one) +-- local two = lpegmatch(deslasher,n > 2 and concat({ ... },"/",2) or select(2,...)) +-- if lpegmatch(hasroot,two) then +-- return one .. two +-- else +-- return one .. "/" .. two +-- end +-- elseif lpegmatch(isroot,one) then +-- local two = lpegmatch(deslasher,n > 2 and concat({ ... },"/",2) or select(2,...)) +-- if lpegmatch(hasroot,two) then +-- return two +-- else +-- return "/" .. two +-- end +-- else +-- return lpegmatch(deslasher,concat({ ... },"/")) +-- end +-- end + +-- print(file.join("c:/whatever")) -- print(file.join("c:/whatever","name")) -- print(file.join("//","/y")) -- print(file.join("/","/y")) diff --git a/Master/texmf-dist/tex/context/base/l-io.lua b/Master/texmf-dist/tex/context/base/l-io.lua index 020e811bf09..a91d44d8776 100644 --- a/Master/texmf-dist/tex/context/base/l-io.lua +++ b/Master/texmf-dist/tex/context/base/l-io.lua @@ -339,11 +339,6 @@ function io.readstring(f,n,m) return str end --- - -if not io.i_limiter then function io.i_limiter() end end -- dummy so we can test safely -if not io.o_limiter then function io.o_limiter() end end -- dummy so we can test safely - -- This works quite ok: -- -- function io.piped(command,writer) diff --git a/Master/texmf-dist/tex/context/base/l-lpeg.lua b/Master/texmf-dist/tex/context/base/l-lpeg.lua index 666af210386..4aadadb727c 100644 --- a/Master/texmf-dist/tex/context/base/l-lpeg.lua +++ b/Master/texmf-dist/tex/context/base/l-lpeg.lua @@ -145,6 +145,9 @@ patterns.utfbom_8 = utfbom_8 patterns.utf_16_be_nl = P("\000\r\000\n") + P("\000\r") + P("\000\n") -- P("\000\r") * (P("\000\n") + P(true)) + P("\000\n") patterns.utf_16_le_nl = P("\r\000\n\000") + P("\r\000") + P("\n\000") -- P("\r\000") * (P("\n\000") + P(true)) + P("\n\000") +patterns.utf_32_be_nl = P("\000\000\000\r\000\000\000\n") + P("\000\000\000\r") + P("\000\000\000\n") +patterns.utf_32_le_nl = P("\r\000\000\000\n\000\000\000") + P("\r\000\000\000") + P("\n\000\000\000") + patterns.utf8one = R("\000\127") patterns.utf8two = R("\194\223") * utf8next patterns.utf8three = R("\224\239") * utf8next * utf8next @@ -183,10 +186,26 @@ local fullstripper = whitespace^0 * C((whitespace^0 * nonwhitespace^1)^0) ----- collapser = Cs(spacer^0/"" * ((spacer^1 * endofstring / "") + (spacer^1/" ") + P(1))^0) local collapser = Cs(spacer^0/"" * nonspacer^0 * ((spacer^0/" " * nonspacer^1)^0)) +local b_collapser = Cs( whitespace^0 /"" * (nonwhitespace^1 + whitespace^1/" ")^0) +local e_collapser = Cs((whitespace^1 * P(-1)/"" + nonwhitespace^1 + whitespace^1/" ")^0) +local m_collapser = Cs( (nonwhitespace^1 + whitespace^1/" ")^0) + +local b_stripper = Cs( spacer^0 /"" * (nonspacer^1 + spacer^1/" ")^0) +local e_stripper = Cs((spacer^1 * P(-1)/"" + nonspacer^1 + spacer^1/" ")^0) +local m_stripper = Cs( (nonspacer^1 + spacer^1/" ")^0) + patterns.stripper = stripper patterns.fullstripper = fullstripper patterns.collapser = collapser +patterns.b_collapser = b_collapser +patterns.m_collapser = m_collapser +patterns.e_collapser = e_collapser + +patterns.b_stripper = b_stripper +patterns.m_stripper = m_stripper +patterns.e_stripper = e_stripper + patterns.lowercase = lowercase patterns.uppercase = uppercase patterns.letter = patterns.lowercase + patterns.uppercase @@ -225,9 +244,12 @@ patterns.integer = sign^-1 * digit^1 patterns.unsigned = digit^0 * period * digit^1 patterns.float = sign^-1 * patterns.unsigned patterns.cunsigned = digit^0 * comma * digit^1 +patterns.cpunsigned = digit^0 * (period + comma) * digit^1 patterns.cfloat = sign^-1 * patterns.cunsigned +patterns.cpfloat = sign^-1 * patterns.cpunsigned patterns.number = patterns.float + patterns.integer patterns.cnumber = patterns.cfloat + patterns.integer +patterns.cpnumber = patterns.cpfloat + patterns.integer patterns.oct = zero * octdigit^1 patterns.octal = patterns.oct patterns.HEX = zero * P("X") * (digit+uppercase)^1 @@ -496,7 +518,6 @@ function lpeg.finder(lst,makefunction,isutf) -- beware: slower than find with 'p pattern = P(lst) end if isutf then --- pattern = ((utf8char or 1)-pattern)^0 * pattern pattern = ((utf8char or 1)-pattern)^0 * pattern else pattern = (1-pattern)^0 * pattern @@ -813,23 +834,48 @@ end -- experiment: +local p_false = P(false) +local p_true = P(true) + local function make(t) - local p + local function making(t) + local p = p_false + local keys = sortedkeys(t) +-- local okay = t[""] + for i=1,#keys do + local k = keys[i] + if k ~= "" then + local v = t[k] + if v == true then + p = p + P(k) * p_true + elseif v == false then + -- can't happen +-- elseif okay then +-- p = p + P(k) * (making(v) + p_true) + else + p = p + P(k) * making(v) + end + end + end + if t[""] then + p = p + p_true + end + return p + end + local p = p_false local keys = sortedkeys(t) for i=1,#keys do local k = keys[i] - local v = t[k] - if not p then - if next(v) then - p = P(k) * make(v) + if k ~= "" then + local v = t[k] + if v == true then + p = p + P(k) * p_true + elseif v == false then + -- can't happen +-- elseif v[""] then +-- p = p + P(k) * (making(v) + p_true) else - p = P(k) - end - else - if next(v) then - p = p + P(k) * make(v) - else - p = p + P(k) + p = p + P(k) * making(v) end end end @@ -838,19 +884,109 @@ end function lpeg.utfchartabletopattern(list) -- goes to util-lpg local tree = { } - for i=1,#list do - local t = tree - for c in gmatch(list[i],".") do - if not t[c] then - t[c] = { } + local n = #list + if n == 0 then + for s in next, list do + local t = tree + local p, pk + for c in gmatch(s,".") do + if t == true then + t = { [c] = true, [""] = true } + p[pk] = t + p = t + t = false + elseif t == false then + t = { [c] = false } + p[pk] = t + p = t + t = false + else + local tc = t[c] + if not tc then + tc = false + t[c] = false + end + p = t + t = tc + end + pk = c + end + if t == false then + p[pk] = true + elseif t == true then + -- okay + else + t[""] = true + end + end + else + for i=1,n do + local s = list[i] + local t = tree + local p, pk + for c in gmatch(s,".") do + if t == true then + t = { [c] = true, [""] = true } + p[pk] = t + p = t + t = false + elseif t == false then + t = { [c] = false } + p[pk] = t + p = t + t = false + else + local tc = t[c] + if not tc then + tc = false + t[c] = false + end + p = t + t = tc + end + pk = c + end + if t == false then + p[pk] = true + elseif t == true then + -- okay + else + t[""] = true end - t = t[c] end end +-- inspect(tree) return make(tree) end --- inspect ( lpeg.utfchartabletopattern { +-- local t = { "a", "abc", "ac", "abe", "abxyz", "xy", "bef","aa" } +-- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/string.upper + 1)^1) + +-- inspect(lpegmatch(p,"a")) +-- inspect(lpegmatch(p,"aa")) +-- inspect(lpegmatch(p,"aaaa")) +-- inspect(lpegmatch(p,"ac")) +-- inspect(lpegmatch(p,"bc")) +-- inspect(lpegmatch(p,"zzbczz")) +-- inspect(lpegmatch(p,"zzabezz")) +-- inspect(lpegmatch(p,"ab")) +-- inspect(lpegmatch(p,"abc")) +-- inspect(lpegmatch(p,"abe")) +-- inspect(lpegmatch(p,"xa")) +-- inspect(lpegmatch(p,"bx")) +-- inspect(lpegmatch(p,"bax")) +-- inspect(lpegmatch(p,"abxyz")) +-- inspect(lpegmatch(p,"foobarbefcrap")) + +-- local t = { ["^"] = 1, ["^^"] = 2, ["^^^"] = 3, ["^^^^"] = 4 } +-- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/t + 1)^1) +-- inspect(lpegmatch(p," ^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^ ^^^^^^^ ")) + +-- local t = { ["^^"] = 2, ["^^^"] = 3, ["^^^^"] = 4 } +-- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/t + 1)^1) +-- inspect(lpegmatch(p," ^ ^^ ^^^ ^^^^ ^^^^^ ^^^^^^ ^^^^^^^ ")) + +-- lpeg.utfchartabletopattern { -- utfchar(0x00A0), -- nbsp -- utfchar(0x2000), -- enquad -- utfchar(0x2001), -- emquad @@ -866,7 +1002,7 @@ end -- utfchar(0x200B), -- zerowidthspace -- utfchar(0x202F), -- narrownobreakspace -- utfchar(0x205F), -- math thinspace --- } ) +-- } -- a few handy ones: -- @@ -935,3 +1071,75 @@ lpeg.patterns.stripzeros = stripper -- lpegmatch(stripper,str) -- print(#str, os.clock()-ts, lpegmatch(stripper,sample)) +-- for practical reasone we keep this here: + +local byte_to_HEX = { } +local byte_to_hex = { } +local byte_to_dec = { } -- for md5 +local hex_to_byte = { } + +for i=0,255 do + local H = format("%02X",i) + local h = format("%02x",i) + local d = format("%03i",i) + local c = char(i) + byte_to_HEX[c] = H + byte_to_hex[c] = h + byte_to_dec[c] = d + hex_to_byte[h] = c + hex_to_byte[H] = c +end + +local hextobyte = P(2)/hex_to_byte +local bytetoHEX = P(1)/byte_to_HEX +local bytetohex = P(1)/byte_to_hex +local bytetodec = P(1)/byte_to_dec +local hextobytes = Cs(hextobyte^0) +local bytestoHEX = Cs(bytetoHEX^0) +local bytestohex = Cs(bytetohex^0) +local bytestodec = Cs(bytetodec^0) + +patterns.hextobyte = hextobyte +patterns.bytetoHEX = bytetoHEX +patterns.bytetohex = bytetohex +patterns.bytetodec = bytetodec +patterns.hextobytes = hextobytes +patterns.bytestoHEX = bytestoHEX +patterns.bytestohex = bytestohex +patterns.bytestodec = bytestodec + +function string.toHEX(s) + if not s or s == "" then + return s + else + return lpegmatch(bytestoHEX,s) + end +end + +function string.tohex(s) + if not s or s == "" then + return s + else + return lpegmatch(bytestohex,s) + end +end + +function string.todec(s) + if not s or s == "" then + return s + else + return lpegmatch(bytestodec,s) + end +end + +function string.tobytes(s) + if not s or s == "" then + return s + else + return lpegmatch(hextobytes,s) + end +end + +-- local h = "ADFE0345" +-- local b = lpegmatch(patterns.hextobytes,h) +-- print(h,b,string.tohex(b),string.toHEX(b)) diff --git a/Master/texmf-dist/tex/context/base/l-lua.lua b/Master/texmf-dist/tex/context/base/l-lua.lua index 9565f484a2a..1a2a9872364 100644 --- a/Master/texmf-dist/tex/context/base/l-lua.lua +++ b/Master/texmf-dist/tex/context/base/l-lua.lua @@ -165,3 +165,14 @@ end if lua then lua.mask = load([[τεχ = 1]]) and "utf" or "ascii" end + +local flush = io.flush + +if flush then + + local execute = os.execute if execute then function os.execute(...) flush() return execute(...) end end + local exec = os.exec if exec then function os.exec (...) flush() return exec (...) end end + local spawn = os.spawn if spawn then function os.spawn (...) flush() return spawn (...) end end + local popen = io.popen if popen then function io.popen (...) flush() return popen (...) end end + +end diff --git a/Master/texmf-dist/tex/context/base/l-math.lua b/Master/texmf-dist/tex/context/base/l-math.lua index 43f60b56bee..ec62919b46a 100644 --- a/Master/texmf-dist/tex/context/base/l-math.lua +++ b/Master/texmf-dist/tex/context/base/l-math.lua @@ -8,6 +8,10 @@ if not modules then modules = { } end modules ['l-math'] = { local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan +if not math.ceiling then + math.ceiling = math.ceil +end + if not math.round then function math.round(x) return floor(x + 0.5) end end diff --git a/Master/texmf-dist/tex/context/base/l-md5.lua b/Master/texmf-dist/tex/context/base/l-md5.lua index 8ac20a5a5fb..00272c873f1 100644 --- a/Master/texmf-dist/tex/context/base/l-md5.lua +++ b/Master/texmf-dist/tex/context/base/l-md5.lua @@ -19,48 +19,38 @@ if not md5 then end local md5, file = md5, file -local gsub, format, byte = string.gsub, string.format, string.byte -local md5sum = md5.sum +local gsub = string.gsub -local function convert(str,fmt) - return (gsub(md5sum(str),".",function(chr) return format(fmt,byte(chr)) end)) -end - -if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end -if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end -if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end - --- local P, Cs, lpegmatch = lpeg.P, lpeg.Cs,lpeg.match --- --- if not md5.HEX then --- local function remap(chr) return format("%02X",byte(chr)) end --- function md5.HEX(str) return (gsub(md5.sum(str),".",remap)) end --- end +-- local gsub, format, byte = string.gsub, string.format, string.byte -- --- if not md5.hex then --- local function remap(chr) return format("%02x",byte(chr)) end --- function md5.hex(str) return (gsub(md5.sum(str),".",remap)) end +-- local function convert(str,fmt) +-- return (gsub(md5sum(str),".",function(chr) return format(fmt,byte(chr)) end)) -- end -- --- if not md5.dec then --- local function remap(chr) return format("%03i",byte(chr)) end --- function md5.dec(str) return (gsub(md5.sum(str),".",remap)) end --- end +-- if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end +-- if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end +-- if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end --- if not md5.HEX then --- local pattern_HEX = Cs( ( P(1) / function(chr) return format("%02X",byte(chr)) end)^0 ) --- function md5.HEX(str) return lpegmatch(pattern_HEX,md5.sum(str)) end --- end --- --- if not md5.hex then --- local pattern_hex = Cs( ( P(1) / function(chr) return format("%02x",byte(chr)) end)^0 ) --- function md5.hex(str) return lpegmatch(pattern_hex,md5.sum(str)) end --- end --- --- if not md5.dec then --- local pattern_dec = Cs( ( P(1) / function(chr) return format("%02i",byte(chr)) end)^0 ) --- function md5.dec(str) return lpegmatch(pattern_dec,md5.sum(str)) end --- end +do + + local patterns = lpeg and lpeg.patterns + + if patterns then + + local bytestoHEX = patterns.bytestoHEX + local bytestohex = patterns.bytestohex + local bytestodec = patterns.bytestodec + + local lpegmatch = lpeg.match + local md5sum = md5.sum + + if not md5.HEX then function md5.HEX(str) if str then return lpegmatch(bytestoHEX,md5sum(str)) end end end + if not md5.hex then function md5.hex(str) if str then return lpegmatch(bytestohex,md5sum(str)) end end end + if not md5.dec then function md5.dec(str) if str then return lpegmatch(bytestodec,md5sum(str)) end end end + + end + +end function file.needsupdating(oldname,newname,threshold) -- size modification access change local oldtime = lfs.attributes(oldname,"modification") diff --git a/Master/texmf-dist/tex/context/base/l-os.lua b/Master/texmf-dist/tex/context/base/l-os.lua index 1dff79cd3f3..f44b31662aa 100644 --- a/Master/texmf-dist/tex/context/base/l-os.lua +++ b/Master/texmf-dist/tex/context/base/l-os.lua @@ -25,8 +25,6 @@ if not modules then modules = { } end modules ['l-os'] = { -- os.sleep() => socket.sleep() -- math.randomseed(tonumber(string.sub(string.reverse(tostring(math.floor(socket.gettime()*10000))),1,6))) --- maybe build io.flush in os.execute - local os = os local date, time = os.date, os.time local find, format, gsub, upper, gmatch = string.find, string.format, string.gsub, string.upper, string.gmatch @@ -118,15 +116,11 @@ end -- end of environment hack -local execute, spawn, exec, iopopen, ioflush = os.execute, os.spawn or os.execute, os.exec or os.execute, io.popen, io.flush - -function os.execute(...) ioflush() return execute(...) end -function os.spawn (...) ioflush() return spawn (...) end -function os.exec (...) ioflush() return exec (...) end -function io.popen (...) ioflush() return iopopen(...) end +local execute = os.execute +local iopopen = io.popen function os.resultof(command) - local handle = io.popen(command,"r") + local handle = iopopen(command,"r") -- already has flush if handle then local result = handle:read("*all") or "" handle:close() @@ -160,7 +154,7 @@ local launchers = { } function os.launch(str) - os.execute(format(launchers[os.name] or launchers.unix,str)) + execute(format(launchers[os.name] or launchers.unix,str)) end if not os.times then -- ? diff --git a/Master/texmf-dist/tex/context/base/l-sandbox.lua b/Master/texmf-dist/tex/context/base/l-sandbox.lua new file mode 100644 index 00000000000..f7901379cd7 --- /dev/null +++ b/Master/texmf-dist/tex/context/base/l-sandbox.lua @@ -0,0 +1,271 @@ +if not modules then modules = { } end modules ['l-sandbox'] = { + version = 1.001, + comment = "companion to luat-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- We use string instead of function variables, so 'io.open' instead of io.open. That +-- way we can still intercept repetetive overloads. One complication is that when we use +-- sandboxed function sin helpers in the sanbox checkers, we can get a recursion loop +-- so for that vreason we need to keep originals around till we enable the sandbox. + +-- if sandbox then return end + +local global = _G +local next = next +local unpack = unpack or table.unpack +local type = type +local tprint = texio.write_nl or print +local tostring = tostring +local format = string.format -- no formatters yet +local concat = table.concat +local sort = table.sort +local gmatch = string.gmatch + +sandbox = { } +local sandboxed = false +local overloads = { } +local skiploads = { } +local initializers = { } +local finalizers = { } +local originals = { } +local comments = { } +local trace = false +local logger = false + +-- this comes real early, so that we can still alias + +local function report(...) + tprint("sandbox ! " .. format(...)) -- poor mans tracer +end + +sandbox.report = report + +function sandbox.setreporter(r) + report = r + sandbox.report = r +end + +function sandbox.settrace(v) + trace = v +end + +function sandbox.setlogger(l) + logger = type(l) == "function" and l or false +end + +local function register(func,overload,comment) + if type(func) == "function" then + if type(overload) == "string" then + comment = overload + overload = nil + end + local function f(...) + if sandboxed then + local overload = overloads[f] + if overload then + if logger then + local result = { overload(func,...) } + logger { + comment = comments[f] or tostring(f), + arguments = { ... }, + result = result[1] and true or false, + } + return unpack(result) + else + return overload(func,...) + end + else + -- ignored, maybe message + end + else + return func(...) + end + end + if comment then + comments[f] = comment + if trace then + report("registering function: %s",comment) + end + end + overloads[f] = overload or false + originals[f] = func + return f + end +end + +local function redefine(func,comment) + if type(func) == "function" then + skiploads[func] = comment or comments[func] or "unknown" + if overloads[func] == false then + overloads[func] = nil -- not initialized anyway + end + end +end + +sandbox.register = register +sandbox.redefine = redefine + +function sandbox.original(func) + return originals and originals[func] or func +end + +function sandbox.overload(func,overload,comment) + comment = comment or comments[func] or "?" + if type(func) ~= "function" then + if trace then + report("overloading unknown function: %s",comment) + end + elseif type(overload) ~= "function" then + if trace then + report("overloading function with bad overload: %s",comment) + end + elseif overloads[func] == nil then + if trace then + report("function is not registered: %s",comment) + end + elseif skiploads[func] then + if trace then + report("function is not skipped: %s",comment) + end + else + if trace then + report("overloading function: %s",comment) + end + overloads[func] = overload + end + return func +end + +function sandbox.initializer(f) + if not sandboxed then + initializers[#initializers+1] = f + elseif trace then + report("already enabled, discarding initializer") + end +end + +function sandbox.finalizer(f) + if not sandboxed then + finalizers[#finalizers+1] = f + elseif trace then + report("already enabled, discarding finalizer") + end +end + +function sandbox.enable() + if not sandboxed then + for i=1,#initializers do + initializers[i]() + end + for i=1,#finalizers do + finalizers[i]() + end + local nnot = 0 + local nyes = 0 + local cnot = { } + local cyes = { } + local skip = { } + for k, v in next, overloads do + local c = comments[k] + if v then + if c then + cyes[#cyes+1] = c + else -- if not skiploads[k] then + nyes = nyes + 1 + end + else + if c then + cnot[#cnot+1] = c + else -- if not skiploads[k] then + nnot = nnot + 1 + end + end + end + for k, v in next, skiploads do + skip[#skip+1] = v + end + if #cyes > 0 then + sort(cyes) + report(" overloaded known : %s",concat(cyes," | ")) + end + if nyes > 0 then + report(" overloaded unknown : %s",nyes) + end + if #cnot > 0 then + sort(cnot) + report("not overloaded known : %s",concat(cnot," | ")) + end + if nnot > 0 then + report("not overloaded unknown : %s",nnot) + end + if #skip > 0 then + sort(skip) + report("not overloaded redefined : %s",concat(skip," | ")) + end + initializers = nil + finalizers = nil + originals = nil + sandboxed = true + end +end + +-- we sandbox some of the built-in functions now: + +-- todo: require +-- todo: load + +local function supported(library) + local l = _G[library] + -- if l then + -- for k, v in next, l do + -- report("%s.%s",library,k) + -- end + -- end + return l +end + +-- io.tmpfile : we don't know where that one ends up but probably is user temp space +-- os.tmpname : no need to deal with this: outputs rubish anyway (\s9v0. \s9v0.1 \s9v0.2 etc) +-- os.tmpdir : not needed either (luatex.vob000 luatex.vob000 etc) + +-- os.setenv : maybe +-- require : maybe (normally taken from tree) +-- http etc : maybe (all schemes that go outside) + +loadfile = register(loadfile,"loadfile") + +if supported("io") then + io.open = register(io.open, "io.open") + io.popen = register(io.popen, "io.popen") -- needs checking + io.lines = register(io.lines, "io.lines") + io.output = register(io.output, "io.output") + io.input = register(io.input, "io.input") +end + +if supported("os") then + os.execute = register(os.execute, "os.execute") + os.spawn = register(os.spawn, "os.spawn") + os.exec = register(os.exec, "os.exec") + os.rename = register(os.rename, "os.rename") + os.remove = register(os.remove, "os.remove") +end + +if supported("lfs") then + lfs.chdir = register(lfs.chdir, "lfs.chdir") + lfs.mkdir = register(lfs.mkdir, "lfs.mkdir") + lfs.rmdir = register(lfs.rmdir, "lfs.rmdir") + lfs.isfile = register(lfs.isfile, "lfs.isfile") + lfs.isdir = register(lfs.isdir, "lfs.isdir") + lfs.attributes = register(lfs.attributes, "lfs.attributes") + lfs.dir = register(lfs.dir, "lfs.dir") + lfs.lock_dir = register(lfs.lock_dir, "lfs.lock_dir") + lfs.touch = register(lfs.touch, "lfs.touch") + lfs.link = register(lfs.link, "lfs.link") + lfs.setmode = register(lfs.setmode, "lfs.setmode") + lfs.readlink = register(lfs.readlink, "lfs.readlink") + lfs.shortname = register(lfs.shortname, "lfs.shortname") + lfs.symlinkattributes = register(lfs.symlinkattributes,"lfs.symlinkattributes") +end diff --git a/Master/texmf-dist/tex/context/base/l-string.lua b/Master/texmf-dist/tex/context/base/l-string.lua index 3b1a0003ff9..70c66f66169 100644 --- a/Master/texmf-dist/tex/context/base/l-string.lua +++ b/Master/texmf-dist/tex/context/base/l-string.lua @@ -94,7 +94,7 @@ end -- return not find(str,"%S") -- end -local pattern = P(" ")^0 * P(-1) +local pattern = P(" ")^0 * P(-1) -- maybe also newlines -- patterns.onlyspaces = pattern diff --git a/Master/texmf-dist/tex/context/base/l-table.lua b/Master/texmf-dist/tex/context/base/l-table.lua index d231830eddc..97e0441eb09 100644 --- a/Master/texmf-dist/tex/context/base/l-table.lua +++ b/Master/texmf-dist/tex/context/base/l-table.lua @@ -49,12 +49,22 @@ function table.keys(t) end end +-- local function compare(a,b) +-- local ta, tb = type(a), type(b) -- needed, else 11 < 2 +-- if ta == tb then +-- return a < b +-- else +-- return tostring(a) < tostring(b) -- not that efficient +-- end +-- end + local function compare(a,b) - local ta, tb = type(a), type(b) -- needed, else 11 < 2 - if ta == tb then + local ta = type(a) -- needed, else 11 < 2 + local tb = type(b) -- needed, else 11 < 2 + if ta == tb and ta == "number" then return a < b else - return tostring(a) < tostring(b) + return tostring(a) < tostring(b) -- not that efficient end end @@ -164,14 +174,14 @@ local function sortedhash(t,cmp) end local n = 0 local m = #s - local function kv(s) + local function kv() -- (s) if n < m then n = n + 1 local k = s[n] return k, t[k] end end - return kv, s + return kv -- , s else return nothing end @@ -400,7 +410,7 @@ local function simple_table(t) if tv == "number" then nt = nt + 1 if hexify then - tt[nt] = format("0x%04X",v) + tt[nt] = format("0x%X",v) else tt[nt] = tostring(v) -- tostring not needed end @@ -451,7 +461,7 @@ local function do_serialize(root,name,depth,level,indexed) local tn = type(name) if tn == "number" then if hexify then - handle(format("%s[0x%04X]={",depth,name)) + handle(format("%s[0x%X]={",depth,name)) else handle(format("%s[%s]={",depth,name)) end @@ -469,7 +479,7 @@ local function do_serialize(root,name,depth,level,indexed) end end -- we could check for k (index) being number (cardinal) - if root and next(root) then + if root and next(root) ~= nil then -- local first, last = nil, 0 -- #root cannot be trusted here (will be ok in 5.2 when ipairs is gone) -- if compact then -- -- NOT: for k=1,#root do (we need to quit at nil) @@ -502,7 +512,7 @@ local function do_serialize(root,name,depth,level,indexed) if compact and first and tk == "number" and k >= first and k <= last then if tv == "number" then if hexify then - handle(format("%s 0x%04X,",depth,v)) + handle(format("%s 0x%X,",depth,v)) else handle(format("%s %s,",depth,v)) -- %.99g end @@ -513,7 +523,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s %q,",depth,v)) end elseif tv == "table" then - if not next(v) then + if next(v) == nil then handle(format("%s {},",depth)) elseif inline then -- and #t > 0 local st = simple_table(v) @@ -543,25 +553,25 @@ local function do_serialize(root,name,depth,level,indexed) elseif tv == "number" then if tk == "number" then if hexify then - handle(format("%s [0x%04X]=0x%04X,",depth,k,v)) + handle(format("%s [0x%X]=0x%X,",depth,k,v)) else handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g end elseif tk == "boolean" then if hexify then - handle(format("%s [%s]=0x%04X,",depth,k and "true" or "false",v)) + handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v)) else handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) -- %.99g end elseif noquotes and not reserved[k] and lpegmatch(propername,k) then if hexify then - handle(format("%s %s=0x%04X,",depth,k,v)) + handle(format("%s %s=0x%X,",depth,k,v)) else handle(format("%s %s=%s,",depth,k,v)) -- %.99g end else if hexify then - handle(format("%s [%q]=0x%04X,",depth,k,v)) + handle(format("%s [%q]=0x%X,",depth,k,v)) else handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g end @@ -570,7 +580,7 @@ local function do_serialize(root,name,depth,level,indexed) if reduce and tonumber(v) then if tk == "number" then if hexify then - handle(format("%s [0x%04X]=%s,",depth,k,v)) + handle(format("%s [0x%X]=%s,",depth,k,v)) else handle(format("%s [%s]=%s,",depth,k,v)) end @@ -584,7 +594,7 @@ local function do_serialize(root,name,depth,level,indexed) else if tk == "number" then if hexify then - handle(format("%s [0x%04X]=%q,",depth,k,v)) + handle(format("%s [0x%X]=%q,",depth,k,v)) else handle(format("%s [%s]=%q,",depth,k,v)) end @@ -597,10 +607,10 @@ local function do_serialize(root,name,depth,level,indexed) end end elseif tv == "table" then - if not next(v) then + if next(v) == nil then if tk == "number" then if hexify then - handle(format("%s [0x%04X]={},",depth,k)) + handle(format("%s [0x%X]={},",depth,k)) else handle(format("%s [%s]={},",depth,k)) end @@ -616,7 +626,7 @@ local function do_serialize(root,name,depth,level,indexed) if st then if tk == "number" then if hexify then - handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", "))) + handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", "))) else handle(format("%s [%s]={ %s },",depth,k,concat(st,", "))) end @@ -636,7 +646,7 @@ local function do_serialize(root,name,depth,level,indexed) elseif tv == "boolean" then if tk == "number" then if hexify then - handle(format("%s [0x%04X]=%s,",depth,k,v and "true" or "false")) + handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false")) else handle(format("%s [%s]=%s,",depth,k,v and "true" or "false")) end @@ -653,7 +663,7 @@ local function do_serialize(root,name,depth,level,indexed) -- local f = getinfo(v).what == "C" and dump(function(...) return v(...) end) or dump(v) -- maybe strip if tk == "number" then if hexify then - handle(format("%s [0x%04X]=load(%q),",depth,k,f)) + handle(format("%s [0x%X]=load(%q),",depth,k,f)) else handle(format("%s [%s]=load(%q),",depth,k,f)) end @@ -668,7 +678,7 @@ local function do_serialize(root,name,depth,level,indexed) else if tk == "number" then if hexify then - handle(format("%s [0x%04X]=%q,",depth,k,tostring(v))) + handle(format("%s [0x%X]=%q,",depth,k,tostring(v))) else handle(format("%s [%s]=%q,",depth,k,tostring(v))) end @@ -683,7 +693,7 @@ local function do_serialize(root,name,depth,level,indexed) --~ end end end - if level > 0 then + if level > 0 then handle(format("%s},",depth)) end end @@ -727,7 +737,7 @@ local function serialize(_handle,root,name,specification) -- handle wins end elseif tname == "number" then if hexify then - handle(format("[0x%04X]={",name)) + handle(format("[0x%X]={",name)) else handle("[" .. name .. "]={") end @@ -748,7 +758,7 @@ local function serialize(_handle,root,name,specification) -- handle wins root._w_h_a_t_e_v_e_r_ = nil end -- Let's forget about empty tables. - if next(root) then + if next(root) ~= nil then do_serialize(root,name,"",0) end end @@ -922,16 +932,27 @@ end table.identical = identical table.are_equal = are_equal --- maybe also make a combined one - -function table.compact(t) -- remove empty tables, assumes subtables - if t then - for k, v in next, t do - if not next(v) then -- no type checking - t[k] = nil +local function sparse(old,nest,keeptables) + local new = { } + for k, v in next, old do + if not (v == "" or v == false) then + if nest and type(v) == "table" then + v = sparse(v,nest) + if keeptables or next(v) ~= nil then + new[k] = v + end + else + new[k] = v end end end + return new +end + +table.sparse = sparse + +function table.compact(t) + return sparse(t,true,true) end function table.contains(t, v) @@ -1055,11 +1076,11 @@ end -- slower than #t on indexed tables (#t only returns the size of the numerically indexed slice) function table.is_empty(t) - return not t or not next(t) + return not t or next(t) == nil end function table.has_one_entry(t) - return t and not next(t,next(t)) + return t and next(t,next(t)) == nil end -- new @@ -1114,3 +1135,49 @@ function table.values(t,s) -- optional sort flag return { } end end + +-- maybe this will move to util-tab.lua + +-- for k, v in table.filtered(t,pattern) do ... end +-- for k, v in table.filtered(t,pattern,true) do ... end +-- for k, v in table.filtered(t,pattern,true,cmp) do ... end + +function table.filtered(t,pattern,sort,cmp) + if t and type(pattern) == "string" then + if sort then + local s + if cmp then + -- it would be nice if the sort function would accept a third argument (or nicer, an optional first) + s = sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s = sortedkeys(t) -- the robust one + end + local n = 0 + local m = #s + local function kv(s) + while n < m do + n = n + 1 + local k = s[n] + if find(k,pattern) then + return k, t[k] + end + end + end + return kv, s + else + local n = next(t) + local function iterator() + while n ~= nil do + local k = n + n = next(t,k) + if find(k,pattern) then + return k, t[k] + end + end + end + return iterator, t + end + else + return nothing + end +end diff --git a/Master/texmf-dist/tex/context/base/l-unicode.lua b/Master/texmf-dist/tex/context/base/l-unicode.lua index be61f3d73cb..02dd1a00304 100644 --- a/Master/texmf-dist/tex/context/base/l-unicode.lua +++ b/Master/texmf-dist/tex/context/base/l-unicode.lua @@ -34,20 +34,23 @@ local type = type local char, byte, format, sub, gmatch = string.char, string.byte, string.format, string.sub, string.gmatch local concat = table.concat local P, C, R, Cs, Ct, Cmt, Cc, Carg, Cp = lpeg.P, lpeg.C, lpeg.R, lpeg.Cs, lpeg.Ct, lpeg.Cmt, lpeg.Cc, lpeg.Carg, lpeg.Cp -local lpegmatch, patterns = lpeg.match, lpeg.patterns -local bytepairs = string.bytepairs +local lpegmatch = lpeg.match +local patterns = lpeg.patterns +local tabletopattern = lpeg.utfchartabletopattern -local finder = lpeg.finder -local replacer = lpeg.replacer +local bytepairs = string.bytepairs -local utfvalues = utf.values -local utfgmatch = utf.gmatch -- not always present +local finder = lpeg.finder +local replacer = lpeg.replacer + +local utfvalues = utf.values +local utfgmatch = utf.gmatch -- not always present local p_utftype = patterns.utftype local p_utfstricttype = patterns.utfstricttype local p_utfoffset = patterns.utfoffset -local p_utf8char = patterns.utf8char +local p_utf8char = patterns.utf8character local p_utf8byte = patterns.utf8byte local p_utfbom = patterns.utfbom local p_newline = patterns.newline @@ -510,22 +513,70 @@ end -- a replacement for simple gsubs: -function utf.remapper(mapping) - local pattern = Cs((p_utf8char/mapping)^0) - return function(str) - if not str or str == "" then - return "" +-- function utf.remapper(mapping) +-- local pattern = Cs((p_utf8char/mapping)^0) +-- return function(str) +-- if not str or str == "" then +-- return "" +-- else +-- return lpegmatch(pattern,str) +-- end +-- end, pattern +-- end + +function utf.remapper(mapping,option) -- static also returns a pattern + local variant = type(mapping) + if variant == "table" then + if option == "dynamic" then + local pattern = false + table.setmetatablenewindex(mapping,function(t,k,v) rawset(t,k,v) pattern = false end) + return function(str) + if not str or str == "" then + return "" + else + if not pattern then + pattern = Cs((tabletopattern(mapping)/mapping + p_utf8char)^0) + end + return lpegmatch(pattern,str) + end + end + elseif option == "pattern" then + return Cs((tabletopattern(mapping)/mapping + p_utf8char)^0) + -- elseif option == "static" then else - return lpegmatch(pattern,str) + local pattern = Cs((tabletopattern(mapping)/mapping + p_utf8char)^0) + return function(str) + if not str or str == "" then + return "" + else + return lpegmatch(pattern,str) + end + end, pattern + end + elseif variant == "function" then + if option == "pattern" then + return Cs((p_utf8char/mapping + p_utf8char)^0) + else + local pattern = Cs((p_utf8char/mapping + p_utf8char)^0) + return function(str) + if not str or str == "" then + return "" + else + return lpegmatch(pattern,str) + end + end, pattern + end + else + -- is actually an error + return function(str) + return str or "" end - end, pattern + end end -- local remap = utf.remapper { a = 'd', b = "c", c = "b", d = "a" } -- print(remap("abcd 1234 abcd")) --- - function utf.replacer(t) -- no precheck, always string builder local r = replacer(t,false,false,true) return function(str) @@ -631,285 +682,359 @@ end local utf16_to_utf8_be, utf16_to_utf8_le local utf32_to_utf8_be, utf32_to_utf8_le -local utf_16_be_linesplitter = patterns.utfbom_16_be^-1 * lpeg.tsplitat(patterns.utf_16_be_nl) -local utf_16_le_linesplitter = patterns.utfbom_16_le^-1 * lpeg.tsplitat(patterns.utf_16_le_nl) +local utf_16_be_getbom = patterns.utfbom_16_be^-1 +local utf_16_le_getbom = patterns.utfbom_16_le^-1 +local utf_32_be_getbom = patterns.utfbom_32_be^-1 +local utf_32_le_getbom = patterns.utfbom_32_le^-1 + +local utf_16_be_linesplitter = utf_16_be_getbom * lpeg.tsplitat(patterns.utf_16_be_nl) +local utf_16_le_linesplitter = utf_16_le_getbom * lpeg.tsplitat(patterns.utf_16_le_nl) +local utf_32_be_linesplitter = utf_32_be_getbom * lpeg.tsplitat(patterns.utf_32_be_nl) +local utf_32_le_linesplitter = utf_32_le_getbom * lpeg.tsplitat(patterns.utf_32_le_nl) + +-- we have three possibilities: bytepairs (using tables), gmatch (using tables), gsub and +-- lpeg. Bytepairs are the fastert but as soon as we need to remove bombs and so the gain +-- is less due to more testing. Also, we seldom have to convert utf16 so we don't care to +-- much about a few milliseconds more runtime. The lpeg variant is upto 20% slower but +-- still pretty fast. +-- +-- for historic resone we keep the bytepairs variants around .. beware they don't grab the +-- bom like the lpegs do so they're not dropins in the functions that follow +-- +-- utf16_to_utf8_be = function(s) +-- if not s then +-- return nil +-- elseif s == "" then +-- return "" +-- end +-- local result, r, more = { }, 0, 0 +-- for left, right in bytepairs(s) do +-- if right then +-- local now = 256*left + right +-- if more > 0 then +-- now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong +-- more = 0 +-- r = r + 1 +-- result[r] = utfchar(now) +-- elseif now >= 0xD800 and now <= 0xDBFF then +-- more = now +-- else +-- r = r + 1 +-- result[r] = utfchar(now) +-- end +-- end +-- end +-- return concat(result) +-- end +-- +-- local utf16_to_utf8_be_t = function(t) +-- if not t then +-- return nil +-- elseif type(t) == "string" then +-- t = lpegmatch(utf_16_be_linesplitter,t) +-- end +-- local result = { } -- we reuse result +-- for i=1,#t do +-- local s = t[i] +-- if s ~= "" then +-- local r, more = 0, 0 +-- for left, right in bytepairs(s) do +-- if right then +-- local now = 256*left + right +-- if more > 0 then +-- now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong +-- more = 0 +-- r = r + 1 +-- result[r] = utfchar(now) +-- elseif now >= 0xD800 and now <= 0xDBFF then +-- more = now +-- else +-- r = r + 1 +-- result[r] = utfchar(now) +-- end +-- end +-- end +-- t[i] = concat(result,"",1,r) -- we reused tmp, hence t +-- end +-- end +-- return t +-- end +-- +-- utf16_to_utf8_le = function(s) +-- if not s then +-- return nil +-- elseif s == "" then +-- return "" +-- end +-- local result, r, more = { }, 0, 0 +-- for left, right in bytepairs(s) do +-- if right then +-- local now = 256*right + left +-- if more > 0 then +-- now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong +-- more = 0 +-- r = r + 1 +-- result[r] = utfchar(now) +-- elseif now >= 0xD800 and now <= 0xDBFF then +-- more = now +-- else +-- r = r + 1 +-- result[r] = utfchar(now) +-- end +-- end +-- end +-- return concat(result) +-- end +-- +-- local utf16_to_utf8_le_t = function(t) +-- if not t then +-- return nil +-- elseif type(t) == "string" then +-- t = lpegmatch(utf_16_le_linesplitter,t) +-- end +-- local result = { } -- we reuse result +-- for i=1,#t do +-- local s = t[i] +-- if s ~= "" then +-- local r, more = 0, 0 +-- for left, right in bytepairs(s) do +-- if right then +-- local now = 256*right + left +-- if more > 0 then +-- now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong +-- more = 0 +-- r = r + 1 +-- result[r] = utfchar(now) +-- elseif now >= 0xD800 and now <= 0xDBFF then +-- more = now +-- else +-- r = r + 1 +-- result[r] = utfchar(now) +-- end +-- end +-- end +-- t[i] = concat(result,"",1,r) -- we reused tmp, hence t +-- end +-- end +-- return t +-- end +-- +-- local utf32_to_utf8_be_t = function(t) +-- if not t then +-- return nil +-- elseif type(t) == "string" then +-- t = lpegmatch(utflinesplitter,t) +-- end +-- local result = { } -- we reuse result +-- for i=1,#t do +-- local r, more = 0, -1 +-- for a,b in bytepairs(t[i]) do +-- if a and b then +-- if more < 0 then +-- more = 256*256*256*a + 256*256*b +-- else +-- r = r + 1 +-- result[t] = utfchar(more + 256*a + b) +-- more = -1 +-- end +-- else +-- break +-- end +-- end +-- t[i] = concat(result,"",1,r) +-- end +-- return t +-- end +-- +-- local utf32_to_utf8_le_t = function(t) +-- if not t then +-- return nil +-- elseif type(t) == "string" then +-- t = lpegmatch(utflinesplitter,t) +-- end +-- local result = { } -- we reuse result +-- for i=1,#t do +-- local r, more = 0, -1 +-- for a,b in bytepairs(t[i]) do +-- if a and b then +-- if more < 0 then +-- more = 256*b + a +-- else +-- r = r + 1 +-- result[t] = utfchar(more + 256*256*256*b + 256*256*a) +-- more = -1 +-- end +-- else +-- break +-- end +-- end +-- t[i] = concat(result,"",1,r) +-- end +-- return t +-- end --- we have three possibilities: +local more = 0 + +local p_utf16_to_utf8_be = C(1) * C(1) /function(left,right) + local now = 256*byte(left) + byte(right) + if more > 0 then + now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong + more = 0 + return utfchar(now) + elseif now >= 0xD800 and now <= 0xDBFF then + more = now + return "" -- else the c's end up in the stream + else + return utfchar(now) + end +end --- bytepairs: 0.048 --- gmatch : 0.069 --- lpeg : 0.089 (match time captures) +local p_utf16_to_utf8_le = C(1) * C(1) /function(right,left) + local now = 256*byte(left) + byte(right) + if more > 0 then + now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong + more = 0 + return utfchar(now) + elseif now >= 0xD800 and now <= 0xDBFF then + more = now + return "" -- else the c's end up in the stream + else + return utfchar(now) + end +end +local p_utf32_to_utf8_be = C(1) * C(1) * C(1) * C(1) /function(a,b,c,d) + return utfchar(256*256*256*byte(a) + 256*256*byte(b) + 256*byte(c) + byte(d)) +end -if bytepairs then +local p_utf32_to_utf8_le = C(1) * C(1) * C(1) * C(1) /function(a,b,c,d) + return utfchar(256*256*256*byte(d) + 256*256*byte(c) + 256*byte(b) + byte(a)) +end - -- with a little bit more code we could include the linesplitter +p_utf16_to_utf8_be = P(true) / function() more = 0 end * utf_16_be_getbom * Cs(p_utf16_to_utf8_be^0) +p_utf16_to_utf8_le = P(true) / function() more = 0 end * utf_16_le_getbom * Cs(p_utf16_to_utf8_le^0) +p_utf32_to_utf8_be = P(true) / function() more = 0 end * utf_32_be_getbom * Cs(p_utf32_to_utf8_be^0) +p_utf32_to_utf8_le = P(true) / function() more = 0 end * utf_32_le_getbom * Cs(p_utf32_to_utf8_le^0) - utf16_to_utf8_be = function(t) - if type(t) == "string" then - t = lpegmatch(utf_16_be_linesplitter,t) - end - local result = { } -- we reuse result - for i=1,#t do - local r, more = 0, 0 - for left, right in bytepairs(t[i]) do - if right then - local now = 256*left + right - if more > 0 then - now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong - more = 0 - r = r + 1 - result[r] = utfchar(now) - elseif now >= 0xD800 and now <= 0xDBFF then - more = now - else - r = r + 1 - result[r] = utfchar(now) - end - end - end - t[i] = concat(result,"",1,r) -- we reused tmp, hence t - end - return t +patterns.utf16_to_utf8_be = p_utf16_to_utf8_be +patterns.utf16_to_utf8_le = p_utf16_to_utf8_le +patterns.utf32_to_utf8_be = p_utf32_to_utf8_be +patterns.utf32_to_utf8_le = p_utf32_to_utf8_le + +utf16_to_utf8_be = function(s) + if s and s ~= "" then + return lpegmatch(p_utf16_to_utf8_be,s) + else + return s end +end - utf16_to_utf8_le = function(t) - if type(t) == "string" then - t = lpegmatch(utf_16_le_linesplitter,t) - end - local result = { } -- we reuse result - for i=1,#t do - local r, more = 0, 0 - for left, right in bytepairs(t[i]) do - if right then - local now = 256*right + left - if more > 0 then - now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong - more = 0 - r = r + 1 - result[r] = utfchar(now) - elseif now >= 0xD800 and now <= 0xDBFF then - more = now - else - r = r + 1 - result[r] = utfchar(now) - end - end - end - t[i] = concat(result,"",1,r) -- we reused tmp, hence t +local utf16_to_utf8_be_t = function(t) + if not t then + return nil + elseif type(t) == "string" then + t = lpegmatch(utf_16_be_linesplitter,t) + end + for i=1,#t do + local s = t[i] + if s ~= "" then + t[i] = lpegmatch(p_utf16_to_utf8_be,s) end - return t end + return t +end - utf32_to_utf8_be = function(t) - if type(t) == "string" then - t = lpegmatch(utflinesplitter,t) - end - local result = { } -- we reuse result - for i=1,#t do - local r, more = 0, -1 - for a,b in bytepairs(t[i]) do - if a and b then - if more < 0 then - more = 256*256*256*a + 256*256*b - else - r = r + 1 - result[t] = utfchar(more + 256*a + b) - more = -1 - end - else - break - end - end - t[i] = concat(result,"",1,r) - end - return t +utf16_to_utf8_le = function(s) + if s and s ~= "" then + return lpegmatch(p_utf16_to_utf8_le,s) + else + return s end +end - utf32_to_utf8_le = function(t) - if type(t) == "string" then - t = lpegmatch(utflinesplitter,t) - end - local result = { } -- we reuse result - for i=1,#t do - local r, more = 0, -1 - for a,b in bytepairs(t[i]) do - if a and b then - if more < 0 then - more = 256*b + a - else - r = r + 1 - result[t] = utfchar(more + 256*256*256*b + 256*256*a) - more = -1 - end - else - break - end - end - t[i] = concat(result,"",1,r) +local utf16_to_utf8_le_t = function(t) + if not t then + return nil + elseif type(t) == "string" then + t = lpegmatch(utf_16_le_linesplitter,t) + end + for i=1,#t do + local s = t[i] + if s ~= "" then + t[i] = lpegmatch(p_utf16_to_utf8_le,s) end - return t end + return t +end -else - - utf16_to_utf8_be = function(t) - if type(t) == "string" then - t = lpegmatch(utf_16_be_linesplitter,t) - end - local result = { } -- we reuse result - for i=1,#t do - local r, more = 0, 0 - for left, right in gmatch(t[i],"(.)(.)") do - if left == "\000" then -- experiment - r = r + 1 - result[r] = utfchar(byte(right)) - elseif right then - local now = 256*byte(left) + byte(right) - if more > 0 then - now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong - more = 0 - r = r + 1 - result[r] = utfchar(now) - elseif now >= 0xD800 and now <= 0xDBFF then - more = now - else - r = r + 1 - result[r] = utfchar(now) - end - end - end - t[i] = concat(result,"",1,r) -- we reused tmp, hence t - end - return t +utf32_to_utf8_be = function(s) + if s and s ~= "" then + return lpegmatch(p_utf32_to_utf8_be,s) + else + return s end +end - utf16_to_utf8_le = function(t) - if type(t) == "string" then - t = lpegmatch(utf_16_le_linesplitter,t) - end - local result = { } -- we reuse result - for i=1,#t do - local r, more = 0, 0 - for left, right in gmatch(t[i],"(.)(.)") do - if right == "\000" then - r = r + 1 - result[r] = utfchar(byte(left)) - elseif right then - local now = 256*byte(right) + byte(left) - if more > 0 then - now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong - more = 0 - r = r + 1 - result[r] = utfchar(now) - elseif now >= 0xD800 and now <= 0xDBFF then - more = now - else - r = r + 1 - result[r] = utfchar(now) - end - end - end - t[i] = concat(result,"",1,r) -- we reused tmp, hence t +local utf32_to_utf8_be_t = function(t) + if not t then + return nil + elseif type(t) == "string" then + t = lpegmatch(utf_32_be_linesplitter,t) + end + for i=1,#t do + local s = t[i] + if s ~= "" then + t[i] = lpegmatch(p_utf32_to_utf8_be,s) end - return t end + return t +end - utf32_to_utf8_le = function() return { } end -- never used anyway - utf32_to_utf8_be = function() return { } end -- never used anyway - - -- the next one is slighty slower - - -- local result, lines, r, more = { }, { }, 0, 0 - -- - -- local simple = Cmt( - -- C(1) * C(1), function(str,p,left,right) - -- local now = 256*byte(left) + byte(right) - -- if more > 0 then - -- now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong - -- more = 0 - -- r = r + 1 - -- result[r] = utfchar(now) - -- elseif now >= 0xD800 and now <= 0xDBFF then - -- more = now - -- else - -- r = r + 1 - -- result[r] = utfchar(now) - -- end - -- return p - -- end - -- ) - -- - -- local complex = Cmt( - -- C(1) * C(1), function(str,p,left,right) - -- local now = 256*byte(left) + byte(right) - -- if more > 0 then - -- now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong - -- more = 0 - -- r = r + 1 - -- result[r] = utfchar(now) - -- elseif now >= 0xD800 and now <= 0xDBFF then - -- more = now - -- else - -- r = r + 1 - -- result[r] = utfchar(now) - -- end - -- return p - -- end - -- ) - -- - -- local lineend = Cmt ( - -- patterns.utf_16_be_nl, function(str,p) - -- lines[#lines+1] = concat(result,"",1,r) - -- r, more = 0, 0 - -- return p - -- end - -- ) - -- - -- local be_1 = patterns.utfbom_16_be^-1 * (simple + complex)^0 - -- local be_2 = patterns.utfbom_16_be^-1 * (lineend + simple + complex)^0 - -- - -- utf16_to_utf8_be = function(t) - -- if type(t) == "string" then - -- local s = t - -- lines, r, more = { }, 0, 0 - -- lpegmatch(be_2,s) - -- if r > 0 then - -- lines[#lines+1] = concat(result,"",1,r) - -- end - -- result = { } - -- return lines - -- else - -- for i=1,#t do - -- r, more = 0, 0 - -- lpegmatch(be_1,t[i]) - -- t[i] = concat(result,"",1,r) - -- end - -- result = { } - -- return t - -- end - -- end +utf32_to_utf8_le = function(s) + if s and s ~= "" then + return lpegmatch(p_utf32_to_utf8_le,s) + else + return s + end +end +local utf32_to_utf8_le_t = function(t) + if not t then + return nil + elseif type(t) == "string" then + t = lpegmatch(utf_32_le_linesplitter,t) + end + for i=1,#t do + local s = t[i] + if s ~= "" then + t[i] = lpegmatch(p_utf32_to_utf8_le,s) + end + end + return t end -utf.utf16_to_utf8_le = utf16_to_utf8_le -utf.utf16_to_utf8_be = utf16_to_utf8_be -utf.utf32_to_utf8_le = utf32_to_utf8_le -utf.utf32_to_utf8_be = utf32_to_utf8_be +utf.utf16_to_utf8_le_t = utf16_to_utf8_le_t +utf.utf16_to_utf8_be_t = utf16_to_utf8_be_t +utf.utf32_to_utf8_le_t = utf32_to_utf8_le_t +utf.utf32_to_utf8_be_t = utf32_to_utf8_be_t -function utf.utf8_to_utf8(t) +utf.utf16_to_utf8_le = utf16_to_utf8_le +utf.utf16_to_utf8_be = utf16_to_utf8_be +utf.utf32_to_utf8_le = utf32_to_utf8_le +utf.utf32_to_utf8_be = utf32_to_utf8_be + +function utf.utf8_to_utf8_t(t) return type(t) == "string" and lpegmatch(utflinesplitter,t) or t end -function utf.utf16_to_utf8(t,endian) - return endian and utf16_to_utf8_be(t) or utf16_to_utf8_le(t) or t +function utf.utf16_to_utf8_t(t,endian) + return endian and utf16_to_utf8_be_t(t) or utf16_to_utf8_le_t(t) or t end -function utf.utf32_to_utf8(t,endian) - return endian and utf32_to_utf8_be(t) or utf32_to_utf8_le(t) or t +function utf.utf32_to_utf8_t(t,endian) + return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t end -local function little(c) - local b = byte(c) +local function little(b) if b < 0x10000 then return char(b%256,b/256) else @@ -919,8 +1044,7 @@ local function little(c) end end -local function big(c) - local b = byte(c) +local function big(b) if b < 0x10000 then return char(b/256,b%256) else @@ -930,18 +1054,10 @@ local function big(c) end end --- function utf.utf8_to_utf16(str,littleendian) --- if littleendian then --- return char(255,254) .. utfgsub(str,".",little) --- else --- return char(254,255) .. utfgsub(str,".",big) --- end --- end - -local _, l_remap = utf.remapper(little) -local _, b_remap = utf.remapper(big) +local l_remap = Cs((p_utf8byte/little+P(1)/"")^0) +local b_remap = Cs((p_utf8byte/big +P(1)/"")^0) -function utf.utf8_to_utf16_be(str,nobom) +local function utf8_to_utf16_be(str,nobom) if nobom then return lpegmatch(b_remap,str) else @@ -949,7 +1065,7 @@ function utf.utf8_to_utf16_be(str,nobom) end end -function utf.utf8_to_utf16_le(str,nobom) +local function utf8_to_utf16_le(str,nobom) if nobom then return lpegmatch(l_remap,str) else @@ -957,11 +1073,14 @@ function utf.utf8_to_utf16_le(str,nobom) end end +utf.utf8_to_utf16_be = utf8_to_utf16_be +utf.utf8_to_utf16_le = utf8_to_utf16_le + function utf.utf8_to_utf16(str,littleendian,nobom) if littleendian then - return utf.utf8_to_utf16_le(str,nobom) + return utf8_to_utf16_le(str,nobom) else - return utf.utf8_to_utf16_be(str,nobom) + return utf8_to_utf16_be(str,nobom) end end @@ -992,16 +1111,16 @@ function utf.xstring(s) end function utf.toeight(str) - if not str then + if not str or str == "" then return nil end local utftype = lpegmatch(p_utfstricttype,str) if utftype == "utf-8" then - return sub(str,4) - elseif utftype == "utf-16-le" then - return utf16_to_utf8_le(str) + return sub(str,4) -- remove the bom elseif utftype == "utf-16-be" then - return utf16_to_utf8_ne(str) + return utf16_to_utf8_be(str) -- bom gets removed + elseif utftype == "utf-16-le" then + return utf16_to_utf8_le(str) -- bom gets removed else return str end diff --git a/Master/texmf-dist/tex/context/base/l-url.lua b/Master/texmf-dist/tex/context/base/l-url.lua index 7bb73125493..b189ec5bba8 100644 --- a/Master/texmf-dist/tex/context/base/l-url.lua +++ b/Master/texmf-dist/tex/context/base/l-url.lua @@ -145,19 +145,25 @@ local splitquery = Cf ( Ct("") * P { "sequence", -- hasher local function hashed(str) -- not yet ok (/test?test) - if str == "" then + if not str or str == "" then return { scheme = "invalid", original = str, } end - local s = split(str) - local rawscheme = s[1] - local rawquery = s[4] - local somescheme = rawscheme ~= "" - local somequery = rawquery ~= "" + local detailed = split(str) + local rawscheme = "" + local rawquery = "" + local somescheme = false + local somequery = false + if detailed then + rawscheme = detailed[1] + rawquery = detailed[4] + somescheme = rawscheme ~= "" + somequery = rawquery ~= "" + end if not somescheme and not somequery then - s = { + return { scheme = "file", authority = "", path = str, @@ -167,30 +173,33 @@ local function hashed(str) -- not yet ok (/test?test) noscheme = true, filename = str, } - else -- not always a filename but handy anyway - local authority, path, filename = s[2], s[3] - if authority == "" then - filename = path - elseif path == "" then - filename = "" - else - filename = authority .. "/" .. path - end - s = { - scheme = rawscheme, - authority = authority, - path = path, - query = lpegmatch(unescaper,rawquery), -- unescaped, but possible conflict with & and = - queries = lpegmatch(splitquery,rawquery), -- split first and then unescaped - fragment = s[5], - original = str, - noscheme = false, - filename = filename, - } end - return s + -- not always a filename but handy anyway + local authority = detailed[2] + local path = detailed[3] + local filename = nil + if authority == "" then + filename = path + elseif path == "" then + filename = "" + else + filename = authority .. "/" .. path + end + return { + scheme = rawscheme, + authority = authority, + path = path, + query = lpegmatch(unescaper,rawquery), -- unescaped, but possible conflict with & and = + queries = lpegmatch(splitquery,rawquery), -- split first and then unescaped + fragment = detailed[5], + original = str, + noscheme = false, + filename = filename, + } end +-- inspect(hashed()) +-- inspect(hashed("")) -- inspect(hashed("template:///test")) -- inspect(hashed("template:///test++.whatever")) -- inspect(hashed("template:///test%2B%2B.whatever")) @@ -247,7 +256,7 @@ function url.construct(hash) -- dodo: we need to escape ! return lpegmatch(escaper,concat(fullurl)) end -local pattern = Cs(noslash * R("az","AZ") * (S(":|")/":") * noslash * P(1)^0) +local pattern = Cs(slash^-1/"" * R("az","AZ") * ((S(":|")/":") + P(":")) * slash * P(1)^0) function url.filename(filename) local spec = hashed(filename) @@ -257,6 +266,7 @@ end -- print(url.filename("/c|/test")) -- print(url.filename("/c/test")) +-- print(url.filename("file:///t:/sources/cow.svg")) local function escapestring(str) return lpegmatch(escaper,str) diff --git a/Master/texmf-dist/tex/context/base/lang-def.mkiv b/Master/texmf-dist/tex/context/base/lang-def.mkiv index 5c1d6de9cbf..c2fb9640cd6 100644 --- a/Master/texmf-dist/tex/context/base/lang-def.mkiv +++ b/Master/texmf-dist/tex/context/base/lang-def.mkiv @@ -271,37 +271,6 @@ \installlanguage [\s!slovenian] [\s!sl] \installlanguage [slovene] [\s!sl] % both possible (mojca: still needed?) -\def\doconvertsloveniancharacters{\dodoconvertcharacters{25}} - -\def\sloveniancharacters{\doconvertsloveniancharacters\sloveniancharacter} -\def\slovenianCharacters{\doconvertsloveniancharacters\slovenianCharacter} - -%D Define general-purpose macros for Slovenian character enumerations: - -\defineconversion [sloveniancharacter] [\sloveniancharacter] -\defineconversion [slovenianCharacter] [\slovenianCharacter] - -\defineconversion [sloveniancharacters] [\sloveniancharacters] -\defineconversion [slovenianCharacters] [\slovenianCharacters] - -%D Define these as the general character enumeration when -%D language is Slovenian. If you feel uncomfortable with this, -%D mail Mojca, since she promised to to take the heat. - -\defineconversion [\s!sl] [character] [\sloveniancharacter] -\defineconversion [\s!sl] [Character] [\slovenianCharacter] - -\defineconversion [\s!sl] [characters] [\sloveniancharacters] -\defineconversion [\s!sl] [Characters] [\slovenianCharacters] - -\defineconversion [\s!sl] [a] [\sloveniancharacters] -\defineconversion [\s!sl] [A] [\slovenianCharacters] -\defineconversion [\s!sl] [AK] [\smallcapped\sloveniancharacters] -\defineconversion [\s!sl] [KA] [\smallcapped\sloveniancharacters] - -\def\sloveniancharacters#1{\ctxcommand{alphabetic(\number#1,"sl")}} -\def\slovenianCharacters#1{\ctxcommand{Alphabetic(\number#1,"sl")}} - % Cyrillic Languages \installlanguage @@ -510,7 +479,8 @@ \c!rightquote=’, \c!leftquotation=“, \c!rightquotation=”, - \c!date={서기,\v!year,년,\v!month,월,\v!day,일}] + % \c!date={서기,\space,\v!year,\labeltext{\v!year},\space,\v!month,\labeltext{\v!month},\space,\v!day,\labeltext{\v!day}}] + \c!date={\v!year,\labeltext{\v!year},\space,\v!month,\labeltext{\v!month},\space,\v!day,\labeltext{\v!day}}] % Greek diff --git a/Master/texmf-dist/tex/context/base/lang-dis.lua b/Master/texmf-dist/tex/context/base/lang-dis.lua new file mode 100644 index 00000000000..db19a0fc5b8 --- /dev/null +++ b/Master/texmf-dist/tex/context/base/lang-dis.lua @@ -0,0 +1,203 @@ +if not modules then modules = { } end modules ['lang-dis'] = { + version = 1.001, + comment = "companion to lang-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local concat = table.concat + +local nodes = nodes + +local tasks = nodes.tasks +local nuts = nodes.nuts +local nodepool = nuts.pool + +local tonode = nuts.tonode +local tonut = nuts.tonut + +local getfield = nuts.getfield +local setfield = nuts.setfield +local getnext = nuts.getnext +local getprev = nuts.getprev +local getid = nuts.getid +local getfont = nuts.getfont +local getattr = nuts.getattr +local getsubtype = nuts.getsubtype +local getchar = nuts.getchar + +local copy_node = nuts.copy +local free_node = nuts.free +local remove_node = nuts.remove +local traverse_id = nuts.traverse_id +local traverse_nodes = nuts.traverse + +local nodecodes = nodes.nodecodes +local disccodes = nodes.disccodes + +local disc_code = nodecodes.disc +local glyph_code = nodecodes.glyph +local discretionary_code = disccodes.discretionary + +local a_visualize = attributes.private("visualizediscretionary") +local setattribute = tex.setattribute + +local getlanguagedata = languages.getdata + +local expanders = { + [disccodes.discretionary] = function(d,template) + -- \discretionary + return template + end, + [disccodes.explicit] = function(d,template) + -- \- + local pre = getfield(d,"pre") + if pre and getid(pre) == glyph_code and getchar(pre) <= 0 then + setfield(d,"pre",nil) + end + local post = getfield(d,"post") + if post and getid(post) == glyph_code and getchar(post) <= 0 then + setfield(d,"post",nil) + end +-- setfield(d,"subtype",discretionary_code) -- to be checked + return template + end, + [disccodes.automatic] = function(d,template) + -- following a - : the pre and post chars are already appended and set + -- so we have pre=preex and post=postex .. however, the previous + -- hyphen is already injected ... downside: the font handler sees this + -- so this is another argument for doing a hyphenation pass in context + if getfield(d,"pre") then + -- we have a preex characters and want that one to replace the + -- character in front which is the trigger + if not template then + -- can there be font kerns already? + template = getprev(d) + if template and getid(template) ~= glyph_code then + template = getnext(d) + if template and getid(template) ~= glyph_code then + template = nil + end + end + end + if template then + local pseudohead = getprev(template) + if pseudohead then + while template ~= d do + pseudohead, template, removed = remove_node(pseudohead,template) + setfield(d,"replace",removed) + -- break ? + end + else + -- can't happen + end + setfield(d,"subtype",discretionary_code) + else + -- print("lone regular discretionary ignored") + end + end + return template + end, + [disccodes.regular] = function(d,template) + -- simple + if not template then + -- can there be font kerns already? + template = getprev(d) + if template and getid(template) ~= glyph_code then + template = getnext(d) + if template and getid(template) ~= glyph_code then + template = nil + end + end + end + if template then + local language = template and getfield(template,"lang") + local data = getlanguagedata(language) + local prechar = data.prehyphenchar + local postchar = data.posthyphenchar + if prechar and prechar > 0 then + local c = copy_node(template) + setfield(c,"char",prechar) + setfield(d,"pre",c) + end + if postchar and postchar > 0 then + local c = copy_node(template) + setfield(c,"char",postchar) + setfield(d,"post",c) + end + setfield(d,"subtype",discretionary_code) + else + -- print("lone regular discretionary ignored") + end + return template + end, + [disccodes.first] = function() + -- forget about them + end, + [disccodes.second] = function() + -- forget about them + end, +} + +languages.expanders = expanders + +function languages.expand(d,template,subtype) + if not subtype then + subtype = getsubtype(d) + end + if subtype ~= discretionary_code then + return expanders[subtype](d,template) + end +end + +local setlistcolor = nodes.tracers.colors.setlist + +function languages.visualizediscretionaries(head) + for d in traverse_id(disc_code,tonut(head)) do + if getattr(d,a_visualize) then + local pre = getfield(d,"pre") + local post = getfield(d,"post") + local replace = getfield(d,"replace") + if pre then + setlistcolor(pre,"darkred") + end + if post then + setlistcolor(post,"darkgreen") + end + if replace then + setlistcolor(replace,"darkblue") + end + end + end +end + +local enabled = false + +function languages.showdiscretionaries(v) + if v == false then + setattribute(a_visualize,unsetvalue) + else -- also nil + if not enabled then + nodes.tasks.enableaction("processors","languages.visualizediscretionaries") + enabled = true + end + setattribute(a_visualize,1) + end +end + +interfaces.implement { + name = "showdiscretionaries", + actions = languages.showdiscretionaries +} + +local toutf = nodes.listtoutf + +function languages.serializediscretionary(d) -- will move to tracer + return string.formatters["{%s}{%s}{%s}"]( + toutf(getfield(d,"pre")) or "", + toutf(getfield(d,"post")) or "", + toutf(getfield(d,"replace")) or "" + ) +end + diff --git a/Master/texmf-dist/tex/context/base/lang-hyp.lua b/Master/texmf-dist/tex/context/base/lang-hyp.lua new file mode 100644 index 00000000000..496cfd19b43 --- /dev/null +++ b/Master/texmf-dist/tex/context/base/lang-hyp.lua @@ -0,0 +1,1648 @@ +if not modules then modules = { } end modules ['lang-hyp'] = { + version = 1.001, + comment = "companion to lang-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- todo: hyphenate over range if needed + +-- to be considered: reset dictionary.hyphenated when a pattern is added +-- or maybe an explicit reset of the cache + +-- In an automated workflow hypenation of long titles can be somewhat problematic +-- especially when demands conflict. For that reason I played a bit with a Lua based +-- variant of the traditional hyphenation machinery. This mechanism has been extended +-- several times in projects, of which a good description can be found in TUGboat, +-- Volume 27 (2006), No. 2 — Proceedings of EuroTEX2006: Automatic non-standard +-- hyphenation in OpenOffice.org by László Németh. +-- +-- Being the result of two days experimenting the following implementation is probably +-- not completely okay yet. If there is demand I might add some more features and plugs. +-- The performance is quite okay but can probably improved a bit, although this is not +-- the most critital code. +-- +-- . a l g o r i t h m . +-- 4l1g4 +-- l g o3 +-- 1g o +-- 2i t h +-- 4h1m +-- --------------------- +-- 4 1 4 3 2 0 4 1 +-- a l-g o-r i t h-m + +-- . a s s z o n n y a l . +-- s1s z/sz=sz,1,3 +-- n1n y/ny=ny,1,3 +-- ----------------------- +-- 0 1 0 0 0 1 0 0 0/sz=sz,2,3,ny=ny,6,3 +-- a s-s z o n-n y a l/sz=sz,2,3,ny=ny,6,3 +-- +-- ab1cd/ef=gh,2,2 : acd - efd (pattern/replacement,start,length +-- +-- In the procecess of wrapping up (for the ctx conference proceedings) I cleaned up +-- and extended the code a bit. + +local type, rawset, tonumber, next = type, rawset, tonumber, next + +local P, R, S, Cg, Cf, Ct, Cc, C, Carg, Cs = lpeg.P, lpeg.R, lpeg.S, lpeg.Cg, lpeg.Cf, lpeg.Ct, lpeg.Cc, lpeg.C, lpeg.Carg, lpeg.Cs +local lpegmatch = lpeg.match + +local concat = table.concat +local insert = table.insert +local remove = table.remove +local formatters = string.formatters +local utfchar = utf.char +local utfbyte = utf.byte + +if not characters then + require("char-ini") +end + +local setmetatableindex = table.setmetatableindex + +-- \enabletrackers[hyphenator.steps=silent] will not write to the terminal + +local trace_steps = false trackers.register("hyphenator.steps", function(v) trace_steps = v end) +local trace_visualize = false trackers.register("hyphenator.visualize",function(v) trace_visualize = v end) + +local report = logs.reporter("hyphenator") + +local implement = interfaces and interfaces.implement or function() end + +languages = languages or { } +local hyphenators = languages.hyphenators or { } +languages.hyphenators = hyphenators +local traditional = hyphenators.traditional or { } +hyphenators.traditional = traditional + +local dictionaries = setmetatableindex(function(t,k) + local v = { + patterns = { }, + hyphenated = { }, + specials = { }, + exceptions = { }, + loaded = false, + } + t[k] = v + return v +end) + +hyphenators.dictionaries = dictionaries + +local character = lpeg.patterns.utf8character +local digit = R("09") +local weight = digit/tonumber + Cc(0) +local fence = P(".") +local hyphen = P("-") +local space = P(" ") +local char = character - space +local validcharacter = (character - S("./")) +local keycharacter = character - S("/") +----- basepart = Ct( (Cc(0) * fence)^-1 * (weight * validcharacter)^1 * weight * (fence * Cc(0))^-1) +local specpart = (P("/") * Cf ( Ct("") * + Cg ( Cc("before") * C((1-P("="))^1) * P("=") ) * + Cg ( Cc("after") * C((1-P(","))^1) ) * + ( P(",") * + Cg ( Cc("start") * ((1-P(","))^1/tonumber) * P(",") ) * + Cg ( Cc("length") * ((1-P(-1) )^1/tonumber) ) + )^-1 + , rawset))^-1 + +local make_hashkey_p = Cs((digit/"" + keycharacter)^1) +----- make_pattern_p = basepart * specpart +local make_hashkey_e = Cs((hyphen/"" + keycharacter)^1) +local make_pattern_e = Ct(P(char) * (hyphen * Cc(true) * P(char) + P(char) * Cc(false))^1) -- catch . and char after - + +-- local make_hashkey_c = Cs((digit + keycharacter/"")^1) +-- local make_pattern_c = Ct((P(1)/tonumber)^1) + +-- local cache = setmetatableindex(function(t,k) +-- local n = lpegmatch(make_hashkey_c,k) +-- local v = lpegmatch(make_pattern_c,n) +-- t[k] = v +-- return v +-- end) +-- +-- local weight_n = digit + Cc("0") +-- local basepart_n = Cs( (Cc("0") * fence)^-1 * (weight * validcharacter)^1 * weight * (fence * Cc("0"))^-1) / cache +-- local make_pattern_n = basepart_n * specpart + +local make_pattern_c = Ct((P(1)/tonumber)^1) + +-- us + nl: 17664 entries -> 827 unique (saves some 3M) + +local cache = setmetatableindex(function(t,k) + local v = lpegmatch(make_pattern_c,k) + t[k] = v + return v +end) + +local weight_n = digit + Cc("0") +local fence_n = fence / "0" +local char_n = validcharacter / "" +local basepart_n = Cs(fence_n^-1 * (weight_n * char_n)^1 * weight_n * fence_n^-1) / cache +local make_pattern_n = basepart_n * specpart + +local function register_pattern(patterns,specials,str,specification) + local k = lpegmatch(make_hashkey_p,str) + -- local v1, v2 = lpegmatch(make_pattern_p,str) + local v1, v2 = lpegmatch(make_pattern_n,str) + patterns[k] = v1 -- is this key still ok for complex patterns + if specification then + specials[k] = specification + elseif v2 then + specials[k] = v2 + end +end + +local function unregister_pattern(patterns,specials,str) + local k = lpegmatch(make_hashkey_p,str) + patterns[k] = nil + specials[k] = nil +end + +local p_lower = lpeg.patterns.utf8lower + +local function register_exception(exceptions,str,specification) + local l = lpegmatch(p_lower,str) + local k = lpegmatch(make_hashkey_e,l) + local v = lpegmatch(make_pattern_e,l) + exceptions[k] = v +end + +local p_pattern = ((Carg(1) * Carg(2) * C(char^1)) / register_pattern + 1)^1 +local p_exception = ((Carg(1) * C(char^1)) / register_exception + 1)^1 +local p_split = Ct(C(character)^1) + +function traditional.loadpatterns(language,filename) + local dictionary = dictionaries[language] + if not dictionary.loaded then + if not filename or filename == "" then + filename = "lang-" .. language + end + filename = file.addsuffix(filename,"lua") + local fullname = resolvers.findfile(filename) + if fullname and fullname ~= "" then + local specification = dofile(fullname) + if specification then + local patterns = specification.patterns + if patterns then + local data = patterns.data + if data and data ~= "" then + lpegmatch(p_pattern,data,1,dictionary.patterns,dictionary.specials) + end + end + local exceptions = specification.exceptions + if exceptions then + local data = exceptions.data + if data and data ~= "" then + lpegmatch(p_exception,data,1,dictionary.exceptions) + end + end + end + end + dictionary.loaded = true + end + return dictionary +end + +local lcchars = characters.lcchars +local uccodes = characters.uccodes +local categories = characters.categories +local nofwords = 0 +local nofhashed = 0 + +local steps = nil +local f_show = formatters["%w%s"] + +local function show_log() + if trace_steps == true then + report() + local w = #steps[1][1] + for i=1,#steps do + local s = steps[i] + report("%s%w%S %S",s[1],w - #s[1] + 3,s[2],s[3]) + end + report() + end +end + +local function show_1(wsplit) + local u = concat(wsplit," ") + steps = { { f_show(0,u), f_show(0,u) } } +end + +local function show_2(c,m,wsplit,done,i,spec) + local s = lpegmatch(p_split,c) + local t = { } + local n = #m + local w = #wsplit + for j=1,n do + t[#t+1] = m[j] + t[#t+1] = s[j] + end + local m = 2*i-2 + local l = #t + local s = spec and table.sequenced(spec) or "" + if m == 0 then + steps[#steps+1] = { f_show(m, concat(t,"",2)), f_show(1,concat(done," ",2,#done),s) } + elseif i+1 == w then + steps[#steps+1] = { f_show(m-1,concat(t,"",1,#t-1)), f_show(1,concat(done," ",2,#done),s) } + else + steps[#steps+1] = { f_show(m-1,concat(t)), f_show(1,concat(done," ",2,#done),s) } + end +end + +local function show_3(wsplit,done) + local t = { } + local h = { } + local n = #wsplit + for i=1,n do + local w = wsplit[i] + if i > 1 then + local d = done[i] + t[#t+1] = i > 2 and d % 2 == 1 and "-" or " " + h[#h+1] = d + end + t[#t+1] = w + h[#h+1] = w + end + steps[#steps+1] = { f_show(0,concat(h)), f_show(0,concat(t)) } + show_log() +end + +local function show_4(wsplit,done) + steps = { { concat(wsplit," ") } } + show_log() +end + +function traditional.lasttrace() + return steps +end + +-- We could reuse the w table but as we cache the resolved words +-- there is not much gain in that complication. +-- +-- Beware: word can be a table and when n is passed to we can +-- assume reuse so we need to honor that n then. + +-- todo: a fast variant for tex ... less lookups (we could check is +-- dictionary has changed) ... although due to caching the already +-- done words, we don't do much here + +local function hyphenate(dictionary,word,n) -- odd is okay + nofwords = nofwords + 1 + local hyphenated = dictionary.hyphenated + local isstring = type(word) == "string" + if isstring then + local done = hyphenated[word] + if done ~= nil then + return done + end + elseif n then + local done = hyphenated[concat(word,"",1,n)] + if done ~= nil then + return done + end + else + local done = hyphenated[concat(word)] + if done ~= nil then + return done + end + end + local key + if isstring then + key = word + word = lpegmatch(p_split,word) + if not n then + n = #word + end + else + if not n then + n = #word + end + key = concat(word,"",1,n) + end + local l = 1 + local w = { "." } + for i=1,n do + local c = word[i] + l = l + 1 + w[l] = lcchars[c] or c + end + l = l + 1 + w[l] = "." + local c = concat(w,"",2,l-1) + -- + local done = hyphenated[c] + if done ~= nil then + hyphenated[key] = done + nofhashed = nofhashed + 1 + return done + end + -- + local exceptions = dictionary.exceptions + local exception = exceptions[c] + if exception then + if trace_steps then + show_4(w,exception) + end + hyphenated[key] = exception + nofhashed = nofhashed + 1 + return exception + end + -- + if trace_steps then + show_1(w) + end + -- + local specials = dictionary.specials + local patterns = dictionary.patterns + -- +-- inspect(specials) + local spec + for i=1,l do + for j=i,l do + local c = concat(w,"",i,j) + local m = patterns[c] + if m then + local s = specials[c] + if not done then + done = { } + spec = nil + -- the string that we resolve has explicit fences (.) so + -- done starts at the first fence and runs upto the last + -- one so we need one slot less + for i=1,l do + done[i] = 0 + end + end + -- we run over the pattern that always has a (zero) value for + -- each character plus one more as we look at both sides + for k=1,#m do + local new = m[k] + if not new then + break + elseif new == true then + report("fatal error") + break + elseif new > 0 then + local pos = i + k - 1 + local old = done[pos] + if not old then + -- break ? + elseif new > old then + done[pos] = new + if s then + local b = i + (s.start or 1) - 1 + if b > 0 then + local e = b + (s.length or 2) - 1 + if e > 0 then + if pos >= b and pos <= e then + if spec then + spec[pos] = { s, k - 1 } + else + spec = { [pos] = { s, k - 1 } } + end + end + end + end + end + end + end + end + if trace_steps and done then + show_2(c,m,w,done,i,s) + end + end + end + end + if trace_steps and done then + show_3(w,done) + end + if done then + local okay = false + for i=3,#done do + if done[i] % 2 == 1 then + done[i-2] = spec and spec[i] or true + okay = true + else + done[i-2] = false + end + end + if okay then + done[#done] = nil + done[#done] = nil + else + done = false + end + else + done = false + end + hyphenated[key] = done + nofhashed = nofhashed + 1 + return done +end + +function traditional.gettrace(language,word) + if not word or word == "" then + return + end + local dictionary = dictionaries[language] + if dictionary then + local hyphenated = dictionary.hyphenated + hyphenated[word] = nil + hyphenate(dictionary,word) + return steps + end +end + +local methods = setmetatableindex(function(t,k) local v = hyphenate t[k] = v return v end) + +function traditional.installmethod(name,f) + if rawget(methods,name) then + report("overloading %a is not permitted",name) + else + methods[name] = f + end +end + +local s_detail_1 = "-" +local f_detail_2 = formatters["%s-%s"] +local f_detail_3 = formatters["{%s}{%s}{}"] +local f_detail_4 = formatters["{%s%s}{%s%s}{%s}"] + +function traditional.injecthyphens(dictionary,word,specification) + if not word then + return false + end + if not specification then + return word + end + local hyphens = hyphenate(dictionary,word) + if not hyphens then + return word + end + + -- the following code is similar to code later on but here we have + -- strings while there we have hyphen specs + + local word = lpegmatch(p_split,word) + local size = #word + + local leftmin = specification.leftcharmin or 2 + local rightmin = size - (specification.rightcharmin or leftmin) + local leftchar = specification.leftchar + local rightchar = specification.rightchar + + local result = { } + local rsize = 0 + local position = 1 + + while position <= size do + if position >= leftmin and position <= rightmin then + local hyphen = hyphens[position] + if not hyphen then + rsize = rsize + 1 + result[rsize] = word[position] + position = position + 1 + elseif hyphen == true then + rsize = rsize + 1 + result[rsize] = word[position] + rsize = rsize + 1 + if leftchar and rightchar then + result[rsize] = f_detail_3(rightchar,leftchar) + else + result[rsize] = s_detail_1 + end + position = position + 1 + else + local o, h = hyphen[2] + if o then + h = hyphen[1] + else + h = hyphen + o = 1 + end + local b = position - o + (h.start or 1) + local e = b + (h.length or 2) - 1 + if b > 0 and e >= b then + for i=1,b-position do + rsize = rsize + 1 + result[rsize] = word[position] + position = position + 1 + end + rsize = rsize + 1 + if leftchar and rightchar then + result[rsize] = f_detail_4(h.before,rightchar,leftchar,h.after,concat(word,"",b,e)) + else + result[rsize] = f_detail_2(h.before,h.after) + end + position = e + 1 + else + -- error + rsize = rsize + 1 + result[rsize] = word[position] + position = position + 1 + end + end + else + rsize = rsize + 1 + result[rsize] = word[position] + position = position + 1 + end + end + return concat(result) +end + +do + + local word = C((1-space)^1) + local spaces = space^1 + + local u_pattern = (Carg(1) * Carg(2) * word / unregister_pattern + spaces)^1 + local r_pattern = (Carg(1) * Carg(2) * word * Carg(3) / register_pattern + spaces)^1 + local e_pattern = (Carg(1) * word / register_exception + spaces)^1 + + function traditional.registerpattern(language,str,specification) + local dictionary = dictionaries[language] + if specification == false then + lpegmatch(u_pattern,str,1,dictionary.patterns,dictionary.specials) + -- unregister_pattern(dictionary.patterns,dictionary.specials,str) + else + lpegmatch(r_pattern,str,1,dictionary.patterns,dictionary.specials,type(specification) == "table" and specification or false) + -- register_pattern(dictionary.patterns,dictionary.specials,str,specification) + end + end + + function traditional.registerexception(language,str) + lpegmatch(e_pattern,str,1,dictionaries[language].exceptions) + end + +end + +-- todo: unicodes or utfhash ? + +if context then + + local nodecodes = nodes.nodecodes + local disccodes = nodes.disccodes + + local glyph_code = nodecodes.glyph + local disc_code = nodecodes.disc + local math_code = nodecodes.math + local hlist_code = nodecodes.hlist + + local discretionary_code = disccodes.discretionary + local explicit_code = disccodes.explicit + local regular_code = disccodes.regular + local automatic_code = disccodes.automatic + + local nuts = nodes.nuts + local tonut = nodes.tonut + local tonode = nodes.tonode + local nodepool = nuts.pool + + local new_disc = nodepool.disc + local new_glyph = nodepool.glyph + + local setfield = nuts.setfield + local getfield = nuts.getfield + local getfont = nuts.getfont + local getchar = nuts.getchar + local getid = nuts.getid + local getattr = nuts.getattr + local getnext = nuts.getnext + local getprev = nuts.getprev + local getsubtype = nuts.getsubtype + local getlist = nuts.getlist + local insert_before = nuts.insert_before + local insert_after = nuts.insert_after + local copy_node = nuts.copy + local remove_node = nuts.remove + local end_of_math = nuts.end_of_math + local node_tail = nuts.tail + local traverse_id = nuts.traverse_id + + local setcolor = nodes.tracers.colors.set + + local variables = interfaces.variables + local v_reset = variables.reset + local v_yes = variables.yes + local v_all = variables.all + + local settings_to_array = utilities.parsers.settings_to_array + + local unsetvalue = attributes.unsetvalue + local texsetattribute = tex.setattribute + + local prehyphenchar = lang.prehyphenchar + local posthyphenchar = lang.posthyphenchar + local preexhyphenchar = lang.preexhyphenchar + local postexhyphenchar = lang.postexhyphenchar + + local lccodes = characters.lccodes + + local a_hyphenation = attributes.private("hyphenation") + + function traditional.loadpatterns(language) + return dictionaries[language] + end + + setmetatableindex(dictionaries,function(t,k) -- for the moment we use an independent data structure + if type(k) == "string" then + -- this will force a load if not yet loaded (we need a nicer way) + -- for the moment that will do (nneeded for examples that register + -- a pattern specification + languages.getnumber(k) + end + local specification = languages.getdata(k) + local dictionary = { + patterns = { }, + exceptions = { }, + hyphenated = { }, + specials = { }, + instance = false, + characters = { }, + unicodes = { }, + } + if specification then + local resources = specification.resources + if resources then + local characters = dictionary.characters or { } + local unicodes = dictionary.unicodes or { } + for i=1,#resources do + local r = resources[i] + if not r.in_dictionary then + r.in_dictionary = true + local patterns = r.patterns + if patterns then + local data = patterns.data + if data then + -- regular patterns + lpegmatch(p_pattern,data,1,dictionary.patterns,dictionary.specials) + end + local extra = patterns.extra + if extra then + -- special patterns + lpegmatch(p_pattern,extra,1,dictionary.patterns,dictionary.specials) + end + end + local exceptions = r.exceptions + if exceptions then + local data = exceptions.data + if data and data ~= "" then + lpegmatch(p_exception,data,1,dictionary.exceptions) + end + end + local usedchars = lpegmatch(p_split,patterns.characters) + for i=1,#usedchars do + local char = usedchars[i] + local code = utfbyte(char) + local upper = uccodes[code] + characters[char] = code + unicodes [code] = char + if type(upper) == "table" then + for i=1,#upper do + local u = upper[i] + unicodes[u] = utfchar(u) + end + else + unicodes[upper] = utfchar(upper) + end + end + end + end + dictionary.characters = characters + dictionary.unicodes = unicodes + setmetatableindex(characters,function(t,k) local v = k and utfbyte(k) t[k] = v return v end) + end + t[specification.number] = dictionary + dictionary.instance = specification.instance -- needed for hyphenchars + end + t[k] = dictionary + return dictionary + end) + + -- Beware: left and right min doesn't mean that in a 1 mmm hsize there can be snippets + -- with less characters than either of them! This could be an option but such a narrow + -- hsize doesn't make sense anyway. + + -- We assume that featuresets are defined global ... local definitions + -- (also mid paragraph) make not much sense anyway. For the moment we + -- assume no predefined sets so we don't need to store them. Nor do we + -- need to hash them in order to save space ... no sane user will define + -- many of them. + + local featuresets = hyphenators.featuresets or { } + hyphenators.featuresets = featuresets + + storage.shared.noflanguagesfeaturesets = storage.shared.noflanguagesfeaturesets or 0 + + local noffeaturesets = storage.shared.noflanguagesfeaturesets + + storage.register("languages/hyphenators/featuresets",featuresets,"languages.hyphenators.featuresets") + + ----- hash = table.sequenced(featureset,",") -- no need now + + local function register(name,featureset) + noffeaturesets = noffeaturesets + 1 + featureset.attribute = noffeaturesets + featuresets[noffeaturesets] = featureset -- access by attribute + featuresets[name] = featureset -- access by name + storage.shared.noflanguagesfeaturesets = noffeaturesets + return noffeaturesets + end + + local function makeset(...) -- a bit overkill, supporting variants but who cares + local set = { } + for i=1,select("#",...) do + local list = select(i,...) + local kind = type(list) + local used = nil + if kind == "string" then + if list == v_all then + -- not ok ... now all get ignored + return setmetatableindex(function(t,k) local v = utfchar(k) t[k] = v return v end) + elseif list ~= "" then + used = lpegmatch(p_split,list) + set = set or { } + for i=1,#used do + local char = used[i] + set[utfbyte(char)] = char + end + end + elseif kind == "table" then + if next(list) then + set = set or { } + for byte, char in next, list do + set[byte] = char == true and utfchar(byte) or char + end + elseif #list > 0 then + set = set or { } + for i=1,#list do + local l = list[i] + if type(l) == "number" then + set[l] = utfchar(l) + else + set[utfbyte(l)] = l + end + end + end + end + end + return set + end + + local defaulthyphens = { + [0x2D] = true, -- hyphen + [0xAD] = true, -- soft hyphen + } + + local defaultjoiners = { + [0x200C] = true, -- nzwj + [0x200D] = true, -- zwj + } + + local function somehyphenchar(c) + c = tonumber(c) + return c ~= 0 and c or nil + end + + local function definefeatures(name,featureset) + local extrachars = featureset.characters -- "[]()" + local hyphenchars = featureset.hyphens + local joinerchars = featureset.joiners + local alternative = featureset.alternative + local rightwordmin = tonumber(featureset.rightwordmin) + local charmin = tonumber(featureset.charmin) + local leftcharmin = tonumber(featureset.leftcharmin) + local rightcharmin = tonumber(featureset.rightcharmin) + local rightedge = featureset.rightedge + local leftchar = somehyphenchar(featureset.leftchar) + local rightchar = somehyphenchar(featureset.rightchar) + -- + joinerchars = joinerchars == v_yes and defaultjoiners or joinerchars + hyphenchars = hyphenchars == v_yes and defaulthyphens or hyphenchars + -- not yet ok: extrachars have to be ignored so it cannot be all) + featureset.extrachars = makeset(joinerchars or "",extrachars or "") + featureset.hyphenchars = makeset(hyphenchars or "") + featureset.alternative = alternative or "hyphenate" + featureset.rightwordmin = rightwordmin and rightwordmin > 0 and rightwordmin or nil + featureset.charmin = charmin and charmin > 0 and charmin or nil + featureset.leftcharmin = leftcharmin and leftcharmin > 0 and leftcharmin or nil + featureset.rightcharmin = rightcharmin and rightcharmin > 0 and rightcharmin or nil + featureset.leftchar = leftchar + featureset.rightchar = rightchar + featureset.strict = rightedge == 'tex' + -- + return register(name,featureset) + end + + local function setfeatures(n) + if not n or n == v_reset then + n = false + else + local f = featuresets[n] + if not f and type(n) == "string" then + local t = settings_to_array(n) + local s = { } + for i=1,#t do + local ti = t[i] + local fs = featuresets[ti] + if fs then + for k, v in next, fs do + s[k] = v + end + end + end + n = register(n,s) + else + n = f and f.attribute + end + end + texsetattribute(a_hyphenation,n or unsetvalue) + end + + traditional.definefeatures = definefeatures + traditional.setfeatures = setfeatures + + implement { + name = "definehyphenationfeatures", + actions = definefeatures, + arguments = { + "string", + { + { "characters" }, + { "hyphens" }, + { "joiners" }, + { "rightwordmin", "integer" }, + { "charmin", "integer" }, + { "leftcharmin", "integer" }, + { "rightcharmin", "integer" }, + { "leftchar", "integer" }, + { "rightchar", "integer" }, + { "alternative" }, + { "rightedge" }, + } + } + } + + implement { + name = "sethyphenationfeatures", + actions = setfeatures, + arguments = "string" + } + + implement { + name = "registerhyphenationpattern", + actions = traditional.registerpattern, + arguments = { "string", "string", "boolean" } + } + + implement { + name = "registerhyphenationexception", + actions = traditional.registerexception, + arguments = { "string", "string" } + } + + -- This is a relative large function with local variables and local + -- functions. A previous implementation had the functions outside but + -- this is cleaner and as efficient. The test runs 100 times over + -- tufte.tex, knuth.tex, zapf.tex, ward.tex and darwin.tex in lower + -- and uppercase with a 1mm hsize. + -- + -- language=0 language>0 4 | 3 * slower + -- + -- tex 2.34 | 1.30 2.55 | 1.45 0.21 | 0.15 + -- lua 2.42 | 1.38 3.30 | 1.84 0.88 | 0.46 + -- + -- Of course we have extra overhead (virtual Lua machine) but also we + -- check attributes and support specific local options). The test puts + -- the typeset text in boxes and discards it. If we also flush the + -- runtime is 4.31|2.56 and 4.99|2.94 seconds so the relative difference + -- is (somehow) smaller. The test has 536 pages. There is a little bit + -- of extra overhead because we store the patterns in a different way. + -- + -- As usual I will look for speedups. Some 0.01 seconds could be gained + -- by sharing patterns which is not impressive but it does save some + -- 3M memory on this test. (Some optimizations already brought the 3.30 + -- seconds down to 3.14 but it all depends on aggressive caching.) + + -- As we kick in the hyphenator before fonts get handled, we don't look + -- at implicit (font) kerns or ligatures. + + local starttiming = statistics.starttiming + local stoptiming = statistics.stoptiming + + local strictids = { + [nodecodes.hlist] = true, + [nodecodes.vlist] = true, + [nodecodes.rule] = true, + [nodecodes.disc] = true, + [nodecodes.accent] = true, + [nodecodes.math] = true, + } + + function traditional.hyphenate(head) + + local first = tonut(head) + local tail = nil + local last = nil + local current = first + local dictionary = nil + local instance = nil + local characters = nil + local unicodes = nil + local exhyphenchar = tex.exhyphenchar + local extrachars = nil + local hyphenchars = nil + local language = nil + local start = nil + local stop = nil + local word = { } -- we reuse this table + local size = 0 + local leftchar = false + local rightchar = false -- utfbyte("-") + local leftexchar = false + local rightexchar = false -- utfbyte("-") + local leftmin = 0 + local rightmin = 0 + local charmin = 1 + local leftcharmin = nil + local rightcharmin = nil + ----- leftwordmin = nil + local rightwordmin = nil + local leftchar = nil + local rightchar = nil + local attr = nil + local lastwordlast = nil + local hyphenated = hyphenate + local strict = nil + + -- We cannot use an 'enabled' boolean (false when no characters or extras) because we + -- can have plugins that set a characters metatable and so) ... it doesn't save much + -- anyway. Using (unicodes and unicodes[code]) and a nil table when no characters also + -- doesn't save much. So there not that much to gain for languages that don't hyphenate. + -- + -- enabled = (unicodes and (next(unicodes) or getmetatable(unicodes))) or (extrachars and next(extrachars)) + -- + -- This can be used to not add characters i.e. keep size 0 but then we need to check for + -- attributes that change it, which costs time too. Not much to gain there. + + starttiming(traditional) + + local function synchronizefeatureset(a) + local f = a and featuresets[a] + if f then + hyphenated = methods[f.alternative or "hyphenate"] + extrachars = f.extrachars + hyphenchars = f.hyphenchars + rightwordmin = f.rightwordmin + charmin = f.charmin + leftcharmin = f.leftcharmin + rightcharmin = f.rightcharmin + leftchar = f.leftchar + rightchar = f.rightchar + strict = f.strict and strictids + if rightwordmin and rightwordmin > 0 and lastwordlast ~= rightwordmin then + -- so we can change mid paragraph but it's kind of unpredictable then + if not tail then + tail = node_tail(first) + end + last = tail + local inword = false + while last and rightwordmin > 0 do + local id = getid(last) + if id == glyph_code then + inword = true + if trace_visualize then + setcolor(last,"darkred") + end + elseif inword then + inword = false + rightwordmin = rightwordmin - 1 + end + last = getprev(last) + end + lastwordlast = rightwordmin + end + if not charmin or charmin == 0 then + charmin = 1 + end + else + hyphenated = methods.hyphenate + extrachars = false + hyphenchars = false + rightwordmin = false + charmin = 1 + leftcharmin = false + rightcharmin = false + leftchar = false + rightchar = false + strict = false + end + + return a + end + + local function flush(hyphens) -- todo: no need for result + + local rightmin = size - rightmin + local result = { } + local rsize = 0 + local position = 1 + + -- todo: remember last dics and don't go back to before that (plus + -- message) .. for simplicity we also assume that we don't start + -- with a dics node + -- + -- there can be a conflict: if we backtrack then we can end up in + -- another disc and get out of sync (dup chars and so) + + while position <= size do + if position >= leftmin and position <= rightmin then + local hyphen = hyphens[position] + if not hyphen then + rsize = rsize + 1 + result[rsize] = word[position] + position = position + 1 + elseif hyphen == true then + rsize = rsize + 1 + result[rsize] = word[position] + rsize = rsize + 1 + result[rsize] = true + position = position + 1 + else + local o, h = hyphen[2] + if o then + -- { hyphen, offset) + h = hyphen[1] + else + -- hyphen + h = hyphen + o = 1 + end + local b = position - o + (h.start or 1) + local e = b + (h.length or 2) - 1 + if b > 0 and e >= b then + for i=1,b-position do + rsize = rsize + 1 + result[rsize] = word[position] + position = position + 1 + end + rsize = rsize + 1 + result[rsize] = { + h.before or "", -- pre + h.after or "", -- post + concat(word,"",b,e), -- replace + h.right, -- optional after pre + h.left, -- optional before post + } + position = e + 1 + else + -- error + rsize = rsize + 1 + result[rsize] = word[position] + position = position + 1 + end + end + else + rsize = rsize + 1 + result[rsize] = word[position] + position = position + 1 + end + end + + local function serialize(replacement,leftchar,rightchar) + if not replacement then + return + elseif replacement == true then + local glyph = copy_node(stop) + setfield(glyph,"char",leftchar or rightchar) + return glyph + end + local head = nil + local current = nil + if leftchar then + head = copy_node(stop) + current = head + setfield(head,"char",leftchar) + end + local rsize = #replacement + if rsize == 1 then + local glyph = copy_node(stop) + setfield(glyph,"char",characters[replacement]) + if head then + insert_after(current,current,glyph) + else + head = glyph + end + current = glyph + elseif rsize > 0 then + local list = lpegmatch(p_split,replacement) -- this is an utf split (could be cached) + for i=1,#list do + local glyph = copy_node(stop) + setfield(glyph,"char",characters[list[i]]) + if head then + insert_after(current,current,glyph) + else + head = glyph + end + current = glyph + end + end + if rightchar then + local glyph = copy_node(stop) + insert_after(current,current,glyph) + setfield(glyph,"char",rightchar) + end + return head + end + + local current = start + + local attributes = getfield(start,"attr") -- todo: just copy the last disc .. faster + + for i=1,rsize do + local r = result[i] + if r == true then + local disc = new_disc() + if rightchar then + setfield(disc,"pre",serialize(true,rightchar)) + end + if leftchar then + setfield(disc,"post",serialize(true,leftchar)) + end + if attributes then + setfield(disc,"attr",attributes) + end + -- could be a replace as well + insert_before(first,current,disc) + elseif type(r) == "table" then + local disc = new_disc() + local pre = r[1] + local post = r[2] + local replace = r[3] + local right = r[4] ~= false and rightchar + local left = r[5] ~= false and leftchar + if pre and pre ~= "" then + setfield(disc,"pre",serialize(pre,false,right)) + end + if post and post ~= "" then + setfield(disc,"post",serialize(post,left,false)) + end + if replace and replace ~= "" then + setfield(disc,"replace",serialize(replace)) + end + if attributes then + setfield(disc,"attr",attributes) + end + insert_before(first,current,disc) + else + setfield(current,"char",characters[r]) + if i < rsize then + current = getnext(current) + end + end + end + if current and current ~= stop then + local current = getnext(current) + local last = getnext(stop) + while current ~= last do + first, current = remove_node(first,current,true) + end + end + + end + + local function inject(leftchar,rightchar,code,attributes) + if first ~= current then + local disc = new_disc() + first, current, glyph = remove_node(first,current) + first, current = insert_before(first,current,disc) + if trace_visualize then + setcolor(glyph,"darkred") -- these get checked + setcolor(disc,"darkgreen") -- in the colorizer + end + setfield(disc,"replace",glyph) + if not leftchar then + leftchar = code + end + if rightchar then + local glyph = copy_node(glyph) + setfield(glyph,"char",rightchar) + setfield(disc,"pre",glyph) + end + if leftchar then + local glyph = copy_node(glyph) + setfield(glyph,"char",leftchar) + setfield(disc,"post",glyph) + end + if attributes then + setfield(disc,"attr",attributes) + end + end + return current + end + + local a = getattr(first,a_hyphenation) + if a ~= attr then + attr = synchronizefeatureset(a) + end + + -- The first attribute in a word determines the way a word gets hyphenated + -- and if relevant, other properties are also set then. We could optimize for + -- silly one-char cases but it has no priority as the code is still not that + -- much slower than the native hyphenator and this variant also provides room + -- for extensions. + + while current and current ~= last do -- and current + local id = getid(current) + if id == glyph_code then + local code = getchar(current) + local lang = getfield(current,"lang") + if lang ~= language then + if dictionary and size > charmin and leftmin + rightmin <= size then + if categories[word[1]] == "lu" and getfield(start,"uchyph") < 0 then + -- skip + else + local hyphens = hyphenated(dictionary,word,size) + if hyphens then + flush(hyphens) + end + end + end + language = lang + if language > 0 then + -- + dictionary = dictionaries[language] + instance = dictionary.instance + characters = dictionary.characters + unicodes = dictionary.unicodes + -- + local a = getattr(current,a_hyphenation) + attr = synchronizefeatureset(a) + leftchar = leftchar or (instance and posthyphenchar (instance)) -- we can make this more + rightchar = rightchar or (instance and prehyphenchar (instance)) -- efficient if needed + leftexchar = (instance and preexhyphenchar (instance)) + rightexchar = (instance and postexhyphenchar(instance)) + leftmin = leftcharmin or getfield(current,"left") + rightmin = rightcharmin or getfield(current,"right") + if not leftchar or leftchar < 0 then + leftchar = false + end + if not rightchar or rightchar < 0 then + rightchar = false + end + -- + local char = unicodes[code] or (extrachars and extrachars[code]) + if char then + word[1] = char + size = 1 + start = current + else + size = 0 + end + else + size = 0 + end + elseif language <= 0 then + -- + elseif size > 0 then + local char = unicodes[code] or (extrachars and extrachars[code]) + if char then + size = size + 1 + word[size] = char + elseif dictionary then + if size > charmin and leftmin + rightmin <= size then + if categories[word[1]] == "lu" and getfield(start,"uchyph") < 0 then + -- skip + else + local hyphens = hyphenated(dictionary,word,size) + if hyphens then + flush(hyphens) + end + end + end + size = 0 + -- maybe also a strict mode here: no hyphenation before hyphenchars and skip + -- the next set (but then, strict is an option) + if code == exhyphenchar then + current = inject(leftexchar,rightexchar,code,getfield(current,"attr")) + elseif hyphenchars and hyphenchars[code] then + current = inject(leftchar,rightchar,code,getfield(current,"attr")) + end + end + else + local a = getattr(current,a_hyphenation) + if a ~= attr then + attr = synchronizefeatureset(a) -- influences extrachars + leftchar = leftchar or (instance and posthyphenchar (instance)) -- we can make this more + rightchar = rightchar or (instance and prehyphenchar (instance)) -- efficient if needed + leftexchar = (instance and preexhyphenchar (instance)) + rightexchar = (instance and postexhyphenchar(instance)) + leftmin = leftcharmin or getfield(current,"left") + rightmin = rightcharmin or getfield(current,"right") + if not leftchar or leftchar < 0 then + leftchar = false + end + if not rightchar or rightchar < 0 then + rightchar = false + end + end + -- + local char = unicodes[code] or (extrachars and extrachars[code]) + if char then + word[1] = char + size = 1 + start = current + end + end + stop = current + current = getnext(current) + else + if id == disc_code then + local subtype = getsubtype(current) + if subtype == discretionary_code then -- \discretionary + size = 0 + current = getnext(current) + elseif subtype == explicit_code then -- \- => only here + size = 0 + current = getnext(current) + while current do + local id = getid(current) + if id == glyph_code or id == disc_code then + current = getnext(current) + else + break + end + end + -- todo: change to discretionary_code + else + -- automatic (-) : the hyphenator turns an exhyphen into glyph+disc + -- first : done by the hyphenator + -- second : done by the hyphenator + -- regular : done by the hyphenator + size = 0 + current = getnext(current) + end + elseif strict and strict[id] then + current = id == math_code and getnext(end_of_math(current)) or getnext(current) + size = 0 + else + current = id == math_code and getnext(end_of_math(current)) or getnext(current) + end + if size > 0 then + if dictionary and size > charmin and leftmin + rightmin <= size then + if categories[word[1]] == "lu" and getfield(start,"uchyph") < 0 then + -- skip + else + local hyphens = hyphenated(dictionary,word,size) + if hyphens then + flush(hyphens) + end + end + end + size = 0 + end + end + end + -- we can have quit due to last so we need to flush the last seen word, we could move this in + -- the loop and test for current but ... messy + if dictionary and size > charmin and leftmin + rightmin <= size then + if categories[word[1]] == "lu" and getfield(start,"uchyph") < 0 then + -- skip + else + local hyphens = hyphenated(dictionary,word,size) + if hyphens then + flush(hyphens) + end + end + end + + stoptiming(traditional) + + return head, true + end + + statistics.register("hyphenation",function() + if nofwords > 0 or statistics.elapsed(traditional) > 0 then + return string.format("%s words hyphenated, %s unique, used time %s", + nofwords,nofhashed,statistics.elapsedseconds(traditional) or 0) + end + end) + + local texmethod = "builders.kernel.hyphenation" + local oldmethod = texmethod + local newmethod = texmethod + + -- local newmethod = "languages.hyphenators.traditional.hyphenate" + -- + -- nodes.tasks.prependaction("processors","words",newmethod) + -- nodes.tasks.disableaction("processors",oldmethod) + -- + -- nodes.tasks.replaceaction("processors","words",oldmethod,newmethod) + + -- \enabledirectives[hyphenators.method=traditional] + -- \enabledirectives[hyphenators.method=builtin] + + -- push / pop ? check first attribute + + -- local replaceaction = nodes.tasks.replaceaction -- no longer overload this way (too many local switches) + + local hyphenate = lang.hyphenate + local expanders = languages.expanders + local methods = { } + local usedmethod = false + local stack = { } + + local function original(head) + local done = hyphenate(head) + return head, done + end + + local function expanded(head) + local done = hyphenate(head) + if done then + for d in traverse_id(disc_code,tonut(head)) do + local s = getsubtype(d) + if s ~= discretionary_code then + expanders[s](d,template) + done = true + end + end + end + return head, done + end + + local getcount = tex.getcount + + hyphenators.methods = methods + hyphenators.optimize = false + + function hyphenators.handler(head,groupcode) + if usedmethod then + if groupcode == "hbox" and hyphenators.optimize then + if getcount("hyphenstate") > 0 then + forced = false + return usedmethod(head) + else + return head, false + end + else + return usedmethod(head) + end + else + return head, false + end + end + + methods.tex = original + methods.original = original + methods.expanded = expanded + methods.traditional = languages.hyphenators.traditional.hyphenate + methods.none = false -- function(head) return head, false end + + usedmethod = original + + local function setmethod(method) + usedmethod = type(method) == "string" and methods[method] + if usedmethod == nil then + usedmethod = methods.tex + end + end + local function pushmethod(method) + insert(stack,usedmethod) + usedmethod = type(method) == "string" and methods[method] + if usedmethod == nil then + usedmethod = methods.tex + end + end + local function popmethod() + usedmethod = remove(stack) or methods.tex + end + + hyphenators.setmethod = setmethod + hyphenators.pushmethod = pushmethod + hyphenators.popmethod = popmethod + + directives.register("hyphenators.method",setmethod) + + function hyphenators.setup(specification) + local method = specification.method + if method then + setmethod(method) + end + end + + implement { name = "sethyphenationmethod", actions = setmethod, arguments = "string" } + implement { name = "pushhyphenation", actions = pushmethod, arguments = "string" } + implement { name = "pophyphenation", actions = popmethod } + + -- can become a runtime loaded one: + + local context = context + local ctx_NC = context.NC + local ctx_NR = context.NR + local ctx_verbatim = context.verbatim + + function hyphenators.showhyphenationtrace(language,word) + if not word or word == "" then + return + end + local saved = trace_steps + trace_steps = "silent" + local steps = traditional.gettrace(language,word) + trace_steps = saved + if steps then + local n = #steps + if n > 0 then + context.starttabulate { "|r|l|l|l|" } + for i=1,n do + local s = steps[i] + ctx_NC() if i > 1 and i < n then context(i-1) end + ctx_NC() ctx_verbatim(s[1]) + ctx_NC() ctx_verbatim(s[2]) + ctx_NC() ctx_verbatim(s[3]) + ctx_NC() + ctx_NR() + end + context.stoptabulate() + end + end + end + + implement { + name = "showhyphenationtrace", + actions = hyphenators.showhyphenationtrace, + arguments = { "string", "string" } + } + + function nodes.stripdiscretionaries(head) + local h = tonut(head) + for l in traverse_id(hlist_code,h) do + for d in traverse_id(disc_code,getlist(l)) do + remove_node(h,false,true) + end + end + return tonode(h) + end + + +else + +-- traditional.loadpatterns("nl","lang-nl") +-- traditional.loadpatterns("de","lang-de") +-- traditional.loadpatterns("us","lang-us") + +-- traditional.registerpattern("nl","e1ë", { start = 1, length = 2, before = "e", after = "e" } ) +-- traditional.registerpattern("nl","oo7ë", { start = 2, length = 3, before = "o", after = "e" } ) +-- traditional.registerpattern("de","qqxc9xkqq",{ start = 3, length = 4, before = "ab", after = "cd" } ) + +-- local specification = { +-- leftcharmin = 2, +-- rightcharmin = 2, +-- leftchar = "<", +-- rightchar = ">", +-- } + +-- print("reëel", traditional.injecthyphens(dictionaries.nl,"reëel", specification),"r{e>}{
+
+local fromsixteen = lpdf.fromsixteen -- maybe inline the lpeg ... but not worth it
+
+local function f_bfchar(t,a,b)
+ t[tonumber(a,16)] = fromsixteen(b)
+end
+
+local function f_bfrange_1(t,a,b,c)
+ print("todo 1",a,b,c)
+ -- c is string
+ -- todo t[tonumber(a,16)] = fromsixteen(b)
+end
+
+local function f_bfrange_2(t,a,b,c)
+ print("todo 2",a,b,c)
+ -- c is table
+ -- todo t[tonumber(a,16)] = fromsixteen(b)
+end
+
+local optionals = spaces^0
+local hexstring = optionals * P("<") * C((1-P(">"))^1) * P(">")
+local bfchar = Carg(1) * hexstring * hexstring / f_bfchar
+local bfrange = Carg(1) * hexstring * hexstring * hexstring / f_bfrange_1
+ + Carg(1) * hexstring * hexstring * optionals * P("[") * Ct(hexstring^1) * optionals * P("]") / f_bfrange_2
+local fromunicode = (
+ P("beginbfchar" ) * bfchar ^1 * optionals * P("endbfchar" ) +
+ P("beginbfrange") * bfrange^1 * optionals * P("endbfrange") +
+ spaces +
+ P(1)
+)^1 * Carg(1)
+
+local function analyzefonts(document,resources) -- unfinished
+ local fonts = document.__fonts__
+ if resources then
+ local fontlist = resources.Font
+ if fontlist then
+ for id, data in expanded(fontlist) do
+ if not fonts[id] then
+ -- a quck hack ... I will look into it more detail if I find a real
+ -- -application for it
+ local tounicode = data.ToUnicode()
+ if tounicode then
+ tounicode = lpegmatch(fromunicode,tounicode,1,{})
+ end
+ fonts[id] = {
+ tounicode = type(tounicode) == "table" and tounicode or { }
+ }
+ table.setmetatableindex(fonts[id],"self")
+ end
+ end
+ end
+ end
+ return fonts
+end
+
+local more = 0
+local unic = nil -- cheaper than passing each time as Carg(1)
+
+local p_hex_to_utf = C(4) / function(s) -- needs checking !
+ local now = tonumber(s,16)
+ if more > 0 then
+ now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong
+ more = 0
+ return unic[now] or utfchar(now)
+ elseif now >= 0xD800 and now <= 0xDBFF then
+ more = now
+ -- return ""
+ else
+ return unic[now] or utfchar(now)
+ end
+end
+
+local p_dec_to_utf = C(1) / function(s) -- needs checking !
+ local now = byte(s)
+ return unic[now] or utfchar(now)
+end
+
+local p_hex_to_utf = P(true) / function() more = 0 end * Cs(p_hex_to_utf^1)
+local p_dec_to_utf = P(true) / function() more = 0 end * Cs(p_dec_to_utf^1)
+
+function lpdf_epdf.getpagecontent(document,pagenumber)
+
+ local page = document.pages[pagenumber]
+
+ if not page then
+ return
+ end
+
+ local fonts = analyzefonts(document,page.Resources)
+
+ local content = page.Contents() or ""
+ local list = lpegmatch(parser,content)
+ local font = nil
+ -- local unic = nil
+
+ for i=1,#list do
+ local entry = list[i]
+ local size = #entry
+ local operator = entry[size]
+ if operator == "Tf" then
+ font = fonts[entry[1]]
+ unic = font.tounicode
+ elseif operator == "TJ" then -- { array, TJ }
+ local list = entry[1]
+ for i=1,#list do
+ local li = list[i]
+ if type(li) == "table" then
+ if li[1] == "hex" then
+ list[i] = lpegmatch(p_hex_to_utf,li[2])
+ else
+ list[i] = lpegmatch(p_dec_to_utf,li[2])
+ end
+ else
+ -- kern
+ end
+ end
+ elseif operator == "Tj" or operator == "'" or operator == '"' then -- { string, Tj } { string, ' } { n, m, string, " }
+ local list = entry[size-1]
+ if list[1] == "hex" then
+ list[2] = lpegmatch(p_hex_to_utf,li[2])
+ else
+ list[2] = lpegmatch(p_dec_to_utf,li[2])
+ end
+ end
+ end
+
+ unic = nil -- can be collected
+
+ return list
+
+end
+
+-- This is also an experiment. When I really neet it I can improve it, fo rinstance
+-- with proper position calculating. It might be usefull for some search or so.
+
+local softhyphen = utfchar(0xAD) .. "$"
+local linefactor = 1.3
+
+function lpdf_epdf.contenttotext(document,list) -- maybe signal fonts
+ local last_y = 0
+ local last_f = 0
+ local text = { }
+ local last = 0
+
+ for i=1,#list do
+ local entry = list[i]
+ local size = #entry
+ local operator = entry[size]
+ if operator == "Tf" then
+ last_f = entry[2]
+ elseif operator == "TJ" then
+ local list = entry[1]
+ for i=1,#list do
+ local li = list[i]
+ if type(li) == "string" then
+ last = last + 1
+ text[last] = li
+ elseif li < -50 then
+ last = last + 1
+ text[last] = " "
+ end
+ end
+ line = concat(list)
+ elseif operator == "Tj" then
+ last = last + 1
+ text[last] = entry[size-1]
+ elseif operator == "cm" or operator == "Tm" then
+ local ty = entry[6]
+ local dy = abs(last_y - ty)
+ if dy > linefactor*last_f then
+ if last > 0 then
+ if find(text[last],softhyphen) then
+ -- ignore
+ else
+ last = last + 1
+ text[last] = "\n"
+ end
+ end
+ end
+ last_y = ty
+ end
+ end
+
+ return concat(text)
+end
+
+function lpdf_epdf.getstructure(document,list) -- just a test
+ local depth = 0
+ for i=1,#list do
+ local entry = list[i]
+ local size = #entry
+ local operator = entry[size]
+ if operator == "BDC" then
+ report_epdf("%w%s : %s",depth,entry[1] or "?",entry[2].MCID or "?")
+ depth = depth + 1
+ elseif operator == "EMC" then
+ depth = depth - 1
+ elseif operator == "TJ" then
+ local list = entry[1]
+ for i=1,#list do
+ local li = list[i]
+ if type(li) == "string" then
+ report_epdf("%w > %s",depth,li)
+ elseif li < -50 then
+ report_epdf("%w >",depth,li)
+ end
+ end
+ elseif operator == "Tj" then
+ report_epdf("%w > %s",depth,entry[size-1])
+ end
+ end
+end
+
+-- document.Catalog.StructTreeRoot.ParentTree.Nums[2][1].A.P[1])
+
-- helpers
--- function lpdf.epdf.getdestinationpage(document,name)
--- local destination = document.data:findDest(name)
+-- function lpdf_epdf.getdestinationpage(document,name)
+-- local destination = document.__data__:findDest(name)
-- return destination and destination.number
-- end
diff --git a/Master/texmf-dist/tex/context/base/lpdf-fld.lua b/Master/texmf-dist/tex/context/base/lpdf-fld.lua
index 414562ad58a..f0aad36237c 100644
--- a/Master/texmf-dist/tex/context/base/lpdf-fld.lua
+++ b/Master/texmf-dist/tex/context/base/lpdf-fld.lua
@@ -280,10 +280,8 @@ end
local pdfdocencodingvector, pdfdocencodingcapsule
--- The pdf doc encoding vector is needed in order to
--- trigger propper unicode. Interesting is that when
--- a glyph is not in the vector, it is still visible
--- as it is taken from some other font. Messy.
+-- The pdf doc encoding vector is needed in order to trigger propper unicode. Interesting is that when
+-- a glyph is not in the vector, it is still visible as it is taken from some other font. Messy.
-- To be checked: only when text/line fields.
@@ -334,7 +332,7 @@ local function fieldsurrounding(specification)
local fontsize = specification.fontsize or "12pt"
local fontstyle = specification.fontstyle or "rm"
local fontalternative = specification.fontalternative or "tf"
- local colorvalue = specification.colorvalue
+ local colorvalue = tonumber(specification.colorvalue)
local s = fontnames[fontstyle]
if not s then
fontstyle, s = "rm", fontnames.rm
diff --git a/Master/texmf-dist/tex/context/base/lpdf-fmt.lua b/Master/texmf-dist/tex/context/base/lpdf-fmt.lua
index 568b801b493..862c011b8a0 100644
--- a/Master/texmf-dist/tex/context/base/lpdf-fmt.lua
+++ b/Master/texmf-dist/tex/context/base/lpdf-fmt.lua
@@ -710,7 +710,9 @@ function codeinjections.setformat(s)
end
end
function codeinjections.setformat(noname)
- report_backend("error, format is already set to %a, ignoring %a",formatname,noname.format)
+ if trace_format then
+ report_backend("error, format is already set to %a, ignoring %a",formatname,noname.format)
+ end
end
else
report_backend("error, format %a is not supported",format)
@@ -732,9 +734,11 @@ directives.register("backend.format", function(v) -- table !
end
end)
-function commands.setformat(s)
- codeinjections.setformat(s)
-end
+interfaces.implement {
+ name = "setformat",
+ actions = codeinjections.setformat,
+ arguments = { { "*" } }
+}
function codeinjections.getformatoption(key)
return formatspecification and formatspecification[key]
diff --git a/Master/texmf-dist/tex/context/base/lpdf-grp.lua b/Master/texmf-dist/tex/context/base/lpdf-grp.lua
index b3cc7ce1f5f..36c3507bed2 100644
--- a/Master/texmf-dist/tex/context/base/lpdf-grp.lua
+++ b/Master/texmf-dist/tex/context/base/lpdf-grp.lua
@@ -118,7 +118,7 @@ function nodeinjections.injectbitmap(t)
height = width * yresolution / xresolution
end
local image = img.new {
- stream = format(template,d(),t.data),
+ stream = formatters[template](d(),t.data),
width = width,
height = height,
bbox = { 0, 0, urx, ury },
diff --git a/Master/texmf-dist/tex/context/base/lpdf-ini.lua b/Master/texmf-dist/tex/context/base/lpdf-ini.lua
index 025f62c4f84..834f845c59a 100644
--- a/Master/texmf-dist/tex/context/base/lpdf-ini.lua
+++ b/Master/texmf-dist/tex/context/base/lpdf-ini.lua
@@ -6,17 +6,27 @@ if not modules then modules = { } end modules ['lpdf-ini'] = {
license = "see context related readme files"
}
+-- beware of "too many locals" here
+
local setmetatable, getmetatable, type, next, tostring, tonumber, rawset = setmetatable, getmetatable, type, next, tostring, tonumber, rawset
local char, byte, format, gsub, concat, match, sub, gmatch = string.char, string.byte, string.format, string.gsub, table.concat, string.match, string.sub, string.gmatch
-local utfchar, utfvalues = utf.char, utf.values
+local utfchar, utfbyte, utfvalues = utf.char, utf.byte, utf.values
local sind, cosd, floor, max, min = math.sind, math.cosd, math.floor, math.max, math.min
local lpegmatch, P, C, R, S, Cc, Cs = lpeg.match, lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cc, lpeg.Cs
local formatters = string.formatters
+local isboolean = string.is_boolean
local report_objects = logs.reporter("backend","objects")
local report_finalizing = logs.reporter("backend","finalizing")
local report_blocked = logs.reporter("backend","blocked")
+local implement = interfaces.implement
+local two_strings = interfaces.strings[2]
+
+-- In ConTeXt MkIV we use utf8 exclusively so all strings get mapped onto a hex
+-- encoded utf16 string type between <>. We could probably save some bytes by using
+-- strings between () but then we end up with escaped ()\ too.
+
-- gethpos : used
-- getpos : used
-- getvpos : used
@@ -56,9 +66,9 @@ local pdf = pdf
local factor = number.dimenfactors.bp
if pdf.setinfo then
--- table.setmetatablenewindex(pdf,function(t,k,v)
--- report_blocked("'pdf.%s' is not supported",k)
--- end)
+ -- table.setmetatablenewindex(pdf,function(t,k,v)
+ -- report_blocked("'pdf.%s' is not supported",k)
+ -- end)
-- the getters are harmless
end
@@ -103,15 +113,27 @@ local pdfimmediateobject = pdf.immediateobj
local pdfdeferredobject = pdf.obj
local pdfreferenceobject = pdf.refobj
-function pdf.setinfo () report_blocked("'pdf.%s' is not supported","setinfo") end -- use lpdf.addtoinfo etc
-function pdf.setcatalog () report_blocked("'pdf.%s' is not supported","setcatalog") end
-function pdf.setnames () report_blocked("'pdf.%s' is not supported","setnames") end
-function pdf.settrailer () report_blocked("'pdf.%s' is not supported","settrailer") end
-function pdf.setpageresources () report_blocked("'pdf.%s' is not supported","setpageresources") end
-function pdf.setpageattributes () report_blocked("'pdf.%s' is not supported","setpageattributes") end
-function pdf.setpagesattributes() report_blocked("'pdf.%s' is not supported","setpagesattributes") end
+-- function pdf.setinfo () report_blocked("'pdf.%s' is not supported","setinfo") end -- use lpdf.addtoinfo etc
+-- function pdf.setcatalog () report_blocked("'pdf.%s' is not supported","setcatalog") end
+-- function pdf.setnames () report_blocked("'pdf.%s' is not supported","setnames") end
+-- function pdf.settrailer () report_blocked("'pdf.%s' is not supported","settrailer") end
+-- function pdf.setpageresources () report_blocked("'pdf.%s' is not supported","setpageresources") end
+-- function pdf.setpageattributes () report_blocked("'pdf.%s' is not supported","setpageattributes") end
+-- function pdf.setpagesattributes() report_blocked("'pdf.%s' is not supported","setpagesattributes") end
+-- function pdf.registerannot () report_blocked("'pdf.%s' is not supported","registerannot") end
+
+local function pdfdisablecommand(command)
+ pdf[command] = function() report_blocked("'pdf.%s' is not supported",command) end
+end
-function pdf.registerannot() report_blocked("'pdf.%s' is not supported","registerannot") end
+pdfdisablecommand("setinfo")
+pdfdisablecommand("setcatalog")
+pdfdisablecommand("setnames")
+pdfdisablecommand("settrailer")
+pdfdisablecommand("setpageresources")
+pdfdisablecommand("setpageattributes")
+pdfdisablecommand("setpagesattributes")
+pdfdisablecommand("registerannot")
local trace_finalizers = false trackers.register("backend.finalizers", function(v) trace_finalizers = v end)
local trace_resources = false trackers.register("backend.resources", function(v) trace_resources = v end)
@@ -180,67 +202,112 @@ function lpdf.rectangle(width,height,depth)
end
end
---
+-- we could use a hash of predefined unicodes
+
+-- local function tosixteen(str) -- an lpeg might be faster (no table)
+-- if not str or str == "" then
+-- return "" -- not () as we want an indication that it's unicode
+-- else
+-- local r, n = { ""
+-- return concat(r)
+-- end
+-- end
+
+local cache = table.setmetatableindex(function(t,k) -- can be made weak
+ local v = utfbyte(k)
+ if v < 0x10000 then
+ v = format("%04x",v)
+ else
+ -- v = format("%04x%04x",v/1024+0xD800,v%1024+0xDC00)
+ v = format("%04x%04x",floor(v/1024),v%1024+0xDC00)
+ end
+ t[k] = v
+ return v
+end)
+
+local escaped = Cs(Cc("(") * (S("\\()")/"\\%0" + P(1))^0 * Cc(")"))
+local unified = Cs(Cc(""))
local function tosixteen(str) -- an lpeg might be faster (no table)
if not str or str == "" then
return "" -- not () as we want an indication that it's unicode
else
- local r, n = { ""
- return concat(r)
+ return lpegmatch(unified,str)
end
end
-lpdf.tosixteen = tosixteen
+local more = 0
+
+local pattern = C(4) / function(s) -- needs checking !
+ local now = tonumber(s,16)
+ if more > 0 then
+ now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong
+ more = 0
+ return utfchar(now)
+ elseif now >= 0xD800 and now <= 0xDBFF then
+ more = now
+ return "" -- else the c's end up in the stream
+ else
+ return utfchar(now)
+ end
+end
--- lpeg is some 5 times faster than gsub (in test) on escaping
+local pattern = P(true) / function() more = 0 end * Cs(pattern^0)
--- local escapes = {
--- ["\\"] = "\\\\",
--- ["/"] = "\\/", ["#"] = "\\#",
--- ["<"] = "\\<", [">"] = "\\>",
--- ["["] = "\\[", ["]"] = "\\]",
--- ["("] = "\\(", [")"] = "\\)",
--- }
---
--- local escaped = Cs(Cc("(") * (S("\\/#<>[]()")/escapes + P(1))^0 * Cc(")"))
---
--- local function toeight(str)
--- if not str or str == "" then
--- return "()"
--- else
--- return lpegmatch(escaped,str)
--- end
--- end
---
--- -- no need for escaping .. just use unicode instead
+local function fromsixteen(str)
+ if not str or str == "" then
+ return ""
+ else
+ return lpegmatch(pattern,str)
+ end
+end
--- \0 \t \n \r \f ( ) [ ] { } / %
+local toregime = regimes.toregime
+local fromregime = regimes.fromregime
-local function toeight(str)
- return "(" .. str .. ")"
+local function topdfdoc(str,default)
+ if not str or str == "" then
+ return ""
+ else
+ return lpegmatch(escaped,toregime("pdfdoc",str,default)) -- could be combined if needed
+ end
end
-lpdf.toeight = toeight
+local function frompdfdoc(str)
+ if not str or str == "" then
+ return ""
+ else
+ return fromregime("pdfdoc",str)
+ end
+end
--- local escaped = lpeg.Cs((lpeg.S("\0\t\n\r\f ()[]{}/%")/function(s) return format("#%02X",byte(s)) end + lpeg.P(1))^0)
---
--- local function cleaned(str)
--- return (str and str ~= "" and lpegmatch(escaped,str)) or ""
--- end
---
--- lpdf.cleaned = cleaned -- not public yet
+if not toregime then topdfdoc = function(s) return s end end
+if not fromregime then frompdfdoc = function(s) return s end end
+
+local function toeight(str)
+ if not str or str == "" then
+ return "()"
+ else
+ return lpegmatch(escaped,str)
+ end
+end
+
+lpdf.tosixteen = tosixteen
+lpdf.toeight = toeight
+lpdf.topdfdoc = topdfdoc
+lpdf.fromsixteen = fromsixteen
+lpdf.frompdfdoc = frompdfdoc
local function merge_t(a,b)
local t = { }
@@ -249,6 +316,7 @@ local function merge_t(a,b)
return setmetatable(t,getmetatable(a))
end
+local f_key_null = formatters["/%s null"]
local f_key_value = formatters["/%s %s"]
local f_key_dictionary = formatters["/%s << % t >>"]
local f_dictionary = formatters["<< % t >>"]
@@ -275,12 +343,17 @@ tostring_d = function(t,contentonly,key)
r[rn] = f_key_value(k,toeight(v))
elseif tv == "number" then
r[rn] = f_key_number(k,v)
- elseif tv == "unicode" then
- r[rn] = f_key_value(k,tosixteen(v))
+ -- elseif tv == "unicode" then -- can't happen
+ -- r[rn] = f_key_value(k,tosixteen(v))
elseif tv == "table" then
local mv = getmetatable(v)
if mv and mv.__lpdftype then
- r[rn] = f_key_value(k,tostring(v))
+ -- if v == t then
+ -- report_objects("ignoring circular reference in dirctionary")
+ -- r[rn] = f_key_null(k)
+ -- else
+ r[rn] = f_key_value(k,tostring(v))
+ -- end
elseif v[1] then
r[rn] = f_key_value(k,tostring_a(v))
else
@@ -315,13 +388,18 @@ tostring_a = function(t,contentonly,key)
r[k] = toeight(v)
elseif tv == "number" then
r[k] = f_tonumber(v)
- elseif tv == "unicode" then
- r[k] = tosixteen(v)
+ -- elseif tv == "unicode" then
+ -- r[k] = tosixteen(v)
elseif tv == "table" then
local mv = getmetatable(v)
local mt = mv and mv.__lpdftype
if mt then
- r[k] = tostring(v)
+ -- if v == t then
+ -- report_objects("ignoring circular reference in array")
+ -- r[k] = "null"
+ -- else
+ r[k] = tostring(v)
+ -- end
elseif v[1] then
r[k] = tostring_a(v)
else
@@ -345,16 +423,17 @@ tostring_a = function(t,contentonly,key)
end
end
-local tostring_x = function(t) return concat(t," ") end
-local tostring_s = function(t) return toeight(t[1]) end
-local tostring_u = function(t) return tosixteen(t[1]) end
-local tostring_n = function(t) return tostring(t[1]) end -- tostring not needed
-local tostring_n = function(t) return f_tonumber(t[1]) end -- tostring not needed
-local tostring_c = function(t) return t[1] end -- already prefixed (hashed)
-local tostring_z = function() return "null" end
-local tostring_t = function() return "true" end
-local tostring_f = function() return "false" end
-local tostring_r = function(t) local n = t[1] return n and n > 0 and (n .. " 0 R") or "NULL" end
+local tostring_x = function(t) return concat(t," ") end
+local tostring_s = function(t) return toeight(t[1]) end
+local tostring_p = function(t) return topdfdoc(t[1],t[2]) end
+local tostring_u = function(t) return tosixteen(t[1]) end
+----- tostring_n = function(t) return tostring(t[1]) end -- tostring not needed
+local tostring_n = function(t) return f_tonumber(t[1]) end -- tostring not needed
+local tostring_c = function(t) return t[1] end -- already prefixed (hashed)
+local tostring_z = function() return "null" end
+local tostring_t = function() return "true" end
+local tostring_f = function() return "false" end
+local tostring_r = function(t) local n = t[1] return n and n > 0 and (n .. " 0 R") or "null" end
local tostring_v = function(t)
local s = t[1]
@@ -365,18 +444,19 @@ local tostring_v = function(t)
end
end
-local function value_x(t) return t end -- the call is experimental
-local function value_s(t,key) return t[1] end -- the call is experimental
-local function value_u(t,key) return t[1] end -- the call is experimental
-local function value_n(t,key) return t[1] end -- the call is experimental
-local function value_c(t) return sub(t[1],2) end -- the call is experimental
-local function value_d(t) return tostring_d(t,true) end -- the call is experimental
-local function value_a(t) return tostring_a(t,true) end -- the call is experimental
-local function value_z() return nil end -- the call is experimental
-local function value_t(t) return t.value or true end -- the call is experimental
-local function value_f(t) return t.value or false end -- the call is experimental
-local function value_r() return t[1] or 0 end -- the call is experimental -- NULL
-local function value_v() return t[1] end -- the call is experimental
+local function value_x(t) return t end
+local function value_s(t) return t[1] end
+local function value_p(t) return t[1] end
+local function value_u(t) return t[1] end
+local function value_n(t) return t[1] end
+local function value_c(t) return sub(t[1],2) end
+local function value_d(t) return tostring_d(t,true) end
+local function value_a(t) return tostring_a(t,true) end
+local function value_z() return nil end
+local function value_t(t) return t.value or true end
+local function value_f(t) return t.value or false end
+local function value_r() return t[1] or 0 end -- null
+local function value_v() return t[1] end
local function add_x(t,k,v) rawset(t,k,tostring(v)) end
@@ -385,6 +465,7 @@ local mt_d = { __lpdftype = "dictionary", __tostring = tostring_d, __call = valu
local mt_a = { __lpdftype = "array", __tostring = tostring_a, __call = value_a }
local mt_u = { __lpdftype = "unicode", __tostring = tostring_u, __call = value_u }
local mt_s = { __lpdftype = "string", __tostring = tostring_s, __call = value_s }
+local mt_p = { __lpdftype = "docstring", __tostring = tostring_p, __call = value_p }
local mt_n = { __lpdftype = "number", __tostring = tostring_n, __call = value_n }
local mt_c = { __lpdftype = "constant", __tostring = tostring_c, __call = value_c }
local mt_z = { __lpdftype = "null", __tostring = tostring_z, __call = value_z }
@@ -418,8 +499,12 @@ local function pdfstring(str,default)
return setmetatable({ str or default or "" },mt_s)
end
+local function pdfdocstring(str,default,defaultchar)
+ return setmetatable({ str or default or "", defaultchar or " " },mt_p)
+end
+
local function pdfunicode(str,default)
- return setmetatable({ str or default or "" },mt_u)
+ return setmetatable({ str or default or "" },mt_u) -- could be a string
end
local cache = { } -- can be weak
@@ -503,6 +588,7 @@ end
lpdf.stream = pdfstream -- THIS WILL PROBABLY CHANGE
lpdf.dictionary = pdfdictionary
lpdf.array = pdfarray
+lpdf.docstring = pdfdocstring
lpdf.string = pdfstring
lpdf.unicode = pdfunicode
lpdf.number = pdfnumber
@@ -532,7 +618,7 @@ end
-- lpdf.object = pdfdeferredobject
-- lpdf.referenceobject = pdfreferenceobject
-local pagereference = pdf.pageref or tex.pdfpageref
+local pagereference = pdf.pageref -- tex.pdfpageref is obsolete
local nofpages = 0
function lpdf.pagereference(n)
@@ -765,108 +851,147 @@ end
callbacks.register("finish_pdffile", lpdf.finalizedocument)
--- some minimal tracing, handy for checking the order
-local function trace_set(what,key)
- if trace_resources then
- report_finalizing("setting key %a in %a",key,what)
- end
-end
-local function trace_flush(what)
- if trace_resources then
- report_finalizing("flushing %a",what)
- end
-end
+do
-lpdf.protectresources = true
+ -- some minimal tracing, handy for checking the order
-local catalog = pdfdictionary { Type = pdfconstant("Catalog") } -- nicer, but when we assign we nil the Type
-local info = pdfdictionary { Type = pdfconstant("Info") } -- nicer, but when we assign we nil the Type
------ names = pdfdictionary { Type = pdfconstant("Names") } -- nicer, but when we assign we nil the Type
+ local function trace_set(what,key)
+ if trace_resources then
+ report_finalizing("setting key %a in %a",key,what)
+ end
+ end
-local function flushcatalog() if not environment.initex then trace_flush("catalog") catalog.Type = nil pdfsetcatalog(catalog()) end end
-local function flushinfo () if not environment.initex then trace_flush("info") info .Type = nil pdfsetinfo (info ()) end end
--------------- flushnames () if not environment.initex then trace_flush("names") names .Type = nil pdfsetnames (names ()) end end
+ local function trace_flush(what)
+ if trace_resources then
+ report_finalizing("flushing %a",what)
+ end
+ end
-function lpdf.addtocatalog(k,v) if not (lpdf.protectresources and catalog[k]) then trace_set("catalog",k) catalog[k] = v end end
-function lpdf.addtoinfo (k,v) if not (lpdf.protectresources and info [k]) then trace_set("info", k) info [k] = v end end
--------- lpdf.addtonames (k,v) if not (lpdf.protectresources and names [k]) then trace_set("names", k) names [k] = v end end
+ lpdf.protectresources = true
-local names = pdfdictionary {
- -- Type = pdfconstant("Names")
-}
+ local catalog = pdfdictionary { Type = pdfconstant("Catalog") } -- nicer, but when we assign we nil the Type
+ local info = pdfdictionary { Type = pdfconstant("Info") } -- nicer, but when we assign we nil the Type
+ ----- names = pdfdictionary { Type = pdfconstant("Names") } -- nicer, but when we assign we nil the Type
-local function flushnames()
- if next(names) and not environment.initex then
- names.Type = pdfconstant("Names")
- trace_flush("names")
- lpdf.addtocatalog("Names",pdfreference(pdfimmediateobject(tostring(names))))
+ local function flushcatalog()
+ if not environment.initex then
+ trace_flush("catalog")
+ catalog.Type = nil
+ pdfsetcatalog(catalog())
+ end
end
-end
-function lpdf.addtonames(k,v)
- if not (lpdf.protectresources and names [k]) then
- trace_set("names", k)
- names [k] = v
+ local function flushinfo()
+ if not environment.initex then
+ trace_flush("info")
+ info.Type = nil
+ pdfsetinfo(info())
+ end
end
-end
-local dummy = pdfreserveobject() -- else bug in hvmd due so some internal luatex conflict
+ -- local function flushnames()
+ -- if not environment.initex then
+ -- trace_flush("names")
+ -- names.Type = nil
+ -- pdfsetnames(names())
+ -- end
+ -- end
+
+ function lpdf.addtocatalog(k,v)
+ if not (lpdf.protectresources and catalog[k]) then
+ trace_set("catalog",k)
+ catalog[k] = v
+ end
+ end
--- Some day I will implement a proper minimalized resource management.
+ function lpdf.addtoinfo(k,v)
+ if not (lpdf.protectresources and info[k]) then
+ trace_set("info",k)
+ info[k] = v
+ end
+ end
-local r_extgstates, d_extgstates = pdfreserveobject(), pdfdictionary() local p_extgstates = pdfreference(r_extgstates)
-local r_colorspaces, d_colorspaces = pdfreserveobject(), pdfdictionary() local p_colorspaces = pdfreference(r_colorspaces)
-local r_patterns, d_patterns = pdfreserveobject(), pdfdictionary() local p_patterns = pdfreference(r_patterns)
-local r_shades, d_shades = pdfreserveobject(), pdfdictionary() local p_shades = pdfreference(r_shades)
+ -- local function lpdf.addtonames(k,v)
+ -- if not (lpdf.protectresources and names[k]) then
+ -- trace_set("names",k)
+ -- names[k] = v
+ -- end
+ -- end
-local function checkextgstates () if next(d_extgstates ) then addtopageresources("ExtGState", p_extgstates ) end end
-local function checkcolorspaces() if next(d_colorspaces) then addtopageresources("ColorSpace",p_colorspaces) end end
-local function checkpatterns () if next(d_patterns ) then addtopageresources("Pattern", p_patterns ) end end
-local function checkshades () if next(d_shades ) then addtopageresources("Shading", p_shades ) end end
+ local names = pdfdictionary {
+ -- Type = pdfconstant("Names")
+ }
-local function flushextgstates () if next(d_extgstates ) then trace_flush("extgstates") pdfimmediateobject(r_extgstates, tostring(d_extgstates )) end end
-local function flushcolorspaces() if next(d_colorspaces) then trace_flush("colorspaces") pdfimmediateobject(r_colorspaces,tostring(d_colorspaces)) end end
-local function flushpatterns () if next(d_patterns ) then trace_flush("patterns") pdfimmediateobject(r_patterns, tostring(d_patterns )) end end
-local function flushshades () if next(d_shades ) then trace_flush("shades") pdfimmediateobject(r_shades, tostring(d_shades )) end end
+ local function flushnames()
+ if next(names) and not environment.initex then
+ names.Type = pdfconstant("Names")
+ trace_flush("names")
+ lpdf.addtocatalog("Names",pdfreference(pdfimmediateobject(tostring(names))))
+ end
+ end
-function lpdf.collectedresources()
- local ExtGState = next(d_extgstates ) and p_extgstates
- local ColorSpace = next(d_colorspaces) and p_colorspaces
- local Pattern = next(d_patterns ) and p_patterns
- local Shading = next(d_shades ) and p_shades
- if ExtGState or ColorSpace or Pattern or Shading then
- local collected = pdfdictionary {
- ExtGState = ExtGState,
- ColorSpace = ColorSpace,
- Pattern = Pattern,
- Shading = Shading,
- -- ProcSet = pdfarray { pdfconstant("PDF") },
- }
- return collected()
- else
- return ""
+ function lpdf.addtonames(k,v)
+ if not (lpdf.protectresources and names[k]) then
+ trace_set("names", k)
+ names [k] = v
+ end
+ end
+
+ local r_extgstates, d_extgstates = pdfreserveobject(), pdfdictionary() local p_extgstates = pdfreference(r_extgstates)
+ local r_colorspaces, d_colorspaces = pdfreserveobject(), pdfdictionary() local p_colorspaces = pdfreference(r_colorspaces)
+ local r_patterns, d_patterns = pdfreserveobject(), pdfdictionary() local p_patterns = pdfreference(r_patterns)
+ local r_shades, d_shades = pdfreserveobject(), pdfdictionary() local p_shades = pdfreference(r_shades)
+
+ local function checkextgstates () if next(d_extgstates ) then addtopageresources("ExtGState", p_extgstates ) end end
+ local function checkcolorspaces() if next(d_colorspaces) then addtopageresources("ColorSpace",p_colorspaces) end end
+ local function checkpatterns () if next(d_patterns ) then addtopageresources("Pattern", p_patterns ) end end
+ local function checkshades () if next(d_shades ) then addtopageresources("Shading", p_shades ) end end
+
+ local function flushextgstates () if next(d_extgstates ) then trace_flush("extgstates") pdfimmediateobject(r_extgstates, tostring(d_extgstates )) end end
+ local function flushcolorspaces() if next(d_colorspaces) then trace_flush("colorspaces") pdfimmediateobject(r_colorspaces,tostring(d_colorspaces)) end end
+ local function flushpatterns () if next(d_patterns ) then trace_flush("patterns") pdfimmediateobject(r_patterns, tostring(d_patterns )) end end
+ local function flushshades () if next(d_shades ) then trace_flush("shades") pdfimmediateobject(r_shades, tostring(d_shades )) end end
+
+ function lpdf.collectedresources()
+ local ExtGState = next(d_extgstates ) and p_extgstates
+ local ColorSpace = next(d_colorspaces) and p_colorspaces
+ local Pattern = next(d_patterns ) and p_patterns
+ local Shading = next(d_shades ) and p_shades
+ if ExtGState or ColorSpace or Pattern or Shading then
+ local collected = pdfdictionary {
+ ExtGState = ExtGState,
+ ColorSpace = ColorSpace,
+ Pattern = Pattern,
+ Shading = Shading,
+ -- ProcSet = pdfarray { pdfconstant("PDF") },
+ }
+ return collected()
+ else
+ return ""
+ end
end
-end
-function lpdf.adddocumentextgstate (k,v) d_extgstates [k] = v end
-function lpdf.adddocumentcolorspace(k,v) d_colorspaces[k] = v end
-function lpdf.adddocumentpattern (k,v) d_patterns [k] = v end
-function lpdf.adddocumentshade (k,v) d_shades [k] = v end
+ function lpdf.adddocumentextgstate (k,v) d_extgstates [k] = v end
+ function lpdf.adddocumentcolorspace(k,v) d_colorspaces[k] = v end
+ function lpdf.adddocumentpattern (k,v) d_patterns [k] = v end
+ function lpdf.adddocumentshade (k,v) d_shades [k] = v end
-registerdocumentfinalizer(flushextgstates,3,"extended graphic states")
-registerdocumentfinalizer(flushcolorspaces,3,"color spaces")
-registerdocumentfinalizer(flushpatterns,3,"patterns")
-registerdocumentfinalizer(flushshades,3,"shades")
+ registerdocumentfinalizer(flushextgstates,3,"extended graphic states")
+ registerdocumentfinalizer(flushcolorspaces,3,"color spaces")
+ registerdocumentfinalizer(flushpatterns,3,"patterns")
+ registerdocumentfinalizer(flushshades,3,"shades")
-registerdocumentfinalizer(flushnames,3,"names") -- before catalog
-registerdocumentfinalizer(flushcatalog,3,"catalog")
-registerdocumentfinalizer(flushinfo,3,"info")
+ registerdocumentfinalizer(flushnames,3,"names") -- before catalog
+ registerdocumentfinalizer(flushcatalog,3,"catalog")
+ registerdocumentfinalizer(flushinfo,3,"info")
-registerpagefinalizer(checkextgstates,3,"extended graphic states")
-registerpagefinalizer(checkcolorspaces,3,"color spaces")
-registerpagefinalizer(checkpatterns,3,"patterns")
-registerpagefinalizer(checkshades,3,"shades")
+ registerpagefinalizer(checkextgstates,3,"extended graphic states")
+ registerpagefinalizer(checkcolorspaces,3,"color spaces")
+ registerpagefinalizer(checkpatterns,3,"patterns")
+ registerpagefinalizer(checkshades,3,"shades")
+
+end
-- in strc-bkm: lpdf.registerdocumentfinalizer(function() structures.bookmarks.place() end,1)
@@ -877,54 +1002,78 @@ end
-- ! -> universaltime
-local timestamp = os.date("%Y-%m-%dT%X") .. os.timezone(true)
+do
-function lpdf.timestamp()
- return timestamp
-end
+ local timestamp = os.date("%Y-%m-%dT%X") .. os.timezone(true)
-function lpdf.pdftimestamp(str)
- local Y, M, D, h, m, s, Zs, Zh, Zm = match(str,"^(%d%d%d%d)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)([%+%-])(%d%d):(%d%d)$")
- return Y and format("D:%s%s%s%s%s%s%s%s'%s'",Y,M,D,h,m,s,Zs,Zh,Zm)
-end
+ function lpdf.timestamp()
+ return timestamp
+ end
+
+ function lpdf.pdftimestamp(str)
+ local Y, M, D, h, m, s, Zs, Zh, Zm = match(str,"^(%d%d%d%d)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)([%+%-])(%d%d):(%d%d)$")
+ return Y and format("D:%s%s%s%s%s%s%s%s'%s'",Y,M,D,h,m,s,Zs,Zh,Zm)
+ end
+
+ function lpdf.id()
+ return format("%s.%s",tex.jobname,timestamp)
+ end
-function lpdf.id()
- return format("%s.%s",tex.jobname,timestamp)
end
+-- return nil is nicer in test prints
+
function lpdf.checkedkey(t,key,variant)
local pn = t and t[key]
- if pn then
+ if pn ~= nil then
local tn = type(pn)
if tn == variant then
if variant == "string" then
- return pn ~= "" and pn or nil
+ if pn ~= "" then
+ return pn
+ end
elseif variant == "table" then
- return next(pn) and pn or nil
+ if next(pn) then
+ return pn
+ end
else
return pn
end
- elseif tn == "string" and variant == "number" then
- return tonumber(pn)
+ elseif tn == "string" then
+ if variant == "number" then
+ return tonumber(pn)
+ elseif variant == "boolean" then
+ return isboolean(pn,nil,true)
+ end
end
end
+ -- return nil
end
function lpdf.checkedvalue(value,variant) -- code not shared
- if value then
+ if value ~= nil then
local tv = type(value)
if tv == variant then
if variant == "string" then
- return value ~= "" and value
+ if value ~= "" then
+ return value
+ end
elseif variant == "table" then
- return next(value) and value
+ if next(value) then
+ return value
+ end
else
return value
end
- elseif tv == "string" and variant == "number" then
- return tonumber(value)
+ elseif tv == "string" then
+ if variant == "number" then
+ return tonumber(value)
+ elseif variant == "boolean" then
+ return isboolean(value,nil,true)
+ end
end
end
+ -- return nil
end
function lpdf.limited(n,min,max,default)
@@ -944,10 +1093,11 @@ function lpdf.limited(n,min,max,default)
end
end
--- lpdf.addtoinfo("ConTeXt.Version", tex.contextversiontoks)
+-- lpdf.addtoinfo("ConTeXt.Version", environment.version)
-- lpdf.addtoinfo("ConTeXt.Time", os.date("%Y.%m.%d %H:%M")) -- :%S
-- lpdf.addtoinfo("ConTeXt.Jobname", environment.jobname)
-- lpdf.addtoinfo("ConTeXt.Url", "www.pragma-ade.com")
+-- lpdf.addtoinfo("ConTeXt.Support", "contextgarden.net")
-- if not pdfreferenceobject then
--
@@ -1002,3 +1152,62 @@ end
-- end
-- end,
-- })
+
+
+-- The next variant of ActualText is what Taco and I could come up with
+-- eventually. As of September 2013 Acrobat copies okay, Sumatra copies a
+-- question mark, pdftotext injects an extra space and Okular adds a
+-- newline plus space.
+
+-- return formatters["BT /Span << /ActualText (CONTEXT) >> BDC [] TJ % t EMC ET"](code)
+
+do
+
+ local f_actual_text_one = formatters["BT /Span << /ActualText >> BDC [] TJ %s EMC ET"]
+ local f_actual_text_two = formatters["BT /Span << /ActualText >> BDC [] TJ %s EMC ET"]
+ local f_actual_text = formatters["/Span <> BDC"]
+
+ local context = context
+ local pdfdirect = nodes.pool.pdfdirect
+
+ function codeinjections.unicodetoactualtext(unicode,pdfcode)
+ if unicode < 0x10000 then
+ return f_actual_text_one(unicode,pdfcode)
+ else
+ return f_actual_text_two(unicode/1024+0xD800,unicode%1024+0xDC00,pdfcode)
+ end
+ end
+
+ implement {
+ name = "startactualtext",
+ arguments = "string",
+ actions = function(str)
+ context(pdfdirect(f_actual_text(tosixteen(str))))
+ end
+ }
+
+ implement {
+ name = "stopactualtext",
+ actions = function()
+ context(pdfdirect("EMC"))
+ end
+ }
+
+end
+
+-- interface
+
+local lpdfverbose = lpdf.verbose
+
+implement { name = "lpdf_collectedresources", actions = { lpdf.collectedresources, context } }
+implement { name = "lpdf_addtocatalog", arguments = two_strings, actions = lpdf.addtocatalog }
+implement { name = "lpdf_addtoinfo", arguments = two_strings, actions = lpdf.addtoinfo }
+implement { name = "lpdf_addtonames", arguments = two_strings, actions = lpdf.addtonames }
+implement { name = "lpdf_addpageattributes", arguments = two_strings, actions = lpdf.addtopageattributes }
+implement { name = "lpdf_addpagesattributes", arguments = two_strings, actions = lpdf.addtopagesattributes }
+implement { name = "lpdf_addpageresources", arguments = two_strings, actions = lpdf.addtopageresources }
+implement { name = "lpdf_adddocumentextgstate", arguments = two_strings, actions = function(a,b) lpdf.adddocumentextgstate (a,lpdfverbose(b)) end }
+implement { name = "lpdf_adddocumentcolorspace", arguments = two_strings, actions = function(a,b) lpdf.adddocumentcolorspace(a,lpdfverbose(b)) end }
+implement { name = "lpdf_adddocumentpattern", arguments = two_strings, actions = function(a,b) lpdf.adddocumentpattern (a,lpdfverbose(b)) end }
+implement { name = "lpdf_adddocumentshade", arguments = two_strings, actions = function(a,b) lpdf.adddocumentshade (a,lpdfverbose(b)) end }
+
diff --git a/Master/texmf-dist/tex/context/base/lpdf-mis.lua b/Master/texmf-dist/tex/context/base/lpdf-mis.lua
index 6efbd38820e..a1b12d8c0bb 100644
--- a/Master/texmf-dist/tex/context/base/lpdf-mis.lua
+++ b/Master/texmf-dist/tex/context/base/lpdf-mis.lua
@@ -241,67 +241,93 @@ lpdf.registerdocumentfinalizer(flushjavascripts,"javascripts")
-- -- --
local pagespecs = {
- [variables.max] = { "FullScreen", false, false },
- [variables.bookmark] = { "UseOutlines", false, false },
- [variables.fit] = { "UseNone", false, true },
- [variables.doublesided] = { "UseNone", "TwoColumnRight", true },
- [variables.singlesided] = { "UseNone", false, false },
- [variables.default] = { "UseNone", "auto", false },
- [variables.auto] = { "UseNone", "auto", false },
- [variables.none] = { false, false, false },
+ [variables.max] = { mode = "FullScreen", layout = false, fit = false, fixed = false, duplex = false },
+ [variables.bookmark] = { mode = "UseOutlines", layout = false, fit = false, fixed = false, duplex = false },
+ [variables.fit] = { mode = "UseNone", layout = false, fit = true, fixed = false, duplex = false },
+ [variables.doublesided] = { mode = "UseNone", layout = "TwoColumnRight", fit = true, fixed = false, duplex = false },
+ [variables.singlesided] = { mode = "UseNone", layout = false, fit = false, fixed = false, duplex = false },
+ [variables.default] = { mode = "UseNone", layout = "auto", fit = false, fixed = false, duplex = false },
+ [variables.auto] = { mode = "UseNone", layout = "auto", fit = false, fixed = false, duplex = false },
+ [variables.none] = { mode = false, layout = false, fit = false, fixed = false, duplex = false },
+ -- new
+ [variables.fixed] = { mode = "UseNone", layout = "auto", fit = false, fixed = true, duplex = false }, -- noscale
+ [variables.landscape] = { mode = "UseNone", layout = "auto", fit = false, fixed = true, duplex = "DuplexFlipShortEdge" },
+ [variables.portrait] = { mode = "UseNone", layout = "auto", fit = false, fixed = true, duplex = "DuplexFlipLongEdge" },
+
}
local pagespec, topoffset, leftoffset, height, width, doublesided = "default", 0, 0, 0, 0, false
+local pdfpaperheight = tex.pdfpageheight
+local pdfpaperwidth = tex.pdfpagewidth
+
function codeinjections.setupcanvas(specification)
local paperheight = specification.paperheight
local paperwidth = specification.paperwidth
local paperdouble = specification.doublesided
if paperheight then
texset('global','pdfpageheight',paperheight)
+ pdfpaperheight = paperheight
end
if paperwidth then
texset('global','pdfpagewidth',paperwidth)
+ pdfpaperwidth = paperwidth
end
pagespec = specification.mode or pagespec
topoffset = specification.topoffset or 0
leftoffset = specification.leftoffset or 0
- height = specification.height or tex.pdfpageheight
- width = specification.width or tex.pdfpagewidth
+ height = specification.height or pdfpaperheight
+ width = specification.width or pdfpaperwidth
if paperdouble ~= nil then
doublesided = paperdouble
end
end
local function documentspecification()
+ if not pagespec or pagespec == "" then
+ pagespec = variables.default
+ end
+ -- local settings = utilities.parsers.settings_to_array(pagespec)
+ -- local spec = pagespecs[variables.default]
+ -- for i=1,#settings do
+ -- local s = pagespecs[settings[i]]
+ -- if s then
+ -- for k, v in next, s do
+ -- spec[k] = v
+ -- end
+ -- end
+ -- end
local spec = pagespecs[pagespec] or pagespecs[variables.default]
- if spec then
- local mode, layout, fit = spec[1], spec[2], spec[3]
- if layout == variables.auto then
- if doublesided then
- spec = pagespecs[variables.doublesided] -- to be checked voor interfaces
- if spec then
- mode, layout, fit = spec[1], spec[2], spec[3]
- end
- else
- layout = false
+ if spec.layout == "auto" then
+ if doublesided then
+ local s = pagespecs[variables.doublesided] -- to be checked voor interfaces
+ for k, v in next, s do
+ spec[k] = v
end
+ else
+ spec.layout = false
end
- mode = mode and pdfconstant(mode)
- layout = layout and pdfconstant(layout)
- fit = fit and pdfdictionary { FitWindow = true }
- if layout then
- addtocatalog("PageLayout",layout)
- end
- if mode then
- addtocatalog("PageMode",mode)
- end
- if fit then
- addtocatalog("ViewerPreferences",fit)
- end
- addtoinfo ("Trapped", pdfconstant("False")) -- '/Trapped' in /Info, 'Trapped' in XMP
- addtocatalog("Version", pdfconstant(format("1.%s",tex.pdfminorversion)))
end
+ local layout = spec.layout
+ local mode = spec.mode
+ local fit = spec.fit
+ local fixed = spec.fixed
+ local duplex = spec.duplex
+ if layout then
+ addtocatalog("PageLayout",pdfconstant(layout))
+ end
+ if mode then
+ addtocatalog("PageMode",pdfconstant(mode))
+ end
+ if fit or fixed or duplex then
+ addtocatalog("ViewerPreferences",pdfdictionary {
+ FitWindow = fit and true or nil,
+ PrintScaling = fixed and pdfconstant("None") or nil,
+ Duplex = duplex and pdfconstant(duplex) or nil,
+ })
+ end
+ addtoinfo ("Trapped", pdfconstant("False")) -- '/Trapped' in /Info, 'Trapped' in XMP
+ addtocatalog("Version", pdfconstant(format("1.%s",tex.pdfminorversion)))
end
-- temp hack: the mediabox is not under our control and has a precision of 4 digits
@@ -313,7 +339,7 @@ local function boxvalue(n) -- we could share them
end
local function pagespecification()
- local pageheight = tex.pdfpageheight
+ local pageheight = pdfpaperheight
local box = pdfarray { -- can be cached
boxvalue(leftoffset),
boxvalue(pageheight+topoffset-height),
diff --git a/Master/texmf-dist/tex/context/base/lpdf-pda.xml b/Master/texmf-dist/tex/context/base/lpdf-pda.xml
index 2d8e7b6f59f..3f6b969c01d 100644
--- a/Master/texmf-dist/tex/context/base/lpdf-pda.xml
+++ b/Master/texmf-dist/tex/context/base/lpdf-pda.xml
@@ -3,15 +3,20 @@
+
application/pdf
-
+
-
+
+
+
+
+
diff --git a/Master/texmf-dist/tex/context/base/lpdf-pdx.xml b/Master/texmf-dist/tex/context/base/lpdf-pdx.xml
index 42e11650e71..d55e1fdf303 100644
--- a/Master/texmf-dist/tex/context/base/lpdf-pdx.xml
+++ b/Master/texmf-dist/tex/context/base/lpdf-pdx.xml
@@ -8,10 +8,14 @@
application/pdf
-
+
-
+
+
+
+
+
diff --git a/Master/texmf-dist/tex/context/base/lpdf-ren.lua b/Master/texmf-dist/tex/context/base/lpdf-ren.lua
index 37b70642076..61676d5a81a 100644
--- a/Master/texmf-dist/tex/context/base/lpdf-ren.lua
+++ b/Master/texmf-dist/tex/context/base/lpdf-ren.lua
@@ -54,12 +54,27 @@ local pdf_ocg = pdfconstant("OCG")
local pdf_ocmd = pdfconstant("OCMD")
local pdf_off = pdfconstant("OFF")
local pdf_on = pdfconstant("ON")
+local pdf_view = pdfconstant("View")
+local pdf_design = pdfconstant("Design")
local pdf_toggle = pdfconstant("Toggle")
local pdf_setocgstate = pdfconstant("SetOCGState")
local copy_node = node.copy
-local lpdf_usage = pdfdictionary { Print = pdfdictionary { PrintState = pdf_off } }
+local pdf_print = {
+ [v_yes] = pdfdictionary { PrintState = pdf_on },
+ [v_no ] = pdfdictionary { PrintState = pdf_off },
+}
+
+local pdf_intent = {
+ [v_yes] = pdf_view,
+ [v_no] = pdf_design,
+}
+
+local pdf_export = {
+ [v_yes] = pdf_on,
+ [v_no] = pdf_off,
+}
-- We can have references to layers before they are places, for instance from
-- hide and vide actions. This is why we need to be able to force usage of layers
@@ -99,10 +114,13 @@ local function useviewerlayer(name) -- move up so that we can use it as local
local nn = pdfreserveobject()
local nr = pdfreference(nn)
local nd = pdfdictionary {
- Type = pdf_ocg,
- Name = specification.title or "unknown",
- Intent = ((specification.editable ~= v_no) and pdf_design) or nil, -- disable layer hiding by user
- Usage = ((specification.printable == v_no) and lpdf_usage) or nil, -- printable or not
+ Type = pdf_ocg,
+ Name = specification.title or "unknown",
+ Usage = {
+ Intent = pdf_intent[specification.editable or v_yes], -- disable layer hiding by user (useless)
+ Print = pdf_print [specification.printable or v_yes], -- printable or not
+ Export = pdf_export[specification.export or v_yes], -- export or not
+ },
}
cache[#cache+1] = { nn, nd }
pdfln[tag] = nr -- was n
@@ -165,6 +183,14 @@ local function flushtextlayers()
ON = videlayers,
OFF = hidelayers,
BaseState = pdf_on,
+
+AS = pdfarray {
+ pdfdictionary {
+ Category = pdfarray { pdfconstant("Print") },
+ Event = pdfconstant("Print"),
+ OCGs = (viewerlayers.hasorder and sortedlayers) or nil,
+ }
+},
},
}
addtocatalog("OCProperties",d)
diff --git a/Master/texmf-dist/tex/context/base/lpdf-tag.lua b/Master/texmf-dist/tex/context/base/lpdf-tag.lua
index 276816e8041..dbe4d3f1ee7 100644
--- a/Master/texmf-dist/tex/context/base/lpdf-tag.lua
+++ b/Master/texmf-dist/tex/context/base/lpdf-tag.lua
@@ -8,8 +8,10 @@ if not modules then modules = { } end modules ['lpdf-tag'] = {
local next = next
local format, match, concat = string.format, string.match, table.concat
-local lpegmatch = lpeg.match
+local lpegmatch, P, S, C = lpeg.match, lpeg.P, lpeg.S, lpeg.C
local utfchar = utf.char
+local settings_to_hash = utilities.parsers.settings_to_hash
+local formatters = string.formatters
local trace_tags = false trackers.register("structures.tags", function(v) trace_tags = v end)
@@ -78,13 +80,17 @@ local root = { pref = pdfreference(structure_ref), kids = structu
local tree = { }
local elements = { }
local names = pdfarray()
-local taglist = structures.tags.taglist
-local usedlabels = structures.tags.labels
-local properties = structures.tags.properties
+
+local structurestags = structures.tags
+local taglist = structurestags.taglist
+local specifications = structurestags.specifications
+local usedlabels = structurestags.labels
+local properties = structurestags.properties
+local lasttaginchain = structurestags.lastinchain
+
local usedmapping = { }
-local colonsplitter = lpeg.splitat(":")
-local dashsplitter = lpeg.splitat("-")
+-- local tagsplitter = structurestags.patterns.splitter
local add_ids = false -- true
@@ -96,13 +102,14 @@ local function finishstructure()
if #structure_kids > 0 then
local nums, n = pdfarray(), 0
for i=1,#tree do
- n = n + 1 ; nums[n] = i-1
+ n = n + 1 ; nums[n] = i - 1
n = n + 1 ; nums[n] = pdfreference(pdfflushobject(tree[i]))
end
local parenttree = pdfdictionary {
Nums = nums
}
-- we need to split names into smaller parts (e.g. alphabetic or so)
+ -- we already have code for that somewhere
if add_ids then
local kids = pdfdictionary {
Limits = pdfarray { names[1], names[#names-1] },
@@ -150,10 +157,10 @@ local pdf_mcr = pdfconstant("MCR")
local pdf_struct_element = pdfconstant("StructElem")
local function initializepage()
- index = 0
+ index = 0
pagenum = texgetcount("realpageno")
pageref = pdfreference(pdfpagereference(pagenum))
- list = pdfarray()
+ list = pdfarray()
tree[pagenum] = list -- we can flush after done, todo
end
@@ -164,20 +171,51 @@ end
-- here we can flush and free elements that are finished
+local pdf_userproperties = pdfconstant("UserProperties")
+
+local function makeattribute(t)
+ if t and next(t) then
+ local properties = pdfarray()
+ for k, v in next, t do
+ properties[#properties+1] = pdfdictionary {
+ N = pdfunicode(k),
+ V = pdfunicode(v),
+ }
+ end
+ return pdfdictionary {
+ O = pdf_userproperties,
+ P = properties,
+ }
+ end
+end
+
local function makeelement(fulltag,parent)
- local tag, n = lpegmatch(dashsplitter,fulltag)
- local tg, detail = lpegmatch(colonsplitter,tag)
- local k, r = pdfarray(), pdfreserveobject()
- usedmapping[tg] = true
- tg = usedlabels[tg] or tg
+ local specification = specifications[fulltag]
+ local tag = specification.tagname
+ if tag == "ignore" then
+ return false
+ elseif tag == "mstackertop" or tag == "mstackerbot" or tag == "mstackermid"then
+ -- TODO
+ return true
+ end
+ --
+ local detail = specification.detail
+ local userdata = specification.userdata
+ --
+ usedmapping[tag] = true
+ --
+ local k = pdfarray()
+ local r = pdfreserveobject()
+ local t = usedlabels[tag] or tag
local d = pdfdictionary {
Type = pdf_struct_element,
- S = pdfconstant(tg),
+ S = pdfconstant(t),
ID = (add_ids and fulltag) or nil,
T = detail and detail or nil,
P = parent.pref,
Pg = pageref,
K = pdfreference(r),
+ A = a and makeattribute(a) or nil,
-- Alt = " Who cares ",
-- ActualText = " Hi Hans ",
}
@@ -188,10 +226,14 @@ local function makeelement(fulltag,parent)
end
local kids = parent.kids
kids[#kids+1] = s
- elements[fulltag] = { tag = tag, pref = s, kids = k, knum = r, pnum = pagenum }
+ local e = { tag = t, pref = s, kids = k, knum = r, pnum = pagenum }
+ elements[fulltag] = e
+ return e
end
-local function makecontent(parent,start,stop,slist,id)
+local f_BDC = formatters["/%s <> BDC"]
+
+local function makecontent(parent,id)
local tag = parent.tag
local kids = parent.kids
local last = index
@@ -215,116 +257,304 @@ local function makecontent(parent,start,stop,slist,id)
kids[#kids+1] = d
end
--
- local bliteral = pdfliteral(format("/%s <>BDC",tag,last))
- local eliteral = pdfliteral("EMC")
- -- use insert instead:
- local prev = getprev(start)
- if prev then
- setfield(prev,"next",bliteral)
- setfield(bliteral,"prev",prev)
- end
- setfield(start,"prev",bliteral)
- setfield(bliteral,"next",start)
- -- use insert instead:
- local next = getnext(stop)
- if next then
- setfield(next,"prev",eliteral)
- setfield(eliteral,"next",next)
- end
- setfield(stop,"next",eliteral)
- setfield(eliteral,"prev",stop)
- --
- if slist and getlist(slist) == start then
- setfield(slist,"list",bliteral)
- elseif not getprev(start) then
- report_tags("this can't happen: injection in front of nothing")
- end
index = index + 1
- list[index] = parent.pref
- return bliteral, eliteral
+ list[index] = parent.pref -- page related list
+ --
+ return f_BDC(tag,last)
end
--- -- --
-
-local level, last, ranges, range = 0, nil, { }, nil
-
-local function collectranges(head,list)
- for n in traverse_nodes(head) do
- local id = getid(n) -- 14: image, 8: literal (mp)
- if id == glyph_code then
- local at = getattr(n,a_tagged)
- if not at then
- range = nil
- elseif last ~= at then
- range = { at, "glyph", n, n, list } -- attr id start stop list
- ranges[#ranges+1] = range
- last = at
- elseif range then
- range[4] = n -- stop
- end
- elseif id == hlist_code or id == vlist_code then
- local at = getattr(n,a_image)
- if at then
+-- no need to adapt head, as we always operate on lists
+
+function nodeinjections.addtags(head)
+
+ local last = nil
+ local ranges = { }
+ local range = nil
+ local head = tonut(head)
+
+ local function collectranges(head,list)
+ for n in traverse_nodes(head) do
+ local id = getid(n) -- 14: image, 8: literal (mp)
+ if id == glyph_code then
local at = getattr(n,a_tagged)
if not at then
range = nil
+ elseif last ~= at then
+ range = { at, "glyph", n, n, list } -- attr id start stop list
+ ranges[#ranges+1] = range
+ last = at
+ elseif range then
+ range[4] = n -- stop
+ end
+ elseif id == hlist_code or id == vlist_code then
+ local at = getattr(n,a_image)
+ if at then
+ local at = getattr(n,a_tagged)
+ if not at then
+ range = nil
+ else
+ ranges[#ranges+1] = { at, "image", n, n, list } -- attr id start stop list
+ end
+ last = nil
else
- ranges[#ranges+1] = { at, "image", n, n, list } -- attr id start stop list
+ local nl = getlist(n)
+ -- slide_nodelist(nl) -- temporary hack till math gets slided (tracker item)
+ collectranges(nl,n)
end
- last = nil
- else
- local nl = getlist(n)
- slide_nodelist(nl) -- temporary hack till math gets slided (tracker item)
- collectranges(nl,n)
end
end
end
-end
-function nodeinjections.addtags(head)
- -- no need to adapt head, as we always operate on lists
- level, last, ranges, range = 0, nil, { }, nil
initializepage()
- head = tonut(head)
+
collectranges(head)
+
if trace_tags then
for i=1,#ranges do
local range = ranges[i]
- local attr, id, start, stop = range[1], range[2], range[3], range[4]
- local tags = taglist[attr]
+ local attr = range[1]
+ local id = range[2]
+ local start = range[3]
+ local stop = range[4]
+ local tags = taglist[attr]
if tags then -- not ok ... only first lines
- report_tags("%s => %s : %05i % t",tosequence(start,start),tosequence(stop,stop),attr,tags)
+ report_tags("%s => %s : %05i % t",tosequence(start,start),tosequence(stop,stop),attr,tags.taglist)
end
end
end
+
+ local top = nil
+ local noftop = 0
+
for i=1,#ranges do
- local range = ranges[i]
- local attr, id, start, stop, list = range[1], range[2], range[3], range[4], range[5]
- local tags = taglist[attr]
- local prev = root
- local noftags, tag = #tags, nil
- for j=1,noftags do
- local tag = tags[j]
- if not elements[tag] then
- makeelement(tag,prev)
+ local range = ranges[i]
+ local attr = range[1]
+ local id = range[2]
+ local start = range[3]
+ local stop = range[4]
+ local list = range[5]
+ local specification = taglist[attr]
+ local taglist = specification.taglist
+ local noftags = #taglist
+ local common = 0
+
+ if top then
+ for i=1,noftags >= noftop and noftop or noftags do
+ if top[i] == taglist[i] then
+ common = i
+ else
+ break
+ end
+ end
+ end
+
+ local prev = common > 0 and elements[taglist[common]] or root
+
+ for j=common+1,noftags do
+ local tag = taglist[j]
+ local prv = elements[tag] or makeelement(tag,prev)
+ if prv == false then
+ -- ignore this one
+ prev = false
+ break
+ elseif prv == true then
+ -- skip this one
+ else
+ prev = prv
end
- prev = elements[tag]
end
- local b, e = makecontent(prev,start,stop,list,id)
- if start == head then
- report_tags("this can't happen: parent list gets tagged")
- head = b
+
+ if prev then
+ -- use insert instead:
+ local literal = pdfliteral(makecontent(prev,id))
+ local prev = getprev(start)
+ if prev then
+ setfield(prev,"next",literal)
+ setfield(literal,"prev",prev)
+ end
+ setfield(start,"prev",literal)
+ setfield(literal,"next",start)
+ if list and getlist(list) == start then
+ setfield(list,"list",literal)
+ end
+ -- use insert instead:
+ local literal = pdfliteral("EMC")
+ local next = getnext(stop)
+ if next then
+ setfield(next,"prev",literal)
+ setfield(literal,"next",next)
+ end
+ setfield(stop,"next",literal)
+ setfield(literal,"prev",stop)
end
+ top = taglist
+ noftop = noftags
end
+
finishpage()
- -- can be separate feature
- --
- -- injectspans(tonut(head)) -- does to work yet
- --
+
head = tonode(head)
return head, true
+
end
+-- variant: more structure but funny collapsing in viewer
+
+-- function nodeinjections.addtags(head)
+--
+-- local last, ranges, range = nil, { }, nil
+--
+-- local function collectranges(head,list)
+-- for n in traverse_nodes(head) do
+-- local id = getid(n) -- 14: image, 8: literal (mp)
+-- if id == glyph_code then
+-- local at = getattr(n,a_tagged)
+-- if not at then
+-- range = nil
+-- elseif last ~= at then
+-- range = { at, "glyph", n, n, list } -- attr id start stop list
+-- ranges[#ranges+1] = range
+-- last = at
+-- elseif range then
+-- range[4] = n -- stop
+-- end
+-- elseif id == hlist_code or id == vlist_code then
+-- local at = getattr(n,a_image)
+-- if at then
+-- local at = getattr(n,a_tagged)
+-- if not at then
+-- range = nil
+-- else
+-- ranges[#ranges+1] = { at, "image", n, n, list } -- attr id start stop list
+-- end
+-- last = nil
+-- else
+-- local nl = getlist(n)
+-- -- slide_nodelist(nl) -- temporary hack till math gets slided (tracker item)
+-- collectranges(nl,n)
+-- end
+-- end
+-- end
+-- end
+--
+-- initializepage()
+--
+-- head = tonut(head)
+-- collectranges(head)
+--
+-- if trace_tags then
+-- for i=1,#ranges do
+-- local range = ranges[i]
+-- local attr = range[1]
+-- local id = range[2]
+-- local start = range[3]
+-- local stop = range[4]
+-- local tags = taglist[attr]
+-- if tags then -- not ok ... only first lines
+-- report_tags("%s => %s : %05i % t",tosequence(start,start),tosequence(stop,stop),attr,tags.taglist)
+-- end
+-- end
+-- end
+--
+-- local top = nil
+-- local noftop = 0
+-- local last = nil
+--
+-- for i=1,#ranges do
+-- local range = ranges[i]
+-- local attr = range[1]
+-- local id = range[2]
+-- local start = range[3]
+-- local stop = range[4]
+-- local list = range[5]
+-- local specification = taglist[attr]
+-- local taglist = specification.taglist
+-- local noftags = #taglist
+-- local tag = nil
+-- local common = 0
+-- -- local prev = root
+--
+-- if top then
+-- for i=1,noftags >= noftop and noftop or noftags do
+-- if top[i] == taglist[i] then
+-- common = i
+-- else
+-- break
+-- end
+-- end
+-- end
+--
+-- local result = { }
+-- local r = noftop - common
+-- if r > 0 then
+-- for i=1,r do
+-- result[i] = "EMC"
+-- end
+-- end
+--
+-- local prev = common > 0 and elements[taglist[common]] or root
+--
+-- for j=common+1,noftags do
+-- local tag = taglist[j]
+-- local prv = elements[tag] or makeelement(tag,prev)
+-- -- if prv == false then
+-- -- -- ignore this one
+-- -- prev = false
+-- -- break
+-- -- elseif prv == true then
+-- -- -- skip this one
+-- -- else
+-- prev = prv
+-- r = r + 1
+-- result[r] = makecontent(prev,id)
+-- -- end
+-- end
+--
+-- if r > 0 then
+-- local literal = pdfliteral(concat(result,"\n"))
+-- -- use insert instead:
+-- local literal = pdfliteral(result)
+-- local prev = getprev(start)
+-- if prev then
+-- setfield(prev,"next",literal)
+-- setfield(literal,"prev",prev)
+-- end
+-- setfield(start,"prev",literal)
+-- setfield(literal,"next",start)
+-- if list and getlist(list) == start then
+-- setfield(list,"list",literal)
+-- end
+-- end
+--
+-- top = taglist
+-- noftop = noftags
+-- last = stop
+--
+-- end
+--
+-- if last and noftop > 0 then
+-- local result = { }
+-- for i=1,noftop do
+-- result[i] = "EMC"
+-- end
+-- local literal = pdfliteral(concat(result,"\n"))
+-- -- use insert instead:
+-- local next = getnext(last)
+-- if next then
+-- setfield(next,"prev",literal)
+-- setfield(literal,"next",next)
+-- end
+-- setfield(last,"next",literal)
+-- setfield(literal,"prev",last)
+-- end
+--
+-- finishpage()
+--
+-- head = tonode(head)
+-- return head, true
+--
+-- end
+
-- this belongs elsewhere (export is not pdf related)
function codeinjections.enabletags(tg,lb)
diff --git a/Master/texmf-dist/tex/context/base/lpdf-xmp.lua b/Master/texmf-dist/tex/context/base/lpdf-xmp.lua
index c8b2d236c62..b44c57b42aa 100644
--- a/Master/texmf-dist/tex/context/base/lpdf-xmp.lua
+++ b/Master/texmf-dist/tex/context/base/lpdf-xmp.lua
@@ -26,7 +26,7 @@ local pdfconstant = lpdf.constant
local pdfreference = lpdf.reference
local pdfflushstreamobject = lpdf.flushstreamobject
--- I wonder why this begin end is empty / w (no time now to look into it)
+-- I wonder why this begin end is empty / w (no time now to look into it) / begin can also be "?"
local xpacket = [[
@@ -50,7 +50,7 @@ local mapping = {
-- Dublin Core schema
["Author"] = "rdf:Description/dc:creator/rdf:Seq/rdf:li",
["Format"] = "rdf:Description/dc:format", -- optional, but nice to have
- ["Subject"] = "rdf:Description/dc:description",
+ ["Subject"] = "rdf:Description/dc:description/rdf:Alt/rdf:li",
["Title"] = "rdf:Description/dc:title/rdf:Alt/rdf:li",
-- XMP Basic schema
["CreateDate"] = "rdf:Description/xmp:CreateDate",
@@ -91,7 +91,12 @@ local function setxmpfile(name)
end
codeinjections.setxmpfile = setxmpfile
-commands.setxmpfile = setxmpfile
+
+interfaces.implement {
+ name = "setxmpfile",
+ arguments = "string",
+ actions = setxmpfile
+}
local function valid_xmp()
if not xmp then
@@ -105,7 +110,7 @@ local function valid_xmp()
if xmpfile ~= "" then
report_xmp("using file %a",xmpfile)
end
- local xmpdata = (xmpfile ~= "" and io.loaddata(xmpfile)) or ""
+ local xmpdata = xmpfile ~= "" and io.loaddata(xmpfile) or ""
xmp = xml.convert(xmpdata)
end
return xmp
@@ -157,8 +162,7 @@ local function flushxmpinfo()
local producer = format("LuaTeX-%0.2f.%s",tex.luatexversion/100,tex.luatexrevision)
local creator = "LuaTeX + ConTeXt MkIV"
local time = lpdf.timestamp()
- local fullbanner = tex.pdftexbanner
- -- local fullbanner = gsub(tex.pdftexbanner,"kpse.*","")
+ local fullbanner = status.banner
pdfaddxmpinfo("DocumentID", documentid)
pdfaddxmpinfo("InstanceID", instanceid)
@@ -173,7 +177,7 @@ local function flushxmpinfo()
pdfaddtoinfo("Creator", creator)
pdfaddtoinfo("CreationDate", time)
pdfaddtoinfo("ModDate", time)
--- pdfaddtoinfo("PTEX.Fullbanner", fullbanner) -- no checking done on existence
+ -- pdfaddtoinfo("PTEX.Fullbanner", fullbanner) -- no checking done on existence
local blob = xml.tostring(xml.first(xmp or valid_xmp(),"/x:xmpmeta"))
local md = pdfdictionary {
diff --git a/Master/texmf-dist/tex/context/base/luat-bas.mkiv b/Master/texmf-dist/tex/context/base/luat-bas.mkiv
index a3891271619..cb00d8f55e7 100644
--- a/Master/texmf-dist/tex/context/base/luat-bas.mkiv
+++ b/Master/texmf-dist/tex/context/base/luat-bas.mkiv
@@ -13,7 +13,8 @@
\writestatus{loading}{ConTeXt Lua Macros / Basic Lua Libraries}
-\registerctxluafile{l-lua} {1.001}
+\registerctxluafile{l-lua} {1.001} % before sandbox
+\registerctxluafile{l-sandbox} {1.001}
\registerctxluafile{l-package} {1.001}
\registerctxluafile{l-lpeg} {1.001}
\registerctxluafile{l-function}{1.001}
diff --git a/Master/texmf-dist/tex/context/base/luat-cnf.lua b/Master/texmf-dist/tex/context/base/luat-cnf.lua
index fba2b71d1ec..0f6b8598f37 100644
--- a/Master/texmf-dist/tex/context/base/luat-cnf.lua
+++ b/Master/texmf-dist/tex/context/base/luat-cnf.lua
@@ -7,7 +7,9 @@ if not modules then modules = { } end modules ['luat-cnf'] = {
}
local type, next, tostring, tonumber = type, next, tostring, tonumber
-local format, concat, find = string.format, table.concat, string.find
+local format, concat, find, lower, gsub = string.format, table.concat, string.find, string.lower, string.gsub
+
+local report = logs.reporter("system")
local allocate = utilities.storage.allocate
@@ -17,8 +19,10 @@ texconfig.shell_escape = 't'
luatex = luatex or { }
local luatex = luatex
-texconfig.error_line = 79 -- 79 -- obsolete
-texconfig.half_error_line = 50 -- 50 -- obsolete
+texconfig.max_print_line = 100000 -- frozen
+texconfig.max_in_open = 127 -- frozen
+texconfig.error_line = 79 -- frozen
+texconfig.half_error_line = 50 -- frozen
texconfig.expand_depth = 10000 -- 10000
texconfig.hash_extra = 100000 -- 0
@@ -28,25 +32,9 @@ texconfig.max_print_line = 10000 -- 79
texconfig.max_strings = 500000 -- 15000
texconfig.param_size = 25000 -- 60
texconfig.save_size = 50000 -- 4000
+texconfig.save_size = 100000 -- 4000
texconfig.stack_size = 10000 -- 300
--- local function initialize()
--- local t, variable = allocate(), resolvers.variable
--- for name, default in next, variablenames do
--- local name = variablenames[i]
--- local value = variable(name)
--- value = tonumber(value)
--- if not value or value == "" or value == 0 then
--- value = default
--- end
--- texconfig[name], t[name] = value, value
--- end
--- initialize = nil
--- return t
--- end
---
--- luatex.variables = initialize()
-
local stub = [[
-- checking
@@ -76,7 +64,7 @@ function texconfig.init()
"string", "table", "coroutine", "debug", "file", "io", "lpeg", "math", "os", "package", "bit32",
},
basictex = { -- noad
- "callback", "font", "img", "lang", "lua", "node", "pdf", "status", "tex", "texconfig", "texio", "token",
+ "callback", "font", "img", "lang", "lua", "node", "pdf", "status", "tex", "texconfig", "texio", "token", "newtoken"
},
extralua = {
"gzip", "zip", "zlib", "lfs", "ltn12", "mime", "socket", "md5", "profiler", "unicode", "utf",
@@ -87,6 +75,7 @@ function texconfig.init()
obsolete = {
"fontforge", -- can be filled by luat-log
"kpse",
+ "token",
},
functions = {
"assert", "pcall", "xpcall", "error", "collectgarbage",
@@ -175,26 +164,55 @@ end)
]]
local variablenames = {
- "error_line", "half_error_line",
- "expand_depth", "hash_extra", "nest_size",
- "max_in_open", "max_print_line", "max_strings",
- "param_size", "save_size", "stack_size",
+ error_line = false,
+ half_error_line = false,
+ max_print_line = false,
+ max_in_open = false,
+ expand_depth = true,
+ hash_extra = true,
+ nest_size = true,
+ max_strings = true,
+ param_size = true,
+ save_size = true,
+ stack_size = true,
}
local function makestub()
name = name or (environment.jobname .. ".lui")
+ report("creating stub file %a using directives:",name)
+ report()
firsttable = firsttable or lua.firstbytecode
local t = {
"-- this file is generated, don't change it\n",
"-- configuration (can be overloaded later)\n"
}
- for _,v in next, variablenames do
+ for v, permitted in table.sortedhash(variablenames) do
+ local d = "luatex." .. gsub(lower(v),"[^%a]","")
+ local dv = directives.value(d)
local tv = texconfig[v]
- if tv and tv ~= "" then
+ if dv then
+ if not tv then
+ report(" %s = %s (%s)",d,dv,"configured")
+ tv = dv
+ elseif not permitted then
+ report(" %s = %s (%s)",d,tv,"frozen")
+ elseif tonumber(dv) >= tonumber(tv) then
+ report(" %s = %s (%s)",d,dv,"overloaded")
+ tv = dv
+ else
+ report(" %s = %s (%s)",d,tv,"preset kept")
+ end
+ elseif tv then
+ report(" %s = %s (%s)",d,tv,permitted and "preset" or "frozen")
+ else
+ report(" %s = ",d)
+ end
+ if tv then
t[#t+1] = format("texconfig.%s=%s",v,tv)
end
end
io.savedata(name,format("%s\n\n%s",concat(t,"\n"),format(stub,firsttable)))
+ logs.newline()
end
lua.registerfinalizer(makestub,"create stub file")
diff --git a/Master/texmf-dist/tex/context/base/luat-cod.lua b/Master/texmf-dist/tex/context/base/luat-cod.lua
index c16a3b110ea..c436ee6d7a6 100644
--- a/Master/texmf-dist/tex/context/base/luat-cod.lua
+++ b/Master/texmf-dist/tex/context/base/luat-cod.lua
@@ -162,7 +162,7 @@ local function target_file(name)
return targetpath .. "/" .. name
end
-local function find_read_file (id,name)
+local function find_read_file(id,name)
return source_file(name)
end
diff --git a/Master/texmf-dist/tex/context/base/luat-exe.lua b/Master/texmf-dist/tex/context/base/luat-exe.lua
index a57a5a006fb..d8d954a307b 100644
--- a/Master/texmf-dist/tex/context/base/luat-exe.lua
+++ b/Master/texmf-dist/tex/context/base/luat-exe.lua
@@ -6,121 +6,68 @@ if not modules then modules = { } end modules ['luat-exe'] = {
license = "see context related readme files"
}
--- this module needs checking (very old and never really used, not even enabled)
+if not sandbox then require("l-sandbox") require("util-sbx") end -- for testing
-local match, find, gmatch = string.match, string.find, string.gmatch
-local concat = table.concat
-local select = select
+local type = type
-local report_executers = logs.reporter("system","executers")
+local executers = resolvers.executers or { }
+resolvers.executers = executers
-resolvers.executers = resolvers.executers or { }
-local executers = resolvers.executers
+local disablerunners = sandbox.disablerunners
+local registerbinary = sandbox.registerbinary
+local registerroot = sandbox.registerroot
-local permitted = { }
+local lpegmatch = lpeg.match
-local osexecute = os.execute
-local osexec = os.exec
-local osspawn = os.spawn
-local iopopen = io.popen
+local sc_splitter = lpeg.tsplitat(";")
+local cm_splitter = lpeg.tsplitat(",")
-local execute = osexecute
-local exec = osexec
-local spawn = osspawn
-local popen = iopopen
-
-local function register(...)
- for k=1,select("#",...) do
- local v = select(k,...)
- permitted[#permitted+1] = v == "*" and ".*" or v
- end
-end
+local execution_mode directives.register("system.executionmode", function(v) execution_mode = v end)
+local execution_list directives.register("system.executionlist", function(v) execution_list = v end)
+local root_list directives.register("system.rootlist", function(v) root_list = v end)
-local function prepare(...)
- -- todo: make more clever first split
- local t = { ... }
- local n = #n
- local one = t[1]
- if n == 1 then
- if type(one) == 'table' then
- return one, concat(t," ",2,n)
- else
- local name, arguments = match(one,"^(.-)%s+(.+)$")
- if name and arguments then
- return name, arguments
- else
- return one, ""
+sandbox.initializer(function()
+ if execution_mode == "none" then
+ -- will be done later
+ elseif execution_mode == "list" then
+ if type(execution_list) == "string" then
+ execution_list = lpegmatch(cm_splitter,execution_list)
+ end
+ if type(execution_list) == "table" then
+ for i=1,#execution_list do
+ registerbinary(execution_list[i])
end
end
else
- return one, concat(t," ",2,n)
+ -- whatever else we have configured
end
-end
+end)
-local function executer(action)
- return function(...)
- local name, arguments = prepare(...)
- for k=1,#permitted do
- local v = permitted[k]
- if find(name,v) then
- return action(name .. " " .. arguments)
- else
- report_executers("not permitted: %s %s",name,arguments)
+sandbox.initializer(function()
+ if type(root_list) == "string" then
+ root_list = lpegmatch(sc_splitter,root_list)
+ end
+ if type(root_list) == "table" then
+ for i=1,#root_list do
+ local entry = root_list[i]
+ if entry ~= "" then
+ registerroot(entry)
end
end
- return action("")
end
-end
+end)
-local function finalize() -- todo: os.exec, todo: report ipv print
- execute = executer(osexecute)
- exec = executer(osexec)
- spawn = executer(osspawn)
- popen = executer(iopopen)
- finalize = function()
- report_executers("already finalized")
- end
- register = function()
- report_executers("already finalized, no registration permitted")
- end
- os.execute = execute
- os.exec = exec
- os.spawn = spawn
- io.popen = popen
-end
-
-executers.finalize = function(...) return finalize(...) end
-executers.register = function(...) return register(...) end
-executers.execute = function(...) return execute (...) end
-executers.exec = function(...) return exec (...) end
-executers.spawn = function(...) return spawn (...) end
-executers.popen = function(...) return popen (...) end
-
-local execution_mode directives.register("system.executionmode", function(v) execution_mode = v end)
-local execution_list directives.register("system.executionlist", function(v) execution_list = v end)
-
-function executers.check()
+sandbox.finalizer(function()
if execution_mode == "none" then
- finalize()
- elseif execution_mode == "list" and execution_list ~= "" then
- for s in gmatch("[^%s,]",execution_list) do
- register(s)
- end
- finalize()
- else
- -- all
+ disablerunners()
end
-end
-
---~ resolvers.executers.register('.*')
---~ resolvers.executers.register('*')
---~ resolvers.executers.register('dir','ls')
---~ resolvers.executers.register('dir')
+end)
---~ resolvers.executers.finalize()
---~ resolvers.executers.execute('dir',"*.tex")
---~ resolvers.executers.execute("dir *.tex")
---~ resolvers.executers.execute("ls *.tex")
---~ os.execute('ls')
+-- Let's prevent abuse of these libraries (built-in support still works).
---~ resolvers.executers.check()
+sandbox.finalizer(function()
+ mplib = nil
+ epdf = nil
+ zip = nil
+ fontloader = nil
+end)
diff --git a/Master/texmf-dist/tex/context/base/luat-fmt.lua b/Master/texmf-dist/tex/context/base/luat-fmt.lua
index 20a4a8fcdf7..92c1dd6c45d 100644
--- a/Master/texmf-dist/tex/context/base/luat-fmt.lua
+++ b/Master/texmf-dist/tex/context/base/luat-fmt.lua
@@ -95,7 +95,7 @@ function environment.make_format(name)
-- generate format
local command = format("%s --ini %s --lua=%s %s %sdump",engine,primaryflags(),quoted(usedluastub),quoted(fulltexsourcename),os.platform == "unix" and "\\\\" or "\\")
report_format("running command: %s\n",command)
- os.spawn(command)
+ os.execute(command)
-- remove related mem files
local pattern = file.removesuffix(file.basename(usedluastub)).."-*.mem"
-- report_format("removing related mplib format with pattern %a", pattern)
@@ -133,7 +133,7 @@ function environment.run_format(name,data,more)
else
local command = format("%s %s --fmt=%s --lua=%s %s %s",engine,primaryflags(),quoted(barename),quoted(luaname),quoted(data),more ~= "" and quoted(more) or "")
report_format("running command: %s",command)
- os.spawn(command)
+ os.execute(command)
end
end
end
diff --git a/Master/texmf-dist/tex/context/base/luat-ini.lua b/Master/texmf-dist/tex/context/base/luat-ini.lua
index 9303b614a3e..34e83e7bb38 100644
--- a/Master/texmf-dist/tex/context/base/luat-ini.lua
+++ b/Master/texmf-dist/tex/context/base/luat-ini.lua
@@ -6,14 +6,6 @@ if not modules then modules = { } end modules ['luat-ini'] = {
license = "see context related readme files"
}
--- rather experimental down here ... adapted to lua 5.2 ... but still
--- experimental
-
-local debug = require("debug")
-
-local string, table, lpeg, math, io, system = string, table, lpeg, math, io, system
-local rawset, rawget, next, setmetatable = rawset, rawget, next, setmetatable
-
--[[ldx--
We cannot load anything yet. However what we will do us reserve a few tables.
These can be used for runtime user data or third party modules and will not be
@@ -29,180 +21,6 @@ parametersets = parametersets or { } -- experimental for team
table.setmetatableindex(moduledata,table.autokey)
table.setmetatableindex(thirddata, table.autokey)
---[[ldx--
-
Please create a namespace within these tables before using them!
-
-
-userdata ['my.name'] = { }
-thirddata['tricks' ] = { }
-
---ldx]]--
-
---[[ldx--
-We could cook up a readonly model for global tables but it makes more sense
-to invite users to use one of the predefined namespaces. One can redefine the
-protector. After all, it's just a lightweight suggestive system, not a
-watertight one.
---ldx]]--
-
-local global = _G
-global.global = global
-
-local dummy = function() end
-
---[[ldx--
-Another approach is to freeze tables by using a metatable, this will be
-implemented stepwise.
---ldx]]--
-
--- moduledata : no need for protection (only for developers)
--- isolatedata : full protection
--- userdata : protected
--- thirddata : protected
-
---[[ldx--
-We could have a metatable that automaticaly creates a top level namespace.
---ldx]]--
-
-local luanames = lua.name -- luatex itself
-
-lua.numbers = lua.numbers or { } local numbers = lua.numbers
-lua.messages = lua.messages or { } local messages = lua.messages
-
-storage.register("lua/numbers", numbers, "lua.numbers" )
-storage.register("lua/messages", messages, "lua.messages")
-
-local f_message = string.formatters["=[instance: %s]"] -- the = controls the lua error / see: lobject.c
-
-local setfenv = setfenv or debug.setfenv -- < 5.2
-
-if setfenv then
-
- local protected = {
- -- global table
- global = global,
- -- user tables
- -- moduledata = moduledata,
- userdata = userdata,
- thirddata = thirddata,
- documentdata = documentdata,
- -- reserved
- protect = dummy,
- unprotect = dummy,
- -- luatex
- tex = tex,
- -- lua
- string = string,
- table = table,
- lpeg = lpeg,
- math = math,
- io = io,
- file = file,
- bit32 = bit32,
- --
- context = context,
- }
-
- local protect_full = function(name)
- local t = { }
- for k, v in next, protected do
- t[k] = v
- end
- return t
- end
-
- local protect_part = function(name) -- adds
- local t = rawget(global,name)
- if not t then
- t = { }
- for k, v in next, protected do
- t[k] = v
- end
- rawset(global,name,t)
- end
- return t
- end
-
- protect = function(name)
- if name == "isolateddata" then
- setfenv(2,protect_full(name))
- else
- setfenv(2,protect_part(name or "shareddata"))
- end
- end
-
- function lua.registername(name,message)
- local lnn = lua.numbers[name]
- if not lnn then
- lnn = #messages + 1
- messages[lnn] = message
- numbers[name] = lnn
- end
- luanames[lnn] = message
- context(lnn)
- -- initialize once
- if name ~= "isolateddata" then
- protect_full(name or "shareddata")
- end
- end
-
-elseif libraries then -- assume >= 5.2
-
- local shared
-
- protect = function(name)
- if not shared then
- -- e.g. context is not yet known
- local public = {
- global = global,
- -- moduledata = moduledata,
- userdata = userdata,
- thirddata = thirddata,
- documentdata = documentdata,
- protect = dummy,
- unprotect = dummy,
- context = context,
- }
- --
- for k, v in next, libraries.builtin do public[k] = v end
- for k, v in next, libraries.functions do public[k] = v end
- for k, v in next, libraries.obsolete do public[k] = nil end
- --
- shared = { __index = public }
- protect = function(name)
- local t = global[name] or { }
- setmetatable(t,shared) -- set each time
- return t
- end
- end
- return protect(name)
- end
-
- function lua.registername(name,message)
- local lnn = lua.numbers[name]
- if not lnn then
- lnn = #messages + 1
- messages[lnn] = message
- numbers[name] = lnn
- end
- luanames[lnn] = f_message(message)
- context(lnn)
- end
-
-else
-
- protect = dummy
-
- function lua.registername(name,message)
- local lnn = lua.numbers[name]
- if not lnn then
- lnn = #messages + 1
- messages[lnn] = message
- numbers[name] = lnn
- end
- luanames[lnn] = f_message(message)
- context(lnn)
- end
-
+if not global then
+ global = _G
end
-
diff --git a/Master/texmf-dist/tex/context/base/luat-ini.mkiv b/Master/texmf-dist/tex/context/base/luat-ini.mkiv
index 7823ebd5a96..b455a415821 100644
--- a/Master/texmf-dist/tex/context/base/luat-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/luat-ini.mkiv
@@ -34,7 +34,7 @@
% the \type {\normalexpanded} around \type {\directlua}. Something to discuss
% in the team.
-\unexpanded\def\startlua % \stoplua
+\normalprotected\def\startlua % \stoplua
{\begingroup
\obeylualines
\luat_start_lua_indeed}
@@ -42,7 +42,7 @@
\def\luat_start_lua_indeed#1\stoplua
{\normalexpanded{\endgroup\noexpand\directlua{#1}}} % \zerocount is default
-\unexpanded\def\startluacode % \stopluacode
+\normalprotected\def\startluacode % \stopluacode
{\begingroup
\obeylualines
\obeyluatokens
@@ -77,7 +77,7 @@
\edef\lua_letter_seven {\string\7} \edef\lua_letter_eight {\string\8}
\edef\lua_letter_nine {\string\9} \edef\lua_letter_zero {\string\0}
-\appendtoks
+\everyluacode {% \appendtoks
\let\\\lua_letter_backslash
\let\|\lua_letter_bar \let\-\lua_letter_dash
\let\(\lua_letter_lparent \let\)\lua_letter_rparent
@@ -92,93 +92,15 @@
\let\5\lua_letter_five \let\6\lua_letter_six
\let\7\lua_letter_seven \let\8\lua_letter_eight
\let\9\lua_letter_nine \let\0\lua_letter_zero
-\to \everyluacode
+} % \to \everyluacode
-\unexpanded\def\obeyluatokens
+\normalprotected\def\obeyluatokens
{\setcatcodetable\luacatcodes
\the\everyluacode}
-
\edef\luamajorversion{\ctxwrite{_MINORVERSION}}
\edef\luaminorversion{\ctxwrite{_MAJORVERSION}}
-%D \macros
-%D {definenamedlua}
-%D
-%D We provide an interface for defining instances:
-
-\def\s!lua{lua} \def\v!code{code} \def\!!name{name} \def\s!data{data}
-
-%D Beware: because \type {\expanded} is een convert command, the error
-%D message will show \type{} as part of the message.
-
-\installcorenamespace{luacode}
-
-\unexpanded\def\luat_start_named_lua_code#1%
- {\begingroup
- \obeylualines
- \obeyluatokens
- \csname\??luacode#1\endcsname}
-
-% \unexpanded\def\definenamedlua[#1]#2[#3]% no optional arg handling here yet / we could use numbers instead (more efficient)
-% {\ifcsname\??luacode#1\endcsname \else
-% \scratchcounter\ctxlua{lua.registername("#1","#3")}%
-% \normalexpanded{\xdef\csname\??luacode#1\endcsname##1\csname\e!stop#1\v!code\endcsname}%
-% {\noexpand\normalexpanded{\endgroup\noexpand\directlua\the\scratchcounter{_G=protect("#1\s!data")##1}}}%
-% \expandafter\edef\csname\e!start#1\v!code\endcsname {\luat_start_named_lua_code{#1}}%
-% \expandafter\edef\csname #1\v!code\endcsname##1{\noexpand\directlua\the\scratchcounter{_G=protect("#1\s!data")##1}}%
-% \fi}
-
-\unexpanded\def\definenamedlua[#1]#2[#3]% no optional arg handling here yet / we could use numbers instead (more efficient)
- {\ifcsname\??luacode#1\endcsname \else
- \expandafter\chardef\csname\??luacode:#1\endcsname\ctxlua{lua.registername("#1","#3")}%
- \normalexpanded{\xdef\csname\??luacode#1\endcsname##1\csname\e!stop#1\v!code\endcsname}%
- {\noexpand\normalexpanded{\endgroup\noexpand\directlua\csname\??luacode:#1\endcsname{_G=protect("#1\s!data")##1}}}%
- \expandafter\edef\csname\e!start#1\v!code\endcsname {\luat_start_named_lua_code{#1}}%
- \expandafter\edef\csname #1\v!code\endcsname##1{\noexpand\directlua\csname\??luacode:#1\endcsname{_G=protect("#1\s!data")##1}}%
- \fi}
-
-%D We predefine a few.
-
-% \definenamedlua[module][module instance] % not needed
-
-\definenamedlua[user] [private user]
-\definenamedlua[third] [third party module]
-\definenamedlua[isolated][isolated]
-
-%D In practice this works out as follows:
-%D
-%D \startbuffer
-%D \startluacode
-%D context("LUA")
-%D \stopluacode
-%D
-%D \startusercode
-%D global.context("USER 1")
-%D context.par()
-%D context("USER 2")
-%D context.par()
-%D if characters then
-%D context("ACCESS directly")
-%D elseif global.characters then
-%D context("ACCESS via global")
-%D else
-%D context("NO ACCESS at all")
-%D end
-%D context.par()
-%D if bogus then
-%D context("ACCESS directly")
-%D elseif global.bogus then
-%D context("ACCESS via global")
-%D else
-%D context("NO ACCESS at all")
-%D end
-%D context.par()
-%D \stopusercode
-%D \stopbuffer
-%D
-%D \typebuffer
-
%D We need a way to pass strings safely to \LUA\ without the
%D need for tricky escaping. Compare:
%D
@@ -196,23 +118,28 @@
%D for it:
%D
%D \starttyping
-%D \long\edef\luaescapestring#1{\!!bs#1\!!es}
+%D \edef\luaescapestring#1{\!!bs#1\!!es}
%D \stoptyping
-\def\setdocumentfilename #1#2{\ctxlua{document.setfilename(#1,"#2")}}
-\def\setdocumentargument #1#2{\ctxlua{document.setargument("#1","#2")}}
-\def\setdocumentargumentdefault#1#2{\ctxlua{document.setdefaultargument("#1","#2")}}
-\def\getdocumentfilename #1{\ctxlua{document.getfilename("#1")}}
-\def\getdocumentargument #1{\ctxlua{document.getargument("#1")}}
-\def\getdocumentargumentdefault#1#2{\ctxlua{document.getargument("#1","#2")}}
-\def\doifdocumentargumentelse #1{\doifsomethingelse{\getdocumentargument{#1}}}
-\def\doifdocumentargument #1{\doifsomething {\getdocumentargument{#1}}}
-\def\doifnotdocumentargument #1{\doifnothing {\getdocumentargument{#1}}}
-\def\doifdocumentfilenameelse #1{\doifsomethingelse{\getdocumentfilename{#1}}}
-\def\doifdocumentfilename #1{\doifsomething {\getdocumentfilename{#1}}}
-\def\doifnotdocumentfilename #1{\doifnothing {\getdocumentfilename{#1}}}
-
-\let\doifelsedocumentargument\doifdocumentargumentelse
+\def\setdocumentfilename #1#2{\clf_setdocumentfilename\numexpr#1\relax{#2}}
+\def\setdocumentargument #1#2{\clf_setdocumentargument{#1}{#2}}
+\def\setdocumentargumentdefault#1#2{\clf_setdocumentdefaultargument{#1}{#2}}
+\def\getdocumentfilename #1{\clf_getdocumentfilename\numexpr#1\relax}
+\def\getdocumentargument #1{\clf_getdocumentargument{#1}{}}
+\def\setdocumentargument #1#2{\clf_setdocumentargument{#1}{#2}}
+\def\getdocumentargumentdefault#1#2{\clf_getdocumentargument{#1}{#2}}
+
+% seldom used so no need for speedy variants:
+
+\def\doifelsedocumentargument #1{\doifelsesomething{\clf_getdocumentargument{#1}}}
+\def\doifdocumentargument #1{\doifsomething {\clf_getdocumentargument{#1}}}
+\def\doifnotdocumentargument #1{\doifnothing {\clf_getdocumentargument{#1}}}
+\def\doifelsedocumentfilename #1{\doifelsesomething{\clf_getdocumentfilename\numexpr#1\relax}}
+\def\doifdocumentfilename #1{\doifsomething {\clf_getdocumentfilename\numexpr#1\relax}}
+\def\doifnotdocumentfilename #1{\doifnothing {\clf_getdocumentfilename\numexpr#1\relax}}
+
+\let\doifdocumentargumentelse\doifelsedocumentargument
+\let\doifdocumentfilenameelse\doifelsedocumentfilename
%D A handy helper:
@@ -220,7 +147,7 @@
%D Experimental:
-\unexpanded\def\startluaparameterset[#1]%
+\normalprotected\def\startluaparameterset[#1]%
{\begingroup
\obeylualines
\obeyluatokens
@@ -259,7 +186,7 @@
%D \ctxluacode{context("%0.5f",1/3)}
%D \stoptyping
-\unexpanded\def\ctxluacode
+\normalprotected\def\ctxluacode
{\begingroup
\obeylualines
\obeyluatokens
@@ -288,25 +215,19 @@
% \dorecurse{10000}{\ctxlua{context(" C3 ")}} \page
% \stoptext
-\installcorenamespace{ctxfunction}
+\installsystemnamespace{ctxfunction}
\normalprotected\def\startctxfunctiondefinition #1 %
{\begingroup \obeylualines \obeyluatokens \luat_start_lua_function_definition_indeed{#1}}
-% \def\luat_start_lua_function_definition_indeed#1#2\stopctxfunctiondefinition
-% {\endgroup\expandafter\edef\csname#1\endcsname{\noexpand\luafunction\ctxcommand{ctxfunction(\!!bs#2\!!es)}\relax}}
-
-\installcorenamespace{luafunction}
+\installsystemnamespace{luafunction}
\def\luat_start_lua_function_definition_indeed#1#2\stopctxfunctiondefinition
{\endgroup
\expandafter\chardef\csname\??luafunction#1\endcsname\ctxcommand{ctxfunction(\!!bs#2\!!es)}\relax
\expandafter\edef\csname#1\endcsname{\noexpand\luafunction\csname\??luafunction#1\endcsname}}
-% \unexpanded\def\setctxluafunction#1#2% experiment
-% {\expandafter\chardef\csname#1\endcsname#2\relax}
-
-\unexpanded\def\setctxluafunction#1#2% experiment
+\normalprotected\def\setctxluafunction#1#2% experiment
{\expandafter\chardef\csname\??luafunction#1\endcsname#2\relax
\expandafter\edef\csname#1\endcsname{\noexpand\luafunction\csname\??luafunction#1\endcsname}}
@@ -323,4 +244,40 @@
\def\ctxfunction#1%
{\csname\??ctxfunction#1\endcsname}
+% In theory this is faster due to the call not being wrapped in a function but in
+% practice the speedup can't be noticed. The actions called for often have lots of
+% lookups so an extra one doesn't matter much. The kind of calls differs a lot per
+% document and often there are other ways to optimize a style. For instance we can
+% gain a lot when defining a font, but when a frozen definition is used that gain
+% gets completely lost. For some calls (take list writers) it can get worse if only
+% because readability gets worse and passing is already efficient due to selective
+% flushing, while with the token scanners one has to scan all of them.
+
+% \startctxfunctiondefinition foo commands.foo() \stopctxfunctiondefinition
+%
+% \installctxfunction\foo{commands.foo}
+
+% This is a forward definition:
+
+\def\checkedstrippedcsname#1% this permits \strippedcsname{\xxx} and \strippedcsname{xxx}
+ {\expandafter\syst_helpers_checked_stripped_csname\string#1}
+
+\def\syst_helpers_checked_stripped_csname#1%
+ {\if\noexpand#1\letterbackslash\else#1\fi}
+
+\normalprotected\def\installctxfunction#1#2%
+ {\edef\m_syst_name{\checkedstrippedcsname#1}%
+ \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxfunction("#2",true)}\relax
+ \expandafter\xdef\csname\m_syst_name\endcsname{\noexpand\luafunction\csname\??luafunction\m_syst_name\endcsname}}
+
+\normalprotected\def\installctxscanner#1#2%
+ {\edef\m_syst_name{\checkedstrippedcsname#1}%
+ \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name","#2",true)}\relax
+ \expandafter\xdef\csname\m_syst_name\endcsname{\noexpand\luafunction\csname\??luafunction\m_syst_name\endcsname}}
+
+\normalprotected\def\resetctxscanner#1%
+ {\edef\m_syst_name{\checkedstrippedcsname#1}%
+ \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\zerocount
+ \global\expandafter\let\csname\m_syst_name\endcsname\relax}
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/luat-iop.lua b/Master/texmf-dist/tex/context/base/luat-iop.lua
index 52f14683e76..e1772af4e90 100644
--- a/Master/texmf-dist/tex/context/base/luat-iop.lua
+++ b/Master/texmf-dist/tex/context/base/luat-iop.lua
@@ -6,190 +6,19 @@ if not modules then modules = { } end modules ['luat-iop'] = {
license = "see context related readme files"
}
--- this paranoid stuff in web2c ... we cannot hook checks into the
--- input functions because one can always change the callback but
--- we can feed back specific patterns and paths into the next
--- mechanism
-
--- os.execute os.exec os.spawn io.fopen
--- os.remove lfs.chdir lfs.mkdir
--- io.open zip.open epdf.open mlib.new
-
--- cache
-
-local topattern, find = string.topattern, string.find
-
-local report_limiter = logs.reporter("system","limiter")
-
--- the basic methods
-
-local function match(ruleset,name)
- local n = #ruleset
- if n > 0 then
- for i=1,n do
- local r = ruleset[i]
- if find(name,r[1]) then
- return r[2]
- end
- end
- return false
- else
- -- nothing defined (or any)
- return true
- end
-end
-
-local function protect(ruleset,proc)
- return function(name,...)
- if name == "" then
- -- report_limiter("no access permitted: ") -- can happen in mplib code
- return nil, "no name given"
- elseif match(ruleset,name) then
- return proc(name,...)
- else
- report_limiter("no access permitted for %a",name)
- return nil, name .. ": no access permitted"
- end
- end
-end
-
-function io.limiter(preset)
- preset = preset or { }
- local ruleset = { }
- for i=1,#preset do
- local p = preset[i]
- local what, spec = p[1] or "", p[2] or ""
- if spec == "" then
- -- skip 'm
- elseif what == "tree" then
- resolvers.dowithpath(spec, function(r)
- local spec = resolvers.resolve(r) or ""
- if spec ~= "" then
- ruleset[#ruleset+1] = { topattern(spec,true), true }
- end
- end)
- elseif what == "permit" then
- ruleset[#ruleset+1] = { topattern(spec,true), true }
- elseif what == "forbid" then
- ruleset[#ruleset+1] = { topattern(spec,true), false }
- end
- end
- if #ruleset > 0 then
- return {
- match = function(name) return match (ruleset,name) end,
- protect = function(proc) return protect(ruleset,proc) end,
- }
- else
- return {
- match = function(name) return true end,
- protect = proc,
- }
- end
-end
-
--- a few handlers
-
-io.i_limiters = { }
-io.o_limiters = { }
-
-function io.i_limiter(v)
- local i = io.i_limiters[v]
- if i then
- local i_limiter = io.limiter(i)
- function io.i_limiter()
- return i_limiter
- end
- return i_limiter
- end
-end
-
-function io.o_limiter(v)
- local o = io.o_limiters[v]
- if o then
- local o_limiter = io.limiter(o)
- function io.o_limiter()
- return o_limiter
- end
- return o_limiter
- end
-end
-
--- the real thing (somewhat fuzzy as we need to know what gets done)
-
-local i_opener, i_limited = io.open, false
-local o_opener, o_limited = io.open, false
-
-local function i_register(v)
- if not i_limited then
- local i_limiter = io.i_limiter(v)
- if i_limiter then
- local protect = i_limiter.protect
- i_opener = protect(i_opener)
- i_limited = true
- report_limiter("input mode set to %a",v)
- end
- end
-end
-
-local function o_register(v)
- if not o_limited then
- local o_limiter = io.o_limiter(v)
- if o_limiter then
- local protect = o_limiter.protect
- o_opener = protect(o_opener)
- o_limited = true
- report_limiter("output mode set to %a",v)
- end
- end
-end
-
-function io.open(name,method)
- if method and find(method,"[wa]") then
- return o_opener(name,method)
- else
- return i_opener(name,method)
- end
-end
-
-directives.register("system.inputmode", i_register)
-directives.register("system.outputmode", o_register)
-
-local i_limited = false
-local o_limited = false
-
-local function i_register(v)
- if not i_limited then
- local i_limiter = io.i_limiter(v)
- if i_limiter then
- local protect = i_limiter.protect
- lfs.chdir = protect(lfs.chdir) -- needs checking
- i_limited = true
- end
- end
-end
-
-local function o_register(v)
- if not o_limited then
- local o_limiter = io.o_limiter(v)
- if o_limiter then
- local protect = o_limiter.protect
- os.remove = protect(os.remove) -- rather okay
- lfs.chdir = protect(lfs.chdir) -- needs checking
- lfs.mkdir = protect(lfs.mkdir) -- needs checking
- o_limited = true
- end
- end
-end
-
-directives.register("system.inputmode", i_register)
-directives.register("system.outputmode", o_register)
-
--- the definitions
-
-local limiters = resolvers.variable("limiters")
-
-if limiters then
- io.i_limiters = limiters.input or { }
- io.o_limiters = limiters.output or { }
-end
-
+local cleanedpathlist = resolvers.cleanedpathlist
+local registerroot = sandbox.registerroot
+
+sandbox.initializer(function()
+ local function register(str,mode)
+ local trees = cleanedpathlist(str)
+ for i=1,#trees do
+ registerroot(trees[i],mode)
+ end
+ end
+ register("TEXMF","read")
+ register("TEXINPUTS","read")
+ register("MPINPUTS","read")
+ -- register("TEXMFCACHE","write")
+ registerroot(".","write")
+end)
diff --git a/Master/texmf-dist/tex/context/base/luat-lib.mkiv b/Master/texmf-dist/tex/context/base/luat-lib.mkiv
index 3f72e780e8b..24f9da41513 100644
--- a/Master/texmf-dist/tex/context/base/luat-lib.mkiv
+++ b/Master/texmf-dist/tex/context/base/luat-lib.mkiv
@@ -36,6 +36,8 @@
\registerctxluafile{util-sta}{1.001}
+\registerctxluafile{util-sbx}{1.001} % needs tracker and templates
+
\registerctxluafile{data-ini}{1.001}
\registerctxluafile{data-exp}{1.001}
\registerctxluafile{data-env}{1.001}
@@ -71,8 +73,8 @@
\registerctxluafile{luat-ini}{1.001}
\registerctxluafile{util-env}{1.001}
\registerctxluafile{luat-env}{1.001}
-\registerctxluafile{luat-exe}{1.001}
-\registerctxluafile{luat-iop}{1.001}
+\registerctxluafile{luat-exe}{1.001} % simplified
+\registerctxluafile{luat-iop}{1.001} % simplified
\registerctxluafile{luat-bwc}{1.001}
\registerctxluafile{trac-lmx}{1.001} % might become l-lmx or luat-lmx
\registerctxluafile{luat-mac}{1.001}
diff --git a/Master/texmf-dist/tex/context/base/luat-mac.lua b/Master/texmf-dist/tex/context/base/luat-mac.lua
index 282dc8ce3d3..6214e591e5b 100644
--- a/Master/texmf-dist/tex/context/base/luat-mac.lua
+++ b/Master/texmf-dist/tex/context/base/luat-mac.lua
@@ -92,7 +92,7 @@ local nolong = 1 - longleft - longright
local utf8character = P(1) * R("\128\191")^1 -- unchecked but fast
local name = (R("AZ","az") + utf8character)^1
-local csname = (R("AZ","az") + S("@?!_") + utf8character)^1
+local csname = (R("AZ","az") + S("@?!_:-*") + utf8character)^1
local longname = (longleft/"") * (nolong^1) * (longright/"")
local variable = P("#") * Cs(name + longname)
local escapedname = escape * csname
@@ -144,7 +144,10 @@ local grammar = { "converter",
* V("texbody")
* stopcode
* poplocal,
- texbody = ( V("definition")
+ texbody = (
+leadingcomment -- new per 2015-03-03 (ugly)
++
+ V("definition")
+ identifier
+ V("braced")
+ (1 - stopcode)
@@ -201,7 +204,7 @@ end
function macros.convertfile(oldname,newname) -- beware, no testing on oldname == newname
local data = resolvers.loadtexfile(oldname)
- data = interfaces.preprocessed(data) or ""
+ data = interfaces.preprocessed(data) or "" -- interfaces not yet defined
io.savedata(newname,data)
end
@@ -385,7 +388,7 @@ end
-- \normalexpanded
-- {\def\yes[#one]#two\csname\e!stop#stoptag\endcsname{\command_yes[#one]{#two}}%
-- \def\nop #one\csname\e!stop#stoptag\endcsname{\command_nop {#one}}}%
--- \doifnextoptionalelse\yes\nop}
+-- \doifelsenextoptional\yes\nop}
-- ]]))
--
-- print(macros.preprocessed([[
diff --git a/Master/texmf-dist/tex/context/base/luat-run.lua b/Master/texmf-dist/tex/context/base/luat-run.lua
index 607c3528ae7..65cf0f33866 100644
--- a/Master/texmf-dist/tex/context/base/luat-run.lua
+++ b/Master/texmf-dist/tex/context/base/luat-run.lua
@@ -130,31 +130,21 @@ luatex.registerstopactions(luatex.cleanuptempfiles)
-- for the moment here
-local synctex = false
-
local report_system = logs.reporter("system")
+local synctex = 0
directives.register("system.synctex", function(v)
- synctex = v
- if v then
- report_system("synctex functionality is enabled!")
+ synctex = tonumber(v) or (toboolean(v,true) and 1) or (v == "zipped" and 1) or (v == "unzipped" and -1) or 0
+ if synctex ~= 0 then
+ report_system("synctex functionality is enabled (%s)!",tostring(synctex))
else
report_system("synctex functionality is disabled!")
end
- synctex = tonumber(synctex) or (toboolean(synctex,true) and 1) or (synctex == "zipped" and 1) or (synctex == "unzipped" and -1) or false
- -- currently this is bugged:
- tex.synctex = synctex
- -- so for the moment we need:
- context.normalsynctex()
- if synctex then
- context.plusone()
- else
- context.zerocount()
- end
+ tex.normalsynctex = synctex
end)
statistics.register("synctex tracing",function()
- if synctex or tex.synctex ~= 0 then
+ if synctex ~= 0 then
return "synctex has been enabled (extra log file generated)"
end
end)
@@ -230,3 +220,12 @@ directives.register("system.reportfiles", function(v)
register("stop_file", report_none)
end
end)
+
+-- start_run doesn't work
+
+-- luatex.registerstartactions(function()
+-- if environment.arguments.sandbox then
+-- sandbox.enable()
+-- end
+-- end)
+
diff --git a/Master/texmf-dist/tex/context/base/luat-usr.lua b/Master/texmf-dist/tex/context/base/luat-usr.lua
new file mode 100644
index 00000000000..071e3bf5bb9
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/luat-usr.lua
@@ -0,0 +1,192 @@
+if not modules then modules = { } end modules ['luat-usr'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local global = global
+
+local moduledata = moduledata
+local thirddata = thirddata
+local userdata = userdata
+local documentdata = documentdata
+
+local context = context
+local tostring = tostring
+local tonumber = tonumber
+local print = print
+
+local string = string
+local table = table
+local lpeg = lpeg
+local math = math
+local io = io
+local os = os
+local lpeg = lpeg
+
+local luanames = lua.name -- luatex itself
+
+local setmetatableindex = table.setmetatableindex
+local load = load
+local xpcall = xpcall
+local instance_banner = string.formatters["=[instance: %s]"] -- the = controls the lua error / see: lobject.c
+local tex_errormessage = context.errmessage
+
+local implement = interfaces.implement
+local reporter = logs.reporter
+
+local report_instance = reporter("lua instance")
+local report_script = reporter("lua script")
+local report_thread = reporter("lua thread")
+local newline = logs.newline
+
+lua.numbers = lua.numbers or { }
+lua.messages = lua.messages or { }
+
+local numbers = lua.numbers
+local messages = lua.messages
+
+storage.register("lua/numbers", numbers, "lua.numbers" )
+storage.register("lua/messages", messages, "lua.messages")
+
+-- First we implement a pure lua version of directlua and a persistent
+-- variant of it:
+
+local function runscript(code)
+ local done, message = loadstring(code)
+ if done then
+ done()
+ else
+ newline()
+ report_script("error : %s",message or "unknown")
+ report_script()
+ report_script("code : %s",code)
+ newline()
+ end
+end
+
+local threads = setmetatableindex(function(t,k)
+ local v = setmetatableindex({},global)
+ t[k] = v
+ return v
+end)
+
+local function runthread(name,code)
+ if not code or code == "" then
+ threads[name] = nil
+ else
+ local thread = threads[name]
+ local done, message = loadstring(code,nil,nil,thread)
+ if done then
+ done()
+ else
+ newline()
+ report_thread("thread: %s",name)
+ report_thread("error : %s",message or "unknown")
+ report_thread()
+ report_thread("code : %s",code)
+ newline()
+ end
+ end
+end
+
+interfaces.implement {
+ name = "luascript",
+ actions = runscript,
+ arguments = "string"
+}
+
+interfaces.implement {
+ name = "luathread",
+ actions = runthread,
+ arguments = { "string", "string" }
+}
+
+-- local scanners = interfaces.scanners
+--
+-- local function ctxscanner(name)
+-- local scanner = scanners[name]
+-- if scanner then
+-- scanner()
+-- else
+-- report("unknown scanner: %s",name)
+-- end
+-- end
+--
+-- interfaces.implement {
+-- name = "clfscanner",
+-- actions = ctxscanner,
+-- arguments = "string",
+-- }
+
+local function registername(name,message)
+ if not name or name == "" then
+ report_instance("no valid name given")
+ return
+ end
+ if not message or message == "" then
+ message = name
+ end
+ local lnn = numbers[name]
+ if not lnn then
+ lnn = #messages + 1
+ messages[lnn] = message
+ numbers[name] = lnn
+ end
+ luanames[lnn] = instance_banner(message)
+ local report = reporter("lua instance",message)
+ local proxy = {
+ -- we can access all via:
+ global = global, -- or maybe just a metatable
+ -- some protected data
+ moduledata = setmetatableindex(moduledata),
+ thirddata = setmetatableindex(thirddata),
+ -- less protected data
+ userdata = userdata,
+ documentdata = documentdata,
+ -- always there fast
+ context = context,
+ tostring = tostring,
+ tonumber = tonumber,
+ -- standard lua modules
+ string = string,
+ table = table,
+ lpeg = lpeg,
+ math = math,
+ io = io,
+ os = os,
+ lpeg = lpeg,
+ --
+ print = print,
+ report = report,
+ }
+ return function(code)
+ local code, message = load(code,nil,nil,proxy)
+ if not code then
+ report_instance("error: %s",message or code)
+ elseif not xpcall(code,report) then
+ tex_errormessage("hit return to continue or quit this run")
+ end
+ end
+end
+
+lua.registername = registername
+
+implement {
+ name = "registernamedlua",
+ arguments = { "string", "string", "string" },
+ actions = function(name,message,csname)
+ if csname and csname ~= "" then
+ implement {
+ name = csname,
+ arguments = "string",
+ actions = registername(name,message) or report,
+ scope = "private",
+ }
+ else
+ report_instance("unvalid csname for %a",message or name or "?")
+ end
+ end
+}
diff --git a/Master/texmf-dist/tex/context/base/luat-usr.mkiv b/Master/texmf-dist/tex/context/base/luat-usr.mkiv
new file mode 100644
index 00000000000..92d40010c0f
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/luat-usr.mkiv
@@ -0,0 +1,126 @@
+%D \module
+%D [ file=luat-usr,
+%D version=2005.08.11,% moved from luat-ini
+%D title=\CONTEXT\ Lua Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Lua Macros / Userspace}
+
+\unprotect
+
+\registerctxluafile{luat-usr}{1.001}
+
+%D A few goodies:
+%D
+%D \startbuffer
+%D \luascript { context("foo 1:") context(i) }
+%D \luathread {test} { i = 10 context("bar 1:") context(i) }
+%D \luathread {test} { context("bar 2:") context(i) }
+%D \luathread {test} {}
+%D \luathread {test} { context("bar 3:") context(i) }
+%D \luascript { context("foo 2:") context(i) }
+%D \stopbuffer
+%D
+%D \typebuffer \startlines \getbuffer \stoplines
+
+\let\luascript \clf_luascript
+\let\luathread \clf_luathread
+%let\clfscanner\clf_clfscanner
+%def\clfscanner#1{\csname clf_#1\endcsname}
+
+%D \macros
+%D {definenamedlua}
+%D
+%D We provide an interface for defining instances:
+
+\def\s!lua {lua}
+\def\s!code {code}
+\def\s!data {data}
+%def\s!start{start}
+%def\s!stop {stop}
+
+%D Beware: because \type {\expanded} is een convert command, the error
+%D message will show \type{} as part of the message.
+
+\installsystemnamespace{luacode}
+
+\unexpanded\def\definenamedlua
+ {\bgroup
+ \dodoubleempty\syst_definenamedlua}
+
+\unexpanded\def\syst_definenamedlua[#1][#2]% no optional arg handling here yet / we could use numbers instead (more efficient)
+ {\iffirstargument
+ \ifcsname\??luacode#1\endcsname \else
+ %
+ \edef\fullname{lua_code_#1}%
+ %
+ \clf_registernamedlua{#1}{#2}{\fullname}%
+ %
+ \unexpanded\expandafter\xdef\csname\s!start#1\s!code\endcsname
+ {\begingroup
+ \obeylualines
+ \obeyluatokens
+ \csname\??luacode#1\endcsname}%
+ %
+ \global\expandafter\let\csname\s!stop#1\s!code\endcsname\relax
+ %
+ \normalexpanded{\xdef\csname\??luacode#1\endcsname##1\csname\s!stop#1\s!code\endcsname}%
+ {\noexpand\expandafter\endgroup
+ \noexpand\expandafter
+ \expandafter\noexpand\csname clf_\fullname\endcsname
+ \noexpand\expandafter{\noexpand\normalexpanded{##1}}}%
+ %
+ \global\expandafter\let\csname#1\s!code\expandafter\endcsname\csname clf_\fullname\endcsname
+ \fi
+ \fi
+ \egroup}
+
+%D We predefine a few.
+
+% \definenamedlua[module][module instance] % not needed
+
+\definenamedlua[user] [private user]
+\definenamedlua[third] [third party module]
+\definenamedlua[isolated][isolated]
+
+%D In practice this works out as follows:
+%D
+%D \startbuffer
+%D \startluacode
+%D context("LUA")
+%D \stopluacode
+%D
+%D \startusercode
+%D global.context("USER 1")
+%D context.par()
+%D context("USER 2")
+%D context.par()
+%D if characters then
+%D context("ACCESS directly")
+%D elseif global.characters then
+%D context("ACCESS via global")
+%D else
+%D context("NO ACCESS at all")
+%D end
+%D context.par()
+%D if bogus then
+%D context("ACCESS directly")
+%D elseif global.bogus then
+%D context("ACCESS via global")
+%D else
+%D context("NO ACCESS at all")
+%D end
+%D context.par()
+%D \stopusercode
+%D \stopbuffer
+%D
+%D \typebuffer
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/lxml-aux.lua b/Master/texmf-dist/tex/context/base/lxml-aux.lua
index 0fffe261a00..f6816ccb6b0 100644
--- a/Master/texmf-dist/tex/context/base/lxml-aux.lua
+++ b/Master/texmf-dist/tex/context/base/lxml-aux.lua
@@ -10,20 +10,23 @@ if not modules then modules = { } end modules ['lxml-aux'] = {
-- compatibility reasons
local trace_manipulations = false trackers.register("lxml.manipulations", function(v) trace_manipulations = v end)
+local trace_inclusions = false trackers.register("lxml.inclusions", function(v) trace_inclusions = v end)
local report_xml = logs.reporter("xml")
local xml = xml
-local xmlconvert, xmlcopy, xmlname = xml.convert, xml.copy, xml.name
+local xmlcopy, xmlname = xml.copy, xml.name
local xmlinheritedconvert = xml.inheritedconvert
local xmlapplylpath = xml.applylpath
local xmlfilter = xml.filter
-local type, setmetatable, getmetatable = type, setmetatable, getmetatable
+local type, next, setmetatable, getmetatable = type, next, setmetatable, getmetatable
local insert, remove, fastcopy, concat = table.insert, table.remove, table.fastcopy, table.concat
local gmatch, gsub, format, find, strip = string.gmatch, string.gsub, string.format, string.find, string.strip
local utfbyte = utf.byte
+local lpegmatch = lpeg.match
+local striplinepatterns = utilities.strings.striplinepatterns
local function report(what,pattern,c,e)
report_xml("%s element %a, root %a, position %a, index %a, pattern %a",what,xmlname(e),xmlname(e.__p__),c,e.ni,pattern)
@@ -83,13 +86,15 @@ end
function xml.each(root,pattern,handle,reverse)
local collected = xmlapplylpath(root,pattern)
if collected then
- if reverse then
- for c=#collected,1,-1 do
- handle(collected[c])
- end
- else
- for c=1,#collected do
- handle(collected[c])
+ if handle then
+ if reverse then
+ for c=#collected,1,-1 do
+ handle(collected[c])
+ end
+ else
+ for c=1,#collected do
+ handle(collected[c])
+ end
end
end
return collected
@@ -162,6 +167,8 @@ local function redo_ni(d)
end
end
+xml.reindex = redo_ni
+
local function xmltoelement(whatever,root)
if not whatever then
return nil
@@ -221,8 +228,18 @@ function xml.delete(root,pattern)
report('deleting',pattern,c,e)
end
local d = p.dt
- remove(d,e.ni)
- redo_ni(d) -- can be made faster and inlined
+ local ni = e.ni
+ if ni <= #d then
+ if false then
+ p.dt[ni] = ""
+ else
+ -- what if multiple deleted in one set
+ remove(d,ni)
+ redo_ni(d) -- can be made faster and inlined
+ end
+ else
+ -- disturbing
+ end
end
end
end
@@ -353,46 +370,63 @@ xml.insertbefore = function(r,p,e) insert_element(r,p,e,true) end
xml.injectafter = inject_element
xml.injectbefore = function(r,p,e) inject_element(r,p,e,true) end
-local function include(xmldata,pattern,attribute,recursive,loaddata)
- -- parse="text" (default: xml), encoding="" (todo)
- -- attribute = attribute or 'href'
- pattern = pattern or 'include'
- loaddata = loaddata or io.loaddata
+local function include(xmldata,pattern,attribute,recursive,loaddata,level)
+ -- attribute = attribute or 'href'
+ pattern = pattern or 'include'
+ loaddata = loaddata or io.loaddata
local collected = xmlapplylpath(xmldata,pattern)
if collected then
+ if not level then
+ level = 1
+ end
for c=1,#collected do
local ek = collected[c]
local name = nil
local ekdt = ek.dt
local ekat = ek.at
- local epdt = ek.__p__.dt
+ local ekrt = ek.__p__
+ local epdt = ekrt.dt
if not attribute or attribute == "" then
name = (type(ekdt) == "table" and ekdt[1]) or ekdt -- check, probably always tab or str
end
if not name then
for a in gmatch(attribute or "href","([^|]+)") do
name = ekat[a]
- if name then break end
+ if name then
+ break
+ end
+ end
+ end
+ local data = nil
+ if name and name ~= "" then
+ data = loaddata(name) or ""
+ if trace_inclusions then
+ report_xml("including %s bytes from %a at level %s by pattern %a and attribute %a (%srecursing)",#data,name,level,pattern,attribute or "",recursive and "" or "not ")
end
end
- local data = (name and name ~= "" and loaddata(name)) or ""
- if data == "" then
+ if not data or data == "" then
epdt[ek.ni] = "" -- xml.empty(d,k)
elseif ekat["parse"] == "text" then
-- for the moment hard coded
epdt[ek.ni] = xml.escaped(data) -- d[k] = xml.escaped(data)
else
---~ local settings = xmldata.settings
---~ settings.parent_root = xmldata -- to be tested
---~ local xi = xmlconvert(data,settings)
local xi = xmlinheritedconvert(data,xmldata)
if not xi then
epdt[ek.ni] = "" -- xml.empty(d,k)
else
if recursive then
- include(xi,pattern,attribute,recursive,loaddata)
+ include(xi,pattern,attribute,recursive,loaddata,level+1)
+ end
+ local child = xml.body(xi) -- xml.assign(d,k,xi)
+ child.__p__ = ekrt
+ child.__f__ = name -- handy for tracing
+ epdt[ek.ni] = child
+ local inclusions = xmldata.settings.inclusions
+ if inclusions then
+ inclusions[#inclusions+1] = name
+ else
+ xmldata.settings.inclusions = { name }
end
- epdt[ek.ni] = xml.body(xi) -- xml.assign(d,k,xi)
end
end
end
@@ -401,68 +435,100 @@ end
xml.include = include
+function xml.inclusion(e,default)
+ while e do
+ local f = e.__f__
+ if f then
+ return f
+ else
+ e = e.__p__
+ end
+ end
+ return default
+end
+
+function xml.inclusions(e,sorted)
+ while e do
+ local settings = e.settings
+ if settings then
+ local inclusions = settings.inclusions
+ if inclusions then
+ inclusions = table.unique(inclusions) -- a copy
+ if sorted then
+ table.sort(inclusions) -- so we sort the copy
+ end
+ return inclusions -- and return the copy
+ else
+ e = e.__p__
+ end
+ else
+ e = e.__p__
+ end
+ end
+end
+
+local b_collapser = lpeg.patterns.b_collapser
+local m_collapser = lpeg.patterns.m_collapser
+local e_collapser = lpeg.patterns.e_collapser
+
+local b_stripper = lpeg.patterns.b_stripper
+local m_stripper = lpeg.patterns.m_stripper
+local e_stripper = lpeg.patterns.e_stripper
+
+local lpegmatch = lpeg.match
+
local function stripelement(e,nolines,anywhere)
local edt = e.dt
if edt then
- if anywhere then
- local t, n = { }, 0
- for e=1,#edt do
+ local n = #edt
+ if n == 0 then
+ return e -- convenient
+ elseif anywhere then
+ local t = { }
+ local m = 0
+ for e=1,n do
local str = edt[e]
if type(str) ~= "string" then
- n = n + 1
- t[n] = str
+ m = m + 1
+ t[m] = str
elseif str ~= "" then
- -- todo: lpeg for each case
if nolines then
- str = gsub(str,"%s+"," ")
+ str = lpegmatch((n == 1 and b_collapser) or (n == m and e_collapser) or m_collapser,str)
+ else
+ str = lpegmatch((n == 1 and b_stripper) or (n == m and e_stripper) or m_stripper,str)
end
- str = gsub(str,"^%s*(.-)%s*$","%1")
if str ~= "" then
- n = n + 1
- t[n] = str
+ m = m + 1
+ t[m] = str
end
end
end
e.dt = t
else
- -- we can assume a regular sparse xml table with no successive strings
- -- otherwise we should use a while loop
- if #edt > 0 then
- -- strip front
- local str = edt[1]
- if type(str) ~= "string" then
- -- nothing
- elseif str == "" then
+ local str = edt[1]
+ if type(str) == "string" then
+ if str ~= "" then
+ str = lpegmatch(nolines and b_collapser or b_stripper,str)
+ end
+ if str == "" then
remove(edt,1)
+ n = n - 1
else
- if nolines then
- str = gsub(str,"%s+"," ")
- end
- str = gsub(str,"^%s+","")
- if str == "" then
- remove(edt,1)
- else
- edt[1] = str
- end
+ edt[1] = str
end
end
- local nedt = #edt
- if nedt > 0 then
- -- strip end
- local str = edt[nedt]
- if type(str) ~= "string" then
- -- nothing
- elseif str == "" then
- remove(edt)
- else
- if nolines then
- str = gsub(str,"%s+"," ")
- end
- str = gsub(str,"%s+$","")
+ if n > 0 then
+ str = edt[n]
+ if type(str) == "string" then
if str == "" then
remove(edt)
else
- edt[nedt] = str
+ str = lpegmatch(nolines and e_collapser or e_stripper,str)
+ if str == "" then
+ remove(edt)
+ else
+ edt[n] = str
+ end
end
end
end
@@ -702,8 +768,8 @@ function xml.finalizers.xml.cdata(collected)
return ""
end
-function xml.insertcomment(e,str,n) -- also insertcdata
- table.insert(e.dt,n or 1,{
+function xml.insertcomment(e,str,n)
+ insert(e.dt,n or 1,{
tg = "@cm@",
ns = "",
special = true,
@@ -712,7 +778,27 @@ function xml.insertcomment(e,str,n) -- also insertcdata
})
end
-function xml.setcdata(e,str) -- also setcomment
+function xml.insertcdata(e,str,n)
+ insert(e.dt,n or 1,{
+ tg = "@cd@",
+ ns = "",
+ special = true,
+ at = { },
+ dt = { str },
+ })
+end
+
+function xml.setcomment(e,str,n)
+ e.dt = { {
+ tg = "@cm@",
+ ns = "",
+ special = true,
+ at = { },
+ dt = { str },
+ } }
+end
+
+function xml.setcdata(e,str)
e.dt = { {
tg = "@cd@",
ns = "",
@@ -790,7 +876,7 @@ local function recurse(e,action)
for i=1,#edt do
local str = edt[i]
if type(str) ~= "string" then
- recurse(str,action,recursive)
+ recurse(str,action) -- ,recursive
elseif str ~= "" then
edt[i] = action(str)
end
@@ -809,3 +895,91 @@ function helpers.recursetext(collected,action,recursive)
end
end
end
+
+-- on request ... undocumented ...
+--
+-- _tag : element name
+-- _type : node type (_element can be an option)
+-- _namespace : only if given
+--
+-- [1..n] : text or table
+-- key : value or attribite 'key'
+--
+-- local str = [[
+--
+--
+--
+--
+--
+-- c > d
+--
+--
+-- ]]
+--
+-- inspect(xml.totable(xml.convert(str)))
+-- inspect(xml.totable(xml.convert(str),true))
+-- inspect(xml.totable(xml.convert(str),true,true))
+
+local specials = {
+ ["@rt@"] = "root",
+ ["@pi@"] = "instruction",
+ ["@cm@"] = "comment",
+ ["@dt@"] = "declaration",
+ ["@cd@"] = "cdata",
+}
+
+local function convert(x,strip,flat)
+ local ns = x.ns
+ local tg = x.tg
+ local at = x.at
+ local dt = x.dt
+ local node = flat and {
+ [0] = (not x.special and (ns ~= "" and ns .. ":" .. tg or tg)) or nil,
+ } or {
+ _namespace = ns ~= "" and ns or nil,
+ _tag = not x.special and tg or nil,
+ _type = specials[tg] or "_element",
+ }
+ if at then
+ for k, v in next, at do
+ node[k] = v
+ end
+ end
+ local n = 0
+ for i=1,#dt do
+ local di = dt[i]
+ if type(di) == "table" then
+ if flat and di.special then
+ -- ignore
+ else
+ di = convert(di,strip,flat)
+ if di then
+ n = n + 1
+ node[n] = di
+ end
+ end
+ elseif strip then
+ di = lpegmatch(strip,di)
+ if di ~= "" then
+ n = n + 1
+ node[n] = di
+ end
+ else
+ n = n + 1
+ node[n] = di
+ end
+ end
+ if next(node) then
+ return node
+ end
+end
+
+function xml.totable(x,strip,flat)
+ if type(x) == "table" then
+ if strip then
+ strip = striplinepatterns[strip]
+ end
+ return convert(x,strip,flat)
+ end
+end
+
diff --git a/Master/texmf-dist/tex/context/base/lxml-css.lua b/Master/texmf-dist/tex/context/base/lxml-css.lua
index 0deaea4d391..fa921b24f48 100644
--- a/Master/texmf-dist/tex/context/base/lxml-css.lua
+++ b/Master/texmf-dist/tex/context/base/lxml-css.lua
@@ -146,7 +146,19 @@ local pattern = Cf( Ct("") * (
+ (C("sansserif") + C("sans")) / "sans-serif" -- match before serif
+ C("serif")
)
- ) + P(1)
+ )
+--+ P("\\") * (
+-- P("bf") * ( Cg ( Cc("weight") * Cc("bold") ) )
+-- + P("bi") * ( Cg ( Cc("weight") * Cc("bold") )
+-- * Cg ( Cc("style") * Cc("italic") ) )
+-- + P("bs") * ( Cg ( Cc("weight") * Cc("bold") )
+-- * Cg ( Cc("style") * Cc("oblique") ) )
+-- + P("it") * ( Cg ( Cc("style") * Cc("italic") ) )
+-- + P("sl") * ( Cg ( Cc("style") * Cc("oblique") ) )
+-- + P("sc") * ( Cg ( Cc("variant") * Cc("small-caps") ) )
+-- + P("tt") * ( Cg ( Cc("family") * Cc("monospace") ) )
+--)
+ + P(1)
)^0 , rawset)
function css.fontspecification(str)
diff --git a/Master/texmf-dist/tex/context/base/lxml-ini.lua b/Master/texmf-dist/tex/context/base/lxml-ini.lua
new file mode 100644
index 00000000000..64e78eb42c8
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/lxml-ini.lua
@@ -0,0 +1,136 @@
+if not modules then modules = { } end modules ['lxml-ini'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local xml = xml
+local lxml = lxml
+
+-- this defines an extra scanner lxmlid:
+
+local scanners = tokens.scanners
+local scanstring = scanners.string
+local getid = lxml.id
+
+scanners.lxmlid = function() return getid(scanstring()) end
+
+local implement = interfaces.implement
+
+-- lxml.id
+
+implement { name = "lxmlid", actions = lxml.getid, arguments = "string" }
+
+implement { name = "xmldoif", actions = lxml.doif, arguments = { "string", "string" } }
+implement { name = "xmldoifnot", actions = lxml.doifnot, arguments = { "string", "string" } }
+implement { name = "xmldoifelse", actions = lxml.doifelse, arguments = { "string", "string" } }
+implement { name = "xmldoiftext", actions = lxml.doiftext, arguments = { "string", "string" } }
+implement { name = "xmldoifnottext", actions = lxml.doifnottext, arguments = { "string", "string" } }
+implement { name = "xmldoifelsetext", actions = lxml.doifelsetext, arguments = { "string", "string" } }
+
+implement { name = "xmldoifempty", actions = lxml.doifempty, arguments = { "string", "string" } }
+implement { name = "xmldoifnotempty", actions = lxml.doifnotempty, arguments = { "string", "string" } }
+implement { name = "xmldoifelseempty", actions = lxml.doifelseempty, arguments = { "string", "string" } }
+implement { name = "xmldoifselfempty", actions = lxml.doifempty, arguments = "string" }
+implement { name = "xmldoifnotselfempty", actions = lxml.doifnotempty, arguments = "string" }
+implement { name = "xmldoifelseselfempty", actions = lxml.doifelseempty, arguments = "string" }
+
+--------- { name = "xmlcontent", actions = lxml.content, arguments = "string" }
+--------- { name = "xmlflushstripped", actions = lxml.strip, arguments = { "string", true } }
+implement { name = "xmlall", actions = lxml.all, arguments = { "string", "string" } }
+implement { name = "xmlatt", actions = lxml.att, arguments = { "string", "string" } }
+implement { name = "xmlattdef", actions = lxml.att, arguments = { "string", "string", "string" } }
+implement { name = "xmlattribute", actions = lxml.attribute, arguments = { "string", "string", "string" } }
+implement { name = "xmlattributedef", actions = lxml.attribute, arguments = { "string", "string", "string", "string" } }
+implement { name = "xmlchainatt", actions = lxml.chainattribute, arguments = { "string", "'/'", "string" } }
+implement { name = "xmlchainattdef", actions = lxml.chainattribute, arguments = { "string", "'/'", "string", "string" } }
+implement { name = "xmlchecknamespace", actions = xml.checknamespace, arguments = { "lxmlid", "string", "string" } }
+implement { name = "xmlcommand", actions = lxml.command, arguments = { "string", "string", "string" } }
+implement { name = "xmlconcat", actions = lxml.concat, arguments = { "string", "string", "string" } } -- \detokenize{#3}
+implement { name = "xmlconcatrange", actions = lxml.concatrange, arguments = { "string", "string", "string", "string", "string" } } -- \detokenize{#5}
+implement { name = "xmlcontext", actions = lxml.context, arguments = { "string", "string" } }
+implement { name = "xmlcount", actions = lxml.count, arguments = { "string", "string" } }
+implement { name = "xmldelete", actions = lxml.delete, arguments = { "string", "string" } }
+implement { name = "xmldirect", actions = lxml.direct, arguments = "string" }
+implement { name = "xmldirectives", actions = lxml.directives.setup, arguments = "string" }
+implement { name = "xmldirectivesafter", actions = lxml.directives.after, arguments = "string" }
+implement { name = "xmldirectivesbefore", actions = lxml.directives.before, arguments = "string" }
+implement { name = "xmldisplayverbatim", actions = lxml.displayverbatim, arguments = "string" }
+implement { name = "xmlelement", actions = lxml.element, arguments = { "string", "string" } } -- could be integer but now we can alias
+implement { name = "xmlfilter", actions = lxml.filter, arguments = { "string", "string" } }
+implement { name = "xmlfilterlist", actions = lxml.filterlist, arguments = { "string", "string" } }
+implement { name = "xmlfirst", actions = lxml.first, arguments = { "string", "string" } }
+implement { name = "xmlflush", actions = lxml.flush, arguments = "string" }
+implement { name = "xmlflushcontext", actions = lxml.context, arguments = "string" }
+implement { name = "xmlflushlinewise", actions = lxml.flushlinewise, arguments = "string" }
+implement { name = "xmlflushspacewise", actions = lxml.flushspacewise, arguments = "string" }
+implement { name = "xmlfunction", actions = lxml.applyfunction, arguments = { "string", "string" } }
+implement { name = "xmlinclude", actions = lxml.include, arguments = { "string", "string", "string", true } }
+implement { name = "xmlincludeoptions", actions = lxml.include, arguments = { "string", "string", "string", "string" } }
+implement { name = "xmlinclusion", actions = lxml.inclusion, arguments = "string" }
+implement { name = "xmlinclusions", actions = lxml.inclusions, arguments = "string" }
+implement { name = "xmlindex", actions = lxml.index, arguments = { "string", "string", "string" } } -- can be integer but now we can alias
+implement { name = "xmlinfo", actions = lxml.info, arguments = "string" }
+implement { name = "xmlinlineverbatim", actions = lxml.inlineverbatim, arguments = "string" }
+implement { name = "xmllast", actions = lxml.last, arguments = "string" }
+implement { name = "xmlload", actions = lxml.load, arguments = { "string", "string", "string", "string" } }
+implement { name = "xmlloadbuffer", actions = lxml.loadbuffer, arguments = { "string", "string", "string", "string" } }
+implement { name = "xmlloaddata", actions = lxml.loaddata, arguments = { "string", "string", "string", "string" } }
+implement { name = "xmlloaddirectives", actions = lxml.directives.load, arguments = "string" }
+implement { name = "xmlloadregistered", actions = lxml.loadregistered, arguments = { "string", "string", "string" } }
+implement { name = "xmlmain", actions = lxml.main, arguments = "string" }
+implement { name = "xmlmatch", actions = lxml.match, arguments = "string" }
+implement { name = "xmlname", actions = lxml.name, arguments = "string" }
+implement { name = "xmlnamespace", actions = lxml.namespace, arguments = "string" }
+implement { name = "xmlnonspace", actions = lxml.nonspace, arguments = { "string", "string" } }
+implement { name = "xmlpos", actions = lxml.pos, arguments = "string" }
+implement { name = "xmlraw", actions = lxml.raw, arguments = { "string", "string" } }
+implement { name = "xmlregisterns", actions = xml.registerns, arguments = { "string", "string" } }
+implement { name = "xmlremapname", actions = xml.remapname, arguments = { "lxmlid", "string","string","string" } }
+implement { name = "xmlremapnamespace", actions = xml.renamespace, arguments = { "lxmlid", "string", "string" } }
+implement { name = "xmlsave", actions = lxml.save, arguments = { "string", "string" } }
+implement { name = "xmlsetfunction", actions = lxml.setaction, arguments = { "string", "string", "string" } }
+implement { name = "xmlsetsetup", actions = lxml.setsetup, arguments = { "string", "string", "string" } }
+implement { name = "xmlsnippet", actions = lxml.snippet, arguments = { "string", "string" } }
+implement { name = "xmlstrip", actions = lxml.strip, arguments = { "string", "string" } }
+implement { name = "xmlstripanywhere", actions = lxml.strip, arguments = { "string", "string", true, true } }
+implement { name = "xmlstripnolines", actions = lxml.strip, arguments = { "string", "string", true } }
+implement { name = "xmlstripped", actions = lxml.stripped, arguments = { "string", "string" } }
+implement { name = "xmlstrippednolines", actions = lxml.stripped, arguments = { "string", "string", true } }
+implement { name = "xmltag", actions = lxml.tag, arguments = "string" }
+implement { name = "xmltext", actions = lxml.text, arguments = { "string", "string" } }
+implement { name = "xmltobuffer", actions = lxml.tobuffer, arguments = { "string", "string", "string" } }
+implement { name = "xmltobufferverbose", actions = lxml.tobuffer, arguments = { "string", "string", "string", true } }
+implement { name = "xmltofile", actions = lxml.tofile, arguments = { "string", "string", "string" } }
+implement { name = "xmltoparameters", actions = lxml.toparameters, arguments = "string" }
+implement { name = "xmlverbatim", actions = lxml.verbatim, arguments = "string" }
+
+implement { name = "xmlstartraw", actions = lxml.startraw }
+implement { name = "xmlstopraw", actions = lxml.stopraw }
+
+implement { name = "xmlprependsetup", actions = lxml.installsetup, arguments = { 1, "string", "string" } } -- 2:*
+implement { name = "xmlappendsetup", actions = lxml.installsetup, arguments = { 2, "string", "string" } } -- 2:*
+implement { name = "xmlbeforesetup", actions = lxml.installsetup, arguments = { 3, "string", "string", "string" } } -- 2:*
+implement { name = "xmlaftersetup", actions = lxml.installsetup, arguments = { 4, "string", "string", "string" } } -- 2:*
+implement { name = "xmlprependdocumentsetup", actions = lxml.installsetup, arguments = { 1, "string", "string" } }
+implement { name = "xmlappenddocumentsetup", actions = lxml.installsetup, arguments = { 2, "string", "string" } }
+implement { name = "xmlbeforedocumentsetup", actions = lxml.installsetup, arguments = { 3, "string", "string", "string" } }
+implement { name = "xmlafterdocumentsetup", actions = lxml.installsetup, arguments = { 4, "string", "string" } }
+implement { name = "xmlremovesetup", actions = lxml.removesetup, arguments = { "string", "string" } } -- 1:*
+implement { name = "xmlremovedocumentsetup", actions = lxml.removesetup, arguments = { "string", "string" } }
+implement { name = "xmlflushdocumentsetups", actions = lxml.flushsetups, arguments = { "string", "string", "string" } } -- 2:*
+implement { name = "xmlresetdocumentsetups", actions = lxml.resetsetups, arguments = "string" }
+
+implement { name = "xmlgetindex", actions = lxml.getindex, arguments = { "string", "string" } }
+implement { name = "xmlwithindex", actions = lxml.withindex, arguments = { "string", "string", "string" } }
+
+implement { name = "xmlsetentity", actions = xml.registerentity, arguments = { "string", "string" } }
+implement { name = "xmltexentity", actions = lxml.registerentity, arguments = { "string", "string" } }
+
+implement { name = "xmlsetcommandtotext", actions = lxml.setcommandtotext, arguments = "string" }
+implement { name = "xmlsetcommandtonone", actions = lxml.setcommandtonone, arguments = "string" }
+
+implement { name = "xmlstarttiming", actions = function() statistics.starttiming(lxml) end }
+implement { name = "xmlstoptiming", actions = function() statistics.stoptiming (lxml) end }
diff --git a/Master/texmf-dist/tex/context/base/lxml-ini.mkiv b/Master/texmf-dist/tex/context/base/lxml-ini.mkiv
index 752e315da5e..1141288992e 100644
--- a/Master/texmf-dist/tex/context/base/lxml-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/lxml-ini.mkiv
@@ -12,6 +12,7 @@
%C details.
%D Todo: auto apply setups (manage at lua end)
+%D Todo: manuak: \xmlinclusion \xmlinclusions
\writestatus{loading}{ConTeXt XML Support / Initialization}
@@ -20,102 +21,195 @@
%registerctxluafile{lxml-xml}{1.001} % xml finalizers
%registerctxluafile{lxml-aux}{1.001} % extras using parser
%registerctxluafile{lxml-mis}{1.001} % extras independent of parser
-\registerctxluafile{char-ent}{1.001}
\registerctxluafile{lxml-ent}{1.001} % entity hacks
\registerctxluafile{lxml-tex}{1.001} % tex finalizers
\registerctxluafile{lxml-dir}{1.001} % ctx hacks
+\registerctxluafile{lxml-ini}{1.001} % interface
\unprotect % todo \!!bs \!!es where handy (slower)
+% todo: { } mandate
+% avoid #
+
\def\ctxlxml #1{\ctxlua{lxml.#1}}
-\def\xmlmain #1{\ctxlxml{main("#1")}}
-\def\xmlmatch #1{\ctxlxml{match("#1")}}
-\def\xmlall #1#2{\ctxlxml{all("#1","#2")}}
-\def\xmlatt #1#2{\ctxlxml{att("#1","#2")}}
-\def\xmlattdef #1#2#3{\ctxlxml{att("#1","#2","#3")}}
-\def\xmlchainatt #1#2{\ctxlxml{chainattribute("#1","/","#2")}}
-\def\xmlchainattdef #1#2#3{\ctxlxml{chainattribute("#1","/","#2","#3")}}
-\def\xmlattribute #1#2#3{\ctxlxml{attribute("#1","#2","#3")}}
-\def\xmlattributedef #1#2#3#4{\ctxlxml{attribute("#1","#2","#3","#4")}}
-\def\xmlcommand #1#2#3{\ctxlxml{command("#1","#2","#3")}}
-\def\xmlconcat #1#2#3{\ctxlxml{concat("#1","#2",[[\detokenize{#3}]])}}
-\def\xmlconcatrange #1#2#3#4#5{\ctxlxml{concatrange("#1","#2","#3","#4",[[\detokenize{#5}]])}}
-\def\xmlcount #1#2{\ctxlxml{count("#1","#2")}}
-\def\xmldelete #1#2{\ctxlxml{delete("#1","#2")}}
-\def\xmldirectives #1{\ctxlxml{directives.setup("#1")}}
-\def\xmldirectivesbefore #1{\ctxlxml{directives.before("#1")}}
-\def\xmldirectivesafter #1{\ctxlxml{directives.after("#1")}}
-\def\xmlfilter #1#2{\ctxlxml{filter("#1",\!!bs#2\!!es)}}
-\def\xmlfilterlist #1#2{\ctxlxml{filterlist("#1",\!!bs#2\!!es)}}
-\def\xmlfunction #1#2{\ctxlxml{applyfunction("#1",\!!bs#2\!!es)}}
-\def\xmlfirst #1#2{\ctxlxml{first("#1","#2")}}
-\def\xmlflush #1{\ctxlxml{flush("#1")}}
-\def\xmlflushlinewise #1{\ctxlxml{flushlinewise("#1")}}
-\def\xmlflushspacewise #1{\ctxlxml{flushspacewise("#1")}}
-%def\xmlcontent #1{\ctxlxml{content("#1")}}
-%def\xmlflushstripped #1{\ctxlxml{strip("#1",true)}}
-\def\xmldirect #1{\ctxlxml{direct("#1")}} % in loops, not dt but root
-\def\xmlidx #1#2#3{\ctxlxml{idx("#1","#2",\number#3)}}
-\def\xmlinclude #1#2#3{\ctxlxml{include("#1","#2","#3",true)}}
-\def\xmlincludeoptions#1#2#3#4{\ctxlxml{include("#1","#2","#3","#4")}}
-\def\xmlsave #1#2{\ctxlxml{save("#1","#2")}}
-\def\xmlindex #1#2#3{\ctxlxml{index("#1","#2",\number#3)}}
-\def\xmlinfo #1{\hbox{\ttxx[\ctxlxml{info("#1")}]}}
+%def\xmlall #1#2{\clf_xmlall {#1}{#2}}
+%def\xmlatt #1#2{\clf_xmlatt {#1}{#2}}
+%def\xmlattdef #1#2#3{\clf_xmlattdef {#1}{#2}{#3}}
+%def\xmlattribute #1#2#3{\clf_xmlattribute {#1}{#2}{#3}}
+%def\xmlattributedef #1#2#3#4{\clf_xmlattributedef {#1}{#2}{#3}{#4}}
+%def\xmlchainatt #1#2{\clf_xmlchainatt {#1}{#2}}
+%def\xmlchainattdef #1#2#3{\clf_xmlchainattdef {#1}{#2}{#3}}
+%def\xmlchecknamespace #1#2#3{\clf_xmlchecknamespace {#1}{#2}{#3}} % element
+%def\xmlcommand #1#2#3{\clf_xmlcommand {#1}{#2}{#3}}
+\def\xmlconcat #1#2#3{\clf_xmlconcat {#1}{#2}{\detokenize{#3}}}
+\def\xmlconcatrange #1#2#3#4#5{\clf_xmlconcatrange {#1}{#2}{#3}{#4}{\detokenize{#5}}}
+%def\xmlcontext #1#2{\clf_xmlcontext {#1}{#2}}
+%def\xmlcount #1#2{\clf_xmlcount {#1}{#2}}
+%def\xmldelete #1#2{\clf_xmldelete {#1}{#2}}
+%def\xmldirect #1{\clf_xmldirect {#1}} % in loops, not dt but root
+%def\xmldirectives #1{\clf_xmldirectives {#1}}
+%def\xmldirectivesafter #1{\clf_xmldirectivesafter {#1}}
+%def\xmldirectivesbefore #1{\clf_xmldirectivesbefore {#1}}
+%def\xmldisplayverbatim #1{\clf_xmldisplayverbatim {#1}}
+%def\xmlelement #1#2{\clf_xmlelement {#1}{#2}}
+%def\xmlfilter #1#2{\clf_xmlfilter {#1}{#2}}
+%def\xmlfilterlist #1#2{\clf_xmlfilterlist {#1}{#2}}
+%def\xmlfirst #1#2{\clf_xmlfirst {#1}{#2}}
+%def\xmlflush #1{\clf_xmlflush {#1}}
+%def\xmlflushcontext #1{\clf_xmlflushcontext {#1}}
+%def\xmlflushlinewise #1{\clf_xmlflushlinewise {#1}}
+%def\xmlflushspacewise #1{\clf_xmlflushspacewise {#1}}
+%def\xmlfunction #1#2{\clf_xmlfunction {#1}{#2}}
+%def\xmlinclude #1#2#3{\clf_xmlinclude {#1}{#2}{#3}}
+%def\xmlincludeoptions#1#2#3#4{\clf_xmlincludeoptions {#1}{#2}{#3}{#4}}
+%def\xmlinclusion #1{\clf_xmlinclusion {#1}}
+%def\xmlinclusions #1{\clf_xmlinclusions {#1}}
+%def\xmlindex #1#2#3{\clf_xmlindex {#1}{#2}{#3}}
+%let\xmlposition \xmlindex
+%def\xmlinlineverbatim #1{\clf_xmlinlineverbatim {#1}}
+%def\xmllast #1#2{\clf_xmllast {#1}{#2}}
+\def\xmlload #1#2{\clf_xmlload {#1}{#2}{\directxmlparameter\c!entities}{\directxmlparameter\c!compress}}
+\def\xmlloadbuffer #1#2{\clf_xmlloadbuffer {#1}{#2}{\directxmlparameter\c!entities}{\directxmlparameter\c!compress}}
+\def\xmlloaddata #1#2{\clf_xmlloaddata {#1}{#2}{\directxmlparameter\c!entities}{\directxmlparameter\c!compress}}
+%def\xmlloaddirectives #1{\clf_xmlloaddirectives {#1}}
+\def\xmlloadregistered #1#2{\clf_xmlloadregistered {#1}{\directxmlparameter\c!entities}{\directxmlparameter\c!compress}}
+%def\xmlmain #1{\clf_xmlmain {#1}}
+%def\xmlmatch #1{\clf_xmlmatch {#1}}
+%def\xmlname #1{\clf_xmlname {#1}}
+%def\xmlnamespace #1{\clf_xmlnamespace {#1}}
+%def\xmlnonspace #1#2{\clf_xmlnonspace {#1}{#2}}
+%def\xmlpos #1{\clf_xmlpos {#1}}
+%def\xmlraw #1#2{\clf_xmlraw {#1}{#2}}
+%def\xmlregisterns #1#2{\clf_xmlregisterns {#1}{#2}} % document
+%def\xmlremapname #1#2#3#4{\clf_xmlremapname {#1}{#2}{#3}{#4}} % element
+%def\xmlremapnamespace #1#2#3{\clf_xmlremapnamespace {#1}{#2}{#3}} % document
+%def\xmlsave #1#2{\clf_xmlsave {#1}{#2}}
+%def\xmlsetfunction #1#2#3{\clf_xmlsetfunction {#1}{#2}{#3}}
+%def\xmlsetsetup #1#2#3{\clf_xmlsetsetup {#1}{#2}{#3}}
+%def\xmlsnippet #1#2{\clf_xmlsnippet {#1}{#2}}
+%def\xmlstrip #1#2{\clf_xmlstrip {#1}{#2}}
+%def\xmlstripanywhere #1#2{\clf_xmlstripanywhere {#1}{#2}}
+%def\xmlstripnolines #1#2{\clf_xmlstripnolines {#1}{#2}}
+%def\xmlstripped #1#2{\clf_xmlstripped {#1}{#2}}
+%def\xmlstrippednolines #1#2{\clf_xmlstrippednolines {#1}{#2}}
+%def\xmltag #1{\clf_xmltag {#1}}
+%def\xmltext #1#2{\clf_xmltext {#1}{#2}}
+%def\xmltobuffer #1#2#3{\clf_xmltobuffer {#1}{#2}{#3}} % id pattern name
+%def\xmltobufferverbose #1#2#3{\clf_xmltobufferverbose {#1}{#2}{#3}} % id pattern name
+%def\xmltofile #1#2#3{\clf_xmltofile {#1}{#2}{#3}} % id pattern filename
+%def\xmltoparameters #1{\clf_xmltoparameters {#1}}
+%def\xmlverbatim #1{\clf_xmlverbatim {#1}}
+
+% experiment:
+\let\xmlall \clf_xmlall
+\let\xmlatt \clf_xmlatt
+\let\xmlattdef \clf_xmlattdef
+\let\xmlattribute \clf_xmlattribute
+\let\xmlattributedef \clf_xmlattributedef
+\let\xmlchainatt \clf_xmlchainatt
+\let\xmlchainattdef \clf_xmlchainattdef
+\let\xmlchecknamespace \clf_xmlchecknamespace
+\let\xmlcommand \clf_xmlcommand
+% \xmlconcat
+% \xmlconcatrange
+\let\xmlcontext \clf_xmlcontext
+\let\xmlcount \clf_xmlcount
+\let\xmldelete \clf_xmldelete
+\let\xmldirect \clf_xmldirect % in loops, not dt but root
+\let\xmldirectives \clf_xmldirectives
+\let\xmldirectivesafter \clf_xmldirectivesafter
+\let\xmldirectivesbefore \clf_xmldirectivesbefore
+\let\xmldisplayverbatim \clf_xmldisplayverbatim
+\let\xmlelement \clf_xmlelement
+\let\xmlfilter \clf_xmlfilter
+\let\xmlfilterlist \clf_xmlfilterlist
+\let\xmlfirst \clf_xmlfirst
+\let\xmlflush \clf_xmlflush
+\let\xmlflushcontext \clf_xmlflushcontext
+\let\xmlflushlinewise \clf_xmlflushlinewise
+\let\xmlflushspacewise \clf_xmlflushspacewise
+\let\xmlfunction \clf_xmlfunction
+\let\xmlinclude \clf_xmlinclude
+\let\xmlincludeoptions \clf_xmlincludeoptions
+\let\xmlinclusion \clf_xmlinclusion
+\let\xmlinclusions \clf_xmlinclusions
+\let\xmlindex \clf_xmlindex
+\let\xmlposition \clf_xmlindex
+\let\xmlinlineverbatim \clf_xmlinlineverbatim
+\let\xmllast \clf_xmllast
+% \xmlload
+% \xmlloadbuffer
+% \xmlloaddata
+\let\xmlloaddirectives \clf_xmlloaddirectives
+% \xmlloadregistered
+\let\xmlmain \clf_xmlmain
+\let\xmlmatch \clf_xmlmatch
+\let\xmlname \clf_xmlname
+\let\xmlnamespace \clf_xmlnamespace
+\let\xmlnonspace \clf_xmlnonspace
+\let\xmlpos \clf_xmlpos
+\let\xmlraw \clf_xmlraw
+\let\xmlregisterns \clf_xmlregisterns % document
+\let\xmlremapname \clf_xmlremapname % element
+\let\xmlremapnamespace \clf_xmlremapnamespace % document
+\let\xmlsave \clf_xmlsave
+\let\xmlsetfunction \clf_xmlsetfunction
+\let\xmlsetsetup \clf_xmlsetsetup
+\let\xmlsnippet \clf_xmlsnippet
+\let\xmlstrip \clf_xmlstrip
+\let\xmlstripanywhere \clf_xmlstripanywhere
+\let\xmlstripnolines \clf_xmlstripnolines
+\let\xmlstripped \clf_xmlstripped
+\let\xmlstrippednolines \clf_xmlstrippednolines
+\let\xmltag \clf_xmltag
+\let\xmltext \clf_xmltext
+\let\xmltobuffer \clf_xmltobuffer % id pattern name
+\let\xmltobufferverbose \clf_xmltobufferverbose % id pattern name
+\let\xmltofile \clf_xmltofile % id pattern filename
+\let\xmltoparameters \clf_xmltoparameters
+\let\xmlverbatim \clf_xmlverbatim
+
+\def\xmlinfo #1{\hbox{\ttxx[\clf_xmlinfo{#1}]}}
\def\xmlshow #1{\startpacked\ttx\xmlverbatim{#1}\stoppacked}
-\def\xmllast #1#2{\ctxlxml{last("#1","#2")}}
-\def\xmlname #1{\ctxlxml{name("#1")}}
-\def\xmlnamespace #1{\ctxlxml{namespace("#1")}}
-\def\xmlnonspace #1#2{\ctxlxml{nonspace("#1","#2")}}
-\def\xmlraw #1#2{\ctxlxml{raw("#1","#2")}}
-\def\xmlcontext #1#2{\ctxlxml{context("#1","#2")}}
-\def\xmlflushcontext #1{\ctxlxml{context("#1")}}
-\def\xmlsnippet #1#2{\ctxlxml{snippet("#1",#2)}}
-\def\xmlelement #1#2{\ctxlxml{element("#1",#2)}}
-\def\xmlregisterns #1#2{\ctxlua{xml.registerns("#1","#2")}} % document
-\def\xmlremapname #1#2#3#4{\ctxlua{xml.remapname(lxml.id("#1"),"#2","#3","#4")}} % element
-\def\xmlremapnamespace #1#2#3{\ctxlua{xml.renamespace(lxml.id("#1"),"#2","#3")}} % document
-\def\xmlchecknamespace #1#2#3{\ctxlua{xml.checknamespace(lxml.id("#1"),"#2","#3")}} % element
-\def\xmlsetfunction #1#2#3{\ctxlxml{setaction("#1",\!!bs#2\!!es,#3)}}
-\def\xmlsetsetup #1#2#3{\ctxlxml{setsetup("#1",\!!bs#2\!!es,"#3")}}
-\def\xmlstrip #1#2{\ctxlxml{strip("#1","#2")}}
-\def\xmlstripnolines #1#2{\ctxlxml{strip("#1","#2",true)}}
-\def\xmlstripanywhere #1#2{\ctxlxml{strip("#1","#2",true,true)}}
-\def\xmlstripped #1#2{\ctxlxml{stripped("#1","#2")}}
-\def\xmlstrippednolines #1#2{\ctxlxml{stripped("#1","#2",true)}}
-\def\xmltag #1{\ctxlxml{tag("#1")}}
-\def\xmltext #1#2{\ctxlxml{text("#1","#2")}}
-\def\xmlverbatim #1{\ctxlxml{verbatim("#1")}}
-\def\xmldisplayverbatim #1{\ctxlxml{displayverbatim("#1")}}
-\def\xmlinlineverbatim #1{\ctxlxml{inlineverbatim("#1")}}
-
-\def\xmlload #1#2{\ctxlxml{load("#1","#2","\directxmlparameter\c!entities","\directxmlparameter\c!compress")}}
-\def\xmlloadbuffer #1#2{\ctxlxml{loadbuffer("#1","#2","\directxmlparameter\c!entities","\directxmlparameter\c!compress")}}
-\def\xmlloaddata #1#2{\ctxlxml{loaddata("#1",\!!bs#2\!!es,"\directxmlparameter\c!entities","\directxmlparameter\c!compress")}}
-\def\xmlloadregistered #1#2{\ctxlxml{loadregistered("#1","\directxmlparameter\c!entities","\directxmlparameter\c!compress")}}
-\def\xmlloaddirectives #1{\ctxlxml{directives.load("any:///#1")}}
-\def\xmlpos #1{\ctxlxml{pos("#1")}}
-
-\def\xmltoparameters #1{\ctxlxml{toparameters("#1")}}
-
-\def\xmltofile #1#2#3{\ctxlxml{tofile("#1","#2","#3")}} % id pattern filename
+
+% goodie:
+
+\unexpanded\def\xmlprettyprint#1#2%
+ {\xmltobufferverbose{#1}{.}{xml-temp}%
+ \ifdefined\scitebuffer
+ \scitebuffer[#2][xml-temp]%
+ \else
+ \typebuffer[xml-temp][\c!option=#2]%
+ \fi}
% kind of special:
-\def\xmlstartraw{\ctxlxml{startraw()}}
-\def\xmlstopraw {\ctxlxml{stopraw()}}
+%def\xmlstartraw{\clf_xmlstartraw}
+%def\xmlstopraw {\clf_xmlstopraw}
+
+\let\xmlstartraw\clf_xmlstartraw
+\let\xmlstopraw \clf_xmlstopraw
-% todo: \xmldoifelseattribute
+% these are expandable! todo: \xmldoifelseattribute
-\def\xmldoif #1#2{\ctxlxml{doif (\!!bs#1\!!es,\!!bs#2\!!es)}} % expandable
-\def\xmldoifnot #1#2{\ctxlxml{doifnot (\!!bs#1\!!es,\!!bs#2\!!es)}} % expandable
-\def\xmldoifelse #1#2{\ctxlxml{doifelse (\!!bs#1\!!es,\!!bs#2\!!es)}} % expandable
-\def\xmldoiftext #1#2{\ctxlxml{doiftext (\!!bs#1\!!es,\!!bs#2\!!es)}} % expandable
-\def\xmldoifnottext #1#2{\ctxlxml{doifnottext (\!!bs#1\!!es,\!!bs#2\!!es)}} % expandable
-\def\xmldoifelsetext #1#2{\ctxlxml{doifelsetext(\!!bs#1\!!es,\!!bs#2\!!es)}} % expandable
+\let\xmldoif \clf_xmldoif
+\let\xmldoifnot \clf_xmldoifnot
+\let\xmldoifelse \clf_xmldoifelse
+\let\xmldoiftext \clf_xmldoiftext
+\let\xmldoifnottext \clf_xmldoifnottext
+\let\xmldoifelsetext \clf_xmldoifelsetext
-%def\xmldoifelseempty #1#2{\ctxlxml{doifelseempty("#1","#2")}} % #2, "*" or "" == self not yet implemented
-%def\xmldoifelseselfempty #1{\ctxlxml{doifelseempty("#1")}}
+\let\xmldoifempty \clf_xmldoifempty
+\let\xmldoifnotempty \clf_xmldoifnotempty
+\let\xmldoifelseempty \clf_xmldoifelseempty
+\let\xmldoifselfempty \clf_xmldoifselfempty
+\let\xmldoifnotselfempty \clf_xmldoifnotselfempty
+\let\xmldoifelseselfempty \clf_xmldoifelseselfempty
+
+\let\xmldoiftextelse \xmldoifelsetext
+\let\xmldoifemptyelse \xmldoifelseempty
+\let\xmldoifselfemptyelse \xmldoifelseselfempty
% \startxmlsetups xml:include
% \xmlinclude{main}{include}{filename|href}
@@ -129,28 +223,28 @@
%\ef\xmlsetup#1#2{\setupwithargument{#2}{#1}}
\let\xmlsetup\setupwithargumentswapped
-\let\xmls\setupwithargumentswapped
-\let\xmlw\setupwithargument
+\let\xmls\setupwithargumentswapped % hardly any faster
+\let\xmlw\setupwithargument % hardly any faster
\newtoks \registeredxmlsetups
% todo: 1:xml:whatever always before 3:xml:something
-\unexpanded\def\xmlprependsetup #1{\ctxlxml{installsetup(1,"*","#1")}}
-\unexpanded\def\xmlappendsetup #1{\ctxlxml{installsetup(2,"*","#1")}}
-\unexpanded\def\xmlbeforesetup #1#2{\ctxlxml{installsetup(3,"*","#1","#2")}}
-\unexpanded\def\xmlaftersetup #1#2{\ctxlxml{installsetup(4,"*","#1","#2")}}
+\unexpanded\def\xmlprependsetup #1{\clf_xmlprependsetup {*}{#1}}
+\unexpanded\def\xmlappendsetup #1{\clf_xmlappendsetup {*}{#1}}
+\unexpanded\def\xmlbeforesetup #1#2{\clf_xmlbeforesetup {*}{#1}{#2}}
+\unexpanded\def\xmlaftersetup #1#2{\clf_xmlaftersetup {*}{#1}{#2}}
-\unexpanded\def\xmlprependdocumentsetup #1#2{\ctxlxml{installsetup(1,"#1","#2")}}
-\unexpanded\def\xmlappenddocumentsetup #1#2{\ctxlxml{installsetup(2,"#1","#2")}}
-\unexpanded\def\xmlbeforedocumentsetup#1#2#3{\ctxlxml{installsetup(3,"#1","#2","#3")}}
-\unexpanded\def\xmlafterdocumentsetup #1#2#3{\ctxlxml{installsetup(4,"#1","#2","#3")}}
+\unexpanded\def\xmlprependdocumentsetup #1#2{\clf_xmlprependdocumentsetup{#1}{#2}}
+\unexpanded\def\xmlappenddocumentsetup #1#2{\clf_xmlappenddocumentsetup {#1}{#2}}
+\unexpanded\def\xmlbeforedocumentsetup #1#2#3{\clf_xmlbeforedocumentsetup {#1}{#2}{#3}}
+\unexpanded\def\xmlafterdocumentsetup #1#2#3{\clf_xmlafterdocumentsetup {#1}{#2}{#3}}
-\unexpanded\def\xmlremovesetup #1{\ctxlxml{removesetup("*","#1")}}
-\unexpanded\def\xmlremovedocumentsetup #1#2{\ctxlxml{removesetup("#1","#2")}}
+\unexpanded\def\xmlremovesetup #1{\clf_xmlremovesetup {*}{#1}}
+\unexpanded\def\xmlremovedocumentsetup #1#2{\clf_xmlremovedocumentsetup {#1}{#2}}
-\unexpanded\def\xmlflushdocumentsetups #1#2{\ctxlxml{flushsetups("#1","*","#2")}} % #1 == id where to apply * and #2
-\unexpanded\def\xmlresetdocumentsetups #1{\ctxlxml{resetsetups("#1")}}
+\unexpanded\def\xmlflushdocumentsetups #1#2{\clf_xmlflushdocumentsetups {#1}{*}{#2}} % #1 == id where to apply * and #2
+\unexpanded\def\xmlresetdocumentsetups #1{\clf_xmlresetdocumentsetups {#1}}
\let\xmlregistersetup \xmlappendsetup
\let\xmlregisterdocumentsetup\xmlappenddocumentsetup
@@ -170,8 +264,8 @@
\xmldefaulttotext{#1}% after include
\xmlstoptiming}
-\unexpanded\def\xmlstarttiming{\ctxlua{statistics.starttiming(lxml)}}
-\unexpanded\def\xmlstoptiming {\ctxlua{statistics.stoptiming (lxml)}}
+\unexpanded\def\xmlstarttiming{\clf_xmlstarttiming}
+\unexpanded\def\xmlstoptiming {\clf_xmlstoptiming}
\def\lxml_process#1#2#3#4#5% flag \loader id name what initializersetup
{\begingroup
@@ -229,11 +323,6 @@
% \xmlsetfunction{main}{verbatim}{lxml.displayverbatim}
% \xmlsetfunction{main}{verb} {lxml.inlineverbatim}
-% \unexpanded\def\startxmldisplayverbatim[#1]{}
-% \unexpanded\def\stopxmldisplayverbatim {}
-% \unexpanded\def\startxmlinlineverbatim [#1]{}
-% \unexpanded\def\stopxmlinlineverbatim {}
-
% we use an xml: namespace so one has to define a suitable verbatim, say
%
% \definetyping[xml:verbatim][typing]
@@ -252,7 +341,7 @@
\unexpanded\def\startxmlinlineverbatim[#1]%
{\begingroup
\edef\currenttype{xml:#1}%
- \let\stopxmldisplayverbatim\endgroup
+ \let\stopxmlinlineverbatim\endgroup
\doinitializeverbatim}
% will move but is developed for xml
@@ -271,14 +360,13 @@
\def\inlinemessage #1{\dontleavehmode{\tttf#1}}
\def\displaymessage#1{\blank\inlinemessage{#1}\blank}
-% \def\xmltraceentities % settextcleanup is not defined
-% {\ctxlua{xml.settextcleanup(lxml.trace_text_entities)}%
-% \appendtoks\ctxlxml{showtextentities()}\to\everygoodbye}
-
% processing instructions
-\def\xmlcontextdirective#1% kind class key value
- {\executeifdefined{xml#1directive}\gobblethreearguments}
+\unexpanded\def\xmlinstalldirective#1#2%
+ {\clf_xmlinstalldirective{#1}{\checkedstrippedcsname#2}}
+
+% \def\xmlcontextdirective#1% kind class key value
+% {\executeifdefined{xml#1directive}\gobblethreearguments}
% setting up xml:
%
@@ -301,15 +389,15 @@
\letvalue{\??xmldefaults\v!text }\plusone
\letvalue{\??xmldefaults\v!hidden}\plustwo
-\unexpanded\def\xmldefaulttotext#1%
+\unexpanded\def\xmldefaulttotext
{\ifcase\xmlprocessingmode
- % unset
+ \expandafter\gobbleoneargument % unset
\or
- \ctxlxml{setcommandtotext("#1")}% 1
+ \expandafter\clf_xmlsetcommandtotext % 1
\or
- \ctxlxml{setcommandtonone("#1")}% 2
+ \expandafter\clf_xmlsetcommandtonone % 2
\else
- % unset
+ \expandafter\gobbleoneargument % unset
\fi}
\appendtoks
@@ -326,22 +414,23 @@
%def\xmlvalue #1#2{\ifcsname\??xmlmapvalue#1:#2\endcsname\csname\??xmlmapvalue#1:#2\expandafter\expandafter\gobbleoneargument\expandafter\endcsname\else\expandafter\firstofoneargument\fi}
\def\xmldoifelsevalue #1#2{\ifcsname\??xmlmapvalue#1:#2\endcsname\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
+\let\xmldoifvalueelse\xmldoifelsevalue
+
\let\xmlmapval\xmlmapvalue
\let\xmlval \xmlvalue
%D Experimental:
-\def\xmlgetindex #1{\ctxlxml{getindex("\xmldocument","#1")}}
-\def\xmlrawindex #1{\ctxlxml{rawindex("#1")}}
-\def\xmlwithindex #1#2{\ctxlxml{withindex("\xmldocument","#1","#2")}}
+\def\xmlgetindex #1{\clf_xmlgetindex {\xmldocument}{#1}}
+\def\xmlwithindex #1#2{\clf_xmlwithindex{\xmldocument}{#1}{#2}}
\def\xmlreference #1#2{\string\xmlwithindex{#1}{#2}}
%D Entities (might change):
\setnewconstant\xmlautoentities\plusone % 0=off, 1=upper, 2=upper,lower
-\def\xmlsetentity#1#2{\ctxlua{xml.registerentity('#1',\!!bs\detokenize{#2}\!!es)}}
-\def\xmltexentity#1#2{\ctxlua{lxml.registerentity('#1',\!!bs\detokenize{#2}\!!es)}}
+\unexpanded\def\xmlsetentity#1#2{\clf_xmlsetentity{#1}{\detokenize{#2}}}
+\unexpanded\def\xmltexentity#1#2{\clf_xmltexentity{#1}{\detokenize{#2}}}
% \xmlsetentity{tex}{\TEX{}} % {} needed
@@ -393,6 +482,16 @@
\let\processxmlfile \processXMLfile
\let\xmldata \XMLdata
+\unexpanded\def\xmlsetinjectors[#1]%
+ {\clf_xmlsetinjectors{#1}}
+
+\unexpanded\def\xmlresetinjectors
+ {\clf_xmlresetinjectors{}}
+
+\def\xmlinjector#1{\executeifdefined{#1}\donothing}
+
+\let\xmlapplyselectors\clf_xmlapplyselectors
+
\protect \endinput
% \newcount\charactersactiveoffset \charactersactiveoffset="10000
diff --git a/Master/texmf-dist/tex/context/base/lxml-lpt.lua b/Master/texmf-dist/tex/context/base/lxml-lpt.lua
index 8567f26234a..decb6567bf5 100644
--- a/Master/texmf-dist/tex/context/base/lxml-lpt.lua
+++ b/Master/texmf-dist/tex/context/base/lxml-lpt.lua
@@ -505,6 +505,9 @@ local function apply_expression(list,expression,order)
return collected
end
+-- this one can be made faster but there are not that many conversions so it doesn't
+-- really pay of
+
local P, V, C, Cs, Cc, Ct, R, S, Cg, Cb = lpeg.P, lpeg.V, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.Ct, lpeg.R, lpeg.S, lpeg.Cg, lpeg.Cb
local spaces = S(" \n\r\t\f")^0
@@ -541,12 +544,11 @@ local lp_builtin = P (
local lp_attribute = (P("@") + P("attribute::")) / "" * Cc("(ll.at and ll.at['") * ((R("az","AZ") + S("-_:"))^1) * Cc("'])")
--- lp_fastpos_p = (P("+")^0 * R("09")^1 * P(-1)) / function(s) return "l==" .. s end
--- lp_fastpos_n = (P("-") * R("09")^1 * P(-1)) / function(s) return "(" .. s .. "<0 and (#list+".. s .. "==l))" end
-
-lp_fastpos_p = P("+")^0 * R("09")^1 * P(-1) / "l==%0"
-lp_fastpos_n = P("-") * R("09")^1 * P(-1) / "(%0<0 and (#list+%0==l))"
+----- lp_fastpos_p = (P("+")^0 * R("09")^1 * P(-1)) / function(s) return "l==" .. s end
+----- lp_fastpos_n = (P("-") * R("09")^1 * P(-1)) / function(s) return "(" .. s .. "<0 and (#list+".. s .. "==l))" end
+local lp_fastpos_p = P("+")^0 * R("09")^1 * P(-1) / "l==%0"
+local lp_fastpos_n = P("-") * R("09")^1 * P(-1) / "(%0<0 and (#list+%0==l))"
local lp_fastpos = lp_fastpos_n + lp_fastpos_p
local lp_reserved = C("and") + C("or") + C("not") + C("div") + C("mod") + C("true") + C("false")
@@ -806,7 +808,7 @@ local function nodesettostring(set,nodetest)
if not ns or ns == "" then ns = "*" end
if not tg or tg == "" then tg = "*" end
tg = (tg == "@rt@" and "[root]") or format("%s:%s",ns,tg)
- t[i] = (directive and tg) or format("not(%s)",tg)
+ t[#t+1] = (directive and tg) or format("not(%s)",tg)
end
if nodetest == false then
return format("not(%s)",concat(t,"|"))
@@ -1132,7 +1134,6 @@ expressions.print = function(...)
return true
end
-expressions.contains = find
expressions.find = find
expressions.upper = upper
expressions.lower = lower
@@ -1156,6 +1157,10 @@ function expressions.contains(str,pattern)
return false
end
+function xml.expressions.idstring(str)
+ return type(str) == "string" and gsub(str,"^#","") or ""
+end
+
-- user interface
local function traverse(root,pattern,handle)
diff --git a/Master/texmf-dist/tex/context/base/lxml-sor.mkiv b/Master/texmf-dist/tex/context/base/lxml-sor.mkiv
index 0ee1f16f3e2..0d8eb6ba174 100644
--- a/Master/texmf-dist/tex/context/base/lxml-sor.mkiv
+++ b/Master/texmf-dist/tex/context/base/lxml-sor.mkiv
@@ -19,10 +19,13 @@
\unprotect
+% the flusher is unexpandable so that it can be used in tables (noalign
+% interferences)
+
\unexpanded\def\xmlresetsorter #1{\ctxlxml{sorters.reset("#1")}}
\unexpanded\def\xmladdsortentry#1#2#3{\ctxlxml{sorters.add("#1","#2",\!!bs#3\!!es)}}
\unexpanded\def\xmlshowsorter #1{\ctxlxml{sorters.show("#1")}}
-\unexpanded\def\xmlflushsorter #1#2{\ctxlxml{sorters.flush("#1","#2")}}
+ \def\xmlflushsorter #1#2{\ctxlxml{sorters.flush("#1","#2")}}
\unexpanded\def\xmlsortentries #1{\ctxlxml{sorters.sort("#1")}}
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/lxml-tab.lua b/Master/texmf-dist/tex/context/base/lxml-tab.lua
index 8b34a96a3c3..0a72640d086 100644
--- a/Master/texmf-dist/tex/context/base/lxml-tab.lua
+++ b/Master/texmf-dist/tex/context/base/lxml-tab.lua
@@ -42,10 +42,10 @@ local xml = xml
--~ local xml = xml
local concat, remove, insert = table.concat, table.remove, table.insert
-local type, next, setmetatable, getmetatable, tonumber = type, next, setmetatable, getmetatable, tonumber
+local type, next, setmetatable, getmetatable, tonumber, rawset = type, next, setmetatable, getmetatable, tonumber, rawset
local lower, find, match, gsub = string.lower, string.find, string.match, string.gsub
local utfchar = utf.char
-local lpegmatch = lpeg.match
+local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
local P, S, R, C, V, C, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.C, lpeg.Cs
local formatters = string.formatters
@@ -325,12 +325,13 @@ end
-- one level expansion (simple case), no checking done
-local rest = (1-P(";"))^0
-local many = P(1)^0
+local p_rest = (1-P(";"))^0
+local p_many = P(1)^0
+local p_char = lpegpatterns.utf8character
local parsedentity =
- P("&") * (P("#x")*(rest/fromhex) + P("#")*(rest/fromdec)) * P(";") * P(-1) +
- (P("#x")*(many/fromhex) + P("#")*(many/fromdec))
+ P("&") * (P("#x")*(p_rest/fromhex) + P("#")*(p_rest/fromdec)) * P(";") * P(-1) +
+ (P("#x")*(p_many/fromhex) + P("#")*(p_many/fromdec))
-- parsing in the xml file
@@ -367,7 +368,41 @@ local privates_n = {
-- keeps track of defined ones
}
-local escaped = utf.remapper(privates_u)
+-- -- local escaped = utf.remapper(privates_u) -- can't be used as it freezes
+-- -- local unprivatized = utf.remapper(privates_p) -- can't be used as it freezes
+--
+-- local p_privates_u = false
+-- local p_privates_p = false
+--
+-- table.setmetatablenewindex(privates_u,function(t,k,v) rawset(t,k,v) p_privates_u = false end)
+-- table.setmetatablenewindex(privates_p,function(t,k,v) rawset(t,k,v) p_privates_p = false end)
+--
+-- local function escaped(str)
+-- if not str or str == "" then
+-- return ""
+-- else
+-- if not p_privates_u then
+-- p_privates_u = Cs((lpeg.utfchartabletopattern(privates_u)/privates_u + p_char)^0)
+-- end
+-- return lpegmatch(p_privates_u,str)
+-- end
+-- end
+--
+-- local function unprivatized(str)
+-- if not str or str == "" then
+-- return ""
+-- else
+-- if not p_privates_p then
+-- p_privates_p = Cs((lpeg.utfchartabletopattern(privates_p)/privates_p + p_char)^0)
+-- end
+-- return lpegmatch(p_privates_p,str)
+-- end
+-- end
+
+local escaped = utf.remapper(privates_u,"dynamic")
+local unprivatized = utf.remapper(privates_p,"dynamic")
+
+xml.unprivatized = unprivatized
local function unescaped(s)
local p = privates_n[s]
@@ -382,10 +417,7 @@ local function unescaped(s)
return p
end
-local unprivatized = utf.remapper(privates_p)
-
xml.privatetoken = unescaped
-xml.unprivatized = unprivatized
xml.privatecodes = privates_n
local function handle_hex_entity(str)
@@ -546,7 +578,7 @@ local valid = R('az', 'AZ', '09') + S('_-.')
local name_yes = C(valid^1) * colon * C(valid^1)
local name_nop = C(P(true)) * C(valid^1)
local name = name_yes + name_nop
-local utfbom = lpeg.patterns.utfbom -- no capture
+local utfbom = lpegpatterns.utfbom -- no capture
local spacing = C(space^0)
----- entitycontent = (1-open-semicolon)^0
@@ -768,7 +800,7 @@ end
-- Because we can have a crash (stack issues) with faulty xml, we wrap this one
-- in a protector:
-function xmlconvert(data,settings)
+local function xmlconvert(data,settings)
local ok, result = pcall(function() return _xmlconvert_(data,settings) end)
if ok then
return result
@@ -919,14 +951,18 @@ and then handle the lot.
-- new experimental reorganized serialize
-local function verbose_element(e,handlers) -- options
+local f_attribute = formatters['%s=%q']
+
+local function verbose_element(e,handlers,escape) -- options
local handle = handlers.handle
local serialize = handlers.serialize
local ens, etg, eat, edt, ern = e.ns, e.tg, e.at, e.dt, e.rn
local ats = eat and next(eat) and { }
if ats then
+ local n = 0
for k,v in next, eat do
- ats[#ats+1] = formatters['%s=%q'](k,escaped(v))
+ n = n + 1
+ ats[n] = f_attribute(k,escaped(v))
end
end
if ern and trace_entities and ern ~= ens then
diff --git a/Master/texmf-dist/tex/context/base/lxml-tex.lua b/Master/texmf-dist/tex/context/base/lxml-tex.lua
index 0c58a47cc9f..adb849347e1 100644
--- a/Master/texmf-dist/tex/context/base/lxml-tex.lua
+++ b/Master/texmf-dist/tex/context/base/lxml-tex.lua
@@ -11,7 +11,7 @@ if not modules then modules = { } end modules ['lxml-tex'] = {
-- be an cldf-xml helper library.
local utfchar = utf.char
-local concat, insert, remove = table.concat, table.insert, table.remove
+local concat, insert, remove, sortedkeys = table.concat, table.insert, table.remove, table.sortedkeys
local format, sub, gsub, find, gmatch, match = string.format, string.sub, string.gsub, string.find, string.gmatch, string.match
local type, next, tonumber, tostring, select = type, next, tonumber, tostring, select
local lpegmatch = lpeg.match
@@ -19,43 +19,65 @@ local P, S, C, Cc = lpeg.P, lpeg.S, lpeg.C, lpeg.Cc
local tex, xml = tex, xml
local lowerchars, upperchars, lettered = characters.lower, characters.upper, characters.lettered
+local basename, dirname, joinfile = file.basename, file.dirname, file.join
lxml = lxml or { }
local lxml = lxml
-local catcodenumbers = catcodes.numbers
-local ctxcatcodes = catcodenumbers.ctxcatcodes -- todo: use different method
-local notcatcodes = catcodenumbers.notcatcodes -- todo: use different method
-
-local commands = commands
-local context = context
-local contextsprint = context.sprint -- with catcodes (here we use fast variants, but with option for tracing)
-
-local xmlelements, xmlcollected, xmlsetproperty = xml.elements, xml.collected, xml.setproperty
-local xmlwithelements = xml.withelements
-local xmlserialize, xmlcollect, xmltext, xmltostring = xml.serialize, xml.collect, xml.text, xml.tostring
-local xmlapplylpath = xml.applylpath
-local xmlunprivatized, xmlprivatetoken, xmlprivatecodes = xml.unprivatized, xml.privatetoken, xml.privatecodes
-local xmlstripelement = xml.stripelement
-
-local variables = interfaces and interfaces.variables or { }
+local catcodenumbers = catcodes.numbers
+local ctxcatcodes = catcodenumbers.ctxcatcodes -- todo: use different method
+local notcatcodes = catcodenumbers.notcatcodes -- todo: use different method
+
+local commands = commands
+local context = context
+local contextsprint = context.sprint -- with catcodes (here we use fast variants, but with option for tracing)
+
+local implement = interfaces.implement
+
+local xmlelements = xml.elements
+local xmlcollected = xml.collected
+local xmlsetproperty = xml.setproperty
+local xmlwithelements = xml.withelements
+local xmlserialize = xml.serialize
+local xmlcollect = xml.collect
+local xmltext = xml.text
+local xmltostring = xml.tostring
+local xmlapplylpath = xml.applylpath
+local xmlunprivatized = xml.unprivatized
+local xmlprivatetoken = xml.privatetoken
+local xmlprivatecodes = xml.privatecodes
+local xmlstripelement = xml.stripelement
+local xmlinclusion = xml.inclusion
+local xmlinclusions = xml.inclusions
+local xmlcontent = xml.content
+
+local variables = interfaces and interfaces.variables or { }
local settings_to_hash = utilities.parsers.settings_to_hash
+local settings_to_set = utilities.parsers.settings_to_set
+local options_to_hash = utilities.parsers.options_to_hash
+local options_to_array = utilities.parsers.options_to_array
+
local insertbeforevalue = utilities.tables.insertbeforevalue
local insertaftervalue = utilities.tables.insertaftervalue
-local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
+local resolveprefix = resolvers.resolve
+
+local starttiming = statistics.starttiming
+local stoptiming = statistics.stoptiming
-local trace_setups = false trackers.register("lxml.setups", function(v) trace_setups = v end)
-local trace_loading = false trackers.register("lxml.loading", function(v) trace_loading = v end)
-local trace_access = false trackers.register("lxml.access", function(v) trace_access = v end)
-local trace_comments = false trackers.register("lxml.comments", function(v) trace_comments = v end)
-local trace_entities = false trackers.register("xml.entities", function(v) trace_entities = v end)
+local trace_setups = false trackers.register("lxml.setups", function(v) trace_setups = v end)
+local trace_loading = false trackers.register("lxml.loading", function(v) trace_loading = v end)
+local trace_access = false trackers.register("lxml.access", function(v) trace_access = v end)
+local trace_comments = false trackers.register("lxml.comments", function(v) trace_comments = v end)
+local trace_entities = false trackers.register("xml.entities", function(v) trace_entities = v end)
+local trace_selectors = false trackers.register("lxml.selectors",function(v) trace_selectors = v end)
-local report_lxml = logs.reporter("xml","tex")
-local report_xml = logs.reporter("xml","tex")
+local report_lxml = logs.reporter("lxml","tex")
+local report_xml = logs.reporter("xml","tex")
-local forceraw, rawroot = false, nil
+local forceraw = false
+local forceraw = nil
-- tex entities
--
@@ -65,7 +87,7 @@ lxml.entities = lxml.entities or { }
storage.register("lxml/entities",lxml.entities,"lxml.entities")
---~ xml.placeholders.unknown_any_entity = nil -- has to be per xml
+-- xml.placeholders.unknown_any_entity = nil -- has to be per xml
local xmlentities = xml.entities
local texentities = lxml.entities
@@ -417,7 +439,7 @@ function lxml.convert(id,data,entities,compress,currentresource)
end
function lxml.load(id,filename,compress,entities)
- filename = commands.preparedfile(filename) -- not commands!
+ filename = ctxrunner.preparedfile(filename)
if trace_loading then
report_lxml("loading file %a as %a",filename,id)
end
@@ -436,37 +458,6 @@ function lxml.register(id,xmltable,filename)
return xmltable
end
--- function lxml.include(id,pattern,attribute,recurse,resolve)
--- starttiming(xml)
--- local root = getid(id)
--- xml.include(root,pattern,attribute,recurse,function(filename)
--- if filename then
--- -- preprocessing
--- filename = commands.preparedfile(filename)
--- -- some protection
--- if file.dirname(filename) == "" and root.filename then
--- local dn = file.dirname(root.filename)
--- if dn ~= "" then
--- filename = file.join(dn,filename)
--- end
--- end
--- if trace_loading then
--- report_lxml("including file %a",filename)
--- end
--- -- handy if we have a flattened structure
--- if resolve then
--- filename = resolvers.resolve(filename) or filename
--- end
--- -- todo: check variants and provide
--- noffiles, nofconverted = noffiles + 1, nofconverted + 1
--- return resolvers.loadtexfile(filename) or ""
--- else
--- return ""
--- end
--- end)
--- stoptiming(xml)
--- end
-
-- recurse prepare rootpath resolve basename
local options_true = { "recurse", "prepare", "rootpath" }
@@ -492,17 +483,17 @@ function lxml.include(id,pattern,attribute,options)
end
-- handy if we have a flattened structure
if options.basename then
- filename = file.basename(filename)
+ filename = basename(filename)
end
if options.resolve then
- filename = resolvers.resolve(filename) or filename
+ filename = resolveprefix(filename) or filename
end
-- some protection
if options.rootpath then
- if file.dirname(filename) == "" and root.filename then
- local dn = file.dirname(root.filename)
+ if dirname(filename) == "" and root.filename then
+ local dn = dirname(root.filename)
if dn ~= "" then
- filename = file.join(dn,filename)
+ filename = joinfile(dn,filename)
end
end
end
@@ -518,6 +509,20 @@ function lxml.include(id,pattern,attribute,options)
stoptiming(xml)
end
+function lxml.inclusion(id,default)
+ local inclusion = xmlinclusion(getid(id),default)
+ if inclusion then
+ context(inclusion)
+ end
+end
+
+function lxml.inclusions(id,sorted)
+ local inclusions = xmlinclusions(getid(id),sorted)
+ if inclusions then
+ context(table.concat(inclusions,","))
+ end
+end
+
function lxml.save(id,name)
xml.save(getid(id),name)
end
@@ -603,30 +608,49 @@ local function tex_element(e,handlers)
end
end
+--
+--
+
local pihandlers = { } xml.pihandlers = pihandlers
-local category = P("context-") * C((1-P("-"))^1) * P("-directive")
local space = S(" \n\r")
local spaces = space^0
local class = C((1-space)^0)
local key = class
+local rest = C(P(1)^0)
local value = C(P(1-(space * -1))^0)
-
-local parser = category * spaces * class * spaces * key * spaces * value
-
-pihandlers[#pihandlers+1] = function(str)
- if str then
- local a, b, c, d = lpegmatch(parser,str)
- if d then
- contextsprint(ctxcatcodes,"\\xmlcontextdirective{",a,"}{",b,"}{",c,"}{",d,"}")
+local category = P("context-") * (
+ C((1-P("-"))^1) * P("-directive")
+ + P("directive") * spaces * key
+ )
+
+local c_parser = category * spaces * value -- rest
+local k_parser = class * spaces * key * spaces * rest --value
+
+implement {
+ name = "xmlinstalldirective",
+ arguments = { "string", "string" },
+ actions = function(name,csname)
+ if csname then
+ local keyvalueparser = k_parser / context[csname]
+ local keyvaluechecker = function(category,rest,e)
+ lpegmatch(keyvalueparser,rest)
+ end
+ pihandlers[name] = keyvaluechecker
end
end
-end
+}
local function tex_pi(e,handlers)
local str = e.dt[1]
- for i=1,#pihandlers do
- pihandlers[i](str)
+ if str and str ~= "" then
+ local category, rest = lpegmatch(c_parser,str)
+ if category and rest and #rest > 0 then
+ local handler = pihandlers[category]
+ if handler then
+ handler(category,rest,e)
+ end
+ end
end
end
@@ -1500,7 +1524,7 @@ end
lxml.content = text
function lxml.position(id,pattern,n)
- position(xmlapplylpath(getid(id),pattern),n)
+ position(xmlapplylpath(getid(id),pattern),tonumber(n))
end
function lxml.chainattribute(id,pattern,a,default)
@@ -1516,7 +1540,7 @@ function lxml.concat(id,pattern,separator,lastseparator,textonly)
end
function lxml.element(id,n)
- position(xmlapplylpath(getid(id),"/*"),n)
+ position(xmlapplylpath(getid(id),"/*"),tonumber(n)) -- tonumber handy
end
lxml.index = lxml.position
@@ -1554,6 +1578,8 @@ function lxml.att(id,a,default)
end
elseif str ~= "" then
contextsprint(notcatcodes,str)
+ else
+ -- explicit empty is valid
end
elseif default and default ~= "" then
contextsprint(notcatcodes,default)
@@ -1679,7 +1705,20 @@ function lxml.doifelsetext (id,pattern) doifelse(not empty(getid(id),pattern)) e
-- special case: "*" and "" -> self else lpath lookup
---~ function lxml.doifelseempty(id,pattern) doifelse(isempty(getid(id),pattern ~= "" and pattern ~= nil)) end -- not yet done, pattern
+local function checkedempty(id,pattern)
+ local e = getid(id)
+ if not pattern or pattern == "" then
+ local dt = e.dt
+ local nt = #dt
+ return (nt == 0) or (nt == 1 and dt[1] == "")
+ else
+ return isempty(getid(id),pattern)
+ end
+end
+
+function lxml.doifempty (id,pattern) doif (checkedempty(id,pattern)) end
+function lxml.doifnotempty (id,pattern) doifnot (checkedempty(id,pattern)) end
+function lxml.doifelseempty(id,pattern) doifelse(checkedempty(id,pattern)) end
-- status info
@@ -1807,3 +1846,213 @@ end
texfinalizers.upperall = xmlfinalizers.upperall
texfinalizers.lowerall = xmlfinalizers.lowerall
+
+function lxml.tobuffer(id,pattern,name,unescaped)
+ local collected = xmlapplylpath(getid(id),pattern)
+ if collected then
+ if unescaped then
+ collected = xmlcontent(collected[1]) -- expanded entities !
+ else
+ collected = tostring(collected[1])
+ end
+ buffers.assign(name,collected)
+ else
+ buffers.erase(name)
+ end
+end
+
+-- relatively new:
+
+local permitted = nil
+local ctx_xmlinjector = context.xmlinjector
+
+xml.pihandlers["injector"] = function(category,rest,e)
+ local options = options_to_array(rest)
+ local action = options[1]
+ if not action then
+ return
+ end
+ local n = #options
+ if n > 1 then
+ local category = options[2]
+ if category == "*" then
+ ctx_xmlinjector(action)
+ elseif permitted then
+ if n == 2 then
+ if permitted[category] then
+ ctx_xmlinjector(action)
+ end
+ else
+ for i=2,n do
+ local category = options[i]
+ if category == "*" or permitted[category] then
+ ctx_xmlinjector(action)
+ return
+ end
+ end
+ end
+ end
+ else
+ ctx_xmlinjector(action)
+ end
+end
+
+local pattern = P("context-") * C((1-lpeg.patterns.whitespace)^1) * C(P(1)^1)
+
+function lxml.applyselectors(id)
+ local root = getid(id)
+ local function filter(e)
+ local dt = e.dt
+ local ndt = #dt
+ local done = false
+ local i = 1
+ while i <= ndt do
+ local dti = dt[i]
+ if type(dti) == "table" then
+ if dti.tg == "@pi@" then
+ local text = dti.dt[1]
+ local what, rest = lpegmatch(pattern,text)
+ if what == "select" then
+ local categories = options_to_hash(rest)
+ if categories["begin"] then
+ local okay = false
+ for k, v in next, permitted do
+ if categories[k] then
+ okay = k
+ break
+ end
+ end
+ if not trace_selectors then
+ -- skip
+ elseif okay then
+ report_lxml("accepting selector: %s",okay)
+ else
+ categories.begin = false
+ report_lxml("rejecting selector: % t",sortedkeys(categories))
+ end
+ for j=i,ndt do
+ local dtj = dt[j]
+ if type(dtj) == "table" then
+ local tg = dtj.tg
+ if tg == "@pi@" then
+ local text = dtj.dt[1]
+ local what, rest = lpegmatch(pattern,text)
+ if what == "select" then
+ local categories = options_to_hash(rest)
+ if categories["end"] then
+ i = j
+ break
+ else
+ -- error
+ end
+ end
+ elseif not okay then
+ dtj.tg = "@cm@"
+ end
+ else
+-- dt[j] = "" -- okay ?
+ end
+ end
+ end
+ elseif what == "include" then
+ local categories = options_to_hash(rest)
+ if categories["begin"] then
+ local okay = false
+ for k, v in next, permitted do
+ if categories[k] then
+ okay = k
+ break
+ end
+ end
+ if not trace_selectors then
+ -- skip
+ elseif okay then
+ report_lxml("accepting include: %s",okay)
+ else
+ categories.begin = false
+ report_lxml("rejecting include: % t",sortedkeys(categories))
+ end
+ if okay then
+ for j=i,ndt do
+ local dtj = dt[j]
+ if type(dtj) == "table" then
+ local tg = dtj.tg
+ if tg == "@cm@" then
+ local content = dtj.dt[1]
+ local element = root and xml.toelement(content,root)
+ dt[j] = element
+ element.__p__ = dt -- needs checking
+ done = true
+ elseif tg == "@pi@" then
+ local text = dtj.dt[1]
+ local what, rest = lpegmatch(pattern,text)
+ if what == "include" then
+ local categories = options_to_hash(rest)
+ if categories["end"] then
+ i = j
+ break
+ else
+ -- error
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ else
+ filter(dti)
+ end
+ end
+ if done then
+ -- probably not needed
+ xml.reindex(dt)
+ end
+ end
+ i = i + 1
+ end
+ end
+ xmlwithelements(root,filter)
+end
+
+function xml.setinjectors(set)
+ local s = settings_to_set(set)
+ if permitted then
+ for k, v in next, s do
+ permitted[k] = true
+ end
+ else
+ permitted = s
+ end
+end
+
+function xml.resetinjectors(set)
+ if permitted and set and set ~= "" then
+ local s = settings_to_set(set)
+ for k, v in next, s do
+ if v then
+ permitted[k] = nil
+ end
+ end
+ else
+ permitted = nil
+ end
+end
+
+implement {
+ name = "xmlsetinjectors",
+ actions = xml.setinjectors,
+ arguments = "string"
+}
+
+implement {
+ name = "xmlresetinjectors",
+ actions = xml.resetinjectors,
+ arguments = "string"
+}
+
+implement {
+ name = "xmlapplyselectors",
+ actions = lxml.applyselectors,
+ arguments = "string"
+}
diff --git a/Master/texmf-dist/tex/context/base/m-chart.lua b/Master/texmf-dist/tex/context/base/m-chart.lua
index 2b9869379f1..f1e7f4cb937 100644
--- a/Master/texmf-dist/tex/context/base/m-chart.lua
+++ b/Master/texmf-dist/tex/context/base/m-chart.lua
@@ -19,8 +19,6 @@ local P, S, C, Cc, lpegmatch = lpeg.P, lpeg.S, lpeg.C, lpeg.Cc, lpeg.match
local report_chart = logs.reporter("chart")
-local points = number.points -- we can use %p instead
-
local variables = interfaces.variables
local v_yes = variables.yes
@@ -229,6 +227,8 @@ function commands.flow_start_cell(settings)
settings = settings,
x = 1,
y = 1,
+ realx = 1,
+ realy = 1,
name = "",
}
end
@@ -325,9 +325,13 @@ local function inject(includedata,data,hash)
if si.include then
inject(si,data,hash)
else
+ local x = si.x + xoffset
+ local y = si.y + yoffset
local t = {
- x = si.x + xoffset,
- y = si.y + yoffset,
+ x = x,
+ y = y,
+ realx = x,
+ realy = y,
settings = settings,
}
setmetatableindex(t,si)
@@ -451,10 +455,12 @@ function commands.flow_set_location(x,y)
else
y = tonumber(y)
end
- temp.x = x or 1
- temp.y = y or 1
- last_x = x or last_x
- last_y = y or last_y
+ temp.x = x or 1
+ temp.y = y or 1
+ temp.realx = x or 1
+ temp.realy = y or 1
+ last_x = x or last_x
+ last_y = y or last_y
end
function commands.flow_set_connection(location,displacement,name)
@@ -499,17 +505,17 @@ local function process_cells(chart,xoffset,yoffset)
local linesettings = settings.line
context("flow_shape_line_color := \\MPcolor{%s} ;", linesettings.color)
context("flow_shape_fill_color := \\MPcolor{%s} ;", linesettings.backgroundcolor)
- context("flow_shape_line_width := %s ; ", points(linesettings.rulethickness))
+ context("flow_shape_line_width := %p ; ", linesettings.rulethickness)
elseif focus[cell.focus] or focus[cell.name] then
local focussettings = settings.focus
context("flow_shape_line_color := \\MPcolor{%s} ;", focussettings.framecolor)
context("flow_shape_fill_color := \\MPcolor{%s} ;", focussettings.backgroundcolor)
- context("flow_shape_line_width := %s ; ", points(focussettings.rulethickness))
+ context("flow_shape_line_width := %p ; ", focussettings.rulethickness)
else
local shapesettings = settings.shape
context("flow_shape_line_color := \\MPcolor{%s} ;", shapesettings.framecolor)
context("flow_shape_fill_color := \\MPcolor{%s} ;", shapesettings.backgroundcolor)
- context("flow_shape_line_width := %s ; " , points(shapesettings.rulethickness))
+ context("flow_shape_line_width := %p ; " , shapesettings.rulethickness)
end
context("flow_peepshape := false ;") -- todo
context("flow_new_shape(%s,%s,%s) ;",cell.x+xoffset,cell.y+yoffset,shapedata.number)
@@ -580,7 +586,7 @@ local function process_connections(chart,xoffset,yoffset)
context("flow_touchshape := %s ;", linesettings.offset == v_none and "true" or "false")
context("flow_dsp_x := %s ; flow_dsp_y := %s ;",connection.dx or 0, connection.dy or 0)
context("flow_connection_line_color := \\MPcolor{%s} ;",linesettings.color)
- context("flow_connection_line_width := %s ;",points(linesettings.rulethickness))
+ context("flow_connection_line_width := %p ;",linesettings.rulethickness)
context("flow_connect_%s_%s (%s) (%s,%s,%s) (%s,%s,%s) ;",where_cell,where_other,j,cellx,celly,what_cell,otherx,othery,what_other)
context("flow_dsp_x := 0 ; flow_dsp_y := 0 ;")
end
@@ -686,6 +692,7 @@ local function getchart(settings,forced_x,forced_y,forced_nx,forced_ny)
print("no such chart",chartname)
return
end
+-- chart = table.copy(chart)
chart = expanded(chart,settings)
local chartsettings = chart.settings.chart
local autofocus = chart.settings.chart.autofocus
@@ -746,8 +753,8 @@ local function getchart(settings,forced_x,forced_y,forced_nx,forced_ny)
-- relocate cells
for i=1,#data do
local cell = data[i]
- cell.x = cell.x - minx + 1
- cell.y = cell.y - miny + 1
+ cell.x = cell.realx - minx + 1
+ cell.y = cell.realy - miny + 1
end
chart.from_x = 1
chart.from_y = 1
@@ -756,7 +763,9 @@ local function getchart(settings,forced_x,forced_y,forced_nx,forced_ny)
chart.nx = nx
chart.ny = ny
--
- -- inspect(chart)
+ chart.shift_x = minx + 1
+ chart.shift_y = miny + 1
+ --
return chart
end
@@ -792,14 +801,14 @@ local function makechart(chart)
local labeloffset = chartsettings.labeloffset
local exitoffset = chartsettings.exitoffset
local commentoffset = chartsettings.commentoffset
- context("flow_grid_width := %s ;", points(gridwidth))
- context("flow_grid_height := %s ;", points(gridheight))
- context("flow_shape_width := %s ;", points(shapewidth))
- context("flow_shape_height := %s ;", points(shapeheight))
- context("flow_chart_offset := %s ;", points(chartoffset))
- context("flow_label_offset := %s ;", points(labeloffset))
- context("flow_exit_offset := %s ;", points(exitoffset))
- context("flow_comment_offset := %s ;", points(commentoffset))
+ context("flow_grid_width := %p ;", gridwidth)
+ context("flow_grid_height := %p ;", gridheight)
+ context("flow_shape_width := %p ;", shapewidth)
+ context("flow_shape_height := %p ;", shapeheight)
+ context("flow_chart_offset := %p ;", chartoffset)
+ context("flow_label_offset := %p ;", labeloffset)
+ context("flow_exit_offset := %p ;", exitoffset)
+ context("flow_comment_offset := %p ;", commentoffset)
--
local radius = settings.line.radius
local rulethickness = settings.line.rulethickness
@@ -814,10 +823,10 @@ local function makechart(chart)
radius = dy
end
end
- context("flow_connection_line_width := %s ;", points(rulethickness))
- context("flow_connection_smooth_size := %s ;", points(radius))
- context("flow_connection_arrow_size := %s ;", points(radius))
- context("flow_connection_dash_size := %s ;", points(radius))
+ context("flow_connection_line_width := %p ;", rulethickness)
+ context("flow_connection_smooth_size := %p ;", radius)
+ context("flow_connection_arrow_size := %p ;", radius)
+ context("flow_connection_dash_size := %p ;", radius)
--
local offset = chartsettings.offset -- todo: pass string
if offset == v_none or offset == v_overlay or offset == "" then
@@ -825,7 +834,7 @@ local function makechart(chart)
elseif offset == v_standard then
offset = radius -- or rulethickness?
end
- context("flow_chart_offset := %s ;",points(offset))
+ context("flow_chart_offset := %p ;",offset)
--
context("flow_reverse_y := true ;")
process_cells(chart,0,0)
@@ -854,7 +863,7 @@ local function splitchart(chart)
local delta_x = splitsettings.dx or 0
local delta_y = splitsettings.dy or 0
--
- report_chart("spliting %a from (%s,%s) upto (%s,%s) into (%s,%s) with overlap (%s,%s)",
+ report_chart("spliting %a from (%s,%s) upto (%s,%s) with steps (%s,%s) and overlap (%s,%s)",
name,from_x,from_y,to_x,to_y,step_x,step_y,delta_x,delta_y)
--
local part_x = 0
@@ -866,6 +875,9 @@ local function splitchart(chart)
if done then
last_x = to_x
end
+-- if first_x >= to_x then
+-- break
+-- end
local part_y = 0
local first_y = from_y
while true do
@@ -875,14 +887,31 @@ local function splitchart(chart)
if done then
last_y = to_y
end
+-- if first_y >= to_y then
+-- break
+-- end
--
+local data = chart.data
+for i=1,#data do
+ local cell = data[i]
+-- inspect(cell)
+ local cx, cy = cell.x, cell.y
+ if cx >= first_x and cx <= last_x then
+ if cy >= first_y and cy <= last_y then
report_chart("part (%s,%s) of %a is split from (%s,%s) -> (%s,%s)",part_x,part_y,name,first_x,first_y,last_x,last_y)
- local x, y, nx, ny = first_x, first_y, last_x - first_x + 1,last_y - first_y + 1
+ local x = first_x
+ local y = first_y
+ local nx = last_x - first_x + 1
+ local ny = last_y - first_y + 1
context.beforeFLOWsplit()
context.handleFLOWsplit(function()
makechart(getchart(settings,x,y,nx,ny)) -- we need to pass frozen settings !
end)
context.afterFLOWsplit()
+ break
+ end
+ end
+end
--
if done then
break
diff --git a/Master/texmf-dist/tex/context/base/m-chart.mkvi b/Master/texmf-dist/tex/context/base/m-chart.mkvi
index 2b1a7447ccd..a0c8b2244a9 100644
--- a/Master/texmf-dist/tex/context/base/m-chart.mkvi
+++ b/Master/texmf-dist/tex/context/base/m-chart.mkvi
@@ -97,7 +97,6 @@
[\c!framecolor=FLOWfocuscolor,
\c!background=\FLOWshapeparameter\c!background,
\c!backgroundcolor=\FLOWshapeparameter\c!backgroundcolor,
- \c!backgroundscreen=\FLOWshapeparameter\c!backgroundscreen,
\c!rulethickness=\FLOWshapeparameter\c!rulethickness,
\c!offset=\FLOWshapeparameter\c!offset]
@@ -177,7 +176,7 @@
corner = "\FLOWlineparameter\c!corner",
dash = "\FLOWlineparameter\c!dash",
arrow = "\FLOWlineparameter\c!arrow",
- offset = "\FLOWlineparameter\c!offset",
+ offset = \number\dimexpr\FLOWlineparameter\c!offset,
},
} }%
\endgroup}
@@ -193,7 +192,7 @@
\insidefloattrue
\dontcomplain
\setupFLOWchart[#settings]%
- \setupbodyfont[\FLOWchartparameter\c!bodyfont]%
+ \usebodyfontparameter\FLOWchartparameter
\ctxcommand{flow_make_chart {
chart = {
name = "#name",
@@ -259,8 +258,9 @@
\def\FLOW_charts[#name][#settings]
{\begingroup
- \setupFLOWsplit[\c!state=\v!start,#settings]%
- \FLOW_chart[#name][]%
+ \setupFLOWchart[\c!split=\v!yes]%
+ \setupFLOWsplit[#settings]%
+ \module_charts_process[#name][]% \FLOWchart...
\endgroup}
\appendtoks
diff --git a/Master/texmf-dist/tex/context/base/m-hemistich.mkiv b/Master/texmf-dist/tex/context/base/m-hemistich.mkiv
index 55fde7b9283..7a849d415be 100644
--- a/Master/texmf-dist/tex/context/base/m-hemistich.mkiv
+++ b/Master/texmf-dist/tex/context/base/m-hemistich.mkiv
@@ -33,7 +33,7 @@
\unexpanded\def\dodohemistiches#1[#2]#3#4%
{\dontleavehmode
\begingroup
- \doifassignmentelse{#2}
+ \doifelseassignment{#2}
{\edef\currenthemistich{#1}%
\setupcurrenthemistich[#2]}
{\def\currenthemistich{#2}}%
@@ -41,21 +41,29 @@
{\scratchwidth\availablehsize}
{\scratchwidth\hemistichparameter\c!width\relax}%
\spaceskip\zeropoint\s!plus\plusone\s!fill\relax
+ \dostarttagged\t!division\currenthemistich
\hbox to \scratchwidth\bgroup
\scratchwidth.5\dimexpr\scratchwidth-\hemistichparameter\c!distance\relax
\hbox to \scratchwidth\bgroup
+ \dostarttagged\t!construct\c!lefttext
\usehemistichstyleandcolor\c!leftstyle\c!leftcolor#3%
+ \dostoptagged
\egroup
\hss
\begingroup
+ \dostarttagged\t!construct\c!separator
\usehemistichstyleandcolor\c!separatorstyle\c!separatorcolor
\hemistichparameter\c!separator
+ \dostoptagged
\endgroup
\hss
\hbox to \scratchwidth\bgroup
+ \dostarttagged\t!construct\c!righttext
\usehemistichstyleandcolor\c!rightstyle\c!rightcolor#4%
+ \dostoptagged
\egroup
\egroup
+ \dostoptagged
\endgroup}
\unexpanded\def\hemistichescaesura#1#2#3%
diff --git a/Master/texmf-dist/tex/context/base/m-matrix.mkiv b/Master/texmf-dist/tex/context/base/m-matrix.mkiv
new file mode 100644
index 00000000000..ccb376e39c7
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/m-matrix.mkiv
@@ -0,0 +1,495 @@
+%D \module
+%D [ file=m-matrix,
+%D version=2014.11.04, % already a year older
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=Matrices,
+%D author={Jeong Dalyoung \& Hans Hagen},
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This code is based on a post by Dalyoung on the context list. After that
+%D we turned it into a module and improved the code a bit. Feel free to ask
+%D us for more. Once we're satisfied, a more general helper l-matrix could
+%D be made. Dalyoung does the clever bits, and Hans only cleanes up and
+%D optimizes a bit.
+
+% \registerctxluafile{l-matrix}{1.001} % not yet
+
+\startmodule[matrix]
+
+\startluacode
+
+local settings_to_hash = utilities.parsers.settings_to_hash
+local formatters = string.formatters
+local copy = table.copy
+local insert = table.insert
+local remove = table.remove
+
+local matrix = { }
+moduledata.matrix = matrix
+
+local f_matrix_slot = formatters["%s_{%s%s}"]
+
+function matrix.symbolic(sym, x, y, nx ,ny) -- symMatrix("a", "m", "n")
+ local nx = nx or 2
+ local ny = ny or nx
+ local function filled(i,y)
+ local mrow = { }
+ for j=1,nx do
+ mrow[#mrow+1] = f_matrix_slot(sym,i,j)
+ end
+ mrow[#mrow+1] = "\\cdots"
+ mrow[#mrow+1] = f_matrix_slot(sym,i,y)
+ return mrow
+ end
+ local function dummy()
+ local mrow = { }
+ for j=1,nx do
+ mrow[#mrow+1] = "\\vdots"
+ end
+ mrow[#mrow+1] = "\\ddots"
+ mrow[#mrow+1] = "\\vdots"
+ return mrow
+ end
+ --
+ local mm = { }
+ for i=1,ny do
+ mm[i] = filled(i,y)
+ end
+ mm[#mm+1] = dummy()
+ mm[#mm+1] = filled(x,y)
+ return mm
+end
+
+-- todo: define a matrix at the tex end so that we have more control
+
+local fences_p = {
+ left = "\\left(\\,",
+ right = "\\,\\right)",
+}
+
+local fences_b = {
+ left = "\\left[\\,",
+ right = "\\,\\right]",
+}
+
+function matrix.typeset(m,options)
+ local options = settings_to_hash(options or "")
+ context.startmatrix(options.determinant and fences_b or fences_p)
+ for i=1, #m do
+ local mi = m[i]
+ for j=1,#mi do
+ context.NC(mi[j])
+ end
+ context.NR()
+ end
+ context.stopmatrix()
+end
+
+-- interchange two rows (i-th, j-th)
+
+function matrix.swap(t,i,j)
+ t[i], t[j] = t[j], t[i]
+end
+
+-- replace i-th row with factor * (i-th row)
+
+function matrix.multiply(m,i,factor)
+ local mi = m[i]
+ for k=1,#mi do
+ mi[k] = factor * mi[k]
+ end
+ return m
+end
+
+-- scalar product "factor * m"
+
+function matrix.scalar(m, factor)
+ for i=1,#m do
+ local mi = m[i]
+ for j=1,#mi do
+ mi[j] = factor * mi[j]
+ end
+ end
+ return m
+end
+
+-- replace i-th row with i-th row + factor * (j-th row)
+
+function matrix.sumrow(m,i,j,factor)
+ local mi = m[i]
+ local mj = m[j]
+ for k=1,#mi do
+ mi[k] = mi[k] + factor * mj[k]
+ end
+end
+
+-- transpose of a matrix
+
+function matrix.transpose(m)
+ local t = { }
+ for j=1,#m[1] do
+ local r = { }
+ for i=1,#m do
+ r[i] = m[i][j]
+ end
+ t[j] = r
+ end
+ return t
+end
+
+-- inner product of two vectors
+
+function matrix.inner(u,v)
+ local nu = #u
+ if nu == 0 then
+ return 0
+ end
+ local nv = #v
+ if nv ~= nu then
+ return 0
+ end
+ local result = 0
+ for i=1,nu do
+ result = result + u[i] * v[i]
+ end
+ return result
+end
+
+-- product of two matrices
+
+function matrix.product(m1,m2)
+ local product = { }
+ if #m1[1] == #m2 then
+ for i=1,#m1 do
+ local m1i = m1[i]
+ local mrow = { }
+ for j=1,#m2[1] do
+ local temp = 0
+ for k=1,#m1[1] do
+ temp = temp + m1i[k] * m2[k][j]
+ end
+ mrow[j] = temp
+ end
+ product[i] = mrow
+ end
+ end
+ return product
+end
+
+local function uppertri(m,sign)
+ local temp = copy(m)
+ for i=1,#temp-1 do
+ local pivot = temp[i][i]
+ if pivot == 0 then
+ local pRow = i +1
+ while temp[pRow][i] == 0 do
+ pRow = pRow + 1
+ if pRow > #temp then -- if there is no nonzero number
+ return temp
+ end
+ end
+ temp[i], temp[pRow] = temp[pRow], temp[i]
+ if sign then
+ sign = -sign
+ end
+ end
+ local mi = temp[i]
+ for k=i+1, #temp do
+ local factor = -temp[k][i]/mi[i]
+ local mk = temp[k]
+ for l=i,#mk do
+ mk[l] = mk[l] + factor * mi[l]
+ end
+ end
+ end
+ if sign then
+ return temp, sign
+ else
+ return temp
+ end
+end
+
+matrix.uppertri = uppertri
+
+function matrix.determinant(m)
+ if #m == #m[1] then
+ local d = 1
+ local t, s = uppertri(m,1)
+ for i=1,#t do
+ d = d * t[i][i]
+ end
+ return s*d
+ else
+ return 0
+ end
+end
+
+local function rowechelon(m,r)
+ local temp = copy(m)
+ local pRow = 1
+ local pCol = 1
+ while pRow <= #temp do
+ local pivot = temp[pRow][pCol]
+ if pivot == 0 then
+ local i = pRow
+ local n = #temp
+ while temp[i][pCol] == 0 do
+ i = i + 1
+ if i > n then
+ -- no nonzero number in a column
+ pCol = pCol + 1
+ if pCol > #temp[pRow] then
+ -- there is no nonzero number in a row
+ return temp
+ end
+ i = pRow
+ end
+ end
+ temp[pRow], temp[i] = temp[i], temp[pRow]
+ end
+ local row = temp[pRow]
+ pivot = row[pCol]
+ for l=pCol,#row do
+ row[l] = row[l]/pivot
+ end
+
+ if r == 1 then
+ -- make the "reduced row echelon form"
+ local row = temp[pRow]
+ for k=1,pRow-1 do
+ local current = temp[k]
+ local factor = -current[pCol]
+ local mk = current
+ for l=pCol,#mk do
+ mk[l] = mk[l] + factor * row[l]
+ end
+ end
+ end
+ -- just make the row echelon form
+ local row = temp[pRow]
+ for k=pRow+1, #temp do
+ local current = temp[k]
+ local factor = -current[pCol]
+ local mk = current
+ for l=pCol,#mk do
+ mk[l] = mk[l] + factor * row[l]
+ end
+ end
+ pRow = pRow + 1
+ pCol = pCol + 1
+
+ if pRow > #temp or pCol > #temp[1] then
+ pRow = #temp + 1
+ end
+ end
+ return temp
+end
+
+matrix.rowechelon = rowechelon
+matrix.rowEchelon = rowechelon
+
+-- solve the linear equation m X = c
+
+local function solve(m,c)
+ local n = #m
+ if n ~= #c then
+ return copy(m)
+ end
+ local newm = copy(m)
+ local temp = copy(c)
+ for i=1,n do
+ insert(newm[i],temp[i])
+ end
+ return rowechelon(newm,1)
+end
+
+matrix.solve = solve
+
+-- find the inverse matrix of m
+
+local function inverse(m)
+ local n = #m
+ local temp = copy(m)
+ if n ~= #m[1] then
+ return temp
+ end
+ for i=1,n do
+ for j=1,n do
+ insert(temp[i],j == i and 1 or 0)
+ end
+ end
+ temp = rowechelon(temp,1)
+ for i=1,n do
+ for j=1,n do
+ remove(temp[i], 1)
+ end
+ end
+ return temp
+end
+
+matrix.inverse = inverse
+
+\stopluacode
+
+\stopmodule
+
+\unexpanded\def\ctxmodulematrix#1{\ctxlua{moduledata.matrix.#1}}
+
+\continueifinputfile{m-matrix.mkiv}
+
+\starttext
+
+\startluacode
+document.DemoMatrixA = {
+ { 0, 2, 4, -4, 1 },
+ { 0, 0, 2, 3, 4 },
+ { 2, 2, -6, 2, 4 },
+ { 2, 0, -6, 9, 7 },
+ { 2, 3, 4, 5, 6 },
+ { 6, 6, -6, 6, 6 },
+}
+
+document.DemoMatrixB = {
+ { 0, 2, 4, -4, 1 },
+ { 0, 0, 2, 3, 4 },
+ { 2, 2, -6, 2, 4 },
+ { 2, 0, -6, 9, 7 },
+ { 2, 2, -6, 2, 4 },
+ { 2, 2, -6, 2, 4 },
+}
+\stopluacode
+
+\startsubject[title={A symbolic matrix}]
+
+\ctxmodulematrix{typeset(moduledata.matrix.symbolic("a", "m", "n"))}
+\ctxmodulematrix{typeset(moduledata.matrix.symbolic("a", "m", "n", 4, 8))}
+
+\stopsubject
+
+\startsubject[title={Swap two rows (2 and 4)}]
+
+\startluacode
+moduledata.matrix.typeset(document.DemoMatrixA)
+context.blank()
+moduledata.matrix.swap(document.DemoMatrixA, 2, 4)
+context.blank()
+moduledata.matrix.typeset(document.DemoMatrixA)
+\stopluacode
+
+\stopsubject
+
+\startsubject[title={Multiply $3 \times r_2$}]
+
+\startluacode
+moduledata.matrix.typeset(document.DemoMatrixA)
+context.blank()
+moduledata.matrix.typeset(moduledata.matrix.multiply(document.DemoMatrixA, 2, 3))
+\stopluacode
+
+\stopsubject
+
+\startsubject[title={Row 2 + $3 \times r_4$}]
+
+\startluacode
+moduledata.matrix.typeset(document.DemoMatrixA)
+context.blank()
+moduledata.matrix.sumrow(document.DemoMatrixA, 2, 3, 4)
+context.blank()
+moduledata.matrix.typeset(document.DemoMatrixA)
+\stopluacode
+
+\stopsubject
+
+\startsubject[title={Transpose a matrix}]
+
+\startluacode
+moduledata.matrix.typeset(document.DemoMatrixA)
+context.blank()
+moduledata.matrix.typeset(moduledata.matrix.transpose(document.DemoMatrixA))
+\stopluacode
+
+\stopsubject
+
+\startsubject[title={The inner product of two vectors}]
+
+\startluacode
+context(moduledata.matrix.inner({ 1, 2, 3 }, { 3, 1, 2 }))
+context.blank()
+context(moduledata.matrix.inner({ 1, 2, 3 }, { 3, 1, 2, 4 }))
+\stopluacode
+
+\startsubject[title={The product of two matrices}]
+
+\startluacode
+moduledata.matrix.typeset(document.DemoMatrixA)
+context.blank()
+moduledata.matrix.typeset(moduledata.matrix.product(document.DemoMatrixA,document.DemoMatrixA))
+\stopluacode
+
+\stopsubject
+
+\startsubject[title={An Upper Triangular Matrix}]
+
+\ctxmodulematrix{typeset(moduledata.matrix.uppertri(document.DemoMatrixB))}
+
+\startsubject[title={A determinant}]
+
+\startluacode
+local m = {
+ { 1, 2, 4 },
+ { 0, 0, 2 },
+ { 2, 2, -6 },
+}
+context(moduledata.matrix.determinant(m))
+\stopluacode
+
+\stopsubject
+
+\startsubject[title={Row echelon form}]
+
+\startluacode
+local m = {
+ { 1, 3, -2, 0, 2, 0, 0 },
+ { 2, 6, -5, -2, 4, -3, -1 },
+ { 0, 0, 5, 10, 0, 15, 5 },
+ { 2, 6, 0, 8, 4, 18, 6 },
+}
+
+moduledata.matrix.typeset(m)
+moduledata.matrix.typeset(moduledata.matrix.rowechelon(m,1))
+\stopluacode
+
+\stopsubject
+
+\startsubject[title={Solving linear equation}]
+
+\startluacode
+local m = {
+ { 1, 3, -2, 0 },
+ { 2, 0, 1, 2 },
+ { 6, -5, -2, 4 },
+ { -3, -1, 5, 10 },
+}
+
+local c = { 5, 2, 6, 8 }
+
+moduledata.matrix.typeset(moduledata.matrix.solve(m,c))
+\stopluacode
+
+\stopsubject
+
+\startsubject[title={Inverse matrix}]
+
+\startcombination[2*1]
+ {\ctxlua{moduledata.matrix.typeset { { 1, 1, 1 }, { 0, 2, 3 }, { 3, 2, 1 } }}} {}
+ {\ctxlua{moduledata.matrix.typeset(moduledata.matrix.inverse { { 1, 1, 1 }, { 0, 2, 3 }, { 3, 2, 1 } })}} {}
+\stopcombination
+
+\stopsubject
+
+\stoptext
diff --git a/Master/texmf-dist/tex/context/base/m-morse.mkvi b/Master/texmf-dist/tex/context/base/m-morse.mkvi
deleted file mode 100644
index a2c20dff745..00000000000
--- a/Master/texmf-dist/tex/context/base/m-morse.mkvi
+++ /dev/null
@@ -1,273 +0,0 @@
-%D \module
-%D [ file=m-morse,
-%D version=2010.12.10,
-%D title=\CONTEXT\ Extra Modules,
-%D subtitle=Morse,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-% todo: act upon the node list
-% make it a buffer operation
-% nice in cld manual
-
-\startluacode
-
-moduledata.morse = moduledata.morse or { }
-local morse = moduledata.morse
-
-local utfcharacters, gsub = string.utfcharacters, string.gsub
-local ucchars, shchars = characters.ucchars, characters.shchars
-
-local codes = {
-
- ["A"] = "·—",
- ["B"] = "—···",
- ["C"] = "—·—·",
- ["D"] = "—··",
- ["E"] = "·",
- ["F"] = "··—·",
- ["G"] = "——·",
- ["H"] = "····",
- ["I"] = "··",
- ["J"] = "·———",
- ["K"] = "—·—",
- ["L"] = "·—··",
- ["M"] = "——",
- ["N"] = "—·",
- ["O"] = "———",
- ["P"] = "·——·",
- ["Q"] = "——·—",
- ["R"] = "·—·",
- ["S"] = "···",
- ["T"] = "—",
- ["U"] = "··—",
- ["V"] = "···—",
- ["W"] = "·——",
- ["X"] = "—··—",
- ["Y"] = "—·——",
- ["Z"] = "——··",
-
- ["0"] = "—————",
- ["1"] = "·————",
- ["2"] = "··———",
- ["3"] = "···——",
- ["4"] = "····—",
- ["5"] = "·····",
- ["6"] = "—····",
- ["7"] = "——···",
- ["8"] = "———··",
- ["9"] = "————·",
-
- ["."] = "·—·—·—",
- [","] = "——··——",
- [":"] = "———···",
- [";"] = "—·—·—",
-
- ["?"] = "··——··",
- ["!"] = "—·—·——",
-
- ["-"] = "—····—",
- ["/"] = "—··—· ",
-
- ["("] = "—·——·",
- [")"] = "—·——·—",
-
- ["="] = "—···—",
- ["@"] = "·——·—·",
-
- ["'"] = "·————·",
- ['"'] = "·—··—·",
-
- ["À"] = "·——·—",
- ["Å"] = "·——·—",
- ["Ä"] = "·—·—",
- ["Æ"] = "·—·—",
- ["Ç"] = "—·—··",
- ["É"] = "··—··",
- ["È"] = "·—··—",
- ["Ñ"] = "——·——",
- ["Ö"] = "———·",
- ["Ø"] = "———·",
- ["Ü"] = "··——",
- ["ß"] = "··· ···",
-
-}
-
-morse.codes = codes
-
-local fallbackself = false
-
-local function codefallback(t,k)
- if k then
- local u = ucchars[k]
- local v = rawget(t,u) or rawget(t,shchars[u]) or false
- t[k] = v
- return v
- elseif fallbackself then
- return k
- else
- return false
- end
-end
-
-table.setmetatableindex(codes,codefallback)
-
-local MorseBetweenWords = context.MorseBetweenWords
-local MorseBetweenCharacters = context.MorseBetweenCharacters
-local MorseLong = context.MorseLong
-local MorseShort = context.MorseShort
-local MorseSpace = context.MorseSpace
-local MorseUnknown = context.MorseUnknown
-
-local function toverbose(str)
- str = gsub(str,"%s*+%s*","+")
- str = gsub(str,"%s+"," ")
- local done = false
- for m in utfcharacters(str) do
- if done then
- MorseBetweenCharacters()
- end
- if m == "·" or m == "." then
- MorseShort()
- done = true
- elseif m == "—" or m == "-" then
- MorseLong()
- done = true
- elseif m == " " then
- if done then
- MorseBetweenCharacters()
- end
- done = false
- elseif m == "+" then
- MorseBetweenWords()
- done = false
- else
- MorseUnknown(m)
- end
- end
-end
-
-local function toregular(str)
- local inmorse = false
- for s in utfcharacters(str) do
- local m = codes[s]
- if m then
- if inmorse then
- MorseBetweenWords()
- else
- inmorse = true
- end
- local done = false
- for m in utfcharacters(m) do
- if done then
- MorseBetweenCharacters()
- else
- done = true
- end
- if m == "·" then
- MorseShort()
- elseif m == "—" then
- MorseLong()
- elseif m == " " then
- MorseBetweenCharacters()
- end
- end
- inmorse = true
- elseif s == "\n" or s == " " then
- MorseSpace()
- inmorse = false
- else
- if inmorse then
- MorseBetweenWords()
- else
- inmorse = true
- end
- MorseUnknown(s)
- end
- end
-end
-
-local function tomorse(str,verbose)
- if verbose then
- toverbose(str)
- else
- toregular(str)
- end
-end
-
-morse.tomorse = tomorse
-
-function morse.filetomorse(name,verbose)
- tomorse(resolvers.loadtexfile(name),verbose)
-end
-
-function morse.showtable()
- context.starttabulate { "|l|l|" } -- { "|l|l|l|" }
- for k, v in table.sortedpairs(codes) do
- context.NC() context(k)
- -- context.NC() context(v)
- context.NC() tomorse(v,true)
- context.NC() context.NR()
- end
- context.stoptabulate()
-end
-
-\stopluacode
-
-\unprotect
-
-% todo: \setupmorse, but probably it's not worth the trouble.
-
-\def\MorseWidth {0.4em}
-\def\MorseHeight {0.2em}
-%def\MorseShort {\dontleavehmode\blackrule[\c!height=\MorseHeight,\c!width=\dimexpr\MorseWidth]}
-%def\MorseLong {\dontleavehmode\blackrule[\c!height=\MorseHeight,\c!width=3\dimexpr\MorseWidth]}
-\def\MorseShort {\dontleavehmode\vrule\!!width \dimexpr\MorseWidth\!!height\MorseHeight\!!depth\zeropoint\relax}
-\def\MorseLong {\dontleavehmode\vrule\!!width3\dimexpr\MorseWidth\!!height\MorseHeight\!!depth\zeropoint\relax}
-\def\MorseBetweenCharacters {\kern\MorseWidth}
-\def\MorseBetweenWords {\hskip3\dimexpr\MorseWidth\relax}
-\def\MorseSpace {\hskip7\dimexpr\MorseWidth\relax}
-\def\MorseUnknown #text{[\detokenize{#text}]}
-
-\unexpanded\def\MorseCode #text{\ctxlua{moduledata.morse.tomorse(\!!bs#text\!!es,true)}}
-\unexpanded\def\MorseString #text{\ctxlua{moduledata.morse.tomorse(\!!bs#text\!!es)}}
-\unexpanded\def\MorseFile #text{\ctxlua{moduledata.morse.filetomorse("#text")}}
-\unexpanded\def\MorseTable {\ctxlua{moduledata.morse.showtable()}}
-
-\let\Morse \MorseString
-
-%def\MorseShort {·}
-%def\MorseLong {—}
-
-\protect
-
-\continueifinputfile{m-morse.mkvi}
-
-\starttext
-
-\MorseTable
-
-\startlines
-\MorseCode{—·—· ——— —· — · —··— —+—— —·— ·· ···—}
-\MorseCode{—·—· ——— —· — · —··— — + —— —·— ·· ···—}
-\Morse{ÀÁÂÃÄÅàáâãäå}
-\Morse{ÆÇæç}
-\Morse{ÈÉÊËèéêë}
-\Morse{ÌÍÎÏìíîï}
-\Morse{Ññ}
-\Morse{ÒÓÔÕÖòóôõö}
-\Morse{Øø}
-\Morse{ÙÚÛÜùúû}
-\Morse{Ýýÿ}
-\Morse{ß}
-\Morse{Ţţ}
-\stoplines
-
-\Morse{A B C D E F G H I J K L M N O P Q R S T U V W X Y Z}
-
-\stoptext
diff --git a/Master/texmf-dist/tex/context/base/m-oldfun.mkiv b/Master/texmf-dist/tex/context/base/m-oldfun.mkiv
index 1c5a1d29d41..3f2ec0263ed 100644
--- a/Master/texmf-dist/tex/context/base/m-oldfun.mkiv
+++ b/Master/texmf-dist/tex/context/base/m-oldfun.mkiv
@@ -131,7 +131,7 @@
\unexpanded\def\DroppedCaps#1#2#3#4#5#6#7% does not yet handle accented chars
{\defconvertedargument\asciia{#7}%
\defconvertedcommand \asciib{\DroppedString}%
- \doifinstringelse\asciia\asciib
+ \doifelseinstring\asciia\asciib
{\noindentation
\dontleavehmode
\checkindentation % redo this one
diff --git a/Master/texmf-dist/tex/context/base/m-oldnum.mkiv b/Master/texmf-dist/tex/context/base/m-oldnum.mkiv
index efc0af4721f..382c56eb674 100644
--- a/Master/texmf-dist/tex/context/base/m-oldnum.mkiv
+++ b/Master/texmf-dist/tex/context/base/m-oldnum.mkiv
@@ -73,8 +73,8 @@
\chardef\digitoutputmode=1 % 0..6
\chardef\digitsignmode =0 % 0..3
-\def\setdigitmode{\chardef\digitoutputmode}
-\def\setdigitsign{\chardef\digitsignmode}
+\unexpanded\def\setdigitmode{\chardef\digitoutputmode}
+\unexpanded\def\setdigitsign{\chardef\digitsignmode}
%D The digit modes are:
%D
@@ -100,7 +100,7 @@
\unexpanded\def\digits
{\bgroup
\let~@%
- \doifnextbgroupelse\dodigits{\doifnextcharelse\normalmathshift\domathdigits\grabdigit}}
+ \doifelsenextbgroup\dodigits{\doifelsenextchar\normalmathshift\domathdigits\grabdigit}}
\def\dodigits#1%
{\grabdigit#1\relax}
@@ -118,7 +118,7 @@
\ifx\normalmathshift\undefined \let\normalmathshift=$ \fi
-\def\scandigit
+\unexpanded\def\scandigit
{\ifx\next\blankspace
\let\next\handledigits
\else\ifx\next\nextobeyedline % the indirect one
@@ -139,10 +139,10 @@
%D typeset it in superscript. The space placeholders are
%D replaced by a \type {@}.
-\def\savedigit#1#2%
+\unexpanded\def\savedigit#1#2%
{\edef#1{#1\saveddigits#2}\let\saveddigits\empty}
-\long\def\collectdigit#1%
+\unexpanded\def\collectdigit#1%
{\ifx#1~%
\savedigit\collecteddigits @%
\else\if#1_% tricky as can be several catcodes ... will become lua code anyway
@@ -158,13 +158,13 @@
\chardef\powerdigits\plusone
\else
\savedigit\collecteddigits#1%
- %\doifnumberelse{#1}
+ %\doifelsenumber{#1}
% {\savedigit\collecteddigits#1}
% {\def\saveddigits{#1}}%
\fi\fi\fi
\else
\savedigit\savedpowerdigits#1%
- %\doifnumberelse{#1}
+ %\doifelsenumber{#1}
% {\savedigit\savedpowerdigits#1}
% {\def\saveddigits{#1}}%
\fi\fi\fi\fi
@@ -173,7 +173,7 @@
\let\handlemathdigits\firstofoneargument
\let\handletextdigits\mathematics
-\def\handledigits
+\unexpanded\def\handledigits
{%\ifcase\powerdigits
% \edef\collecteddigits{\collecteddigits\saveddigits}%
%\else
@@ -235,7 +235,7 @@
% 0,- is invalid, should be =
% 0,-- is invalid, should be ==
-\def\digitzeroamount
+\unexpanded\def\digitzeroamount
{\digitsgn\zeroamount
\def\digitzeroamount
{\hphantom
@@ -243,7 +243,7 @@
\hskip-\wd\scratchbox}%
\let\digitzeroamount\empty}}
-\def\scandigits#1%
+\unexpanded\def\scandigits#1%
{\if#1.\digitsep1\else
\if#1,\digitsep2\else
\if#1@\digitnop \else
@@ -261,7 +261,7 @@
\newbox\digitsepbox \chardef\autodigitmode=1
-\def\digitsep#1%
+\unexpanded\def\digitsep#1%
{\ifcase\autodigitmode
\doscandigit#1%
\else
@@ -277,7 +277,7 @@
%
% while this works
-\def\digitnop
+\unexpanded\def\digitnop
{\hbox{\hphantom{\box\digitsepbox}}%
\hphantom{0}\chardef\skipdigit1\relax}
@@ -287,7 +287,7 @@
% {\hphantom{\box\digitsepbox0}%
% \chardef\skipdigit1\relax}
-\def\digitsgn#1%
+\unexpanded\def\digitsgn#1%
{\ifcase\digitsignmode#1\else
\hbox
{\setbox\scratchbox\hbox{0}%
@@ -404,11 +404,11 @@
%D \digittemplate 12.000.000,00 % \digittemplate .,
%D \stoptyping
-\def\digittemplate #1 %
+\unexpanded\def\digittemplate #1 %
{\chardef\digitinputmode\zerocount
\handletokens#1\with\scandigittemplate}
-\def\scandigittemplate#1%
+\unexpanded\def\scandigittemplate#1%
{\if #1.\ifcase\digitinputmode\chardef\digitinputmode\plusone \fi% period
\else\if#1,\ifcase\digitinputmode\chardef\digitinputmode\plustwo \fi% comma
\fi\fi}
diff --git a/Master/texmf-dist/tex/context/base/m-scite.mkiv b/Master/texmf-dist/tex/context/base/m-scite.mkiv
index aed2c26315d..7a8e8b06e6f 100644
--- a/Master/texmf-dist/tex/context/base/m-scite.mkiv
+++ b/Master/texmf-dist/tex/context/base/m-scite.mkiv
@@ -66,6 +66,8 @@ local f_mapping = [[
\let\string\slxR\string\letterrightbrace
\let\string\slxM\string\letterdollar
\let\string\slxV\string\letterbar
+\let\string\slxU\string\letterhat
+\let\string\slxD\string\letterunderscore
\let\string\slxH\string\letterhash
\let\string\slxB\string\letterbackslash
\let\string\slxP\string\letterpercent
@@ -76,6 +78,8 @@ local replacer = lpeg.replacer {
["{"] = "\\slxL ",
["}"] = "\\slxR ",
["$"] = "\\slxM ",
+ ["^"] = "\\slxU ",
+ ["_"] = "\\slxD ",
["|"] = "\\slxV ",
["#"] = "\\slxH ",
["\\"] = "\\slxB ",
@@ -195,6 +199,7 @@ end
\installscitecommands
\tt
\dontcomplain
+ \setcatcodetable\ctxcatcodes % needed in xml
\startscite
\getbuffer[lex]%
\stopscite
@@ -213,6 +218,7 @@ end
\installscitecommands
\tt
\dontcomplain
+ \setcatcodetable\ctxcatcodes % needed in xml
\startscite
\getbuffer[lex]%
\stopscite
diff --git a/Master/texmf-dist/tex/context/base/m-spreadsheet.mkiv b/Master/texmf-dist/tex/context/base/m-spreadsheet.mkiv
index 5e0499184bb..914a2b57a9e 100644
--- a/Master/texmf-dist/tex/context/base/m-spreadsheet.mkiv
+++ b/Master/texmf-dist/tex/context/base/m-spreadsheet.mkiv
@@ -88,6 +88,8 @@
\unexpanded\def\doifelsespreadsheetcell
{\dosingleempty\module_spreadsheet_doifelse_cell}
+\let\doifspreadsheetcellelse\doifelsespreadsheetcell
+
\unexpanded\def\module_spreadsheet_doifelse_cell[#1]#2#3%
{\ctxlua{moduledata.spreadsheets.doifelsecell("#1",\number#2,\number#3)}}
@@ -118,7 +120,7 @@
\let\stoprow \module_spreadsheet_row_stop
\let\startcell\module_spreadsheet_cell_start
\let\stopcell \module_spreadsheet_cell_stop
- \doifassignmentelse{#1}
+ \doifelseassignment{#1}
{\module_spreadsheet_start
\directsetup{spreadsheet:before:\currentspreadsheet}%
\bTABLE[\c!align=\v!flushright,#1]}
@@ -136,7 +138,7 @@
\unexpanded\def\module_spreadsheet_row_stop {\eTR}
\unexpanded\def\module_spreadsheet_cell_start
- {\doifnextoptionalelse\module_spreadsheet_cell_start_yes\module_spreadsheet_cell_start_nop}
+ {\doifelsenextoptional\module_spreadsheet_cell_start_yes\module_spreadsheet_cell_start_nop}
\unexpanded\def\module_spreadsheet_cell_start_yes[#1]#2\stopcell
{\bTD[#1]\getspr{#2}\eTD}
diff --git a/Master/texmf-dist/tex/context/base/m-steps.lua b/Master/texmf-dist/tex/context/base/m-steps.lua
index 97759b79917..8eb4815506e 100644
--- a/Master/texmf-dist/tex/context/base/m-steps.lua
+++ b/Master/texmf-dist/tex/context/base/m-steps.lua
@@ -10,7 +10,6 @@ if not modules then modules = { } end modules ['x-flow'] = {
moduledata.steps = moduledata.steps or { }
-local points = number.points -- number.pt
local variables = interfaces.variables
local trace_charts = false
@@ -100,22 +99,22 @@ function commands.step_make_chart(settings)
end
--
context("text_line_color := \\MPcolor{%s} ;", textsettings.framecolor)
- context("text_line_width := %s ;", points(textsettings.rulethickness))
+ context("text_line_width := %p ;", textsettings.rulethickness)
context("text_fill_color := \\MPcolor{%s} ;", textsettings.backgroundcolor)
- context("text_offset := %s ;", points(textsettings.offset))
- context("text_distance_set := %s ;", points(textsettings.distance))
+ context("text_offset := %p ;", textsettings.offset)
+ context("text_distance_set := %p ;", textsettings.distance)
--
context("cell_line_color := \\MPcolor{%s} ;", cellsettings.framecolor)
- context("cell_line_width := %s ;", points(cellsettings.rulethickness))
+ context("cell_line_width := %p ;", cellsettings.rulethickness)
context("cell_fill_color := \\MPcolor{%s} ;", cellsettings.backgroundcolor)
- context("cell_offset := %s ;", points(cellsettings.offset))
- context("cell_distance_x := %s ;", points(cellsettings.dx))
- context("cell_distance_y := %s ;", points(cellsettings.dy))
+ context("cell_offset := %p ;", cellsettings.offset)
+ context("cell_distance_x := %p ;", cellsettings.dx)
+ context("cell_distance_y := %p ;", cellsettings.dy)
--
context("line_line_color := \\MPcolor{%s} ;", linesettings.color)
- context("line_line_width := %s ;", points(linesettings.rulethickness))
- context("line_distance := %s ;", points(linesettings.distance))
- context("line_offset := %s ;", points(linesettings.offset))
+ context("line_line_width := %p ;", linesettings.rulethickness)
+ context("line_distance := %p ;", linesettings.distance)
+ context("line_offset := %p ;", linesettings.offset)
--
for i=1,#steps do
local step = steps[i]
diff --git a/Master/texmf-dist/tex/context/base/m-steps.mkvi b/Master/texmf-dist/tex/context/base/m-steps.mkvi
index a07ece3ae8d..c9c5a063620 100644
--- a/Master/texmf-dist/tex/context/base/m-steps.mkvi
+++ b/Master/texmf-dist/tex/context/base/m-steps.mkvi
@@ -98,7 +98,7 @@
\def\module_steps_start_chart[#name][#settings]%
{\startnointerference
\iffirstargument
- \doifassignmentelse{#name}
+ \doifelseassignment{#name}
{\let\currentSTEPchart\empty
\xdef\module_steps_flush_chart{\module_steps_chart[][#name]}}
{\edef\currentSTEPchart{#name}%
diff --git a/Master/texmf-dist/tex/context/base/m-translate.mkiv b/Master/texmf-dist/tex/context/base/m-translate.mkiv
index f36f9a9fba2..2e6cbe95088 100644
--- a/Master/texmf-dist/tex/context/base/m-translate.mkiv
+++ b/Master/texmf-dist/tex/context/base/m-translate.mkiv
@@ -22,12 +22,34 @@
local compiled, list = nil, nil
+ -- function translators.register(from,to)
+ -- local l = lpeg.P(from)/to
+ -- if not list then
+ -- list = l
+ -- else
+ -- list = list + l
+ -- end
+ -- compiled = nil
+ -- end
+ --
+ -- function translators.translate(s)
+ -- if list then
+ -- if not compiled then
+ -- compiled = lpeg.Cs((list + lpeg.P(1))^0)
+ -- end
+ -- return compiled:match(s)
+ -- else
+ -- return s
+ -- end
+ -- end
+
+ -- local function prepare()
+
function translators.register(from,to)
- local l = lpeg.P(from)/to
if not list then
- list = l
+ list = { [from] = to }
else
- list = list + l
+ list[from] = to
end
compiled = nil
end
@@ -35,7 +57,8 @@
function translators.translate(s)
if list then
if not compiled then
- compiled = lpeg.Cs((list + lpeg.P(1))^0)
+ local tree = lpeg.utfchartabletopattern(list)
+ compiled = lpeg.Cs((tree/list + lpeg.patterns.utf8character)^0 * lpeg.P(-1)) -- the P(1) is needed in order to accept non utf
end
return compiled:match(s)
else
diff --git a/Master/texmf-dist/tex/context/base/m-visual.mkiv b/Master/texmf-dist/tex/context/base/m-visual.mkiv
index 504c0d0c5f2..3c57691ec64 100644
--- a/Master/texmf-dist/tex/context/base/m-visual.mkiv
+++ b/Master/texmf-dist/tex/context/base/m-visual.mkiv
@@ -161,7 +161,7 @@
{\freezerandomseed
\let\endstrut\relax
\let\begstrut\relax
- \doifinsetelse{#1}{\v!left,\v!right}
+ \doifelseinset{#1}{\v!left,\v!right}
{\fakewords{2}{4}}
{\fakewords{4}{10}}}%
{\doifinset{#1}{\v!left,\v!right}
@@ -762,7 +762,7 @@
\startoverlay
{\copy\scratchbox}
{\dodotagbox{#1}\scratchbox{\framed
- [\c!background=\v!screen,\c!backgroundscreen=1]{#2}}}
+ [\c!background=\v!color,\c!backgroundcolor=\v!gray]{#2}}}
\stopoverlay
\egroup
\nextboxwd\the\wd\scratchbox
diff --git a/Master/texmf-dist/tex/context/base/math-act.lua b/Master/texmf-dist/tex/context/base/math-act.lua
index 879480dce59..d0ea789909c 100644
--- a/Master/texmf-dist/tex/context/base/math-act.lua
+++ b/Master/texmf-dist/tex/context/base/math-act.lua
@@ -90,6 +90,8 @@ end
sequencers.appendaction("mathparameters","system","mathematics.scaleparameters")
+-- AccentBaseHeight vs FlattenedAccentBaseHeight
+
function mathematics.checkaccentbaseheight(target,original)
local mathparameters = target.mathparameters
if mathparameters and mathparameters.AccentBaseHeight == 0 then
@@ -103,15 +105,23 @@ function mathematics.checkprivateparameters(target,original)
local mathparameters = target.mathparameters
if mathparameters then
local parameters = target.parameters
+ local properties = target.properties
if parameters then
- if not mathparameters.FractionDelimiterSize then
- mathparameters.FractionDelimiterSize = 1.01 * parameters.size
- end
- if not mathparameters.FractionDelimiterDisplayStyleSize then
- mathparameters.FractionDelimiterDisplayStyleSize = 2.40 * parameters.size
+ local size = parameters.size
+ if size then
+ if not mathparameters.FractionDelimiterSize then
+ mathparameters.FractionDelimiterSize = 1.01 * size
+ end
+ if not mathparameters.FractionDelimiterDisplayStyleSize then
+ mathparameters.FractionDelimiterDisplayStyleSize = 2.40 * size
+ end
+ elseif properties then
+ report_math("invalid parameters in font %a",properties.fullname or "?")
+ else
+ report_math("invalid parameters in font")
end
- elseif target.properties then
- report_math("no parameters in font %a",target.properties.fullname or "?")
+ elseif properties then
+ report_math("no parameters in font %a",properties.fullname or "?")
else
report_math("no parameters and properties in font")
end
@@ -465,21 +475,17 @@ setmetatableindex(extensibles,function(extensibles,font)
return codes
end)
-function mathematics.extensiblecode(family,unicode)
+local function extensiblecode(family,unicode)
return extensibles[family_font(family or 0)][unicode][1]
end
-function commands.extensiblecode(family,unicode)
- context(extensibles[family_font(family or 0)][unicode][1])
-end
-
-- left : [head] ...
-- right : ... [head]
-- horizontal : [head] ... [head]
--
-- abs(right["start"] - right["end"]) | right.advance | characters[right.glyph].width
-function commands.horizontalcode(family,unicode)
+local function horizontalcode(family,unicode)
local font = family_font(family or 0)
local data = extensibles[font][unicode]
local kind = data[1]
@@ -503,13 +509,30 @@ function commands.horizontalcode(family,unicode)
loffset = abs((left ["start"] or 0) - (left ["end"] or 0))
roffset = abs((right["start"] or 0) - (right["end"] or 0))
end
- else
end
- texsetdimen("scratchleftoffset",loffset)
- texsetdimen("scratchrightoffset",roffset)
- context(kind)
+ return kind, loffset, roffset
end
+mathematics.extensiblecode = extensiblecode
+mathematics.horizontalcode = horizontalcode
+
+interfaces.implement {
+ name = "extensiblecode",
+ arguments = { "integer", "integer" },
+ actions = { extensiblecode, context }
+}
+
+interfaces.implement {
+ name = "horizontalcode",
+ arguments = { "integer", "integer" },
+ actions = function(family,unicode)
+ local kind, loffset, roffset = horizontalcode(family,unicode)
+ texsetdimen("scratchleftoffset", loffset)
+ texsetdimen("scratchrightoffset",roffset)
+ context(kind)
+ end
+}
+
-- experiment
-- check: when true, only set when present in font
@@ -517,85 +540,6 @@ end
local blocks = characters.blocks -- this will move to char-ini
-blocks["uppercasenormal"] = { first = 0x00041, last = 0x0005A }
-blocks["uppercasebold"] = { first = 0x1D400, last = 0x1D419 }
-blocks["uppercaseitalic"] = { first = 0x1D434, last = 0x1D44D }
-blocks["uppercasebolditalic"] = { first = 0x1D468, last = 0x1D481 }
-blocks["uppercasescript"] = { first = 0x1D49C, last = 0x1D4B5 }
-blocks["uppercaseboldscript"] = { first = 0x1D4D0, last = 0x1D4E9 }
-blocks["uppercasefraktur"] = { first = 0x1D504, last = 0x1D51D }
-blocks["uppercasedoublestruck"] = { first = 0x1D538, last = 0x1D551 }
-blocks["uppercaseboldfraktur"] = { first = 0x1D56C, last = 0x1D585 }
-blocks["uppercasesansserifnormal"] = { first = 0x1D5A0, last = 0x1D5B9 }
-blocks["uppercasesansserifbold"] = { first = 0x1D5D4, last = 0x1D5ED }
-blocks["uppercasesansserifitalic"] = { first = 0x1D608, last = 0x1D621 }
-blocks["uppercasesansserifbolditalic"] = { first = 0x1D63C, last = 0x1D655 }
-blocks["uppercasemonospace"] = { first = 0x1D670, last = 0x1D689 }
-blocks["uppercasegreeknormal"] = { first = 0x00391, last = 0x003AA }
-blocks["uppercasegreekbold"] = { first = 0x1D6A8, last = 0x1D6C1 }
-blocks["uppercasegreekitalic"] = { first = 0x1D6E2, last = 0x1D6FB }
-blocks["uppercasegreekbolditalic"] = { first = 0x1D71C, last = 0x1D735 }
-blocks["uppercasegreeksansserifbold"] = { first = 0x1D756, last = 0x1D76F }
-blocks["uppercasegreeksansserifbolditalic"] = { first = 0x1D790, last = 0x1D7A9 }
-
-blocks["lowercasenormal"] = { first = 0x00061, last = 0x0007A }
-blocks["lowercasebold"] = { first = 0x1D41A, last = 0x1D433 }
-blocks["lowercaseitalic"] = { first = 0x1D44E, last = 0x1D467 }
-blocks["lowercasebolditalic"] = { first = 0x1D482, last = 0x1D49B }
-blocks["lowercasescript"] = { first = 0x1D4B6, last = 0x1D4CF }
-blocks["lowercaseboldscript"] = { first = 0x1D4EA, last = 0x1D503 }
-blocks["lowercasefraktur"] = { first = 0x1D51E, last = 0x1D537 }
-blocks["lowercasedoublestruck"] = { first = 0x1D552, last = 0x1D56B }
-blocks["lowercaseboldfraktur"] = { first = 0x1D586, last = 0x1D59F }
-blocks["lowercasesansserifnormal"] = { first = 0x1D5BA, last = 0x1D5D3 }
-blocks["lowercasesansserifbold"] = { first = 0x1D5EE, last = 0x1D607 }
-blocks["lowercasesansserifitalic"] = { first = 0x1D622, last = 0x1D63B }
-blocks["lowercasesansserifbolditalic"] = { first = 0x1D656, last = 0x1D66F }
-blocks["lowercasemonospace"] = { first = 0x1D68A, last = 0x1D6A3 }
-blocks["lowercasegreeknormal"] = { first = 0x003B1, last = 0x003CA }
-blocks["lowercasegreekbold"] = { first = 0x1D6C2, last = 0x1D6DB }
-blocks["lowercasegreekitalic"] = { first = 0x1D6FC, last = 0x1D715 }
-blocks["lowercasegreekbolditalic"] = { first = 0x1D736, last = 0x1D74F }
-blocks["lowercasegreeksansserifbold"] = { first = 0x1D770, last = 0x1D789 }
-blocks["lowercasegreeksansserifbolditalic"] = { first = 0x1D7AA, last = 0x1D7C3 }
-
-blocks["digitsnormal"] = { first = 0x00030, last = 0x00039 }
-blocks["digitsbold"] = { first = 0x1D7CE, last = 0x1D7D8 }
-blocks["digitsdoublestruck"] = { first = 0x1D7D8, last = 0x1D7E2 }
-blocks["digitssansserifnormal"] = { first = 0x1D7E2, last = 0x1D7EC }
-blocks["digitssansserifbold"] = { first = 0x1D7EC, last = 0x1D805 }
-blocks["digitsmonospace"] = { first = 0x1D7F6, last = 0x1D80F }
-
-blocks["mathematicaloperators"] = { first = 0x02200, last = 0x022FF }
-blocks["miscellaneousmathematicalsymbolsa"] = { first = 0x027C0, last = 0x027EF }
-blocks["miscellaneousmathematicalsymbolsb"] = { first = 0x02980, last = 0x029FF }
-blocks["supplementalmathematicaloperators"] = { first = 0x02A00, last = 0x02AFF }
-blocks["letterlikesymbols"] = { first = 0x02100, last = 0x0214F }
-blocks["miscellaneoustechnical"] = { first = 0x02308, last = 0x0230B }
-blocks["geometricshapes"] = { first = 0x025A0, last = 0x025FF }
-blocks["miscellaneoussymbolsandarrows"] = { first = 0x02B30, last = 0x02B4C }
-blocks["mathematicalalphanumericsymbols"] = { first = 0x00400, last = 0x1D7FF }
-
-blocks["digitslatin"] = { first = 0x00030, last = 0x00039 }
-blocks["digitsarabicindic"] = { first = 0x00660, last = 0x00669 }
-blocks["digitsextendedarabicindic"] = { first = 0x006F0, last = 0x006F9 }
-------["digitsdevanagari"] = { first = 0x00966, last = 0x0096F }
-------["digitsbengali"] = { first = 0x009E6, last = 0x009EF }
-------["digitsgurmukhi"] = { first = 0x00A66, last = 0x00A6F }
-------["digitsgujarati"] = { first = 0x00AE6, last = 0x00AEF }
-------["digitsoriya"] = { first = 0x00B66, last = 0x00B6F }
-------["digitstamil"] = { first = 0x00030, last = 0x00039 } -- no zero
-------["digitstelugu"] = { first = 0x00C66, last = 0x00C6F }
-------["digitskannada"] = { first = 0x00CE6, last = 0x00CEF }
-------["digitsmalayalam"] = { first = 0x00D66, last = 0x00D6F }
-------["digitsthai"] = { first = 0x00E50, last = 0x00E59 }
-------["digitslao"] = { first = 0x00ED0, last = 0x00ED9 }
-------["digitstibetan"] = { first = 0x00F20, last = 0x00F29 }
-------["digitsmyanmar"] = { first = 0x01040, last = 0x01049 }
-------["digitsethiopic"] = { first = 0x01369, last = 0x01371 }
-------["digitskhmer"] = { first = 0x017E0, last = 0x017E9 }
-------["digitsmongolian"] = { first = 0x01810, last = 0x01809 }
-
-- operators : 0x02200
-- symbolsa : 0x02701
-- symbolsb : 0x02901
diff --git a/Master/texmf-dist/tex/context/base/math-ali.mkiv b/Master/texmf-dist/tex/context/base/math-ali.mkiv
index 6bfde57b6f3..bba55ba72c4 100644
--- a/Master/texmf-dist/tex/context/base/math-ali.mkiv
+++ b/Master/texmf-dist/tex/context/base/math-ali.mkiv
@@ -31,6 +31,8 @@
\newtoks\c_math_align_b
\newtoks\c_math_align_c
+\def\displayopenupvalue{.25\bodyfontsize}
+
\def\math_build_eqalign
{\scratchtoks\emptytoks
\dorecurse{\mathalignmentparameter\c!m}\math_build_eqalign_step
@@ -38,19 +40,25 @@
\def\math_build_eqalign_step
{\ifnum\recurselevel>\plusone
- %\appendtoks
- % \tabskip\mathalignmentparameter\c!distance\aligntab\tabskip\zeropoint
- %\to\scratchtoks
\scratchtoks\expandafter{\the\scratchtoks\tabskip\mathalignmentparameter\c!distance\aligntab\tabskip\zeropoint}%
\fi
\normalexpanded{\scratchtoks{\the\scratchtoks\the\c_math_align_a}}%
\dorecurse{\numexpr\mathalignmentparameter\c!n-\plusone\relax}
{\normalexpanded{\scratchtoks{\the\scratchtoks\the\c_math_align_b}}}}
-\def\math_math_in_eqalign#1{$\tabskip\zeropoint\everycr\emptytoks\displaystyle{{}#1{}}$}
-\def\math_text_in_eqalign#1{$\tabskip\zeropoint\everycr\emptytoks#1$}
+\def\math_math_in_eqalign#1%
+ {\startforceddisplaymath
+ \tabskip\zeropoint
+ \everycr\emptytoks
+ {{}#1{}}%
+ \stopforceddisplaymath}
-\def\displayopenupvalue{.25\bodyfontsize}
+\def\math_text_in_eqalign#1%
+ {\startimath
+ \tabskip\zeropoint
+ \everycr\emptytoks
+ #1%
+ \stopimath}
\def\eqalign#1% why no halign here, probably because of displaywidth
{\emptyhbox
@@ -58,7 +66,15 @@
\vcenter
{\math_openup\displayopenupvalue % was: \openup\jot
\mathsurround\zeropoint
- \ialign{\strut\hfil$\displaystyle{\alignmark\alignmark}$\aligntab$\displaystyle{{}\alignmark\alignmark{}}$\hfil\crcr#1\crcr}}%
+ \ialign{%
+ \strut
+ \hfil
+ \startforceddisplaymath{\alignmark\alignmark}\stopforceddisplaymath
+ \aligntab
+ \startforceddisplaymath{{}\alignmark\alignmark{}}\stopforceddisplaymath
+ \hfil\crcr
+ #1\crcr}%
+ }%
\mskip\thinmuskip}
% preamble is scanned for tabskips so we need the span to prevent an error message
@@ -257,7 +273,7 @@
%
-\def\numberedeqalign
+\unexpanded\def\numberedeqalign
{\doifelse{\formulaparameter\c!location}\v!left
\math_handle_eqalign_no_l_aligned
\math_handle_eqalign_no_r_aligned}
@@ -605,16 +621,27 @@
{\iffirstargument
\setupcurrentmathmatrix[#1]%
\fi
- \emptyhbox
+ % \emptyhbox % noted at 25-05-2014: what was that one doing here? it messed up spacing
\math_matrix_align_method_analyze
\mathmatrixleft
+ % new per 13-10-2014
+ \edef\p_strut{\mathmatrixparameter\c!strut}%
+ \ifx\p_strut\v!no
+ \let\m_matrix_strut\relax
+ \else
+ \let\m_matrix_strut\strut
+ \ifx\p_strut\v!yes\else
+ \spacing\p_strut
+ \fi
+ \fi
+ %
\mathmatrixbox\bgroup
\pushmacro\math_matrix_NC
\let\endmath\relax
\def\NC{\math_matrix_NC}%
\def\MC{\math_matrix_NC\ifmmode\else\startimath\let\endmath\stopimath\fi}%
\global\let\math_matrix_NC\math_matrix_NC_indeed
- \def\NR{\endmath\global\let\math_matrix_NC\math_matrix_NC_indeed\crcr}%
+ \def\NR{\endmath\global\let\math_matrix_NC\math_matrix_NC_indeed\m_matrix_strut \crcr}%
\normalbaselines
\mathsurround\zeropoint
\everycr\emptytoks
@@ -700,7 +727,7 @@
%D
%D \typebuffer \getbuffer
%D
-%D \definemathmatrix[bmatrix][left={\left[\mskip\thinmuskip},right={\mskip\thinmuskip\right]}]
+%D \definemathmatrix[bmatrix][left={\left[\mskip\thinmuskip},right={\mskip\thinmuskip\right]},strut=1.25]
%D
%D \startbuffer
%D \placeformula \startformula[-] \startbmatrix
@@ -1024,8 +1051,7 @@
\strc_formulas_place_number
\setbox\scratchbox\math_hbox to \displaywidth\bgroup
\mathinnerstrut
- $%
- \displaystyle
+ \startforceddisplaymath
\ifcase\mathraggedstatus\or\hfill\or\hfill\fi}
\def\math_box_llapped_math_no
@@ -1047,7 +1073,7 @@
\fi}
\unexpanded\def\stopmathbox
- {$%
+ {\stopforceddisplaymath
\ifcase\mathraggedstatus\or\or\hfill\or\hfill\fi
\egroup
\setbox0\hbox{\unhcopy\scratchbox}%
diff --git a/Master/texmf-dist/tex/context/base/math-arr.mkiv b/Master/texmf-dist/tex/context/base/math-arr.mkiv
index 6824c362e67..0e3a53f3219 100644
--- a/Master/texmf-dist/tex/context/base/math-arr.mkiv
+++ b/Master/texmf-dist/tex/context/base/math-arr.mkiv
@@ -63,7 +63,7 @@
\setvalue{\??matharrowsettings\v!big }{\def\m_math_arrows_extra{20}}
\setvalue{\??matharrowsettings\v!normal }{}
\setvalue{\??matharrowsettings }{}
-\setvalue{\??matharrowsettings\s!unknown}{\doifnumberelse\p_math_spacing{\let\m_math_arrows_extra\p_math_spacing}\donothing}
+\setvalue{\??matharrowsettings\s!unknown}{\doifelsenumber\p_math_spacing{\let\m_math_arrows_extra\p_math_spacing}\donothing}
\def\math_arrows_construct#1#2#3#4#5% hm, looks like we do a double mathrel (a bit cleaned up .. needs checking)
{\begingroup
diff --git a/Master/texmf-dist/tex/context/base/math-def.mkiv b/Master/texmf-dist/tex/context/base/math-def.mkiv
index 25098695902..0888081f065 100644
--- a/Master/texmf-dist/tex/context/base/math-def.mkiv
+++ b/Master/texmf-dist/tex/context/base/math-def.mkiv
@@ -30,6 +30,9 @@
\definemathcommand [arccos] [nolop] {\mfunctionlabeltext{arccos}}
\definemathcommand [arcsin] [nolop] {\mfunctionlabeltext{arcsin}}
\definemathcommand [arctan] [nolop] {\mfunctionlabeltext{arctan}}
+\definemathcommand [acos] [nolop] {\mfunctionlabeltext{acos}}
+\definemathcommand [asin] [nolop] {\mfunctionlabeltext{asin}}
+\definemathcommand [atan] [nolop] {\mfunctionlabeltext{atan}}
\definemathcommand [arg] [nolop] {\mfunctionlabeltext{arg}}
\definemathcommand [cosh] [nolop] {\mfunctionlabeltext{cosh}}
\definemathcommand [cos] [nolop] {\mfunctionlabeltext{cos}}
diff --git a/Master/texmf-dist/tex/context/base/math-dir.lua b/Master/texmf-dist/tex/context/base/math-dir.lua
index bcc5461e976..0f871beede2 100644
--- a/Master/texmf-dist/tex/context/base/math-dir.lua
+++ b/Master/texmf-dist/tex/context/base/math-dir.lua
@@ -33,7 +33,6 @@ local getid = nuts.getid
local getlist = nuts.getlist
local setfield = nuts.setfield
local getattr = nuts.getattr
-local setattr = nuts.setattr
local insert_node_before = nuts.insert_before
local insert_node_after = nuts.insert_after
@@ -163,4 +162,8 @@ function directions.setmath(n)
end
end
-commands.setmathdirection = directions.setmath
+interfaces.implement {
+ name = "setmathdirection",
+ actions = directions.setmath,
+ arguments = "integer"
+}
diff --git a/Master/texmf-dist/tex/context/base/math-fbk.lua b/Master/texmf-dist/tex/context/base/math-fbk.lua
index 70a8ae8d61c..76dd1ad9b1a 100644
--- a/Master/texmf-dist/tex/context/base/math-fbk.lua
+++ b/Master/texmf-dist/tex/context/base/math-fbk.lua
@@ -20,7 +20,6 @@ local virtualcharacters = { }
local identifiers = fonts.hashes.identifiers
local lastmathids = fonts.hashes.lastmathids
-local tounicode16 = fonts.mappings.tounicode16
-- we need a trick (todo): if we define scriptscript, script and text in
-- that order we could use their id's .. i.e. we could always add a font
@@ -190,12 +189,12 @@ virtualcharacters[0x207B] = function(data)
end
virtualcharacters[0x208A] = function(data)
- data.replacement = 0x2212
+ data.replacement = 0x002B
return raised(data,true)
end
virtualcharacters[0x208B] = function(data)
- data.replacement = 0x002B
+ data.replacement = 0x2212
return raised(data,true)
end
@@ -330,7 +329,7 @@ end
-- we could move the defs from math-act here
-local function accent_to_extensible(target,newchr,original,oldchr,height,depth,swap,offset)
+local function accent_to_extensible(target,newchr,original,oldchr,height,depth,swap,offset,unicode)
local characters = target.characters
local olddata = characters[oldchr]
-- brrr ... pagella has only next
@@ -350,6 +349,7 @@ local function accent_to_extensible(target,newchr,original,oldchr,height,depth,s
width = olddata.width,
height = height,
depth = depth,
+ unicode = unicode,
}
local glyphdata = newdata
local nextglyph = olddata.next
@@ -415,7 +415,7 @@ virtualcharacters[0x203E] = function(data) -- could be FE33E instead
height = target.parameters.xheight/4
depth = height
end
- return accent_to_extensible(target,0x203E,data.original,0x0305,height,depth)
+ return accent_to_extensible(target,0x203E,data.original,0x0305,height,depth,nil,nil,0x203E)
end
virtualcharacters[0xFE33E] = virtualcharacters[0x203E] -- convenient
@@ -426,37 +426,37 @@ local function smashed(data,unicode,swap,private)
local original = data.original
local chardata = target.characters[unicode]
if chardata and chardata.height > target.parameters.xheight then
- return accent_to_extensible(target,private,original,unicode,0,0,swap)
+ return accent_to_extensible(target,private,original,unicode,0,0,swap,nil,unicode)
else
return original.characters[unicode]
end
end
-addextra(0xFE3DE, { description="EXTENSIBLE OF 0x03DE", unicodeslot=0xFE3DE, mathextensible = "r", mathstretch = "h" } )
-addextra(0xFE3DC, { description="EXTENSIBLE OF 0x03DC", unicodeslot=0xFE3DC, mathextensible = "r", mathstretch = "h" } )
-addextra(0xFE3B4, { description="EXTENSIBLE OF 0x03B4", unicodeslot=0xFE3B4, mathextensible = "r", mathstretch = "h" } )
+addextra(0xFE3DE, { description="EXTENSIBLE OF 0x03DE", unicodeslot=0xFE3DE, mathextensible = "r", mathstretch = "h", mathclass = "topaccent" } )
+addextra(0xFE3DC, { description="EXTENSIBLE OF 0x03DC", unicodeslot=0xFE3DC, mathextensible = "r", mathstretch = "h", mathclass = "topaccent" } )
+addextra(0xFE3B4, { description="EXTENSIBLE OF 0x03B4", unicodeslot=0xFE3B4, mathextensible = "r", mathstretch = "h", mathclass = "topaccent" } )
virtualcharacters[0xFE3DE] = function(data) return smashed(data,0x23DE,0x23DF,0xFE3DE) end
virtualcharacters[0xFE3DC] = function(data) return smashed(data,0x23DC,0x23DD,0xFE3DC) end
virtualcharacters[0xFE3B4] = function(data) return smashed(data,0x23B4,0x23B5,0xFE3B4) end
-addextra(0xFE3DF, { description="EXTENSIBLE OF 0x03DF", unicodeslot=0xFE3DF, mathextensible = "r", mathstretch = "h" } )
-addextra(0xFE3DD, { description="EXTENSIBLE OF 0x03DD", unicodeslot=0xFE3DD, mathextensible = "r", mathstretch = "h" } )
-addextra(0xFE3B5, { description="EXTENSIBLE OF 0x03B5", unicodeslot=0xFE3B5, mathextensible = "r", mathstretch = "h" } )
+addextra(0xFE3DF, { description="EXTENSIBLE OF 0x03DF", unicodeslot=0xFE3DF, mathextensible = "r", mathstretch = "h", mathclass = "botaccent" } )
+addextra(0xFE3DD, { description="EXTENSIBLE OF 0x03DD", unicodeslot=0xFE3DD, mathextensible = "r", mathstretch = "h", mathclass = "botaccent" } )
+addextra(0xFE3B5, { description="EXTENSIBLE OF 0x03B5", unicodeslot=0xFE3B5, mathextensible = "r", mathstretch = "h", mathclass = "botaccent" } )
-virtualcharacters[0xFE3DF] = function(data) return data.target.characters[0x23DF] end
-virtualcharacters[0xFE3DD] = function(data) return data.target.characters[0x23DD] end
-virtualcharacters[0xFE3B5] = function(data) return data.target.characters[0x23B5] end
+virtualcharacters[0xFE3DF] = function(data) local c = data.target.characters[0x23DF] if c then c.unicode = 0x23DF return c end end
+virtualcharacters[0xFE3DD] = function(data) local c = data.target.characters[0x23DD] if c then c.unicode = 0x23DD return c end end
+virtualcharacters[0xFE3B5] = function(data) local c = data.target.characters[0x23B5] if c then c.unicode = 0x23B5 return c end end
-- todo: add some more .. numbers might change
-addextra(0xFE302, { description="EXTENSIBLE OF 0x0302", unicodeslot=0xFE302, mathstretch = "h" } )
-addextra(0xFE303, { description="EXTENSIBLE OF 0x0303", unicodeslot=0xFE303, mathstretch = "h" } )
+addextra(0xFE302, { description="EXTENSIBLE OF 0x0302", unicodeslot=0xFE302, mathstretch = "h", mathclass = "topaccent" } )
+addextra(0xFE303, { description="EXTENSIBLE OF 0x0303", unicodeslot=0xFE303, mathstretch = "h", mathclass = "topaccent" } )
local function smashed(data,unicode,private)
local target = data.target
local height = target.parameters.xheight / 2
- local c, done = accent_to_extensible(target,private,data.original,unicode,height,0,nil,-height)
+ local c, done = accent_to_extensible(target,private,data.original,unicode,height,0,nil,-height,unicode)
if done then
c.top_accent = nil -- or maybe also all the others
end
@@ -467,15 +467,21 @@ virtualcharacters[0xFE302] = function(data) return smashed(data,0x0302,0xFE302)
virtualcharacters[0xFE303] = function(data) return smashed(data,0x0303,0xFE303) end
-- another crazy hack .. doesn't work as we define scrscr first .. we now have smaller
--- primes so we have smaller primes for the moment, big ones will become an option
+-- primes so we have smaller primes for the moment, big ones will become an option ..
+-- these primes in fonts are a real mess .. kind of a dead end, so don't wonder about
+-- the values below
+
+-- todo: check tounicodes
local function smashed(data,unicode,optional)
local oldchar = data.characters[unicode]
if oldchar then
- local height = 1.2 * data.target.parameters.xheight
+ local xheight = data.target.parameters.xheight
+ local height = 1.2 * xheight
+ local shift = oldchar.height - height
local newchar = {
commands = {
- { "down", oldchar.height - height },
+ { "down", shift },
{ "char", unicode },
},
height = height,
@@ -487,6 +493,30 @@ local function smashed(data,unicode,optional)
end
end
+-- -- relocate all but less flexible so not used .. instead some noad hackery plus
+-- -- the above
+--
+-- local function smashed(data,unicode,optional)
+-- local oldchar = data.characters[unicode]
+-- if oldchar then
+-- local xheight = data.target.parameters.xheight
+-- local height = oldchar.height
+-- local shift = oldchar.height < 1.5*xheight and -(1.8*xheight-height) or 0
+-- local newchar = {
+-- commands = {
+-- { "down", shift },
+-- { "char", unicode },
+-- },
+-- unicode = unicode,
+-- height = height,
+-- width = oldchar.width,
+-- }
+-- return newchar
+-- elseif not optional then
+-- report_fallbacks("missing %U prime in font %a",unicode,data.target.properties.fullname)
+-- end
+-- end
+
addextra(0xFE932, { description="SMASHED PRIME 0x02032", unicodeslot=0xFE932 } )
addextra(0xFE933, { description="SMASHED PRIME 0x02033", unicodeslot=0xFE933 } )
addextra(0xFE934, { description="SMASHED PRIME 0x02034", unicodeslot=0xFE934 } )
@@ -520,7 +550,7 @@ local function actuarian(data)
-- todo: add alttext
-- compromise: lm has large hooks e.g. \actuarial{a}
width = basewidth + 4 * linewidth,
- tounicode = tounicode16(0x20E7),
+ unicode = 0x20E7,
commands = {
{ "right", 2 * linewidth },
{ "down", - baseheight - 3 * linewidth },
diff --git a/Master/texmf-dist/tex/context/base/math-frc.lua b/Master/texmf-dist/tex/context/base/math-frc.lua
index 4f531a5307a..639edc94ba3 100644
--- a/Master/texmf-dist/tex/context/base/math-frc.lua
+++ b/Master/texmf-dist/tex/context/base/math-frc.lua
@@ -25,13 +25,13 @@ table.setmetatableindex(resolved, function(t,k)
return v
end)
-local normalatop = context.normalatop
-local normalover = context.normalover
+local ctx_normalatop = context.normalatop
+local ctx_normalover = context.normalover
-function commands.math_frac(how,left,right,width)
- if how == v_no then
+local function mathfraction(how,left,right,width) -- of course we could use the scanners directly here which
+ if how == v_no then -- is faster but also less abstract ... maybe some day
if left == 0x002E and right == 0x002E then
- normalatop()
+ ctx_normalatop()
else
context("\\atopwithdelims%s%s",resolved[left],resolved[right])
end
@@ -43,9 +43,15 @@ function commands.math_frac(how,left,right,width)
end
else -- v_auto
if left == 0x002E and right == 0x002E then
- normalover()
+ ctx_normalover()
else
context("\\overwithdelims%s%s",resolved[left],resolved[right])
end
end
end
+
+interfaces.implement {
+ name = "mathfraction",
+ actions = mathfraction,
+ arguments = { "string", "number", "number", "dimen" }
+}
diff --git a/Master/texmf-dist/tex/context/base/math-frc.mkiv b/Master/texmf-dist/tex/context/base/math-frc.mkiv
index 7032c665b08..cbe342b6608 100644
--- a/Master/texmf-dist/tex/context/base/math-frc.mkiv
+++ b/Master/texmf-dist/tex/context/base/math-frc.mkiv
@@ -15,7 +15,14 @@
\unprotect
-%D todo: struts ... depends on demand
+%D I need to check it all again as there was a bug in luatex with dimensions that could
+%D resulted in side effects that made me mess with spacing.
+
+\unexpanded\def\topstrut{\vrule\s!width\zeropoint\s!height\strutht\s!depth\zeropoint\relax}
+\unexpanded\def\botstrut{\vrule\s!width\zeropoint\s!height\zeropoint\s!depth\strutdp\relax}
+
+\unexpanded\def\mathtopstrut{\setbox\scratchbox\mathstylehbox{(}\vrule\s!width\zeropoint\s!height\ht\scratchbox\s!depth\zeropoint\relax}
+\unexpanded\def\mathbotstrut{\setbox\scratchbox\mathstylehbox{(}\vrule\s!width\zeropoint\s!height\zeropoint\s!depth\dp\scratchbox\relax}
%D This module is reimplemented in \MKIV\ style.
@@ -106,6 +113,7 @@
\c!rulethickness=.25\exheight,
\c!left=0x2E,
\c!right=0x2E,
+ \c!strut=\v!yes,
\c!topdistance=,
\c!bottomdistance=,
\c!rule=\v!auto]
@@ -122,6 +130,8 @@
\math_fraction_set_distance
\to \everymathematics
+% why only displaystyle .. a bit weak
+
\unexpanded\def\math_fraction_set_distance_top
{\Umathfractionnumup \displaystyle\m_math_fraction_distance_top
\relax}
@@ -157,13 +167,43 @@
% So far for control.
+\installcorenamespace{mathfractionstrut}
+
+\setvalue{\??mathfractionstrut\v!yes}%
+ {\let\m_fractions_strut_top\mathstrut
+ \let\m_fractions_strut_bot\mathstrut}
+
+\setvalue{\??mathfractionstrut\v!math}%
+ {\let\m_fractions_strut_top\mathstrut
+ \let\m_fractions_strut_bot\mathstrut}
+
+\setvalue{\??mathfractionstrut\v!no}%
+ {\let\m_fractions_strut_top\relax
+ \let\m_fractions_strut_bot\relax}
+
+\setvalue{\??mathfractionstrut\v!tight}%
+ {\let\m_fractions_strut_top\mathbotstrut % indeed swapped name
+ \let\m_fractions_strut_bot\mathtopstrut} % indeed swapped name
+
+\let\m_fractions_strut_top\relax
+\let\m_fractions_strut_bot\relax
+
\newdimen\d_math_fraction_margin
\unexpanded\def\math_frac#1%
{\begingroup
\edef\currentmathfraction{#1}%
+ %
\d_math_fraction_margin\mathfractionparameter\c!margin
+ %
\edef\p_math_fractions_color{\mathfractionparameter\c!color}%
+ %
+ \edef\p_math_fractions_strut{\mathfractionparameter\c!strut}%
+ \csname
+ \??mathfractionstrut
+ \ifcsname\??mathfractionstrut\p_math_fractions_strut\endcsname\p_math_fractions_strut\else\v!no\fi
+ \endcsname
+ %
\ifx\p_math_fractions_color\empty
\expandafter\math_frac_normal
\else
@@ -181,18 +221,17 @@
% we use utfchar anyway so we can as well do all at the lua end
\def\math_frac_command
- {\ctxcommand{math_frac(%
- "\mathfractionparameter\c!rule",%
- \number\mathfractionparameter\c!left,%
- \number\mathfractionparameter\c!right,%
- \number\dimexpr\mathfractionparameter\c!rulethickness%
- )}}
-
-% Having a \withmarginornot{#1}{#2} makes not much sense nor do
-% 4 tests or 4 redundant kerns (longer node lists plus possible
-% interference). A split in normal and margin also makes testing
-% easier. When left and right margins are needed we might merge
-% the variants again. After all, these are not real installers.
+ {\clf_mathfraction
+ {\mathfractionparameter\c!rule}%
+ \mathfractionparameter\c!left\space
+ \mathfractionparameter\c!right\space
+ \dimexpr\mathfractionparameter\c!rulethickness\relax
+ \relax}
+
+% Having a \withmarginornot{#1}{#2} makes not much sense nor do 4 tests or 4 redundant
+% kerns (longer node lists plus possible interference). A split in normal and margin
+% also makes testing easier. When left and right margins are needed we might merge the
+% variants again. After all, these are not real installers.
\setvalue{\??mathfractionalternative\v!inner}%
{\ifcase\d_math_fraction_margin
@@ -201,24 +240,6 @@
\expandafter\math_fraction_inner_margin
\fi}
-\def\math_fraction_inner_normal#1#2%
- {\Ustack{%
- {\usemathstyleparameter\mathfractionparameter{#1}}% we should store this one
- \math_frac_command
- {\usemathstyleparameter\mathfractionparameter{#2}}% and reuse it here
- }\endgroup}
-
-\def\math_fraction_inner_margin#1#2%
- {\Ustack{%
- {\kern\d_math_fraction_margin
- \usemathstyleparameter\mathfractionparameter{#1}% we should store this one
- \kern\d_math_fraction_margin}%
- \math_frac_command
- {\kern\d_math_fraction_margin
- \usemathstyleparameter\mathfractionparameter{#2}% and reuse it here
- \kern\d_math_fraction_margin}%
- }\endgroup}
-
\setvalue{\??mathfractionalternative\v!outer}%
{\ifcase\d_math_fraction_margin
\expandafter\math_fraction_outer_normal
@@ -226,21 +247,84 @@
\expandafter\math_fraction_outer_margin
\fi}
+\setvalue{\??mathfractionalternative\v!both}%
+ {\ifcase\d_math_fraction_margin
+ \expandafter\math_fraction_both_normal
+ \else
+ \expandafter\math_fraction_both_margin
+ \fi}
+
+% todo: store first state and reuse second time
+
+\def\math_fraction_inner_normal#1#2%
+ {\Ustack{%
+ {%
+ {\usemathstyleparameter\mathfractionparameter{\m_fractions_strut_top#1}}%
+ \math_frac_command
+ {\usemathstyleparameter\mathfractionparameter{\m_fractions_strut_bot#2}}%
+ }%
+ }\endgroup}
+
\def\math_fraction_outer_normal#1#2%
{\Ustack{%
\usemathstyleparameter\mathfractionparameter
- {{#1}\math_frac_command{#2}}%
+ {%
+ {\m_fractions_strut_top#1}%
+ \math_frac_command
+ {\m_fractions_strut_bot#2}%
+ }%
+ }\endgroup}
+
+\def\math_fraction_both_normal#1#2%
+ {\Ustack{%
+ \usemathstyleparameter\mathfractionparameter
+ {%
+ {\usemathstyleparameter\mathfractionparameter\m_fractions_strut_top#1}%
+ \math_frac_command
+ {\usemathstyleparameter\mathfractionparameter\m_fractions_strut_bot#2}%
+ }%
+ }\endgroup}
+
+\def\math_fraction_inner_margin#1#2%
+ {\Ustack{%
+ {%
+ {\kern\d_math_fraction_margin
+ \usemathstyleparameter\mathfractionparameter{\m_fractions_strut_top#1}%
+ \kern\d_math_fraction_margin}%
+ \math_frac_command
+ {\kern\d_math_fraction_margin
+ \usemathstyleparameter\mathfractionparameter{\m_fractions_strut_bot#2}%
+ \kern\d_math_fraction_margin}%
+ }%
}\endgroup}
\def\math_fraction_outer_margin#1#2%
{\Ustack{%
\usemathstyleparameter\mathfractionparameter
- {{\kern\d_math_fraction_margin#1\kern\d_math_fraction_margin}%
- \math_frac_command
- {\kern\d_math_fraction_margin#2\kern\d_math_fraction_margin}}%
+ {%
+ {\kern\d_math_fraction_margin
+ \m_fractions_strut_top#1%
+ \kern\d_math_fraction_margin}%
+ \math_frac_command
+ {\kern\d_math_fraction_margin
+ \m_fractions_strut_bot#2%
+ \kern\d_math_fraction_margin}%
+ }%
}\endgroup}
-\definemathfraction[frac][\c!mathstyle=]
+\def\math_fraction_both_margin#1#2%
+ {\Ustack{%
+ \usemathstyleparameter\mathfractionparameter
+ {%
+ {\kern\d_math_fraction_margin
+ \usemathstyleparameter\mathfractionparameter\m_fractions_strut_top#1%
+ \kern\d_math_fraction_margin}%
+ \math_frac_command
+ {\kern\d_math_fraction_margin
+ \usemathstyleparameter\mathfractionparameter\m_fractions_strut_bot#2%
+ \kern\d_math_fraction_margin}%
+ }%
+ }\endgroup}
\unexpanded\def\xfrac {\begingroup\let\xfrac\xxfrac\math_frac_alternative\scriptstyle}
\unexpanded\def\xxfrac{\begingroup \math_frac_alternative\scriptscriptstyle}
@@ -251,6 +335,40 @@
{\begingroup
\math_frac_alternative\scriptscriptstyle{#1}{\raise.25\exheight\hbox{$\scriptscriptstyle#2$}}}
+%D Spacing:
+
+\unexpanded\def\nomathfractiongaps {\normalexpanded{\math_no_fraction_gaps \triggermathstyle\mathstyle}} % maybe collect settings
+\unexpanded\def\overlaymathfractiongaps{\normalexpanded{\math_overlay_fraction_gaps\triggermathstyle\mathstyle}} % maybe collect settings
+
+\unexpanded\def\math_no_fraction_gaps#1%
+ {\Umathfractionnumup #1\zeropoint
+ \Umathfractiondenomdown#1\zeropoint}
+
+\unexpanded\def\math_overlay_fraction_gaps#1%
+ {\Umathfractionnumup #1\zeropoint
+ \Umathfractionnumvgap #1\zeropoint
+ %Umathfractionrule #1\zeropoint
+ \Umathfractiondenomvgap#1\zeropoint
+ \Umathfractiondenomdown#1\zeropoint}
+
+\installcorenamespace{mathfractiondistance}
+
+\letvalue{\??mathfractiondistance\v!none }\nomathfractiongaps
+\letvalue{\??mathfractiondistance\v!no }\nomathfractiongaps
+\letvalue{\??mathfractiondistance\v!overlay}\overlaymathfractiongaps
+
+\setupmathfractions
+ [\c!distance=\v!none]
+
+\appendtoks
+ \edef\p_distance{\rootmathfractionparameter\c!distance}%
+ \ifx\p_distance\empty\else
+ \ifcsname\??mathfractiondistance\p_distance\endcsname
+ \csname\??mathfractiondistance\p_distance\endcsname
+ \fi
+ \fi
+\to \everymathematics
+
%D \macros
%D {dfrac, tfrac, frac, dbinom, tbinom, binom}
%D
@@ -277,9 +395,36 @@
% \unexpanded\def\dfrac #1#2{{\displaystyle {{#1}\normalover {#2}}}}
% \unexpanded\def\tfrac #1#2{{\textstyle {{#1}\normalover {#2}}}}
-\definemathfraction[dfrac][\c!alternative=\v!outer,\c!mathstyle=\s!display]
-\definemathfraction[tfrac][\c!alternative=\v!outer,\c!mathstyle=\s!text]
-\definemathfraction[sfrac][\c!alternative=\v!outer,\c!mathstyle=\s!script]
+\definemathfraction[i:frac] [\c!alternative=\v!inner,\c!mathstyle=] % was script and then small but nothing needed
+\definemathfraction[i:tfrac][\c!alternative=\v!inner,\c!mathstyle=\s!text] % was script (before luatex fix)
+\definemathfraction[i:sfrac][\c!alternative=\v!inner,\c!mathstyle=\s!scriptscript]
+\definemathfraction[i:dfrac][\c!alternative=\v!inner,\c!mathstyle=\s!display]
+
+\definemathfraction[d:frac] [\c!alternative=\v!inner,\c!mathstyle=\s!cramped] % was cramped,text
+\definemathfraction[d:tfrac][\c!alternative=\v!both ,\c!mathstyle={\s!cramped,\s!text}] % was cramped,script (before luatex fix)
+\definemathfraction[d:sfrac][\c!alternative=\v!both ,\c!mathstyle={\s!cramped,\s!scriptscript}]
+\definemathfraction[d:dfrac][\c!alternative=\v!inner,\c!mathstyle=\s!display]
+
+%D \unexpanded\def\ShowMathFractions#1#2%
+%D {\dontleavehmode
+%D \begingroup
+%D \showmathstruts
+%D \mathematics{x+\tfrac{#1}{#2}+1+\frac{#1}{#2}+2+\sfrac{#1}{#2}+g}%
+%D \endgroup}
+%D
+%D The default \type {tfrac}, \type {frac} and \type \sfrac} look like this:
+%D
+%D \blank
+%D \ShowMathFractions{a}{a}\par
+%D \ShowMathFractions{1}{x}\par
+%D \ShowMathFractions{a}{b}\par
+%D \ShowMathFractions{1}{b}\par
+%D \blank
+
+\unexpanded\def\frac {\csname\inlineordisplaymath id:frac\endcsname}
+\unexpanded\def\tfrac{\csname\inlineordisplaymath id:tfrac\endcsname}
+\unexpanded\def\sfrac{\csname\inlineordisplaymath id:sfrac\endcsname}
+\unexpanded\def\dfrac{\csname\inlineordisplaymath id:dfrac\endcsname}
% \definemathfraction[ddfrac][\c!mathstyle=\s!display]
% \definemathfraction[ttfrac][\c!mathstyle=\s!text]
@@ -319,7 +464,7 @@
%D \getbuffer
\unexpanded\def\cfrac
- {\doifnextoptionalcselse\math_cfrac_yes\math_cfrac_nop}
+ {\doifelsenextoptionalcs\math_cfrac_yes\math_cfrac_nop}
\def\math_cfrac_nop {\math_cfrac_indeed[cc]}
\def\math_cfrac_yes[#1]{\math_cfrac_indeed[#1cc]}
@@ -364,6 +509,11 @@
\unexpanded\def\splitdfrac#1#2%
{{\displaystyle{{ #1\quad\hfill}\normalabove\zeropoint{ \hfill\quad\mathstrut#2}}}}
+%D For testing:
+
+% \unexpanded\def\ShowMathFractions#1#2%
+% {\mathematics{x+\tfrac{#1}{#2}+1+\frac{#1}{#2}+2+\sfrac{#1}{#2}+g}}
+
\protect \endinput
% I have no clue what \mthfrac and \mthsqrt are supposed to do but
diff --git a/Master/texmf-dist/tex/context/base/math-ini.lua b/Master/texmf-dist/tex/context/base/math-ini.lua
index 9772ce5389d..88159e10746 100644
--- a/Master/texmf-dist/tex/context/base/math-ini.lua
+++ b/Master/texmf-dist/tex/context/base/math-ini.lua
@@ -18,30 +18,33 @@ if not modules then modules = { } end modules ['math-ini'] = {
local formatters, find = string.formatters, string.find
local utfchar, utfbyte, utflength = utf.char, utf.byte, utf.length
local floor = math.floor
+local toboolean = toboolean
-local context = context
-local commands = commands
+local context = context
+local commands = commands
+local implement = interfaces.implement
-local context_sprint = context.sprint
------ context_fprint = context.fprint -- a bit inefficient
+local context_sprint = context.sprint
+----- context_fprint = context.fprint -- a bit inefficient
+local ctx_doifelsesomething = commands.doifelsesomething
-local trace_defining = false trackers.register("math.defining", function(v) trace_defining = v end)
+local trace_defining = false trackers.register("math.defining", function(v) trace_defining = v end)
-local report_math = logs.reporter("mathematics","initializing")
+local report_math = logs.reporter("mathematics","initializing")
-mathematics = mathematics or { }
-local mathematics = mathematics
+mathematics = mathematics or { }
+local mathematics = mathematics
-mathematics.extrabase = 0xFE000 -- here we push some virtuals
-mathematics.privatebase = 0xFF000 -- here we push the ex
+mathematics.extrabase = 0xFE000 -- here we push some virtuals
+mathematics.privatebase = 0xFF000 -- here we push the ex
-local unsetvalue = attributes.unsetvalue
-local allocate = utilities.storage.allocate
-local chardata = characters.data
+local unsetvalue = attributes.unsetvalue
+local allocate = utilities.storage.allocate
+local chardata = characters.data
-local texsetattribute = tex.setattribute
-local setmathcode = tex.setmathcode
-local setdelcode = tex.setdelcode
+local texsetattribute = tex.setattribute
+local setmathcode = tex.setmathcode
+local setdelcode = tex.setdelcode
local families = allocate {
mr = 0,
@@ -464,7 +467,7 @@ end
local function utfmathfiller(chr, default)
local cd = somechar[chr]
- local cmd = cd and (cd.mathfiller or cd.mathname)
+ local cmd = cd and cd.mathfiller -- or cd.mathname
return cmd or default or ""
end
@@ -476,20 +479,72 @@ mathematics.utfmathaccent = utfmathaccent
-- interfaced
-function commands.utfmathclass (...) context(utfmathclass (...)) end
-function commands.utfmathstretch(...) context(utfmathstretch(...)) end
-function commands.utfmathcommand(...) context(utfmathcommand(...)) end
-function commands.utfmathfiller (...) context(utfmathfiller (...)) end
+implement {
+ name = "utfmathclass",
+ actions = { utfmathclass, context },
+ arguments = "string"
+}
-function commands.doifelseutfmathaccent(chr,asked)
- commands.doifelse(utfmathaccent(chr,nil,asked))
-end
+implement {
+ name = "utfmathstretch",
+ actions = { utfmathstretch, context },
+ arguments = "string"
+}
+
+implement {
+ name = "utfmathcommand",
+ actions = { utfmathcommand, context },
+ arguments = "string"
+}
+
+implement {
+ name = "utfmathfiller",
+ actions = { utfmathfiller, context },
+ arguments = "string"
+}
-function commands.utfmathcommandabove(asked) context(utfmathcommand(asked,nil,"topaccent","over" )) end
-function commands.utfmathcommandbelow(asked) context(utfmathcommand(asked,nil,"botaccent","under")) end
+implement {
+ name = "utfmathcommandabove",
+ actions = { utfmathcommand, context },
+ arguments = { "string", false, "'topaccent'","'over'" }
+}
-function commands.doifelseutfmathabove(chr) commands.doifelse(utfmathaccent(chr,nil,"topaccent","over" )) end
-function commands.doifelseutfmathbelow(chr) commands.doifelse(utfmathaccent(chr,nil,"botaccent","under")) end
+implement {
+ name = "utfmathcommandbelow",
+ actions = { utfmathcommand, context },
+ arguments = { "string", false, "'botaccent'","'under'" }
+}
+implement {
+ name = "utfmathcommandfiller",
+ actions = { utfmathfiller, context },
+ arguments = "string"
+}
+
+-- todo: make this a helper:
+
+implement {
+ name = "doifelseutfmathabove",
+ actions = { utfmathaccent, ctx_doifelsesomething },
+ arguments = { "string", false, "'topaccent'", "'over'" }
+}
+
+implement {
+ name = "doifelseutfmathbelow",
+ actions = { utfmathaccent, ctx_doifelsesomething },
+ arguments = { "string", false, "'botaccent'", "'under'" }
+}
+
+implement {
+ name = "doifelseutfmathaccent",
+ actions = { utfmathaccent, ctx_doifelsesomething },
+ arguments = "string",
+}
+
+implement {
+ name = "doifelseutfmathfiller",
+ actions = { utfmathfiller, ctx_doifelsesomething },
+ arguments = "string",
+}
-- helpers
--
@@ -599,30 +654,34 @@ local noffunctions = 1000 -- offset
categories.functions = functions
-function commands.taggedmathfunction(tag,label,apply)
- local delta = apply and 1000 or 0
- if label then
- local n = functions[tag]
- if not n then
- noffunctions = noffunctions + 1
- functions[noffunctions] = tag
- functions[tag] = noffunctions
- texsetattribute(a_mathcategory,noffunctions + delta)
+implement {
+ name = "taggedmathfunction",
+ arguments = { "string", "string", "string" },
+ actions = function(tag,label,apply)
+ local delta = toboolean(apply) and 1000 or 0
+ if toboolean(label) then
+ local n = functions[tag]
+ if not n then
+ noffunctions = noffunctions + 1
+ functions[noffunctions] = tag
+ functions[tag] = noffunctions
+ texsetattribute(a_mathcategory,noffunctions + delta)
+ else
+ texsetattribute(a_mathcategory,n + delta)
+ end
+ context.mathlabeltext(tag)
else
- texsetattribute(a_mathcategory,n + delta)
+ texsetattribute(a_mathcategory,1000 + delta)
+ context(tag)
end
- context.mathlabeltext(tag)
- else
- texsetattribute(a_mathcategory,1000 + delta)
- context(tag)
end
-end
+}
--
local list
-function commands.resetmathattributes()
+function mathematics.resetattributes()
if not list then
list = { }
for k, v in next, attributes.numbers do
@@ -635,3 +694,16 @@ function commands.resetmathattributes()
texsetattribute(list[i],unsetvalue)
end
end
+
+implement {
+ name = "resetmathattributes",
+ actions = mathematics.resetattributes
+}
+
+-- weird to do this here but it's a side affect of math anyway
+
+interfaces.implement {
+ name = "enableasciimode",
+ onlyonce = true,
+ actions = resolvers.macros.enablecomment,
+}
diff --git a/Master/texmf-dist/tex/context/base/math-ini.mkiv b/Master/texmf-dist/tex/context/base/math-ini.mkiv
index adf252d9526..2d6090c03b9 100644
--- a/Master/texmf-dist/tex/context/base/math-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/math-ini.mkiv
@@ -13,6 +13,18 @@
\writestatus{loading}{ConTeXt Math Macros / Initializations}
+% Todo in luatex maincontrol.w: also accept a number here:
+%
+% case set_math_param_cmd:
+% p = cur_chr;
+% get_token();
+% if (cur_cmd != math_style_cmd) {
+%
+% plus two new math styles: larger/smaller
+%
+% \unexpanded\def\Umathshow#1%
+% {\hbox{\infofont(\string#1:\the#1\textstyle,\the#1\scriptstyle,\the#1\scriptscriptstyle)}}
+
%D This module provides namespaces for math fonts, thereby permitting mixed usage of
%D math fonts. Although not strictly needed, we also provide a family name mapping
%D mechanism as used in the (original) AMS math definition files, but here these
@@ -26,6 +38,15 @@
%D restore a changed mathstyle so best avoid that one. However, there are cases where
%D we really need to use such grouping.
+% Weird, these fail, maybe amp is solved in a later state from char noads (needs a
+% fix in luatex):
+%
+% $\char"26$
+% $\a$
+% $\string&$
+
+% mathop applied to characters centers it vertically
+
\unprotect
%D We move these definitions into the format:
@@ -80,7 +101,35 @@
\setnewconstant\defaultmathfamily \zerocount % 255
-\unexpanded\def\resetmathattributes{\ctxcommand{resetmathattributes()}}
+\unexpanded\def\resetmathattributes{\clf_resetmathattributes}
+
+% handy
+
+\newconditional\indisplaymath
+
+\appendtoks
+ \setfalse\indisplaymath
+\to \everymath
+
+\appendtoks
+ \settrue\indisplaymath
+\to \everydisplay
+
+\def\inlineordisplaymath{\ifconditional\indisplaymath\expandafter\secondoftwoarguments\else\expandafter\firstoftwoarguments\fi}
+
+\unexpanded\def\forcedisplaymath
+ {\ifmmode
+ \displaystyle
+ \settrue\indisplaymath
+ \fi}
+
+\unexpanded\def\startforceddisplaymath
+ {\startimath
+ \displaystyle
+ \settrue\indisplaymath}
+
+\unexpanded\def\stopforceddisplaymath
+ {\stopimath}
% \unexpanded\def\rawmathcharacter#1% slow but only for tracing
% {\begingroup
@@ -94,9 +143,9 @@
\unexpanded\def\rawmathematics#1% slow but only for tracing
{\begingroup
\ifmmode
- \resetmathattributes#1%
+ \clf_resetmathattributes#1%
\else
- \startimath\resetmathattributes#1\stopimath
+ \startimath\clf_resetmathattributes#1\stopimath
\fi
\endgroup}
@@ -117,7 +166,7 @@
\installswitchcommandhandler \??mathematics {mathematics} \??mathematics
\unexpanded\def\startmathematics % no grouping, if ever then also an optional second
- {\doifnextoptionalcselse\math_mathematics_start_yes\math_mathematics_start_nop}
+ {\doifelsenextoptionalcs\math_mathematics_start_yes\math_mathematics_start_nop}
\unexpanded\def\math_mathematics_start_yes[#1]%
{\pushmacro\currentmathematics
@@ -143,14 +192,14 @@
% these commands are semi-public but should not be used directly (lua names wil change)
-\unexpanded\def\math_set_attribute #1#2{\ifmmode\ctxcommand{setmathattribute("#1","#2")}\fi}
-\unexpanded\def\math_set_alphabet #1{\ifmmode\ctxcommand{setmathalphabet("#1")}\fi}
-\unexpanded\def\math_set_font_style #1{\ifmmode\ctxcommand{setmathstyle("#1")}\fi}
-\unexpanded\def\math_set_font_alternate#1{\ifmmode\ctxcommand{setmathalternate(\number\defaultmathfamily,"#1")}\fi}
+\unexpanded\def\math_set_attribute #1#2{\ifmmode\clf_setmathattribute{#1}{#2}\fi}
+\unexpanded\def\math_set_alphabet #1{\ifmmode\clf_setmathalphabet{#1}\fi}
+\unexpanded\def\math_set_font_style #1{\ifmmode\clf_setmathstyle{#1}\fi}
+\unexpanded\def\math_set_font_alternate#1{\ifmmode\clf_setmathalternate\defaultmathfamily{#1}\fi}
\installcorenamespace{mathstylealternate} % might become a setuphandler
-\unexpanded\def\math_set_font_style_alterternate#1%
+\unexpanded\def\math_set_font_style_alternate#1%
{\ifcsname\??mathstylealternate\fontclass:#1\endcsname
\expandafter\math_set_font_alternate\csname\??mathstylealternate\fontclass:#1\endcsname
\else\ifcsname\??mathstylealternate#1\endcsname
@@ -169,31 +218,31 @@
\unexpanded\def\mathaltcal{\math_set_font_alternate{cal}\cal} % ss01 in xits
-\let\setmathattribute \math_set_attribute
-\let\setmathalphabet \math_set_alphabet
-\let\setmathfontstyle \math_set_font_style
-\let\setmathfontalternate \math_set_font_alternate
-\let\setmathfontstylealterternate\math_set_font_style_alterternate
+\let\setmathattribute \math_set_attribute
+\let\setmathalphabet \math_set_alphabet
+\let\setmathfontstyle \math_set_font_style
+\let\setmathfontalternate \math_set_font_alternate
+\let\setmathfontstylealternate\math_set_font_style_alternate
-\let\mathalternate \math_set_font_alternate % obsolete
+\let\mathalternate \math_set_font_alternate % obsolete
-\unexpanded\def\mathupright {\math_set_attribute\s!regular\s!tf\math_set_font_style_alterternate\s!tf}
-\unexpanded\def\mathdefault {\math_set_attribute\s!regular\s!it\math_set_font_style_alterternate\s!it}
-\unexpanded\def\mathscript {\math_set_alphabet \s!script \math_set_font_style_alterternate\s!script}
-\unexpanded\def\mathfraktur {\math_set_alphabet \s!fraktur \math_set_font_style_alterternate\s!fraktur}
-\unexpanded\def\mathblackboard{\math_set_alphabet \s!blackboard \math_set_font_style_alterternate\s!blackboard}
+\unexpanded\def\mathupright {\math_set_attribute\s!regular\s!tf\math_set_font_style_alternate\s!tf}
+\unexpanded\def\mathdefault {\math_set_attribute\s!regular\s!it\math_set_font_style_alternate\s!it}
+\unexpanded\def\mathscript {\math_set_alphabet \s!script \math_set_font_style_alternate\s!script}
+\unexpanded\def\mathfraktur {\math_set_alphabet \s!fraktur \math_set_font_style_alternate\s!fraktur}
+\unexpanded\def\mathblackboard{\math_set_alphabet \s!blackboard \math_set_font_style_alternate\s!blackboard}
-\unexpanded\def\mathrm {\math_set_attribute\s!rm\s!tf \math_set_font_style_alterternate\s!tf}
-\unexpanded\def\mathss {\math_set_attribute\s!ss\s!tf \math_set_font_style_alterternate\s!tf}
-\unexpanded\def\mathtt {\math_set_attribute\s!tt\s!tf \math_set_font_style_alterternate\s!tf}
+\unexpanded\def\mathrm {\math_set_attribute\s!rm\s!tf \math_set_font_style_alternate\s!tf}
+\unexpanded\def\mathss {\math_set_attribute\s!ss\s!tf \math_set_font_style_alternate\s!tf}
+\unexpanded\def\mathtt {\math_set_attribute\s!tt\s!tf \math_set_font_style_alternate\s!tf}
-\unexpanded\def\mathtf {\math_set_font_style\s!tf \math_set_font_style_alterternate\s!tf}
-\unexpanded\def\mathsl {\math_set_font_style\s!it \math_set_font_style_alterternate\s!it} % no sl
-\unexpanded\def\mathit {\math_set_font_style\s!it \math_set_font_style_alterternate\s!it}
+\unexpanded\def\mathtf {\math_set_font_style\s!tf \math_set_font_style_alternate\s!tf}
+\unexpanded\def\mathsl {\math_set_font_style\s!it \math_set_font_style_alternate\s!it} % no sl
+\unexpanded\def\mathit {\math_set_font_style\s!it \math_set_font_style_alternate\s!it}
-\unexpanded\def\mathbf {\math_set_font_style\s!bf \math_set_font_style_alterternate\s!bf}
-\unexpanded\def\mathbs {\math_set_font_style\s!bi \math_set_font_style_alterternate\s!bi} % no sl
-\unexpanded\def\mathbi {\math_set_font_style\s!bi \math_set_font_style_alterternate\s!bi}
+\unexpanded\def\mathbf {\math_set_font_style\s!bf \math_set_font_style_alternate\s!bf}
+\unexpanded\def\mathbs {\math_set_font_style\s!bi \math_set_font_style_alternate\s!bi} % no sl
+\unexpanded\def\mathbi {\math_set_font_style\s!bi \math_set_font_style_alternate\s!bi}
\let\tfmath\mathtf % maybe a grouped command
\let\slmath\mathsl
@@ -216,12 +265,12 @@
\unexpanded\def\mathfrak#1{{\mathfraktur #1}} % for AMS compatibility
\unexpanded\def\mathbb #1{{\mathblackboard#1}} % for AMS compatibility
-\let\normaltf\tf \unexpanded\def\tf{\ifmmode\mathtf\else\normaltf\fi}
-\let\normalbf\bf \unexpanded\def\bf{\ifmmode\mathbf\else\normalbf\fi}
-\let\normalit\it \unexpanded\def\it{\ifmmode\mathit\else\normalit\fi}
-\let\normalsl\sl \unexpanded\def\sl{\ifmmode\mathsl\else\normalsl\fi}
-\let\normalbi\bi \unexpanded\def\bi{\ifmmode\mathbi\else\normalbi\fi}
-\let\normalbs\bs \unexpanded\def\bs{\ifmmode\mathbs\else\normalbs\fi}
+\ifdefined\normaltf\else\let\normaltf\tf\fi \unexpanded\def\tf{\ifmmode\mathtf\else\normaltf\fi}
+\ifdefined\normalbf\else\let\normalbf\bf\fi \unexpanded\def\bf{\ifmmode\mathbf\else\normalbf\fi}
+\ifdefined\normalit\else\let\normalit\it\fi \unexpanded\def\it{\ifmmode\mathit\else\normalit\fi}
+\ifdefined\normalsl\else\let\normalsl\sl\fi \unexpanded\def\sl{\ifmmode\mathsl\else\normalsl\fi}
+\ifdefined\normalbi\else\let\normalbi\bi\fi \unexpanded\def\bi{\ifmmode\mathbi\else\normalbi\fi}
+\ifdefined\normalbs\else\let\normalbs\bs\fi \unexpanded\def\bs{\ifmmode\mathbs\else\normalbs\fi}
\let\normalrm\rm \unexpanded\def\rm{\ifmmode\mathrm\else\normalrm\fi}
\let\normalss\ss \unexpanded\def\ss{\ifmmode\mathss\else\normalss\fi}
@@ -231,9 +280,9 @@
\ifdefined\mb \else \let\mb\relax \fi
% 1: $\setmathattribute{ss}{bf}3$
-% 2: $\setmathattribute{ss}{bf}\setmathfontstylealterternate{bf}3$
+% 2: $\setmathattribute{ss}{bf}\setmathfontstylealternate{bf}3$
% 3: $\setmathattribute{ss}{bf}\setmathfontstyle{bf}3$
-% 4: $\setmathattribute{ss}{bf}\setmathfontstyle{bf}\setmathfontstylealterternate{bf}3$
+% 4: $\setmathattribute{ss}{bf}\setmathfontstyle{bf}\setmathfontstylealternate{bf}3$
% 5: $e=mc^2 \quad \mb e=mc^2$
\prependtoks
@@ -260,7 +309,7 @@
\newcount\c_math_renderings_attribute
\appendtoks
- \c_math_renderings_attribute\ctxcommand{mathrenderset("\mathematicsparameter\c!symbolset")}\relax
+ \c_math_renderings_attribute\clf_mathrenderset{\mathematicsparameter\c!symbolset}\relax
\to \everysetupmathematics % only in mathematics
\appendtoks
@@ -282,24 +331,26 @@
\unexpanded\def\boldsymbol
{\mathortext\mathboldsymbol\bold}
-%D Helpers:
+%D Helpers
-\def\utfmathclass #1{\ctxcommand{utfmathclass (\!!bs#1\!!es)}}
-\def\utfmathstretch#1{\ctxcommand{utfmathstretch(\!!bs#1\!!es)}}
-\def\utfmathcommand#1{\ctxcommand{utfmathcommand(\!!bs#1\!!es)}}
-\def\utfmathfiller #1{\ctxcommand{utfmathfiller (\!!bs#1\!!es)}}
+\def\utfmathclass #1{\clf_utfmathclass {#1}}
+\def\utfmathstretch#1{\clf_utfmathstretch{#1}}
+\def\utfmathcommand#1{\clf_utfmathcommand{#1}}
+\def\utfmathfiller #1{\clf_utfmathfiller {#1}}
-\def\utfmathclassfiltered #1#2{\ctxcommand{utfmathclass (\!!bs#1\!!es,nil,"#2")}}
-\def\utfmathcommandfiltered#1#2{\ctxcommand{utfmathcommand(\!!bs#1\!!es,nil,"#2")}}
+\def\utfmathcommandabove #1{\clf_utfmathcommandabove {#1}}
+\def\utfmathcommandbelow #1{\clf_utfmathcommandbelow {#1}}
+\def\utfmathcommandfiller#1{\clf_utfmathcommandfiller{#1}}
-\def\utfmathcommandabove#1{\ctxcommand{utfmathcommandabove(\!!bs#1\!!es)}}
-\def\utfmathcommandbelow#1{\ctxcommand{utfmathcommandbelow(\!!bs#1\!!es)}}
+\unexpanded\def\doifelseutfmathaccent#1{\clf_doifelseutfmathaccent{#1}}
+\unexpanded\def\doifelseutfmathabove #1{\clf_doifelseutfmathabove {#1}}
+\unexpanded\def\doifelseutfmathbelow #1{\clf_doifelseutfmathbelow {#1}}
+\unexpanded\def\doifelseutfmathfiller#1{\clf_doifelseutfmathfiller{#1}}
-\unexpanded\def\doifelseutfmathaccent #1{\ctxcommand{doifelseutfmathaccent(\!!bs#1\!!es)}}
-\unexpanded\def\doifelseutfmathaccentfiltered#1#2{\ctxcommand{doifelseutfmathaccent(\!!bs#1\!!es,"#2")}}
-
-\unexpanded\def\doifelseutfmathabove #1{\ctxcommand{doifelseutfmathabove(\!!bs#1\!!es)}}
-\unexpanded\def\doifelseutfmathbelow #1{\ctxcommand{doifelseutfmathbelow(\!!bs#1\!!es)}}
+\let\doifutfmathaccentelse \doifelseutfmathaccent
+\let\doifutfmathaboveelse \doifelseutfmathabove
+\let\doifutfmathbelowelse \doifelseutfmathbelow
+\let\doifutfmathfillerelse \doifelseutfmathfiller
%D Not used that much:
@@ -396,7 +447,7 @@
\relax
\hskip-.01\emwidth}
-\unexpanded\def\showmathstruts % let's not overload \nath_strut_normal
+\unexpanded\def\showmathstruts % let's not overload \math_strut_normal
{\let\math_strut\math_strut_visual}
\let\math_strut\math_strut_normal
@@ -456,7 +507,7 @@
\startimath#1\stopimath
\egroup
\ht\scratchbox\strutht
- \dp\scratchbox\strutht
+ \dp\scratchbox\strutdp
\box\scratchbox
\endgroup}
@@ -479,8 +530,8 @@
% Once this is stable we can store the number at the tex end which is
% faster. Functions getnumbers >= 1000.
-\expanded\def\math_tags_mathfunction_indeed #1{\ctxcommand{taggedmathfunction("#1",false,\ifconditional\c_apply_function true\else false\fi)}}
-\expanded\def\math_tags_mathfunctionlabeltext_indeed#1{\ctxcommand{taggedmathfunction("#1",true ,\ifconditional\c_apply_function true\else false\fi)}}
+\expanded\def\math_tags_mathfunction_indeed #1{\clf_taggedmathfunction{#1}{false}{\ifconditional\c_apply_function true\else false\fi}}
+\expanded\def\math_tags_mathfunctionlabeltext_indeed#1{\clf_taggedmathfunction{#1} {true}{\ifconditional\c_apply_function true\else false\fi}}
\expanded\def\math_tags_mo_indeed#1{\begingroup \attribute\mathcategoryattribute\plusone #1\endgroup}
\expanded\def\math_tags_mi_indeed#1{\begingroup \attribute\mathcategoryattribute\plustwo #1\endgroup}
@@ -823,17 +874,16 @@
% \ifconditional\knuthmode\else\donknuthmode\fi}
\unexpanded\def\enableasciimode
- {\ctxlua{resolvers.macros.enablecomment()}%
- \glet\enableasciimode\relax}
+ {\clf_enableasciimode} % relaxes itself
\unexpanded\def\asciimode
{\catcodetable\txtcatcodes
- \enableasciimode}
+ \clf_enableasciimode}
\unexpanded\def\startasciimode
{\pushcatcodetable
\catcodetable\txtcatcodes
- \enableasciimode}
+ \clf_enableasciimode}
\unexpanded\def\stopasciimode
{\popcatcodetable}
@@ -851,7 +901,7 @@
\to \everysetupmathematics
\setupmathematics
- [\c!compact=no]
+ [\c!compact=\v!no]
% \enabletrackers[typesetters.directions.math]
@@ -902,8 +952,8 @@
\newcount\c_math_bidi
-\setvalue{\??mathbidi\v!no }{\ctxcommand{setmathdirection(0)}\c_math_bidi\attributeunsetvalue}
-\setvalue{\??mathbidi\v!yes}{\ctxcommand{setmathdirection(1)}\c_math_bidi\plusone}
+\setvalue{\??mathbidi\v!no }{\clf_setmathdirection\zerocount\relax\c_math_bidi\attributeunsetvalue}
+\setvalue{\??mathbidi\v!yes}{\clf_setmathdirection\plusone \relax\c_math_bidi\plusone}
\appendtoks
\edef\p_bidi{\mathematicsparameter\c!bidi}%
@@ -985,7 +1035,7 @@
\def\math_italics_initialize
{\ifnum\c_math_italics_attribute=\attributeunsetvalue \else
- \ctxcommand{setmathitalics()}% one time
+ \clf_setmathitalics % one time
\global\let\math_italics_initialize\relax
\fi}
@@ -1491,6 +1541,16 @@
\crampedscriptstyle \or
\fi}
+\newcount\c_math_saved_style
+
+\unexpanded\def\pushmathstyle % assumes begingroup .. endgroup
+ {\c_math_saved_style\mathstyle}
+
+\unexpanded\def\popmathstyle
+ {\ifnum\mathstyle=\c_math_saved_style\else
+ \triggermathstyle\c_math_saved_style
+ \fi}
+
\installcorenamespace{mathstylecommand}
\installcorenamespace{mathstylecache}
@@ -1826,7 +1886,14 @@
\ifdefined\text\else \let\text\hbox \fi
-\unexpanded\def\mathoptext#1{\mathop{\text{#1}}}
+% \unexpanded\def\mathoptext#1{\mathop{\text{#1}}}
+
+\unexpanded\def\mathoptext
+ {\normalizebodyfontsize\m_math_text_choice_face{\mathstyleface\normalmathstyle}%
+ %\showmathstyle
+ \dowithnextbox
+ {\mathop{\box\nextbox}}%
+ \hbox\bgroup\font_basics_switchtobodyfont\m_math_text_choice_face\let\next}
% new:
@@ -1851,11 +1918,140 @@
% this should be a primitive:
-% \def\mathextensiblecode#1#2%
-% {\cldcontext{mathematics.extensiblecode(\number#1,\number#2)}}
+\def\mathextensiblecode#1#2{\clf_extensiblecode\numexpr#1\relax\numexpr#2\relax}
+\def\mathhorizontalcode#1#2{\clf_horizontalcode\numexpr#1\relax\numexpr#2\relax}
-\def\mathextensiblecode#1#2{\ctxcommand{extensiblecode(\number#1,\number#2)}}
-\def\mathhorizontalcode#1#2{\ctxcommand{horizontalcode(\number#1,\number#2)}}
+% experimental:
+
+%D \starttyping
+%D \enabletrackers[math.openedup]
+%D
+%D \dorecurse{10}{\dorecurse{#1}{whatever }}
+%D
+%D \startitemize[packed]
+%D \startitem whatever \openedupimath{\frac{1}{2}} whatever
+%D \startitem whatever \openedupimath{\frac{1}{2}} whatever
+%D \startitem whatever \openedupimath{\frac{1}{2}} whatever
+%D \stopitemize
+%D \startitemize[packed,columns]
+%D \startitem whatever \openedupimath{\frac{1}{2}} whatever
+%D \startitem whatever \openedupimath{\frac{1}{2}} whatever
+%D \startitem whatever \openedupimath{\frac{1}{2}} whatever
+%D \startitem whatever \openedupimath{\frac{1}{2}} whatever
+%D \startitem whatever \openedupimath{\frac{1}{2}} whatever
+%D \startitem whatever \openedupimath{\frac{1}{2}} whatever
+%D \stopitemize
+%D
+%D \dorecurse{5}{\dorecurse{#1}{whatever }\openedupimath{\frac{1}{2}} }
+%D
+%D \startitemize[packed,columns]
+%D \startitem whatever \openedupimath{1+2} whatever
+%D \startitem whatever \openedupimath{1+2} whatever
+%D \startitem whatever \openedupimath{\frac{1}{2}} whatever
+%D \startitem whatever \openedupimath{1+2} whatever
+%D \startitem whatever \openedupimath{1+2} whatever
+%D \stopitemize
+%D
+%D \dorecurse{5}{\dorecurse{#1}{whatever }\openedupimath{1+2} }
+%D
+%D \startitemize[packed]
+%D \startitem whatever \openedupimath{\frac{1}{2}} whatever
+%D \startitem whatever \openedupimath{\frac{1}{2}} whatever
+%D \startitem whatever \openedupimath{\frac{1}{2}} whatever
+%D \stopitemize
+%D
+%D \dorecurse{10}{whatever }
+%D \dorecurse {5}{\dorecurse{#1}{whatever }\openedupimath{\frac{1}{2}} }
+%D \dorecurse{10}{whatever }
+%D \stoptyping
+
+\def\m_math_inline_openup_ht{\dimexpr\ifinsidecolumns\strutdp\else\lineheight\fi/\plusfour\relax}
+\def\m_math_inline_openup_dp{\dimexpr\ifinsidecolumns\strutdp\else\lineheight\fi/\plusfour\relax}
+
+% \def\m_math_inline_openup_ht{\dimexpr\lineheight/\ifinsidecolumns\pluseight\else\plusfour\fi\relax}
+% \def\m_math_inline_openup_dp{\dimexpr\lineheight/\ifinsidecolumns\pluseight\else\plusfour\fi\relax}
+
+\installtextracker
+ {math.openedup}
+ {\let\math_inline_openup_start_yes\math_inline_openup_traced_start}
+ {\let\math_inline_openup_start_yes\math_inline_openup_normal_start}
+
+\unexpanded\def\math_inline_openup_normal_start
+ {\scratchheight\dimexpr\ht\scratchbox+\m_math_inline_openup_ht\relax
+ \scratchdepth \dimexpr\dp\scratchbox+\m_math_inline_openup_dp\relax
+ \vrule\s!width\zeropoint\s!height\scratchheight\s!depth\scratchdepth\relax
+ \begingroup
+ \let\math_inline_openup_stop\math_inline_openup_normal_stop}
+
+\unexpanded\def\math_inline_openup_normal_stop
+ {\endgroup
+ \vrule\s!width\zeropoint\s!height\scratchheight\s!depth\scratchdepth\relax}
+
+\unexpanded\def\math_inline_openup_traced_start
+ {\scratchtopoffset \ht\scratchbox
+ \scratchbottomoffset\dp\scratchbox
+ \scratchheight \dimexpr\scratchtopoffset +\m_math_inline_openup_ht\relax
+ \scratchdepth \dimexpr\scratchbottomoffset+\m_math_inline_openup_dp\relax
+ \vrule\s!width\zeropoint\s!height\scratchheight\s!depth\scratchdepth\relax
+ \begingroup
+ \dofastcoloractivation{darkred}%
+ \vrule\s!width\emwidth\s!height\scratchheight\s!depth-\scratchtopoffset\relax
+ \endgroup
+ \kern-\emwidth
+ \begingroup
+ \let\math_inline_openup_stop\math_inline_openup_traced_stop}
+
+\unexpanded\def\math_inline_openup_traced_stop
+ {\endgroup
+ \kern-\emwidth
+ \begingroup
+ \dofastcoloractivation{darkblue}%
+ \vrule\s!width\emwidth\s!height-\scratchbottomoffset\s!depth\scratchdepth\relax
+ \endgroup
+ \vrule\s!width\zeropoint\s!height\scratchheight\s!depth\scratchdepth\relax}
+
+\let\math_inline_openup_start_yes\math_inline_openup_normal_start
+\let\math_inline_openup_stop \relax
+
+\def\math_inline_openup_start_nop
+ {\let\math_inline_openup_stop\relax}
+
+\unexpanded\def\openedupimath
+ {\dontleavehmode
+ \begingroup
+ \ifmmode
+ \expandafter\openedupimath_math
+ \else
+ \expandafter\openedupimath_text
+ \fi}
+
+\unexpanded\def\openedupimath_math#1%
+ {\setbox\scratchbox\mathstylehbox{#1}%
+ \ifdim\ht\scratchbox>\strutht
+ \math_inline_openup_start_yes
+ \else\ifdim\dp\scratchbox>\strutdp
+ \math_inline_openup_start_yes
+ \else
+ \math_inline_openup_start_nop
+ \fi\fi
+ #1%
+ \math_inline_openup_stop
+ \endgroup}
+
+\unexpanded\def\openedupimath_text#1%
+ {\setbox\scratchbox\hbox{\startimath#1\stopimath}%
+ \ifdim\ht\scratchbox>\strutht
+ \math_inline_openup_start_yes
+ \else\ifdim\dp\scratchbox>\strutdp
+ \math_inline_openup_start_yes
+ \else
+ \math_inline_openup_start_nop
+ \fi\fi
+ \startimath
+ #1%
+ \stopimath
+ \math_inline_openup_stop
+ \endgroup}
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/math-int.mkiv b/Master/texmf-dist/tex/context/base/math-int.mkiv
index 6b480961b6a..6b65738ff2e 100644
--- a/Master/texmf-dist/tex/context/base/math-int.mkiv
+++ b/Master/texmf-dist/tex/context/base/math-int.mkiv
@@ -13,6 +13,8 @@
\writestatus{loading}{ConTeXt Math Macros / Integrals}
+% todo: int and sum etc can be stackers
+
\unprotect
%D \startbuffer
diff --git a/Master/texmf-dist/tex/context/base/math-map.lua b/Master/texmf-dist/tex/context/base/math-map.lua
index f2a588fc7de..add6afa4c1c 100644
--- a/Master/texmf-dist/tex/context/base/math-map.lua
+++ b/Master/texmf-dist/tex/context/base/math-map.lua
@@ -53,6 +53,8 @@ local report_remapping = logs.reporter("mathematics","remapping")
mathematics = mathematics or { }
local mathematics = mathematics
+local implement = interfaces.implement
+
-- Unfortunately some alphabets have gaps (thereby troubling all applications that
-- need to deal with math). Somewhat strange considering all those weird symbols that
-- were added afterwards. The following trickery (and data) is only to be used for
@@ -184,7 +186,7 @@ local regular_tf = {
},
symbols = {
[0x2202]=0x2202, [0x2207]=0x2207,
- [0x0027]=0x2032, -- prime
+ [0x0027]=0x2032, -- prime
},
}
@@ -617,6 +619,39 @@ function mathematics.syncname(alphabet)
texsetattribute(mathalphabet,data and data.attribute or texattribute[mathalphabet])
end
+implement {
+ name = "setmathattribute",
+ arguments = { "string", "string" },
+ actions = function(alphabet,style)
+ local data = alphabets[alphabet] or regular
+ data = data[style] or data.tf
+ texsetattribute(mathalphabet,data and data.attribute or texattribute[mathalphabet])
+ end
+}
+
+implement {
+ name = "setmathstyle",
+ arguments = "string",
+ actions = function(style)
+ local r = mathremap[texgetattribute(mathalphabet)]
+ local alphabet = r and r.alphabet or "regular"
+ local data = alphabets[alphabet][style]
+ texsetattribute(mathalphabet,data and data.attribute or texattribute[mathalphabet])
+ end
+}
+
+implement {
+ name = "setmathalphabet",
+ arguments = "string",
+ actions = function(alphabet)
+ -- local r = mathremap[mathalphabet]
+ local r = mathremap[texgetattribute(mathalphabet)]
+ local style = r and r.style or "tf"
+ local data = alphabets[alphabet][style]
+ texsetattribute(mathalphabet,data and data.attribute or texattribute[mathalphabet])
+ end
+}
+
local islcgreek = regular_tf.lcgreek
local isucgreek = regular_tf.ucgreek
local issygreek = regular_tf.symbols
@@ -742,9 +777,3 @@ function mathematics.addfallbacks(main)
checkedcopy(characters,regular.bi.ucgreek,regular.it.ucgreek)
checkedcopy(characters,regular.bi.lcgreek,regular.it.lcgreek)
end
-
--- interface
-
-commands.setmathattribute = mathematics.syncboth
-commands.setmathalphabet = mathematics.syncname
-commands.setmathstyle = mathematics.syncstyle
diff --git a/Master/texmf-dist/tex/context/base/math-noa.lua b/Master/texmf-dist/tex/context/base/math-noa.lua
index 3a0af01cc9e..893ee6f48d3 100644
--- a/Master/texmf-dist/tex/context/base/math-noa.lua
+++ b/Master/texmf-dist/tex/context/base/math-noa.lua
@@ -28,31 +28,38 @@ local otf = fonts.handlers.otf
local otffeatures = fonts.constructors.newfeatures("otf")
local registerotffeature = otffeatures.register
-local trace_remapping = false trackers.register("math.remapping", function(v) trace_remapping = v end)
-local trace_processing = false trackers.register("math.processing", function(v) trace_processing = v end)
-local trace_analyzing = false trackers.register("math.analyzing", function(v) trace_analyzing = v end)
-local trace_normalizing = false trackers.register("math.normalizing", function(v) trace_normalizing = v end)
-local trace_collapsing = false trackers.register("math.collapsing", function(v) trace_collapsing = v end)
-local trace_goodies = false trackers.register("math.goodies", function(v) trace_goodies = v end)
-local trace_variants = false trackers.register("math.variants", function(v) trace_variants = v end)
-local trace_alternates = false trackers.register("math.alternates", function(v) trace_alternates = v end)
-local trace_italics = false trackers.register("math.italics", function(v) trace_italics = v end)
-local trace_families = false trackers.register("math.families", function(v) trace_families = v end)
-
-local check_coverage = true directives.register("math.checkcoverage", function(v) check_coverage = v end)
-
-local report_processing = logs.reporter("mathematics","processing")
-local report_remapping = logs.reporter("mathematics","remapping")
-local report_normalizing = logs.reporter("mathematics","normalizing")
-local report_collapsing = logs.reporter("mathematics","collapsing")
-local report_goodies = logs.reporter("mathematics","goodies")
-local report_variants = logs.reporter("mathematics","variants")
-local report_alternates = logs.reporter("mathematics","alternates")
-local report_italics = logs.reporter("mathematics","italics")
-local report_families = logs.reporter("mathematics","families")
-
-local a_mathrendering = attributes.private("mathrendering")
-local a_exportstatus = attributes.private("exportstatus")
+local privateattribute = attributes.private
+local registertracker = trackers.register
+local registerdirective = directives.register
+local logreporter = logs.reporter
+
+local trace_remapping = false registertracker("math.remapping", function(v) trace_remapping = v end)
+local trace_processing = false registertracker("math.processing", function(v) trace_processing = v end)
+local trace_analyzing = false registertracker("math.analyzing", function(v) trace_analyzing = v end)
+local trace_normalizing = false registertracker("math.normalizing", function(v) trace_normalizing = v end)
+local trace_collapsing = false registertracker("math.collapsing", function(v) trace_collapsing = v end)
+local trace_patching = false registertracker("math.patching", function(v) trace_patching = v end)
+local trace_goodies = false registertracker("math.goodies", function(v) trace_goodies = v end)
+local trace_variants = false registertracker("math.variants", function(v) trace_variants = v end)
+local trace_alternates = false registertracker("math.alternates", function(v) trace_alternates = v end)
+local trace_italics = false registertracker("math.italics", function(v) trace_italics = v end)
+local trace_families = false registertracker("math.families", function(v) trace_families = v end)
+
+local check_coverage = true registerdirective("math.checkcoverage", function(v) check_coverage = v end)
+
+local report_processing = logreporter("mathematics","processing")
+local report_remapping = logreporter("mathematics","remapping")
+local report_normalizing = logreporter("mathematics","normalizing")
+local report_collapsing = logreporter("mathematics","collapsing")
+local report_patching = logreporter("mathematics","patching")
+local report_goodies = logreporter("mathematics","goodies")
+local report_variants = logreporter("mathematics","variants")
+local report_alternates = logreporter("mathematics","alternates")
+local report_italics = logreporter("mathematics","italics")
+local report_families = logreporter("mathematics","families")
+
+local a_mathrendering = privateattribute("mathrendering")
+local a_exportstatus = privateattribute("exportstatus")
local nuts = nodes.nuts
local nodepool = nuts.pool
@@ -83,8 +90,6 @@ local font_of_family = node.family_font
local new_kern = nodepool.kern
local new_rule = nodepool.rule
-local topoints = number.points
-
local fonthashes = fonts.hashes
local fontdata = fonthashes.identifiers
local fontcharacters = fonthashes.characters
@@ -236,7 +241,7 @@ noads.process = processnoads
-- might as well do this
local families = { }
-local a_mathfamily = attributes.private("mathfamily")
+local a_mathfamily = privateattribute("mathfamily")
local boldmap = mathematics.boldmap
local familymap = { [0] =
@@ -336,8 +341,8 @@ end
-- character remapping
-local a_mathalphabet = attributes.private("mathalphabet")
-local a_mathgreek = attributes.private("mathgreek")
+local a_mathalphabet = privateattribute("mathalphabet")
+local a_mathgreek = privateattribute("mathgreek")
processors.relocate = { }
@@ -488,7 +493,7 @@ end
-- todo: just replace the character by an ord noad
-- and remove the right delimiter as well
-local mathsize = attributes.private("mathsize")
+local mathsize = privateattribute("mathsize")
local resize = { } processors.resize = resize
@@ -517,137 +522,17 @@ function handlers.resize(head,style,penalties)
return true
end
-local collapse = { } processors.collapse = collapse
-
-local mathpairs = characters.mathpairs
-
-mathpairs[0x2032] = { [0x2032] = 0x2033, [0x2033] = 0x2034, [0x2034] = 0x2057 } -- (prime,prime) (prime,doubleprime) (prime,tripleprime)
-mathpairs[0x2033] = { [0x2032] = 0x2034, [0x2033] = 0x2057 } -- (doubleprime,prime) (doubleprime,doubleprime)
-mathpairs[0x2034] = { [0x2032] = 0x2057 } -- (tripleprime,prime)
-
-mathpairs[0x2035] = { [0x2035] = 0x2036, [0x2036] = 0x2037 } -- (reversedprime,reversedprime) (reversedprime,doublereversedprime)
-mathpairs[0x2036] = { [0x2035] = 0x2037 } -- (doublereversedprime,reversedprime)
-
-mathpairs[0x222B] = { [0x222B] = 0x222C, [0x222C] = 0x222D }
-mathpairs[0x222C] = { [0x222B] = 0x222D }
-
-mathpairs[0x007C] = { [0x007C] = 0x2016, [0x2016] = 0x2980 } -- bar+bar=double bar+double=triple
-mathpairs[0x2016] = { [0x007C] = 0x2980 } -- double+bar=triple
-
-local movesub = {
- -- primes
- [0x2032] = 0xFE932,
- [0x2033] = 0xFE933,
- [0x2034] = 0xFE934,
- [0x2057] = 0xFE957,
- -- reverse primes
- [0x2035] = 0xFE935,
- [0x2036] = 0xFE936,
- [0x2037] = 0xFE937,
-}
-
-local validpair = {
- [noad_rel] = true,
- [noad_ord] = true,
- [noad_opdisplaylimits] = true,
- [noad_oplimits] = true,
- [noad_opnolimits] = true,
-}
-
-local function movesubscript(parent,current_nucleus,current_char)
- local prev = getfield(parent,"prev")
- if prev and getid(prev) == math_noad then
- if not getfield(prev,"sup") and not getfield(prev,"sub") then
- setfield(current_nucleus,"char",movesub[current_char or getchar(current_nucleus)])
- -- {f} {'}_n => f_n^'
- local nucleus = getfield(parent,"nucleus")
- local sub = getfield(parent,"sub")
- local sup = getfield(parent,"sup")
- setfield(prev,"sup",nucleus)
- setfield(prev,"sub",sub)
- local dummy = copy_node(nucleus)
- setfield(dummy,"char",0)
- setfield(parent,"nucleus",dummy)
- setfield(parent,"sub",nil)
- if trace_collapsing then
- report_collapsing("fixing subscript")
- end
- end
- end
-end
-
-local function collapsepair(pointer,what,n,parent,nested) -- todo: switch to turn in on and off
- if parent then
- if validpair[getsubtype(parent)] then
- local current_nucleus = getfield(parent,"nucleus")
- if getid(current_nucleus) == math_char then
- local current_char = getchar(current_nucleus)
- if not getfield(parent,"sub") and not getfield(parent,"sup") then
- local mathpair = mathpairs[current_char]
- if mathpair then
- local next_noad = getnext(parent)
- if next_noad and getid(next_noad) == math_noad then
- if validpair[getsubtype(next_noad)] then
- local next_nucleus = getfield(next_noad,"nucleus")
- if getid(next_nucleus) == math_char then
- local next_char = getchar(next_nucleus)
- local newchar = mathpair[next_char]
- if newchar then
- local fam = getfield(current_nucleus,"fam")
- local id = font_of_family(fam)
- local characters = fontcharacters[id]
- if characters and characters[newchar] then
- if trace_collapsing then
- report_collapsing("%U + %U => %U",current_char,next_char,newchar)
- end
- setfield(current_nucleus,"char",newchar)
- local next_next_noad = getnext(next_noad)
- if next_next_noad then
- setfield(parent,"next",next_next_noad)
- setfield(next_next_noad,"prev",parent)
- else
- setfield(parent,"next",nil)
- end
- setfield(parent,"sup",getfield(next_noad,"sup"))
- setfield(parent,"sub",getfield(next_noad,"sub"))
- setfield(next_noad,"sup",nil)
- setfield(next_noad,"sub",nil)
- free_node(next_noad)
- collapsepair(pointer,what,n,parent,true)
- if not nested and movesub[current_char] then
- movesubscript(parent,current_nucleus)
- end
- end
- end
- end
- end
- end
- elseif not nested and movesub[current_char] then
- movesubscript(parent,current_nucleus,current_char)
- end
- elseif not nested and movesub[current_char] then
- movesubscript(parent,current_nucleus,current_char)
- end
- end
- end
- end
-end
-
-collapse[math_char] = collapsepair
-
-function noads.handlers.collapse(head,style,penalties)
- processnoads(head,collapse,"collapse")
- return true
-end
-
-- normalize scripts
local unscript = { } noads.processors.unscript = unscript
+local checkers = { } noads.processors.checkers = checkers
local superscripts = characters.superscripts
local subscripts = characters.subscripts
+local fractions = characters.fractions
local replaced = { }
+local unknowns = { }
local function replace(pointer,what,n,parent)
pointer = parent -- we're following the parent list (chars trigger this)
@@ -726,22 +611,83 @@ local function replace(pointer,what,n,parent)
-- we could return stop
end
+local tracked = false trackers.register("fonts.missing", function(v) tracked = v end)
+local checked = { } -- simple case
+local cached = table.setmetatableindex("table") -- complex case
+
+local function check(pointer,what,n,parent)
+ if tracked then
+ -- slower as we check each font too and we always replace as math has
+ -- more demands than text
+ local char = getchar(pointer)
+ local font = font_of_family(getfield(pointer,"fam"))
+ local fake = cached[font][char]
+ if fake then
+ unknowns[char] = unknowns[char] + 1
+ setfield(pointer,"char",fake)
+ else
+ local chars = fontcharacters[font]
+ if not chars[char] then
+ unknowns[char] = 1
+ local kind, fake = fonts.checkers.placeholder(font,char)
+ if kind == "char" then
+ cached[font][char] = fake
+ setfield(pointer,"char",fake)
+ else
+ cached[font][char] = 0x3F
+ end
+ end
+ end
+ else
+ -- only simple checking, report at the end so one should take
+ -- action anyway ... we can miss a few checks but that is ok
+ -- as there is at least one reported
+ local char = getchar(pointer)
+ local done = unknowns[char]
+ if done then
+ unknowns[char] = done + 1
+ setfield(pointer,"char",0x3F)
+ elseif not checked[char] then
+ local font = font_of_family(getfield(pointer,"fam"))
+ local chars = fontcharacters[font]
+ if not chars[char] then
+ unknowns[char] = 1
+ setfield(pointer,"char",0x3F)
+ if trace_normalizing then
+ report_normalizing("character %C is not available",char)
+ end
+ end
+ end
+ checked[char] = true
+ end
+end
+
unscript[math_char] = replace -- not noads as we need to recurse
+checkers[math_char] = check -- not noads as we need to recurse
function handlers.unscript(head,style,penalties)
processnoads(head,unscript,"unscript")
+ processnoads(head,checkers,"checkers")
return true
end
-statistics.register("math script replacements", function()
- if next(replaced) then
+local function collected(list)
+ if list and next(list) then
local n, t = 0, { }
- for k, v in table.sortedpairs(replaced) do
+ for k, v in table.sortedpairs(list) do
n = n + v
t[#t+1] = formatters["%C"](k)
end
return formatters["% t (n=%s)"](t,n)
end
+end
+
+statistics.register("math script replacements", function()
+ return collected(replaced)
+end)
+
+statistics.register("unknown math characters", function()
+ return collected(unknowns)
end)
-- math alternates: (in xits lgf: $ABC$ $\cal ABC$ $\mathalternate{cal}\cal ABC$)
@@ -787,7 +733,7 @@ registerotffeature {
local getalternate = otf.getalternate
-local a_mathalternate = attributes.private("mathalternate")
+local a_mathalternate = privateattribute("mathalternate")
local alternate = { } -- processors.alternate = alternate
@@ -831,7 +777,12 @@ end
-- = we check for correction first because accessing nodes is slower
-- = the actual glyph is not that important (we can control it with numbers)
-local a_mathitalics = attributes.private("mathitalics")
+-- Italic correction in luatex math is a mess. There are all kind of assumptions based on
+-- old fonts and new font. Eventually there should be a flag that can signal to ignore all
+-- those heuristics. We want to deal with it ourselves also in the perspective of mxed math
+-- and text.
+
+local a_mathitalics = privateattribute("mathitalics")
local italics = { }
local default_factor = 1/20
@@ -899,6 +850,12 @@ local function getcorrection(method,font,char) -- -- or character.italic -- (thi
end
+local setcolor = nodes.tracers.colors.set
+local resetcolor = nodes.tracers.colors.reset
+local italic_kern = new_kern
+local c_positive_d = "trace:db"
+local c_negative_d = "trace:dr"
+
local function insert_kern(current,kern)
local sub = new_node(math_sub) -- todo: pool
local noad = new_node(math_noad) -- todo: pool
@@ -908,13 +865,7 @@ local function insert_kern(current,kern)
return sub
end
-local setcolor = nodes.tracers.colors.set
-local resetcolor = nodes.tracers.colors.reset
-local italic_kern = new_kern
-local c_positive_d = "trace:db"
-local c_negative_d = "trace:dr"
-
-trackers.register("math.italics", function(v)
+registertracker("math.italics.visualize", function(v)
if v then
italic_kern = function(k,font)
local ex = 1.5 * fontexheights[font]
@@ -959,12 +910,14 @@ italics[math_char] = function(pointer,what,n,parent)
report_italics("method %a, adding %p italic correction for lower limit of %C",method,correction,char)
end
end
- else
- if sup then
+ elseif sup then
+ if pointer ~= sub then
setfield(parent,"sup",insert_kern(sup,italic_kern(correction,font)))
if trace_italics then
report_italics("method %a, adding %p italic correction before superscript after %C",method,correction,char)
end
+ else
+ -- otherwise we inject twice
end
end
else
@@ -1044,6 +997,147 @@ function mathematics.resetitalics()
texsetattribute(a_mathitalics,unsetvalue)
end
+-- primes and such
+
+local collapse = { } processors.collapse = collapse
+
+local mathpairs = characters.mathpairs
+
+mathpairs[0x2032] = { [0x2032] = 0x2033, [0x2033] = 0x2034, [0x2034] = 0x2057 } -- (prime,prime) (prime,doubleprime) (prime,tripleprime)
+mathpairs[0x2033] = { [0x2032] = 0x2034, [0x2033] = 0x2057 } -- (doubleprime,prime) (doubleprime,doubleprime)
+mathpairs[0x2034] = { [0x2032] = 0x2057 } -- (tripleprime,prime)
+
+mathpairs[0x2035] = { [0x2035] = 0x2036, [0x2036] = 0x2037 } -- (reversedprime,reversedprime) (reversedprime,doublereversedprime)
+mathpairs[0x2036] = { [0x2035] = 0x2037 } -- (doublereversedprime,reversedprime)
+
+mathpairs[0x222B] = { [0x222B] = 0x222C, [0x222C] = 0x222D }
+mathpairs[0x222C] = { [0x222B] = 0x222D }
+
+mathpairs[0x007C] = { [0x007C] = 0x2016, [0x2016] = 0x2980 } -- bar+bar=double bar+double=triple
+mathpairs[0x2016] = { [0x007C] = 0x2980 } -- double+bar=triple
+
+local movesub = {
+ -- primes
+ [0x2032] = 0xFE932,
+ [0x2033] = 0xFE933,
+ [0x2034] = 0xFE934,
+ [0x2057] = 0xFE957,
+ -- reverse primes
+ [0x2035] = 0xFE935,
+ [0x2036] = 0xFE936,
+ [0x2037] = 0xFE937,
+}
+
+local validpair = {
+ [noad_rel] = true,
+ [noad_ord] = true,
+ [noad_opdisplaylimits] = true,
+ [noad_oplimits] = true,
+ [noad_opnolimits] = true,
+}
+
+local function movesubscript(parent,current_nucleus,current_char)
+ local prev = getfield(parent,"prev")
+ if prev and getid(prev) == math_noad then
+ if not getfield(prev,"sup") and not getfield(prev,"sub") then
+ -- {f} {'}_n => f_n^'
+ setfield(current_nucleus,"char",movesub[current_char or getchar(current_nucleus)])
+ local nucleus = getfield(parent,"nucleus")
+ local sub = getfield(parent,"sub")
+ local sup = getfield(parent,"sup")
+ setfield(prev,"sup",nucleus)
+ setfield(prev,"sub",sub)
+ local dummy = copy_node(nucleus)
+ setfield(dummy,"char",0)
+ setfield(parent,"nucleus",dummy)
+ setfield(parent,"sub",nil)
+ if trace_collapsing then
+ report_collapsing("fixing subscript")
+ end
+ elseif not getfield(prev,"sup") then
+ -- {f} {'}_n => f_n^'
+ setfield(current_nucleus,"char",movesub[current_char or getchar(current_nucleus)])
+ local nucleus = getfield(parent,"nucleus")
+ local sup = getfield(parent,"sup")
+ setfield(prev,"sup",nucleus)
+ local dummy = copy_node(nucleus)
+ setfield(dummy,"char",0)
+ setfield(parent,"nucleus",dummy)
+ if trace_collapsing then
+ report_collapsing("fixing subscript")
+ end
+ end
+ end
+end
+
+local function collapsepair(pointer,what,n,parent,nested) -- todo: switch to turn in on and off
+ if parent then
+ if validpair[getsubtype(parent)] then
+ local current_nucleus = getfield(parent,"nucleus")
+ if getid(current_nucleus) == math_char then
+ local current_char = getchar(current_nucleus)
+ if not getfield(parent,"sub") and not getfield(parent,"sup") then
+ local mathpair = mathpairs[current_char]
+ if mathpair then
+ local next_noad = getnext(parent)
+ if next_noad and getid(next_noad) == math_noad then
+ if validpair[getsubtype(next_noad)] then
+ local next_nucleus = getfield(next_noad,"nucleus")
+ local next_char = getchar(next_nucleus)
+ if getid(next_nucleus) == math_char then
+ local newchar = mathpair[next_char]
+ if newchar then
+ local fam = getfield(current_nucleus,"fam")
+ local id = font_of_family(fam)
+ local characters = fontcharacters[id]
+ if characters and characters[newchar] then
+ if trace_collapsing then
+ report_collapsing("%U + %U => %U",current_char,next_char,newchar)
+ end
+ setfield(current_nucleus,"char",newchar)
+ local next_next_noad = getnext(next_noad)
+ if next_next_noad then
+ setfield(parent,"next",next_next_noad)
+ setfield(next_next_noad,"prev",parent)
+ else
+ setfield(parent,"next",nil)
+ end
+ setfield(parent,"sup",getfield(next_noad,"sup"))
+ setfield(parent,"sub",getfield(next_noad,"sub"))
+ setfield(next_noad,"sup",nil)
+ setfield(next_noad,"sub",nil)
+ free_node(next_noad)
+ collapsepair(pointer,what,n,parent,true)
+ -- if not nested and movesub[current_char] then
+ -- movesubscript(parent,current_nucleus,current_char)
+ -- end
+ end
+ elseif not nested and movesub[current_char] then
+ movesubscript(parent,current_nucleus,current_char)
+ end
+ end
+ end
+ elseif not nested and movesub[current_char] then
+ movesubscript(parent,current_nucleus,current_char)
+ end
+ elseif not nested and movesub[current_char] then
+ movesubscript(parent,current_nucleus,current_char)
+ end
+ elseif not nested and movesub[current_char] then
+ movesubscript(parent,current_nucleus,current_char)
+ end
+ end
+ end
+ end
+end
+
+collapse[math_char] = collapsepair
+
+function noads.handlers.collapse(head,style,penalties)
+ processnoads(head,collapse,"collapse")
+ return true
+end
+
-- variants
local variants = { }
@@ -1139,7 +1233,7 @@ function handlers.classes(head,style,penalties)
return true
end
-trackers.register("math.classes",function(v) tasks.setaction("math","noads.handlers.classes",v) end)
+registertracker("math.classes",function(v) tasks.setaction("math","noads.handlers.classes",v) end)
-- just for me
@@ -1147,7 +1241,7 @@ function handlers.showtree(head,style,penalties)
inspect(nodes.totree(head))
end
-trackers.register("math.showtree",function(v) tasks.setaction("math","noads.handlers.showtree",v) end)
+registertracker("math.showtree",function(v) tasks.setaction("math","noads.handlers.showtree",v) end)
-- the normal builder
@@ -1202,6 +1296,20 @@ end)
-- interface
-commands.setmathalternate = mathematics.setalternate
-commands.setmathitalics = mathematics.setitalics
-commands.resetmathitalics = mathematics.resetitalics
+local implement = interfaces.implement
+
+implement {
+ name = "setmathalternate",
+ actions = mathematics.setalternate,
+ arguments = { "integer", "string" }
+}
+
+implement {
+ name = "setmathitalics",
+ actions = mathematics.setitalics
+}
+
+implement {
+ name = "resetmathitalics",
+ actions = mathematics.resetitalics
+}
diff --git a/Master/texmf-dist/tex/context/base/math-rad.mkvi b/Master/texmf-dist/tex/context/base/math-rad.mkvi
index 027b5c27d50..23e056c1fd2 100644
--- a/Master/texmf-dist/tex/context/base/math-rad.mkvi
+++ b/Master/texmf-dist/tex/context/base/math-rad.mkvi
@@ -28,13 +28,13 @@
\def\root#1\of{\rootradical{#1}} % #2
-\unexpanded\def\sqrt{\doifnextoptionalcselse\rootwithdegree\rootwithoutdegree}
+\unexpanded\def\sqrt{\doifelsenextoptionalcs\rootwithdegree\rootwithoutdegree}
-\def\styledrootradical#1#2% so that \text works ok ... \rootradical behaves somewhat weird
+\unexpanded\def\styledrootradical#1#2% so that \text works ok ... \rootradical behaves somewhat weird
{\normalexpanded{\rootradical{\normalunexpanded{#1}}{\noexpand\triggermathstyle{\normalmathstyle}\normalunexpanded{#2}}}}
-\def\rootwithdegree[#1]{\rootradical{#1}}
-\def\rootwithoutdegree {\rootradical {}}
+\unexpanded\def\rootwithdegree[#1]{\rootradical{#1}}
+\unexpanded\def\rootwithoutdegree {\rootradical {}}
%D Even older stuff:
@@ -62,7 +62,7 @@
\unexpanded\def\math_radical_handle#tag%
{\begingroup
\edef\currentmathradical{#tag}%
- \doifnextoptionalcselse\math_radical_degree_yes\math_radical_degree_nop}
+ \doifelsenextoptionalcs\math_radical_degree_yes\math_radical_degree_nop}
\def\math_radical_alternative{\csname\??mathradicalalternative\mathradicalparameter\c!alternative\endcsname}
@@ -173,11 +173,11 @@
\setbox\nextbox\mathstylehbox{#body}%
% we use the \overlay variables as these are passes anyway and
% it's more efficient than using parameters
- \edef\overlaywidth {\the\wd\nextbox}%
- \edef\overlayheight {\the\ht\nextbox}%
- \edef\overlaydepth {\the\dp\nextbox}%
- \edef\overlayoffset {\the\scratchoffset}%
- \edef\overlaylinewidth{\the\linewidth}%
+ \d_overlay_width \wd\nextbox
+ \d_overlay_height \ht\nextbox
+ \d_overlay_depth \dp\nextbox
+ \d_overlay_offset \scratchoffset
+ \d_overlay_linewidth\linewidth
\edef\overlaylinecolor{\mathradicalparameter\c!color}%
%
\edef\p_mp{\mathradicalparameter\c!mp}%
@@ -233,11 +233,11 @@
{\begingroup
\scratchoffset\mathornamentparameter\c!mpoffset
\setbox\nextbox\mathstylehbox{#body}%
- \edef\overlaywidth {\the\wd\nextbox}%
- \edef\overlayheight {\the\ht\nextbox}%
- \edef\overlaydepth {\the\dp\nextbox}%
- \edef\overlayoffset {\the\scratchoffset}%
- \edef\overlaylinewidth{\the\linewidth}%
+ \d_overlay_width \wd\nextbox
+ \d_overlay_height \ht\nextbox
+ \d_overlay_depth \dp\nextbox
+ \d_overlay_offset \scratchoffset
+ \d_overlay_linewidth\linewidth
\edef\overlaylinecolor{\mathornamentparameter\c!color}%
\edef\p_mp{\mathornamentparameter\c!mp}%
% thw width of the graphic determines the width of the final result
diff --git a/Master/texmf-dist/tex/context/base/math-ren.lua b/Master/texmf-dist/tex/context/base/math-ren.lua
index 5c4c1336944..4628ffe5587 100644
--- a/Master/texmf-dist/tex/context/base/math-ren.lua
+++ b/Master/texmf-dist/tex/context/base/math-ren.lua
@@ -60,6 +60,8 @@ end
mathematics.renderset = renderset
-function commands.mathrenderset(list)
- context(renderset(list))
-end
+interfaces.implement {
+ name = "mathrenderset",
+ actions = { renderset, context },
+ arguments = "string",
+}
diff --git a/Master/texmf-dist/tex/context/base/math-stc.mkvi b/Master/texmf-dist/tex/context/base/math-stc.mkvi
index 76a07db5c68..a879d157f27 100644
--- a/Master/texmf-dist/tex/context/base/math-stc.mkvi
+++ b/Master/texmf-dist/tex/context/base/math-stc.mkvi
@@ -16,6 +16,12 @@
\unprotect
+%D WARNING: If the code here changes, the export needs to be checked! Stackers are rather
+%D special because the order in mathml matters, so we flush in [base under over] order. We
+%D also do some analysis at the \TEX\ end (passing the right variant). It's easy in the
+%D export to deal with it but in the pdf stream less trivial as we don't actually analyze
+%D there.
+
%D At some point the \MKII\ arrow mechanism has been converted to \MKIV, but we kept
%D most of the logic. We now have a more generic variant dealing with extensibles.
%D There are a few demands than we need to meet:
@@ -78,7 +84,7 @@
{\mathstylehbox{\usemathstackerscolorparameter\c!color
\Umathaccent\fam\zerocount\scratchunicode{\hskip\hsize}}}
-% these delimiters are a unuseable as theu don't center for small arguments:
+% these delimiters are a unuseable as they don't center for small arguments:
%
% $\Umathaccent 0 0 "2190{x}$ \par $\Umathaccent 0 0 "27F8{x}$\par
% $\Udelimiterunder 0 "2190{x}$ \par $\Udelimiterunder 0 "27F8{x}$\par
@@ -121,6 +127,18 @@
\def\math_stackers_skip_indeed#amount%
{\filledhboxk{\unsetteststrut\strut\hskip#amount}} % \dontshowstruts
+\let\math_stackers_start_tagged_mid\relax
+\let\math_stackers_start_tagged_top\relax
+\let\math_stackers_start_tagged_bot\relax
+\let\math_stackers_stop_tagged \relax
+
+\appendtoks
+ \def\math_stackers_start_tagged_mid{\dostarttagged\t!mathstackermid\empty\hbox\bgroup}%
+ \def\math_stackers_start_tagged_top{\dostarttagged\t!mathstackertop\empty\hbox\bgroup}%
+ \def\math_stackers_start_tagged_bot{\dostarttagged\t!mathstackerbot\empty\hbox\bgroup}%
+ \def\math_stackers_stop_tagged {\egroup\dostoptagged}%
+\to \everysetuptagging
+
%D We define a full featured command handler.
\installcorenamespace {mathstackers}
@@ -139,9 +157,10 @@
\c!mpoffset=.25\exheight,
\c!voffset=.25\exheight,
\c!hoffset=.5\emwidth,
+ \c!distance=\mathstackersparameter\c!voffset, % distance between symbol and base (can be different from voffset)
\c!minheight=\exheight,
\c!mindepth=\zeropoint,
- \c!minwidth=\emwidth,
+ \c!minwidth=.5\emwidth,
\c!order=\v!normal,
\c!strut=,
\c!color=, % todo: when I need it
@@ -203,11 +222,11 @@
\setvalue{\??mathstackersalternative\v!mp}%
{\hbox\bgroup % todo: add code key + tag
- \edef\overlaywidth {\the\scratchwidth}%
- \edef\overlayheight {\the\dimexpr\mathstackersparameter\c!mpheight}%
- \edef\overlaydepth {\the\dimexpr\mathstackersparameter\c!mpdepth}%
- \edef\overlayoffset {\the\dimexpr\mathstackersparameter\c!mpoffset}%
- \edef\overlaylinewidth{\the\linewidth}%
+ \d_overlay_width \scratchwidth
+ \d_overlay_height \dimexpr\mathstackersparameter\c!mpheight
+ \d_overlay_depth \dimexpr\mathstackersparameter\c!mpdepth
+ \d_overlay_offset \dimexpr\mathstackersparameter\c!mpoffset
+ \d_overlay_linewidth\linewidth
\edef\overlaylinecolor{\mathstackersparameter\c!color}%
\edef\p_mp{\mathstackersparameter\c!mp}%
\uniqueMPgraphic{\p_mp}%
@@ -261,9 +280,11 @@
\fi}
\unexpanded\def\math_stackers_triplet#method#category#codepoint#toptext#bottomtext%
+ %{\math_stackers_start_group{#category}%
{\begingroup
\edef\currentmathstackers{#category}%
\mathstackersparameter\c!left\relax
+ \dostarttagged\t!mathstacker\currentmathstackers
\ifmmode\math_class_by_parameter\mathstackersparameter\else\dontleavehmode\fi
{\edef\p_offset {\mathstackersparameter\c!offset}%
\edef\p_location {\mathstackersparameter\c!location}%
@@ -311,7 +332,11 @@
\fi
\scratchwidth\wd
\ifdim\wd\scratchboxone>\wd\scratchboxtwo
- \scratchboxone
+ \ifdim\wd\scratchboxone>\wd\scratchboxthree
+ \scratchboxone
+ \else
+ \scratchboxthree
+ \fi
\else\ifdim\wd\scratchboxtwo>\wd\scratchboxthree
\scratchboxtwo
\else
@@ -327,7 +352,9 @@
\advance\scratchwidth2\scratchhoffset
%
\ifcase#method\relax
+ \dostarttagged\t!mathstackermid\empty
\setbox\scratchboxthree\csname\??mathstackersalternative\p_alternative\endcsname
+ \dostoptagged
\fi
%
\ifdim\wd\scratchboxone<\scratchwidth
@@ -370,30 +397,54 @@
\fi
%
\math_stackers_normalize_three
- %
- \math_stackers_middle\bgroup
- \box\scratchboxthree
- \egroup
- %
- \ifdim\htdp\scratchboxone>\zeropoint
- \scratchoffset\dimexpr\scratchvoffset
- \kern-\scratchwidth
- \math_stackers_top\bgroup
- \raise\dimexpr\dp\scratchboxone+\scratchheight+\scratchoffset+\scratchtopoffset\relax
- \box\scratchboxone
+ % analysis
+ \ifdim\htdp\scratchboxtwo>\zeropoint
+ \ifdim\htdp\scratchboxone>\zeropoint
+ \dosettagproperty\s!subtype\t!munderover
+ \else
+ \dosettagproperty\s!subtype\t!munder
+ \fi
+ \else
+ \ifdim\htdp\scratchboxone>\zeropoint
+ \dosettagproperty\s!subtype\t!mover
+ \else
+ % brrr
+ \fi
+ \fi
+ % base
+ \math_stackers_start_tagged_mid
+ \math_stackers_middle\bgroup
+ \box\scratchboxthree
\egroup
+ \math_stackers_stop_tagged
+ % under
+ \ifdim\htdp\scratchboxtwo>\zeropoint
+ \math_stackers_start_tagged_bot
+ \scratchoffset\scratchvoffset
+ \kern-\scratchwidth
+ \math_stackers_bottom\bgroup
+ \lower\dimexpr\ht\scratchboxtwo+\scratchdepth+\scratchoffset+\scratchbottomoffset\relax
+ \box\scratchboxtwo
+ \egroup
+ \math_stackers_stop_tagged
+ \fi
+ % over
+ \ifdim\htdp\scratchboxone>\zeropoint
+ \math_stackers_start_tagged_top
+ \scratchoffset\scratchvoffset
+ \kern-\scratchwidth
+ \math_stackers_top\bgroup
+ \raise\dimexpr\dp\scratchboxone+\scratchheight+\scratchoffset+\scratchtopoffset\relax
+ \box\scratchboxone
+ \egroup
+ \math_stackers_stop_tagged
\fi
%
- \ifdim\htdp\scratchboxtwo>\zeropoint
- \scratchoffset\dimexpr\scratchvoffset
- \kern-\scratchwidth
- \math_stackers_bottom\bgroup
- \lower\dimexpr\ht\scratchboxtwo+\scratchdepth+\scratchoffset+\scratchbottomoffset\relax
- \box\scratchboxtwo
- \egroup
- \fi}%
+ }%
+ \dostoptagged
\mathstackersparameter\c!right\relax
\endgroup}
+ %\math_stackers_start_group}
\unexpanded\def\definemathextensible
{\dotripleempty\math_stackers_define_normal}
@@ -449,13 +500,25 @@
\def\math_class_by_parameter_indeed#1%
{\csname\??mathclasses\ifcsname\??mathclasses#1\endcsname#1\fi\endcsname}
-\unexpanded\def\math_stackers_make_double#top#bottom#category#codepoint#codeextra#text%
+% 1 0 name n 0 | 0 1 name n 0 | 1 1 name n n
+
+\unexpanded\def\math_stackers_start_group#category%
{\begingroup
\edef\currentmathstackers{#category}%
+ \edef\p_limits{\mathstackersparameter\c!mathlimits}%
+ \ifx\p_limits\v!yes
+ \def\math_stackers_stop_group{\egroup\endgroup\limits}%
+ \mathop\bgroup
+ \else
+ \let\math_stackers_stop_group\endgroup
+ \fi}
+
+\unexpanded\def\math_stackers_make_double#top#bottom#category#codepoint#codeextra#text%
+ {\math_stackers_start_group{#category}%
\mathstackersparameter\c!left\relax
+ \dostarttagged\t!mathstacker\currentmathstackers
\ifmmode\math_class_by_parameter\mathstackersparameter\else\dontleavehmode\fi
- {\edef\currentmathstackers{#category}%
- \edef\m_math_stackers_text_middle {#text}%
+ {\edef\m_math_stackers_text_middle {#text}%
%
\edef\p_offset {\mathstackersparameter\c!offset}%
\edef\p_location {\mathstackersparameter\c!location}%
@@ -467,7 +530,7 @@
%
\math_stackers_check_unicode{#codepoint}%
%
- \ifx\currentmathtext\empty
+ \ifx\math_stackers_middle\empty
\setbox\scratchboxthree\emptyhbox
\else
\setmathtextbox\scratchboxthree\hbox{\math_stackers_middletext}%
@@ -480,44 +543,74 @@
\fi
\advance\scratchwidth2\scratchhoffset
%
- \setbox\scratchboxtwo \csname\??mathstackersalternative\p_alternative\endcsname
+ \setbox\scratchboxtwo\csname\??mathstackersalternative\p_alternative\endcsname
\setbox\scratchboxthree\hbox to \scratchwidth{\hss\box\scratchboxthree\hss}%
%
- \math_stackers_normalize_three
+ \scratchunicode#codeextra\relax
+ \ifcase\scratchunicode\else
+ \setbox\scratchboxone\csname\??mathstackersalternative\p_alternative\endcsname
+ \fi
%
- \math_stackers_middle\bgroup
- \box\scratchboxthree
- \egroup
+ \math_stackers_normalize_three
+ % analysis
+ \ifcase#bottom\relax
+ \ifcase#top\relax
+ \dosettagproperty\s!subtype\t!munderover
+ \else
+ \dosettagproperty\s!subtype\t!mover
+ \fi
+ \else
+ \ifcase#top\relax
+ \dosettagproperty\s!subtype\t!munder
+ \else
+ % brrr
+ \fi
+ \fi
+ % base
+ \math_stackers_start_tagged_mid
+ \math_stackers_middle\bgroup
+ \box\scratchboxthree
+ \egroup
+ \math_stackers_stop_tagged
%
\ifdim\htdp\scratchboxtwo>\zeropoint
- \kern-\scratchwidth
- \ifcase#top\else
- \math_stackers_top\bgroup
- % \raise\dimexpr\scratchheight+\scratchtopoffset\relax
- \raise\dimexpr\scratchheight+\mathstackersparameter\c!voffset\relax
- \box\scratchboxtwo
- \egroup
- \fi
- \scratchunicode#codeextra\relax
- \ifcase\scratchunicode\else
+ \ifcase#bottom\else
\kern-\scratchwidth
- \setbox\scratchboxtwo\csname\??mathstackersalternative\p_alternative\endcsname
+ % under
+ \math_stackers_start_tagged_bot
+ \math_stackers_bottom\bgroup
+ \lower\dimexpr
+ \scratchdepth
+ +\ht\scratchboxtwo
+ +\mathstackersparameter\c!distance % was \c!voffset
+ \relax
+ \ifcase#top\relax
+ \box\scratchboxtwo
+ \else
+ \box\scratchboxone
+ \fi
+ \egroup
+ \math_stackers_stop_tagged
\fi
- \ifcase#bottom\else
- \math_stackers_bottom\bgroup
- % \lower\dimexpr\scratchdepth+\ht\scratchboxtwo+\scratchbottomoffset\relax
- \lower\dimexpr\scratchdepth+\ht\scratchboxtwo+\mathstackersparameter\c!voffset\relax
- \box\scratchboxtwo
- \egroup
+ \ifcase#top\else
+ \kern-\scratchwidth
+ % over
+ \math_stackers_start_tagged_top
+ \math_stackers_top\bgroup
+ \raise\dimexpr
+ \scratchheight
+ +\dp\scratchboxtwo % new
+ +\mathstackersparameter\c!distance % was \c!voffset
+ \relax
+ \box\scratchboxtwo
+ \egroup
+ \math_stackers_stop_tagged
\fi
+ %
\fi}%
+ \dostoptagged
\mathstackersparameter\c!right\relax
- \edef\p_limits{\mathstackersparameter\c!mathlimits}%
- \ifx\p_limits\v!yes
- \expandafter\endgroup\expandafter\limits
- \else
- \expandafter\endgroup
- \fi}
+ \math_stackers_stop_group}
\unexpanded\def\definemathoverextensible {\dotripleempty \math_extensibles_define_over }
\unexpanded\def\definemathunderextensible {\dotripleempty \math_extensibles_define_under}
@@ -551,14 +644,173 @@
\def\math_stackers_handle_over[#category]%
{\math_stackers_direct_double\plusone\zerocount{\iffirstargument#category\else\v!top \fi}} % will be defined later on
-\def\math_stackers_handle_under[#category]#codepoint#bottomtext%
+\def\math_stackers_handle_under[#category]%
{\math_stackers_direct_double\zerocount\plusone{\iffirstargument#category\else\v!bottom\fi}} % will be defined later on
-\def\math_stackers_handle_double[#category]#codepoint#bottomtext%
+\def\math_stackers_handle_double[#category]%
{\math_stackers_direct_double\plusone\plusone {\iffirstargument#category\else\v!bottom\fi}} % will be defined later on
\def\math_stackers_direct_double#top#bottom#category#codepoint#text%
- {\math_stackers_make_double#top#bottom{#category}{#codepoint}{#text}%
+ {\math_stackers_make_double#top#bottom{#category}{#codepoint}{0}{#text}%
+ \endgroup}
+
+%D A relative new one is a combination of accents and text (as needed in mathml):
+
+\unexpanded\def\math_stackers_make_double_text#where#category#codepoint#text#extra%
+ {\math_stackers_start_group{#category}%
+ \mathstackersparameter\c!left\relax
+ \dostarttagged\t!mathstacker\currentmathstackers
+ \ifmmode\math_class_by_parameter\mathstackersparameter\else\dontleavehmode\fi
+ {\edef\currentmathstackers{#category}%
+ %
+ \edef\p_offset {\mathstackersparameter\c!offset}%
+ \edef\p_location {\mathstackersparameter\c!location}%
+ \edef\p_strut {\mathstackersparameter\c!strut}%
+ \edef\p_alternative{\mathstackersparameter\c!alternative}%
+ %
+ \scratchleftoffset \zeropoint
+ \scratchrightoffset\zeropoint
+ %
+ \edef\m_math_stackers_text_middle{#text}%
+ \math_stackers_check_unicode{#codepoint}%
+ \scratchunicode#codepoint\relax
+ %
+ \ifx\math_stackers_middle\empty
+ \setbox\scratchboxthree\emptyhbox
+ \else
+ \setmathtextbox\scratchboxthree\hbox{\math_stackers_middletext}%
+ \fi
+ %
+ \ifcase#where\relax
+ \edef\m_math_stackers_text_top{#extra}%
+ \ifx\math_stackers_top\empty
+ \setbox\scratchboxone\emptyhbox
+ \else
+ \setmathsmalltextbox\scratchboxone\hbox{\math_stackers_toptext}%
+ \fi
+ \else
+ \edef\m_math_stackers_text_bottom{#extra}%
+ \ifx\math_stackers_bottom\empty
+ \setbox\scratchboxone\emptyhbox
+ \else
+ \setmathsmalltextbox\scratchboxone\hbox{\math_stackers_bottomtext}%
+ \fi
+ \fi
+ %
+ \scratchwidth\wd
+ \ifdim\wd\scratchboxone>\wd\scratchboxthree
+ \scratchboxone
+ \else
+ \scratchboxthree
+ \fi
+ \relax
+ \scratchdimen\mathstackersparameter\c!minwidth\relax
+ \ifdim\scratchwidth<\scratchdimen
+ \scratchwidth\scratchdimen
+ \fi
+ \advance\scratchwidth2\scratchhoffset
+ %
+ \ifdim\wd\scratchboxone<\scratchwidth
+ \setbox\scratchboxone\hbox to \scratchwidth{\hss\unhbox\scratchboxone\hss}%
+ \fi
+ \ifdim\wd\scratchboxthree<\scratchwidth
+ \setbox\scratchboxthree\hbox to \scratchwidth{\hss\unhbox\scratchboxthree\hss}%
+ \fi
+ %
+ \math_stackers_normalize_three
+ % analysis
+ \dosettagproperty\s!subtype\t!munderover
+ % base
+ \math_stackers_start_tagged_mid
+ \math_stackers_middle\bgroup
+ \box\scratchboxthree
+ \egroup
+ \math_stackers_stop_tagged
+ %
+ \setbox\scratchboxtwo\csname\??mathstackersalternative\p_alternative\endcsname
+ \kern-\scratchwidth
+ \ifcase#where\relax
+ % under
+ \math_stackers_start_tagged_bot
+ \math_stackers_bottom\bgroup
+ \lower\dimexpr
+ \scratchdepth
+ +\ht\scratchboxtwo
+ +\mathstackersparameter\c!distance
+ \relax
+ \box\scratchboxtwo % accent
+ \egroup
+ \math_stackers_stop_tagged
+ \kern-\scratchwidth
+ % over
+ \math_stackers_start_tagged_top
+ \math_stackers_top\bgroup
+ \raise\dimexpr
+ \scratchheight
+ +\dp\scratchboxone
+ +\mathstackersparameter\c!voffset
+ \relax
+ \box\scratchboxone % toptext
+ \egroup
+ \math_stackers_stop_tagged
+ \else
+ % under
+ \math_stackers_start_tagged_bot
+ \math_stackers_bottom\bgroup
+ \lower\dimexpr
+ \scratchdepth
+ +\ht\scratchboxone
+ +\mathstackersparameter\c!voffset
+ \relax
+ \box\scratchboxone % bottext
+ \egroup
+ \math_stackers_stop_tagged
+ \kern-\scratchwidth
+ % over
+ \math_stackers_start_tagged_top
+ \math_stackers_top\bgroup
+ \raise\dimexpr
+ \scratchheight
+ +\dp\scratchboxtwo % new
+ +\mathstackersparameter\c!distance
+ \relax
+ \box\scratchboxtwo % accent
+ \egroup
+ \math_stackers_stop_tagged
+ \fi
+ }%
+ \dostoptagged
+ \mathstackersparameter\c!right\relax
+ \math_stackers_stop_group}
+
+\unexpanded\def\definemathovertextextensible {\dotripleempty\math_extensibles_define_over_text }
+\unexpanded\def\definemathundertextextensible{\dotripleempty\math_extensibles_define_under_text}
+
+\def\math_extensibles_define_over_text[#1][#2][#3]%
+ {\ifthirdargument
+ \setuevalue{#2}{\math_stackers_make_double_text\plusone {#1}{\number#3}}%
+ \else
+ \setuevalue{#1}{\math_stackers_make_double_text\plusone \noexpand\currentmathstackers{\number#2}}%
+ \fi}
+
+\def\math_extensibles_define_under_text[#1][#2][#3]%
+ {\ifthirdargument
+ \setuevalue{#2}{\math_stackers_make_double_text\zerocount{#1}{\number#3}}%
+ \else
+ \setuevalue{#1}{\math_stackers_make_double_text\zerocount\noexpand\currentmathstackers{\number#2}}%
+ \fi}
+
+\unexpanded\def\mathovertext {\begingroup\dosingleempty\math_stackers_handle_over_text }
+\unexpanded\def\mathundertext{\begingroup\dosingleempty\math_stackers_handle_under_text }
+
+\def\math_stackers_handle_over_text[#category]%
+ {\math_stackers_direct_double_text\plusone {\iffirstargument#category\else\v!top \fi}} % will be defined later on
+
+\def\math_stackers_handle_under_text[#category]%
+ {\math_stackers_direct_double_text\zerocount{\iffirstargument#category\else\v!bottom\fi}} % will be defined later on
+
+\def\math_stackers_direct_double_text#where#category#codepoint#text#extra%%
+ {\math_stackers_make_double_text#where{#category}{#codepoint}{#text}{#extra}%
\endgroup}
%D Here is a bonus macro that takes three texts. It can be used to get consistent
@@ -654,11 +906,23 @@
[\v!both]
\definemathstackers
- [vfenced]
+ [\v!vfenced]
[\v!both]
[\c!mathclass=\s!ord,
\c!mathlimits=\v!yes]
+% these are needed for mathml:
+
+% \setupmathstackers
+% [\v!both]
+% [\c!hoffset=1pt,
+% \c!voffset=1pt]
+
+\definemathstackers
+ [\v!bothtext]
+ [\v!both]
+ [\c!strut=\v!yes]
+
% These are compatibity definitions, math only.
% todo: top= bottom= middle= is nicer (compare math-fen)
@@ -761,6 +1025,24 @@
\definemathextensible [\v!mathematics] [mrightleftharpoons] ["21CC]
\definemathextensible [\v!mathematics] [mtriplerel] ["2261]
+\definemathextensible [\v!mathematics] [eleftarrowfill] ["2190] % ["27F5]
+\definemathextensible [\v!mathematics] [erightarrowfill] ["2192] % ["27F6]
+\definemathextensible [\v!mathematics] [eleftrightarrowfill] ["27F7]
+\definemathextensible [\v!mathematics] [etwoheadrightarrowfill] ["27F9]
+\definemathextensible [\v!mathematics] [eleftharpoondownfill] ["21BD]
+\definemathextensible [\v!mathematics] [eleftharpoonupfill] ["21BC]
+\definemathextensible [\v!mathematics] [erightharpoondownfill] ["21C1]
+\definemathextensible [\v!mathematics] [erightharpoonupfill] ["21C0]
+
+\definemathextensible [\v!mathematics] [eoverbarfill] ["FE33E]
+\definemathextensible [\v!mathematics] [eunderbarfill] ["FE33F]
+\definemathextensible [\v!mathematics] [eoverbracefill] ["FE3DE]
+\definemathextensible [\v!mathematics] [eunderbracefill] ["FE3DF]
+\definemathextensible [\v!mathematics] [eoverparentfill] ["FE3DC]
+\definemathextensible [\v!mathematics] [eunderparentfill] ["FE3DD]
+\definemathextensible [\v!mathematics] [eoverbracketfill] ["FE3B4]
+\definemathextensible [\v!mathematics] [eunderbracketfill] ["FE3B5]
+
\definemathextensible [\v!text] [trel] ["002D]
\definemathextensible [\v!text] [tequal] ["003D]
\definemathextensible [\v!text] [tmapsto] ["21A6]
@@ -819,23 +1101,39 @@
% alternatively we can move the original to FE*
\definemathoverextensible [vfenced] [overbar] ["FE33E] % ["203E]
-\definemathunderextensible [vfenced] [underbar] ["FE33F] % ["203E]
+\definemathunderextensible [vfenced] [underbar] ["FE33F] % ["203E]
\definemathdoubleextensible [vfenced] [doublebar] ["FE33E] ["FE33F]
\definemathoverextensible [vfenced] [overbrace] ["FE3DE] % ["023DE]
-\definemathunderextensible [vfenced] [underbrace] ["FE3DF] % ["023DF]
+\definemathunderextensible [vfenced] [underbrace] ["FE3DF] % ["023DF]
\definemathdoubleextensible [vfenced] [doublebrace] ["FE3DE] ["FE3DF]
\definemathoverextensible [vfenced] [overparent] ["FE3DC] % ["023DC]
-\definemathunderextensible [vfenced] [underparent] ["FE3DD] % ["023DD]
+\definemathunderextensible [vfenced] [underparent] ["FE3DD] % ["023DD]
\definemathdoubleextensible [vfenced] [doubleparent] ["FE3DC] ["FE3DD]
\definemathoverextensible [vfenced] [overbracket] ["FE3B4] % ["023B4]
-\definemathunderextensible [vfenced] [underbracket] ["FE3B5] % ["023B5]
+\definemathunderextensible [vfenced] [underbracket] ["FE3B5] % ["023B5]
\definemathdoubleextensible [vfenced] [doublebracket] ["FE3B4] ["FE3B5]
% \unexpanded\def\mathopwithlimits#1#2{\mathop{#1{#2}}\limits}
+%D For mathml:
+
+\definemathdoubleextensible [both] [overbarunderbar] ["FE33E] ["FE33F]
+\definemathdoubleextensible [both] [overbraceunderbrace] ["FE3DE] ["FE3DF]
+\definemathdoubleextensible [both] [overparentunderparent] ["FE3DC] ["FE3DD]
+\definemathdoubleextensible [both] [overbracketunderbracket] ["FE3B4] ["FE3B5]
+
+\definemathovertextextensible [bothtext] [overbartext] ["FE33E]
+\definemathundertextextensible [bothtext] [underbartext] ["FE33F]
+\definemathovertextextensible [bothtext] [overbracetext] ["FE3DE]
+\definemathundertextextensible [bothtext] [underbracetext] ["FE3DF]
+\definemathovertextextensible [bothtext] [overparenttext] ["FE3DC]
+\definemathundertextextensible [bothtext] [underparenttext] ["FE3DD]
+\definemathovertextextensible [bothtext] [overbrackettext] ["FE3B4]
+\definemathundertextextensible [bothtext] [underbrackettext] ["FE3B5]
+
%D Some bonus ones (for the moment here):
\definemathstackers
@@ -927,6 +1225,15 @@
\defineextensiblefiller [Leftrightarrowfill] ["27FA]
\defineextensiblefiller [Leftrightarrowfill] ["27FA]
+%defineextensiblefiller [overbarfill] ["FE33E] % untested
+%defineextensiblefiller [underbarfill] ["FE33F] % untested
+\defineextensiblefiller [overbracefill] ["FE3DE] % untested
+\defineextensiblefiller [underbracefill] ["FE3DF] % untested
+\defineextensiblefiller [overparentfill] ["FE3DC] % untested
+\defineextensiblefiller [underparentfill] ["FE3DD] % untested
+\defineextensiblefiller [overbracketfill] ["FE3B4] % untested
+\defineextensiblefiller [underbracketfill] ["FE3B5] % untested
+
%D Extra:
\unexpanded\edef\singlebond{\mathematics{\mathsurround\zeropoint\char\number"002D}}
diff --git a/Master/texmf-dist/tex/context/base/math-tag.lua b/Master/texmf-dist/tex/context/base/math-tag.lua
index 3cd4cae16eb..61d28edde61 100644
--- a/Master/texmf-dist/tex/context/base/math-tag.lua
+++ b/Master/texmf-dist/tex/context/base/math-tag.lua
@@ -6,10 +6,12 @@ if not modules then modules = { } end modules ['math-tag'] = {
license = "see context related readme files"
}
+-- todo: have a local list with local tags that then get appended
+
-- use lpeg matchers
local find, match = string.find, string.match
-local insert, remove = table.insert, table.remove
+local insert, remove, concat = table.insert, table.remove, table.concat
local attributes = attributes
local nodes = nodes
@@ -22,6 +24,7 @@ local getid = nuts.getid
local getchar = nuts.getchar
local getlist = nuts.getlist
local getfield = nuts.getfield
+local getsubtype = nuts.getsubtype
local getattr = nuts.getattr
local setattr = nuts.setattr
@@ -43,15 +46,32 @@ local math_style_code = nodecodes.style -- attr style
local math_choice_code = nodecodes.choice -- attr display text script scriptscript
local math_fence_code = nodecodes.fence -- attr subtype
+local accentcodes = nodes.accentcodes
+
+local math_fixed_top = accentcodes.fixedtop
+local math_fixed_bottom = accentcodes.fixedbottom
+local math_fixed_both = accentcodes.fixedboth
+
+local kerncodes = nodes.kerncodes
+
+local fontkern_code = kerncodes.fontkern
+
local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
local glyph_code = nodecodes.glyph
+local disc_code = nodecodes.disc
local glue_code = nodecodes.glue
+local kern_code = nodecodes.kern
+local math_code = nodecodes.math
+
+local processnoads = noads.process
local a_tagged = attributes.private('tagged')
+local a_taggedpar = attributes.private('taggedpar')
local a_exportstatus = attributes.private('exportstatus')
local a_mathcategory = attributes.private('mathcategory')
local a_mathmode = attributes.private('mathmode')
+local a_fontkern = attributes.private('fontkern')
local tags = structures.tags
@@ -67,33 +87,53 @@ local mathcodes = mathematics.codes
local ordinary_code = mathcodes.ordinary
local variable_code = mathcodes.variable
+local fromunicode16 = fonts.mappings.fromunicode16
+local font_of_family = node.family_font
+local fontcharacters = fonts.hashes.characters
+
+local report_tags = logs.reporter("structure","tags")
+
local process
local function processsubsup(start)
-- At some point we might need to add an attribute signaling the
-- super- and subscripts because TeX and MathML use a different
- -- order.
+ -- order. The mrows are needed to keep mn's separated.
local nucleus = getfield(start,"nucleus")
local sup = getfield(start,"sup")
local sub = getfield(start,"sub")
if sub then
if sup then
setattr(start,a_tagged,start_tagged("msubsup"))
+ -- start_tagged("mrow")
process(nucleus)
+ -- stop_tagged()
+ start_tagged("mrow")
process(sub)
+ stop_tagged()
+ start_tagged("mrow")
process(sup)
stop_tagged()
+ stop_tagged()
else
setattr(start,a_tagged,start_tagged("msub"))
+ -- start_tagged("mrow")
process(nucleus)
+ -- stop_tagged()
+ start_tagged("mrow")
process(sub)
stop_tagged()
+ stop_tagged()
end
elseif sup then
setattr(start,a_tagged,start_tagged("msup"))
+ -- start_tagged("mrow")
process(nucleus)
+ -- stop_tagged()
+ start_tagged("mrow")
process(sup)
stop_tagged()
+ stop_tagged()
else
process(nucleus)
end
@@ -104,263 +144,407 @@ end
-- todo: variants -> original
local actionstack = { }
+local fencesstack = { }
+
+-- glyph nodes and such can happen in under and over stuff
+
+local function getunicode(n) -- instead of getchar
+ local char = getchar(n)
+ local font = font_of_family(getfield(n,"fam")) -- font_of_family
+ local data = fontcharacters[font][char]
+ return data.unicode or char
+end
+
+-------------------
+
+local content = { }
+local found = false
+
+content[math_char_code] = function() found = true end
+
+local function hascontent(head)
+ found = false
+ processnoads(head,content,"content")
+ return found
+end
+
+--------------------
+
+local function showtag(n,id)
+ local attr = getattr(n,a_tagged)
+ report_tags("%s = %s",nodecodes[id or getid(n)],attr and taglist[attr].tagname or "?")
+end
process = function(start) -- we cannot use the processor as we have no finalizers (yet)
+ local mtexttag = nil
while start do
local id = getid(start)
- if id == math_char_code then
- local char = getchar(start)
- -- check for code
- local a = getattr(start,a_mathcategory)
- if a then
- a = { detail = a }
+
+-- showtag(start,id)
+
+ if id == glyph_code or id == disc_code then
+ if not mtexttag then
+ mtexttag = start_tagged("mtext")
end
- local code = getmathcode(char)
- if code then
- code = code[1]
+ setattr(start,a_tagged,mtexttag)
+ elseif mtexttag and id == kern_code and (getsubtype(start) == fontkern_code or getattr(start,a_fontkern)) then
+ setattr(start,a_tagged,mtexttag)
+ else
+ if mtexttag then
+ stop_tagged()
+ mtexttag = nil
end
- local tag
- if code == ordinary_code or code == variable_code then
- local ch = chardata[char]
- local mc = ch and ch.mathclass
- if mc == "number" then
- tag = "mn"
- elseif mc == "variable" or not mc then -- variable is default
- tag = "mi"
+ if id == math_char_code then
+ local char = getchar(start)
+ local code = getmathcode(char)
+ if code then
+ code = code[1]
+ end
+ local tag
+ if code == ordinary_code or code == variable_code then
+ local ch = chardata[char]
+ local mc = ch and ch.mathclass
+ if mc == "number" then
+ tag = "mn"
+ elseif mc == "variable" or not mc then -- variable is default
+ tag = "mi"
+ else
+ tag = "mo"
+ end
else
tag = "mo"
end
- else
- tag = "mo"
- end
- setattr(start,a_tagged,start_tagged(tag,a))
- stop_tagged()
- break -- okay?
- elseif id == math_textchar_code then
- -- check for code
- local a = getattr(start,a_mathcategory)
- if a then
- setattr(start,a_tagged,start_tagged("ms",{ detail = a }))
- else
- setattr(start,a_tagged,start_tagged("ms"))
- end
- stop_tagged()
- break
- elseif id == math_delim_code then
- -- check for code
- setattr(start,a_tagged,start_tagged("mo"))
- stop_tagged()
- break
- elseif id == math_style_code then
- -- has a next
- elseif id == math_noad_code then
- processsubsup(start)
- elseif id == math_box_code or id == hlist_code or id == vlist_code then
- -- keep an eye on math_box_code and see what ends up in there
- local attr = getattr(start,a_tagged)
- local last = attr and taglist[attr]
- if last and find(last[#last],"formulacaption[:%-]") then
- -- leave alone, will nicely move to the outer level
- else
- local text = start_tagged("mtext")
- setattr(start,a_tagged,text)
- local list = getfield(start,"list")
- if not list then
- -- empty list
- elseif not attr then
- -- box comes from strange place
- set_attributes(list,a_tagged,text)
+ local a = getattr(start,a_mathcategory)
+ if a then
+ setattr(start,a_tagged,start_tagged(tag,{ mathcategory = a }))
else
- -- Beware, the first node in list is the actual list so we definitely
- -- need to nest. This approach is a hack, maybe I'll make a proper
- -- nesting feature to deal with this at another level. Here we just
- -- fake structure by enforcing the inner one.
- local tagdata = taglist[attr]
- local common = #tagdata + 1
- local function runner(list) -- quite inefficient
- local cache = { } -- we can have nested unboxed mess so best local to runner
- for n in traverse_nodes(list) do
- local id = getid(n)
- local aa = getattr(n,a_tagged)
- if aa then
- local ac = cache[aa]
- if not ac then
- local tagdata = taglist[aa]
- local extra = #tagdata
- if common <= extra then
- for i=common,extra do
- ac = restart_tagged(tagdata[i]) -- can be made faster
- end
- for i=common,extra do
- stop_tagged() -- can be made faster
+ setattr(start,a_tagged,start_tagged(tag)) -- todo: a_mathcategory
+ end
+ stop_tagged()
+ break -- okay?
+ elseif id == math_textchar_code then -- or id == glyph_code
+ -- check for code
+ local a = getattr(start,a_mathcategory)
+ if a then
+ setattr(start,a_tagged,start_tagged("ms",{ mathcategory = a })) -- mtext
+ else
+ setattr(start,a_tagged,start_tagged("ms")) -- mtext
+ end
+ stop_tagged()
+ break
+ elseif id == math_delim_code then
+ -- check for code
+ setattr(start,a_tagged,start_tagged("mo"))
+ stop_tagged()
+ break
+ elseif id == math_style_code then
+ -- has a next
+ elseif id == math_noad_code then
+ processsubsup(start)
+ elseif id == math_box_code or id == hlist_code or id == vlist_code then
+ -- keep an eye on math_box_code and see what ends up in there
+ local attr = getattr(start,a_tagged)
+ local specification = taglist[attr]
+ local tag = specification.tagname
+ if tag == "formulacaption" then
+ -- skip
+ elseif tag == "mstacker" then
+ local list = getfield(start,"list")
+ if list then
+ process(list)
+ end
+ else
+ if tag ~= "mstackertop" and tag ~= "mstackermid" and tag ~= "mstackerbot" then
+ tag = "mtext"
+ end
+ local text = start_tagged(tag)
+ setattr(start,a_tagged,text)
+ local list = getfield(start,"list")
+ if not list then
+ -- empty list
+ elseif not attr then
+ -- box comes from strange place
+ set_attributes(list,a_tagged,text) -- only the first node ?
+ else
+ -- Beware, the first node in list is the actual list so we definitely
+ -- need to nest. This approach is a hack, maybe I'll make a proper
+ -- nesting feature to deal with this at another level. Here we just
+ -- fake structure by enforcing the inner one.
+ --
+ -- todo: have a local list with local tags that then get appended
+ --
+ local tagdata = specification.taglist
+ local common = #tagdata + 1
+ local function runner(list,depth) -- quite inefficient
+ local cache = { } -- we can have nested unboxed mess so best local to runner
+ local keep = nil
+ -- local keep = { } -- win case we might need to move keep outside
+ for n in traverse_nodes(list) do
+ local id = getid(n)
+ local mth = id == math_code and getsubtype(n)
+ if mth == 0 then
+ -- insert(keep,text)
+ keep = text
+ text = start_tagged("mrow")
+ common = common + 1
+ end
+ local aa = getattr(n,a_tagged)
+ if aa then
+ local ac = cache[aa]
+ if not ac then
+ local tagdata = taglist[aa].taglist
+ local extra = #tagdata
+ if common <= extra then
+ for i=common,extra do
+ ac = restart_tagged(tagdata[i]) -- can be made faster
+ end
+ for i=common,extra do
+ stop_tagged() -- can be made faster
+ end
+ else
+ ac = text
end
- else
- ac = text
+ cache[aa] = ac
end
- cache[aa] = ac
+ setattr(n,a_tagged,ac)
+ else
+ setattr(n,a_tagged,text)
+ end
+
+ if id == hlist_code or id == vlist_code then
+ runner(getlist(n),depth+1)
+ elseif id == glyph_code then
+ runner(getfield(n,"components"),depth+1) -- this should not be needed
+ elseif id == disc_node then
+ runner(getfield(n,"pre"),depth+1) -- idem
+ runner(getfield(n,"post"),depth+1) -- idem
+ runner(getfield(n,"replace"),depth+1) -- idem
+ end
+ if mth == 1 then
+ stop_tagged()
+ -- text = remove(keep)
+ text = keep
+ common = common - 1
end
- setattr(n,a_tagged,ac)
- else
- setattr(n,a_tagged,text)
- end
- if id == hlist_code or id == vlist_code then
- runner(getlist(n))
end
end
+ runner(list,0)
end
- runner(list)
+ stop_tagged()
end
- stop_tagged()
- end
- elseif id == math_sub_code then
- local list = getfield(start,"list")
- if list then
- local attr = getattr(start,a_tagged)
- local last = attr and taglist[attr]
- local action = last and match(last[#last],"maction:(.-)%-")
- if action and action ~= "" then
- if actionstack[#actionstack] == action then
+ elseif id == math_sub_code then -- normally a hbox
+ local list = getfield(start,"list")
+ if list then
+ local attr = getattr(start,a_tagged)
+ local last = attr and taglist[attr]
+ if last then
+ local tag = last.tagname
+ local detail = last.detail
+ if tag == "maction" then
+ if detail == "" then
+ setattr(start,a_tagged,start_tagged("mrow"))
+ process(list)
+ stop_tagged()
+ elseif actionstack[#actionstack] == action then
+ setattr(start,a_tagged,start_tagged("mrow"))
+ process(list)
+ stop_tagged()
+ else
+ insert(actionstack,action)
+ setattr(start,a_tagged,start_tagged("mrow",{ detail = action }))
+ process(list)
+ stop_tagged()
+ remove(actionstack)
+ end
+ elseif tag == "mstacker" then -- or tag == "mstackertop" or tag == "mstackermid" or tag == "mstackerbot" then
+ -- looks like it gets processed twice
+-- do we still end up here ?
+ setattr(start,a_tagged,restart_tagged(attr)) -- so we just reuse the attribute
+ process(list)
+ stop_tagged()
+ else
+ setattr(start,a_tagged,start_tagged("mrow"))
+ process(list)
+ stop_tagged()
+ end
+ else -- never happens, we're always document
setattr(start,a_tagged,start_tagged("mrow"))
process(list)
stop_tagged()
- else
- insert(actionstack,action)
- setattr(start,a_tagged,start_tagged("mrow",{ detail = action }))
- process(list)
- stop_tagged()
- remove(actionstack)
end
- else
- setattr(start,a_tagged,start_tagged("mrow"))
- process(list)
- stop_tagged()
end
- end
- elseif id == math_fraction_code then
- local num = getfield(start,"num")
- local denom = getfield(start,"denom")
- local left = getfield(start,"left")
- local right = getfield(start,"right")
- if left then
- setattr(left,a_tagged,start_tagged("mo"))
- process(left)
- stop_tagged()
- end
- setattr(start,a_tagged,start_tagged("mfrac"))
- process(num)
- process(denom)
- stop_tagged()
- if right then
- setattr(right,a_tagged,start_tagged("mo"))
- process(right)
+ elseif id == math_fraction_code then
+ local num = getfield(start,"num")
+ local denom = getfield(start,"denom")
+ local left = getfield(start,"left")
+ local right = getfield(start,"right")
+ if left then
+ setattr(left,a_tagged,start_tagged("mo"))
+ process(left)
+ stop_tagged()
+ end
+ setattr(start,a_tagged,start_tagged("mfrac"))
+ process(num)
+ process(denom)
stop_tagged()
- end
- elseif id == math_choice_code then
- local display = getfield(start,"display")
- local text = getfield(start,"text")
- local script = getfield(start,"script")
- local scriptscript = getfield(start,"scriptscript")
- if display then
- process(display)
- end
- if text then
- process(text)
- end
- if script then
- process(script)
- end
- if scriptscript then
- process(scriptscript)
- end
- elseif id == math_fence_code then
- local delim = getfield(start,"delim")
- local subtype = getfield(start,"subtype")
- -- setattr(start,a_tagged,start_tagged("mfenced")) -- needs checking
- if subtype == 1 then
- -- left
- if delim then
- setattr(start,a_tagged,start_tagged("mleft"))
- process(delim)
+ if right then
+ setattr(right,a_tagged,start_tagged("mo"))
+ process(right)
stop_tagged()
end
- elseif subtype == 2 then
- -- middle
- if delim then
- setattr(start,a_tagged,start_tagged("mmiddle"))
- process(delim)
+ elseif id == math_choice_code then
+ local display = getfield(start,"display")
+ local text = getfield(start,"text")
+ local script = getfield(start,"script")
+ local scriptscript = getfield(start,"scriptscript")
+ if display then
+ process(display)
+ end
+ if text then
+ process(text)
+ end
+ if script then
+ process(script)
+ end
+ if scriptscript then
+ process(scriptscript)
+ end
+ elseif id == math_fence_code then
+ local delim = getfield(start,"delim")
+ local subtype = getfield(start,"subtype")
+ if subtype == 1 then
+ -- left
+ local properties = { }
+ insert(fencesstack,properties)
+ setattr(start,a_tagged,start_tagged("mfenced",{ properties = properties })) -- needs checking
+ if delim then
+ start_tagged("ignore")
+ local chr = getfield(delim,"small_char")
+ if chr ~= 0 then
+ properties.left = chr
+ end
+ process(delim)
+ stop_tagged()
+ end
+ start_tagged("mrow") -- begin of subsequence
+ elseif subtype == 2 then
+ -- middle
+ if delim then
+ start_tagged("ignore")
+ local top = fencesstack[#fencesstack]
+ local chr = getfield(delim,"small_char")
+ if chr ~= 0 then
+ local mid = top.middle
+ if mid then
+ mid[#mid+1] = chr
+ else
+ top.middle = { chr }
+ end
+ end
+ process(delim)
+ stop_tagged()
+ end
+ stop_tagged() -- end of subsequence
+ start_tagged("mrow") -- begin of subsequence
+ elseif subtype == 3 then
+ local properties = remove(fencesstack)
+ if not properties then
+ report_tags("missing right fence")
+ properties = { }
+ end
+ if delim then
+ start_tagged("ignore")
+ local chr = getfield(delim,"small_char")
+ if chr ~= 0 then
+ properties.right = chr
+ end
+ process(delim)
+ stop_tagged()
+ end
+ stop_tagged() -- end of subsequence
stop_tagged()
+ else
+ -- can't happen
end
- elseif subtype == 3 then
- if delim then
- setattr(start,a_tagged,start_tagged("mright"))
- process(delim)
+ elseif id == math_radical_code then
+ local left = getfield(start,"left")
+ local degree = getfield(start,"degree")
+ if left then
+ start_tagged("ignore")
+ process(left) -- root symbol, ignored
stop_tagged()
end
- else
- -- can't happen
- end
- -- stop_tagged()
- elseif id == math_radical_code then
- local left = getfield(start,"left")
- local degree = getfield(start,"degree")
- if left then
- start_tagged("")
- process(left) -- root symbol, ignored
- stop_tagged()
- end
- if degree then -- not good enough, can be empty mlist
- setattr(start,a_tagged,start_tagged("mroot"))
- processsubsup(start)
- process(degree)
- stop_tagged()
- else
- setattr(start,a_tagged,start_tagged("msqrt"))
- processsubsup(start)
- stop_tagged()
- end
- elseif id == math_accent_code then
- local accent = getfield(start,"accent")
- local bot_accent = getfield(start,"bot_accent")
- if bot_accent then
- if accent then
- setattr(start,a_tagged,start_tagged("munderover",{ detail = "accent" }))
+ if degree and hascontent(degree) then
+ setattr(start,a_tagged,start_tagged("mroot"))
processsubsup(start)
- process(bot_accent)
- process(accent)
+ process(degree)
stop_tagged()
else
- setattr(start,a_tagged,start_tagged("munder",{ detail = "accent" }))
+ setattr(start,a_tagged,start_tagged("msqrt"))
processsubsup(start)
- process(bot_accent)
stop_tagged()
end
- elseif accent then
- setattr(start,a_tagged,start_tagged("mover",{ detail = "accent" }))
- processsubsup(start)
- process(accent)
+ elseif id == math_accent_code then
+ local accent = getfield(start,"accent")
+ local bot_accent = getfield(start,"bot_accent")
+ local subtype = getsubtype(start)
+ if bot_accent then
+ if accent then
+ setattr(start,a_tagged,start_tagged("munderover", {
+ accent = true,
+ top = getunicode(accent),
+ bottom = getunicode(bot_accent),
+ topfixed = subtype == math_fixed_top or subtype == math_fixed_both,
+ bottomfixed = subtype == math_fixed_bottom or subtype == math_fixed_both,
+ }))
+ processsubsup(start)
+ process(bot_accent)
+ process(accent)
+ stop_tagged()
+ else
+ setattr(start,a_tagged,start_tagged("munder", {
+ accent = true,
+ bottom = getunicode(bot_accent),
+ bottomfixed = subtype == math_fixed_bottom or subtype == math_fixed_both,
+ }))
+ processsubsup(start)
+ process(bot_accent)
+ stop_tagged()
+ end
+ elseif accent then
+ setattr(start,a_tagged,start_tagged("mover", {
+ accent = true,
+ top = getunicode(accent),
+ topfixed = subtype == math_fixed_top or subtype == math_fixed_both,
+ }))
+ processsubsup(start)
+ process(accent)
+ stop_tagged()
+ else
+ processsubsup(start)
+ end
+ elseif id == glue_code then
+ -- local spec = getfield(start,"spec")
+ -- setattr(start,a_tagged,start_tagged("mspace",{ width = getfield(spec,"width") }))
+ setattr(start,a_tagged,start_tagged("mspace"))
stop_tagged()
else
- processsubsup(start)
+ setattr(start,a_tagged,start_tagged("merror", { detail = nodecodes[i] }))
+ stop_tagged()
end
- elseif id == glue_code then
- setattr(start,a_tagged,start_tagged("mspace"))
- stop_tagged()
- else
- setattr(start,a_tagged,start_tagged("merror", { detail = nodecodes[i] }))
- stop_tagged()
end
start = getnext(start)
end
+ if mtexttag then
+ stop_tagged()
+ end
end
function noads.handlers.tags(head,style,penalties)
head = tonut(head)
- local v_math = start_tagged("math")
- local v_mrow = start_tagged("mrow")
local v_mode = getattr(head,a_mathmode)
- -- setattr(head,a_tagged,v_math)
- setattr(head,a_tagged,v_mrow)
- tags.setattributehash(v_math,"mode",v_mode == 1 and "display" or "inline")
+ local v_math = start_tagged("math", { mode = v_mode == 1 and "display" or "inline" })
+ setattr(head,a_tagged,start_tagged("mrow"))
process(head)
stop_tagged()
stop_tagged()
diff --git a/Master/texmf-dist/tex/context/base/math-vfu.lua b/Master/texmf-dist/tex/context/base/math-vfu.lua
index 6d9a9f903bc..a683e02cfdc 100644
--- a/Master/texmf-dist/tex/context/base/math-vfu.lua
+++ b/Master/texmf-dist/tex/context/base/math-vfu.lua
@@ -41,6 +41,8 @@ local allocate = utilities.storage.allocate
local setmetatableindex = table.setmetatableindex
local formatters = string.formatters
+local chardata = characters.data
+
local mathencodings = allocate()
fonts.encodings.math = mathencodings -- better is then: fonts.encodings.vectors
local vfmath = allocate()
@@ -432,6 +434,14 @@ local function repeated(main,characters,id,size,unicode,u,n,private,fraction) --
end
end
+local function cloned(main,characters,id,size,source,target)
+ local data = characters[source]
+ if data then
+ characters[target] = data
+ return true
+ end
+end
+
-- we use the fact that context defines the smallest sizes first .. a real dirty and ugly hack
local data_of_smaller = nil
@@ -451,10 +461,11 @@ function vfmath.addmissing(main,id,size)
-- here id is the index in fonts (normally 14 or so) and that slot points to self
- local characters = main.characters
- local shared = main.shared
- local variables = main.goodies.mathematics and main.goodies.mathematics.variables or { }
+ local characters = main.characters
+ local shared = main.shared
+ local variables = main.goodies.mathematics and main.goodies.mathematics.variables or { }
local joinrelfactor = variables.joinrelfactor or 3
+
for i=0x7A,0x7D do
make(main,characters,id,size,i,1)
end
@@ -536,23 +547,24 @@ function vfmath.addmissing(main,id,size)
-- 21CB leftrightharpoon
-- 21CC rightleftharpoon
- stack (main,characters,id,size,0x2259,0x0003D,3,0x02227) -- \buildrel\wedge\over=
- jointwo (main,characters,id,size,0x22C8,0x022B3,joinrelfactor,0x022B2) -- \mathrel\triangleright\joinrel\mathrel\triangleleft (4 looks better than 3)
- jointwo (main,characters,id,size,0x22A7,0x0007C,joinrelfactor,0x0003D) -- \mathrel|\joinrel=
- jointwo (main,characters,id,size,0x2260,0x00338,0,0x0003D) -- \not\equal
- jointwo (main,characters,id,size,0x2284,0x00338,0,0x02282) -- \not\subset
- jointwo (main,characters,id,size,0x2285,0x00338,0,0x02283) -- \not\supset
- jointwo (main,characters,id,size,0x2209,0x00338,0,0x02208) -- \not\in
- jointwo (main,characters,id,size,0x2254,0x03A,0,0x03D) -- := (≔)
+ stack(main,characters,id,size,0x2259,0x0003D,3,0x02227) -- \buildrel\wedge\over=
+
+ jointwo(main,characters,id,size,0x22C8,0x022B3,joinrelfactor,0x022B2) -- \mathrel\triangleright\joinrel\mathrel\triangleleft (4 looks better than 3)
+ jointwo(main,characters,id,size,0x22A7,0x0007C,joinrelfactor,0x0003D) -- \mathrel|\joinrel=
+ jointwo(main,characters,id,size,0x2260,0x00338,0,0x0003D) -- \not\equal
+ jointwo(main,characters,id,size,0x2284,0x00338,0,0x02282) -- \not\subset
+ jointwo(main,characters,id,size,0x2285,0x00338,0,0x02283) -- \not\supset
+ jointwo(main,characters,id,size,0x2209,0x00338,0,0x02208) -- \not\in
+ jointwo(main,characters,id,size,0x2254,0x03A,0,0x03D) -- := (≔)
repeated(main,characters,id,size,0x222C,0x222B,2,0xFF800,1/3)
repeated(main,characters,id,size,0x222D,0x222B,3,0xFF810,1/3)
- characters[0xFE325] = fastcopy(characters[0x2032])
-
- raise (main,characters,id,size,0x02032,0xFE325,1,id_of_smaller) -- prime
- raise (main,characters,id,size,0x02033,0xFE325,2,id_of_smaller) -- double prime
- raise (main,characters,id,size,0x02034,0xFE325,3,id_of_smaller) -- triple prime
+ if cloned(main,characters,id,size,0x2032,0xFE325) then
+ raise(main,characters,id,size,0x2032,0xFE325,1,id_of_smaller) -- prime
+ raise(main,characters,id,size,0x2033,0xFE325,2,id_of_smaller) -- double prime
+ raise(main,characters,id,size,0x2034,0xFE325,3,id_of_smaller) -- triple prime
+ end
-- there are more (needs discussion first):
@@ -882,7 +894,7 @@ function vfmath.define(specification,set,goodies)
local ru = rv[unicode]
if not ru then
if trace_virtual then
- report_virtual("unicode slot %U has no index %H in vector %a for font %a",unicode,index,vectorname,fontname)
+ report_virtual("unicode slot %U has no index %H in vector %a for font %a (%S)",unicode,index,vectorname,fontname,chardata[unicode].description)
elseif not already_reported then
report_virtual("the mapping is incomplete for %a at %p",name,size)
already_reported = true
diff --git a/Master/texmf-dist/tex/context/base/meta-fig.mkiv b/Master/texmf-dist/tex/context/base/meta-fig.mkiv
index 46dc4cffc81..bf37aa7bfa7 100644
--- a/Master/texmf-dist/tex/context/base/meta-fig.mkiv
+++ b/Master/texmf-dist/tex/context/base/meta-fig.mkiv
@@ -47,6 +47,9 @@
\c!command=\meta_process_graphic_instance{\fittingpageparameter\c!instance},
\c!instance=]
+\unexpanded\def\setupMPpage
+ {\setupfittingpage[MPpage]}
+
%D \macros
%D {MPfigure}
%D
@@ -56,7 +59,7 @@
{\bgroup
\getfiguredimensions[#1]% [\c!object=\v!no] already set
\startMPcode
- externalfigure "#1"
+ draw externalfigure "#1"
xscaled \the\dimexpr\figurewidth \relax\space % must be points
yscaled \the\dimexpr\figureheight\relax\space % must be points
#2 ;
diff --git a/Master/texmf-dist/tex/context/base/meta-fnt.lua b/Master/texmf-dist/tex/context/base/meta-fnt.lua
index 596d0f45669..95bdfa6d966 100644
--- a/Master/texmf-dist/tex/context/base/meta-fnt.lua
+++ b/Master/texmf-dist/tex/context/base/meta-fnt.lua
@@ -21,32 +21,18 @@ mpfonts.version = mpfonts.version or 1.20
mpfonts.inline = true
mpfonts.cache = containers.define("fonts", "mp", mpfonts.version, true)
-metapost.fonts = metapost.fonts or { }
+metapost.fonts = metapost.fonts or { }
+
+local function unicodetoactualtext(...)
+ unicodetoactualtext = backends.codeinjections.unicodetoactualtext
+ return unicodetoactualtext(...)
+end
-- a few glocals
local characters, descriptions = { }, { }
local factor, code, slot, width, height, depth, total, variants, bbox, llx, lly, urx, ury = 100, { }, 0, 0, 0, 0, 0, 0, true, 0, 0, 0, 0
--- The next variant of ActualText is what Taco and I could come up with
--- eventually. As of September 2013 Acrobat copies okay, Sumatra copies a
--- question mark, pdftotext injects an extra space and Okular adds a
--- newline plus space.
-
--- return formatters["BT /Span << /ActualText (CONTEXT) >> BDC [] TJ % t EMC ET"](code)
-
-local function topdf(n,code)
- if n < 0x10000 then
- return formatters["BT /Span << /ActualText >> BDC [] TJ % t EMC ET"](n,code)
- else
- return formatters["BT /Span << /ActualText >> BDC [] TJ % t EMC ET"](n/1024+0xD800,n%1024+0xDC00,code)
- end
-end
-
--- local function topdf(n,code)
--- return formatters["/Span << /ActualText (CTX) >> BDC % t EMC"](code)
--- end
-
local flusher = {
startfigure = function(_chr_,_llx_,_lly_,_urx_,_ury_)
code = { }
@@ -68,6 +54,7 @@ local flusher = {
end,
stopfigure = function()
local cd = chardata[n]
+ local code = unicodetoactualtext(slot,concat(code," ")) or ""
descriptions[slot] = {
-- unicode = slot,
name = cd and cd.adobename,
@@ -79,7 +66,7 @@ local flusher = {
if inline then
characters[slot] = {
commands = {
- { "special", "pdf:" .. topdf(slot,code) },
+ { "special", "pdf:" .. code },
}
}
else
@@ -88,13 +75,14 @@ local flusher = {
{
"image",
{
- stream = topdf(slot,code),
+ stream = code,
bbox = { 0, -depth * 65536, width * 65536, height * 65536 }
},
},
}
}
end
+ code = nil -- no need to keep that
end
}
@@ -261,7 +249,16 @@ function metapost.fonts.define(specification)
} )
end
-commands.definemetafont = metapost.fonts.define
+interfaces.implement {
+ name = "definemetafont",
+ actions = metapost.fonts.define,
+ arguments = {
+ {
+ { "fontname" },
+ { "filename" },
+ }
+ }
+}
-- metapost.fonts.define {
-- fontname = "bidi",
diff --git a/Master/texmf-dist/tex/context/base/meta-fnt.mkiv b/Master/texmf-dist/tex/context/base/meta-fnt.mkiv
index 603fcf14d51..e54c0be0a4f 100644
--- a/Master/texmf-dist/tex/context/base/meta-fnt.mkiv
+++ b/Master/texmf-dist/tex/context/base/meta-fnt.mkiv
@@ -21,11 +21,11 @@
{\dotripleempty\meta_font_define}
\def\meta_font_define[#1][#2][#3]%
- {\ctxcommand{definemetafont {
- fontname = "#1",
- filename = "#2"
+ {\clf_definemetafont
+ fontname {#1}%
+ filename {#2}%
% no #3 settings yet (compose, instances)
- }}}
+ \relax}
% \startluacode
% metapost.fonts.define { fontname = "bidi-symbols", filename = "bidi-symbols.mp" }
diff --git a/Master/texmf-dist/tex/context/base/meta-fun.lua b/Master/texmf-dist/tex/context/base/meta-fun.lua
index 78ee25bafe4..7aaaf2818ec 100644
--- a/Master/texmf-dist/tex/context/base/meta-fun.lua
+++ b/Master/texmf-dist/tex/context/base/meta-fun.lua
@@ -26,7 +26,7 @@ function metafun.topath(t,connector)
if type(ti) == "string" then
context(ti)
else
- context("(%s,%s)",ti.x or ti[1] or 0,ti.y or ti[2] or 0)
+ context("(%F,%F)",ti.x or ti[1] or 0,ti.y or ti[2] or 0)
end
end
else
@@ -47,7 +47,7 @@ function metafun.interpolate(f,b,e,s,c)
else
done = true
end
- context("(%s,%s)",i,d(i))
+ context("(%F,%F)",i,d(i))
end
end
if not done then
diff --git a/Master/texmf-dist/tex/context/base/meta-imp-dum.mkiv b/Master/texmf-dist/tex/context/base/meta-imp-dum.mkiv
index 1daff57ac8c..e6ccc234c6d 100644
--- a/Master/texmf-dist/tex/context/base/meta-imp-dum.mkiv
+++ b/Master/texmf-dist/tex/context/base/meta-imp-dum.mkiv
@@ -60,6 +60,8 @@
% \stopuseMPgraphic
\startuseMPgraphic{figure:placeholder}{width,height,reduction,color}
+ begingroup ;
+ save w, h, d, r, p, c, b ;
numeric w, h, d, r ; path p ;
if cmykcolor \MPvar{color} :
cmykcolor c, b ; b := (0,0,0,0)
@@ -80,6 +82,7 @@
withcolor r[c randomized(.3,.9),b] ;
endfor ;
clip currentpicture to p ;
+ endgroup ;
\stopuseMPgraphic
\defineoverlay
diff --git a/Master/texmf-dist/tex/context/base/meta-imp-tab.mkiv b/Master/texmf-dist/tex/context/base/meta-imp-tab.mkiv
new file mode 100644
index 00000000000..a4affbea458
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/meta-imp-tab.mkiv
@@ -0,0 +1,73 @@
+%D \module
+%D [ file=meta-tab,
+%D version=2003.03.21, % very old but now with splitter
+%D title=\METAPOST\ Graphics,
+%D subtitle=Dummy (External) Graphics,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\startuseMPgraphic{TallyBar}
+ height := (10/12) * LineHeight ;
+ span := ( 4/10) * LineHeight ;
+ drift := ( 1/10) * LineHeight ;
+ def d = (uniformdeviate drift) enddef ;
+ for i := 1 upto \MPvar{n} :
+ draw
+ if (i mod 5)=0 :
+ ((-d-4.5span,d)--(+d-0.5span,height-d))
+ else :
+ ((-d,+d)--(+d,height-d))
+ fi
+ shifted (span*i,d-drift) withpen pencircle ;
+ endfor ;
+ currentpicture := currentpicture scaled .75 ;
+\stopuseMPgraphic
+
+\setupMPvariables
+ [TallyBar]
+ [n=0]
+
+\unexpanded\def\tallynumeral#1%
+ {\dontleavehmode
+ \lower.25\exheight\hbox{\useMPgraphic{TallyBar}{n=#1}}}
+
+\unexpanded\def\tallynumerals#1%
+ {\dontleavehmode
+ \begingroup
+ \scratchcounter#1\relax
+ \doloop
+ {\ifnum\scratchcounter>\plusfive
+ \lower.25\exheight\hbox{\useMPgraphic{TallyBar}{n=5}}%
+ \advance\scratchcounter-\plusfive
+ \space
+ \else
+ \lower.25\exheight\hbox{\useMPgraphic{TallyBar}{n=\the\scratchcounter}}%
+ \exitloop
+ \fi}%
+ \endgroup}
+
+\let\FunnyBar\tallynumeral
+
+\defineconversion[tally][\tallynumerals]
+
+\continueifinputfile{meta-imp-tab.mkiv}
+
+\starttext
+
+ \starttabulate[|pr|c|]
+ \NC \tallynumerals {24} \NC \NR
+ \NC \tallynumerals {12} \NC \times \NR
+ \HL
+ \NC \tallynumerals{288} \NC = \NR
+ \stoptabulate
+
+ \tallynumerals{"FFFF}
+
+\stoptext
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/meta-imp-txt.mkiv b/Master/texmf-dist/tex/context/base/meta-imp-txt.mkiv
index bcfc5513fbe..7069d21a4ea 100644
--- a/Master/texmf-dist/tex/context/base/meta-imp-txt.mkiv
+++ b/Master/texmf-dist/tex/context/base/meta-imp-txt.mkiv
@@ -104,7 +104,7 @@
\unexpanded\def\getshapecharacteristics
{\doglobal\increment\currentshapetext
- \doifdefinedelse{parlines:\currentshapetext}
+ \doifelsedefined{parlines:\currentshapetext}
{\global\parlines \getvalue{parlines:\currentshapetext}%
\global\chardef\parfirst \getvalue{parfirst:\currentshapetext}%
\global\parvoffset \getvalue{parvoffset:\currentshapetext}%
@@ -152,7 +152,7 @@
%%%%%%% rotfont nog definieren
-\doifundefined{RotFont}{\definefont[RotFont][RegularBold]}
+\doifundefined{RotFont}{\definefont[RotFont][RegularBold*default]}
\unexpanded\def\processfollowingtoken#1% strut toegevoegd
{\appendtoks#1\to\MPtoks
@@ -174,9 +174,7 @@
{\vbox\bgroup
\forgetall
\dontcomplain
- \startMPenvironment
- \doifundefined{RotFont}{\definefont[RotFont][RegularBold]}%
- \stopMPenvironment
+ \doifundefined{RotFont}{\definefont[RotFont][RegularBold*default]}%
\MPtoks\emptytoks
\resetMPdrawing
\startMPdrawing
@@ -225,6 +223,7 @@
withpen pencircle scaled .50pt withcolor green ;
fi ;
endfor ;
+% fill boundingbox currentpicture ;
\stopMPdrawing
\MPdrawingdonetrue
\getMPdrawing
diff --git a/Master/texmf-dist/tex/context/base/meta-ini.lua b/Master/texmf-dist/tex/context/base/meta-ini.lua
index 713ba3d5d01..8f713126323 100644
--- a/Master/texmf-dist/tex/context/base/meta-ini.lua
+++ b/Master/texmf-dist/tex/context/base/meta-ini.lua
@@ -15,34 +15,6 @@ local context = context
metapost = metapost or { }
--- for the moment downward compatible
-
-local report_metapost = logs.reporter ("metapost")
-local status_metapost = logs.messenger("metapost")
-
-local patterns = { "meta-imp-%s.mkiv", "meta-imp-%s.tex", "meta-%s.mkiv", "meta-%s.tex" } -- we are compatible
-
-local function action(name,foundname)
- status_metapost("library %a is loaded",name)
- context.startreadingfile()
- context.input(foundname)
- context.stopreadingfile()
-end
-
-local function failure(name)
- report_metapost("library %a is unknown or invalid",name)
-end
-
-function commands.useMPlibrary(name)
- commands.uselibrary {
- name = name,
- patterns = patterns,
- action = action,
- failure = failure,
- onlyonce = true,
- }
-end
-
-- experimental
local colorhash = attributes.list[attributes.private('color')]
diff --git a/Master/texmf-dist/tex/context/base/meta-ini.mkiv b/Master/texmf-dist/tex/context/base/meta-ini.mkiv
index 555deca2cbf..c3b94f899cd 100644
--- a/Master/texmf-dist/tex/context/base/meta-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/meta-ini.mkiv
@@ -106,7 +106,7 @@
{\dosinglegroupempty\meta_start_extensions}
\def\meta_start_extensions#1#2\stopMPextensions % we could use buffers instead
- {\ctxlua{metapost.setextensions("#1",\!!bs#2\!!es)}}
+ {\clf_setmpextensions{#1}{#2}}
\let\stopMPextensions\relax
@@ -155,12 +155,12 @@
\global\t_meta_inclusions\expandafter{\the\t_meta_inclusions#2}%
\let\currentMPinstance\m_meta_saved_instance}
-\def\meta_preset_definitions
- {\edef\overlaywidth {\overlaywidth \space}%
- \edef\overlayheight {\overlayheight \space}%
- \edef\overlaylinewidth{\overlaylinewidth\space}%
- \edef\currentwidth {\the\hsize \space}%
- \edef\currentheight {\the\vsize \space}}
+% \def\meta_preset_definitions
+% {\edef\overlaywidth {\overlaywidth \space}%
+% \edef\overlayheight {\overlayheight \space}%
+% \edef\overlaylinewidth{\overlaylinewidth\space}}
+
+\let\meta_preset_definitions\relax
\installcommandhandler \??mpinstance {MPinstance} \??mpinstance
@@ -217,14 +217,22 @@
\def\currentMPinstance {\defaultMPinstance}
\def\currentMPformat {\currentMPinstance}
-\defineMPinstance[metafun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
-\defineMPinstance[extrafun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
-\defineMPinstance[doublefun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes,\c!method=\s!double]
-\defineMPinstance[binaryfun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes,\c!method=\s!binary]
-\defineMPinstance[decimalfun][\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes,\c!method=\s!decimal]
-\defineMPinstance[mprun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
-\defineMPinstance[metapost] [\s!format=mpost]
-\defineMPinstance[nofun] [\s!format=mpost]
+\defineMPinstance[metafun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
+\defineMPinstance[extrafun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
+\defineMPinstance[lessfun] [\s!format=metafun]
+\defineMPinstance[doublefun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes,\c!method=\s!double]
+\defineMPinstance[binaryfun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes,\c!method=\s!binary]
+\defineMPinstance[decimalfun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes,\c!method=\s!decimal]
+
+\defineMPinstance[mprun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
+
+\defineMPinstance[metapost] [\s!format=mpost]
+\defineMPinstance[nofun] [\s!format=mpost]
+\defineMPinstance[doublepost] [\s!format=mpost,\c!method=\s!double]
+\defineMPinstance[binarypost] [\s!format=mpost,\c!method=\s!binary]
+\defineMPinstance[decimalpost][\s!format=mpost,\c!method=\s!decimal]
+
+%defineMPinstance[megapost] [\s!format=mpost,\c!method=\s!decimal]
\newconditional\c_meta_include_initializations
@@ -295,20 +303,19 @@
\forgetall
\edef\p_extensions{\MPinstanceparameter\s!extensions}%
\meta_process_graphic_start
- \normalexpanded{\noexpand\ctxlua{metapost.graphic {
- instance = "\currentMPinstance",
- format = "\currentMPformat",
- data = \!!bs#1;\!!es,
- initializations = \!!bs\meta_flush_current_initializations\!!es,
-% useextensions = "\MPinstanceparameter\s!extensions",
-\ifx\p_extensions\v!yes
- extensions = \!!bs\ctxcommand{getmpextensions("\currentMPinstance")}\!!es,
-\fi
- inclusions = \!!bs\meta_flush_current_inclusions\!!es,
- definitions = \!!bs\meta_flush_current_definitions\!!es,
- figure = "\MPaskedfigure",
- method = "\MPinstanceparameter\c!method",
- }}}%
+ \normalexpanded{\noexpand\clf_mpgraphic
+ instance {\currentMPinstance}%
+ format {\currentMPformat}%
+ data {#1;}%
+ initializations {\meta_flush_current_initializations}%
+ \ifx\p_extensions\v!yes
+ extensions {\clf_getmpextensions{\currentMPinstance}}% goes through tex again
+ \fi
+ inclusions {\meta_flush_current_inclusions}%
+ definitions {\meta_flush_current_definitions}%
+ figure {\MPaskedfigure}%
+ method {\MPinstanceparameter\c!method}%
+ \relax}%
\meta_process_graphic_stop
\meta_stop_current_graphic}
@@ -338,14 +345,32 @@
%D Calling up previously defined graphics.
+% \def\includeMPgraphic#1% gets expanded !
+% {\ifcsname\??mpgraphic#1\endcsname
+% \csname\??mpgraphic#1\endcsname ; % ; is safeguard
+% \fi}
+%
+% \unexpanded\def\meta_enable_include % public
+% {\let\meta_handle_use_graphic \thirdofthreearguments
+% \let\meta_handle_reusable_graphic\thirdofthreearguments}
+%
+% but ... we want this too:
+%
+% \startuseMPgraphic{x}
+% draw textext("\externalfigure[foo.pdf]") ;
+% \stopuseMPgraphic
+%
+% \useMPgraphic{x}
+%
+% so we cannot overload unless we let back to the original meanings
+% each graphic ... a better solution is:
+
\def\includeMPgraphic#1% gets expanded !
{\ifcsname\??mpgraphic#1\endcsname
- \csname\??mpgraphic#1\endcsname ; % ; is safeguard
+ \doubleexpandafter\fourthoffourarguments\csname\??mpgraphic#1\endcsname ; % ; is safeguard
\fi}
-\unexpanded\def\meta_enable_include % public
- {\let\meta_handle_use_graphic \thirdofthreearguments
- \let\meta_handle_reusable_graphic\thirdofthreearguments}
+\let\meta_enable_include\relax
%D Drawings (stepwise built):
@@ -401,20 +426,13 @@
\unexpanded\def\meta_grab_clip_path#1#2#3#4% #4 is alternative (called in backend code)
{\begingroup
- \edef\width {#2\space}\let\overlaywidth \width
- \edef\height{#3\space}\let\overlayheight\height
- \ifcsname\??mpclip#1\endcsname
- \meta_start_current_graphic
- \xdef\MPclippath{\normalexpanded{\noexpand\ctxlua{metapost.theclippath {
- instance = "\currentMPinstance",
- format = "\currentMPformat",
- data = \!!bs\getvalue{\??mpclip#1}\!!es,
- initializations = \!!bs\meta_flush_current_initializations\!!es,
- useextensions = "\MPinstanceparameter\s!extensions",
- inclusions = \!!bs\meta_flush_current_inclusions\!!es,
- method = "\MPinstanceparameter\c!method",
- }}}}%
- \meta_stop_current_graphic
+ \edef\width {#2}% \let\overlaywidth \width
+ \edef\height{#3}% \let\overlayheight\height
+ \d_overlay_width #2\onebasepoint
+ \d_overlay_height#3\onebasepoint
+ \edef\currentMPclip{#1}%
+ \ifcsname\??mpclip\currentMPclip\endcsname
+ \meta_grab_clip_path_indeed
\ifx\MPclippath\empty
\xdef\MPclippath{#4}%
\fi
@@ -423,6 +441,19 @@
\fi
\endgroup}
+\def\meta_grab_clip_path_indeed
+ {\meta_start_current_graphic
+ \normalexpanded{\noexpand\clf_mpsetclippath
+ instance {\currentMPinstance}%
+ format {\currentMPformat}%
+ data {\csname\??mpclip\currentMPclip\endcsname}%
+ initializations {\meta_flush_current_initializations}%
+ useextensions {\MPinstanceparameter\s!extensions}%
+ inclusions {\meta_flush_current_inclusions}%
+ method {\MPinstanceparameter\c!method}%
+ \relax}%
+ \meta_stop_current_graphic}
+
%D Since we want lables to follow the document settings, we
%D also set the font related variables.
@@ -430,7 +461,7 @@
{\dontleavehmode
\begingroup
\definedfont[#1]%
- \hskip\cldcontext{fonts.hashes.parameters[font.current()].designsize}sp\relax
+ \hskip\clf_currentdesignsize\scaledpoint\relax
\endgroup}
\definefontsynonym[MetafunDefault][Regular*default]
@@ -438,7 +469,7 @@
\startMPinitializations % scale is not yet ok
defaultfont:="\truefontname{MetafunDefault}";
% defaultscale:=\the\bodyfontsize/10pt; % only when hard coded 10pt
- defaultscale:=1;
+ % defaultscale:=1;
\stopMPinitializations
% watch out, this is a type1 font because mp can only handle 8 bit fonts
@@ -571,7 +602,7 @@
\def\meta_prepare_variable_yes
{\defconvertedcommand\ascii\m_meta_current_variable % otherwise problems
- \doifcolorelse \ascii % with 2\bodyfontsize
+ \doifelsecolor \ascii % with 2\bodyfontsize
{\meta_prepare_variable_color}
{\begingroup
\setbox\b_meta_variable_box\hbox{\scratchdimen\m_meta_current_variable sp}%
@@ -600,7 +631,13 @@
%D \stoptyping
\def\overlaystamp % watch the \MPcolor, since colors can be redefined
- {\overlaywidth:\overlayheight:\overlaydepth:\overlayoffset:\overlaylinewidth:\MPcolor\overlaycolor:\MPcolor\overlaylinecolor}
+ {\the\d_overlay_width :%
+ \the\d_overlay_height :%
+ \the\d_overlay_depth :%
+ \the\d_overlay_offset :%
+ \the\d_overlay_linewidth:%
+ \MPcolor\overlaycolor :% % todo, expand once \m_overlaycolor
+ \MPcolor\overlaylinecolor} % todo, expand once \m_overlaylinecolor
%D A better approach is to let additional variables play a role
%D in determining the uniqueness. In the next macro, the
@@ -783,19 +820,25 @@
\let\reuseMPgraphic \useMPgraphic % we can save a setup here if needed
\let\reusableMPgraphic\reuseMPgraphic % we can save a setup here if needed
-\unexpanded\def\meta_enable_include
- {\let\meta_handle_use_graphic \thirdofthreearguments
- \let\meta_handle_reusable_graphic\thirdofthreearguments}
-
%D \macros
%D {startuniqueMPpagegraphic,uniqueMPpagegraphic}
%D
%D Experimental.
-\def\m_meta_page_prefix{\doifoddpageelse oe}
+\def\m_meta_page_prefix{\doifelseoddpage oe}
+
+% \def\overlaypagestamp
+% {\m_meta_page_prefix:\overlaywidth:\overlayheight:\overlaydepth:\MPcolor\overlaycolor:\MPcolor\overlaylinecolor}
\def\overlaypagestamp
- {\m_meta_page_prefix:\overlaywidth:\overlayheight:\overlaydepth:\MPcolor\overlaycolor:\MPcolor\overlaylinecolor}
+ {\m_meta_page_prefix :%
+ \the\d_overlay_width :%
+ \the\d_overlay_height :%
+ \the\d_overlay_depth :%
+ \the\d_overlay_offset :%
+ \the\d_overlay_linewidth:%
+ \MPcolor\overlaycolor :%
+ \MPcolor\overlaylinecolor}
\unexpanded\def\startuniqueMPpagegraphic
{\dodoublegroupempty\meta_start_unique_page_graphic}
@@ -859,12 +902,21 @@
% makempy.registerfile(filename)
-\startMPinitializations
- boolean collapse_data; collapse_data:=true;
- def data_mpd_file = "\MPdataMPDfile" enddef ;
- def data_mpo_file = "\MPdataMPOfile" enddef ;
- def data_mpy_file = "\MPdataMPYfile" enddef ;
-\stopMPinitializations
+% % hm. extensions get expanded so the wrong names then end up in format
+%
+% \startMPinitializations
+% boolean collapse_data; collapse_data:=true ; % will be obsolete
+% def data_mpd_file = "\MPdataMPDfile" enddef ; % will go via lua
+% def data_mpo_file = "\MPdataMPOfile" enddef ;
+% def data_mpy_file = "\MPdataMPYfile" enddef ;
+% \stopMPinitializations
+
+\startMPextensions
+ boolean collapse_data; collapse_data:=true ; % will be obsolete
+ def data_mpd_file = "\noexpand\MPdataMPDfile" enddef ; % will go via lua
+ def data_mpo_file = "\noexpand\MPdataMPOfile" enddef ;
+ def data_mpy_file = "\noexpand\MPdataMPYfile" enddef ;
+\stopMPextensions
\unexpanded\def\getMPdata
{\let\MPdata\secondoftwoarguments
@@ -884,7 +936,7 @@
\def\meta_process_buffer[#1]%
{\meta_begin_graphic_group{#1}%
- \meta_process_graphic{\ctxcommand{feedback("\currentMPgraphicname")}}%
+ \meta_process_graphic{\clf_feedback{\currentMPgraphicname}}%
\meta_end_graphic_group}
\unexpanded\def\runMPbuffer
@@ -928,15 +980,15 @@
\else\ifx\m_meta_option\!!plustoken
#2% % use in main doc too
\fi\fi\fi
- \ctxlua{metapost.tex.set(\!!bs\detokenize{#2}\!!es)}}
+ \clf_mptexset{\detokenize{#2}}}
\let\stopMPenvironment\relax
\unexpanded\def\resetMPenvironment
- {\ctxlua{metapost.tex.reset()}}
+ {\clf_mptexreset}
\unexpanded\def\useMPenvironmentbuffer[#1]%
- {\ctxlua{metapost.tex.set(buffers.content("#1"))}}
+ {\clf_mpsetfrombuffer{#1}}
%D This command takes \type {[reset]} as optional
%D argument.
@@ -1058,7 +1110,7 @@
%D Loading specific \METAPOST\ related definitions is
%D accomplished by:
-\unexpanded\def\useMPlibrary[#1]{\ctxcommand{useMPlibrary(\!!bs#1\!!es)}}
+\unexpanded\def\useMPlibrary[#1]{\clf_useMPlibrary{#1}}
%D \macros
%D {setMPtext, MPtext, MPstring, MPbetex}
@@ -1088,46 +1140,62 @@
% \setupcolors[state=stop,conversion=never] % quite tricky ... type mismatch
-% A dirty trick, ** in colo-ini.lua (mpcolor).
+% \startMPextensions
+% color OverlayColor,OverlayLineColor;
+% \stopMPextensions
-\def\m_meta_colo_initializations{% no vardef, goes wrong with spot colors
- def OverlayLineColor=\MPcolor{\overlaylinecolor} enddef;
- def OverlayColor=\MPcolor{\overlaycolor} enddef;
-}
+\startMPinitializations
+ CurrentLayout:="\currentlayout";
+\stopMPinitializations
-\startMPextensions
- color OverlayColor,OverlayLineColor;
-\stopMPextensions
+% \startMPinitializations
+% OverlayWidth:=\overlaywidth;
+% OverlayHeight:=\overlayheight;
+% OverlayDepth:=\overlaydepth;
+% OverlayLineWidth:=\overlaylinewidth;
+% OverlayOffset:=\overlayoffset;
+% \stopMPinitializations
+
+% A dirty trick, ** in colo-ini.lua (mpcolor). We cannot use a vardef, because
+% that fails with spot colors.
\startMPinitializations
- CurrentLayout:="\currentlayout";
- OverlayWidth:=\overlaywidth;
- OverlayHeight:=\overlayheight;
- OverlayDepth:=\overlaydepth;
- OverlayLineWidth:=\overlaylinewidth;
- OverlayOffset:=\overlayoffset;
- %
- \m_meta_colo_initializations
- %
- BaseLineSkip:=\the\baselineskip;
- LineHeight:=\the\baselineskip;
- BodyFontSize:=\the\bodyfontsize;
- %
- TopSkip:=\the\topskip;
- StrutHeight:=\strutheight;
- StrutDepth:=\strutdepth;
- %
- CurrentWidth:=\the\hsize;
- CurrentHeight:=\the\vsize;
- %
- EmWidth:=\the\emwidth;
- ExHeight:=\the\exheight;
- %
- PageNumber:=\the\pageno;
- RealPageNumber:=\the\realpageno;
- LastPageNumber:= \lastpage;
+ def OverlayLineColor=\ifx\overlaylinecolor\empty black \else\MPcolor{\overlaylinecolor} \fi enddef;
+ def OverlayColor =\ifx\overlaycolor \empty black \else\MPcolor{\overlaycolor} \fi enddef;
\stopMPinitializations
+% \newcount\c_overlay_colormodel
+% \newcount\c_overlay_color
+% \newcount\c_overlay_transparency
+% \newcount\c_overlay_linecolor
+% \newcount\c_overlay_linetransparency
+
+% \appendtoks
+% \c_overlay_colormodel \attribute\colormodelattribute
+% \c_overlay_color \colo_helpers_inherited_current_ca\overlaycolor
+% \c_overlay_transparency \colo_helpers_inherited_current_ta\overlaycolor
+% \c_overlay_linecolor \colo_helpers_inherited_current_ca\overlaylinecolor
+% \c_overlay_linetransparency\colo_helpers_inherited_current_ta\overlaylinecolor
+% \to \everyMPgraphic
+
+% \startMPinitializations
+% BaseLineSkip:=\the\baselineskip;
+% LineHeight:=\the\baselineskip;
+% BodyFontSize:=\the\bodyfontsize;
+% %
+% TopSkip:=\the\topskip;
+% StrutHeight:=\strutheight;
+% StrutDepth:=\strutdepth;
+% %
+% CurrentWidth:=\the\hsize;
+% CurrentHeight:=\the\vsize;
+% HSize:=\the\hsize ;
+% VSize:=\the\vsize ;
+% %
+% EmWidth:=\the\emwidth;
+% ExHeight:=\the\exheight;
+% \stopMPinitializations
+
\appendtoks
\disablediscretionaries
\disablecompoundcharacters
@@ -1157,11 +1225,6 @@
\let \} \letterclosebrace
\to \everyMPgraphic
-\startMPinitializations
- prologues:=0;
- mpprocset:=1;
-\stopMPinitializations
-
%D \macros
%D {PDFMPformoffset}
%D
@@ -1188,21 +1251,36 @@
enddef;
\stopMPextensions
-\startMPinitializations
- HSize:=\the\hsize ;
- VSize:=\the\vsize ;
-\stopMPinitializations
-
\startMPextensions
vardef ForegroundBox =
unitsquare xysized(HSize,VSize)
enddef ;
- PageFraction := 1 ;
\stopMPextensions
-\startMPinitializations
- PageFraction := if \lastpage>1: (\realfolio-1)/(\lastpage-1) else: 1 fi ;
-\stopMPinitializations
+% \startMPextensions
+% PageFraction := 1 ;
+% \stopMPextensions
+
+% \startMPinitializations
+% PageFraction := if \lastpage>1: (\realfolio-1)/(\lastpage-1) else: 1 fi ;
+% \stopMPinitializations
+
+\startMPdefinitions {metapost}
+ if unknown context_bare : input mp-bare.mpiv ; fi ;
+\stopMPdefinitions
+\startMPdefinitions {binarypost}
+ if unknown context_bare : input mp-bare.mpiv ; fi ;
+\stopMPdefinitions
+\startMPdefinitions {decimalpost}
+ if unknown context_bare : input mp-bare.mpiv ; fi ;
+\stopMPdefinitions
+\startMPdefinitions {doublepost}
+ if unknown context_bare : input mp-bare.mpiv ; fi ;
+\stopMPdefinitions
+
+% \startMPdefinitions {nofun}
+% if unknown context_bare : input mp-bare.mpiv ; fi ;
+% \stopMPdefinitions
%D And some more. These are not really needed since we
%D don't use the normal figure inclusion macros any longer.
@@ -1363,12 +1441,16 @@
\newconstant\MPcolormethod
\appendtoks
- \ctxlua{metapost.setoutercolor(\number\MPcolormethod,\number\attribute\colormodelattribute,\number\attribute\colorattribute,\number\dogetattribute{transparency})}%
+ \clf_mpsetoutercolor
+ \MPcolormethod\space
+ \attribute\colormodelattribute\space
+ \attribute\colorattribute\space
+ \dogetattribute{transparency}\relax
\to \everyMPgraphic
-\startMPinitializations
- defaultcolormodel := \ifcase\MPcolormethod1\or1\or3\else3\fi;
-\stopMPinitializations
+% \startMPinitializations
+% defaultcolormodel := \ifcase\MPcolormethod1\or1\or3\else3\fi;
+% \stopMPinitializations
%D macros
%D {mprunvar,mpruntab,mprunset}
@@ -1394,9 +1476,9 @@
%D $(x,y) = (\MPrunset{point}{,})$
%D \stoptyping
-\def\MPrunvar #1{\ctxcommand{mprunvar("#1")}} \let\mprunvar\MPrunvar
-\def\MPruntab#1#2{\ctxcommand{mprunvar("#1",\number#2)}} \let\mpruntab\MPruntab
-\def\MPrunset#1#2{\ctxcommand{mprunvar("#1","#2")}} \let\mprunset\MPrunset
+\def\MPrunvar #1{\clf_mprunvar{#1}} \let\mprunvar\MPrunvar
+\def\MPruntab#1#2{\clf_mpruntab{#1}#2\relax} \let\mpruntab\MPruntab % #2 is number
+\def\MPrunset#1#2{\clf_mprunset{#1}{#2}} \let\mprunset\MPrunset
%D We also provide an outputless run:
@@ -1465,7 +1547,7 @@
\edef\p_mpy{\directMPgraphicsparameter{mpy}}%
\ifx\p_mpy\empty \else
\let\MPdataMPYfile\p_mpy
- \ctxlua{metapost.makempy.registerfile("\p_mpy")}%
+ \clf_registermpyfile{\p_mpy}%
\fi
\to \everysetupMPgraphics
diff --git a/Master/texmf-dist/tex/context/base/meta-pag.mkiv b/Master/texmf-dist/tex/context/base/meta-pag.mkiv
index a25353b188e..6b6abd21135 100644
--- a/Master/texmf-dist/tex/context/base/meta-pag.mkiv
+++ b/Master/texmf-dist/tex/context/base/meta-pag.mkiv
@@ -23,82 +23,76 @@
%D pagebody looks.
\startMPextensions
- boolean PageStateAvailable,OnRightPage,InPageBody;
+ boolean PageStateAvailable;
PageStateAvailable:=true;
\stopMPextensions
-\startMPinitializations
- OnRightPage:=true;
- InPageBody:=\ifinpagebody true \else false \fi;
-\stopMPinitializations
-
-\startMPinitializations
- CurrentColumn:=\number\mofcolumns;
- NOfColumns:=\number\nofcolumns;
- % todo: ColumnDistance
-\stopMPinitializations
-
% maybe always set as frozen anyway
-\startMPinitializations
- % def LoadPageState =
- OnRightPage:=\MPonrightpage;
- OnOddPage:=\MPonoddpage;
- RealPageNumber:=\the\realpageno;
- PageNumber:=\the\pageno;
- NOfPages:=\lastpage;
- PaperHeight:=\the\paperheight;
- PaperWidth:=\the\paperwidth;
- PrintPaperHeight:=\the\printpaperheight;
- PrintPaperWidth:=\the\printpaperwidth;
- TopSpace:=\the\topspace;
- BottomSpace:=\the\bottomspace;
- BackSpace:=\the\backspace;
- CutSpace:=\the\cutspace;
- MakeupHeight:=\the\makeupheight;
- MakeupWidth:=\the\makeupwidth;
- TopHeight:=\the\topheight;
- TopDistance:=\the\topdistance;
- HeaderHeight:=\the\headerheight;
- HeaderDistance:=\the\headerdistance;
- TextHeight:=\the\textheight;
- FooterDistance:=\the\footerdistance;
- FooterHeight:=\the\footerheight;
- BottomDistance:=\the\bottomdistance;
- BottomHeight:=\the\bottomheight;
- LeftEdgeWidth:=\the\leftedgewidth;
- LeftEdgeDistance:=\the\leftedgedistance;
- LeftMarginWidth:=\the\leftmarginwidth;
- LeftMarginDistance:=\the\leftmargindistance;
- TextWidth:=\the\textwidth ;
- RightMarginDistance:=\the\rightmargindistance;
- RightMarginWidth:=\the\rightmarginwidth;
- RightEdgeDistance:=\the\rightedgedistance;
- RightEdgeWidth:=\the\rightedgewidth;
- InnerMarginDistance:=\the\innermargindistance;
- InnerMarginWidth:=\the\innermarginwidth;
- OuterMarginDistance:=\the\outermargindistance;
- OuterMarginWidth:=\the\outermarginwidth;
- InnerEdgeDistance:=\the\inneredgedistance;
- InnerEdgeWidth:=\the\inneredgewidth;
- OuterEdgeDistance:=\the\outeredgedistance;
- OuterEdgeWidth:=\the\outeredgewidth;
- PageOffset:=\the\pagebackgroundoffset;
- PageDepth:=\the\pagebackgrounddepth;
- LayoutColumns:=\the\layoutcolumns;
- LayoutColumnDistance:=\the\layoutcolumndistance;
- LayoutColumnWidth:=\the\layoutcolumnwidth;
- def LoadPageState =
- % now always set .. this dummy can move to the mp code
- enddef;
-\stopMPinitializations
+% \startMPinitializations
+% PaperHeight:=\the\paperheight;
+% PaperWidth:=\the\paperwidth;
+% PrintPaperHeight:=\the\printpaperheight;
+% PrintPaperWidth:=\the\printpaperwidth;
+% TopSpace:=\the\topspace;
+% BottomSpace:=\the\bottomspace;
+% BackSpace:=\the\backspace;
+% CutSpace:=\the\cutspace;
+% MakeupHeight:=\the\makeupheight;
+% MakeupWidth:=\the\makeupwidth;
+% TopHeight:=\the\topheight;
+% TopDistance:=\the\topdistance;
+% HeaderHeight:=\the\headerheight;
+% HeaderDistance:=\the\headerdistance;
+% TextHeight:=\the\textheight;
+% FooterDistance:=\the\footerdistance;
+% FooterHeight:=\the\footerheight;
+% BottomDistance:=\the\bottomdistance;
+% BottomHeight:=\the\bottomheight;
+% LeftEdgeWidth:=\the\leftedgewidth;
+% LeftEdgeDistance:=\the\leftedgedistance;
+% LeftMarginWidth:=\the\leftmarginwidth;
+% LeftMarginDistance:=\the\leftmargindistance;
+% TextWidth:=\the\textwidth;
+% RightMarginDistance:=\the\rightmargindistance;
+% RightMarginWidth:=\the\rightmarginwidth;
+% RightEdgeDistance:=\the\rightedgedistance;
+% RightEdgeWidth:=\the\rightedgewidth;
+% InnerMarginDistance:=\the\innermargindistance;
+% InnerMarginWidth:=\the\innermarginwidth;
+% OuterMarginDistance:=\the\outermargindistance;
+% OuterMarginWidth:=\the\outermarginwidth;
+% InnerEdgeDistance:=\the\inneredgedistance;
+% InnerEdgeWidth:=\the\inneredgewidth;
+% OuterEdgeDistance:=\the\outeredgedistance;
+% OuterEdgeWidth:=\the\outeredgewidth;
+% PageOffset:=\the\pagebackgroundoffset;
+% PageDepth:=\the\pagebackgrounddepth;
+% LayoutColumns:=\the\layoutcolumns;
+% LayoutColumnDistance:=\the\layoutcolumndistance;
+% LayoutColumnWidth:=\the\layoutcolumnwidth;
+% %
+% boolean OnRightPage,OnOddPage,InPageBody;
+% %
+% OnRightPage:=\MPonrightpage;
+% OnOddPage:=\MPonoddpage;
+% InPageBody:=\ifinpagebody true \else false \fi;
+% %
+% RealPageNumber:=\the\realpageno;
+% PageNumber:=\the\pageno;
+% NOfPages:=\lastpage;
+% LastPageNumber:=\lastpage;
+% %
+% CurrentColumn:=\number\mofcolumns;
+% NOfColumns:=\number\nofcolumns;
+% \stopMPinitializations
\def\MPonrightpage{true}
\def\MPonoddpage {true}
\def\freezeMPpagelayout
{\edef\MPonrightpage{\doifbothsides {tru}{tru}{fals}e}%
- \edef\MPonoddpage {\doifoddpageelse {tru}{fals}e}}
+ \edef\MPonoddpage {\doifelseoddpage {tru}{fals}e}}
%D We need to freeze the pagelayout before the backgrounds
%D are build, because the overlay will temporarily become
@@ -121,7 +115,7 @@
% \to \everyMPgraphic
\prependtoks
- \calculatereducedvsizes % this is really needed
+ \calculatereducedvsizes % bah, this is really needed
\to \everyMPgraphic
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/meta-pdf.lua b/Master/texmf-dist/tex/context/base/meta-pdf.lua
index 512384450a8..3cbff63b168 100644
--- a/Master/texmf-dist/tex/context/base/meta-pdf.lua
+++ b/Master/texmf-dist/tex/context/base/meta-pdf.lua
@@ -329,7 +329,7 @@ handlers[50] = function() report_mptopdf("skipping special %s",50) end
--end of not supported
function mps.setrgbcolor(r,g,b) -- extra check
- r, g = tonumber(r), tonumber(g) -- needed when we use lpeg
+ r, g, b = tonumber(r), tonumber(g), tonumber(b) -- needed when we use lpeg
if r == 0.0123 and g < 0.1 then
g, b = round(g*10000), round(b*10000)
local s = specials[b]
@@ -411,7 +411,8 @@ function mps.fshow(str,font,scale) -- lpeg parser
mps.textext(font,scale,lpegmatch(package,str))
end
-local cnumber = lpegC(number)
+----- cnumber = lpegC(number)
+local cnumber = number/tonumber -- we now expect numbers (feeds into %F)
local cstring = lpegC(nonspace)
local specials = (lpegP("%%MetaPostSpecials:") * sp * (cstring * sp^0)^0 * eol) / mps.specials
@@ -572,3 +573,11 @@ statistics.register("mps conversion time",function()
return nil
end
end)
+
+-- interface
+
+interfaces.implement {
+ name = "convertmpstopdf",
+ arguments = "string",
+ actions = mptopdf.convertmpstopdf
+}
diff --git a/Master/texmf-dist/tex/context/base/meta-pdf.mkiv b/Master/texmf-dist/tex/context/base/meta-pdf.mkiv
index 3469419d468..50eb1dd720a 100644
--- a/Master/texmf-dist/tex/context/base/meta-pdf.mkiv
+++ b/Master/texmf-dist/tex/context/base/meta-pdf.mkiv
@@ -46,7 +46,7 @@
\forgetall
\offinterlineskip
\setbox\MPbox\vbox\bgroup
- \ctxlua{metapost.mptopdf.convertmpstopdf("\MPfilename")}%
+ \clf_convertmpstopdf{\MPfilename}%
\removeunwantedspaces % not that needed
\egroup
\finalizeMPbox
diff --git a/Master/texmf-dist/tex/context/base/meta-pdh.mkiv b/Master/texmf-dist/tex/context/base/meta-pdh.mkiv
index b65fe6ac697..f3db5b38866 100644
--- a/Master/texmf-dist/tex/context/base/meta-pdh.mkiv
+++ b/Master/texmf-dist/tex/context/base/meta-pdh.mkiv
@@ -374,17 +374,17 @@
%D
%D \startbuffer
%D \startuniqueMPgraphic{CircularShade}
-%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D path p ; p := unitsquare xscaled OverlayWidth yscaled OverlayHeight ;
%D circular_shade(p,0,.2red,.9red) ;
%D \stopuniqueMPgraphic
%D
%D \startuniqueMPgraphic{LinearShade}
-%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D path p ; p := unitsquare xscaled OverlayWidth yscaled OverlayHeight ;
%D linear_shade(p,0,.2blue,.9blue) ;
%D \stopuniqueMPgraphic
%D
%D \startuniqueMPgraphic{DuotoneShade}
-%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D path p ; p := unitsquare xscaled OverlayWidth yscaled OverlayHeight ;
%D linear_shade(p,2,.5green,.5red) ;
%D \stopuniqueMPgraphic
%D \stopbuffer
@@ -429,8 +429,8 @@
%D
%D \def\SomeShade#1#2#3#4#5%
%D {\startuniqueMPgraphic{Shade-#1}
-%D width := \overlaywidth ;
-%D height := \overlayheight ;
+%D width := OverlayWidth ;
+%D height := OverlayHeight ;
%D path p ; p := unitsquare xscaled width yscaled height ;
%D #2_shade(p,#3,#4,#5) ;
%D \stopuniqueMPgraphic
diff --git a/Master/texmf-dist/tex/context/base/meta-tex.lua b/Master/texmf-dist/tex/context/base/meta-tex.lua
index 7a4123abbb3..1008e45c05e 100644
--- a/Master/texmf-dist/tex/context/base/meta-tex.lua
+++ b/Master/texmf-dist/tex/context/base/meta-tex.lua
@@ -6,12 +6,15 @@ if not modules then modules = { } end modules ['meta-tex'] = {
license = "see context related readme files"
}
+local tostring = tostring
local format, gsub, find, match = string.format, string.gsub, string.find, string.match
local formatters = string.formatters
local P, S, R, C, Cs, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cs, lpeg.match
metapost = metapost or { }
+local implement = interfaces.implement
+
-- local left = P("[")
-- local right = P("]")
-- local space = P(" ")
@@ -39,6 +42,12 @@ function metapost.escaped(str)
context(lpegmatch(pattern,str))
end
+implement {
+ name = "metapostescaped",
+ actions = metapost.escaped,
+ arguments = "string"
+}
+
local simplify = true
-- local function strip(n,e)
@@ -108,10 +117,6 @@ local enumber = number * S("eE") * number
local cleaner = Cs((P("@@")/"@" + P("@")/"%%" + P(1))^0)
-function format_n(fmt,...)
- return
-end
-
context = context or { exponent = function(...) print(...) end }
function metapost.format_string(fmt,...)
@@ -142,6 +147,9 @@ function metapost.nvformat(fmt,str)
metapost.format_number(fmt,metapost.untagvariable(str,false))
end
+implement { name = "metapostformatted", actions = metapost.svformat, arguments = { "string", "string" } }
+implement { name = "metapostgraphformat", actions = metapost.nvformat, arguments = { "string", "string" } }
+
-- local function test(fmt,n)
-- logs.report("mp format test","fmt: %s, n: %s, result: %s, \\exponent{%s}{%s}",fmt,n,
-- formatters[lpegmatch(cleaner,fmt)](n),
@@ -167,3 +175,34 @@ end
-- test("@j","1.2e+102")
-- test("@j","1.23e+102")
-- test("@j","1.234e+102")
+
+local f_textext = formatters[ [[textext("%s")]] ]
+local f_mthtext = formatters[ [[textext("\mathematics{%s}")]] ]
+local f_exptext = formatters[ [[textext("\mathematics{%s\times10^{%s}}")]] ]
+
+local mpprint = mp.print
+
+function mp.format(fmt,str)
+ fmt = lpegmatch(cleaner,fmt)
+ mpprint(f_textext(formatters[fmt](metapost.untagvariable(str,false))))
+end
+
+function mp.formatted(fmt,num) -- svformat
+ fmt = lpegmatch(cleaner,fmt)
+ mpprint(f_textext(formatters[fmt](tonumber(num) or num)))
+end
+
+function mp.graphformat(fmt,num) -- nvformat
+ fmt = lpegmatch(cleaner,fmt)
+ local number = tonumber(num)
+ if number then
+ local base, exponent = lpegmatch(enumber,number)
+ if base and exponent then
+ mpprint(f_exptext(base,exponent))
+ else
+ mpprint(f_mthtext(num))
+ end
+ else
+ mpprint(f_textext(tostring(num)))
+ end
+end
diff --git a/Master/texmf-dist/tex/context/base/meta-tex.mkiv b/Master/texmf-dist/tex/context/base/meta-tex.mkiv
index e7ed5972787..0f5a27ff862 100644
--- a/Master/texmf-dist/tex/context/base/meta-tex.mkiv
+++ b/Master/texmf-dist/tex/context/base/meta-tex.mkiv
@@ -68,7 +68,7 @@
\unexpanded\def\definetextext[#1]%
{\def\currenttextext{#1}%
- \doifnextoptionalcselse\meta_textext_define_one\meta_textext_define_zero}
+ \doifelsenextoptionalcs\meta_textext_define_one\meta_textext_define_zero}
\def\meta_textext_define_one {\setvalue{\??graphictexarguments1:\currenttextext}}
\def\meta_textext_define_zero{\setvalue{\??graphictexarguments0:\currenttextext}}
@@ -76,10 +76,10 @@
\def\sometxt#1#{\meta_some_txt{#1}}
\def\meta_some_txt#1#2% we need to capture embedded quotes (a bit messy as later on textext is filtered
- {textext.drt("\mpsometxt#1{\ctxlua{metapost.escaped(\!!bs#2\!!es)}}")}
+ {textext.drt("\mpsometxt#1{\clf_metapostescaped{#2}}")}
\unexpanded\def\mpsometxt % no _ catcode
- {\doifnextoptionalcselse\meta_some_txt_indeed_yes\meta_some_txt_indeed_nop}
+ {\doifelsenextoptionalcs\meta_some_txt_indeed_yes\meta_some_txt_indeed_nop}
\def\meta_some_txt_indeed_yes[#1]%
{\def\currenttextext{#1}%
@@ -116,8 +116,8 @@
%
% \unexpanded\def\definetextext[#1]#2{\setvalue{@@st@@#1}{#2}}
%
-% \long\def\sometxt #1#{\dosometxt{#1}} % grab optional [args]
-% \long\def\dosometxt #1#2{\ctxlua{metapost.sometxt(\!!bs#1\!!es,\!!bs#2\!!es)}}
+% \def\sometxt #1#{\dosometxt{#1}} % grab optional [args]
+% \def\dosometxt #1#2{\ctxlua{metapost.sometxt(\!!bs#1\!!es,\!!bs#2\!!es)}}
%
% \def\sometxta #1{textext.drt("#1")}
% \def\sometxtb #1#2{textext.drt("\getvalue{@@st@@#1}{#2}")}
@@ -139,7 +139,7 @@
% {\showstruts\useMPgraphic{testgraphic}}
\unexpanded\def\MPexponent #1#2{\mathematics{#1\times10^{#2}}}
-\unexpanded\def\MPformatted #1#2{\ctxlua{metapost.svformat("#1","#2")}}
-\unexpanded\def\MPgraphformat#1#2{\ctxlua{metapost.nvformat("#1","#2")}}
+\unexpanded\def\MPformatted #1#2{\clf_metapostformatted{#1}{#2}}
+\unexpanded\def\MPgraphformat#1#2{\clf_metapostgraphformat{#1}{#2}}
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mlib-ctx.lua b/Master/texmf-dist/tex/context/base/mlib-ctx.lua
index fe52187719e..b437e1212c7 100644
--- a/Master/texmf-dist/tex/context/base/mlib-ctx.lua
+++ b/Master/texmf-dist/tex/context/base/mlib-ctx.lua
@@ -6,21 +6,28 @@ if not modules then modules = { } end modules ['mlib-ctx'] = {
license = "see context related readme files",
}
--- todo
+-- for the moment we have the scanners here but they migh tbe moved to
+-- the other modules
+local type, tostring = type, tostring
local format, concat = string.format, table.concat
local settings_to_hash = utilities.parsers.settings_to_hash
local report_metapost = logs.reporter("metapost")
-local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
+local starttiming = statistics.starttiming
+local stoptiming = statistics.stoptiming
-local mplib = mplib
+local mplib = mplib
-metapost = metapost or {}
-local metapost = metapost
+metapost = metapost or {}
+local metapost = metapost
-local v_no = interfaces.variables.no
+local setters = tokens.setters
+local setmacro = setters.macro
+local implement = interfaces.implement
+
+local v_no = interfaces.variables.no
metapost.defaultformat = "metafun"
metapost.defaultinstance = "metafun"
@@ -78,15 +85,155 @@ function metapost.getextensions(instance,state)
end
end
-function commands.getmpextensions(instance,state)
- context(metapost.getextensions(instance,state))
+-- function commands.getmpextensions(instance,state)
+-- context(metapost.getextensions(instance,state))
+-- end
+
+implement {
+ name = "setmpextensions",
+ actions = metapost.setextensions,
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "getmpextensions",
+ actions = { metapost.getextensions, context } ,
+ arguments = "string"
+}
+
+local report_metapost = logs.reporter ("metapost")
+local status_metapost = logs.messenger("metapost")
+
+local patterns = {
+ "meta-imp-%s.mkiv",
+ "meta-imp-%s.tex",
+ -- obsolete:
+ "meta-%s.mkiv",
+ "meta-%s.tex"
+}
+
+local function action(name,foundname)
+ status_metapost("library %a is loaded",name)
+ context.startreadingfile()
+ context.input(foundname)
+ context.stopreadingfile()
+end
+
+local function failure(name)
+ report_metapost("library %a is unknown or invalid",name)
end
+implement {
+ name = "useMPlibrary",
+ arguments = "string",
+ actions = function(name)
+ resolvers.uselibrary {
+ name = name,
+ patterns = patterns,
+ action = action,
+ failure = failure,
+ onlyonce = true,
+ }
+ end
+}
+
+-- metapost.variables = { } -- to be stacked
+
+implement {
+ name = "mprunvar",
+ arguments = "string",
+ actions = function(name)
+ local value = metapost.variables[name]
+ if value ~= nil then
+ local tvalue = type(value)
+ if tvalue == "table" then
+ context(concat(value," "))
+ elseif tvalue == "number" or tvalue == "boolean" then
+ context(tostring(value))
+ elseif tvalue == "string" then
+ context(value)
+ end
+ end
+ end
+}
+
+implement {
+ name = "mpruntab",
+ arguments = { "string", "integer" },
+ actions = function(name,n)
+ local value = metapost.variables[name]
+ if value ~= nil then
+ local tvalue = type(value)
+ if tvalue == "table" then
+ context(value[n])
+ elseif tvalue == "number" or tvalue == "boolean" then
+ context(tostring(value))
+ elseif tvalue == "string" then
+ context(value)
+ end
+ end
+ end
+}
+
+implement {
+ name = "mprunset",
+ actions = function(name,connector)
+ local value = metapost.variables[name]
+ if value ~= nil then
+ local tvalue = type(value)
+ if tvalue == "table" then
+ context(concat(value,connector))
+ elseif tvalue == "number" or tvalue == "boolean" then
+ context(tostring(value))
+ elseif tvalue == "string" then
+ context(value)
+ end
+ end
+ end
+}
+
+-- we need to move more from pps to here as pps is the plugin .. the order is a mess
+-- or just move the scanners to pps
+
function metapost.graphic(specification)
- setmpsformat(specification)
- metapost.graphic_base_pass(specification)
+ metapost.graphic_base_pass(setmpsformat(specification))
end
+implement {
+ name = "mpgraphic",
+ actions = metapost.graphic,
+ arguments = {
+ {
+ { "instance" },
+ { "format" },
+ { "data" },
+ { "initializations" },
+ { "extensions" },
+ { "inclusions" },
+ { "definitions" },
+ { "figure" },
+ { "method" },
+ }
+ }
+}
+
+implement {
+ name = "mpsetoutercolor",
+ actions = function(...) metapost.setoutercolor(...) end, -- not yet implemented
+ arguments = { "integer", "integer", "integer", "integer" }
+}
+
+implement {
+ name = "mpflushreset",
+ actions = function() metapost.flushreset() end -- not yet implemented
+}
+
+implement {
+ name = "mpflushliteral",
+ actions = function(str) metapost.flushliteral(str) end, -- not yet implemented
+ arguments = "string",
+}
+
function metapost.getclippath(specification) -- why not a special instance for this
setmpsformat(specification)
local mpx = specification.mpx
@@ -135,11 +282,31 @@ end
function metapost.theclippath(...)
local result = metapost.getclippath(...)
if result then -- we could just print the table
- result = concat(metapost.flushnormalpath(result),"\n")
- context(result)
+-- return concat(metapost.flushnormalpath(result),"\n")
+ return concat(metapost.flushnormalpath(result)," ")
+ else
+ return ""
end
end
+implement {
+ name = "mpsetclippath",
+ actions = function(specification)
+ setmacro("MPclippath",metapost.theclippath(specification),"global")
+ end,
+ arguments = {
+ {
+ { "instance" },
+ { "format" },
+ { "data" },
+ { "initializations" },
+ { "useextensions" },
+ { "inclusions" },
+ { "method" },
+ },
+ }
+}
+
statistics.register("metapost processing time", function()
local n = metapost.n
if n and n > 0 then
@@ -165,17 +332,44 @@ end)
-- only used in graphictexts
metapost.tex = metapost.tex or { }
+local mptex = metapost.tex
local environments = { }
-function metapost.tex.set(str)
+function mptex.set(str)
environments[#environments+1] = str
end
-function metapost.tex.reset()
- environments = { }
+function mptex.setfrombuffer(name)
+ environments[#environments+1] = buffers.content(name)
end
-function metapost.tex.get()
+function mptex.get()
return concat(environments,"\n")
end
+
+function mptex.reset()
+ environments = { }
+end
+
+implement {
+ name = "mptexset",
+ arguments = "string",
+ actions = mptex.set
+}
+
+implement {
+ name = "mptexsetfrombuffer",
+ arguments = "string",
+ actions = mptex.setfrombuffer
+}
+
+implement {
+ name = "mptexget",
+ actions = { mptex.get, context }
+}
+
+implement {
+ name = "mptexreset",
+ actions = mptex.reset
+}
diff --git a/Master/texmf-dist/tex/context/base/mlib-ctx.mkiv b/Master/texmf-dist/tex/context/base/mlib-ctx.mkiv
index e4c1cb6fe3e..a7bb612c854 100644
--- a/Master/texmf-dist/tex/context/base/mlib-ctx.mkiv
+++ b/Master/texmf-dist/tex/context/base/mlib-ctx.mkiv
@@ -19,6 +19,7 @@
\registerctxluafile{mlib-run}{1.001}
\registerctxluafile{mlib-ctx}{1.001}
\registerctxluafile{mlib-lua}{1.001}
+\registerctxluafile{mlib-int}{1.001} % here ?
\unprotect
diff --git a/Master/texmf-dist/tex/context/base/mlib-int.lua b/Master/texmf-dist/tex/context/base/mlib-int.lua
new file mode 100644
index 00000000000..43bf14d3831
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mlib-int.lua
@@ -0,0 +1,149 @@
+if not modules then modules = { } end modules ['mlib-int'] = {
+ version = 1.001,
+ comment = "companion to mlib-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+local factor = number.dimenfactors.bp
+local mpprint = mp.print
+local mpboolean = mp.boolean
+local mpquoted = mp.quoted
+local getdimen = tex.getdimen
+local getcount = tex.getcount
+local get = tex.get
+local mpcolor = attributes.colors.mpcolor
+local emwidths = fonts.hashes.emwidths
+local exheights = fonts.hashes.exheights
+
+function mp.PaperHeight () mpprint(getdimen("paperheight") *factor) end
+function mp.PaperWidth () mpprint(getdimen("paperwidth") *factor) end
+function mp.PrintPaperHeight () mpprint(getdimen("printpaperheight") *factor) end
+function mp.PrintPaperWidth () mpprint(getdimen("printpaperwidth") *factor) end
+function mp.TopSpace () mpprint(getdimen("topspace") *factor) end
+function mp.BottomSpace () mpprint(getdimen("bottomspace") *factor) end
+function mp.BackSpace () mpprint(getdimen("backspace") *factor) end
+function mp.CutSpace () mpprint(getdimen("cutspace") *factor) end
+function mp.MakeupHeight () mpprint(getdimen("makeupheight") *factor) end
+function mp.MakeupWidth () mpprint(getdimen("makeupwidth") *factor) end
+function mp.TopHeight () mpprint(getdimen("topheight") *factor) end
+function mp.TopDistance () mpprint(getdimen("topdistance") *factor) end
+function mp.HeaderHeight () mpprint(getdimen("headerheight") *factor) end
+function mp.HeaderDistance () mpprint(getdimen("headerdistance") *factor) end
+function mp.TextHeight () mpprint(getdimen("textheight") *factor) end
+function mp.FooterDistance () mpprint(getdimen("footerdistance") *factor) end
+function mp.FooterHeight () mpprint(getdimen("footerheight") *factor) end
+function mp.BottomDistance () mpprint(getdimen("bottomdistance") *factor) end
+function mp.BottomHeight () mpprint(getdimen("bottomheight") *factor) end
+function mp.LeftEdgeWidth () mpprint(getdimen("leftedgewidth") *factor) end
+function mp.LeftEdgeDistance () mpprint(getdimen("leftedgedistance") *factor) end
+function mp.LeftMarginWidth () mpprint(getdimen("leftmarginwidth") *factor) end
+function mp.LeftMarginDistance () mpprint(getdimen("leftmargindistance") *factor) end
+function mp.TextWidth () mpprint(getdimen("textwidth") *factor) end
+function mp.RightMarginDistance () mpprint(getdimen("rightmargindistance") *factor) end
+function mp.RightMarginWidth () mpprint(getdimen("rightmarginwidth") *factor) end
+function mp.RightEdgeDistance () mpprint(getdimen("rightedgedistance") *factor) end
+function mp.RightEdgeWidth () mpprint(getdimen("rightedgewidth") *factor) end
+function mp.InnerMarginDistance () mpprint(getdimen("innermargindistance") *factor) end
+function mp.InnerMarginWidth () mpprint(getdimen("innermarginwidth") *factor) end
+function mp.OuterMarginDistance () mpprint(getdimen("outermargindistance") *factor) end
+function mp.OuterMarginWidth () mpprint(getdimen("outermarginwidth") *factor) end
+function mp.InnerEdgeDistance () mpprint(getdimen("inneredgedistance") *factor) end
+function mp.InnerEdgeWidth () mpprint(getdimen("inneredgewidth") *factor) end
+function mp.OuterEdgeDistance () mpprint(getdimen("outeredgedistance") *factor) end
+function mp.OuterEdgeWidth () mpprint(getdimen("outeredgewidth") *factor) end
+function mp.PageOffset () mpprint(getdimen("pagebackgroundoffset")*factor) end
+function mp.PageDepth () mpprint(getdimen("pagebackgrounddepth") *factor) end
+function mp.LayoutColumns () mpprint(getcount("layoutcolumns")) end
+function mp.LayoutColumnDistance() mpprint(getdimen("layoutcolumndistance")*factor) end
+function mp.LayoutColumnWidth () mpprint(getdimen("layoutcolumnwidth") *factor) end
+function mp.SpineWidth () mpprint(getdimen("spinewidth") *factor) end
+function mp.PaperBleed () mpprint(getdimen("paperbleed") *factor) end
+
+function mp.PageNumber () mpprint(getcount("pageno")) end
+function mp.RealPageNumber () mpprint(getcount("realpageno")) end
+function mp.NOfPages () mpprint(getcount("lastpageno")) end
+
+function mp.CurrentColumn () mpprint(getcount("mofcolumns")) end
+function mp.NOfColumns () mpprint(getcount("nofcolumns")) end
+
+function mp.BaseLineSkip () mpprint(getdimen("baselineskip") *factor) end
+function mp.LineHeight () mpprint(getdimen("lineheight") *factor) end
+function mp.BodyFontSize () mpprint(getdimen("bodyfontsize") *factor) end
+
+function mp.TopSkip () mpprint(getdimen("topskip") *factor) end
+function mp.StrutHeight () mpprint(getdimen("strutht") *factor) end
+function mp.StrutDepth () mpprint(getdimen("strutdp") *factor) end
+
+function mp.PageNumber () mpprint(getcount("pageno")) end
+function mp.RealPageNumber () mpprint(getcount("realpageno")) end
+function mp.NOfPages () mpprint(getcount("lastpageno")) end
+
+function mp.CurrentWidth () mpprint(get("hsize") *factor) end
+function mp.CurrentHeight () mpprint(get("vsize") *factor) end
+
+function mp.EmWidth () mpprint(emwidths [false]*factor) end
+function mp.ExHeight () mpprint(exheights[false]*factor) end
+
+mp.HSize = mp.CurrentWidth
+mp.VSize = mp.CurrentHeight
+mp.LastPageNumber = mp.NOfPages
+
+function mp.PageFraction ()
+ local lastpage = getcount("lastpageno")
+ if lastpage > 1 then
+ mpprint((getcount("realpageno")-1)/(lastpage-1))
+ else
+ mpprint(1)
+ end
+end
+
+-- locals
+
+mp.OnRightPage = function() mpprint(structures.pages.on_right()) end -- needs checking
+mp.OnOddPage = function() mpprint(structures.pages.is_odd ()) end -- needs checking
+mp.InPageBody = function() mpprint(structures.pages.in_body ()) end -- needs checking
+
+-- mp.CurrentLayout : \currentlayout
+
+function mp.OverlayWidth () mpprint(getdimen("d_overlay_width") *factor) end
+function mp.OverlayHeight () mpprint(getdimen("d_overlay_height") *factor) end
+function mp.OverlayDepth () mpprint(getdimen("d_overlay_depth") *factor) end
+function mp.OverlayLineWidth () mpprint(getdimen("d_overlay_linewidth")*factor) end
+function mp.OverlayOffset () mpprint(getdimen("d_overlay_offset") *factor) end
+
+function mp.defaultcolormodel()
+ local colormethod = getcount("MPcolormethod")
+ -- if colormethod == 0 then
+ -- return 1
+ -- elseif colormethod == 1 then
+ -- return 1
+ -- elseif colormethod == 2 then
+ -- return 3
+ -- else
+ -- return 3
+ -- end
+ return (colormethod == 0 or colormethod == 1) and 1 or 3
+end
+
+-- not much difference (10000 calls in a graphic neither as expansion seems to win
+-- over defining the macro etc) so let's not waste counters then
+
+-- function mp.OverlayColor()
+-- local c = mpcolor(
+-- getcount("c_overlay_colormodel"),
+-- getcount("c_overlay_color"),
+-- getcount("c_overlay_transparency")
+-- )
+-- mpquoted(c)
+-- end
+--
+-- function mp.OverlayLineColor()
+-- local c = mpcolor(
+-- getcount("c_overlay_colormodel"),
+-- getcount("c_overlay_linecolor"),
+-- getcount("c_overlay_linetransparency")
+-- )
+-- mpquoted(c)
+-- end
diff --git a/Master/texmf-dist/tex/context/base/mlib-lua.lua b/Master/texmf-dist/tex/context/base/mlib-lua.lua
index e3a3ba5d8db..7e05684630d 100644
--- a/Master/texmf-dist/tex/context/base/mlib-lua.lua
+++ b/Master/texmf-dist/tex/context/base/mlib-lua.lua
@@ -1,4 +1,4 @@
-if not modules then modules = { } end modules ['mlib-pdf'] = {
+if not modules then modules = { } end modules ['mlib-lua'] = {
version = 1.001,
comment = "companion to mlib-ctx.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -11,16 +11,21 @@ if not modules then modules = { } end modules ['mlib-pdf'] = {
-- maybe we need mplib.model, but how with instances
local type, tostring, select, loadstring = type, tostring, select, loadstring
-local formatters = string.formatters
local find, gsub = string.find, string.gsub
-local concat = table.concat
-local lpegmatch = lpeg.match
+
+local formatters = string.formatters
+local concat = table.concat
+local lpegmatch = lpeg.match
+
+local P, S, Ct = lpeg.P, lpeg.S, lpeg.Ct
local report_luarun = logs.reporter("metapost","lua")
local trace_luarun = false trackers.register("metapost.lua",function(v) trace_luarun = v end)
local trace_enabled = true
+local be_tolerant = true directives.register("metapost.lua.tolerant",function(v) be_tolerant = v end)
+
mp = mp or { } -- system namespace
MP = MP or { } -- user namespace
@@ -53,6 +58,8 @@ function mp._f_()
end
end
+local f_code = formatters["%s return mp._f_()"]
+
local f_numeric = formatters["%.16f"]
local f_pair = formatters["(%.16f,%.16f)"]
local f_triplet = formatters["(%.16f,%.16f,%.16f)"]
@@ -61,20 +68,32 @@ local f_quadruple = formatters["(%.16f,%.16f,%.16f,%.16f)"]
function mp.print(...)
for i=1,select("#",...) do
local value = select(i,...)
- if value then
+ if value ~= nil then
n = n + 1
local t = type(value)
if t == "number" then
buffer[n] = f_numeric(value)
elseif t == "string" then
buffer[n] = value
- else
+ elseif t == "table" then
+ buffer[n] = "(" .. concat(value,",") .. ")"
+ else -- boolean or whatever
buffer[n] = tostring(value)
end
end
end
end
+function mp.boolean(n)
+ n = n + 1
+ buffer[n] = n and "true" or "false"
+end
+
+function mp.numeric(n)
+ n = n + 1
+ buffer[n] = n and f_numeric(n) or "0"
+end
+
function mp.pair(x,y)
n = n + 1
if type(x) == "table" then
@@ -102,6 +121,55 @@ function mp.quadruple(w,x,y,z)
end
end
+function mp.path(t,connector,cycle)
+ if type(t) == "table" then
+ local tn = #t
+ if tn > 0 then
+ if connector == true then
+ connector = "--"
+ cycle = true
+ elseif not connector then
+ connector = "--"
+ end
+ local ti = t[1]
+ n = n + 1 ; buffer[n] = f_pair(ti[1],ti[2])
+ for i=2,tn do
+ local ti = t[i]
+ n = n + 1 ; buffer[n] = connector
+ n = n + 1 ; buffer[n] = f_pair(ti[1],ti[2])
+ end
+ if cycle then
+ n = n + 1 ; buffer[n] = connector
+ n = n + 1 ; buffer[n] = "cycle"
+ end
+ end
+ end
+end
+
+function mp.size(t)
+ n = n + 1
+ buffer[n] = type(t) == "table" and f_numeric(#t) or "0"
+end
+
+-- experiment: names can change
+
+local datasets = { }
+mp.datasets = datasets
+
+function datasets.load(tag,filename)
+ if not filename then
+ tag, filename = file.basename(tag), tag
+ end
+ local data = mp.dataset(io.loaddata(filename) or "")
+ datasets[tag] = {
+ Data = data,
+ Line = function(n) mp.path(data[n or 1]) end,
+ Size = function() mp.size(data) end,
+ }
+end
+
+--
+
local replacer = lpeg.replacer("@","%%")
function mp.format(fmt,...)
@@ -124,7 +192,53 @@ function mp.quoted(fmt,s,...)
end
end
-local f_code = formatters["%s return mp._f_()"]
+function mp.n(t)
+ return type(t) == "table" and #t or 0
+end
+
+local whitespace = lpeg.patterns.whitespace
+local newline = lpeg.patterns.newline
+local setsep = newline^2
+local comment = (S("#%") + P("--")) * (1-newline)^0 * (whitespace - setsep)^0
+local value = (1-whitespace)^1 / tonumber
+local entry = Ct( value * whitespace * value)
+local set = Ct((entry * (whitespace-setsep)^0 * comment^0)^1)
+local series = Ct((set * whitespace^0)^1)
+
+local pattern = whitespace^0 * series
+
+function mp.dataset(str)
+ return lpegmatch(pattern,str)
+end
+
+-- \startluacode
+-- local str = [[
+-- 10 20 20 20
+-- 30 40 40 60
+-- 50 10
+--
+-- 10 10 20 30
+-- 30 50 40 50
+-- 50 20 -- the last one
+--
+-- 10 20 % comment
+-- 20 10
+-- 30 40 # comment
+-- 40 20
+-- 50 10
+-- ]]
+--
+-- MP.myset = mp.dataset(str)
+--
+-- inspect(MP.myset)
+-- \stopluacode
+--
+-- \startMPpage
+-- color c[] ; c[1] := red ; c[2] := green ; c[3] := blue ;
+-- for i=1 upto lua("mp.print(mp.n(MP.myset))") :
+-- draw lua("mp.path(MP.myset[" & decimal i & "])") withcolor c[i] ;
+-- endfor ;
+-- \stopMPpage
-- function metapost.runscript(code)
-- local f = loadstring(f_code(code))
@@ -147,13 +261,17 @@ local f_code = formatters["%s return mp._f_()"]
local cache, n = { }, 0 -- todo: when > n then reset cache or make weak
function metapost.runscript(code)
- if trace_enabled and trace_luarun then
+ local trace = trace_enabled and trace_luarun
+ if trace then
report_luarun("code: %s",code)
end
local f
if n > 100 then
cache = nil -- forget about caching
f = loadstring(f_code(code))
+ if not f and be_tolerant then
+ f = loadstring(code)
+ end
else
f = cache[code]
if not f then
@@ -161,6 +279,12 @@ function metapost.runscript(code)
if f then
n = n + 1
cache[code] = f
+ elseif be_tolerant then
+ f = loadstring(code)
+ if f then
+ n = n + 1
+ cache[code] = f
+ end
end
end
end
@@ -169,13 +293,21 @@ function metapost.runscript(code)
if result then
local t = type(result)
if t == "number" then
- return f_numeric(result)
+ t = f_numeric(result)
elseif t == "string" then
- return result
+ t = result
else
- return tostring(result)
+ t = tostring(result)
end
+ if trace then
+ report_luarun("result: %s",code)
+ end
+ return t
+ elseif trace then
+ report_luarun("no result")
end
+ else
+ report_luarun("no result, invalid code")
end
return ""
end
@@ -201,12 +333,51 @@ local get_number = get_numeric
local currentmpx = nil
-mp.numeric = function(s) return get_numeric(currentmpx,s) end
-mp.string = function(s) return get_string (currentmpx,s) end
-mp.boolean = function(s) return get_boolean(currentmpx,s) end
-mp.number = mp.numeric
+local get = { }
+mp.get = get
+
+get.numeric = function(s) return get_numeric(currentmpx,s) end
+get.string = function(s) return get_string (currentmpx,s) end
+get.boolean = function(s) return get_boolean(currentmpx,s) end
+get.number = mp.numeric
function metapost.initializescriptrunner(mpx,trialrun)
currentmpx = mpx
- trace_enabled = not trialrun
+ if trace_luarun then
+ report_luarun("type of run: %s", trialrun and "trial" or "final")
+ end
+ -- trace_enabled = not trialrun blocks too much
+end
+
+-- texts:
+
+local factor = 65536*(7227/7200)
+local textexts = nil
+local mptriplet = mp.triplet
+
+function mp.tt_initialize(tt)
+ textexts = tt
+end
+
+-- function mp.tt_wd(n)
+-- local box = textexts and textexts[n]
+-- mpprint(box and box.width/factor or 0)
+-- end
+-- function mp.tt_ht(n)
+-- local box = textexts and textexts[n]
+-- mpprint(box and box.height/factor or 0)
+-- end
+-- function mp.tt_dp(n)
+-- local box = textexts and textexts[n]
+-- mpprint(box and box.depth/factor or 0)
+-- end
+
+function mp.tt_dimensions(n)
+ local box = textexts[n]
+ if box then
+ -- could be made faster with nuts but not critical
+ mptriplet(box.width/factor,box.height/factor,box.depth/factor)
+ else
+ mptriplet(0,0,0)
+ end
end
diff --git a/Master/texmf-dist/tex/context/base/mlib-pdf.lua b/Master/texmf-dist/tex/context/base/mlib-pdf.lua
index d25dde88469..8de09f42a60 100644
--- a/Master/texmf-dist/tex/context/base/mlib-pdf.lua
+++ b/Master/texmf-dist/tex/context/base/mlib-pdf.lua
@@ -19,13 +19,19 @@ local report_metapost = logs.reporter("metapost")
local trace_variables = false trackers.register("metapost.variables",function(v) trace_variables = v end)
-local mplib, context = mplib, context
+local mplib = mplib
+local context = context
local allocate = utilities.storage.allocate
local copy_node = node.copy
local write_node = node.write
+local pen_info = mplib.pen_info
+local object_fields = mplib.fields
+
+local save_table = false
+
metapost = metapost or { }
local metapost = metapost
@@ -33,7 +39,6 @@ metapost.flushers = metapost.flushers or { }
local pdfflusher = { }
metapost.flushers.pdf = pdfflusher
-metapost.multipass = false -- to be stacked
metapost.n = 0
metapost.optimize = true -- false
@@ -53,9 +58,19 @@ local f_J = formatters["%i J"]
local f_d = formatters["[%s] %F d"]
local f_w = formatters["%F w"]
-local pdfliteral = function(s)
+directives.register("metapost.savetable",function(v)
+ if type(v) == "string" then
+ save_table = file.addsuffix(v,"mpl")
+ elseif v then
+ save_table = file.addsuffix(environment.jobname .. "-graphic","mpl")
+ else
+ save_table = false
+ end
+end)
+
+local pdfliteral = function(pdfcode)
local literal = copy_node(mpsliteral)
- literal.data = s
+ literal.data = pdfcode
return literal
end
@@ -64,18 +79,19 @@ end
-- get a new result table and the stored objects are forgotten. Otherwise they
-- are reused.
-local function getobjects(result,figure,f)
+local function getobjects(result,figure,index)
if metapost.optimize then
- local objects = result.objects
- if not objects then
- result.objects = { }
+ local robjects = result.objects
+ if not robjects then
+ robjects = { }
+ result.objects = robjects
end
- objects = result.objects[f]
- if not objects then
- objects = figure:objects()
- result.objects[f] = objects
+ local fobjects = robjects[index or 1]
+ if not fobjects then
+ fobjects = figure:objects()
+ robjects[index] = fobjects
end
- return objects
+ return fobjects
else
return figure:objects()
end
@@ -83,15 +99,20 @@ end
function metapost.convert(result, trialrun, flusher, multipass, askedfig)
if trialrun then
- metapost.multipass = false
- metapost.parse(result, askedfig)
- if multipass and not metapost.multipass and metapost.optimize then
- metapost.flush(result, flusher, askedfig) -- saves a run
+ local multipassindeed = metapost.parse(result,askedfig)
+ if multipass and not multipassindeed and metapost.optimize then
+ if save_table then
+ table.save(save_table,metapost.totable(result,1)) -- direct
+ end
+ metapost.flush(result,flusher,askedfig) -- saves a run
else
return false
end
else
- metapost.flush(result, flusher, askedfig)
+ if save_table then
+ table.save(save_table,metapost.totable(result,1)) -- direct
+ end
+ metapost.flush(result,flusher,askedfig)
end
return true -- done
end
@@ -168,8 +189,6 @@ local bend_tolerance = 131/65536
local rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1
-local pen_info = mplib.pen_info
-
local function pen_characteristics(object)
local t = pen_info(object)
rx, ry, sx, sy, tx, ty = t.rx, t.ry, t.sx, t.sy, t.tx, t.ty
@@ -323,32 +342,8 @@ local variable =
local pattern_lst = (variable * newline^0)^0
-metapost.variables = { } -- to be stacked
-metapost.llx = 0 -- to be stacked
-metapost.lly = 0 -- to be stacked
-metapost.urx = 0 -- to be stacked
-metapost.ury = 0 -- to be stacked
-
-function commands.mprunvar(key,n) -- should be defined in another lib
- local value = metapost.variables[key]
- if value ~= nil then
- local tvalue = type(value)
- if tvalue == "table" then
- local ntype = type(n)
- if ntype == "number" then
- context(value[n])
- elseif ntype == "string" then
- context(concat(value,n))
- else
- context(concat(value," "))
- end
- elseif tvalue == "number" or tvalue == "boolean" then
- context(tostring(value))
- elseif tvalue == "string" then
- context(value)
- end
- end
-end
+metapost.variables = { } -- to be stacked
+metapost.properties = { } -- to be stacked
function metapost.untagvariable(str,variables) -- will be redone
if variables == false then
@@ -374,6 +369,30 @@ function metapost.processspecial(str)
end
end
+local function setproperties(figure)
+ local boundingbox = figure:boundingbox()
+ local properties = {
+ llx = boundingbox[1],
+ lly = boundingbox[2],
+ urx = boundingbox[3],
+ ury = boundingbox[4],
+ slot = figure:charcode(),
+ width = figure:width(),
+ height = figure:height(),
+ depth = figure:depth(),
+ italic = figure:italcorr(),
+ number = figure:charcode() or 0,
+ }
+ metapost.properties = properties
+ return properties
+end
+
+local function setvariables(figure)
+ local variables = { }
+ metapost.variables = variables
+ return variables
+end
+
function metapost.flush(result,flusher,askedfig)
if result then
local figures = result.fig
@@ -388,42 +407,27 @@ function metapost.flush(result,flusher,askedfig)
local flushfigure = flusher.flushfigure
local textfigure = flusher.textfigure
local processspecial = flusher.processspecial or metapost.processspecial
- for f=1,#figures do
- local figure = figures[f]
- local objects = getobjects(result,figure,f)
- local fignum = figure:charcode() or 0
- if askedfig == "direct" or askedfig == "all" or askedfig == fignum then
- local t = { }
+ local variables = setvariables(figure) -- also resets then in case of not found
+ for index=1,#figures do
+ local figure = figures[index]
+ local properties = setproperties(figure)
+ if askedfig == "direct" or askedfig == "all" or askedfig == properties.number then
+ local objects = getobjects(result,figure,index)
+ local result = { }
local miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
- local bbox = figure:boundingbox()
- local llx, lly, urx, ury = bbox[1], bbox[2], bbox[3], bbox[4]
- local variables = { }
- metapost.variables = variables
- metapost.properties = {
- llx = llx,
- lly = lly,
- urx = urx,
- ury = ury,
- slot = figure:charcode(),
- width = figure:width(),
- height = figure:height(),
- depth = figure:depth(),
- italic = figure:italcorr(),
- }
- -- replaced by the above
- metapost.llx = llx
- metapost.lly = lly
- metapost.urx = urx
- metapost.ury = ury
+ local llx = properties.llx
+ local lly = properties.lly
+ local urx = properties.urx
+ local ury = properties.ury
if urx < llx then
-- invalid
- startfigure(fignum,0,0,0,0,"invalid",figure)
+ startfigure(properties.number,0,0,0,0,"invalid",figure)
stopfigure()
else
- startfigure(fignum,llx,lly,urx,ury,"begin",figure)
- t[#t+1] = "q"
+ startfigure(properties.number,llx,lly,urx,ury,"begin",figure)
+ result[#result+1] = "q"
if objects then
- resetplugins(t) -- we should move the colorinitializer here
+ resetplugins(result) -- we should move the colorinitializer here
for o=1,#objects do
local object = objects[o]
local objecttype = object.type
@@ -434,20 +438,21 @@ function metapost.flush(result,flusher,askedfig)
processspecial(object.prescript)
end
elseif objecttype == "start_clip" then
- t[#t+1] = "q"
- flushnormalpath(object.path,t,false)
- t[#t+1] = "W n"
+ local evenodd = not object.istext and object.postscript == "evenodd"
+ result[#result+1] = "q"
+ flushnormalpath(object.path,result,false)
+ result[#result+1] = evenodd and "W* n" or "W n"
elseif objecttype == "stop_clip" then
- t[#t+1] = "Q"
- miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
+ result[#result+1] = "Q"
+ miterlimit, linecap, linejoin, dashed = -1, -1, -1, "" -- was false
elseif objecttype == "text" then
- t[#t+1] = "q"
+ result[#result+1] = "q"
local ot = object.transform -- 3,4,5,6,1,2
- t[#t+1] = f_cm(ot[3],ot[4],ot[5],ot[6],ot[1],ot[2]) -- TH: formatters["%F %F m %F %F %F %F 0 0 cm"](unpack(ot))
- flushfigure(t) -- flush accumulated literals
- t = { }
+ result[#result+1] = f_cm(ot[3],ot[4],ot[5],ot[6],ot[1],ot[2]) -- TH: formatters["%F %F m %F %F %F %F 0 0 cm"](unpack(ot))
+ flushfigure(result) -- flush accumulated literals
+ result = { }
textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth)
- t[#t+1] = "Q"
+ result[#result+1] = "Q"
else
-- we use an indirect table as we want to overload
-- entries but this is not possible in userdata
@@ -463,32 +468,32 @@ function metapost.flush(result,flusher,askedfig)
local before, after = processplugins(object)
local objecttype = object.type -- can have changed
if before then
- t = pluginactions(before,t,flushfigure)
+ result = pluginactions(before,result,flushfigure)
end
local ml = object.miterlimit
if ml and ml ~= miterlimit then
miterlimit = ml
- t[#t+1] = f_M(ml)
+ result[#result+1] = f_M(ml)
end
local lj = object.linejoin
if lj and lj ~= linejoin then
linejoin = lj
- t[#t+1] = f_j(lj)
+ result[#result+1] = f_j(lj)
end
local lc = object.linecap
if lc and lc ~= linecap then
linecap = lc
- t[#t+1] = f_J(lc)
+ result[#result+1] = f_J(lc)
end
local dl = object.dash
if dl then
local d = f_d(concat(dl.dashes or {}," "),dl.offset)
if d ~= dashed then
dashed = d
- t[#t+1] = dashed
+ result[#result+1] = d
end
- elseif dashed then
- t[#t+1] = "[] 0 d"
+ elseif dashed ~= false then -- was just dashed test
+ result[#result+1] = "[] 0 d"
dashed = false
end
local path = object.path -- newpath
@@ -498,7 +503,7 @@ function metapost.flush(result,flusher,askedfig)
if pen then
if pen.type == 'elliptical' then
transformed, penwidth = pen_characteristics(original) -- boolean, value
- t[#t+1] = f_w(penwidth) -- todo: only if changed
+ result[#result+1] = f_w(penwidth) -- todo: only if changed
if objecttype == 'fill' then
objecttype = 'both'
end
@@ -507,58 +512,59 @@ function metapost.flush(result,flusher,askedfig)
end
end
if transformed then
- t[#t+1] = "q"
+ result[#result+1] = "q"
end
+ local evenodd = not object.istext and object.postscript == "evenodd"
if path then
if transformed then
- flushconcatpath(path,t,open)
+ flushconcatpath(path,result,open)
else
- flushnormalpath(path,t,open)
+ flushnormalpath(path,result,open)
end
if objecttype == "fill" then
- t[#t+1] = "h f"
+ result[#result+1] = evenodd and "h f*" or "h f" -- f* = eo
elseif objecttype == "outline" then
- t[#t+1] = open and "S" or "h S"
+ result[#result+1] = open and "S" or "h S"
elseif objecttype == "both" then
- t[#t+1] = "h B"
+ result[#result+1] = evenodd and "h B*" or "h B"-- B* = eo -- b includes closepath
end
end
if transformed then
- t[#t+1] = "Q"
+ result[#result+1] = "Q"
end
local path = object.htap
if path then
if transformed then
- t[#t+1] = "q"
+ result[#result+1] = "q"
end
if transformed then
- flushconcatpath(path,t,open)
+ flushconcatpath(path,result,open)
else
- flushnormalpath(path,t,open)
+ flushnormalpath(path,result,open)
end
if objecttype == "fill" then
- t[#t+1] = "h f"
+ result[#result+1] = evenodd and "h f*" or "h f" -- f* = eo
elseif objecttype == "outline" then
- t[#t+1] = open and "S" or "h S"
+ result[#result+1] = open and "S" or "h S"
elseif objecttype == "both" then
- t[#t+1] = "h B"
+ result[#result+1] = evenodd and "h B*" or "h B"-- B* = eo -- b includes closepath
end
if transformed then
- t[#t+1] = "Q"
+ result[#result+1] = "Q"
end
end
if after then
- t = pluginactions(after,t,flushfigure)
+ result = pluginactions(after,result,flushfigure)
end
if object.grouped then
-- can be qQ'd so changes can end up in groups
- miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
+ miterlimit, linecap, linejoin, dashed = -1, -1, -1, "" -- was false
end
end
end
end
- t[#t+1] = "Q"
- flushfigure(t)
+ result[#result+1] = "Q"
+ flushfigure(result)
stopfigure("end")
end
if askedfig ~= "all" then
@@ -574,20 +580,18 @@ function metapost.parse(result,askedfig)
if result then
local figures = result.fig
if figures then
+ local multipass = false
local analyzeplugins = metapost.analyzeplugins -- each object
- for f=1,#figures do
- local figure = figures[f]
- local fignum = figure:charcode() or 0
- if askedfig == "direct" or askedfig == "all" or askedfig == fignum then
- local bbox = figure:boundingbox()
- metapost.llx = bbox[1]
- metapost.lly = bbox[2]
- metapost.urx = bbox[3]
- metapost.ury = bbox[4]
- local objects = getobjects(result,figure,f)
+ for index=1,#figures do
+ local figure = figures[index]
+ local properties = setproperties(figure)
+ if askedfig == "direct" or askedfig == "all" or askedfig == properties.number then
+ local objects = getobjects(result,figure,index)
if objects then
for o=1,#objects do
- analyzeplugins(objects[o])
+ if analyzeplugins(objects[o]) then
+ multipass = true
+ end
end
end
if askedfig ~= "all" then
@@ -595,24 +599,24 @@ function metapost.parse(result,askedfig)
end
end
end
+ return multipass
end
end
end
-- tracing:
-local t = { }
+local result = { }
local flusher = {
startfigure = function()
- t = { }
+ result = { }
context.startnointerference()
end,
flushfigure = function(literals)
- local n = #t
- for i=1, #literals do
- n = n + 1
- t[n] = literals[i]
+ local n = #result
+ for i=1,#literals do
+ result[n+i] = literals[i]
end
end,
stopfigure = function()
@@ -622,30 +626,35 @@ local flusher = {
function metapost.pdfliterals(result)
metapost.flush(result,flusher)
- return t
+ return result
end
--- so far
-
-function metapost.totable(result)
- local figure = result and result.fig and result.fig[1]
+function metapost.totable(result,askedfig)
+ local askedfig = askedfig or 1
+ local figure = result and result.fig and result.fig[1]
if figure then
- local t = { }
- local objects = figure:objects()
+ local results = { }
+ -- local objects = figure:objects()
+ local objects = getobjects(result,figure,askedfig)
for o=1,#objects do
local object = objects[o]
- local tt = { }
- local fields = mplib.fields(object)
+ local result = { }
+ local fields = object_fields(object) -- hm, is this the whole list, if so, we can get it once
for f=1,#fields do
local field = fields[f]
- tt[field] = object[field]
+ result[field] = object[field]
end
- t[o] = tt
+ results[o] = result
end
- local b = figure:boundingbox()
+ local boundingbox = figure:boundingbox()
return {
- boundingbox = { llx = b[1], lly = b[2], urx = b[3], ury = b[4] },
- objects = t
+ boundingbox = {
+ llx = boundingbox[1],
+ lly = boundingbox[2],
+ urx = boundingbox[3],
+ ury = boundingbox[4],
+ },
+ objects = results
}
else
return nil
diff --git a/Master/texmf-dist/tex/context/base/mlib-pdf.mkiv b/Master/texmf-dist/tex/context/base/mlib-pdf.mkiv
index 0913b3699ae..92bf86ea9f1 100644
--- a/Master/texmf-dist/tex/context/base/mlib-pdf.mkiv
+++ b/Master/texmf-dist/tex/context/base/mlib-pdf.mkiv
@@ -88,7 +88,7 @@
% MPLIB specific:
-\def\MPLIBtoPDF#1{\ctxlua{metapost.flushliteral(#1)}}
+\def\MPLIBtoPDF{\clf_mpflushliteral}
\def\startMPLIBtoPDF#1#2#3#4%
{\meta_process_graphic_figure_start
@@ -109,7 +109,7 @@
\meta_process_graphic_figure_stop}
\def\MPLIBflushreset % This can (will) move to the Lua end.
- {\ctxlua{metapost.flushreset()}}
+ {\clf_mpflushreset}
%D Kind of special:
%
@@ -134,27 +134,50 @@
\unexpanded\def\directMPgraphic
{\dodoublegroupempty\mlib_direct_graphic}
+% \def\mlib_direct_graphic#1#2% makes pages (todo: make boxes)
+% {\meta_begin_graphic_group{#1}%
+% \let\startMPLIBtoPDF\directstartMPLIBtoPDF
+% \let\stopMPLIBtoPDF \directstopMPLIBtoPDF
+% \meta_start_current_graphic
+% \forgetall
+% \edef\p_extensions{\MPinstanceparameter\s!extensions}%
+% \normalexpanded{\noexpand\ctxlua{metapost.graphic {
+% instance = "\currentMPinstance",
+% format = "\currentMPformat",
+% data = \!!bs#2;\!!es,
+% initializations = \!!bs\meta_flush_current_initializations\!!es,
+% % useextensions = "\MPinstanceparameter\s!extensions",
+% \ifx\p_extensions\v!yes
+% extensions = \!!bs\clf_getmpextensions{\currentMPinstance}\!!es,
+% \fi
+% inclusions = \!!bs\meta_flush_current_inclusions\!!es,
+% definitions = \!!bs\meta_flush_current_definitions\!!es,
+% figure = "all",
+% method = "\MPinstanceparameter\c!method",
+% }}}%
+% \meta_stop_current_graphic
+% \meta_end_graphic_group}
+
\def\mlib_direct_graphic#1#2% makes pages (todo: make boxes)
{\meta_begin_graphic_group{#1}%
\let\startMPLIBtoPDF\directstartMPLIBtoPDF
\let\stopMPLIBtoPDF \directstopMPLIBtoPDF
\meta_start_current_graphic
- \forgetall
- \edef\p_extensions{\MPinstanceparameter\s!extensions}%
- \normalexpanded{\noexpand\ctxlua{metapost.graphic {
- instance = "\currentMPinstance",
- format = "\currentMPformat",
- data = \!!bs#2;\!!es,
- initializations = \!!bs\meta_flush_current_initializations\!!es,
-% useextensions = "\MPinstanceparameter\s!extensions",
-\ifx\p_extensions\v!yes
- extensions = \!!bs\ctxcommand{getmpextensions("\currentMPinstance")}\!!es,
-\fi
- inclusions = \!!bs\meta_flush_current_inclusions\!!es,
- definitions = \!!bs\meta_flush_current_definitions\!!es,
- figure = "all",
- method = "\MPinstanceparameter\c!method",
- }}}%
+ \forgetall
+ \edef\p_extensions{\MPinstanceparameter\s!extensions}%
+ \normalexpanded{\noexpand\clf_mpgraphic
+ instance {\currentMPinstance}%
+ format {\currentMPformat}%
+ data {#2;}%
+ initializations {\meta_flush_current_initializations}%
+ \ifx\p_extensions\v!yes
+ extensions {\clf_getmpextensions{\currentMPinstance}}%
+ \fi
+ inclusions {\meta_flush_current_inclusions}%
+ definitions {\meta_flush_current_definitions}%
+ figure {all}%
+ method {\MPinstanceparameter\c!method}%
+ \relax}%
\meta_stop_current_graphic
\meta_end_graphic_group}
diff --git a/Master/texmf-dist/tex/context/base/mlib-pps.lua b/Master/texmf-dist/tex/context/base/mlib-pps.lua
index ce95d5ca734..ab56699b9f9 100644
--- a/Master/texmf-dist/tex/context/base/mlib-pps.lua
+++ b/Master/texmf-dist/tex/context/base/mlib-pps.lua
@@ -6,10 +6,8 @@ if not modules then modules = { } end modules ['mlib-pps'] = {
license = "see context related readme files",
}
--- todo: pass multipass nicer
-
local format, gmatch, match, split = string.format, string.gmatch, string.match, string.split
-local tonumber, type = tonumber, type
+local tonumber, type, unpack = tonumber, type, unpack
local round = math.round
local insert, remove, concat = table.insert, table.remove, table.concat
local Cs, Cf, C, Cg, Ct, P, S, V, Carg = lpeg.Cs, lpeg.Cf, lpeg.C, lpeg.Cg, lpeg.Ct, lpeg.P, lpeg.S, lpeg.V, lpeg.Carg
@@ -21,8 +19,12 @@ local mplib, metapost, lpdf, context = mplib, metapost, lpdf, context
local context = context
local context_setvalue = context.setvalue
+local implement = interfaces.implement
+local setmacro = interfaces.setmacro
+
local texgetbox = tex.getbox
local texsetbox = tex.setbox
+local textakebox = tex.takebox
local copy_list = node.copy_list
local free_list = node.flush_list
local setmetatableindex = table.setmetatableindex
@@ -40,11 +42,19 @@ local report_textexts = logs.reporter("metapost","textexts")
local report_scripts = logs.reporter("metapost","scripts")
local colors = attributes.colors
+local defineprocesscolor = colors.defineprocesscolor
+local definespotcolor = colors.definespotcolor
+local definemultitonecolor = colors.definemultitonecolor
+local colorvalue = colors.value
+
+local transparencies = attributes.transparencies
+local registertransparency = transparencies.register
+local transparencyvalue = transparencies.value
-local rgbtocmyk = colors.rgbtocmyk or function() return 0,0,0,1 end
-local cmyktorgb = colors.cmyktorgb or function() return 0,0,0 end
-local rgbtogray = colors.rgbtogray or function() return 0 end
-local cmyktogray = colors.cmyktogray or function() return 0 end
+local rgbtocmyk = colors.rgbtocmyk -- or function() return 0,0,0,1 end
+local cmyktorgb = colors.cmyktorgb -- or function() return 0,0,0 end
+local rgbtogray = colors.rgbtogray -- or function() return 0 end
+local cmyktogray = colors.cmyktogray -- or function() return 0 end
metapost.makempy = metapost.makempy or { nofconverted = 0 }
local makempy = metapost.makempy
@@ -59,11 +69,6 @@ local innertransparency = nooutertransparency
local pdfcolor = lpdf.color
local pdftransparency = lpdf.transparency
-local registercolor = colors.register
-local registerspotcolor = colors.registerspotcolor
-
-local transparencies = attributes.transparencies
-local registertransparency = transparencies.register
function metapost.setoutercolor(mode,colormodel,colorattribute,transparencyattribute)
-- has always to be called before conversion
@@ -85,6 +90,8 @@ function metapost.setoutercolor(mode,colormodel,colorattribute,transparencyattri
innertransparency = outertransparency -- not yet used
end
+-- todo: get this from the lpdf module
+
local f_f = formatters["%F"]
local f_f3 = formatters["%.3F"]
@@ -94,6 +101,8 @@ local f_cmyk = formatters["%.3F %.3F %.3F %.3F k %.3F %.3F %.3F %.3F K"]
local f_cm = formatters["q %F %F %F %F %F %F cm"]
local f_shade = formatters["MpSh%s"]
+local f_spot = formatters["/%s cs /%s CS %s SCN %s scn"]
+
local function checked_color_pair(color,...)
if not color then
return innercolor, outercolor
@@ -143,15 +152,6 @@ local function normalize(ca,cb)
end
end
--- todo: check for the same colorspace (actually a backend issue), now we can
--- have several similar resources
---
--- normalize(ca,cb) fails for spotcolors
-
-local function spotcolorconverter(parent, n, d, p)
- registerspotcolor(parent)
- return pdfcolor(colors.model,registercolor(nil,'spot',parent,n,d,p)), outercolor
-end
local commasplitter = tsplitat(",")
@@ -217,21 +217,34 @@ local function checkandconvert(ca,cb)
end
end
+-- We keep textexts in a shared list (as it's easier that way and we also had that in
+-- the beginning). Each graphic gets its own (1 based) subtable so that we can also
+-- handle multiple conversions in one go which is needed when we process mp files
+-- directly.
+
local stack = { } -- quick hack, we will pass topofstack around
local top = nil
local nofruns = 0 -- askedfig: "all", "first", number
-local function startjob(texmode)
- top = {
- textexts = { }, -- all boxes, optionally with a different color
- texslots = { }, -- references to textexts in order or usage
- texorder = { }, -- references to textexts by mp index
+local function preset(t,k)
+ -- references to textexts by mp index
+ local v = {
textrial = 0,
texfinal = 0,
- -- used by tx plugin
+ texslots = { },
+ texorder = { },
texhash = { },
+ }
+ t[k] = v
+ return v
+end
+
+local function startjob(plugmode)
+ top = {
+ textexts = { }, -- all boxes, optionally with a different color
texlast = 0,
- texmode = texmode, -- some day we can then skip all pre/postscripts
+ texdata = setmetatableindex({},preset), -- references to textexts in order or usage
+ plugmode = plugmode, -- some day we can then skip all pre/postscripts
}
insert(stack,top)
if trace_runs then
@@ -245,7 +258,7 @@ local function stopjob()
for n, tn in next, top.textexts do
free_list(tn)
if trace_textexts then
- report_textexts("freeing box %s",n)
+ report_textexts("freeing text %s",n)
end
end
if trace_runs then
@@ -257,27 +270,41 @@ local function stopjob()
end
end
-function metapost.settextexts () end -- obsolete
-function metapost.resettextexts() end -- obsolete
+function metapost.getjobdata()
+ return top
+end
-- end of new
-function metapost.settext(box,slot)
- top.textexts[slot] = copy_list(texgetbox(box))
- texsetbox(box,nil)
- -- this will become
- -- top.textexts[slot] = texgetbox(box)
- -- unsetbox(box)
+local function settext(box,slot)
+ if top then
+ top.textexts[slot] = copy_list(texgetbox(box))
+ texsetbox(box,nil)
+ -- this can become
+ -- top.textexts[slot] = textakebox(box)
+ else
+ -- weird error
+ end
end
-function metapost.gettext(box,slot)
- texsetbox(box,copy_list(top.textexts[slot]))
- if trace_textexts then
- report_textexts("putting text %s in box %s",slot,box)
+local function gettext(box,slot)
+ if top then
+ texsetbox(box,copy_list(top.textexts[slot]))
+ if trace_textexts then
+ report_textexts("putting text %s in box %s",slot,box)
+ end
+ -- top.textexts[slot] = nil -- no, pictures can be placed several times
+ else
+ -- weird error
end
- -- top.textexts[slot] = nil -- no, pictures can be placed several times
end
+metapost.settext = settext
+metapost.gettext = gettext
+
+implement { name = "mpsettext", actions = settext, arguments = { "integer", "integer" } } -- box slot
+implement { name = "mpgettext", actions = gettext, arguments = { "integer", "integer" } } -- box slot
+
-- rather generic pdf, so use this elsewhere too it no longer pays
-- off to distinguish between outline and fill (we now have both
-- too, e.g. in arrows)
@@ -467,7 +494,7 @@ end
-- currently a a one-liner produces less code
-- textext.*(".*") can have "'s but tricky parsing as we can have concatenated strings
--- so this is something for a boring plain or train trip and we might assume proper mp
+-- so this is something for a boring plane or train trip and we might assume proper mp
-- input anyway
local parser = Cs((
@@ -477,57 +504,95 @@ local parser = Cs((
+ 1
)^0)
+local checking_enabled = true directives.register("metapost.checktexts",function(v) checking_enabled = v end)
+
local function checktexts(str)
- found, forced = false, false
- return lpegmatch(parser,str), found, forced
+ if checking_enabled then
+ found, forced = false, false
+ return lpegmatch(parser,str), found, forced
+ else
+ return str
+ end
end
metapost.checktexts = checktexts
local factor = 65536*(7227/7200)
-function metapost.edefsxsy(wd,ht,dp) -- helper for figure
- local hd = ht + dp
- context_setvalue("sx",wd ~= 0 and factor/wd or 0)
- context_setvalue("sy",hd ~= 0 and factor/hd or 0)
-end
+-- function metapost.edefsxsy(wd,ht,dp) -- helper for figure
+-- local hd = ht + dp
+-- context_setvalue("sx",wd ~= 0 and factor/wd or 0)
+-- context_setvalue("sy",hd ~= 0 and factor/hd or 0)
+-- end
+
+implement {
+ name = "mpsetsxsy",
+ arguments = { "dimen", "dimen", "dimen" },
+ actions = function(wd,ht,dp)
+ local hd = ht + dp
+ setmacro("sx",wd ~= 0 and factor/wd or 0)
+ setmacro("sy",hd ~= 0 and factor/hd or 0)
+ end
+}
local function sxsy(wd,ht,dp) -- helper for text
local hd = ht + dp
return (wd ~= 0 and factor/wd) or 0, (hd ~= 0 and factor/hd) or 0
end
-local no_first_run = "mfun_first_run := false ;"
-local do_first_run = "mfun_first_run := true ;"
-local no_trial_run = "mfun_trial_run := false ;"
-local do_trial_run = "mfun_trial_run := true ;"
+-- for stock mp we need to declare the booleans first
+
+local no_first_run = "boolean mfun_first_run ; mfun_first_run := false ;"
+local do_first_run = "boolean mfun_first_run ; mfun_first_run := true ;"
+local no_trial_run = "boolean mfun_trial_run ; mfun_trial_run := false ;"
+local do_trial_run = "boolean mfun_trial_run ; mfun_trial_run := true ;"
local do_begin_fig = "; beginfig(1) ; "
local do_end_fig = "; endfig ;"
local do_safeguard = ";"
-local f_text_data = formatters["mfun_tt_w[%i] := %f ; mfun_tt_h[%i] := %f ; mfun_tt_d[%i] := %f ;"]
+-- local f_text_data = formatters["mfun_tt_w[%i] := %f ; mfun_tt_h[%i] := %f ; mfun_tt_d[%i] := %f ;"]
+--
+-- function metapost.textextsdata()
+-- local textexts = top.textexts
+-- local collected = { }
+-- local nofcollected = 0
+-- for k, data in sortedhash(top.texdata) do -- sort is nicer in trace
+-- local texorder = data.texorder
+-- for n=1,#texorder do
+-- local box = textexts[texorder[n]]
+-- if box then
+-- local wd, ht, dp = box.width/factor, box.height/factor, box.depth/factor
+-- if trace_textexts then
+-- report_textexts("passed data item %s:%s > (%p,%p,%p)",k,n,wd,ht,dp)
+-- end
+-- nofcollected = nofcollected + 1
+-- collected[nofcollected] = f_text_data(n,wd,n,ht,n,dp)
+-- else
+-- break
+-- end
+-- end
+-- end
+-- return collected
+-- end
function metapost.textextsdata()
- local texorder = top.texorder
- local textexts = top.textexts
- local collected = { }
- local nofcollected = 0
- for n=1,#texorder do
- local box = textexts[texorder[n]]
- if box then
- local wd, ht, dp = box.width/factor, box.height/factor, box.depth/factor
- if trace_textexts then
- report_textexts("passed data item %s: (%p,%p,%p)",n,wd,ht,dp)
+ local textexts = top.textexts
+ local collected = { }
+ for k, data in sortedhash(top.texdata) do -- sort is nicer in trace
+ local texorder = data.texorder
+ for n=1,#texorder do
+ local box = textexts[texorder[n]]
+ if box then
+ collected[n] = box
+ else
+ break
end
- nofcollected = nofcollected + 1
- collected[nofcollected] = f_text_data(n,wd,n,ht,n,dp)
- else
- break
end
end
- return collected
+ mp.tt_initialize(collected)
end
+
metapost.intermediate = metapost.intermediate or { }
metapost.intermediate.actions = metapost.intermediate.actions or { }
@@ -558,16 +623,16 @@ local function extrapass()
if trace_runs then
report_metapost("second run of job %s, asked figure %a",top.nofruns,top.askedfig)
end
+ local textexts = metapost.textextsdata()
processmetapost(top.mpx, {
top.wrappit and do_begin_fig or "",
no_trial_run,
- concat(metapost.textextsdata()," ;\n"),
+ textexts and concat(textexts," ;\n") or "",
top.initializations,
do_safeguard,
top.data,
top.wrappit and do_end_fig or "",
}, false, nil, false, true, top.askedfig)
- -- context.MPLIBresettexts() -- must happen afterwards
end
function metapost.graphic_base_pass(specification) -- name will change (see mlib-ctx.lua)
@@ -591,17 +656,18 @@ function metapost.graphic_base_pass(specification) -- name will change (see mlib
top.nofruns = nofruns
--
local done_1, done_2, done_3, forced_1, forced_2, forced_3
- data, done_1, forced_1 = checktexts(data)
- -- we had preamble = extensions + inclusions
- if extensions == "" then
- extensions, done_2, forced_2 = "", false, false
- else
- extensions, done_2, forced_2 = checktexts(extensions)
- end
- if inclusions == "" then
- inclusions, done_3, forced_3 = "", false, false
- else
- inclusions, done_3, forced_3 = checktexts(inclusions)
+ if checking_enabled then
+ data, done_1, forced_1 = checktexts(data)
+ if extensions == "" then
+ extensions, done_2, forced_2 = "", false, false
+ else
+ extensions, done_2, forced_2 = checktexts(extensions)
+ end
+ if inclusions == "" then
+ inclusions, done_3, forced_3 = "", false, false
+ else
+ inclusions, done_3, forced_3 = checktexts(inclusions)
+ end
end
top.intermediate = false
top.multipass = false -- no needed here
@@ -686,6 +752,12 @@ function makempy.registerfile(filename)
mpyfilename = filename
end
+implement {
+ name = "registermpyfile",
+ actions = makempy.registerfile,
+ arguments = "string"
+}
+
function makempy.processgraphics(graphics)
if #graphics == 0 then
return
@@ -726,13 +798,13 @@ end
-- -- the new plugin handler -- --
-local sequencers = utilities.sequencers
-local appendgroup = sequencers.appendgroup
-local appendaction = sequencers.appendaction
+local sequencers = utilities.sequencers
+local appendgroup = sequencers.appendgroup
+local appendaction = sequencers.appendaction
-local resetter = nil
-local analyzer = nil
-local processor = nil
+local resetter = nil
+local analyzer = nil
+local processor = nil
local resetteractions = sequencers.new { arguments = "t" }
local analyzeractions = sequencers.new { arguments = "object,prescript" }
@@ -779,7 +851,7 @@ end
-- end
function metapost.pluginactions(what,t,flushfigure) -- before/after object, depending on what
- if top.texmode then
+ if top.plugmode then -- hm, what about other features
for i=1,#what do
local wi = what[i]
if type(wi) == "function" then
@@ -796,7 +868,7 @@ function metapost.pluginactions(what,t,flushfigure) -- before/after object, depe
end
function metapost.resetplugins(t) -- intialize plugins, before figure
- if top.texmode then
+ if top.plugmode then
-- plugins can have been added
resetter = resetteractions.runner
analyzer = analyzeractions.runner
@@ -807,16 +879,18 @@ function metapost.resetplugins(t) -- intialize plugins, before figure
end
function metapost.analyzeplugins(object) -- each object (first pass)
- if top.texmode then
+ if top.plugmode then
local prescript = object.prescript -- specifications
if prescript and #prescript > 0 then
- return analyzer(object,splitprescript(prescript))
+ analyzer(object,splitprescript(prescript))
+ return top.multipass
end
end
+ return false
end
function metapost.processplugins(object) -- each object (second pass)
- if top.texmode then
+ if top.plugmode then
local prescript = object.prescript -- specifications
if prescript and #prescript > 0 then
local before = { }
@@ -860,6 +934,7 @@ end
local function tx_reset()
if top then
+ -- why ?
top.texhash = { }
top.texlast = 0
end
@@ -869,14 +944,23 @@ local fmt = formatters["%s %s %s % t"]
----- pat = tsplitat(":")
local pat = lpeg.tsplitter(":",tonumber) -- so that %F can do its work
+local f_gray_yes = formatters["s=%F,a=%F,t=%F"]
+local f_gray_nop = formatters["s=%F"]
+local f_rgb_yes = formatters["r=%F,g=%F,b=%F,a=%F,t=%F"]
+local f_rgb_nop = formatters["r=%F,g=%F,b=%F"]
+local f_cmyk_yes = formatters["c=%F,m=%F,y=%F,k=%F,a=%F,t=%F"]
+local f_cmyk_nop = formatters["c=%F,m=%F,y=%F,k=%F"]
+
local ctx_MPLIBsetNtext = context.MPLIBsetNtext
local ctx_MPLIBsetCtext = context.MPLIBsetCtext
+local ctx_MPLIBsettext = context.MPLIBsettext
local function tx_analyze(object,prescript) -- todo: hash content and reuse them
+ local data = top.texdata[metapost.properties.number]
local tx_stage = prescript.tx_stage
if tx_stage == "trial" then
- local tx_trial = top.textrial + 1
- top.textrial = tx_trial
+ local tx_trial = data.textrial + 1
+ data.textrial = tx_trial
local tx_number = tonumber(prescript.tx_number)
local s = object.postscript or ""
local c = object.color -- only simple ones, no transparency
@@ -886,80 +970,80 @@ local function tx_analyze(object,prescript) -- todo: hash content and reuse them
c = lpegmatch(pat,txc)
end
end
- local a = prescript.tr_alternative
- local t = prescript.tr_transparency
+ local a = tonumber(prescript.tr_alternative)
+ local t = tonumber(prescript.tr_transparency)
local h = fmt(tx_number,a or "-",t or "-",c or "-")
- local n = top.texhash[h] -- todo: hashed variant with s (nicer for similar labels)
+ local n = data.texhash[h] -- todo: hashed variant with s (nicer for similar labels)
if not n then
local tx_last = top.texlast + 1
top.texlast = tx_last
+ -- report_textexts("tex string: %s",s)
if not c then
ctx_MPLIBsetNtext(tx_last,s)
elseif #c == 1 then
if a and t then
- ctx_MPLIBsetCtext(tx_last,formatters["s=%F,a=%F,t=%F"](c[1],a,t),s)
+ ctx_MPLIBsetCtext(tx_last,f_gray_yes(c[1],a,t),s)
else
- ctx_MPLIBsetCtext(tx_last,formatters["s=%F"](c[1]),s)
+ ctx_MPLIBsetCtext(tx_last,f_gray_nop(c[1]),s)
end
elseif #c == 3 then
if a and t then
- ctx_MPLIBsetCtext(tx_last,formatters["r=%F,g=%F,b=%F,a=%F,t=%F"](c[1],c[2],c[3],a,t),s)
+ ctx_MPLIBsetCtext(tx_last,f_rgb_nop(c[1],c[2],c[3],a,t),s)
else
- ctx_MPLIBsetCtext(tx_last,formatters["r=%F,g=%F,b=%F"](c[1],c[2],c[3]),s)
+ ctx_MPLIBsetCtext(tx_last,f_rgb_nop(c[1],c[2],c[3]),s)
end
elseif #c == 4 then
if a and t then
- ctx_MPLIBsetCtext(tx_last,formatters["c=%F,m=%F,y=%F,k=%F,a=%F,t=%F"](c[1],c[2],c[3],c[4],a,t),s)
+ ctx_MPLIBsetCtext(tx_last,f_cmyk_yes(c[1],c[2],c[3],c[4],a,t),s)
else
- ctx_MPLIBsetCtext(tx_last,formatters["c=%F,m=%F,y=%F,k=%F"](c[1],c[2],c[3],c[4]),s)
+ ctx_MPLIBsetCtext(tx_last,f_cmyk_nop(c[1],c[2],c[3],c[4]),s)
end
else
ctx_MPLIBsetNtext(tx_last,s)
end
top.multipass = true
- metapost.multipass = true -- ugly
- top.texhash[h] = tx_last
- top.texslots[tx_trial] = tx_last
- top.texorder[tx_number] = tx_last
+ data.texhash [h] = tx_last
+ data.texslots[tx_trial] = tx_last
+ data.texorder[tx_number] = tx_last
if trace_textexts then
- report_textexts("stage %a, usage %a, number %a, new %a, hash %a",tx_stage,tx_trial,tx_number,tx_last,h)
+ report_textexts("stage %a, usage %a, number %a, new %a, hash %a, text %a",tx_stage,tx_trial,tx_number,tx_last,h,s)
end
else
- top.texslots[tx_trial] = n
+ data.texslots[tx_trial] = n
if trace_textexts then
- report_textexts("stage %a, usage %a, number %a, new %a, hash %a",tx_stage,tx_trial,tx_number,n,h)
+ report_textexts("stage %a, usage %a, number %a, old %a, hash %a, text %a",tx_stage,tx_trial,tx_number,n,h,s)
end
end
elseif tx_stage == "extra" then
- local tx_trial = top.textrial + 1
- top.textrial = tx_trial
+ local tx_trial = data.textrial + 1
+ data.textrial = tx_trial
local tx_number = tonumber(prescript.tx_number)
- if not top.texorder[tx_number] then
+ if not data.texorder[tx_number] then
local s = object.postscript or ""
local tx_last = top.texlast + 1
top.texlast = tx_last
- context.MPLIBsettext(tx_last,s)
+ ctx_MPLIBsettext(tx_last,s)
top.multipass = true
- metapost.multipass = true -- ugly
- top.texslots[tx_trial] = tx_last
- top.texorder[tx_number] = tx_last
+ data.texslots[tx_trial] = tx_last
+ data.texorder[tx_number] = tx_last
if trace_textexts then
- report_textexts("stage %a, usage %a, number %a, extra %a",tx_stage,tx_trial,tx_number,tx_last)
+ report_textexts("stage %a, usage %a, number %a, extra %a, text %a",tx_stage,tx_trial,tx_number,tx_last,s)
end
end
end
end
local function tx_process(object,prescript,before,after)
- local tx_number = prescript.tx_number
+ local data = top.texdata[metapost.properties.number]
+ local tx_number = tonumber(prescript.tx_number)
if tx_number then
- tx_number = tonumber(tx_number)
local tx_stage = prescript.tx_stage
if tx_stage == "final" then
- top.texfinal = top.texfinal + 1
- local n = top.texslots[top.texfinal]
+ local tx_final = data.texfinal + 1
+ data.texfinal = tx_final
+ local n = data.texslots[tx_final]
if trace_textexts then
- report_textexts("stage %a, usage %a, number %a, use %a",tx_stage,top.texfinal,tx_number,n)
+ report_textexts("stage %a, usage %a, number %a, use %a",tx_stage,tx_final,tx_number,n)
end
local sx, rx, ry, sy, tx, ty = cm(object) -- needs to be frozen outside the function
local box = top.textexts[n]
@@ -983,8 +1067,9 @@ local function tx_process(object,prescript,before,after)
if not trace_textexts then
object.path = false -- else: keep it
end
- object.color = false
+ object.color = false
object.grouped = true
+ object.istext = true
end
end
end
@@ -1007,7 +1092,6 @@ local function gt_analyze(object,prescript)
graphics[gt_index] = formatters["\\MPLIBgraphictext{%s}"](object.postscript or "")
top.intermediate = true
top.multipass = true
- metapost.multipass = true -- ugly
end
end
@@ -1023,9 +1107,9 @@ local function sh_process(object,prescript,before,after)
local sh_type = prescript.sh_type
if sh_type then
nofshades = nofshades + 1
- local domain = lpegmatch(domainsplitter,prescript.sh_domain)
- local centera = lpegmatch(centersplitter,prescript.sh_center_a)
- local centerb = lpegmatch(centersplitter,prescript.sh_center_b)
+ local domain = lpegmatch(domainsplitter,prescript.sh_domain or "0 1")
+ local centera = lpegmatch(centersplitter,prescript.sh_center_a or "0 0")
+ local centerb = lpegmatch(centersplitter,prescript.sh_center_b or "0 0")
--
local sh_color_a = prescript.sh_color_a or "1"
local sh_color_b = prescript.sh_color_b or "1"
@@ -1074,8 +1158,9 @@ local function sh_process(object,prescript,before,after)
local coordinates = { centera[1], centera[2], centerb[1], centerb[2] }
lpdf.linearshade(name,domain,ca,cb,1,colorspace,coordinates,separation) -- backend specific (will be renamed)
elseif sh_type == "circular" then
- local radiusa = tonumber(prescript.sh_radius_a)
- local radiusb = tonumber(prescript.sh_radius_b)
+ local factor = tonumber(prescript.sh_factor) or 1
+ local radiusa = factor * tonumber(prescript.sh_radius_a)
+ local radiusb = factor * tonumber(prescript.sh_radius_b)
local coordinates = { centera[1], centera[2], radiusa, centerb[1], centerb[2], radiusb }
lpdf.circularshade(name,domain,ca,cb,1,colorspace,coordinates,separation) -- backend specific (will be renamed)
else
@@ -1120,8 +1205,9 @@ local function ps_process(object,prescript,before,after)
local first, third = op[1], op[3]
local x, y = first.x_coord, first.y_coord
local w, h = third.x_coord - x, third.y_coord - y
- x = x - metapost.llx
- y = metapost.ury - y
+ local properties = metapost.properties
+ x = x - properties.llx
+ y = properties.ury - y
before[#before+1] = function()
context.MPLIBpositionwhd(ps_label,x,y,w,h)
end
@@ -1156,6 +1242,12 @@ local value = Cs ( (
local t_list = attributes.list[attributes.private('transparency')]
local c_list = attributes.list[attributes.private('color')]
+local remappers = {
+ [1] = formatters["s=%s"],
+ [3] = formatters["r=%s,g=%s,b=%s"],
+ [4] = formatters["c=%s,m=%s,y=%s,k=%s"],
+}
+
local function tr_process(object,prescript,before,after)
-- before can be shortcut to t
local tr_alternative = prescript.tr_alternative
@@ -1171,56 +1263,83 @@ local function tr_process(object,prescript,before,after)
local sp_type = prescript.sp_type
if not sp_type then
c_b, c_a = colorconverter(cs)
- elseif sp_type == "spot" or sp_type == "multitone" then
- local sp_name = prescript.sp_name or "black"
- local sp_fractions = prescript.sp_fractions or 1
- local sp_components = prescript.sp_components or ""
- local sp_value = prescript.sp_value or "1"
- local cf = cs[1]
- if cf ~= 1 then
- -- beware, we do scale the spotcolors but not the alternative representation
- sp_value = lpegmatch(value,sp_value,1,cf) or sp_value
- end
- c_b, c_a = spotcolorconverter(sp_name,sp_fractions,sp_components,sp_value)
- elseif sp_type == "named" then
- -- we might move this to another namespace .. also, named can be a spotcolor
- -- so we need to check for that too ... also we need to resolve indirect
- -- colors so we might need the second pass for this (draw dots with \MPcolor)
+ else
local sp_name = prescript.sp_name or "black"
- if not tr_alternative then
- -- todo: sp_name is not yet registered at this time
- local t = t_list[sp_name] -- string or attribute
- local v = t and attributes.transparencies.value(t)
- if v then
- before[#before+1] = formatters["/Tr%s gs"](registertransparency(nil,v[1],v[2],true))
- after[#after+1] = "/Tr0 gs" -- outertransparency
+ if sp_type == "spot" then
+ local sp_value = prescript.sp_value or "s:1"
+ local sp_temp = formatters["mp:%s"](sp_value)
+ local s = split(sp_value,":")
+ local r = remappers[#s]
+ defineprocesscolor(sp_temp,r and r(unpack(s)) or "s=0",true,true)
+ definespotcolor(sp_name,sp_temp,"p=1",true)
+ sp_type = "named"
+ elseif sp_type == "multitone" then
+ local sp_value = prescript.sp_value or "s:1"
+ local sp_spec = { }
+ local sp_list = split(sp_value," ")
+ for i=1,#sp_list do
+ local v = sp_list[i]
+ local t = formatters["mp:%s"](v)
+ local s = split(v,":")
+ local r = remappers[#s]
+ defineprocesscolor(t,r and r(unpack(s)) or "s=0",true,true)
+ local tt = formatters["ms:%s"](v)
+ definespotcolor(tt,t,"p=1",true)
+ sp_spec[#sp_spec+1] = formatters["%s=1"](t)
end
+ sp_spec = concat(sp_spec,",")
+ definemultitonecolor(sp_name,sp_spec,"","",true)
+ sp_type = "named"
end
- local c = c_list[sp_name] -- string or attribute
- local v = c and attributes.colors.value(c)
- if v then
- -- all=1 gray=2 rgb=3 cmyk=4
- local colorspace = v[1]
- local f = cs[1]
- if colorspace == 2 then
- local s = f*v[2]
- c_b, c_a = checked_color_pair(f_gray,s,s)
- elseif colorspace == 3 then
- local r, g, b = f*v[3], f*v[4], f*v[5]
- c_b, c_a = checked_color_pair(f_rgb,r,g,b,r,g,b)
- elseif colorspace == 4 or colorspace == 1 then
- local c, m, y, k = f*v[6], f*v[7], f*v[8], f*v[9]
- c_b, c_a = checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
- else
- local s = f*v[2]
- c_b, c_a = checked_color_pair(f_gray,s,s)
+ if sp_type == "named" then
+ -- we might move this to another namespace .. also, named can be a spotcolor
+ -- so we need to check for that too ... also we need to resolve indirect
+ -- colors so we might need the second pass for this (draw dots with \MPcolor)
+ if not tr_alternative then
+ -- todo: sp_name is not yet registered at this time
+ local t = t_list[sp_name] -- string or attribute
+ local v = t and transparencyvalue(t)
+ if v then
+ before[#before+1] = formatters["/Tr%s gs"](registertransparency(nil,v[1],v[2],true))
+ after[#after+1] = "/Tr0 gs" -- outertransparency
+ end
+ end
+ local c = c_list[sp_name] -- string or attribute
+ local v = c and colorvalue(c)
+ if v then
+ -- all=1 gray=2 rgb=3 cmyk=4
+ local colorspace = v[1]
+ local f = cs[1]
+ if colorspace == 2 then
+ local s = f*v[2]
+ c_b, c_a = checked_color_pair(f_gray,s,s)
+ elseif colorspace == 3 then
+ local r, g, b = f*v[3], f*v[4], f*v[5]
+ c_b, c_a = checked_color_pair(f_rgb,r,g,b,r,g,b)
+ elseif colorspace == 4 or colorspace == 1 then
+ local c, m, y, k = f*v[6], f*v[7], f*v[8], f*v[9]
+ c_b, c_a = checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
+ elseif colorspace == 5 then
+ -- not all viewers show the fractions ok
+ local name = v[10]
+ local value = split(v[13],",")
+ if f ~= 1 then
+ for i=1,#value do
+ value[i] = f * (tonumber(value[i]) or 1)
+ end
+ end
+ value = concat(value," ")
+ c_b, c_a = checked_color_pair(f_spot,name,name,value,value)
+ else
+ local s = f*v[2]
+ c_b, c_a = checked_color_pair(f_gray,s,s)
+ end
end
end
- --
end
if c_a and c_b then
before[#before+1] = c_b
- after[#after+1] = c_a
+ after [#after +1] = c_a
end
end
end
diff --git a/Master/texmf-dist/tex/context/base/mlib-pps.mkiv b/Master/texmf-dist/tex/context/base/mlib-pps.mkiv
index 207d9730c8a..07ac84b8d32 100644
--- a/Master/texmf-dist/tex/context/base/mlib-pps.mkiv
+++ b/Master/texmf-dist/tex/context/base/mlib-pps.mkiv
@@ -33,43 +33,23 @@
\newbox \MPtextbox
\newtoks\everyMPLIBsettext % not used
-% \def\MPLIBsettext#1% #2%
-% {\dowithnextbox{\ctxlua{metapost.settext(\number\nextbox,#1)}}\hbox}
-%
-% \def\MPLIBresettexts
-% {\ctxlua{metapost.resettextexts()}}
-%
-% \newconditional\MPLIBtextgetdone
-%
-% \def\MPLIBsettext#1% #2%
-% {\ifconditional\MPLIBtextgetdone
-% \else
-% \cldcontext{metapost.tex.get()}% MPenvironments are depricated
-% \settrue\MPLIBtextgetdone % no \global needed
-% \fi
-% \dowithnextbox{\ctxlua{metapost.settext(\number\nextbox,#1)}}\hbox}
-%
-% \def\MPLIBresettexts
-% {\ctxlua{metapost.resettextexts()}%
-% \setfalse\MPLIBtextgetdone}
-
\def\doMPLIBflushenvironment
{%\writestatus\m!metapost{flushing environment}%
- \cldcontext{metapost.tex.get()}%
+ \clf_mptexget
\let\MPLIBflushenvironment\relax}% MPenvironments are depricated}
\let\MPLIBflushenvironment\doMPLIBflushenvironment
\unexpanded\def\MPLIBsetNtext#1% #2% box text
{\MPLIBflushenvironment
- \dowithnextbox{\ctxlua{metapost.settext(\number\nextbox,#1)}}\hbox\bgroup
+ \dowithnextbox{\clf_mpsettext\nextbox #1}\hbox\bgroup
\meta_set_current_color
\let\MPLIBflushenvironment\doMPLIBflushenvironment
\let\next} % gobble open brace
\unexpanded\def\MPLIBsetCtext#1#2% #3% box colorspec text
{\MPLIBflushenvironment
- \dowithnextbox{\ctxlua{metapost.settext(\number\nextbox,#1)}}\hbox\bgroup
+ \dowithnextbox{\clf_mpsettext\nextbox #1}\hbox\bgroup
\directcolored[#2]%
\meta_set_current_color % so, textcolor wins !
\let\MPLIBflushenvironment\doMPLIBflushenvironment
@@ -77,22 +57,19 @@
\let\MPLIBsettext\MPLIBsetNtext
-\unexpanded\def\MPLIBresettexts
- {\ctxlua{metapost.resettextexts()}}
-
\unexpanded\def\MPLIBgettextscaled#1#2#3% why a copy .. can be used more often
- {\ctxlua{metapost.gettext(\number\MPtextbox,#1)}%
+ {\clf_mpgettext\MPtextbox #1%
\vbox to \zeropoint{\vss\hbox to \zeropoint{\scale[\c!sx=#2,\c!sy=#3]{\raise\dp\MPtextbox\box\MPtextbox}\forcecolorhack\hss}}}
\unexpanded\def\MPLIBfigure#1#2%
{\setbox\scratchbox\hbox{\externalfigure[#1][\c!mask=#2]}%
- \ctxlua{metapost.edefsxsy(\number\wd\scratchbox,\number\ht\scratchbox,0)}%
+ \clf_mpsetsxsy\wd\scratchbox\ht\scratchbox\zeropoint
\vbox to \zeropoint{\vss\hbox to \zeropoint{\scale[\c!sx=\sx,\c!sy=\sy]{\box\scratchbox}\hss}}}
% horrible (we could inline scale and matrix code):
\unexpanded\def\MPLIBgettextscaledcm#1#2#3#4#5#6#7#8#9% 2-7: sx,rx,ry,sy,tx,ty
- {\ctxlua{metapost.gettext(\number\MPtextbox,#1)}%
+ {\clf_mpgettext\MPtextbox #1%
\setbox\MPbox\hbox\bgroup
\dotransformnextbox{#2}{#3}{#4}{#5}{#6}{#7}% does push pop ... will be changed to proper lua call (avoid small numbers)
\vbox to \zeropoint\bgroup
diff --git a/Master/texmf-dist/tex/context/base/mlib-run.lua b/Master/texmf-dist/tex/context/base/mlib-run.lua
index 2a34f44d5c8..121c32ae95a 100644
--- a/Master/texmf-dist/tex/context/base/mlib-run.lua
+++ b/Master/texmf-dist/tex/context/base/mlib-run.lua
@@ -44,12 +44,12 @@ local texerrormessage = logs.texerrormessage
local starttiming = statistics.starttiming
local stoptiming = statistics.stoptiming
+local formatters = string.formatters
+
local mplib = mplib
metapost = metapost or { }
local metapost = metapost
-local mplibone = tonumber(mplib.version()) <= 1.50
-
metapost.showlog = false
metapost.lastlog = ""
metapost.collapse = true -- currently mplib cannot deal with begingroup/endgroup mismatch in stepwise processing
@@ -84,77 +84,74 @@ local mpbasepath = lpeg.instringchecker(P("/metapost/") * (P("context") + P("bas
-- mplib has no real io interface so we have a different mechanism than
-- tex (as soon as we have more control, we will use the normal code)
-
-local finders = { }
-mplib.finders = finders
-
+--
-- for some reason mp sometimes calls this function twice which is inefficient
-- but we cannot catch this
-local function preprocessed(name)
- if not mpbasepath(name) then
- -- we could use the via file but we don't have a complete io interface yet
- local data, found, forced = metapost.checktexts(io.loaddata(name) or "")
- if found then
- local temp = luatex.registertempfile(name,true)
- io.savedata(temp,data)
- return temp
+do
+
+ local finders = { }
+ mplib.finders = finders -- also used in meta-lua.lua
+
+ local new_instance = mplib.new
+ local resolved_file = resolvers.findfile
+
+ local function preprocessed(name)
+ if not mpbasepath(name) then
+ -- we could use the via file but we don't have a complete io interface yet
+ local data, found, forced = metapost.checktexts(io.loaddata(name) or "")
+ if found then
+ local temp = luatex.registertempfile(name,true)
+ io.savedata(temp,data)
+ return temp
+ end
end
+ return name
end
- return name
-end
-mplib.preprocessed = preprocessed -- helper
+ mplib.preprocessed = preprocessed -- helper
-finders.file = function(specification,name,mode,ftype)
- return preprocessed(resolvers.findfile(name,ftype))
-end
+ local function validftype(ftype)
+ if ftype == "" then
+ -- whatever
+ elseif ftype == 0 then
+ -- mplib bug
+ else
+ return ftype
+ end
+ end
-local function i_finder(name,mode,ftype) -- fake message for mpost.map and metafun.mpvi
- local specification = url.hashed(name)
- local finder = finders[specification.scheme] or finders.file
- return finder(specification,name,mode,ftype)
-end
+ finders.file = function(specification,name,mode,ftype)
+ return preprocessed(resolvers.findfile(name,validftype(ftype)))
+ end
-local function o_finder(name,mode,ftype)
- -- report_metapost("output file %a, mode %a, ftype %a",name,mode,ftype)
- return name
-end
+ local function i_finder(name,mode,ftype) -- fake message for mpost.map and metafun.mpvi
+ local specification = url.hashed(name)
+ local finder = finders[specification.scheme] or finders.file
+ return finder(specification,name,mode,validftype(ftype))
+ end
-local function finder(name,mode,ftype)
- if mode == "w" then
- return o_finder(name,mode,ftype)
- else
- return i_finder(name,mode,ftype)
+ local function o_finder(name,mode,ftype)
+ return name
end
-end
-local i_limited = false
-local o_limited = false
+ o_finder = sandbox.register(o_finder,sandbox.filehandlerone,"mplib output finder")
-directives.register("system.inputmode", function(v)
- if not i_limited then
- local i_limiter = io.i_limiter(v)
- if i_limiter then
- i_finder = i_limiter.protect(i_finder)
- i_limited = true
- end
+ local function finder(name,mode,ftype)
+ return (mode == "w" and o_finder or i_finder)(name,mode,validftype(ftype))
end
-end)
-
-directives.register("system.outputmode", function(v)
- if not o_limited then
- local o_limiter = io.o_limiter(v)
- if o_limiter then
- o_finder = o_limiter.protect(o_finder)
- o_limited = true
- end
+
+ function mplib.new(specification)
+ specification.find_file = finder -- so we block an overload
+ return new_instance(specification)
end
-end)
--- -- --
+ mplib.finder = finder
+
+end
-metapost.finder = finder
+local new_instance = mplib.new
+local find_file = mplib.finder
function metapost.reporterror(result)
if not result then
@@ -182,184 +179,93 @@ function metapost.reporterror(result)
return true
end
-if mplibone then
-
- report_metapost("fatal error: mplib is too old")
-
- os.exit()
-
- -- local preamble = [[
- -- boolean mplib ; mplib := true ;
- -- string mp_parent_version ; mp_parent_version := "%s" ;
- -- input "%s" ; dump ;
- -- ]]
- --
- -- metapost.parameters = {
- -- hash_size = 100000,
- -- main_memory = 4000000,
- -- max_in_open = 50,
- -- param_size = 100000,
- -- }
- --
- -- function metapost.make(name, target, version)
- -- starttiming(mplib)
- -- target = file.replacesuffix(target or name, "mem") -- redundant
- -- local mpx = mplib.new ( table.merged (
- -- metapost.parameters,
- -- {
- -- ini_version = true,
- -- find_file = finder,
- -- job_name = file.removesuffix(target),
- -- }
- -- ) )
- -- if mpx then
- -- starttiming(metapost.exectime)
- -- local result = mpx:execute(format(preamble,version or "unknown",name))
- -- stoptiming(metapost.exectime)
- -- mpx:finish()
- -- end
- -- stoptiming(mplib)
- -- end
- --
- -- function metapost.load(name)
- -- starttiming(mplib)
- -- local mpx = mplib.new ( table.merged (
- -- metapost.parameters,
- -- {
- -- ini_version = false,
- -- mem_name = file.replacesuffix(name,"mem"),
- -- find_file = finder,
- -- -- job_name = "mplib",
- -- }
- -- ) )
- -- local result
- -- if not mpx then
- -- result = { status = 99, error = "out of memory"}
- -- end
- -- stoptiming(mplib)
- -- return mpx, result
- -- end
- --
- -- function metapost.checkformat(mpsinput)
- -- local mpsversion = environment.version or "unset version"
- -- local mpsinput = file.addsuffix(mpsinput or "metafun", "mp")
- -- local mpsformat = file.removesuffix(file.basename(texconfig.formatname or (tex and tex.formatname) or mpsinput))
- -- local mpsbase = file.removesuffix(file.basename(mpsinput))
- -- if mpsbase ~= mpsformat then
- -- mpsformat = mpsformat .. "-" .. mpsbase
- -- end
- -- mpsformat = file.addsuffix(mpsformat, "mem")
- -- local mpsformatfullname = caches.getfirstreadablefile(mpsformat,"formats","metapost") or ""
- -- if mpsformatfullname ~= "" then
- -- report_metapost("loading %a from %a", mpsinput, mpsformatfullname)
- -- local mpx, result = metapost.load(mpsformatfullname)
- -- if mpx then
- -- local result = mpx:execute("show mp_parent_version ;")
- -- if not result.log then
- -- metapost.reporterror(result)
- -- else
- -- local version = match(result.log,">> *(.-)[\n\r]") or "unknown"
- -- version = gsub(version,"[\'\"]","")
- -- if version ~= mpsversion then
- -- report_metapost("version mismatch: %s <> %s", version or "unknown", mpsversion)
- -- else
- -- return mpx
- -- end
- -- end
- -- else
- -- report_metapost("error in loading %a from %a", mpsinput, mpsformatfullname)
- -- metapost.reporterror(result)
- -- end
- -- end
- -- local mpsformatfullname = caches.setfirstwritablefile(mpsformat,"formats")
- -- report_metapost("making %a into %a", mpsinput, mpsformatfullname)
- -- metapost.make(mpsinput,mpsformatfullname,mpsversion) -- somehow return ... fails here
- -- if lfs.isfile(mpsformatfullname) then
- -- report_metapost("loading %a from %a", mpsinput, mpsformatfullname)
- -- return metapost.load(mpsformatfullname)
- -- else
- -- report_metapost("problems with %a from %a", mpsinput, mpsformatfullname)
- -- end
- -- end
-
-else
-
- -- let end = relax ;
-
- local preamble = [[
- boolean mplib ; mplib := true ;
- let dump = endinput ;
- input "%s" ;
- ]]
-
- local methods = {
- double = "double",
- scaled = "scaled",
- binary = "binary",
- decimal = "decimal",
- default = "scaled",
- }
+local f_preamble = formatters [ [[
+ boolean mplib ; mplib := true ;
+ let dump = endinput ;
+ input "%s" ;
+]] ]
+
+local methods = {
+ double = "double",
+ scaled = "scaled",
+ binary = "binary",
+ decimal = "decimal",
+ default = "scaled",
+}
- function metapost.runscript(code)
- return code
- end
+function metapost.runscript(code)
+ return code
+end
- function metapost.scripterror(str)
- report_metapost("script error: %s",str)
+function metapost.scripterror(str)
+ report_metapost("script error: %s",str)
+end
+
+-- todo: random_seed
+
+local f_textext = formatters[ [[rawtextext("%s")]] ]
+
+function metapost.maketext(s,mode)
+ if mode and mode == 1 then
+ -- report_metapost("ignoring verbatimtex: %s",s)
+ else
+ -- report_metapost("handling btex ... etex: %s",s)
+ s = gsub(s,'"','"&ditto&"')
+ return f_textext(s)
end
+end
- function metapost.load(name,method)
- starttiming(mplib)
- method = method and methods[method] or "scaled"
- local mpx = mplib.new {
- ini_version = true,
- find_file = finder,
- math_mode = method,
- run_script = metapost.runscript,
- script_error = metapost.scripterror,
- }
- report_metapost("initializing number mode %a",method)
- local result
- if not mpx then
- result = { status = 99, error = "out of memory"}
- else
- result = mpx:execute(format(preamble, file.addsuffix(name,"mp"))) -- addsuffix is redundant
- end
- stoptiming(mplib)
- metapost.reporterror(result)
- return mpx, result
+function metapost.load(name,method)
+ starttiming(mplib)
+ method = method and methods[method] or "scaled"
+ local mpx = new_instance {
+ ini_version = true,
+ math_mode = method,
+ run_script = metapost.runscript,
+ script_error = metapost.scripterror,
+ make_text = metapost.maketext,
+ extensions = 1,
+ }
+ report_metapost("initializing number mode %a",method)
+ local result
+ if not mpx then
+ result = { status = 99, error = "out of memory"}
+ else
+ result = mpx:execute(f_preamble(file.addsuffix(name,"mp"))) -- addsuffix is redundant
end
+ stoptiming(mplib)
+ metapost.reporterror(result)
+ return mpx, result
+end
- function metapost.checkformat(mpsinput,method)
- local mpsversion = environment.version or "unset version"
- local mpsinput = mpsinput or "metafun"
- local foundfile = ""
- if file.suffix(mpsinput) ~= "" then
- foundfile = finder(mpsinput) or ""
- end
- if foundfile == "" then
- foundfile = finder(file.replacesuffix(mpsinput,"mpvi")) or ""
- end
- if foundfile == "" then
- foundfile = finder(file.replacesuffix(mpsinput,"mpiv")) or ""
- end
- if foundfile == "" then
- foundfile = finder(file.replacesuffix(mpsinput,"mp")) or ""
- end
- if foundfile == "" then
- report_metapost("loading %a fails, format not found",mpsinput)
+function metapost.checkformat(mpsinput,method)
+ local mpsversion = environment.version or "unset version"
+ local mpsinput = mpsinput or "metafun"
+ local foundfile = ""
+ if file.suffix(mpsinput) ~= "" then
+ foundfile = find_file(mpsinput) or ""
+ end
+ if foundfile == "" then
+ foundfile = find_file(file.replacesuffix(mpsinput,"mpvi")) or ""
+ end
+ if foundfile == "" then
+ foundfile = find_file(file.replacesuffix(mpsinput,"mpiv")) or ""
+ end
+ if foundfile == "" then
+ foundfile = find_file(file.replacesuffix(mpsinput,"mp")) or ""
+ end
+ if foundfile == "" then
+ report_metapost("loading %a fails, format not found",mpsinput)
+ else
+ report_metapost("loading %a as %a using method %a",mpsinput,foundfile,method or "default")
+ local mpx, result = metapost.load(foundfile,method)
+ if mpx then
+ return mpx
else
- report_metapost("loading %a as %a using method %a",mpsinput,foundfile,method or "default")
- local mpx, result = metapost.load(foundfile,method)
- if mpx then
- return mpx
- else
- report_metapost("error in loading %a",mpsinput)
- metapost.reporterror(result)
- end
+ report_metapost("error in loading %a",mpsinput)
+ metapost.reporterror(result)
end
end
-
end
function metapost.unload(mpx)
@@ -409,7 +315,8 @@ function metapost.reset(mpx)
end
end
-local mp_inp, mp_log, mp_tag = { }, { }, 0
+local mp_tra = { }
+local mp_tag = 0
-- key/values
@@ -423,18 +330,24 @@ function metapost.process(mpx, data, trialrun, flusher, multipass, isextrapass,
mpx = metapost.format(mpx) -- goody
end
if mpx and data then
+ local tra = nil
starttiming(metapost)
metapost.initializescriptrunner(mpx,trialrun)
if trace_graphics then
- if not mp_inp[mpx] then
+ tra = mp_tra[mpx]
+ if not tra then
mp_tag = mp_tag + 1
local jobname = tex.jobname
- mp_inp[mpx] = io.open(format("%s-mplib-run-%03i.mp", jobname,mp_tag),"w")
- mp_log[mpx] = io.open(format("%s-mplib-run-%03i.log",jobname,mp_tag),"w")
+ tra = {
+ inp = io.open(formatters["%s-mplib-run-%03i.mp"] (jobname,mp_tag),"w"),
+ log = io.open(formatters["%s-mplib-run-%03i.log"](jobname,mp_tag),"w"),
+ }
+ mp_tra[mpx] = tra
end
- local banner = format("%% begin graphic: n=%s, trialrun=%s, multipass=%s, isextrapass=%s\n\n", metapost.n, tostring(trialrun), tostring(multipass), tostring(isextrapass))
- mp_inp[mpx]:write(banner)
- mp_log[mpx]:write(banner)
+ local banner = formatters["%% begin graphic: n=%s, trialrun=%s, multipass=%s, isextrapass=%s\n\n"](
+ metapost.n, tostring(trialrun), tostring(multipass), tostring(isextrapass))
+ tra.inp:write(banner)
+ tra.log:write(banner)
end
if type(data) == "table" then
-- this hack is needed because the library currently barks on \n\n
@@ -471,17 +384,17 @@ function metapost.process(mpx, data, trialrun, flusher, multipass, isextrapass,
-- d = string.gsub(d,"\r","")
if d then
if trace_graphics then
- mp_inp[mpx]:write(format("\n%% begin snippet %s\n",i))
- mp_inp[mpx]:write(d)
- mp_inp[mpx]:write(format("\n%% end snippet %s\n",i))
+ tra.inp:write(formatters["\n%% begin snippet %s\n"](i))
+ tra.inp:write(d)
+ tra.inp:write(formatters["\n%% end snippet %s\n"](i))
end
starttiming(metapost.exectime)
- result = mpx:execute(d)
+ result = mpx:execute(d) -- some day we wil use a coroutine with textexts
stoptiming(metapost.exectime)
if trace_graphics and result then
local str = result.log or result.error
if str and str ~= "" then
- mp_log[mpx]:write(str)
+ tra.log:write(str)
end
end
if not metapost.reporterror(result) then
@@ -505,7 +418,7 @@ function metapost.process(mpx, data, trialrun, flusher, multipass, isextrapass,
data = "tracingall;" .. data
end
if trace_graphics then
- mp_inp[mpx]:write(data)
+ tra.inp:write(data)
end
starttiming(metapost.exectime)
result = mpx:execute(data)
@@ -513,7 +426,7 @@ function metapost.process(mpx, data, trialrun, flusher, multipass, isextrapass,
if trace_graphics and result then
local str = result.log or result.error
if str and str ~= "" then
- mp_log[mpx]:write(str)
+ tra.log:write(str)
end
end
-- todo: error message
@@ -533,8 +446,8 @@ function metapost.process(mpx, data, trialrun, flusher, multipass, isextrapass,
end
if trace_graphics then
local banner = "\n% end graphic\n\n"
- mp_inp[mpx]:write(banner)
- mp_log[mpx]:write(banner)
+ tra.inp:write(banner)
+ tra.log:write(banner)
end
stoptiming(metapost)
end
@@ -596,7 +509,7 @@ function metapost.directrun(formatname,filename,outputformat,astable,mpdata)
else
output = figures[v]:svg() -- (3) for prologues
end
- local outname = format("%s-%s.%s",basename,v,outputformat)
+ local outname = formatters["%s-%s.%s"](basename,v,outputformat)
report_metapost("saving %s bytes in %a",#output,outname)
io.savedata(outname,output)
end
@@ -629,7 +542,7 @@ function metapost.quickanddirty(mpxformat,data)
stopfigure = function()
end
}
- local data = format("; beginfig(1) ;\n %s\n ; endfig ;",data)
+ local data = formatters["; beginfig(1) ;\n %s\n ; endfig ;"](data)
metapost.process(mpxformat, { data }, false, flusher, false, false, "all")
if code then
return {
diff --git a/Master/texmf-dist/tex/context/base/mtx-context-arrange.tex b/Master/texmf-dist/tex/context/base/mtx-context-arrange.tex
index 49920293fe6..fb53406d800 100644
--- a/Master/texmf-dist/tex/context/base/mtx-context-arrange.tex
+++ b/Master/texmf-dist/tex/context/base/mtx-context-arrange.tex
@@ -27,10 +27,11 @@
% --printformat : 2UP, etc
% --paperformat=spec : paper*print or paperxprint
%
-% example: context --extra=arrange --printformat=2UP --paperformat=A4,A3,landscape myfile
+% example: context --extra=arrange --printformat=2UP --paperformat=A4*A3,landscape myfile
%
% end help
+
\input mtx-context-common.tex
\doifdocumentargument {paperoffset} {
@@ -46,6 +47,7 @@
\setdocumentargument{sided}{singlesided}
}
+
\setuppapersize
[\getdocumentargument{paperformat_paper}]
[\getdocumentargument{paperformat_print}]
@@ -95,16 +97,17 @@
\starttext
\startluacode
- local format = string.format
- local fprint = function(...) tex.sprint(tex.ctxcatcodes,format(...)) end
-
- if #document.files > 0 then
- if document.arguments.sort then
- table.sort(document.files)
+ local arguments = document.arguments
+ local files = document.files
+ local noffiles = #files
+ if noffiles > 0 then
+ if arguments.sort then
+ table.sort(files)
end
- local emptypages = document.arguments.addempty or ""
- local textwidth = document.arguments.textwidth or "0cm"
- for _, filename in ipairs(document.files) do
+ local emptypages = arguments.addempty or ""
+ local textwidth = arguments.textwidth or "0cm"
+ for i=1,noffiles do
+ local filename = files[i]
if not string.find(filename,"^mtx%-context%-") then
context.insertpages (
{ filename },
@@ -114,7 +117,7 @@
end
end
else
- fprint("no files given")
+ context("no files given")
end
\stopluacode
diff --git a/Master/texmf-dist/tex/context/base/mtx-context-listing.tex b/Master/texmf-dist/tex/context/base/mtx-context-listing.tex
index 2a333c78923..a38fc60a9df 100644
--- a/Master/texmf-dist/tex/context/base/mtx-context-listing.tex
+++ b/Master/texmf-dist/tex/context/base/mtx-context-listing.tex
@@ -24,13 +24,20 @@
% --scite : pretty print comform suffix using scite lexer
% --bodyfont=list : additional bodyfont settings
% --paperformat=spec : paper*print or paperxprint
+% --compact : small margins, small font
%
% end help
\input mtx-context-common.tex
+\doifdocumentargument {compact} {
+ \setdocumentargument{topspace} {5mm}
+ \setdocumentargument{backspace}{5mm}
+ \setdocumentargument{bodyfont} {8pt}
+}
+
\setupbodyfont
- [11pt,tt,\getdocumentargument{bodyfont}]
+ [dejavu,11pt,tt,\getdocumentargument{bodyfont}] % dejavu is more complete
\setuptyping
[lines=yes]
diff --git a/Master/texmf-dist/tex/context/base/mtx-context-precache.tex b/Master/texmf-dist/tex/context/base/mtx-context-precache.tex
new file mode 100644
index 00000000000..9cbb46cf2c5
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mtx-context-precache.tex
@@ -0,0 +1,161 @@
+%D \module
+%D [ file=mtx-context-precache,
+%D version=2014.12.24,
+%D title=\CONTEXT\ Extra Trickry,
+%D subtitle=Precaching Fonts,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% begin help
+%
+% usage: context --extra=precache [no options yet]
+%
+% example: context --extra=precache
+%
+% end help
+
+\startluacode
+
+local lower = string.lower
+local filesuffix = file.suffix
+local findfile = resolvers.find_file
+
+local report = logs.reporter("fonts","precache")
+
+function fonts.names.precache()
+ local handlers = fonts.handlers
+ if not handlers then
+ report("no handlers available")
+ return
+ end
+ local otfloader = handlers.otf and handlers.otf.load
+ local afmloader = handlers.afm and handlers.afm.load
+ if not (otfloader or afmloader) then
+ report("no otf or afm handler available")
+ return
+ end
+ fonts.names.load()
+ local data = fonts.names.data
+ if not data then
+ report("no font data available")
+ return
+ end
+ local specifications = data.specifications
+ if not specifications then
+ report("no font specifications available")
+ return
+ end
+ local n = 0
+ for i=1,#specifications do
+ local specification = specifications[i]
+ local filename = specification.filename
+ local cleanfilename = specification.cleanfilename
+ local foundfile = findfile(filename)
+ if foundfile and foundfile ~= "" then
+ local suffix = lower(filesuffix(foundfile))
+ if suffix == "otf" or suffix == "ttf" then
+ if otfloader then
+ report("caching otf file: %s",foundfile)
+ otfloader(foundfile) -- todo: ttc/sub
+ n = n + 1
+ end
+ elseif suffix == "afm" then
+ if afmloader then
+ report("caching afm file: %s",foundfile)
+ afmloader(foundfile)
+ n = n + 1
+ end
+ end
+ end
+ end
+ report("%s files out of %s cached",n,#specifications)
+end
+
+\stopluacode
+
+\starttext
+
+\setuppapersize
+ [A4,landscape]
+
+\setuplayout
+ [width=middle,
+ height=middle,
+ footer=0pt,
+ header=1cm,
+ headerdistance=0cm,
+ backspace=5mm,
+ topspace=5mm]
+
+\setupbodyfont
+ [dejavu,6pt,tt]
+
+\startmode[*first]
+ \startluacode
+ fonts.names.precache()
+ \stopluacode
+\stopmode
+
+\startluacode
+ fonts.names.load()
+
+ local specifications = fonts.names.data.specifications
+
+ local sorted = { }
+ local hashed = { }
+
+ for i=1,#specifications do
+ local filename = specifications[i].cleanfilename
+ sorted[i] = filename
+ hashed[filename] = i
+ end
+
+ table.sort(sorted)
+
+ local context = context
+ local basename = file.basename
+
+ local NC = context.NC
+ local NR = context.NR
+ local HL = context.HL
+ local bold = context.bold
+
+ context.starttabulate { "||||||||||" }
+ HL()
+ NC() bold("format")
+ NC() bold("cleanfilename")
+ NC() bold("filename")
+ -- NC() bold("familyname")
+ -- NC() bold("fontname")
+ NC() bold("fullname")
+ NC() bold("rawname")
+ NC() bold("style")
+ NC() bold("variant")
+ NC() bold("weight")
+ NC() bold("width")
+ NC() NR()
+ HL()
+ for i=1,#sorted do
+ local specification = specifications[hashed[sorted[i]]]
+ NC() context(specification.format)
+ NC() context(specification.cleanfilename)
+ NC() context(basename(specification.filename))
+ -- NC() context(specification.familyname)
+ -- NC() context(specification.fontname)
+ NC() context(specification.fullname)
+ NC() context(specification.rawname)
+ NC() context(specification.style)
+ NC() context(specification.variant)
+ NC() context(specification.weight)
+ NC() context(specification.width)
+ NC() NR()
+ end
+ context.stoptabulate()
+\stopluacode
+
+\stoptext
diff --git a/Master/texmf-dist/tex/context/base/mult-aux.lua b/Master/texmf-dist/tex/context/base/mult-aux.lua
index 5a103213cde..353b5e69c3a 100644
--- a/Master/texmf-dist/tex/context/base/mult-aux.lua
+++ b/Master/texmf-dist/tex/context/base/mult-aux.lua
@@ -154,3 +154,15 @@ function namespaces.list()
local keys = { "type", "name", "comment", "version", "parent", "definition", "setup", "style" }
utilities.formatters.list(data,"namespace",keys)
end
+
+
+interfaces.implement {
+ name = "definenamespace",
+ arguments = { "string", "string" },
+ actions = namespaces.define
+}
+
+interfaces.implement {
+ name = "listnamespaces",
+ actions = namespaces.list
+}
diff --git a/Master/texmf-dist/tex/context/base/mult-aux.mkiv b/Master/texmf-dist/tex/context/base/mult-aux.mkiv
index bfac58261d3..b69d7f37068 100644
--- a/Master/texmf-dist/tex/context/base/mult-aux.mkiv
+++ b/Master/texmf-dist/tex/context/base/mult-aux.mkiv
@@ -223,14 +223,30 @@
\def#8##1{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\s!empty\fi\endcsname}%
\def#9##1{\csname#1#2:##1\endcsname}}
+% pre-expansion can be a bit faster but handly any effect on a normal run so let's go for
+% saving some memory
+%
+% \unexpanded\def\mult_interfaces_install_parameter_handler#1#2#3#4#5#6#7#8#9% inlining \csname*\endcsname is more efficient (#3 and #6 only)
+% {\ifx#2\relax\let#2\empty\fi % it is hardly faster but produces less expansion tracing
+% %\def#3##1{\csname#4{#1#2}{##1}\endcsname}%
+% \edef#3##1{\noexpand\csname\noexpand\ifcsname#1\noexpand#2:##1\endcsname#1\noexpand#2:##1\noexpand\else\noexpand\expandafter\noexpand#5\noexpand\csname#1\noexpand#2:\s!parent\endcsname{##1}\noexpand\fi\endcsname}%
+% \edef#4##1##2{\noexpand\ifcsname##1:##2\endcsname##1:##2\noexpand\else\noexpand\expandafter\noexpand#5\noexpand\csname##1:\s!parent\endcsname{##2}\noexpand\fi}%
+% \def #5##1##2{\ifx##1\relax\s!empty\else#4{##1}{##2}\fi}% is {} needed around ##1 ?
+% \edef#6##1##2{\noexpand\csname\noexpand\ifcsname#1##1:##2\endcsname#1##1:##2\noexpand\else\noexpand\expandafter\noexpand#5\noexpand\csname#1##1:\s!parent\endcsname{##2}\noexpand\fi\endcsname}%
+% \def#7##1{\detokenize\expandafter\expandafter\expandafter{\csname#1#2:##1\endcsname}}% always root, no backtrack
+% % \def#7##1{\mult_interfaces_detokenize{\csname#4{#1#2}{##1}\endcsname}}% compact version
+% % \def#7##1{\mult_interfaces_detokenize{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}}%
+% \edef#8##1{\noexpand\csname\noexpand\ifcsname#1\noexpand#2:##1\endcsname#1\noexpand#2:##1\noexpand\else\s!empty\noexpand\fi\endcsname}%
+% \edef#9##1{\noexpand\csname#1#2:##1\endcsname}}
+
\unexpanded\def\installparameterhandler#1#2%
{\normalexpanded
{\mult_interfaces_install_parameter_handler
{\noexpand#1}% \??aa
\expandafter\noexpand\csname current#2\endcsname
\expandafter\noexpand\csname #2parameter\endcsname
- \expandafter\noexpand\csname do#2parameter\endcsname % or : #2_parameter_hash
- \expandafter\noexpand\csname do#2parentparameter\endcsname % or : #2_parent_parameter_hash
+ \expandafter\noexpand\csname do#2parameter\endcsname % or : #2_parameter
+ \expandafter\noexpand\csname do#2parentparameter\endcsname % or : #2_parent_parameter
\expandafter\noexpand\csname named#2parameter\endcsname
\expandafter\noexpand\csname detokenized#2parameter\endcsname
\expandafter\noexpand\csname strict#2parameter\endcsname % checked
@@ -339,6 +355,11 @@
\expandafter\edef\csname#1#4:\s!parent\endcsname{#2}%
\fi \fi}
+\def\mult_interfaces_chain#1#2{\ifcsname#1#2:\s!chain\endcsname\csname#1#2:\s!chain\endcsname\space\fi}
+\def\getparentchain #1#2{\ifcsname#1#2:\s!chain\endcsname\csname#1#2:\s!chain\endcsname\fi}
+\def\getcurrentparentchain#1#2{\csname#1#2:\s!chain\endcsname} % for the moment test:
+\def\getcurrentparentchain#1#2{\ifcsname#1#2:\s!chain\endcsname\csname#1#2:\s!chain\endcsname\fi}
+
\unexpanded\def\mult_interfaces_install_define_handler#1#2#3#4#5#6#7#8#9% why is \expanded still needed in clones
{\ifx#4\relax\let#4\empty\fi % see \defineregister
\unexpanded\def#2{\dotripleempty#5}%
@@ -351,6 +372,7 @@
\the#6% predefine
\edef#8{##2}%
\mult_check_for_parent{#1}{#3}#4#8%
+ \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
\expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}%
\mult_interfaces_get_parameters{#1#4:}[##3]%
\else\ifsecondargument
@@ -358,16 +380,19 @@
\expandafter\mult_check_for_assignment_indeed\detokenize{##2}=@@\_end_
\ifassignment
\let#8\empty
+ \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}%
\expandafter\edef\csname#1#4:\s!parent\endcsname{#3}%
\mult_interfaces_get_parameters{#1#4:}[##2]%
\else
\edef#8{##2}%
\mult_check_for_parent{#1}{#3}#4#8%
+ \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
\expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}%
\fi
\else
\the#6% predefine
\let#8\empty
+ \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}%
\expandafter\edef\csname#1#4:\s!parent\endcsname{#3}%
\fi\fi
\the#7%
@@ -696,7 +721,7 @@
\edef#2{##1}%
#3[##2]%
\else\iffirstargument
- \doifassignmentelse{##1}
+ \doifelseassignment{##1}
{\let#2\empty
#3[##1]}%
{\edef#2{##1}}%
@@ -758,11 +783,11 @@
\else
\global\advance\c_mult_interfaces_n_of_namespaces\plusone
\expandafter\edef\csname ??#1\endcsname{\v_interfaces_prefix_template}%
- \ctxcommand{registernamespace(\number\c_mult_interfaces_n_of_namespaces,"#1")}%
+ \clf_registernamespace\c_mult_interfaces_n_of_namespaces{#1}%
\fi}
\def\mult_interfaces_get_parameters_error_indeed#1#2%
- {\ctxcommand{showassignerror("#1","#2",\the\inputlineno)}} % no longer \waitonfatalerror
+ {\clf_showassignerror{#1}{#2}\inputlineno} % no longer \waitonfatalerror
% We install two core namespaces here, as we want nice error messages. Maybe
% we will reserve the first 9.
@@ -844,10 +869,10 @@
{\dodoubleargument\mult_interfaces_define_name_space}
\def\mult_interfaces_define_name_space[#1][#2]% namespace settings
- {\ctxlua{interfaces.namespaces.define(\!!bs#1\!!es,\!!bs#2\!!es)}}
+ {\clf_definenamespace{#1}{#2}}
\def\listnamespaces
- {\ctxlua{interfaces.namespaces.list()}}
+ {\clf_listnamespaces}
%D Helper:
%D
@@ -873,6 +898,8 @@
\expandafter\secondoftwoarguments
\fi}
+\let\doifcommandhandlerelse\doifelsecommandhandler
+
\unexpanded\def\doifcommandhandler#1#2% namespace name
{\ifcsname#1#2:\s!parent\endcsname
\expandafter\firstofoneargument
@@ -891,10 +918,10 @@
% another set of (fast) helpers (grep for usage):
-\def\expandnamespaceparameter#1#2#3% \??xx \getp \c!xx \c!yy
+\def\expandnamespaceparameter#1#2#3% \??xx \getp \c!xx \v!yy
{\csname#1\ifcsname#1\expandafter\expandafter\expandafter\mult_aux_expand_namespace_parameter#2#3}
-\def\mult_aux_expand_namespace_parameter#1#2% \cs \c!yy
+\def\mult_aux_expand_namespace_parameter#1#2% \cs \v!yy
{#1\endcsname#1\else#2\fi\endcsname}
\def\expandnamespacemacro#1#2#3% \??xx \some_edefed_cs \c!yy
@@ -933,13 +960,13 @@
\unexpanded\def\syst_helpers_double_empty#1#2#3%
{\syst_helpers_argument_reset
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_double_empty_one_yes_mult#2#3}%
{\syst_helpers_double_empty_one_nop_mult#1}}
\def\syst_helpers_double_empty_one_yes_mult#1#2[#3]%
{\firstargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\secondargumenttrue#2[{#3}]}%
{\syst_helpers_double_empty_two_nop_mult#1{#3}}}
@@ -1006,19 +1033,19 @@
\unexpanded\def\syst_helpers_triple_empty#1#2#3#4%
{\syst_helpers_argument_reset
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_triple_empty_one_yes_mult#2#3#4}%
{\syst_helpers_triple_empty_one_nop_mult#1}}
\def\syst_helpers_triple_empty_one_yes_mult#1#2#3[#4]%
{\firstargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_triple_empty_two_yes_mult#2#3{#4}}%
{\syst_helpers_triple_empty_two_nop_mult#1{#4}}}
\def\syst_helpers_triple_empty_two_yes_mult#1#2#3[#4]%
{\secondargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\thirdargumenttrue#2[{#3}][{#4}]}%
{\syst_helpers_triple_empty_three_nop_mult#1{#3}{#4}}}
@@ -1102,8 +1129,8 @@
\expandafter\noexpand\csname saved_setup_current#2\endcsname
\expandafter\noexpand\csname nested_setup_current#2\endcsname}}
-% okay, we can also get rid of the #9, but thiS code looks pretty bad, while the previous is
-% still okay given that we can also use #6 as setup1 (so in fact we can save some cs again and
+% okay, we can also get rid of the #9, but this code looks pretty bad, while the previous is
+% still okay given that we can also use #6 as setup (so in fact we can save some cs again and
% only use one extra)
%
% \global\advance\commalevel \plusone
@@ -1116,4 +1143,108 @@
% % \syst_helpers_do_do_process_comma_item##1,]\relax
% \global\advance\commalevel \minusone
+% The next one is experimental (and used in publications):
+
+\let\c_mult_set\relax
+
+\unexpanded\def\mult_interfaces_install_definition_set#1#2#3#4#5#6#7%
+ {\newcount#3%
+ \let#6\empty
+ \unexpanded\def#2%
+ {\expandafter\let\expandafter\c_mult_set\csname #1_t_#6\endcsname
+ \ifx\c_mult_set\relax
+ \expandafter\newtoks\c_mult_set
+ \expandafter\let\csname #1_t_#6\endcsname\c_mult_set
+ \fi}
+ \unexpanded\def#4##1%
+ {\pushmacro#6%
+ \advance#3\plusone
+ \edef#6{##1}%
+ \unprotect}%
+ \unexpanded\def#5%
+ {\protect
+ \advance#3\minusone
+ \popmacro#6}%
+ \unexpanded\def#7##1%
+ {\edef#6{##1}%
+ #2%
+ \the\c_mult_set\relax}}
+
+\unexpanded\def\installdefinitionset#1#2%
+ {\normalexpanded
+ {\mult_interfaces_install_definition_set
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname set_#2_toks\endcsname
+ \expandafter\noexpand\csname #2_nesting_depth\endcsname
+ \expandafter\noexpand\csname push#2\endcsname
+ \expandafter\noexpand\csname pop#2\endcsname
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname use#2\endcsname}}
+
+\unexpanded\def\mult_interfaces_install_definition_set_member#1#2#3#4#5#6#7#8#9% no everysetups etc
+ {\let#5#2%
+ \unexpanded\def#2%
+ {\ifcase#4\relax\expandafter#5\else\expandafter#6\fi}%
+ \unexpanded\def#6%
+ {\dodoubleempty#7}%
+ \unexpanded\def#7[##1][##2]%
+ {\ifsecondargument
+ #3\c_mult_set\expandafter{\the\c_mult_set#9[##1][##2]}%
+ \else\iffirstargument
+ #3\c_mult_set\expandafter{\the\c_mult_set#8[##1]}%
+ \fi\fi}}
+
+\unexpanded\def\installdefinitionsetmember#1#2#3#4%
+ {\normalexpanded
+ {\mult_interfaces_install_definition_set_member
+ {\noexpand#3}% \??aa
+ \expandafter\noexpand\csname setup#4\endcsname
+ \expandafter\noexpand\csname set_#2_toks\endcsname
+ \expandafter\noexpand\csname #2_nesting_depth\endcsname
+ \expandafter\noexpand\csname normal_setup_#4\endcsname
+ \expandafter\noexpand\csname delayed_setup_#4\endcsname
+ \expandafter\noexpand\csname do_delayed_setup_#4\endcsname
+ \expandafter\noexpand\csname setup#4_\s!single\endcsname
+ \expandafter\noexpand\csname setup#4_\s!double\endcsname}}
+
+%D Another experiment:
+
+\unexpanded\def\mult_interfaces_install_parent_injector#1#2#3#4%
+ {\unexpanded\def#4##1%
+ {\ifx#3\empty
+ \expandafter\def\csname#1#2:\s!parent\endcsname{#1##1}%
+ \fi}}
+
+\unexpanded\def\installparentinjector#1#2%
+ {\normalexpanded{\mult_interfaces_install_parent_injector
+ {\noexpand#1}%
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname current#2parent\endcsname
+ \expandafter\noexpand\csname inject#2parent\endcsname}}
+
\protect
+
+%\unprotect
+% \installcorenamespace {test} \installcommandhandler \??test {test} \??test
+% \unexpanded\def\TestMeA[#1]%
+% {\edef\currenttest{#1}
+% \edef\p_before{\testparameter\c!before}%
+% \ifx\p_before\empty \relax \else \relax \fi}
+% \unexpanded\def\TestMeB[#1]%
+% {\edef\currenttest{#1}
+% \doifelsenothing{\testparameter\c!before}\relax\relax}
+% \unexpanded\def\TestMeC[#1]%
+% {\edef\currenttest{#1}
+% \expandafter\expandafter\expandafter\ifx\testparameter\c!before\empty \relax \else \relax \fi}
+% \unexpanded\def\TestMeD[#1]%
+% {\edef\currenttest{#1}
+% \doubleexpandafter\ifx\testparameter\c!before\empty \relax \else \relax \fi}
+% \protect
+%
+% \starttext
+% \definetest[foo] \definetest[bar][foo] \setuptest[bar][before=indeed]
+% \resettimer \dorecurse{100000}{\TestMeA[bar]} A:\elapsedtime \par % 0.502
+% \resettimer \dorecurse{100000}{\TestMeB[bar]} B:\elapsedtime \par % 0.530
+% \resettimer \dorecurse{100000}{\TestMeC[bar]} C:\elapsedtime \par % 0.487
+% \resettimer \dorecurse{100000}{\TestMeD[bar]} D:\elapsedtime \par % 0.493
+% \stoptext
diff --git a/Master/texmf-dist/tex/context/base/mult-chk.lua b/Master/texmf-dist/tex/context/base/mult-chk.lua
index 2a2dfcd4bd9..44a9f739f9e 100644
--- a/Master/texmf-dist/tex/context/base/mult-chk.lua
+++ b/Master/texmf-dist/tex/context/base/mult-chk.lua
@@ -16,7 +16,8 @@ local allocate = utilities.storage.allocate
local report_interface = logs.reporter("interface","checking")
-interfaces = interfaces or { }
+local interfaces = interfaces
+local implement = interfaces.implement
interfaces.syntax = allocate {
test = { keys = table.tohash { "a","b","c","d","e","f","g" } }
@@ -48,6 +49,18 @@ function interfaces.addvalidkeys(category,list)
end
end
+implement {
+ name = "setvalidinterfacekeys",
+ actions = interfaces.setvalidkeys,
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "addvalidinterfacekeys",
+ actions = interfaces.addvalidkeys,
+ arguments = { "string", "string" }
+}
+
-- weird code, looks incomplete ... probably an experiment
local prefix, category, keys
@@ -73,4 +86,8 @@ function interfaces.getcheckedparameters(k,p,s)
end
end
--- _igcp_ = interfaces.getcheckedparameters
+implement {
+ name = "getcheckedinterfaceparameters",
+ actions = interfaces.getcheckedparameters,
+ arguments = { "string", "string", "string" }
+}
diff --git a/Master/texmf-dist/tex/context/base/mult-chk.mkiv b/Master/texmf-dist/tex/context/base/mult-chk.mkiv
index 1d02f166d1b..9208a73e1e5 100644
--- a/Master/texmf-dist/tex/context/base/mult-chk.mkiv
+++ b/Master/texmf-dist/tex/context/base/mult-chk.mkiv
@@ -38,8 +38,8 @@
\unexpanded\def\setvalidparameterkeys{\dodoubleargument\mult_checkers_set_valid_parameter_keys}
\unexpanded\def\addvalidparameterkeys{\dodoubleargument\mult_checkers_add_valid_parameter_keys}
-\def\mult_checkers_set_valid_parameter_keys[#1][#2]{\ctxlua{interfaces.setvalidkeys("#1",\!!bs#2\!!es)}}
-\def\mult_checkers_add_valid_parameter_keys[#1][#2]{\ctxlua{interfaces.addvalidkeys("#1",\!!bs#2\!!es)}}
+\def\mult_checkers_set_valid_parameter_keys[#1][#2]{\clf_setvalidinterfacekeys{#1}{#2}}
+\def\mult_checkers_add_valid_parameter_keys[#1][#2]{\clf_addvalidinterfacekeys{#1}{#2}}
\def\mult_checkers_get_checked_parameters_yes[#1]#2[#3]#4[#5%
{\if\noexpand#5]%
@@ -50,8 +50,7 @@
\fi{#1}{#3}#5}
\def\mult_checkers_get_checked_parameters_yes_indeed#1#2#3]%
- %{\ctxlua{_igcp_("#1","#2",\!!bs\detokenize{#3}\!!es)}}
- {\ctxlua{interfaces.getcheckedparameters("#1","#2",\!!bs\detokenize{#3}\!!es)}}
+ {\clf_getcheckedinterfaceparameters{#1}{#2}{\detokenize{#3}}}
\def\mult_checkers_get_checked_parameters_nop[#1]#2[#3]#4[#5%
{\if\noexpand#5]%
diff --git a/Master/texmf-dist/tex/context/base/mult-de.mkii b/Master/texmf-dist/tex/context/base/mult-de.mkii
index 9e7ecd93071..90aae390e0d 100644
--- a/Master/texmf-dist/tex/context/base/mult-de.mkii
+++ b/Master/texmf-dist/tex/context/base/mult-de.mkii
@@ -180,6 +180,7 @@
\setinterfacevariable{flushleft}{flushleft}
\setinterfacevariable{flushouter}{flushouter}
\setinterfacevariable{flushright}{flushright}
+\setinterfacevariable{followingpage}{followingpage}
\setinterfacevariable{footer}{fusszeile}
\setinterfacevariable{footnote}{fussnote}
\setinterfacevariable{force}{zwinge}
@@ -301,6 +302,7 @@
\setinterfacevariable{mirrored}{gespiegelt}
\setinterfacevariable{monday}{montag}
\setinterfacevariable{mono}{mono}
+\setinterfacevariable{monobold}{monofett}
\setinterfacevariable{month}{monat}
\setinterfacevariable{more}{more}
\setinterfacevariable{morehyphenation}{morehyphenation}
@@ -360,6 +362,7 @@
\setinterfacevariable{positive}{positiv}
\setinterfacevariable{postponing}{verschieben}
\setinterfacevariable{postscript}{postscript}
+\setinterfacevariable{precedingpage}{followingpage}
\setinterfacevariable{preference}{einstellung}
\setinterfacevariable{preview}{vorschau}
\setinterfacevariable{previous}{vorig}
@@ -419,7 +422,7 @@
\setinterfacevariable{september}{september}
\setinterfacevariable{serif}{serif}
\setinterfacevariable{serried}{kleinerabstand}
-\setinterfacevariable{setups}{impostazioni}
+\setinterfacevariable{setups}{setups}
\setinterfacevariable{sheet}{sheet}
\setinterfacevariable{short}{kurz}
\setinterfacevariable{simplefonts}{simplefonts}
@@ -651,7 +654,7 @@
\setinterfaceconstant{coupling}{verknuepfung}
\setinterfaceconstant{couplingway}{verkopplungsart}
\setinterfaceconstant{criterium}{kriterium}
-\setinterfaceconstant{css}{css}
+\setinterfaceconstant{cssfile}{cssfile}
\setinterfaceconstant{current}{aktuell}
\setinterfaceconstant{cutspace}{cutspace}
\setinterfaceconstant{dash}{strich}
@@ -686,7 +689,7 @@
\setinterfaceconstant{equalwidth}{equalwidth}
\setinterfaceconstant{escape}{escape}
\setinterfaceconstant{evenmargin}{geraderand}
-\setinterfaceconstant{exitoffset}{labeloffset}
+\setinterfaceconstant{exitoffset}{exitoffset}
\setinterfaceconstant{expansion}{expansion}
\setinterfaceconstant{export}{export}
\setinterfaceconstant{extras}{extras}
@@ -753,6 +756,7 @@
\setinterfaceconstant{indenting}{einziehen}
\setinterfaceconstant{indentnext}{ziehefolgendeein}
\setinterfaceconstant{indicator}{indikator}
+\setinterfaceconstant{initialsep}{initialsep}
\setinterfaceconstant{inner}{innen}
\setinterfaceconstant{innermargin}{innermargin}
\setinterfaceconstant{inputfile}{inputfile}
@@ -858,6 +862,7 @@
\setinterfaceconstant{nright}{nrechts}
\setinterfaceconstant{ntop}{noben}
\setinterfaceconstant{number}{nummer}
+\setinterfaceconstant{numberalign}{numberalign}
\setinterfaceconstant{numbercolor}{nummernfarbe}
\setinterfaceconstant{numbercommand}{nummerbefehl}
\setinterfaceconstant{numberconversion}{numberconversion}
@@ -1281,6 +1286,7 @@
\setinterfacecommand{definetabletemplate}{definieretabellenvorlage}
\setinterfacecommand{definetabulate}{definieretabulator}
\setinterfacecommand{definetext}{definieretext}
+\setinterfacecommand{definetextbackground}{definetextbackground}
\setinterfacecommand{definetextposition}{definetextposition}
\setinterfacecommand{definetextvariable}{definetextvariable}
\setinterfacecommand{definetype}{definetype}
@@ -1441,7 +1447,6 @@
\setinterfacecommand{paperheight}{papierhoehe}
\setinterfacecommand{paperwidth}{papierbreite}
\setinterfacecommand{periods}{punkt}
-\setinterfacecommand{plaatsruwelijst}{placerawlist}
\setinterfacecommand{placebookmarks}{platzierebookmarks}
\setinterfacecommand{placecombinedlist}{platzierezusammengestellteliste}
\setinterfacecommand{placefloat}{placefloat}
@@ -1451,11 +1456,13 @@
\setinterfacecommand{placeheadtext}{placeheadtext}
\setinterfacecommand{placelegend}{platzierelegende}
\setinterfacecommand{placelist}{platziereliste}
+\setinterfacecommand{placelistofsynonyms}{placelistofsynonyms}
\setinterfacecommand{placelocalfootnotes}{platzierelokalefussnoten}
\setinterfacecommand{placelogos}{platzierelogo}
\setinterfacecommand{placeongrid}{amgitterausrichten}
\setinterfacecommand{placeontopofeachother}{platziereuntereinander}
\setinterfacecommand{placepagenumber}{placepagenumber}
+\setinterfacecommand{placerawlist}{placerawlist}
\setinterfacecommand{placereferencelist}{placereferencelist}
\setinterfacecommand{placeregister}{platziereregister}
\setinterfacecommand{placerule}{placerule}
@@ -1602,7 +1609,6 @@
\setinterfacecommand{setupregister}{stelleregisterein}
\setinterfacecommand{setuprotate}{stelledrehenein}
\setinterfacecommand{setuprule}{setuprule}
-\setinterfacecommand{setups}{einstellungen}
\setinterfacecommand{setupscreens}{stellerasterein}
\setinterfacecommand{setupsection}{stelleabschnittein}
\setinterfacecommand{setupsectionblock}{stelleabschnittsblockein}
@@ -1620,6 +1626,7 @@
\setinterfacecommand{setuptables}{stelletabellenein}
\setinterfacecommand{setuptabulate}{stelletabulatorein}
\setinterfacecommand{setuptext}{stelletextein}
+\setinterfacecommand{setuptextbackground}{setuptextbackground}
\setinterfacecommand{setuptextposition}{setuptextposition}
\setinterfacecommand{setuptextrules}{stelletextumrissein}
\setinterfacecommand{setuptexttexts}{stelletexttexteein}
@@ -1666,6 +1673,7 @@
\setinterfacecommand{startdocument}{startdokument}
\setinterfacecommand{startenvironment}{startumgebung}
\setinterfacecommand{startfigure}{startabbildung}
+\setinterfacecommand{startframed}{startframed}
\setinterfacecommand{startglobal}{startglobal}
\setinterfacecommand{startline}{startzeile}
\setinterfacecommand{startlinecorrection}{startzeilenkorrektur}
@@ -1692,6 +1700,7 @@
\setinterfacecommand{starttable}{starttabelle}
\setinterfacecommand{starttables}{starttabellen}
\setinterfacecommand{starttext}{starttext}
+\setinterfacecommand{starttextbackground}{starttextbackground}
\setinterfacecommand{starttextrule}{starttextlinie}
\setinterfacecommand{startunpacked}{startgrosserdurchschuss}
\setinterfacecommand{startversion}{startversion}
@@ -1706,6 +1715,7 @@
\setinterfacecommand{stopcomponent}{stopkomponente}
\setinterfacecommand{stopdocument}{stopdokument}
\setinterfacecommand{stopenvironment}{stopumgebung}
+\setinterfacecommand{stopframed}{stopframed}
\setinterfacecommand{stopglobal}{stopglobal}
\setinterfacecommand{stopline}{stopzeile}
\setinterfacecommand{stoplinecorrection}{stopzeilenkorrektur}
@@ -1731,6 +1741,7 @@
\setinterfacecommand{stoptable}{stoptabelle}
\setinterfacecommand{stoptables}{stoptabellen}
\setinterfacecommand{stoptext}{stoptext}
+\setinterfacecommand{stoptextbackground}{stoptextbackground}
\setinterfacecommand{stoptextrule}{stoptextlinie}
\setinterfacecommand{stopunpacked}{stopgrosserdurchschuss}
\setinterfacecommand{stopversion}{stopversion}
diff --git a/Master/texmf-dist/tex/context/base/mult-def.lua b/Master/texmf-dist/tex/context/base/mult-def.lua
index bd8b361851e..c0831de2d95 100644
--- a/Master/texmf-dist/tex/context/base/mult-def.lua
+++ b/Master/texmf-dist/tex/context/base/mult-def.lua
@@ -1275,6 +1275,10 @@ return {
["pe"]="تعریفمترادفها",
["ro"]="definestesinonim",
},
+ ["placelistofsynonyms"]={
+ ["en"]="placelistofsynonyms",
+ ["nl"]="plaatslijstmetsynoniemen",
+ },
["definetabletemplate"]={
["cs"]="definujsablonutabulky",
["de"]="definieretabellenvorlage",
@@ -2905,7 +2909,7 @@ return {
["pe"]="نقطهها",
["ro"]="puncte",
},
- ["plaatsruwelijst"]={
+ ["placerawlist"]={
["cs"]="placerawlist",
["de"]="placerawlist",
["en"]="placerawlist",
@@ -4509,16 +4513,6 @@ return {
["pe"]="بارگذاریخط",
["ro"]="seteazarigla",
},
- ["setups"]={
- ["cs"]="nastaveni",
- ["de"]="einstellungen",
- ["en"]="setups",
- ["fr"]="reglages",
- ["it"]="impostazioni",
- ["nl"]="instellingen",
- ["pe"]="بارگذاریها",
- ["ro"]="setari",
- },
["setupscreens"]={
["cs"]="nastavrastr",
["de"]="stellerasterein",
@@ -5039,6 +5033,30 @@ return {
["pe"]="شروعتنظیم",
["ro"]="startaliniere",
},
+ ["starttextbackground"]={
+ ["en"]="starttextbackground",
+ ["nl"]="starttekstachtergrond",
+ },
+ ["stoptextbackground"]={
+ ["en"]="stoptextbackground",
+ ["nl"]="stoptekstachtergrond",
+ },
+ ["setuptextbackground"]={
+ ["en"]="setuptextbackground",
+ ["nl"]="steltekstachtergrondin",
+ },
+ ["definetextbackground"]={
+ ["en"]="definetextbackground",
+ ["nl"]="definieertekstachtergrond",
+ },
+ ["startframed"]={
+ ["en"]="startframed",
+ ["nl"]="startomlijnd",
+ },
+ ["stopframed"]={
+ ["en"]="stopframed",
+ ["nl"]="stopomlijnd",
+ },
["startbackground"]={
["cs"]="startpozadi",
["de"]="starthintergrund",
@@ -6454,6 +6472,10 @@ return {
},
},
["constants"]={
+ ["setups"]={
+ ["comment"]="no translations",
+ ["en"]="setups",
+ },
-- select/simplefonts
["regularfont"] ={ ["en"]="regularfont" },
["boldfont"] ={ ["en"]="boldfont" },
@@ -6508,8 +6530,8 @@ return {
["export"] = {
["en"]="export",
},
- ["css"] = {
- ["en"]="css",
+ ["cssfile"] = {
+ ["en"]="cssfile",
},
["xhtml"] = {
["en"]="xhtml",
@@ -6522,7 +6544,7 @@ return {
["en"]="labeloffset",
},
["exitoffset"]={
- ["en"]="labeloffset",
+ ["en"]="exitoffset",
},
["commentoffset"]={
["en"]="commentoffset",
@@ -6558,6 +6580,10 @@ return {
["en"]="headalign",
["nl"]="kopuitlijnen",
},
+ ["numberalign"]={
+ ["en"]="numberalign",
+ ["nl"]="nummeruitlijnen",
+ },
["alignsymbol"]={
["en"]="alignsymbol",
},
@@ -6625,6 +6651,9 @@ return {
["surnamesep"]={
["en"]="surnamesep",
},
+ ["initialsep"]={
+ ["en"]="initialsep",
+ },
["surnameinitialsep"]={
["en"]="surnameinitialsep",
},
@@ -8944,7 +8973,7 @@ return {
["de"]="mindepth",
["en"]="mindepth",
["fr"]="profondeurmin",
- ["it"]="mindeoth",
+ ["it"]="mindepth",
["nl"]="mindiepte",
["pe"]="کمترینعمق",
["ro"]="mindepth",
@@ -10133,16 +10162,6 @@ return {
["pe"]="قراربده",
["ro"]="set",
},
- ["setups"]={
- ["cs"]="setups",
- ["de"]="setups",
- ["en"]="setups",
- ["fr"]="reglages",
- ["it"]="setups",
- ["nl"]="setups",
- ["pe"]="بارگذاریها",
- ["ro"]="setups",
- },
["shrink"]={
["en"]="shrink",
["nl"]="krimp",
@@ -11402,6 +11421,18 @@ return {
},
},
["variables"]={
+ ["setups"]={
+ ["comment"]="no translations",
+ ["en"]="setups",
+ },
+ ["followingpage"]={
+ ["en"]="followingpage",
+ ["nl"]="opvolgendepagina",
+ },
+ ["precedingpage"]={
+ ["en"]="followingpage",
+ ["nl"]="voorafgaandepagina",
+ },
["math"]={
["en"]="math",
},
@@ -11518,21 +11549,27 @@ return {
},
["maxheight"]={
["en"]="maxheight",
+ ["nl"]="maxhoogte",
},
["maxdepth"]={
["en"]="maxdepth",
+ ["nl"]="maxdiepte",
},
["maxwidth"]={
["en"]="maxwidth",
+ ["nl"]="maxbreedte",
},
["minheight"]={
["en"]="minheight",
+ ["nl"]="minhoogte",
},
["mindepth"]={
["en"]="mindepth",
+ ["nl"]="mindiepte",
},
["minwidth"]={
["en"]="minwidth",
+ ["nl"]="minbreedte",
},
["short"]={
["nl"]="kort",
@@ -14387,6 +14424,16 @@ return {
["pe"]="مونو",
["ro"]="mono",
},
+ ["monobold"]={
+ ["cs"]="monotucne",
+ ["de"]="monofett",
+ ["en"]="monobold",
+ ["fr"]="monogras",
+ ["it"]="monograssetto",
+ ["nl"]="monovet",
+ ["pe"]="monobold",
+ ["ro"]="monoaldin",
+ },
["month"]={
["cs"]="mesic",
["de"]="monat",
@@ -15484,16 +15531,6 @@ return {
["pe"]="تنگهم",
["ro"]="serried",
},
- ["setups"]={
- ["cs"]="einstellungen",
- ["de"]="impostazioni",
- ["en"]="setups",
- ["fr"]="reglages",
- ["it"]="nastaveni",
- ["nl"]="instellingen",
- ["pe"]="بارگذاریها",
- ["ro"]="setari",
- },
["sheet"]={
["cs"]="sheet",
["de"]="sheet",
diff --git a/Master/texmf-dist/tex/context/base/mult-def.mkiv b/Master/texmf-dist/tex/context/base/mult-def.mkiv
index 321f06154a8..6efeb30694c 100644
--- a/Master/texmf-dist/tex/context/base/mult-def.mkiv
+++ b/Master/texmf-dist/tex/context/base/mult-def.mkiv
@@ -30,85 +30,114 @@
% \input mult-\userinterfacetag \relax
% \input mult-m\userresponsestag \relax
-\ctxlua{interfaces.setuserinterface("\userinterfacetag","\userresponsestag")}
-
-% start todo:
-
-\def\c!fences {fences}
-\def\c!keeptogether {keeptogether}
-\def\c!viewerprefix {viewerprefix}
-
-\def\c!dataset {dataset}
-\def\c!sectionblock {sectionblock}
-\def\c!language {language}
-\def\c!compressseparator{compressseparator}
-\def\c!renderingsetup {renderingsetup}
-\def\c!filler {filler}
-\def\c!resources {resources}
-\def\c!first {first}
-\def\c!last {last}
-\def\c!quotechar {quotechar}
-\def\c!commentchar {commentchar}
-\def\c!symbolcommand {symbolcommand}
-\def\c!xmlsetup {xmlsetup}
-\def\c!comma {comma}
-\def\c!period {period}
-\def\c!monthconversion {monthconversion}
-\def\c!authorconversion {authorconversion}
-\def\c!comment {comment}
-\def\c!textalign {textalign}
-\def\c!up {up}
-\def\c!down {down}
-\def\c!instance {instance}
-\def\c!database {database}
-\def\c!group {group}
-\def\c!groupsuffix {groupsuffix}
-
-\def\c!referencemethod {referencemethod} % forward both
-
-\def\v!dataset {dataset}
-\def\v!compressseparator{compressseparator}
-\def\v!notation {notation}
-\def\v!endnote {endnote}
-\def\v!interactive {interactive}
-\def\v!autopunctuation {autopunctuation}
-\def\v!integral {integral}
-\def\v!shiftup {shiftup}
-\def\v!shiftdown {shiftdown}
-\def\v!construction {construction}
-\def\v!unframed {unframed}
-\def\v!chemical {chemical}
-\def\v!chemicals {chemicals}
-\def\v!words {words}
-\def\v!combination {combination}
-\def\v!norepeat {norepeat}
-\def\v!mixed {mixed}
-\def\v!centerlast {centerlast}
-
-\def\s!lcgreek {lcgreek}
-\def\s!ucgreek {ucgreek}
-\def\s!sygreek {sygreek}
-\def\s!italics {italics}
-\def\s!integral {integral}
-\def\s!insert {insert} % maybe insertclass
-\def\s!marker {marker}
-
-\def\s!mixedcolumn {mixedcolumn}
-
-\def\s!double {double}
-\def\s!decimal {decimal}
-\def\s!binary {binary}
-
-\def\s!internal {internal}
-
-\def\s!current {current}
-
-\def\s!rel {rel}
-\def\s!ord {ord}
-
-\def\c!HL {HL}
-\def\c!VL {VL}
-\def\c!NL {NL}
+\clf_setuserinterface{\userinterfacetag}{\userresponsestag}
+
+% start todo in mult-def.lua:
+
+\def\v!alphabetic {alphabetic}
+\def\v!Alphabetic {Alphabetic}
+
+\def\c!svgstyle {svgstyle}
+
+\def\c!translate {translate}
+
+\def\c!nextleft {nextleft}
+\def\c!nextright {nextright}
+\def\c!nextleftquotation {nextleftquotation}
+\def\c!nextrightquotation{nextrightquotation}
+
+\def\c!fences {fences}
+\def\c!words {words}
+\def\c!characters {characters}
+\def\c!hyphens {hyphens}
+\def\c!joiners {joiners}
+\def\c!leftwords {leftwords}
+\def\c!rightwords {rightwords}
+\def\c!keeptogether {keeptogether}
+\def\c!viewerprefix {viewerprefix}
+
+\def\v!display {display}
+\def\v!inline {inline}
+
+\def\v!camel {camel}
+
+\def\c!dataset {dataset}
+\def\c!sectionblock {sectionblock}
+\def\c!language {language}
+\def\c!compressseparator {compressseparator}
+\def\c!renderingsetup {renderingsetup}
+\def\c!filler {filler}
+\def\c!resources {resources}
+\def\c!first {first}
+\def\c!last {last}
+\def\c!quotechar {quotechar}
+\def\c!commentchar {commentchar}
+\def\c!symbolcommand {symbolcommand}
+\def\c!xmlsetup {xmlsetup}
+\def\c!comma {comma}
+\def\c!period {period}
+\def\c!monthconversion {monthconversion}
+\def\c!authorconversion {authorconversion}
+\def\c!comment {comment}
+\def\c!textalign {textalign}
+\def\c!up {up}
+\def\c!down {down}
+\def\c!instance {instance}
+\def\c!database {database}
+\def\c!group {group}
+\def\c!groupsuffix {groupsuffix}
+\def\c!properties {properties}
+\def\c!journalconversion {journalconversion}
+\def\c!register {register}
+\def\c!note {note}
+\def\c!field {field}
+\def\c!ignore {ignore}
+\def\c!specification {specification}
+
+\def\c!pageleft {pageleft}
+\def\c!pageright {pageright}
+\def\c!pagesep {pagesep}
+\def\c!lastpagesep {lastpagesep}
+\def\c!finalpagesep {finalpagesep}
+\def\c!pageconnector {pageconnector}
+
+\def\c!referencemethod {referencemethod} % forward both
+
+\def\v!dataset {dataset}
+\def\v!compressseparator {compressseparator}
+\def\v!notation {notation}
+\def\v!endnote {endnote}
+\def\v!interactive {interactive}
+\def\v!autopunctuation {autopunctuation}
+\def\v!integral {integral}
+\def\v!shiftup {shiftup}
+\def\v!shiftdown {shiftdown}
+\def\v!construction {construction}
+\def\v!unframed {unframed}
+\def\v!chemical {chemical}
+\def\v!chemicals {chemicals}
+\def\v!words {words}
+\def\v!combination {combination}
+\def\v!norepeat {norepeat}
+\def\v!mixed {mixed}
+\def\v!centerlast {centerlast}
+\def\v!long {long}
+\def\v!box {box}
+
+\def\v!noline {noline}
+\def\v!noheight {noheight}
+\def\v!nodepth {nodepth}
+
+\def\v!bookmark {bookmark}
+
+\def\v!vfenced {vfenced}
+\def\v!bothtext {bothtext}
+
+\def\s!traditional {traditional}
+
+\def\c!HL {HL}
+\def\c!VL {VL}
+\def\c!NL {NL}
\ifdefined\v!kerncharacters\else \def\v!kerncharacters{kerncharacters} \fi % no time now for translations should be a e! actually
\ifdefined\v!letterspacing \else \def\v!letterspacing {letterspacing} \fi % no time now for translations should be a e! actually
diff --git a/Master/texmf-dist/tex/context/base/mult-en.mkii b/Master/texmf-dist/tex/context/base/mult-en.mkii
index bf72af384c7..b08070ba044 100644
--- a/Master/texmf-dist/tex/context/base/mult-en.mkii
+++ b/Master/texmf-dist/tex/context/base/mult-en.mkii
@@ -180,6 +180,7 @@
\setinterfacevariable{flushleft}{flushleft}
\setinterfacevariable{flushouter}{flushouter}
\setinterfacevariable{flushright}{flushright}
+\setinterfacevariable{followingpage}{followingpage}
\setinterfacevariable{footer}{footer}
\setinterfacevariable{footnote}{footnote}
\setinterfacevariable{force}{force}
@@ -301,6 +302,7 @@
\setinterfacevariable{mirrored}{mirrored}
\setinterfacevariable{monday}{monday}
\setinterfacevariable{mono}{mono}
+\setinterfacevariable{monobold}{monobold}
\setinterfacevariable{month}{month}
\setinterfacevariable{more}{more}
\setinterfacevariable{morehyphenation}{morehyphenation}
@@ -360,6 +362,7 @@
\setinterfacevariable{positive}{positive}
\setinterfacevariable{postponing}{postponing}
\setinterfacevariable{postscript}{postscript}
+\setinterfacevariable{precedingpage}{followingpage}
\setinterfacevariable{preference}{preference}
\setinterfacevariable{preview}{preview}
\setinterfacevariable{previous}{previous}
@@ -651,7 +654,7 @@
\setinterfaceconstant{coupling}{coupling}
\setinterfaceconstant{couplingway}{couplingway}
\setinterfaceconstant{criterium}{criterium}
-\setinterfaceconstant{css}{css}
+\setinterfaceconstant{cssfile}{cssfile}
\setinterfaceconstant{current}{current}
\setinterfaceconstant{cutspace}{cutspace}
\setinterfaceconstant{dash}{dash}
@@ -686,7 +689,7 @@
\setinterfaceconstant{equalwidth}{equalwidth}
\setinterfaceconstant{escape}{escape}
\setinterfaceconstant{evenmargin}{evenmargin}
-\setinterfaceconstant{exitoffset}{labeloffset}
+\setinterfaceconstant{exitoffset}{exitoffset}
\setinterfaceconstant{expansion}{expansion}
\setinterfaceconstant{export}{export}
\setinterfaceconstant{extras}{extras}
@@ -753,6 +756,7 @@
\setinterfaceconstant{indenting}{indenting}
\setinterfaceconstant{indentnext}{indentnext}
\setinterfaceconstant{indicator}{indicator}
+\setinterfaceconstant{initialsep}{initialsep}
\setinterfaceconstant{inner}{inner}
\setinterfaceconstant{innermargin}{innermargin}
\setinterfaceconstant{inputfile}{inputfile}
@@ -858,6 +862,7 @@
\setinterfaceconstant{nright}{nright}
\setinterfaceconstant{ntop}{ntop}
\setinterfaceconstant{number}{number}
+\setinterfaceconstant{numberalign}{numberalign}
\setinterfaceconstant{numbercolor}{numbercolor}
\setinterfaceconstant{numbercommand}{numbercommand}
\setinterfaceconstant{numberconversion}{numberconversion}
@@ -1281,6 +1286,7 @@
\setinterfacecommand{definetabletemplate}{definetabletemplate}
\setinterfacecommand{definetabulate}{definetabulate}
\setinterfacecommand{definetext}{definetext}
+\setinterfacecommand{definetextbackground}{definetextbackground}
\setinterfacecommand{definetextposition}{definetextposition}
\setinterfacecommand{definetextvariable}{definetextvariable}
\setinterfacecommand{definetype}{definetype}
@@ -1441,7 +1447,6 @@
\setinterfacecommand{paperheight}{paperheight}
\setinterfacecommand{paperwidth}{paperwidth}
\setinterfacecommand{periods}{periods}
-\setinterfacecommand{plaatsruwelijst}{placerawlist}
\setinterfacecommand{placebookmarks}{placebookmarks}
\setinterfacecommand{placecombinedlist}{placecombinedlist}
\setinterfacecommand{placefloat}{placefloat}
@@ -1451,11 +1456,13 @@
\setinterfacecommand{placeheadtext}{placeheadtext}
\setinterfacecommand{placelegend}{placelegend}
\setinterfacecommand{placelist}{placelist}
+\setinterfacecommand{placelistofsynonyms}{placelistofsynonyms}
\setinterfacecommand{placelocalfootnotes}{placelocalfootnotes}
\setinterfacecommand{placelogos}{placelogos}
\setinterfacecommand{placeongrid}{placeongrid}
\setinterfacecommand{placeontopofeachother}{placeontopofeachother}
\setinterfacecommand{placepagenumber}{placepagenumber}
+\setinterfacecommand{placerawlist}{placerawlist}
\setinterfacecommand{placereferencelist}{placereferencelist}
\setinterfacecommand{placeregister}{placeregister}
\setinterfacecommand{placerule}{placerule}
@@ -1602,7 +1609,6 @@
\setinterfacecommand{setupregister}{setupregister}
\setinterfacecommand{setuprotate}{setuprotate}
\setinterfacecommand{setuprule}{setuprule}
-\setinterfacecommand{setups}{setups}
\setinterfacecommand{setupscreens}{setupscreens}
\setinterfacecommand{setupsection}{setupsection}
\setinterfacecommand{setupsectionblock}{setupsectionblock}
@@ -1620,6 +1626,7 @@
\setinterfacecommand{setuptables}{setuptables}
\setinterfacecommand{setuptabulate}{setuptabulate}
\setinterfacecommand{setuptext}{setuptext}
+\setinterfacecommand{setuptextbackground}{setuptextbackground}
\setinterfacecommand{setuptextposition}{setuptextposition}
\setinterfacecommand{setuptextrules}{setuptextrules}
\setinterfacecommand{setuptexttexts}{setuptexttexts}
@@ -1666,6 +1673,7 @@
\setinterfacecommand{startdocument}{startdocument}
\setinterfacecommand{startenvironment}{startenvironment}
\setinterfacecommand{startfigure}{startfigure}
+\setinterfacecommand{startframed}{startframed}
\setinterfacecommand{startglobal}{startglobal}
\setinterfacecommand{startline}{startline}
\setinterfacecommand{startlinecorrection}{startlinecorrection}
@@ -1692,6 +1700,7 @@
\setinterfacecommand{starttable}{starttable}
\setinterfacecommand{starttables}{starttables}
\setinterfacecommand{starttext}{starttext}
+\setinterfacecommand{starttextbackground}{starttextbackground}
\setinterfacecommand{starttextrule}{starttextrule}
\setinterfacecommand{startunpacked}{startunpacked}
\setinterfacecommand{startversion}{startversion}
@@ -1706,6 +1715,7 @@
\setinterfacecommand{stopcomponent}{stopcomponent}
\setinterfacecommand{stopdocument}{stopdocument}
\setinterfacecommand{stopenvironment}{stopenvironment}
+\setinterfacecommand{stopframed}{stopframed}
\setinterfacecommand{stopglobal}{stopglobal}
\setinterfacecommand{stopline}{stopline}
\setinterfacecommand{stoplinecorrection}{stoplinecorrection}
@@ -1731,6 +1741,7 @@
\setinterfacecommand{stoptable}{stoptable}
\setinterfacecommand{stoptables}{stoptables}
\setinterfacecommand{stoptext}{stoptext}
+\setinterfacecommand{stoptextbackground}{stoptextbackground}
\setinterfacecommand{stoptextrule}{stoptextrule}
\setinterfacecommand{stopunpacked}{stopunpacked}
\setinterfacecommand{stopversion}{stopversion}
diff --git a/Master/texmf-dist/tex/context/base/mult-fr.mkii b/Master/texmf-dist/tex/context/base/mult-fr.mkii
index e1129848fec..d76da18d9e0 100644
--- a/Master/texmf-dist/tex/context/base/mult-fr.mkii
+++ b/Master/texmf-dist/tex/context/base/mult-fr.mkii
@@ -180,6 +180,7 @@
\setinterfacevariable{flushleft}{flushleft}
\setinterfacevariable{flushouter}{flushouter}
\setinterfacevariable{flushright}{flushright}
+\setinterfacevariable{followingpage}{followingpage}
\setinterfacevariable{footer}{pdp}
\setinterfacevariable{footnote}{notepdp}
\setinterfacevariable{force}{force}
@@ -301,6 +302,7 @@
\setinterfacevariable{mirrored}{reflete}
\setinterfacevariable{monday}{lundi}
\setinterfacevariable{mono}{mono}
+\setinterfacevariable{monobold}{monogras}
\setinterfacevariable{month}{mois}
\setinterfacevariable{more}{more}
\setinterfacevariable{morehyphenation}{morehyphenation}
@@ -360,6 +362,7 @@
\setinterfacevariable{positive}{positif}
\setinterfacevariable{postponing}{postponing}
\setinterfacevariable{postscript}{postscript}
+\setinterfacevariable{precedingpage}{followingpage}
\setinterfacevariable{preference}{preference}
\setinterfacevariable{preview}{previsualisation}
\setinterfacevariable{previous}{precedent}
@@ -419,7 +422,7 @@
\setinterfacevariable{september}{septembre}
\setinterfacevariable{serif}{serif}
\setinterfacevariable{serried}{serried}
-\setinterfacevariable{setups}{reglages}
+\setinterfacevariable{setups}{setups}
\setinterfacevariable{sheet}{sheet}
\setinterfacevariable{short}{short}
\setinterfacevariable{simplefonts}{simplefonts}
@@ -651,7 +654,7 @@
\setinterfaceconstant{coupling}{couplage}
\setinterfaceconstant{couplingway}{modecouplage}
\setinterfaceconstant{criterium}{critere}
-\setinterfaceconstant{css}{css}
+\setinterfaceconstant{cssfile}{cssfile}
\setinterfaceconstant{current}{courant}
\setinterfaceconstant{cutspace}{cutspace}
\setinterfaceconstant{dash}{pointille}
@@ -686,7 +689,7 @@
\setinterfaceconstant{equalwidth}{equalwidth}
\setinterfaceconstant{escape}{escape}
\setinterfaceconstant{evenmargin}{margepaire}
-\setinterfaceconstant{exitoffset}{labeloffset}
+\setinterfaceconstant{exitoffset}{exitoffset}
\setinterfaceconstant{expansion}{expansion}
\setinterfaceconstant{export}{export}
\setinterfaceconstant{extras}{extras}
@@ -753,6 +756,7 @@
\setinterfaceconstant{indenting}{composeenalinea}
\setinterfaceconstant{indentnext}{indentesuivant}
\setinterfaceconstant{indicator}{indicateur}
+\setinterfaceconstant{initialsep}{initialsep}
\setinterfaceconstant{inner}{interieur}
\setinterfaceconstant{innermargin}{margeinterieure}
\setinterfaceconstant{inputfile}{fichierentree}
@@ -858,6 +862,7 @@
\setinterfaceconstant{nright}{ndroite}
\setinterfaceconstant{ntop}{nsup}
\setinterfaceconstant{number}{numero}
+\setinterfaceconstant{numberalign}{numberalign}
\setinterfaceconstant{numbercolor}{couleurnumero}
\setinterfaceconstant{numbercommand}{commandenumero}
\setinterfaceconstant{numberconversion}{numberconversion}
@@ -1002,7 +1007,7 @@
\setinterfaceconstant{separatorcolor}{separatorcolor}
\setinterfaceconstant{separatorstyle}{separatorstyle}
\setinterfaceconstant{set}{set}
-\setinterfaceconstant{setups}{reglages}
+\setinterfaceconstant{setups}{setups}
\setinterfaceconstant{shrink}{shrink}
\setinterfaceconstant{side}{cote}
\setinterfaceconstant{sidealign}{sidealign}
@@ -1281,6 +1286,7 @@
\setinterfacecommand{definetabletemplate}{definittrametableau}
\setinterfacecommand{definetabulate}{definittabulation}
\setinterfacecommand{definetext}{definittexte}
+\setinterfacecommand{definetextbackground}{definetextbackground}
\setinterfacecommand{definetextposition}{definitpositiontexte}
\setinterfacecommand{definetextvariable}{definitvariabletexte}
\setinterfacecommand{definetype}{definittype}
@@ -1441,7 +1447,6 @@
\setinterfacecommand{paperheight}{hauteurpapier}
\setinterfacecommand{paperwidth}{largeurpapier}
\setinterfacecommand{periods}{periodes}
-\setinterfacecommand{plaatsruwelijst}{placerawlist}
\setinterfacecommand{placebookmarks}{placemarquespages}
\setinterfacecommand{placecombinedlist}{placelisteinmbriquee}
\setinterfacecommand{placefloat}{placeflottant}
@@ -1451,11 +1456,13 @@
\setinterfacecommand{placeheadtext}{placetextetete}
\setinterfacecommand{placelegend}{placelegende}
\setinterfacecommand{placelist}{placeliste}
+\setinterfacecommand{placelistofsynonyms}{placelistofsynonyms}
\setinterfacecommand{placelocalfootnotes}{placenotespdplocales}
\setinterfacecommand{placelogos}{placelogos}
\setinterfacecommand{placeongrid}{placesurgrille}
\setinterfacecommand{placeontopofeachother}{placelesunsaudessusdesautres}
\setinterfacecommand{placepagenumber}{placenumeropage}
+\setinterfacecommand{placerawlist}{placerawlist}
\setinterfacecommand{placereferencelist}{placelistereference}
\setinterfacecommand{placeregister}{placeregistre}
\setinterfacecommand{placerule}{placeregle}
@@ -1602,7 +1609,6 @@
\setinterfacecommand{setupregister}{regleregistre}
\setinterfacecommand{setuprotate}{regleoriente}
\setinterfacecommand{setuprule}{regleregle}
-\setinterfacecommand{setups}{reglages}
\setinterfacecommand{setupscreens}{regleecrans}
\setinterfacecommand{setupsection}{reglesection}
\setinterfacecommand{setupsectionblock}{regleblocsection}
@@ -1620,6 +1626,7 @@
\setinterfacecommand{setuptables}{regletableaux}
\setinterfacecommand{setuptabulate}{regletabulation}
\setinterfacecommand{setuptext}{regletexte}
+\setinterfacecommand{setuptextbackground}{setuptextbackground}
\setinterfacecommand{setuptextposition}{reglepositiontexte}
\setinterfacecommand{setuptextrules}{reglelignesreglestexte}
\setinterfacecommand{setuptexttexts}{regletextestexte}
@@ -1666,6 +1673,7 @@
\setinterfacecommand{startdocument}{demarredocument}
\setinterfacecommand{startenvironment}{demarreenvironement}
\setinterfacecommand{startfigure}{demarrefigure}
+\setinterfacecommand{startframed}{startframed}
\setinterfacecommand{startglobal}{demarreglobal}
\setinterfacecommand{startline}{demarreligne}
\setinterfacecommand{startlinecorrection}{demarrecorrectionligne}
@@ -1692,6 +1700,7 @@
\setinterfacecommand{starttable}{demarretableau}
\setinterfacecommand{starttables}{demarretableaux}
\setinterfacecommand{starttext}{demarretexte}
+\setinterfacecommand{starttextbackground}{starttextbackground}
\setinterfacecommand{starttextrule}{demarreligneregleetexte}
\setinterfacecommand{startunpacked}{demarredegroupe}
\setinterfacecommand{startversion}{demarreversion}
@@ -1706,6 +1715,7 @@
\setinterfacecommand{stopcomponent}{stoppecomposant}
\setinterfacecommand{stopdocument}{stoppedocument}
\setinterfacecommand{stopenvironment}{stoppeenvironement}
+\setinterfacecommand{stopframed}{stopframed}
\setinterfacecommand{stopglobal}{stoppeglobal}
\setinterfacecommand{stopline}{stoppeligne}
\setinterfacecommand{stoplinecorrection}{stoppecorrectionligne}
@@ -1731,6 +1741,7 @@
\setinterfacecommand{stoptable}{stoppetableau}
\setinterfacecommand{stoptables}{stoppetableaux}
\setinterfacecommand{stoptext}{stoppetexte}
+\setinterfacecommand{stoptextbackground}{stoptextbackground}
\setinterfacecommand{stoptextrule}{stoppeligneregleetexte}
\setinterfacecommand{stopunpacked}{stoppedegroupe}
\setinterfacecommand{stopversion}{stoppeversion}
diff --git a/Master/texmf-dist/tex/context/base/mult-fun.lua b/Master/texmf-dist/tex/context/base/mult-fun.lua
index 846a50ddf3d..27aa3205510 100644
--- a/Master/texmf-dist/tex/context/base/mult-fun.lua
+++ b/Master/texmf-dist/tex/context/base/mult-fun.lua
@@ -4,20 +4,23 @@ return {
"nocolormodel", "greycolormodel", "graycolormodel", "rgbcolormodel", "cmykcolormodel",
"shadefactor",
"textextoffset",
- "normaltransparent", "multiplytransparent", "screentransparent", "overlaytransparent", "softlighttransparent",
- "hardlighttransparent", "colordodgetransparent", "colorburntransparent", "darkentransparent", "lightentransparent",
- "differencetransparent", "exclusiontransparent", "huetransparent", "saturationtransparent", "colortransparent", "luminositytransparent",
--- "originlength", "tickstep ", "ticklength",
--- "autoarrows", "ahfactor",
--- "angleoffset", anglelength", anglemethod",
+ "normaltransparent", "multiplytransparent", "screentransparent", "overlaytransparent",
+ "softlighttransparent", "hardlighttransparent", "colordodgetransparent", "colorburntransparent",
+ "darkentransparent", "lightentransparent", "differencetransparent", "exclusiontransparent",
+ "huetransparent", "saturationtransparent", "colortransparent", "luminositytransparent",
+ -- "originlength", "tickstep ", "ticklength",
+ -- "autoarrows", "ahfactor",
+ -- "angleoffset", anglelength", anglemethod",
"metapostversion",
"maxdimensions",
},
commands = {
+ "transparency",
--
"sqr", "log", "ln", "exp", "inv", "pow", "pi", "radian",
"tand", "cotd", "sin", "cos", "tan", "cot", "atan", "asin", "acos",
"invsin", "invcos", "invtan", "acosh", "asinh", "sinh", "cosh",
+ "zmod",
"paired", "tripled",
"unitcircle", "fulldiamond", "unitdiamond", "fullsquare",
-- "halfcircle", "quartercircle",
@@ -37,24 +40,32 @@ return {
"xsized", "ysized", "xysized", "sized", "xyscaled",
"intersection_point", "intersection_found", "penpoint",
"bbwidth", "bbheight",
- "withshade", "withlinearshading", "withcircularshading", "withfromshadecolor", "withtoshadecolor", "withshading", "shadedinto",
- "withcircularshade", "withlinearshade",
+ "withshade", "withcircularshade", "withlinearshade", -- old but kept
+ "defineshade", "shaded",
+ -- "withshading", "withlinearshading", "withcircularshading", "withfromshadecolor", "withtoshadecolor",
+ "shadedinto", "withshadecolors", "withshadedomain", "withshademethod", "withshadefactor", "withshadevector", "withshadecenter",
"cmyk", "spotcolor", "multitonecolor", "namedcolor",
"drawfill", "undrawfill",
"inverted", "uncolored", "softened", "grayed", "greyed",
"onlayer",
"along",
- "graphictext", "loadfigure", "externalfigure", "withmask", "figure", "register", "bitmapimage",
+ "graphictext", "loadfigure", "externalfigure", "figure", "register",
+ "withmask", "bitmapimage",
"colordecimals", "ddecimal", "dddecimal", "ddddecimal",
- "textext", "thetextext", "rawtextext", "textextoffset", "verbatim", "thelabel", "label", "autoalign",
+ "textext", "thetextext", "rawtextext", "textextoffset",
+ "verbatim",
+ "thelabel", "label",
+ "autoalign",
"transparent", "withtransparency",
"property", "properties", "withproperties",
"asgroup",
- "infont", -- redefined usign textext
- -- "property", "withproperties", "properties", -- not yet
- "set_linear_vector", "linear_shade", "define_linear_shade", "define_circular_linear_shade", "define_sampled_linear_shade",
- "set_circular_vector", "circular_shade", "define_circular_shade", "define_circular_linear_shade", "define_sampled_circular_shade",
- "space", "CRLF",
+ "infont", -- redefined using textext
+ -- "set_linear_vector", "set_circular_vector",
+ -- "linear_shade", "circular_shade",
+ -- "define_linear_shade", "define_circular_shade",
+ -- "define_circular_linear_shade", "define_circular_linear_shade",
+ -- "define_sampled_linear_shade", "define_sampled_circular_shade",
+ "space", "crlf", "dquote", "percent", "SPACE", "CRLF", "DQUOTE", "PERCENT",
"grayscale", "greyscale", "withgray", "withgrey",
"colorpart",
"readfile",
@@ -64,10 +75,12 @@ return {
"break",
"xstretched", "ystretched", "snapped",
--
- "pathconnectors", "function", "constructedpath", "constructedpairs",
- "punkedfunction", "curvedfunction", "tightfunction",
- "punkedpath", "curvedpath", "tightpath",
- "punkedpairs", "curvedpairs", "tightpairs",
+ "pathconnectors", "function",
+ "constructedfunction", "constructedpath", "constructedpairs",
+ -- "punkedfunction", "punkedpath", "punkedpairs",
+ "straightfunction", "straightpath", "straightpairs",
+ "curvedfunction", "curvedpath", "curvedpairs",
+ -- "tightfunction", "tightpath", "tightpairs",
--
"evenly", "oddly",
--
@@ -76,26 +89,31 @@ return {
"pushcurrentpicture", "popcurrentpicture",
--
"arrowpath",
--- "colorlike", "dowithpath", "rangepath", "straightpath", "addbackground",
--- "cleanstring", "asciistring", "setunstringed", "getunstringed", "unstringed",
--- "showgrid",
--- "phantom",
--- "xshifted", "yshifted",
--- "drawarrowpath", "midarrowhead", "arrowheadonpath",
--- "drawxticks", "drawyticks", "drawticks",
--- "pointarrow",
--- "thefreelabel", "freelabel", "freedotlabel",
--- "anglebetween", "colorcircle",
--- "remapcolors", "normalcolors", "resetcolormap", "remapcolor", "remappedcolor",
--- "recolor", "refill", "redraw", "retext", "untext", "restroke", "reprocess", "repathed",
+ -- "colorlike", "dowithpath", "rangepath", "straightpath", "addbackground",
+ -- "cleanstring", "asciistring", "setunstringed", "getunstringed", "unstringed",
+ -- "showgrid",
+ -- "phantom",
+ -- "xshifted", "yshifted",
+ -- "drawarrowpath", "midarrowhead", "arrowheadonpath",
+ -- "drawxticks", "drawyticks", "drawticks",
+ -- "pointarrow",
+ -- "thefreelabel", "freelabel", "freedotlabel",
+ -- "anglebetween", "colorcircle",
+ -- "remapcolors", "normalcolors", "resetcolormap", "remapcolor", "remappedcolor",
+ -- "recolor", "refill", "redraw", "retext", "untext", "restroke", "reprocess", "repathed",
"tensecircle", "roundedsquare",
- "colortype", "whitecolor", "blackcolor",
+ "colortype", "whitecolor", "blackcolor", "basiccolors",
--
--- "swappointlabels",
+ -- "swappointlabels",
"normalfill", "normaldraw", "visualizepaths", "naturalizepaths",
- "drawboundary", "drawwholepath", "visualizeddraw", "visualizedfill", "draworigin", "drawboundingbox",
- "drawpath", "drawpoint", "drawpoints", "drawcontrolpoints", "drawcontrollines", "drawpointlabels",
- "drawlineoptions", "drawpointoptions", "drawcontroloptions", "drawlabeloptions", "draworiginoptions", "drawboundoptions", "drawpathoptions", "resetdrawoptions",
+ "drawboundary", "drawwholepath",
+ "visualizeddraw", "visualizedfill",
+ "draworigin", "drawboundingbox",
+ "drawpath",
+ "drawpoint", "drawpoints", "drawcontrolpoints", "drawcontrollines",
+ "drawpointlabels",
+ "drawlineoptions", "drawpointoptions", "drawcontroloptions", "drawlabeloptions",
+ "draworiginoptions", "drawboundoptions", "drawpathoptions", "resetdrawoptions",
--
"undashed",
--
@@ -103,5 +121,8 @@ return {
--
"passvariable", "passarrayvariable", "tostring", "format", "formatted",
"startpassingvariable", "stoppassingvariable",
+ --
+ "eofill", "eoclip",
+ "area",
},
}
diff --git a/Master/texmf-dist/tex/context/base/mult-ini.lua b/Master/texmf-dist/tex/context/base/mult-ini.lua
index 62e983abca7..bd3b1d38b37 100644
--- a/Master/texmf-dist/tex/context/base/mult-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mult-ini.lua
@@ -12,6 +12,7 @@ local serialize = table.serialize
local context = context
local commands = commands
+local implement = interfaces.implement
local allocate = utilities.storage.allocate
local mark = utilities.storage.mark
@@ -240,9 +241,17 @@ function interfaces.setuserinterface(interface,response)
end
report_interface("definitions: %a constants, %a variables, %a elements, %a commands, %a formats, %a translations",
nofconstants,nofvariables,nofelements,nofcommands,nofformats,noftranslations)
+ else
+ report_interface("the language(s) can only be set when making the format")
end
end
+interfaces.implement {
+ name = "setuserinterface",
+ actions = interfaces.setuserinterface,
+ arguments = { "string", "string" }
+}
+
interfaces.cachedsetups = interfaces.cachedsetups or { }
interfaces.hashedsetups = interfaces.hashedsetups or { }
@@ -282,34 +291,43 @@ end
-- interface
-function commands.writestatus(category,message,...)
- local r = reporters[category]
- if r then
- r(message,...)
- end
+function interfaces.writestatus(category,message)
+ reporters[category](message) -- could also be a setmetatablecall
end
-commands.registernamespace = interfaces.registernamespace
-commands.setinterfaceconstant = interfaces.setconstant
-commands.setinterfacevariable = interfaces.setvariable
-commands.setinterfaceelement = interfaces.setelement
-commands.setinterfacemessage = interfaces.setmessage
-commands.setinterfacemessages = interfaces.setmessages
-commands.showmessage = interfaces.showmessage
+implement { name = "registernamespace", actions = interfaces.registernamespace, arguments = { "integer", "string" } }
+implement { name = "setinterfaceconstant", actions = interfaces.setconstant, arguments = { "string", "string" } }
+implement { name = "setinterfacevariable", actions = interfaces.setvariable, arguments = { "string", "string" } }
+implement { name = "setinterfaceelement", actions = interfaces.setelement, arguments = { "string", "string" } }
+implement { name = "setinterfacemessage", actions = interfaces.setmessage, arguments = { "string", "string", "string" } }
+implement { name = "setinterfacemessages", actions = interfaces.setmessages, arguments = { "string", "string" } }
+implement { name = "showmessage", actions = interfaces.showmessage, arguments = { "string", "string", "string" } }
+
+implement {
+ name = "doifelsemessage",
+ actions = { interfaces.doifelsemessage, commands.doifelse },
+ arguments = { "string", "string" },
+}
-function commands.doifelsemessage(category,tag)
- commands.doifelse(interfaces.doifelsemessage(category,tag))
-end
+implement {
+ name = "getmessage",
+ actions = { interfaces.getmessage, context },
+ arguments = { "string", "string", "string" },
+}
-function commands.getmessage(category,tag,default)
- context(interfaces.getmessage(category,tag,default))
-end
+implement {
+ name = "writestatus",
+ overload = true,
+ actions = interfaces.writestatus,
+ arguments = { "string", "string" },
+}
-function commands.showassignerror(namespace,key,line)
+local function showassignerror(namespace,key,line)
local ns, instance = match(namespace,"^(%d+)[^%a]+(%a*)")
if ns then
namespace = corenamespaces[tonumber(ns)] or ns
end
+ -- injected in the stream for timing:
if instance and instance ~= "" then
context.writestatus("setup",formatters["error in line %a, namespace %a, instance %a, key %a"](line,namespace,instance,key))
else
@@ -317,6 +335,12 @@ function commands.showassignerror(namespace,key,line)
end
end
+implement {
+ name = "showassignerror",
+ actions = showassignerror,
+ arguments = { "string", "string", "integer" },
+}
+
-- a simple helper
local settings_to_hash = utilities.parsers.settings_to_hash
diff --git a/Master/texmf-dist/tex/context/base/mult-ini.mkiv b/Master/texmf-dist/tex/context/base/mult-ini.mkiv
index 09fc5daf0ae..1dd5a696a94 100644
--- a/Master/texmf-dist/tex/context/base/mult-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mult-ini.mkiv
@@ -365,10 +365,10 @@
{\bgroup
\ifcsname\m!prefix!#2\endcsname\else\setgvalue{\m!prefix!#2}{#2}\fi
\catcode\endoflineasciicode\activecatcode
- \doifinsetelse{#1}{\currentresponses,all}\mult_messages_start_yes\mult_messages_start_nop{#2}}
+ \doifelseinset{#1}{\currentresponses,all}\mult_messages_start_yes\mult_messages_start_nop{#2}}
\def\mult_messages_start_yes#1#2\stopmessages
- {\ctxcommand{setinterfacemessages("#1",\!!bs#2\!!es)}%
+ {\clf_setinterfacemessages{#1}{#2}%
\egroup}
\def\mult_messages_start_nop#1#2\stopmessages
@@ -378,13 +378,15 @@
\unexpanded\def\setinterfacemessage#1#2#3%
{\ifcsname\m!prefix!#1\endcsname\else\setgvalue{\m!prefix!#1}{#1}\fi
- \ctxcommand{setinterfacemessage("#1","#2",\!!bs#3\!!es)}}
+ \clf_setinterfacemessage{#1}{#2}{#3}}
-\unexpanded\def\setmessagetext #1#2{\edef\currentmessagetext{\ctxcommand{getmessage("#1","#2")}}}
-\unexpanded\def\getmessage #1#2{\ctxcommand{getmessage("#1","#2")}}
-\unexpanded\def\doifelsemessage #1#2{\ctxcommand{doifelsemessage("#1","#2")}}
-\unexpanded\def\showmessage #1#2#3{\ctxcommand{showmessage("#1","#2",\!!bs#3\!!es)}}
-\unexpanded\def\writestatus #1#2{\ctxcommand{writestatus("#1",\!!bs#2\!!es)}}
+\unexpanded\def\setmessagetext #1#2{\edef\currentmessagetext{\clf_getmessage{#1}{#2}}}
+\unexpanded\def\getmessage #1#2{\clf_getmessage{#1}{#2}}
+\unexpanded\def\doifelsemessage #1#2{\clf_doifelsemessage{#1}{#2}}
+\unexpanded\def\showmessage #1#2#3{\clf_showmessage{#1}{#2}{#3}}
+\unexpanded\def\writestatus #1#2{\clf_writestatus{#1}{#2}}
+
+\let\doifmessageelse\doifelsemessage
%D \macros
%D {ifshowwarnings, ifshowmessages}
@@ -730,11 +732,11 @@
% temporary mkiv hack (we can best just store the whole table in memory)
\unexpanded\def\setinterfaceconstant#1#2%
- {\ctxcommand{setinterfaceconstant("#1","#2")}%
+ {\clf_setinterfaceconstant{#1}{#2}%
\expandafter\def\csname\c!prefix!#1\endcsname{#1}}
\unexpanded\def\setinterfacevariable#1#2%
- {\ctxcommand{setinterfacevariable("#1","#2")}%
+ {\clf_setinterfacevariable{#1}{#2}%
\expandafter\def\csname\v!prefix!#1\endcsname{#2}}
%D \macros
@@ -763,7 +765,7 @@
%D part is needed, we use a \type{-}:
\unexpanded\def\setinterfaceelement#1#2%
- {\ctxcommand{setinterfaceelement("#1","#2")}%
+ {\clf_setinterfaceelement{#1}{#2}%
\ifcsname\e!prefix!#1\endcsname
\doifnotvalue{\e!prefix!#1}{#2}{\setvalue{\e!prefix!#1}{#2}}%
\else
diff --git a/Master/texmf-dist/tex/context/base/mult-it.mkii b/Master/texmf-dist/tex/context/base/mult-it.mkii
index 5646a212e21..6474d93c4c3 100644
--- a/Master/texmf-dist/tex/context/base/mult-it.mkii
+++ b/Master/texmf-dist/tex/context/base/mult-it.mkii
@@ -180,6 +180,7 @@
\setinterfacevariable{flushleft}{flushleft}
\setinterfacevariable{flushouter}{flushouter}
\setinterfacevariable{flushright}{flushright}
+\setinterfacevariable{followingpage}{followingpage}
\setinterfacevariable{footer}{piedipagina}
\setinterfacevariable{footnote}{notapdp}
\setinterfacevariable{force}{forza}
@@ -301,6 +302,7 @@
\setinterfacevariable{mirrored}{riflesso}
\setinterfacevariable{monday}{lunedi}
\setinterfacevariable{mono}{mono}
+\setinterfacevariable{monobold}{monograssetto}
\setinterfacevariable{month}{mese}
\setinterfacevariable{more}{more}
\setinterfacevariable{morehyphenation}{morehyphenation}
@@ -360,6 +362,7 @@
\setinterfacevariable{positive}{positivo}
\setinterfacevariable{postponing}{posporre}
\setinterfacevariable{postscript}{postscript}
+\setinterfacevariable{precedingpage}{followingpage}
\setinterfacevariable{preference}{preferenza}
\setinterfacevariable{preview}{anteprima}
\setinterfacevariable{previous}{precedente}
@@ -419,7 +422,7 @@
\setinterfacevariable{september}{settembre}
\setinterfacevariable{serif}{serif}
\setinterfacevariable{serried}{vicino}
-\setinterfacevariable{setups}{nastaveni}
+\setinterfacevariable{setups}{setups}
\setinterfacevariable{sheet}{sheet}
\setinterfacevariable{short}{short}
\setinterfacevariable{simplefonts}{simplefonts}
@@ -651,7 +654,7 @@
\setinterfaceconstant{coupling}{accoppiamento}
\setinterfaceconstant{couplingway}{modoaccoppiamento}
\setinterfaceconstant{criterium}{criterio}
-\setinterfaceconstant{css}{css}
+\setinterfaceconstant{cssfile}{cssfile}
\setinterfaceconstant{current}{corrente}
\setinterfaceconstant{cutspace}{cutspace}
\setinterfaceconstant{dash}{dash}
@@ -686,7 +689,7 @@
\setinterfaceconstant{equalwidth}{equalwidth}
\setinterfaceconstant{escape}{escape}
\setinterfaceconstant{evenmargin}{marginepari}
-\setinterfaceconstant{exitoffset}{labeloffset}
+\setinterfaceconstant{exitoffset}{exitoffset}
\setinterfaceconstant{expansion}{espansione}
\setinterfaceconstant{export}{export}
\setinterfaceconstant{extras}{extras}
@@ -753,6 +756,7 @@
\setinterfaceconstant{indenting}{rientro}
\setinterfaceconstant{indentnext}{rientrasuccessivo}
\setinterfaceconstant{indicator}{indicatore}
+\setinterfaceconstant{initialsep}{initialsep}
\setinterfaceconstant{inner}{interno}
\setinterfaceconstant{innermargin}{margineinterno}
\setinterfaceconstant{inputfile}{inputfile}
@@ -834,7 +838,7 @@
\setinterfaceconstant{middletext}{testocentro}
\setinterfaceconstant{midsentence}{midsentence}
\setinterfaceconstant{min}{min}
-\setinterfaceconstant{mindepth}{mindeoth}
+\setinterfaceconstant{mindepth}{mindepth}
\setinterfaceconstant{minheight}{altezzamin}
\setinterfaceconstant{minwidth}{ampiezzamin}
\setinterfaceconstant{moffset}{moffset}
@@ -858,6 +862,7 @@
\setinterfaceconstant{nright}{ndestra}
\setinterfaceconstant{ntop}{ncima}
\setinterfaceconstant{number}{numero}
+\setinterfaceconstant{numberalign}{numberalign}
\setinterfaceconstant{numbercolor}{colorenumero}
\setinterfaceconstant{numbercommand}{comandonumero}
\setinterfaceconstant{numberconversion}{numberconversion}
@@ -1281,6 +1286,7 @@
\setinterfacecommand{definetabletemplate}{definiscimodellotabella}
\setinterfacecommand{definetabulate}{definiscitabulato}
\setinterfacecommand{definetext}{definiscitesto}
+\setinterfacecommand{definetextbackground}{definetextbackground}
\setinterfacecommand{definetextposition}{definisciposizionetesto}
\setinterfacecommand{definetextvariable}{definiscivariabiletesto}
\setinterfacecommand{definetype}{definiscitype}
@@ -1441,7 +1447,6 @@
\setinterfacecommand{paperheight}{altezzacarta}
\setinterfacecommand{paperwidth}{ampiezzacarta}
\setinterfacecommand{periods}{punti}
-\setinterfacecommand{plaatsruwelijst}{placerawlist}
\setinterfacecommand{placebookmarks}{mettisegnalibro}
\setinterfacecommand{placecombinedlist}{mettielencocombinato}
\setinterfacecommand{placefloat}{placefloat}
@@ -1451,11 +1456,13 @@
\setinterfacecommand{placeheadtext}{posizionatestotesta}
\setinterfacecommand{placelegend}{mettilegenda}
\setinterfacecommand{placelist}{mettielenco}
+\setinterfacecommand{placelistofsynonyms}{placelistofsynonyms}
\setinterfacecommand{placelocalfootnotes}{mettinotepdplocali}
\setinterfacecommand{placelogos}{mettiloghi}
\setinterfacecommand{placeongrid}{mettiingriglia}
\setinterfacecommand{placeontopofeachother}{mettiunosullaltro}
\setinterfacecommand{placepagenumber}{mettinumeropagina}
+\setinterfacecommand{placerawlist}{placerawlist}
\setinterfacecommand{placereferencelist}{placereferencelist}
\setinterfacecommand{placeregister}{mettiregistro}
\setinterfacecommand{placerule}{mettilinea}
@@ -1602,7 +1609,6 @@
\setinterfacecommand{setupregister}{impostaregistro}
\setinterfacecommand{setuprotate}{impostarotazione}
\setinterfacecommand{setuprule}{impostalinea}
-\setinterfacecommand{setups}{impostazioni}
\setinterfacecommand{setupscreens}{impostaschermi}
\setinterfacecommand{setupsection}{impostasezione}
\setinterfacecommand{setupsectionblock}{impostabloccosezione}
@@ -1620,6 +1626,7 @@
\setinterfacecommand{setuptables}{impostatabelle}
\setinterfacecommand{setuptabulate}{impostatabulato}
\setinterfacecommand{setuptext}{impostatesto}
+\setinterfacecommand{setuptextbackground}{setuptextbackground}
\setinterfacecommand{setuptextposition}{impostaposizionetesto}
\setinterfacecommand{setuptextrules}{impostalineetesto}
\setinterfacecommand{setuptexttexts}{impostatestotesti}
@@ -1666,6 +1673,7 @@
\setinterfacecommand{startdocument}{iniziadocumento}
\setinterfacecommand{startenvironment}{iniziaambiente}
\setinterfacecommand{startfigure}{iniziafigura}
+\setinterfacecommand{startframed}{startframed}
\setinterfacecommand{startglobal}{iniziaglobale}
\setinterfacecommand{startline}{iniziariga}
\setinterfacecommand{startlinecorrection}{iniziacorrezioneriga}
@@ -1692,6 +1700,7 @@
\setinterfacecommand{starttable}{iniziatabella}
\setinterfacecommand{starttables}{iniziatabelle}
\setinterfacecommand{starttext}{iniziatesto}
+\setinterfacecommand{starttextbackground}{starttextbackground}
\setinterfacecommand{starttextrule}{inizialineatesto}
\setinterfacecommand{startunpacked}{iniziaunpacked}
\setinterfacecommand{startversion}{iniziaversione}
@@ -1706,6 +1715,7 @@
\setinterfacecommand{stopcomponent}{terminacomponente}
\setinterfacecommand{stopdocument}{terminadocumento}
\setinterfacecommand{stopenvironment}{terminaambiente}
+\setinterfacecommand{stopframed}{stopframed}
\setinterfacecommand{stopglobal}{terminaglobale}
\setinterfacecommand{stopline}{terminariga}
\setinterfacecommand{stoplinecorrection}{terminacorrezioneriga}
@@ -1731,6 +1741,7 @@
\setinterfacecommand{stoptable}{terminatabella}
\setinterfacecommand{stoptables}{terminatabelle}
\setinterfacecommand{stoptext}{terminatesto}
+\setinterfacecommand{stoptextbackground}{stoptextbackground}
\setinterfacecommand{stoptextrule}{terminalineatesto}
\setinterfacecommand{stopunpacked}{terminaunpacked}
\setinterfacecommand{stopversion}{terminaversioni}
diff --git a/Master/texmf-dist/tex/context/base/mult-low.lua b/Master/texmf-dist/tex/context/base/mult-low.lua
index dda4e5aadb4..1ad0f9ebbda 100644
--- a/Master/texmf-dist/tex/context/base/mult-low.lua
+++ b/Master/texmf-dist/tex/context/base/mult-low.lua
@@ -13,7 +13,7 @@ return {
--
"zerocount", "minusone", "minustwo", "plusone", "plustwo", "plusthree", "plusfour", "plusfive",
"plussix", "plusseven", "pluseight", "plusnine", "plusten", "plussixteen", "plushundred",
- "plusthousand", "plustenthousand", "plustwentythousand", "medcard", "maxcard",
+ "plusthousand", "plustenthousand", "plustwentythousand", "medcard", "maxcard", "maxcardminusone",
"zeropoint", "onepoint", "halfapoint", "onebasepoint", "maxdimen", "scaledpoint", "thousandpoint",
"points", "halfpoint",
"zeroskip",
@@ -31,7 +31,9 @@ return {
--
"fmtname", "fmtversion", "texengine", "texenginename", "texengineversion",
"luatexengine", "pdftexengine", "xetexengine", "unknownengine",
- "etexversion", "pdftexversion", "xetexversion", "xetexrevision",
+ -- "etexversion",
+ -- "pdftexversion", "pdftexrevision",
+ -- "xetexversion", "xetexrevision",
--
"activecatcode",
--
@@ -60,7 +62,7 @@ return {
"lessthanasciicode", "morethanasciicode", "doublecommentsignal",
"atsignasciicode", "exclamationmarkasciicode", "questionmarkasciicode",
"doublequoteasciicode", "singlequoteasciicode", "forwardslashasciicode",
- "primeasciicode",
+ "primeasciicode", "hyphenasciicode",
--
"activemathcharcode",
--
@@ -85,13 +87,15 @@ return {
"fontexheight", "fontemwidth", "fontextraspace", "slantperpoint",
"interwordspace", "interwordstretch", "interwordshrink", "exheight", "emwidth", "extraspace",
"mathsupdisplay", "mathsupnormal", "mathsupcramped", "mathsubnormal", "mathsubcombined", "mathaxisheight",
+ "muquad",
--
-- maybe a different class
--
"startmode", "stopmode", "startnotmode", "stopnotmode", "startmodeset", "stopmodeset",
- "doifmode", "doifmodeelse", "doifnotmode",
+ "doifmode", "doifelsemode", "doifmodeelse", "doifnotmode",
"startmodeset","stopmodeset",
- "startallmodes", "stopallmodes", "startnotallmodes", "stopnotallmodes", "doifallmodes", "doifallmodeselse", "doifnotallmodes",
+ "startallmodes", "stopallmodes", "startnotallmodes", "stopnotallmodes",
+ "doifallmodes", "doifelseallmodes", "doifallmodeselse", "doifnotallmodes",
"startenvironment", "stopenvironment", "environment",
"startcomponent", "stopcomponent", "component",
"startproduct", "stopproduct", "product",
@@ -103,7 +107,7 @@ return {
"startTEXpage", "stopTEXpage",
-- "startMPpage", "stopMPpage", -- already catched by nested lexer
--
- "enablemode", "disablemode", "preventmode",
+ "enablemode", "disablemode", "preventmode", "definemode",
"globalenablemode", "globaldisablemode", "globalpreventmode",
"pushmode", "popmode",
--
@@ -121,12 +125,12 @@ return {
--
"lefttorightmark", "righttoleftmark",
--
- "breakablethinspace", "nobreakspace", "narrownobreakspace", "zerowidthnobreakspace",
+ "breakablethinspace", "nobreakspace", "nonbreakablespace", "narrownobreakspace", "zerowidthnobreakspace",
"ideographicspace", "ideographichalffillspace",
"twoperemspace", "threeperemspace", "fourperemspace", "fiveperemspace", "sixperemspace",
"figurespace", "punctuationspace", "hairspace",
"zerowidthspace", "zerowidthnonjoiner", "zerowidthjoiner", "zwnj", "zwj",
- "optionalspace",
+ "optionalspace", "asciispacechar",
},
["helpers"] = {
--
@@ -140,9 +144,10 @@ return {
"starttexcode", "stoptexcode",
"startcontextcode", "stopcontextcode",
"startcontextdefinitioncode", "stopcontextdefinitioncode",
+ "texdefinition",
--
- "doifsetupselse", "doifsetups", "doifnotsetups", "setup", "setups", "texsetup", "xmlsetup", "luasetup", "directsetup",
- "doifelsecommandhandler","doifnotcommandhandler","doifcommandhandler",
+ "doifelsesetups", "doifsetupselse", "doifsetups", "doifnotsetups", "setup", "setups", "texsetup", "xmlsetup", "luasetup", "directsetup", "fastsetup",
+ "doifelsecommandhandler", "doifcommandhandlerelse", "doifnotcommandhandler", "doifcommandhandler",
--
"newmode", "setmode", "resetmode",
"newsystemmode", "setsystemmode", "resetsystemmode", "pushsystemmode", "popsystemmode",
@@ -154,7 +159,7 @@ return {
"then",
"begcsname",
--
- "strippedcsname",
+ "strippedcsname","checkedstrippedcsname",
--
"firstargumentfalse", "firstargumenttrue",
"secondargumentfalse", "secondargumenttrue",
@@ -169,6 +174,8 @@ return {
--
"donetrue", "donefalse",
--
+ "inlineordisplaymath","indisplaymath","forcedisplaymath","startforceddisplaymath","stopforceddisplaymath","reqno",
+ --
"htdp",
"unvoidbox",
"hfilll", "vfilll",
@@ -200,7 +207,7 @@ return {
--
"normalbaselineskip", "normallineskip", "normallineskiplimit",
--
- "availablehsize", "localhsize", "setlocalhsize",
+ "availablehsize", "localhsize", "setlocalhsize", "distributedhsize", "hsizefraction",
--
"nextbox", "dowithnextbox", "dowithnextboxcs", "dowithnextboxcontent", "dowithnextboxcontentcs",
--
@@ -222,25 +229,36 @@ return {
"scratchleftskip", "scratchrightskip", "scratchtopskip", "scratchbottomskip",
--
"doif", "doifnot", "doifelse",
- "doifinset", "doifnotinset", "doifinsetelse",
- "doifnextcharelse", "doifnextoptionalelse", "doifnextoptionalcselse", "doiffastoptionalcheckelse",
- "doifnextbgroupelse", "doifnextbgroupcselse",
- "doifnextparenthesiselse",
- "doifundefinedelse", "doifdefinedelse", "doifundefined", "doifdefined",
+ "doifinset", "doifnotinset",
+ "doifelseinset", "doifinsetelse",
+ "doifelsenextchar", "doifnextcharelse",
+ "doifelsenextoptional", "doifnextoptionalelse",
+ "doifelsenextoptionalcs", "doifnextoptionalcselse",
+ "doifelsefastoptionalcheck", "doiffastoptionalcheckelse",
+ "doifelsenextbgroup", "doifnextbgroupelse",
+ "doifelsenextbgroupcs", "doifnextbgroupcselse",
+ "doifelsenextparenthesis", "doifnextparenthesiselse",
+ "doifelseundefined", "doifundefinedelse",
+ "doifelsedefined", "doifdefinedelse",
+ "doifundefined", "doifdefined",
"doifelsevalue", "doifvalue", "doifnotvalue",
- "doifnothing", "doifsomething", "doifelsenothing", "doifsomethingelse",
- "doifvaluenothing", "doifvaluesomething", "doifelsevaluenothing",
- "doifdimensionelse", "doifnumberelse", "doifnumber", "doifnotnumber",
- "doifcommonelse", "doifcommon", "doifnotcommon",
- "doifinstring", "doifnotinstring", "doifinstringelse",
- "doifassignmentelse", "docheckassignment",
+ "doifnothing", "doifsomething",
+ "doifelsenothing", "doifnothingelse",
+ "doifelsesomething", "doifsomethingelse",
+ "doifvaluenothing", "doifvaluesomething",
+ "doifelsevaluenothing", "doifvaluenothingelse",
+ "doifelsedimension", "doifdimensionelse",
+ "doifelsenumber", "doifnumberelse", "doifnumber", "doifnotnumber",
+ "doifelsecommon", "doifcommonelse", "doifcommon", "doifnotcommon",
+ "doifinstring", "doifnotinstring", "doifelseinstring", "doifinstringelse",
+ "doifelseassignment", "doifassignmentelse", "docheckassignment",
--
"tracingall", "tracingnone", "loggingall",
--
"removetoks", "appendtoks", "prependtoks", "appendtotoks", "prependtotoks", "to",
--
- "endgraf", "endpar", "everyendpar", "reseteverypar", "finishpar", "empty", "null", "space", "quad", "enspace",
- "obeyspaces", "obeylines", "obeyedspace", "obeyedline",
+ "endgraf", "endpar", "everyendpar", "reseteverypar", "finishpar", "empty", "null", "space", "quad", "enspace", "nbsp",
+ "obeyspaces", "obeylines", "obeyedspace", "obeyedline", "obeyedtab", "obeyedpage",
"normalspace",
--
"executeifdefined",
@@ -279,6 +297,8 @@ return {
"firstofsixarguments", "secondofsixarguments", "thirdofsixarguments", "fourthofsixarguments", "fifthofsixarguments", "sixthofsixarguments",
--
"firstofoneunexpanded",
+ "firstoftwounexpanded", "secondoftwounexpanded",
+ "firstofthreeunexpanded", "secondofthreeunexpanded", "thirdofthreeunexpanded",
--
"gobbleoneargument", "gobbletwoarguments", "gobblethreearguments", "gobblefourarguments", "gobblefivearguments", "gobblesixarguments", "gobblesevenarguments", "gobbleeightarguments", "gobbleninearguments", "gobbletenarguments",
"gobbleoneoptional", "gobbletwooptionals", "gobblethreeoptionals", "gobblefouroptionals", "gobblefiveoptionals",
@@ -300,7 +320,7 @@ return {
--
"modulonumber", "dividenumber",
--
- "getfirstcharacter", "doiffirstcharelse",
+ "getfirstcharacter", "doifelsefirstchar", "doiffirstcharelse",
--
"startnointerference", "stopnointerference",
--
@@ -310,7 +330,7 @@ return {
--
"offinterlineskip", "oninterlineskip", "nointerlineskip",
--
- "strut", "setstrut", "strutbox", "strutht", "strutdp", "strutwd", "struthtdp", "begstrut", "endstrut", "lineheight",
+ "strut", "halfstrut", "quarterstrut", "depthstrut", "setstrut", "strutbox", "strutht", "strutdp", "strutwd", "struthtdp", "begstrut", "endstrut", "lineheight",
--
"ordordspacing", "ordopspacing", "ordbinspacing", "ordrelspacing",
"ordopenspacing", "ordclosespacing", "ordpunctspacing", "ordinnerspacing",
@@ -344,13 +364,17 @@ return {
"uncramped", "cramped", "triggermathstyle", "mathstylefont", "mathsmallstylefont", "mathstyleface", "mathsmallstyleface", "mathstylecommand", "mathpalette",
"mathstylehbox", "mathstylevbox", "mathstylevcenter", "mathstylevcenteredhbox", "mathstylevcenteredvbox",
"mathtext", "setmathsmalltextbox", "setmathtextbox",
+ "pushmathstyle", "popmathstyle",
--
"triggerdisplaystyle", "triggertextstyle", "triggerscriptstyle", "triggerscriptscriptstyle",
"triggeruncrampedstyle", "triggercrampedstyle",
"triggersmallstyle", "triggeruncrampedsmallstyle", "triggercrampedsmallstyle",
"triggerbigstyle", "triggeruncrampedbigstyle", "triggercrampedbigstyle",
--
- "luaexpr", "expdoifelse", "expdoif", "expdoifnot", "expdoifcommonelse", "expdoifinsetelse",
+ "luaexpr",
+ "expelsedoif", "expdoif", "expdoifnot",
+ "expdoifelsecommon", "expdoifcommonelse",
+ "expdoifelseinset", "expdoifinsetelse",
--
"ctxdirectlua", "ctxlatelua", "ctxsprint", "ctxwrite", "ctxcommand", "ctxdirectcommand", "ctxlatecommand", "ctxreport",
"ctxlua", "luacode", "lateluacode", "directluacode",
@@ -362,7 +386,7 @@ return {
"obeylualines", "obeyluatokens",
"startluacode", "stopluacode", "startlua", "stoplua",
"startctxfunction","stopctxfunction","ctxfunction",
- "startctxfunctiondefinition","stopctxfunctiondefinition",
+ "startctxfunctiondefinition","stopctxfunctiondefinition", "installctxfunction",
--
"carryoverpar",
--
@@ -379,5 +403,6 @@ return {
--
"Ucheckedstartdisplaymath", "Ucheckedstopdisplaymath",
--
+ "nobreak", "allowbreak", "goodbreak",
}
}
diff --git a/Master/texmf-dist/tex/context/base/mult-mes.lua b/Master/texmf-dist/tex/context/base/mult-mes.lua
index 0affb43d6d8..64184f8b0f0 100644
--- a/Master/texmf-dist/tex/context/base/mult-mes.lua
+++ b/Master/texmf-dist/tex/context/base/mult-mes.lua
@@ -1002,6 +1002,15 @@ return {
["publications:11"] = {
en = "unknown command %a",
},
+ ["publications:12"] = {
+ en = "missing setup: %s",
+ },
+ ["publications:13"] = {
+ en = "no field %a for tag %a in dataset %a",
+ },
+ ["publications:14"] = {
+ en = "unknown rendering alternative %a",
+ },
["pushing level: %a"] = {
nl = "niveau omhoog: %a",
},
diff --git a/Master/texmf-dist/tex/context/base/mult-mps.lua b/Master/texmf-dist/tex/context/base/mult-mps.lua
index 717536fbf91..a6bebc26613 100644
--- a/Master/texmf-dist/tex/context/base/mult-mps.lua
+++ b/Master/texmf-dist/tex/context/base/mult-mps.lua
@@ -3,7 +3,7 @@ return {
"btex", "etex", "verbatimtex",
},
shortcuts = {
- "..", "...", "--", "---", "&",
+ "..", "...", "--", "---", "&", "\\",
},
primitives = { -- to be checked
"charcode", "day", "linecap", "linejoin", "miterlimit", "month", "pausing",
@@ -31,8 +31,10 @@ return {
"def", "vardef", "enddef", "expr", "suffix", "text", "primary", "secondary",
"tertiary", "primarydef", "secondarydef", "tertiarydef",
"randomseed", "also", "contour", "doublepath",
- "withcolor", "withcmykcolor", "withpen", "dashed", "if", "else", "elseif", "fi", "for", "endfor", "forever", "exitif", "within",
- "forsuffixes", "downto", "upto", "step", "until",
+ "withcolor", "withcmykcolor", "withpen",
+ "dashed",
+ "if", "else", "elseif", "fi", "for", "endfor", "forever", "exitif", "within",
+ "forsuffixes", "step", "until",
"charlist", "extensible", "fontdimen", "headerbyte", "kern", "ligtable",
"boundarychar", "chardp", "charext", "charht", "charic", "charwd", "designsize",
"fontmaking", "charexists",
@@ -50,29 +52,34 @@ return {
"withprescript", "withpostscript",
"top", "bot", "lft", "rt", "ulft", "urt", "llft", "lrt",
--
- "redpart", "greenpart", "bluepart", "cyanpart", "magentapart", "yellowpart", "blackpart", "greypart",
+ "redpart", "greenpart", "bluepart",
+ "cyanpart", "magentapart", "yellowpart",
+ "blackpart",
"prescriptpart", "postscriptpart",
- "rgbcolor", "cmykcolor", "greycolor", "graycolor",
- "colormodel", "graypart",
+ "rgbcolor", "cmykcolor", -- "greycolor", "graycolor",
+ "colormodel", "graypart", "greypart", "greycolor", "graycolor",
"dashpart", "penpart",
-- "colorpart",
"stroked", "filled", "textual", "clipped", "bounded", "pathpart",
"expandafter",
- "minute", "hour", "outputformat", "outputtemplate", "filenametemplate", "fontmapfile", "fontmapline",
+ "minute", "hour",
+ "outputformat", "outputtemplate", "filenametemplate", "fontmapfile", "fontmapline",
"fontpart", "fontsize", "glyph", "restoreclipcolor", "troffmode",
--
- "runscript",
+ "runscript", "maketext",
},
commands = {
+ "upto", "downto",
"beginfig", "endfig",
- "beginglyph", "endglyph", "charscale",
+ "beginglyph", "endglyph", -- actually a mult-fun one
"rotatedaround", "reflectedabout",
"arrowhead",
"currentpen", "currentpicture", "cuttings",
"defaultfont", "extra_beginfig", "extra_endfig",
"ditto", "EOF", "down",
"evenly", "fullcircle", "halfcircle", "identity", "in", "left",
- "origin", "pensquare", "quartercircle", "right",
+ "pensquare", "penrazor", "penspec",
+ "origin", "quartercircle", "right",
"unitsquare", "up", "withdots",
"abs", "bbox", "ceiling", "center", "cutafter", "cutbefore", "dir",
"directionpoint", "div", "dotprod", "intersectionpoint", "inverse", "mod",
@@ -99,14 +106,13 @@ return {
"counterclockwise", "tensepath", "takepower", "direction",
"softjoin", -- "magstep",
"makelabel", -- "laboff",
- "rotatedabout", "flex", "superellipse", "erase", "image",
+ "rotatedabout", "flex", "superellipse", "image",
"nullpen", "savepen", "clearpen", "penpos", "penlabels", -- "clear_pen_memory",
- "range", "numtok", "thru",
+ "range", "thru",
"z", "laboff",
"bye",
--
"red", "green", "blue", "cyan", "magenta", "yellow", "black", "white", "background",
- "graypart", "graycolor",
--
"mm", "pt", "dd", "bp", "cm", "pc", "cc", "in",
--
@@ -116,8 +122,41 @@ return {
--
"mitered", "rounded", "beveled", "butt", "squared",
"eps", "epsilon", "infinity",
- "bboxmargin", "ahlength", "ahangle", "labeloffset", "dotlabeldiam", "defaultpen", "defaultscale", "join_radius",
+ "bboxmargin",
+ "ahlength", "ahangle",
+ "labeloffset", "dotlabeldiam",
+ "defaultpen", "defaultscale",
+ "join_radius",
+ "charscale", -- actually a mult-fun one
--
"pen_lft", "pen_rt", "pen_top", "pen_bot", -- "pen_count_",
},
+ metafont = {
+ -- :: =: =:| =:|> |=: |=:> |=:| |=:|> |=:|>> ||:
+ "autorounding", "beginchar", "blacker", "boundarychar", "capsule_def",
+ "capsule_end", "change_width", "chardp", "chardx", "chardy", "charexists",
+ "charext", "charht", "charic", "charlist", "charwd", "cull", "cullit",
+ "currenttransform", "currentwindow", "define_blacker_pixels",
+ "define_corrected_pixels", "define_good_x_pixels", "define_good_y_pixels",
+ "define_horizontal_corrected_pixels", "define_pixels",
+ "define_whole_blacker_pixels", "define_whole_pixels",
+ "define_whole_vertical_blacker_pixels", "define_whole_vertical_pixels",
+ "designsize", "display", "displaying", "endchar", "extensible", "extra_beginchar",
+ "extra_endchar", "extra_setup", "fillin", "font_coding_scheme",
+ "font_extra_space", "font_identifier", "font_normal_shrink",
+ "font_normal_space", "font_normal_stretch", "font_quad", "font_size",
+ "font_slant", "font_x_height", "fontdimen", "fontmaking", "gfcorners",
+ "granularity", "grayfont", "headerbyte", "hppp", "hround", "imagerules",
+ "italcorr", "kern", "labelfont", "ligtable", "lowres_fix", "makebox",
+ "makegrid", "maketicks", "mode_def", "mode_setup", "nodisplays",
+ "notransforms", "numspecial", "o_correction", "openit", "openwindow",
+ "pixels_per_inch", "proofing", "proofoffset", "proofrule", "proofrulethickness",
+ "rulepen", "screenchars", "screenrule", "screenstrokes", "screen_cols", "screen_rows",
+ "showit", "slantfont", "smode", "smoothing", "titlefont", "totalweight",
+ "tracingedges", "tracingpens", "turningcheck", "unitpixel", "vppp", "vround",
+ "xoffset", "yoffset",
+ },
+ disabled = {
+ "verbatimtex", "troffmode"
+ }
}
diff --git a/Master/texmf-dist/tex/context/base/mult-nl.mkii b/Master/texmf-dist/tex/context/base/mult-nl.mkii
index aa376c39a1e..22350dc50c3 100644
--- a/Master/texmf-dist/tex/context/base/mult-nl.mkii
+++ b/Master/texmf-dist/tex/context/base/mult-nl.mkii
@@ -180,6 +180,7 @@
\setinterfacevariable{flushleft}{lijnlinks}
\setinterfacevariable{flushouter}{lijnbuiten}
\setinterfacevariable{flushright}{lijnrechts}
+\setinterfacevariable{followingpage}{opvolgendepagina}
\setinterfacevariable{footer}{voet}
\setinterfacevariable{footnote}{voetnoot}
\setinterfacevariable{force}{forceer}
@@ -287,20 +288,21 @@
\setinterfacevariable{mathematics}{wiskunde}
\setinterfacevariable{mathmatrix}{wiskundematrix}
\setinterfacevariable{max}{max}
-\setinterfacevariable{maxdepth}{maxdepth}
-\setinterfacevariable{maxheight}{maxheight}
-\setinterfacevariable{maxwidth}{maxwidth}
+\setinterfacevariable{maxdepth}{maxdiepte}
+\setinterfacevariable{maxheight}{maxhoogte}
+\setinterfacevariable{maxwidth}{maxbreedte}
\setinterfacevariable{may}{mei}
\setinterfacevariable{mediaeval}{mediaeval}
\setinterfacevariable{medium}{middel}
\setinterfacevariable{middle}{midden}
\setinterfacevariable{min}{min}
-\setinterfacevariable{mindepth}{mindepth}
+\setinterfacevariable{mindepth}{mindiepte}
\setinterfacevariable{minheight}{minhoogte}
\setinterfacevariable{minwidth}{minbreedte}
\setinterfacevariable{mirrored}{gespiegeld}
\setinterfacevariable{monday}{maandag}
\setinterfacevariable{mono}{mono}
+\setinterfacevariable{monobold}{monovet}
\setinterfacevariable{month}{maand}
\setinterfacevariable{more}{meer}
\setinterfacevariable{morehyphenation}{morehyphenation}
@@ -360,6 +362,7 @@
\setinterfacevariable{positive}{positief}
\setinterfacevariable{postponing}{uitstellen}
\setinterfacevariable{postscript}{postscript}
+\setinterfacevariable{precedingpage}{voorafgaandepagina}
\setinterfacevariable{preference}{voorkeur}
\setinterfacevariable{preview}{preview}
\setinterfacevariable{previous}{vorige}
@@ -419,7 +422,7 @@
\setinterfacevariable{september}{september}
\setinterfacevariable{serif}{serif}
\setinterfacevariable{serried}{aanelkaar}
-\setinterfacevariable{setups}{instellingen}
+\setinterfacevariable{setups}{setups}
\setinterfacevariable{sheet}{sheet}
\setinterfacevariable{short}{kort}
\setinterfacevariable{simplefonts}{simplefonts}
@@ -651,7 +654,7 @@
\setinterfaceconstant{coupling}{koppeling}
\setinterfaceconstant{couplingway}{koppelwijze}
\setinterfaceconstant{criterium}{criterium}
-\setinterfaceconstant{css}{css}
+\setinterfaceconstant{cssfile}{cssfile}
\setinterfaceconstant{current}{huidige}
\setinterfaceconstant{cutspace}{snijwit}
\setinterfaceconstant{dash}{streep}
@@ -686,7 +689,7 @@
\setinterfaceconstant{equalwidth}{equalwidth}
\setinterfaceconstant{escape}{escape}
\setinterfaceconstant{evenmargin}{evenmarge}
-\setinterfaceconstant{exitoffset}{labeloffset}
+\setinterfaceconstant{exitoffset}{exitoffset}
\setinterfaceconstant{expansion}{expansie}
\setinterfaceconstant{export}{exporteer}
\setinterfaceconstant{extras}{extras}
@@ -753,6 +756,7 @@
\setinterfaceconstant{indenting}{inspringen}
\setinterfaceconstant{indentnext}{springvolgendein}
\setinterfaceconstant{indicator}{aanduiding}
+\setinterfaceconstant{initialsep}{initialsep}
\setinterfaceconstant{inner}{binnen}
\setinterfaceconstant{innermargin}{binnenmarge}
\setinterfaceconstant{inputfile}{inputfile}
@@ -858,6 +862,7 @@
\setinterfaceconstant{nright}{nrechts}
\setinterfaceconstant{ntop}{nboven}
\setinterfaceconstant{number}{nummer}
+\setinterfaceconstant{numberalign}{nummeruitlijnen}
\setinterfaceconstant{numbercolor}{nummerkleur}
\setinterfaceconstant{numbercommand}{nummercommando}
\setinterfaceconstant{numberconversion}{numberconversion}
@@ -1281,6 +1286,7 @@
\setinterfacecommand{definetabletemplate}{definieertabelvorm}
\setinterfacecommand{definetabulate}{definieertabulatie}
\setinterfacecommand{definetext}{definieertekst}
+\setinterfacecommand{definetextbackground}{definieertekstachtergrond}
\setinterfacecommand{definetextposition}{definieertekstpositie}
\setinterfacecommand{definetextvariable}{definieertekstvariabele}
\setinterfacecommand{definetype}{definieertype}
@@ -1441,7 +1447,6 @@
\setinterfacecommand{paperheight}{papierhoogte}
\setinterfacecommand{paperwidth}{papierbreedte}
\setinterfacecommand{periods}{punten}
-\setinterfacecommand{plaatsruwelijst}{plaatsruwelijst}
\setinterfacecommand{placebookmarks}{plaatsbookmarks}
\setinterfacecommand{placecombinedlist}{plaatssamengesteldelijst}
\setinterfacecommand{placefloat}{plaatsplaatsblok}
@@ -1451,11 +1456,13 @@
\setinterfacecommand{placeheadtext}{plaatskoptekst}
\setinterfacecommand{placelegend}{plaatslegenda}
\setinterfacecommand{placelist}{plaatslijst}
+\setinterfacecommand{placelistofsynonyms}{plaatslijstmetsynoniemen}
\setinterfacecommand{placelocalfootnotes}{plaatslokalevoetnoten}
\setinterfacecommand{placelogos}{plaatsbeeldmerken}
\setinterfacecommand{placeongrid}{plaatsopgrid}
\setinterfacecommand{placeontopofeachother}{plaatsonderelkaar}
\setinterfacecommand{placepagenumber}{plaatspaginanummer}
+\setinterfacecommand{placerawlist}{plaatsruwelijst}
\setinterfacecommand{placereferencelist}{plaatsreferentielijst}
\setinterfacecommand{placeregister}{plaatsregister}
\setinterfacecommand{placerule}{plaatslijn}
@@ -1602,7 +1609,6 @@
\setinterfacecommand{setupregister}{stelregisterin}
\setinterfacecommand{setuprotate}{stelroterenin}
\setinterfacecommand{setuprule}{stellijnin}
-\setinterfacecommand{setups}{instellingen}
\setinterfacecommand{setupscreens}{stelrastersin}
\setinterfacecommand{setupsection}{stelsectiein}
\setinterfacecommand{setupsectionblock}{stelsectieblokin}
@@ -1620,6 +1626,7 @@
\setinterfacecommand{setuptables}{steltabellenin}
\setinterfacecommand{setuptabulate}{steltabulatiein}
\setinterfacecommand{setuptext}{steltekstin}
+\setinterfacecommand{setuptextbackground}{steltekstachtergrondin}
\setinterfacecommand{setuptextposition}{steltekstpositiein}
\setinterfacecommand{setuptextrules}{steltekstlijnenin}
\setinterfacecommand{setuptexttexts}{stelteksttekstenin}
@@ -1666,6 +1673,7 @@
\setinterfacecommand{startdocument}{startdocument}
\setinterfacecommand{startenvironment}{startomgeving}
\setinterfacecommand{startfigure}{startfiguur}
+\setinterfacecommand{startframed}{startomlijnd}
\setinterfacecommand{startglobal}{startglobaal}
\setinterfacecommand{startline}{startregel}
\setinterfacecommand{startlinecorrection}{startregelcorrectie}
@@ -1692,6 +1700,7 @@
\setinterfacecommand{starttable}{starttabel}
\setinterfacecommand{starttables}{starttabellen}
\setinterfacecommand{starttext}{starttekst}
+\setinterfacecommand{starttextbackground}{starttekstachtergrond}
\setinterfacecommand{starttextrule}{starttekstlijn}
\setinterfacecommand{startunpacked}{startvanelkaar}
\setinterfacecommand{startversion}{startversie}
@@ -1706,6 +1715,7 @@
\setinterfacecommand{stopcomponent}{stoponderdeel}
\setinterfacecommand{stopdocument}{stopdocument}
\setinterfacecommand{stopenvironment}{stopomgeving}
+\setinterfacecommand{stopframed}{stopomlijnd}
\setinterfacecommand{stopglobal}{stopglobaal}
\setinterfacecommand{stopline}{stopregel}
\setinterfacecommand{stoplinecorrection}{stopregelcorrectie}
@@ -1731,6 +1741,7 @@
\setinterfacecommand{stoptable}{stoptabel}
\setinterfacecommand{stoptables}{stoptabellen}
\setinterfacecommand{stoptext}{stoptekst}
+\setinterfacecommand{stoptextbackground}{stoptekstachtergrond}
\setinterfacecommand{stoptextrule}{stoptekstlijn}
\setinterfacecommand{stopunpacked}{stopvanelkaar}
\setinterfacecommand{stopversion}{stopversie}
diff --git a/Master/texmf-dist/tex/context/base/mult-pe.mkii b/Master/texmf-dist/tex/context/base/mult-pe.mkii
index 16871bb6260..32cf32db1c3 100644
--- a/Master/texmf-dist/tex/context/base/mult-pe.mkii
+++ b/Master/texmf-dist/tex/context/base/mult-pe.mkii
@@ -180,6 +180,7 @@
\setinterfacevariable{flushleft}{پمپچپ}
\setinterfacevariable{flushouter}{پمپخارجی}
\setinterfacevariable{flushright}{پمپراست}
+\setinterfacevariable{followingpage}{followingpage}
\setinterfacevariable{footer}{تهبرگ}
\setinterfacevariable{footnote}{پانوشت}
\setinterfacevariable{force}{اجبار}
@@ -301,6 +302,7 @@
\setinterfacevariable{mirrored}{منعکس}
\setinterfacevariable{monday}{دوشنبه}
\setinterfacevariable{mono}{مونو}
+\setinterfacevariable{monobold}{monobold}
\setinterfacevariable{month}{ماه}
\setinterfacevariable{more}{more}
\setinterfacevariable{morehyphenation}{شکستکلماتبیشتر}
@@ -360,6 +362,7 @@
\setinterfacevariable{positive}{مثبت}
\setinterfacevariable{postponing}{تاخیر}
\setinterfacevariable{postscript}{پستاسکریپت}
+\setinterfacevariable{precedingpage}{followingpage}
\setinterfacevariable{preference}{ترجیح}
\setinterfacevariable{preview}{پیشدید}
\setinterfacevariable{previous}{قبلی}
@@ -419,7 +422,7 @@
\setinterfacevariable{september}{سپتامبر}
\setinterfacevariable{serif}{سریف}
\setinterfacevariable{serried}{تنگهم}
-\setinterfacevariable{setups}{بارگذاریها}
+\setinterfacevariable{setups}{setups}
\setinterfacevariable{sheet}{ورقه}
\setinterfacevariable{short}{short}
\setinterfacevariable{simplefonts}{simplefonts}
@@ -651,7 +654,7 @@
\setinterfaceconstant{coupling}{تزویج}
\setinterfaceconstant{couplingway}{روشتزویج}
\setinterfaceconstant{criterium}{criterium}
-\setinterfaceconstant{css}{css}
+\setinterfaceconstant{cssfile}{cssfile}
\setinterfaceconstant{current}{جاری}
\setinterfaceconstant{cutspace}{فضایبرش}
\setinterfaceconstant{dash}{دش}
@@ -686,7 +689,7 @@
\setinterfaceconstant{equalwidth}{عرضیکسان}
\setinterfaceconstant{escape}{فرار}
\setinterfaceconstant{evenmargin}{حاشیهزوج}
-\setinterfaceconstant{exitoffset}{labeloffset}
+\setinterfaceconstant{exitoffset}{exitoffset}
\setinterfaceconstant{expansion}{گسترش}
\setinterfaceconstant{export}{export}
\setinterfaceconstant{extras}{extras}
@@ -753,6 +756,7 @@
\setinterfaceconstant{indenting}{تورفتگی}
\setinterfaceconstant{indentnext}{متنتورفته}
\setinterfaceconstant{indicator}{اندیکاتور}
+\setinterfaceconstant{initialsep}{initialsep}
\setinterfaceconstant{inner}{داخلی}
\setinterfaceconstant{innermargin}{حاشیهداخلی}
\setinterfaceconstant{inputfile}{پروندهورودی}
@@ -858,6 +862,7 @@
\setinterfaceconstant{nright}{nright}
\setinterfaceconstant{ntop}{ntop}
\setinterfaceconstant{number}{شماره}
+\setinterfaceconstant{numberalign}{numberalign}
\setinterfaceconstant{numbercolor}{رنگشماره}
\setinterfaceconstant{numbercommand}{فرمانشماره}
\setinterfaceconstant{numberconversion}{numberconversion}
@@ -1002,7 +1007,7 @@
\setinterfaceconstant{separatorcolor}{separatorcolor}
\setinterfaceconstant{separatorstyle}{separatorstyle}
\setinterfaceconstant{set}{قراربده}
-\setinterfaceconstant{setups}{بارگذاریها}
+\setinterfaceconstant{setups}{setups}
\setinterfaceconstant{shrink}{shrink}
\setinterfaceconstant{side}{کنار}
\setinterfaceconstant{sidealign}{تنظیمکنار}
@@ -1281,6 +1286,7 @@
\setinterfacecommand{definetabletemplate}{تعریفالگویجدول}
\setinterfacecommand{definetabulate}{تعریفجدولبندی}
\setinterfacecommand{definetext}{تعریفمتن}
+\setinterfacecommand{definetextbackground}{definetextbackground}
\setinterfacecommand{definetextposition}{تعریفمکانمتن}
\setinterfacecommand{definetextvariable}{تعریفمتغیرمتن}
\setinterfacecommand{definetype}{تعریفتایپ}
@@ -1441,7 +1447,6 @@
\setinterfacecommand{paperheight}{ارتفاعبرگ}
\setinterfacecommand{paperwidth}{عرضبرگ}
\setinterfacecommand{periods}{نقطهها}
-\setinterfacecommand{plaatsruwelijst}{درجلیستخام}
\setinterfacecommand{placebookmarks}{درجچوبخط}
\setinterfacecommand{placecombinedlist}{درجلیستمختلط}
\setinterfacecommand{placefloat}{درجشناور}
@@ -1451,11 +1456,13 @@
\setinterfacecommand{placeheadtext}{درجمتنسر}
\setinterfacecommand{placelegend}{درجراهنما}
\setinterfacecommand{placelist}{درجلیست}
+\setinterfacecommand{placelistofsynonyms}{placelistofsynonyms}
\setinterfacecommand{placelocalfootnotes}{درجپانوشتهایموضعی}
\setinterfacecommand{placelogos}{درجآرمها}
\setinterfacecommand{placeongrid}{درجدرتوری}
\setinterfacecommand{placeontopofeachother}{درجدربالاییکدیگر}
\setinterfacecommand{placepagenumber}{درجشمارهصفحه}
+\setinterfacecommand{placerawlist}{درجلیستخام}
\setinterfacecommand{placereferencelist}{درجلیستمرجع}
\setinterfacecommand{placeregister}{درجثبت}
\setinterfacecommand{placerule}{درجخط}
@@ -1602,7 +1609,6 @@
\setinterfacecommand{setupregister}{بارگذاریثبت}
\setinterfacecommand{setuprotate}{بارگذاریدوران}
\setinterfacecommand{setuprule}{بارگذاریخط}
-\setinterfacecommand{setups}{بارگذاریها}
\setinterfacecommand{setupscreens}{بارگذاریپردهها}
\setinterfacecommand{setupsection}{بارگذاریبخش}
\setinterfacecommand{setupsectionblock}{بارگذاریبلوکبخش}
@@ -1620,6 +1626,7 @@
\setinterfacecommand{setuptables}{بارگذاریجدولها}
\setinterfacecommand{setuptabulate}{بارگذاریجدولبندی}
\setinterfacecommand{setuptext}{بارگذاریمتن}
+\setinterfacecommand{setuptextbackground}{setuptextbackground}
\setinterfacecommand{setuptextposition}{بارگذاریمکانمتن}
\setinterfacecommand{setuptextrules}{بارگذاریخطهایمتن}
\setinterfacecommand{setuptexttexts}{بارگذاریمتنمتنها}
@@ -1666,6 +1673,7 @@
\setinterfacecommand{startdocument}{شروعنوشتار}
\setinterfacecommand{startenvironment}{شروعمحیط}
\setinterfacecommand{startfigure}{شروعشکل}
+\setinterfacecommand{startframed}{startframed}
\setinterfacecommand{startglobal}{شروعسراسری}
\setinterfacecommand{startline}{شروعخط}
\setinterfacecommand{startlinecorrection}{شروعتصحیحخط}
@@ -1692,6 +1700,7 @@
\setinterfacecommand{starttable}{شروعجدول}
\setinterfacecommand{starttables}{شروعجدولها}
\setinterfacecommand{starttext}{شروعمتن}
+\setinterfacecommand{starttextbackground}{starttextbackground}
\setinterfacecommand{starttextrule}{شروعخطمتن}
\setinterfacecommand{startunpacked}{شروعغیرفشرده}
\setinterfacecommand{startversion}{شروعنسخه}
@@ -1706,6 +1715,7 @@
\setinterfacecommand{stopcomponent}{پایانمولفه}
\setinterfacecommand{stopdocument}{پایاننوشتار}
\setinterfacecommand{stopenvironment}{پایانمحیط}
+\setinterfacecommand{stopframed}{stopframed}
\setinterfacecommand{stopglobal}{پایانسراسری}
\setinterfacecommand{stopline}{پایانخط}
\setinterfacecommand{stoplinecorrection}{پایانتصحیحخط}
@@ -1731,6 +1741,7 @@
\setinterfacecommand{stoptable}{پایانجدول}
\setinterfacecommand{stoptables}{پایانجدولها}
\setinterfacecommand{stoptext}{پایانمتن}
+\setinterfacecommand{stoptextbackground}{stoptextbackground}
\setinterfacecommand{stoptextrule}{پایانخطمتن}
\setinterfacecommand{stopunpacked}{پایانغیرفشرده}
\setinterfacecommand{stopversion}{پایاننسخه}
diff --git a/Master/texmf-dist/tex/context/base/mult-prm.lua b/Master/texmf-dist/tex/context/base/mult-prm.lua
index f0b850a5c26..3b4d8435668 100644
--- a/Master/texmf-dist/tex/context/base/mult-prm.lua
+++ b/Master/texmf-dist/tex/context/base/mult-prm.lua
@@ -232,7 +232,7 @@ return {
"latelua",
"luaescapestring",
"luastartup",
- "luatexdatestamp",
+ "luatexbanner",
"luatexrevision",
"luatexversion",
"luafunction",
@@ -253,6 +253,7 @@ return {
"suppressifcsnameerror",
"suppresslongerror",
"suppressoutererror",
+ "suppressmathparerror",
"synctex",
},
["omega"]={
@@ -773,7 +774,7 @@ return {
"lpcode",
"luaescapestring",
"luastartup",
- "luatexdatestamp",
+ "luatexbanner",
"luatexrevision",
"luatexversion",
"mag",
diff --git a/Master/texmf-dist/tex/context/base/mult-ro.mkii b/Master/texmf-dist/tex/context/base/mult-ro.mkii
index d01822944da..a5d90033f03 100644
--- a/Master/texmf-dist/tex/context/base/mult-ro.mkii
+++ b/Master/texmf-dist/tex/context/base/mult-ro.mkii
@@ -180,6 +180,7 @@
\setinterfacevariable{flushleft}{flushleft}
\setinterfacevariable{flushouter}{flushouter}
\setinterfacevariable{flushright}{flushright}
+\setinterfacevariable{followingpage}{followingpage}
\setinterfacevariable{footer}{subsol}
\setinterfacevariable{footnote}{notasubsol}
\setinterfacevariable{force}{fortat}
@@ -301,6 +302,7 @@
\setinterfacevariable{mirrored}{oglindit}
\setinterfacevariable{monday}{luni}
\setinterfacevariable{mono}{mono}
+\setinterfacevariable{monobold}{monoaldin}
\setinterfacevariable{month}{luna}
\setinterfacevariable{more}{more}
\setinterfacevariable{morehyphenation}{morehyphenation}
@@ -360,6 +362,7 @@
\setinterfacevariable{positive}{positiv}
\setinterfacevariable{postponing}{postponing}
\setinterfacevariable{postscript}{postscript}
+\setinterfacevariable{precedingpage}{followingpage}
\setinterfacevariable{preference}{preferinta}
\setinterfacevariable{preview}{previzualizare}
\setinterfacevariable{previous}{precedent}
@@ -419,7 +422,7 @@
\setinterfacevariable{september}{septembrie}
\setinterfacevariable{serif}{serif}
\setinterfacevariable{serried}{serried}
-\setinterfacevariable{setups}{setari}
+\setinterfacevariable{setups}{setups}
\setinterfacevariable{sheet}{sheet}
\setinterfacevariable{short}{short}
\setinterfacevariable{simplefonts}{simplefonts}
@@ -651,7 +654,7 @@
\setinterfaceconstant{coupling}{cuplare}
\setinterfaceconstant{couplingway}{modcuplare}
\setinterfaceconstant{criterium}{criteriu}
-\setinterfaceconstant{css}{css}
+\setinterfaceconstant{cssfile}{cssfile}
\setinterfaceconstant{current}{curent}
\setinterfaceconstant{cutspace}{cutspace}
\setinterfaceconstant{dash}{dash}
@@ -686,7 +689,7 @@
\setinterfaceconstant{equalwidth}{equalwidth}
\setinterfaceconstant{escape}{escape}
\setinterfaceconstant{evenmargin}{marginepara}
-\setinterfaceconstant{exitoffset}{labeloffset}
+\setinterfaceconstant{exitoffset}{exitoffset}
\setinterfaceconstant{expansion}{expansiune}
\setinterfaceconstant{export}{export}
\setinterfaceconstant{extras}{extras}
@@ -753,6 +756,7 @@
\setinterfaceconstant{indenting}{aliniat}
\setinterfaceconstant{indentnext}{aliniaturmator}
\setinterfaceconstant{indicator}{indicator}
+\setinterfaceconstant{initialsep}{initialsep}
\setinterfaceconstant{inner}{intern}
\setinterfaceconstant{innermargin}{innermargin}
\setinterfaceconstant{inputfile}{inputfile}
@@ -858,6 +862,7 @@
\setinterfaceconstant{nright}{ndreapta}
\setinterfaceconstant{ntop}{nsus}
\setinterfaceconstant{number}{numar}
+\setinterfaceconstant{numberalign}{numberalign}
\setinterfaceconstant{numbercolor}{culoarenumar}
\setinterfaceconstant{numbercommand}{comandanumar}
\setinterfaceconstant{numberconversion}{numberconversion}
@@ -1281,6 +1286,7 @@
\setinterfacecommand{definetabletemplate}{definestesablontabel}
\setinterfacecommand{definetabulate}{definestetabulatori}
\setinterfacecommand{definetext}{definestetext}
+\setinterfacecommand{definetextbackground}{definetextbackground}
\setinterfacecommand{definetextposition}{definestepozitietext}
\setinterfacecommand{definetextvariable}{definestevariabilatext}
\setinterfacecommand{definetype}{definetype}
@@ -1441,7 +1447,6 @@
\setinterfacecommand{paperheight}{inaltimehartie}
\setinterfacecommand{paperwidth}{latimehartie}
\setinterfacecommand{periods}{puncte}
-\setinterfacecommand{plaatsruwelijst}{placerawlist}
\setinterfacecommand{placebookmarks}{plaseazasemnecarte}
\setinterfacecommand{placecombinedlist}{punelistacombinata}
\setinterfacecommand{placefloat}{placefloat}
@@ -1451,11 +1456,13 @@
\setinterfacecommand{placeheadtext}{placeheadtext}
\setinterfacecommand{placelegend}{punelegenda}
\setinterfacecommand{placelist}{punelista}
+\setinterfacecommand{placelistofsynonyms}{placelistofsynonyms}
\setinterfacecommand{placelocalfootnotes}{punenotesubsollocale}
\setinterfacecommand{placelogos}{punelogouri}
\setinterfacecommand{placeongrid}{plaseazapegrid}
\setinterfacecommand{placeontopofeachother}{punedeasuprafiecareia}
\setinterfacecommand{placepagenumber}{punenumarpagina}
+\setinterfacecommand{placerawlist}{placerawlist}
\setinterfacecommand{placereferencelist}{placereferencelist}
\setinterfacecommand{placeregister}{puneregistru}
\setinterfacecommand{placerule}{punerigla}
@@ -1602,7 +1609,6 @@
\setinterfacecommand{setupregister}{seteazaregistru}
\setinterfacecommand{setuprotate}{seteazarotare}
\setinterfacecommand{setuprule}{seteazarigla}
-\setinterfacecommand{setups}{setari}
\setinterfacecommand{setupscreens}{seteazaecrane}
\setinterfacecommand{setupsection}{seteazasectiune}
\setinterfacecommand{setupsectionblock}{seteazablocsectiune}
@@ -1620,6 +1626,7 @@
\setinterfacecommand{setuptables}{seteazatabele}
\setinterfacecommand{setuptabulate}{seteazatabulatori}
\setinterfacecommand{setuptext}{seteazatext}
+\setinterfacecommand{setuptextbackground}{setuptextbackground}
\setinterfacecommand{setuptextposition}{seteazapozitietext}
\setinterfacecommand{setuptextrules}{seteazarigletext}
\setinterfacecommand{setuptexttexts}{seteazatextetext}
@@ -1666,6 +1673,7 @@
\setinterfacecommand{startdocument}{startdocument}
\setinterfacecommand{startenvironment}{startmediu}
\setinterfacecommand{startfigure}{startfigura}
+\setinterfacecommand{startframed}{startframed}
\setinterfacecommand{startglobal}{startglobal}
\setinterfacecommand{startline}{startlinie}
\setinterfacecommand{startlinecorrection}{startcorectielinie}
@@ -1692,6 +1700,7 @@
\setinterfacecommand{starttable}{starttabel}
\setinterfacecommand{starttables}{starttabele}
\setinterfacecommand{starttext}{starttext}
+\setinterfacecommand{starttextbackground}{starttextbackground}
\setinterfacecommand{starttextrule}{startriglatext}
\setinterfacecommand{startunpacked}{startneimpachetat}
\setinterfacecommand{startversion}{startversiune}
@@ -1706,6 +1715,7 @@
\setinterfacecommand{stopcomponent}{stopcomponenta}
\setinterfacecommand{stopdocument}{stopdocument}
\setinterfacecommand{stopenvironment}{stopmediu}
+\setinterfacecommand{stopframed}{stopframed}
\setinterfacecommand{stopglobal}{stopblobal}
\setinterfacecommand{stopline}{stoplinie}
\setinterfacecommand{stoplinecorrection}{stopcorectielinie}
@@ -1731,6 +1741,7 @@
\setinterfacecommand{stoptable}{stoptabel}
\setinterfacecommand{stoptables}{stoptabele}
\setinterfacecommand{stoptext}{stoptext}
+\setinterfacecommand{stoptextbackground}{stoptextbackground}
\setinterfacecommand{stoptextrule}{stopriglatext}
\setinterfacecommand{stopunpacked}{stopneimpachetat}
\setinterfacecommand{stopversion}{stopversiune}
diff --git a/Master/texmf-dist/tex/context/base/mult-sys.mkiv b/Master/texmf-dist/tex/context/base/mult-sys.mkiv
index 8c1bff2bc40..63a89492a7f 100644
--- a/Master/texmf-dist/tex/context/base/mult-sys.mkiv
+++ b/Master/texmf-dist/tex/context/base/mult-sys.mkiv
@@ -124,7 +124,7 @@
\definesystemconstant {SansSlanted}
\definesystemconstant {SansBoldSlanted}
\definesystemconstant {SansCaps}
-% \definesystemconstant {SansCapsSlanted}
+%definesystemconstant {SansCapsSlanted}
\definesystemconstant {Mono}
\definesystemconstant {MonoBold}
@@ -133,8 +133,8 @@
\definesystemconstant {MonoSlanted}
\definesystemconstant {MonoBoldSlanted}
\definesystemconstant {MonoCaps}
-% \definesystemconstant {MonoCapsSlanted}
-% \definesystemconstant {MonoVariable}
+%definesystemconstant {MonoCapsSlanted}
+%definesystemconstant {MonoVariable}
\definesystemconstant {DefaultFont}
@@ -261,6 +261,19 @@
\definesystemconstant {single}
\definesystemconstant {multi}
\definesystemconstant {indeed}
+\definesystemconstant {internal}
+\definesystemconstant {current}
+\definesystemconstant {chain}
+
+% translating setups is asking for a mess so we keep them as-is:
+
+\definesystemconstant {setups}
+
+\definesystemconstant {cite}
+\definesystemconstant {nocite}
+\definesystemconstant {list}
+\definesystemconstant {register}
+\definesystemconstant {author}
% \def\s!parent{->} % 1% faster / => does not work in assignments
% \def\s!child {<-} % 1% faster / <= does not work in assignments
@@ -279,12 +292,16 @@
\definesystemconstant {bold}
\definesystemconstant {italic}
\definesystemconstant {slanted}
-
-\definesystemconstant {default}
\definesystemconstant {smallcaps}
+\definesystemconstant {lcgreek}
+\definesystemconstant {ucgreek}
+\definesystemconstant {sygreek}
+\definesystemconstant {italics}
\definesystemconstant {run}
+\definesystemconstant {default}
+
\definesystemconstant {mode}
\definesystemconstant {setup}
\definesystemconstant {environment}
@@ -298,11 +315,22 @@
\definesystemconstant {uncramped}
\definesystemconstant {cramped}
+\definesystemconstant {hyphenmin}
\definesystemconstant {lefthyphenmin}
\definesystemconstant {righthyphenmin}
\definesystemconstant {lefthyphenchar}
\definesystemconstant {righthyphenchar}
+\definesystemconstant {head}
+\definesystemconstant {symbol}
+\definesystemconstant {sub}
+\definesystemconstant {margin}
+\definesystemconstant {edge}
+
+\definesystemconstant {double}
+\definesystemconstant {decimal}
+\definesystemconstant {binary}
+
%definesystemconstant {skewchar}
%definesystemconstant {hyphenchar}
\definesystemconstant {catcodes}
@@ -322,6 +350,12 @@
\definesystemconstant {designsize}
%definesystemconstant {background}
%definesystemconstant {ucmap}
+\definesystemconstant {level}
+\definesystemconstant {integral}
+\definesystemconstant {insert} % maybe insertclass
+\definesystemconstant {marker}
+
+\definesystemconstant {mixedcolumn}
%definesystemconstant {property}
%definesystemconstant {overprint}
@@ -382,8 +416,13 @@
\definesystemconstant {size}
\definesystemconstant {depth}
+\definesystemconstant {height}
+\definesystemconstant {noheight}
\definesystemconstant {nodepth}
+\definesystemconstant {rel}
+\definesystemconstant {ord}
+
%D Just to be complete we define the standard \TEX\ units.
\definesystemconstant {cm}
@@ -538,6 +577,13 @@
\defineinterfacevariable {c} {c}
\defineinterfacevariable {d} {d}
+%D For tagging:
+
+\definesystemconstant {subtype}
+\definesystemconstant {top}
+\definesystemconstant {bottom}
+\definesystemconstant {both}
+
%D Special purpose variables:
\def\v!oddeven#1{\ifodd#1\v!odd\else\v!even\fi}
diff --git a/Master/texmf-dist/tex/context/base/node-aux.lua b/Master/texmf-dist/tex/context/base/node-aux.lua
index 49911625822..12da8ea8ab3 100644
--- a/Master/texmf-dist/tex/context/base/node-aux.lua
+++ b/Master/texmf-dist/tex/context/base/node-aux.lua
@@ -314,13 +314,17 @@ nuts .firstcharinbox = firstcharinbox
nodes.firstcharinbox = firstcharinbox
nodes.firstcharacter = vianuts(firstcharacter)
-function commands.buildtextaccent(n)
- local char = firstcharinbox(n)
- if char > 0 then
- -- context.accent(false,char)
- context([[\accent%s\relax]],char)
+interfaces.implement {
+ name = "buildtextaccent",
+ arguments = "integer",
+ actions = function(n) -- Is this crap really used? Or was it an experiment?
+ local char = firstcharinbox(n)
+ if char > 0 then
+ -- context.accent(false,char)
+ context([[\accent%s\relax]],char)
+ end
end
-end
+}
-- this depends on fonts, so we have a funny dependency ... will be
-- sorted out .. we could make tonodes a plugin into this
@@ -352,7 +356,8 @@ local function tonodes(str,fnt,attr) -- (str,template_glyph) -- moved from blob-
n = new_glyph(fnt,s)
end
if attr then -- normally false when template
- setfield(n,"attr",copy_node_list(attr))
+ -- setfield(n,"attr",copy_node_list(attr))
+ setfield(n,"attr",attr)
end
if head then
insert_node_after(head,tail,n)
diff --git a/Master/texmf-dist/tex/context/base/node-bck.lua b/Master/texmf-dist/tex/context/base/node-bck.lua
index 4b7b4a0643d..99992de0903 100644
--- a/Master/texmf-dist/tex/context/base/node-bck.lua
+++ b/Master/texmf-dist/tex/context/base/node-bck.lua
@@ -178,5 +178,19 @@ nodes.handlers.alignbackgrounds = function(head) local head, done = add_alignbac
-- elsewhere: needs checking
-tasks.appendaction("shipouts","normalizers","nodes.handlers.backgrounds")
-tasks.appendaction("shipouts","normalizers","nodes.handlers.alignbackgrounds")
+-- tasks.appendaction("shipouts","normalizers","nodes.handlers.backgrounds")
+-- tasks.appendaction("shipouts","normalizers","nodes.handlers.alignbackgrounds")
+
+interfaces.implement {
+ name = "enablebackgroundboxes",
+ onlyonce = true,
+ actions = nodes.tasks.enableaction,
+ arguments = { "'shipouts'", "'nodes.handlers.backgrounds'" }
+}
+
+interfaces.implement {
+ name = "enablebackgroundalign",
+ onlyonce = true,
+ actions = nodes.tasks.enableaction,
+ arguments = { "'shipouts'", "'nodes.handlers.alignbackgrounds'" }
+}
diff --git a/Master/texmf-dist/tex/context/base/node-bck.mkiv b/Master/texmf-dist/tex/context/base/node-bck.mkiv
index 25739c56042..ff0de6a5d0c 100644
--- a/Master/texmf-dist/tex/context/base/node-bck.mkiv
+++ b/Master/texmf-dist/tex/context/base/node-bck.mkiv
@@ -21,14 +21,6 @@
\registerctxluafile{node-bck}{1.001}
-\def\node_backgrounds_boxes_initialize % will move to lua
- {\ctxlua{nodes.tasks.enableaction("shipouts","nodes.handlers.backgrounds")}%
- \glet\node_backgrounds_boxes_initialize\donothing}
-
-\def\node_backgrounds_align_initialize % will move to lua
- {\ctxlua{nodes.tasks.enableaction("shipouts","nodes.handlers.alignbackgrounds")}%
- \glet\node_backgrounds_align_initialize\donothing}
-
% \backgroundvbox[green] {\input tufte } \par
% \backgroundvbox[blue] {\input ward } \par
% \backgroundvbox[red] {\input knuth } \par
@@ -71,7 +63,7 @@
% \def\node_backgrounds_boxes_add#1[#2]%
% {\begingroup
-% \node_backgrounds_boxes_initialize
+% \clf_enablebackgroundboxes
% \dousecolorparameter{#2}%
% \normalexpanded{\endgroup#1
% attr \backgroundattribute \plusone
@@ -82,13 +74,13 @@
% more efficient:
\def\node_backgrounds_boxes_add#1[#2]%
- {\node_backgrounds_boxes_initialize
+ {\clf_enablebackgroundboxes
#1\backgroundcolorattr{#2}}
% less argument carry over:
%
% \def\node_backgrounds_boxes_add#1[#2]%
-% {\node_backgrounds_boxes_initialize#1%
+% {\clf_enablebackgroundboxes#1%
% \ifcsname\??colorattribute\currentcolorprefix#2\endcsname
% \thebackgroundcolorattr{\currentcolorprefix#2}%
% \else\ifcsname\??colorattribute#2\endcsname
diff --git a/Master/texmf-dist/tex/context/base/node-fin.lua b/Master/texmf-dist/tex/context/base/node-fin.lua
index 250035f3958..84c5b9a2f93 100644
--- a/Master/texmf-dist/tex/context/base/node-fin.lua
+++ b/Master/texmf-dist/tex/context/base/node-fin.lua
@@ -9,7 +9,7 @@ if not modules then modules = { } end modules ['node-fin'] = {
-- this module is being reconstructed
-- local functions, only slightly slower
--
--- leaders are also triggers
+-- leaders are also triggers ... see colo-ext for an example (negate a box)
local next, type, format = next, type, string.format
@@ -27,7 +27,6 @@ local getid = nuts.getid
local getlist = nuts.getlist
local getleader = nuts.getleader
local getattr = nuts.getattr
-local setattr = nuts.setattr
local copy_node = nuts.copy
local insert_node_before = nuts.insert_before
@@ -51,6 +50,8 @@ local numbers = attributes.numbers
local a_trigger = attributes.private('trigger')
local triggering = false
+local implement = interfaces.implement
+
local starttiming = statistics.starttiming
local stoptiming = statistics.stoptiming
local loadstripped = utilities.lua.loadstripped
@@ -61,6 +62,9 @@ local unsetvalue = attributes.unsetvalue
function states.enabletriggering () triggering = true end
function states.disabletriggering() triggering = false end
+implement { name = "enablestatetriggering", actions = states.enabletriggering }
+implement { name = "disablestatetriggering", actions = states.disabletriggering }
+
nodes.plugindata = nil
-- inheritance: -0x7FFFFFFF -- we can best use nil and skip !
@@ -129,7 +133,7 @@ end
local nsdata, nsnone, nslistwise, nsforced, nsselector, nstrigger
local current, current_selector, done = 0, 0, false -- nb, stack has a local current !
-local nsbegin, nsend
+local nsbegin, nsend, nsreset
function states.initialize(namespace,attribute,head)
nsdata = namespace.data
@@ -143,6 +147,7 @@ function states.initialize(namespace,attribute,head)
done = false -- todo: done cleanup
nsstep = namespace.resolve_step
if nsstep then
+ nsreset = namespace.resolve_reset
nsbegin = namespace.resolve_begin
nsend = namespace.resolve_end
nspush = namespace.push
@@ -168,7 +173,6 @@ function states.finalize(namespace,attribute,head) -- is this one ok?
return head, false, false
end
--- disc nodes can be ignored
-- we need to deal with literals too (reset as well as oval)
-- if id == glyph_code or (id == whatsit_code and getsubtype(stack) == pdfliteral_code) or (id == rule_code and stack.width ~= 0) or (id == glue_code and stack.leader) then
@@ -181,6 +185,8 @@ local function process(namespace,attribute,head,inheritance,default) -- one attr
local id = getid(stack)
if id == glyph_code then
check = true
+ -- elseif id == disc_code then
+ -- check = true -- no longer needed as we flatten replace
elseif id == glue_code then
leader = getleader(stack)
if leader then
@@ -294,6 +300,8 @@ local function selective(namespace,attribute,head,inheritance,default) -- two at
local id = getid(stack)
if id == glyph_code then
check = true
+ -- elseif id == disc_code then
+ -- check = true -- no longer needed as we flatten replace
elseif id == glue_code then
leader = getleader(stack)
if leader then
@@ -364,7 +372,7 @@ local function selective(namespace,attribute,head,inheritance,default) -- two at
done = done or ok
end
-- end nested
- leader = false
+ leader = false
end
elseif default and inheritance then
if current ~= default then
@@ -484,14 +492,17 @@ end
-- experimental
local function stacker(namespace,attribute,head,default) -- no triggering, no inheritance, but list-wise
- nsbegin()
+
+-- nsbegin()
+ local stacked = false
+
local current = head
local previous = head
local done = false
- local okay = false
local attrib = default or unsetvalue
local check = false
local leader = false
+
while current do
local id = getid(current)
if id == glyph_code then
@@ -530,13 +541,15 @@ local function stacker(namespace,attribute,head,default) -- no triggering, no in
if check then
local a = getattr(current,attribute) or unsetvalue
if a ~= attrib then
+ if not stacked then
+ stacked = true
+ nsbegin()
+ end
local n = nsstep(a)
if n then
- -- !!!! TEST CODE !!!!
- -- head = insert_node_before(head,current,copied(nsdata[tonumber(n)])) -- a
head = insert_node_before(head,current,tonut(n)) -- a
end
- attrib, done, okay = a, true, true
+ attrib, done = a, true
if leader then
-- tricky as a leader has to be a list so we cannot inject before
local list, ok = stacker(namespace,attribute,leader,attrib)
@@ -550,19 +563,23 @@ local function stacker(namespace,attribute,head,default) -- no triggering, no in
previous = current
current = getnext(current)
end
- if okay then
- local n = nsend()
- if n then
- -- !!!! TEST CODE !!!!
- -- head = insert_node_after(head,previous,copied(nsdata[tostring(n)]))
- head = insert_node_after(head,previous,tonut(n))
- end
+
+if stacked then
+
+ local n = nsend()
+ while n do
+ head = insert_node_after(head,previous,tonut(n))
+ n = nsend()
end
+
+end
+
return head, done
end
states.stacker = function(namespace,attribute,head,default)
local head, done = stacker(namespace,attribute,tonut(head),default)
+ nsreset()
return tonode(head), done
end
diff --git a/Master/texmf-dist/tex/context/base/node-fin.mkiv b/Master/texmf-dist/tex/context/base/node-fin.mkiv
index 2eb033fc16a..7c95699dd12 100644
--- a/Master/texmf-dist/tex/context/base/node-fin.mkiv
+++ b/Master/texmf-dist/tex/context/base/node-fin.mkiv
@@ -23,12 +23,12 @@
% we might have two variants at some point (efficiency)
-\unexpanded\def\finalizeobjectbox #1{\ctxcommand{finalizebox(\number#1)}}
-\unexpanded\def\finalizeshipoutbox#1{\ctxcommand{finalizebox(\number#1)}}
+\unexpanded\def\finalizeobjectbox #1{\clf_finalizebox#1\relax}
+\unexpanded\def\finalizeshipoutbox#1{\clf_finalizebox#1\relax}
% Experimental (for Aditya):
-\unexpanded\def\cleanupbox#1{\ctxcommand{cleanupbox(\number#1)}}
+\unexpanded\def\cleanupbox#1{\clf_cleanupbox#1\relax}
% Tricky stuff: this might become obsolete.
@@ -61,12 +61,12 @@
\stopinheritattributes}
\def\enableattributeinheritance
- {\ctxlua{attributes.states.enabletriggering()}%
+ {\clf_enablestatetriggering
\let\attributedcopy\doattributedcopy
\let\attributedbox \doattributedbox}
\def\disableattributeinheritance
- {\ctxlua{attributes.states.disabletriggering()}%
+ {\clf_disablestatetriggering
\let\attributedcopy\copy
\let\attributedbox \box}
diff --git a/Master/texmf-dist/tex/context/base/node-fnt.lua b/Master/texmf-dist/tex/context/base/node-fnt.lua
index 7000c4fd7ac..774a687186a 100644
--- a/Master/texmf-dist/tex/context/base/node-fnt.lua
+++ b/Master/texmf-dist/tex/context/base/node-fnt.lua
@@ -13,8 +13,11 @@ local concat, keys = table.concat, table.keys
local nodes, node, fonts = nodes, node, fonts
-local trace_characters = false trackers.register("nodes.characters", function(v) trace_characters = v end)
-local trace_fontrun = false trackers.register("nodes.fontrun", function(v) trace_fontrun = v end)
+local trace_characters = false trackers .register("nodes.characters", function(v) trace_characters = v end)
+local trace_fontrun = false trackers .register("nodes.fontrun", function(v) trace_fontrun = v end)
+
+local force_discrun = true directives.register("nodes.discrun", function(v) force_discrun = v end)
+local force_basepass = true directives.register("nodes.basepass", function(v) force_basepass = v end)
local report_fonts = logs.reporter("fonts","processing")
@@ -31,6 +34,7 @@ local handlers = nodes.handlers
local nuts = nodes.nuts
local tonut = nuts.tonut
+local tonode = nuts.tonode
local getattr = nuts.getattr
local getid = nuts.getid
@@ -38,6 +42,8 @@ local getfont = nuts.getfont
local getsubtype = nuts.getsubtype
local getchar = nuts.getchar
local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getfield = nuts.getfield
local traverse_id = nuts.traverse_id
@@ -111,11 +117,25 @@ fonts.hashes.processes = fontprocesses
-- inside a run which means that we need to keep track of this which in turn complicates matters
-- in a way i don't like
+-- we need to deal with the basemode fonts here and can only run over ranges as we
+-- otherwise get luatex craches due to all kind of asserts in the disc/lig builder
+
+local ligaturing = node.ligaturing
+local kerning = node.kerning
+
function handlers.characters(head)
-- either next or not, but definitely no already processed list
starttiming(nodes)
- local usedfonts, attrfonts = { }, { }
- local a, u, prevfont, prevattr, done = 0, 0, nil, 0, false
+
+ local usedfonts = { }
+ local attrfonts = { }
+ local basefonts = { }
+ local a, u, b = 0, 0, 0
+ local basefont = nil
+ local prevfont = nil
+ local prevattr = 0
+ local done = false
+
if trace_fontrun then
run = run + 1
report_fonts()
@@ -136,43 +156,114 @@ function handlers.characters(head)
n = getnext(n)
end
end
- for n in traverse_id(glyph_code,tonut(head)) do
- -- if getsubtype(n) <256 then -- all are 1
- local font = getfont(n)
- local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context
- if font ~= prevfont or attr ~= prevattr then
- if attr > 0 then
- local used = attrfonts[font]
- if not used then
- used = { }
- attrfonts[font] = used
+
+ local nuthead = tonut(head)
+
+ for n in traverse_id(glyph_code,nuthead) do
+ if getsubtype(n) < 256 then -- all are 1
+ local font = getfont(n)
+ local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context
+ if font ~= prevfont or attr ~= prevattr then
+ if basefont then
+ basefont[2] = tonode(getprev(n)) -- todo, save p
end
- if not used[attr] then
- local fd = setfontdynamics[font]
- if fd then
- used[attr] = fd[attr]
- a = a + 1
+ if attr > 0 then
+ local used = attrfonts[font]
+ if not used then
+ used = { }
+ attrfonts[font] = used
+ end
+ if not used[attr] then
+ local fd = setfontdynamics[font]
+ if fd then
+ used[attr] = fd[attr]
+ a = a + 1
+ elseif force_basepass then
+ b = b + 1
+ basefont = { tonode(n), nil }
+ basefonts[b] = basefont
+ end
+ end
+ else
+ local used = usedfonts[font]
+ if not used then
+ local fp = fontprocesses[font]
+ if fp then
+ usedfonts[font] = fp
+ u = u + 1
+ elseif force_basepass then
+ b = b + 1
+ basefont = { tonode(n), nil }
+ basefonts[b] = basefont
+ end
end
end
- else
- local used = usedfonts[font]
- if not used then
- local fp = fontprocesses[font]
- if fp then
- usedfonts[font] = fp
- u = u + 1
- end
+ prevfont = font
+ prevattr = attr
+ end
+ end
+ end
+
+ -- could be an optional pass : seldom needed, only for documentation as a discretionary
+ -- with pre/post/replace will normally not occur on it's own
+
+ if force_discrun then
+
+ -- basefont is not supported in disc only runs ... it would mean a lot of
+ -- ranges .. we could try to run basemode as a separate processor run but
+ -- not for now (we can consider it when the new node code is tested
+
+ -- local prevfont = nil
+ -- local prevattr = 0
+
+ for d in traverse_id(disc_code,nuthead) do
+ -- we could use first_glyph
+ local r = getfield(n,"replace") -- good enough
+ if r then
+ for n in traverse_id(glyph_code,r) do
+ if getsubtype(n) < 256 then -- all are 1
+ local font = getfont(n)
+ local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context
+ if font ~= prevfont or attr ~= prevattr then
+ if attr > 0 then
+ local used = attrfonts[font]
+ if not used then
+ used = { }
+ attrfonts[font] = used
+ end
+ if not used[attr] then
+ local fd = setfontdynamics[font]
+ if fd then
+ used[attr] = fd[attr]
+ a = a + 1
+ end
+ end
+ else
+ local used = usedfonts[font]
+ if not used then
+ local fp = fontprocesses[font]
+ if fp then
+ usedfonts[font] = fp
+ u = u + 1
+ end
+ end
+ end
+ prevfont = font
+ prevattr = attr
+ end
+ end
+ break
end
end
- prevfont = font
- prevattr = attr
end
- -- end
+
end
+
if trace_fontrun then
report_fonts()
- report_fonts("statics : %s",(u > 0 and concat(keys(usedfonts)," ")) or "none")
- report_fonts("dynamics: %s",(a > 0 and concat(keys(attrfonts)," ")) or "none")
+ report_fonts("statics : %s",u > 0 and concat(keys(usedfonts)," ") or "none")
+ report_fonts("dynamics: %s",a > 0 and concat(keys(attrfonts)," ") or "none")
+ report_fonts("built-in: %s",b > 0 and b or "none")
report_fonts()
end
-- in context we always have at least 2 processors
@@ -224,6 +315,49 @@ function handlers.characters(head)
end
end
end
+ if b == 0 then
+ -- skip
+ elseif b == 1 then
+ -- only one font
+ local front = head == start
+ local range = basefonts[1]
+ local start = range[1]
+ local stop = range[2]
+ if stop then
+ start, stop = ligaturing(start,stop)
+ start, stop = kerning(start,stop)
+ elseif start then -- safeguard
+ start = ligaturing(start)
+ start = kerning(start)
+ else
+ -- something bad happened
+ end
+ if front then
+ -- shouldn't happen
+ head = start
+ end
+ else
+ -- multiple fonts
+ local front = head == start
+ for i=1,b do
+ local range = basefonts[i]
+ local start = range[1]
+ local stop = range[2]
+ if stop then
+ start, stop = ligaturing(start,stop)
+ start, stop = kerning(start,stop)
+ elseif start then -- safeguard
+ start = ligaturing(start)
+ start = kerning(start)
+ else
+ -- something bad happened
+ end
+ end
+ if front then
+ -- shouldn't happen
+ head = start
+ end
+ end
stoptiming(nodes)
if trace_characters then
nodes.report(head,done)
@@ -292,7 +426,9 @@ end
-- return false
-- end
-- end)
-
+--
+-- -- TODO: basepasses!
+--
-- function handlers.characters(head)
-- -- either next or not, but definitely no already processed list
-- starttiming(nodes)
@@ -408,3 +544,13 @@ local d_unprotect_glyphs = nuts.unprotect_glyphs
handlers.protectglyphs = function(n) return d_protect_glyphs (tonut(n)) end
handlers.unprotectglyphs = function(n) return d_unprotect_glyphs(tonut(n)) end
+
+-- function handlers.protectglyphs(h)
+-- local h = tonut(h)
+-- for n in traverse_id(disc_code,h) do
+-- local d = getfield(n,"pre") if d then d_protect_glyphs(d) end
+-- local d = getfield(n,"post") if d then d_protect_glyphs(d) end
+-- local d = getfield(n,"replace") if d then d_protect_glyphs(d) end
+-- end
+-- return d_protect_glyphs(h)
+-- end
diff --git a/Master/texmf-dist/tex/context/base/node-ini.lua b/Master/texmf-dist/tex/context/base/node-ini.lua
index a9ef305c03f..02d4c7a3fb8 100644
--- a/Master/texmf-dist/tex/context/base/node-ini.lua
+++ b/Master/texmf-dist/tex/context/base/node-ini.lua
@@ -154,9 +154,9 @@ local disccodes = allocate {
[0] = "discretionary", -- \discretionary
[1] = "explicit", -- \-
[2] = "automatic", -- following a -
- [3] = "regular", -- simple
- [4] = "first", -- hard first item
- [5] = "second", -- hard second item
+ [3] = "regular", -- by hyphenator: simple
+ [4] = "first", -- by hyphenator: hard first item
+ [5] = "second", -- by hyphenator: hard second item
}
local accentcodes = allocate {
@@ -206,7 +206,7 @@ nodes.whatcodes = whatcodes nodes.whatsitcodes = whatcodes -- more offici
nodes.listcodes = listcodes
nodes.glyphcodes = glyphcodes
nodes.kerncodes = kerncodes
-nodes.penaltycodes = kerncodes
+nodes.penaltycodes = penaltycodes
nodes.mathcodes = mathcodes
nodes.fillcodes = fillcodes
nodes.margincodes = margincodes
diff --git a/Master/texmf-dist/tex/context/base/node-ini.mkiv b/Master/texmf-dist/tex/context/base/node-ini.mkiv
index 5fc519069db..d04e647de42 100644
--- a/Master/texmf-dist/tex/context/base/node-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/node-ini.mkiv
@@ -35,7 +35,7 @@
\registerctxluafile{node-acc}{1.001} % experimental
%registerctxluafile{node-prp}{1.001} % makes no sense (yet)
-\doiffileelse{node-ppt.lua}{\registerctxluafile{node-ppt}{1.001}}{}
+\doifelsefile{node-ppt.lua}{\registerctxluafile{node-ppt}{1.001}}{}
\newcount\c_node_tracers_show_box % box number
diff --git a/Master/texmf-dist/tex/context/base/node-inj.lua b/Master/texmf-dist/tex/context/base/node-inj.lua
index b91646ffc1a..402403529c6 100644
--- a/Master/texmf-dist/tex/context/base/node-inj.lua
+++ b/Master/texmf-dist/tex/context/base/node-inj.lua
@@ -56,7 +56,7 @@ local insert_node_before = nuts.insert_before
local insert_node_after = nuts.insert_after
local a_kernpair = attributes.private('kernpair')
------ a_ligacomp = attributes.private('ligacomp')
+local a_ligacomp = attributes.private('ligacomp')
local a_markbase = attributes.private('markbase')
local a_markmark = attributes.private('markmark')
local a_markdone = attributes.private('markdone')
@@ -64,6 +64,8 @@ local a_cursbase = attributes.private('cursbase')
local a_curscurs = attributes.private('curscurs')
local a_cursdone = attributes.private('cursdone')
+local unsetvalue = attributes.unsetvalue
+
-- This injector has been tested by Idris Samawi Hamid (several arabic fonts as well as
-- the rather demanding Husayni font), Khaled Hosny (latin and arabic) and Kaj Eigner
-- (arabic, hebrew and thai) and myself (whatever font I come across). I'm pretty sure
@@ -84,6 +86,33 @@ local kerns = { }
-- For the moment we pass the r2l key ... volt/arabtype tests .. idris: this needs
-- checking with husayni (volt and fontforge).
+function injections.reset(n)
+-- if getattr(n,a_kernpair) then
+-- setattr(n,a_kernpair,unsetvalue)
+-- end
+-- if getattr(n,a_markdone) then
+-- setattr(n,a_markbase,unsetvalue)
+-- setattr(n,a_markmark,unsetvalue)
+-- setattr(n,a_markdone,unsetvalue)
+-- end
+-- if getattr(n,a_cursdone) then
+-- setattr(n,a_cursbase,unsetvalue)
+-- setattr(n,a_curscurs,unsetvalue)
+-- setattr(n,a_cursdone,unsetvalue)
+-- end
+-- if getattr(n,a_ligacomp) then
+-- setattr(n,a_ligacomp,unsetvalue)
+-- end
+end
+
+function injections.setligaindex(n,index)
+ setattr(n,a_ligacomp,index)
+end
+
+function injections.getligaindex(n,default)
+ return getattr(n,a_ligacomp) or default
+end
+
function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
local dx, dy = factor*(exit[1]-entry[1]), factor*(exit[2]-entry[2])
local ws, wn = tfmstart.width, tfmnext.width
@@ -343,7 +372,7 @@ function injections.handler(head,where,keep)
for i=maxt,1,-1 do
ny = ny + d[i]
local ti = t[i]
- setfield(ti,"yoffset",ny)
+ setfield(ti,"yoffset",ny) -- maybe add to current yoffset
end
maxt = 0
end
diff --git a/Master/texmf-dist/tex/context/base/node-ltp.lua b/Master/texmf-dist/tex/context/base/node-ltp.lua
index 6ad5de140b9..9529213fc37 100644
--- a/Master/texmf-dist/tex/context/base/node-ltp.lua
+++ b/Master/texmf-dist/tex/context/base/node-ltp.lua
@@ -406,13 +406,13 @@ end
-- resolvers --
-local whatsiters = {
+local whatsitters = {
get_width = { },
get_dimensions = { },
}
-local get_whatsit_width = whatsiters.get_width
-local get_whatsit_dimensions = whatsiters.get_dimensions
+local get_whatsit_width = whatsitters.get_width
+local get_whatsit_dimensions = whatsitters.get_dimensions
local function get_width (n,dir) return getfield(n,"width") end
local function get_dimensions(n,dir) return getfield(n,"width"), getfield(n,"height"), getfield(n,"depth") end
@@ -423,6 +423,8 @@ get_whatsit_width[pdfrefxform_code ] = get_width
get_whatsit_dimensions[pdfrefximage_code] = get_dimensions
get_whatsit_dimensions[pdfrefxform_code ] = get_dimensions
+nodes.whatsitters = whatsitters
+
-- expansion etc --
local function calculate_fraction(x,n,d,max_answer)
@@ -1243,6 +1245,7 @@ local function post_line_break(par)
setfield(prevlast,"post",nil)
end
elseif subtype == first_disc_code then
+ -- what is v ... next probably
if not (getid(v) == disc_code and getsubtype(v) == second_disc_code) then
report_parbuilders('unsupported disc at location %a',4)
end
@@ -2547,10 +2550,10 @@ function diagnostics.feasible_break(par, current, r, b, pi, d, artificial_demeri
par.font_in_short_display = short_display("log",getnext(printed_node),par.font_in_short_display)
else
local save_link = getnext(current)
- setfield(cur_p,"next",nil)
+ setfield(current,"next",nil)
write_nl("log","")
par.font_in_short_display = short_display("log",getnext(printed_node),par.font_in_short_display)
- setfield(cur_p,"next",save_link)
+ setfield(current,"next",save_link)
end
par.printed_node = current
end
@@ -3145,7 +3148,7 @@ local function hpack(head,width,method,direction,firstline,line) -- fast version
end
diagnostics.overfull_hbox(hlist,line,-delta)
end
- elseif order == 0 and hlist.list and last_badness > tex.hbadness then
+ elseif order == 0 and getlist(hlist) and last_badness > tex.hbadness then
diagnostics.bad_hbox(hlist,line,last_badness)
end
end
@@ -3154,6 +3157,8 @@ end
xpack_nodes = hpack -- comment this for old fashioned expansion (we need to fix float mess)
+constructors.methods.hpack = hpack
+
local function common_message(hlist,line,str)
write_nl("")
if status.output_active then -- unset
diff --git a/Master/texmf-dist/tex/context/base/node-nut.lua b/Master/texmf-dist/tex/context/base/node-nut.lua
index 2b4e9968c6e..32f2d57ec32 100644
--- a/Master/texmf-dist/tex/context/base/node-nut.lua
+++ b/Master/texmf-dist/tex/context/base/node-nut.lua
@@ -86,10 +86,14 @@ if not modules then modules = { } end modules ['node-met'] = {
-- luatex 3.9 sec / 54 pps
-- luajittex 2.3 sec / 93 pps
+local type, rawget = type, rawget
+
local nodes = nodes
local gonuts = nodes.gonuts
local direct = node.direct
+local fastcopy = table.fastcopy
+
if type(direct) ~= "table" then
return
elseif gonuts then
@@ -136,6 +140,20 @@ nuts.getsubtype = direct.getsubtype
nuts.getlist = direct.getlist -- only hlist and vlist !
nuts.getleader = direct.getleader
+-- local function track(name)
+-- local n = 0
+-- local f = nuts[name]
+-- function nuts[name](...)
+-- n = n + 1
+-- if n % 1000 == 0 then
+-- print(name,n)
+-- end
+-- return f(...)
+-- end
+-- end
+
+-- track("getsubtype")
+
-- local dgf = direct.getfield function nuts.getlist(n) return dgf(n,"list") end
-- setters
@@ -662,8 +680,14 @@ if propertydata then
data = propertydata,
}
- direct.set_properties_mode(true,false)
- -- direct.set_properties_mode(true,true)
+ -- direct.set_properties_mode(true,false) -- shallow copy ... problem: in fonts we then affect the originals too
+ direct.set_properties_mode(true,true) -- create metatable, slower but needed for font-inj.lua (unless we use an intermediate table)
+
+ -- todo:
+ --
+ -- function direct.set_properties_mode()
+ -- -- we really need the set modes
+ -- end
-- experimental code with respect to copying attributes has been removed
-- as it doesn't pay of (most attributes are only accessed once anyway)
@@ -700,3 +724,31 @@ else
nodes.getprop = setattr
end
+
+function nuts.copy_properties(source,target,what)
+ local newprops = propertydata[source]
+ if not newprops then
+ -- nothing to copy
+ return
+ end
+ if what then
+ -- copy one category
+ newprops = rawget(source,what)
+ if newprops then
+ newprops = fastcopy(newprops)
+ local p = rawget(propertydata,target)
+ if p then
+ p[what] = newprops
+ else
+ propertydata[target] = {
+ [what] = newprops,
+ }
+ end
+ end
+ else
+ -- copy all properties
+ newprops = fastcopy(newprops)
+ propertydata[target] = newprops
+ end
+ return newprops -- for checking
+end
diff --git a/Master/texmf-dist/tex/context/base/node-pro.lua b/Master/texmf-dist/tex/context/base/node-pro.lua
index 2cc00601c77..27e349893b6 100644
--- a/Master/texmf-dist/tex/context/base/node-pro.lua
+++ b/Master/texmf-dist/tex/context/base/node-pro.lua
@@ -55,7 +55,7 @@ do
return concat(t)
end
- local function tracer(what,state,head,groupcode,before,after,show)
+ function processors.tracer(what,state,head,groupcode,before,after,show)
if not groupcode then
groupcode = "unknown"
elseif groupcode == "" then
@@ -69,10 +69,10 @@ do
end
end
- processors.tracer = tracer
-
end
+local tracer = processors.tracer
+
processors.enabled = true -- this will become a proper state (like trackers)
function processors.pre_linebreak_filter(head,groupcode) -- ,size,packtype,direction
diff --git a/Master/texmf-dist/tex/context/base/node-ref.lua b/Master/texmf-dist/tex/context/base/node-ref.lua
index 78ef409bca5..9703cc184a9 100644
--- a/Master/texmf-dist/tex/context/base/node-ref.lua
+++ b/Master/texmf-dist/tex/context/base/node-ref.lua
@@ -16,6 +16,8 @@ if not modules then modules = { } end modules ['node-ref'] = {
-- is grouplevel still used?
+local concat = table.concat
+
local attributes, nodes, node = attributes, nodes, node
local allocate = utilities.storage.allocate, utilities.storage.mark
@@ -32,9 +34,11 @@ local colors = attributes.colors
local references = structures.references
local tasks = nodes.tasks
-local trace_backend = false trackers.register("nodes.backend", function(v) trace_backend = v end)
-local trace_references = false trackers.register("nodes.references", function(v) trace_references = v end)
-local trace_destinations = false trackers.register("nodes.destinations", function(v) trace_destinations = v end)
+local trace_references = false trackers.register("nodes.references", function(v) trace_references = v end)
+local trace_destinations = false trackers.register("nodes.destinations", function(v) trace_destinations = v end)
+local trace_areas = false trackers.register("nodes.areas", function(v) trace_areas = v end)
+local show_references = false trackers.register("nodes.references.show", function(v) show_references = tonumber(v) or (v and 2.25 or false) end)
+local show_destinations = false trackers.register("nodes.destinations.show", function(v) show_destinations = tonumber(v) or (v and 2.00 or false) end)
local report_reference = logs.reporter("backend","references")
local report_destination = logs.reporter("backend","destinations")
@@ -57,6 +61,7 @@ local setattr = nuts.setattr
local getsubtype = nuts.getsubtype
local hpack_list = nuts.hpack
+local vpack_list = nuts.vpack
local list_dimensions = nuts.dimensions
local traverse = nuts.traverse
local find_node_tail = nuts.tail
@@ -69,6 +74,8 @@ local listcodes = nodes.listcodes
local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
local glue_code = nodecodes.glue
+local glyph_code = nodecodes.glyph
+local rule_code = nodecodes.rule
local whatsit_code = nodecodes.whatsit
local leftskip_code = skipcodes.leftskip
@@ -83,68 +90,147 @@ local line_code = listcodes.line
local new_rule = nodepool.rule
local new_kern = nodepool.kern
+local free_node = nuts.free
+
local tosequence = nodes.tosequence
--- local function dimensions(parent,start,stop)
--- stop = stop and getnext(stop)
--- if parent then
--- if stop then
--- return list_dimensions(getfield(parent,"glue_set"),getfield(parent,"glue_sign"),getfield(parent,"glue_order"),start,stop)
--- else
--- return list_dimensions(getfield(parent,"glue_set"),getfield(parent,"glue_sign",getfield(parent,"glue_order"),start)
--- end
--- else
--- if stop then
--- return list_dimensions(start,stop)
--- else
--- return list_dimensions(start)
--- end
--- end
--- end
---
--- -- more compact
+local implement = interfaces.implement
+
+-- Normally a (destination) area is a box or a simple stretch if nodes but when it is
+-- a paragraph we hav ea problem: we cannot calculate the height well. This happens
+-- with footnotes or content broken across a page.
+
+local function vlist_dimensions(start,stop)
+ local temp
+ if stop then
+ temp = getnext(stop)
+ setfield(stop,"next",nil)
+ end
+ local v = vpack_list(start)
+ local w = getfield(v,"width")
+ local h = getfield(v,"height")
+ local d = getfield(v,"depth")
+ setfield(v,"list",nil)
+ free_node(v)
+ if temp then
+ setfield(stop,"next",temp)
+ end
+ return w, h, d
+end
-local function dimensions(parent,start,stop)
+local function hlist_dimensions(start,stop,parent)
+ local last = stop and getnext(stop)
+ if parent then
+ return list_dimensions(getfield(parent,"glue_set"),getfield(parent,"glue_sign"),getfield(parent,"glue_order"),start,last)
+ else
+ return list_dimensions(start,last)
+ end
+end
+
+local function dimensions(parent,start,stop) -- in principle we could move some to the caller
+ local id = getid(start)
+ if start == stop then
+ if id == hlist_code or id == vlist_code or id == glyph_code or id == rule_code then -- or image
+ if trace_areas then
+ report_area("dimensions taken of %a",nodecodes[id])
+ end
+ return getfield(start,"width"), getfield(parent,"height"), getfield(parent,"depth")
+ else
+ if trace_areas then
+ report_area("dimensions calculated of %a",nodecodes[id])
+ end
+ return hlist_dimensions(start,stop) -- one node only so simple
+ end
+ end
+ local last = stop and getnext(stop)
if parent then
- return list_dimensions(getfield(parent,"glue_set"),getfield(parent,"glue_sign"),getfield(parent,"glue_order"),start,stop and getnext(stop))
+ -- todo: if no prev and no next and parent
+ -- todo: we need a a list_dimensions for a vlist
+ if getid(parent) == vlist_code then
+ local l = getlist(parent)
+ local c = l
+ local ok = false
+ while c do
+ if c == start then
+ ok = true
+ end
+ if ok and getid(c) == hlist_code then
+ break
+ else
+ c = getnext(c)
+ end
+ end
+ if ok and c then
+ if trace_areas then
+ report_area("dimensions taken of first line in vlist")
+ end
+ return getfield(c,"width"), getfield(c,"height"), getfield(c,"depth"), c
+ else
+ if trace_areas then
+ report_area("dimensions taken of vlist (probably wrong)")
+ end
+ return hlist_dimensions(start,stop,parent)
+ end
+ else
+ if trace_areas then
+ report_area("dimensions taken of range starting with %a using parent",nodecodes[id])
+ end
+ return hlist_dimensions(start,stop,parent)
+ end
else
- return list_dimensions(start,stop and getnext(stop))
+ if trace_areas then
+ report_area("dimensions taken of range starting with %a",nodecodes[id])
+ end
+ return hlist_dimensions(start,stop)
end
end
-- is pardir important at all?
local function inject_range(head,first,last,reference,make,stack,parent,pardir,txtdir)
- local width, height, depth = dimensions(parent,first,last)
+ local width, height, depth, line = dimensions(parent,first,last)
if txtdir == "+TRT" or (txtdir == "===" and pardir == "TRT") then -- KH: textdir == "===" test added
width = - width
end
local result, resolved = make(width,height,depth,reference)
if result and resolved then
- if head == first then
- if trace_backend then
- report_area("%s: %04i %s %s %s => w=%p, h=%p, d=%p, c=%S","head",
- reference,pardir or "---",txtdir or "---",tosequence(first,last,true),width,height,depth,resolved)
+ if line then
+ -- special case, we only treat the first line in a vlist
+ local l = getlist(line)
+ if trace_areas then
+ report_area("%s: %04i %s %s %s => w=%p, h=%p, d=%p, c=%S","line",
+ reference,pardir or "---",txtdir or "---",tosequence(l,nil,true),width,height,depth,resolved)
end
- setfield(result,"next",first)
- setfield(first,"prev",result)
- return result, last
+ setfield(line,"list",result)
+ setfield(result,"next",l)
+ setfield(l,"prev",result)
+ return head, last
else
- if trace_backend then
- report_area("%s: %04i %s %s %s => w=%p, h=%p, d=%p, c=%S","middle",
- reference,pardir or "---",txtdir or "---",tosequence(first,last,true),width,height,depth,resolved)
- end
- local prev = getprev(first)
- if prev then
- setfield(prev,"next",result)
- setfield(result,"prev",prev)
+ if head == first then
+ if trace_areas then
+ report_area("%s: %04i %s %s %s => w=%p, h=%p, d=%p, c=%S","head",
+ reference,pardir or "---",txtdir or "---",tosequence(first,last,true),width,height,depth,resolved)
+ end
+ setfield(result,"next",first)
+ setfield(first,"prev",result)
+ return result, last
+ else
+ if trace_areas then
+ report_area("%s: %04i %s %s %s => w=%p, h=%p, d=%p, c=%S","middle",
+ reference,pardir or "---",txtdir or "---",tosequence(first,last,true),width,height,depth,resolved)
+ end
+ local prev = getprev(first)
+ if prev then
+ setfield(prev,"next",result)
+ setfield(result,"prev",prev)
+ end
+ setfield(result,"next",first)
+ setfield(first,"prev",result)
+ -- if first == getnext(head) then
+ -- setfield(head,"next",result) -- hm, weird
+ -- end
+ return head, last
end
- setfield(result,"next",first)
- setfield(first,"prev",result)
--- if first == getnext(head) then
--- setfield(head,"next",result) -- hm, weird
--- end
- return head, last
end
else
return head, last
@@ -152,9 +238,12 @@ local function inject_range(head,first,last,reference,make,stack,parent,pardir,t
end
local function inject_list(id,current,reference,make,stack,pardir,txtdir)
- local width, height, depth, correction = getfield(current,"width"), getfield(current,"height"), getfield(current,"depth"), 0
- local moveright = false
- local first = getlist(current)
+ local width = getfield(current,"width")
+ local height = getfield(current,"height")
+ local depth = getfield(current,"depth")
+ local correction = 0
+ local moveright = false
+ local first = getlist(current)
if id == hlist_code then -- box_code line_code
-- can be either an explicit hbox or a line and there is no way
-- to recognize this; anyway only if ht/dp (then inline)
@@ -193,7 +282,7 @@ local function inject_list(id,current,reference,make,stack,pardir,txtdir)
local result, resolved = make(width,height,depth,reference)
-- todo: only when width is ok
if result and resolved then
- if trace_backend then
+ if trace_areas then
report_area("%s: %04i %s %s %s: w=%p, h=%p, d=%p, c=%S","box",
reference,pardir or "---",txtdir or "----","[]",width,height,depth,resolved)
end
@@ -227,6 +316,10 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx
while current do
local id = getid(current)
if id == hlist_code or id == vlist_code then
+
+ -- see dimensions: this is tricky with split off boxes like inserts
+ -- where we can end up with a first and last spanning lines
+
local r = getattr(current,attribute)
-- test \goto{test}[page(2)] test \gotobox{test}[page(2)]
-- test \goto{\TeX}[page(2)] test \gotobox{\hbox {x} \hbox {x}}[page(2)]
@@ -330,7 +423,7 @@ local function inject_area(head,attribute,make,stack,done,parent,pardir,txtdir)
return head, true
end
--- tracing
+-- tracing: todo: use predefined colors
local register_color = colors.register
@@ -341,7 +434,33 @@ local u_transparency = nil
local u_colors = { }
local force_gray = true
-local function colorize(width,height,depth,n,reference,what)
+local function addstring(what,str,shift) --todo make a pluggable helper (in font-ctx)
+ if str then
+ local typesetters = nuts.typesetters
+ if typesetters then
+ local hashes = fonts.hashes
+ local infofont = fonts.infofont()
+ local emwidth = hashes.emwidths [infofont]
+ local exheight = hashes.exheights[infofont]
+ if what == "reference" then
+ str = str .. " "
+ shift = - (shift or 2.25) * exheight
+ else
+ str = str .. " "
+ shift = (shift or 2) * exheight
+ end
+ local text = typesetters.fast_hpack(str,infofont)
+ local rule = new_rule(emwidth/5,4*exheight,3*exheight)
+ local list = getlist(text)
+ setfield(text,"shift",shift)
+ return nuts.fasthpack(nuts.linked(text,rule))
+ -- local text = typesetters.fast_hpack(str,fonts.infofont())
+ -- return text
+ end
+ end
+end
+
+local function colorize(width,height,depth,n,reference,what,sr,offset)
if force_gray then n = 0 end
u_transparency = u_transparency or transparencies.register(nil,2,.65)
local ucolor = u_colors[n]
@@ -379,10 +498,37 @@ local function colorize(width,height,depth,n,reference,what)
setfield(rule,"prev",kern)
return kern
else
+
+if sr and sr ~= "" then
+ local text = addstring(what,sr,shift)
+ if text then
+ local kern = new_kern(-getfield(text,"width"))
+ setfield(kern,"next",text)
+ setfield(text,"prev",kern)
+ setfield(text,"next",rule)
+ setfield(rule,"prev",text)
+ return kern
+ end
+end
+
return rule
end
end
+local function justadd(what,sr,shift)
+ if sr and sr ~= "" then
+ local text = addstring(what,sr,shift)
+ if text then
+ local kern = new_kern(-getfield(text,"width"))
+ setfield(kern,"next",text)
+ setfield(text,"prev",kern)
+ setfield(text,"next",rule)
+ setfield(rule,"prev",text)
+ return kern
+ end
+ end
+end
+
-- references:
local texsetattribute = tex.setattribute
@@ -423,23 +569,45 @@ local function makereference(width,height,depth,reference) -- height and depth a
report_reference("resolving attribute %a",reference)
end
local resolved, ht, dp, set, n = sr[1], sr[2], sr[3], sr[4], sr[5]
--- logs.report("temp","child: ht=%p dp=%p, parent: ht=%p dp=%p",ht,dp,height,depth)
+ -- logs.report("temp","child: ht=%p dp=%p, parent: ht=%p dp=%p",ht,dp,height,depth)
if ht then
if height < ht then height = ht end
if depth < dp then depth = dp end
end
--- logs.report("temp","used: ht=%p dp=%p",height,depth)
--- step = 0
+ -- logs.report("temp","used: ht=%p dp=%p",height,depth)
local annot = nodeinjections.reference(width,height,depth,set)
if annot then
-annot = tonut(annot)
+ annot = tonut(annot) -- todo
nofreferences = nofreferences + 1
- local result, current
+ local result, current, texts
+ if show_references then
+ local d = sr[1]
+ if d then
+ local r = d.reference
+ local p = d.prefix
+ if r then
+ if p then
+ texts = p .. "|" .. r
+ else
+ texts = r
+ end
+ else
+ -- t[#t+1] = d.internal or "?"
+ end
+ end
+ end
if trace_references then
local step = 65536
- result = hpack_list(colorize(width,height-step,depth-step,2,reference,"reference")) -- step subtracted so that we can see seperate links
+ result = hpack_list(colorize(width,height-step,depth-step,2,reference,"reference",texts,show_references)) -- step subtracted so that we can see seperate links
setfield(result,"width",0)
current = result
+ elseif texts then
+ texts = justadd("reference",texts,show_references)
+ if texts then
+ result = hpack_list(texts)
+ setfield(result,"width",0)
+ current = result
+ end
end
if current then
setfield(current,"next",annot)
@@ -506,19 +674,49 @@ local function makedestination(width,height,depth,reference)
if trace_destinations then
report_destination("resolving attribute %a",reference)
end
- local resolved, ht, dp, name, view = sr[1], sr[2], sr[3], sr[4], sr[5]
+ local resolved, ht, dp, name, view = sr[1], sr[2], sr[3], sr[4], sr[5] -- sr[4] will change to just internal
if ht then
if height < ht then height = ht end
if depth < dp then depth = dp end
end
- local result, current
+ local result, current, texts
+ if show_destinations then
+ if name and #name > 0 then
+ local t = { }
+ for i=1,#name do
+ local s = name[i]
+ if type(s) == "number" then
+ local d = references.internals[s]
+ if d then
+ d = d.references
+ local r = d.reference
+ local p = d.usedprefix
+ if r then
+ if p then
+ t[#t+1] = p .. "|" .. r
+ else
+ t[#t+1] = r
+ end
+ else
+ -- t[#t+1] = d.internal or "?"
+ end
+ end
+ else
+ -- in fact we have a prefix:name here
+ end
+ end
+ if #t > 0 then
+ texts = concat(t," & ")
+ end
+ end
+ end
if trace_destinations then
local step = 0
if width == 0 then
step = 4*65536
width, height, depth = 5*step, 5*step, 0
end
- local rule = hpack_list(colorize(width,height,depth,3,reference,"destination"))
+ local rule = hpack_list(colorize(width,height,depth,3,reference,"destination",texts,show_destinations))
setfield(rule,"width",0)
if not result then
result, current = rule, rule
@@ -528,6 +726,15 @@ local function makedestination(width,height,depth,reference)
current = rule
end
width, height = width - step, height - step
+ elseif texts then
+ texts = justadd("destination",texts,show_destinations)
+ if texts then
+ result = hpack_list(texts)
+ if result then
+ setfield(result,"width",0)
+ current = result
+ end
+ end
end
nofdestinations = nofdestinations + 1
local annot = nodeinjections.destination(width,height,depth,name,view)
@@ -580,14 +787,17 @@ function references.mark(reference,h,d,view)
return setdestination(tex.currentgrouplevel,h,d,reference,view)
end
-function references.inject(prefix,reference,h,d,highlight,newwindow,layer) -- todo: use currentreference is possible
+function references.inject(prefix,reference,specification) -- todo: use currentreference is possible
+-- print(prefix,reference,h,d,highlight,newwindow,layer)
local set, bug = references.identify(prefix,reference)
if bug or #set == 0 then
-- unknown ref, just don't set it and issue an error
else
-- check
- set.highlight, set.newwindow, set.layer = highlight, newwindow, layer
- setreference(h,d,set) -- sets attribute / todo: for set[*].error
+ set.highlight = specification.highlight
+ set.newwindow = specification.newwindow
+ set.layer = specification.layer
+ setreference(specification.height,specification.depth,set) -- sets attribute / todo: for set[*].error
end
end
@@ -598,8 +808,32 @@ function references.injectcurrentset(h,d) -- used inside doifelse
end
end
-commands.injectreference = references.inject
-commands.injectcurrentreference = references.injectcurrentset
+implement {
+ name = "injectreference",
+ actions = references.inject,
+ arguments = {
+ "string",
+ "string",
+ {
+ { "highlight", "boolean" },
+ { "newwindow", "boolean" },
+ { "layer" },
+ { "height", "dimen" },
+ { "depth", "dimen" },
+ }
+ }
+}
+
+implement {
+ name = "injectcurrentreference",
+ actions = references.injectcurrentset,
+}
+
+implement {
+ name = "injectcurrentreferencehtdp",
+ actions = references.injectcurrentset,
+ arguments = { "dimen", "dimen" },
+}
--
@@ -628,4 +862,11 @@ end)
function references.enableinteraction()
tasks.enableaction("shipouts","nodes.references.handler")
tasks.enableaction("shipouts","nodes.destinations.handler")
+ function references.enableinteraction() end
end
+
+implement {
+ name = "enableinteraction",
+ actions = references.enableinteraction,
+ onlyonce = true
+}
diff --git a/Master/texmf-dist/tex/context/base/node-res.lua b/Master/texmf-dist/tex/context/base/node-res.lua
index 1a9d6f02e2e..43dd3895ed6 100644
--- a/Master/texmf-dist/tex/context/base/node-res.lua
+++ b/Master/texmf-dist/tex/context/base/node-res.lua
@@ -146,6 +146,7 @@ local user_n = register_nut(new_nut("whatsit",whatsitcodes.userdefine
local user_l = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_l,"type",110) -- 44
local user_s = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_s,"type",115) -- 44
local user_t = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_t,"type",116) -- 44
+----- user_c = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_c,"type",108) -- 44
local left_margin_kern = register_nut(new_nut("margin_kern",0))
local right_margin_kern = register_nut(new_nut("margin_kern",1))
local lineskip = register_nut(new_nut("glue",skipcodes.lineskip))
@@ -504,6 +505,17 @@ function nutpool.usertokens(id,tokens)
return n
end
+-- function nutpool.usercode(id,code)
+-- local n = copy_nut(user_c)
+-- if code then
+-- setfield(n,"user_id",id)
+-- setfield(n,"value",code)
+-- else
+-- setfield(n,"value",id)
+-- end
+-- return n
+-- end
+
function nutpool.special(str)
local n = copy_nut(special)
setfield(n,"data",str)
diff --git a/Master/texmf-dist/tex/context/base/node-rul.lua b/Master/texmf-dist/tex/context/base/node-rul.lua
index 6f3bc9df9e6..36d56a16c1a 100644
--- a/Master/texmf-dist/tex/context/base/node-rul.lua
+++ b/Master/texmf-dist/tex/context/base/node-rul.lua
@@ -424,3 +424,52 @@ nodes.shifts.handler = function(head) return process(a_shifted,data,flush_shifte
function nodes.shifts.enable()
tasks.enableaction("shipouts","nodes.shifts.handler")
end
+
+-- interface
+
+local implement = interfaces.implement
+
+implement {
+ name = "definerule",
+ actions = { nodes.rules.define, context },
+ arguments = {
+ {
+ { "continue" },
+ { "unit" },
+ { "order" },
+ { "method", "integer" },
+ { "offset", "number" },
+ { "rulethickness", "string" },
+ { "dy", "number" },
+ { "max", "number" },
+ { "ma", "integer" },
+ { "ca", "integer" },
+ { "ta", "integer" },
+ }
+ }
+}
+
+implement {
+ name = "enablerules",
+ onlyonce = true,
+ actions = nodes.rules.enable
+}
+
+implement {
+ name = "defineshift",
+ actions = { nodes.shifts.define, context },
+ arguments = {
+ {
+ { "continue" },
+ { "unit" },
+ { "method", "integer" },
+ { "dy", "number" },
+ }
+ }
+}
+
+implement {
+ name = "enableshifts",
+ onlyonce = true,
+ actions = nodes.shifts.enable
+}
diff --git a/Master/texmf-dist/tex/context/base/node-rul.mkiv b/Master/texmf-dist/tex/context/base/node-rul.mkiv
index 2d2e61134ef..7fa0473a5ff 100644
--- a/Master/texmf-dist/tex/context/base/node-rul.mkiv
+++ b/Master/texmf-dist/tex/context/base/node-rul.mkiv
@@ -112,19 +112,20 @@
\unexpanded\def\node_rules_define
{\edef\p_node_rules_color{\barparameter\c!color}%
- \setevalue{\??barattribute\currentbar}{\number\ctxlua{nodes.rules.define {
- method = \barparameter\c!method,
- offset = \barparameter\c!offset,
- continue = "\barparameter\c!continue",
- dy = \barparameter\c!dy,
- rulethickness = "\barparameter\c!rulethickness",
- unit = "\barparameter\c!unit",
- order = "\barparameter\c!order",
- max = \barparameter\c!max,
- ma = \thecolormodelattribute,
- ca = \thecolorattribute\p_node_rules_color,
- ta = \thetransparencyattribute\p_node_rules_color
- }}}}
+ \setevalue{\??barattribute\currentbar}{\number
+ \clf_definerule
+ continue {\barparameter\c!continue}%
+ unit {\barparameter\c!unit}%
+ order {\barparameter\c!order}%
+ rulethickness {\barparameter\c!rulethickness}%
+ method \barparameter\c!method
+ ma \thecolormodelattribute
+ ca \thecolorattribute\p_node_rules_color
+ ta \thetransparencyattribute\p_node_rules_color
+ offset \barparameter\c!offset\space % number
+ dy \barparameter\c!dy\space % number
+ max \barparameter\c!max
+ \relax}}
\unexpanded\def\node_rules_redefine#1%
{\def\currentbar{#1}\node_rules_define}
@@ -132,13 +133,16 @@
\unexpanded\def\node_rules_direct#1%
{\groupedcommand{\node_rules_set{#1}}\relax}
-\def\node_rules_set
- {\ctxlua{nodes.rules.enable()}% will be moved to lua
- \glet\node_rules_set\node_rules_set_indeed
- \node_rules_set}
+% \unexpanded\def\node_rules_set
+% {\clf_enablerules % will be moved to lua
+% \glet\node_rules_set\node_rules_set_indeed
+% \node_rules_set}
+%
+%\unexpanded\def\node_rules_set_indeed#1% maybe reverse the 1000 (also maybe use more attributes instead of settings)
-\def\node_rules_set_indeed#1% maybe reverse the 1000 (also maybe use more attributes instead of settings)
- {\edef\currentbar{#1}%
+\unexpanded\def\node_rules_set#1% maybe reverse the 1000 (also maybe use more attributes instead of settings)
+ {\clf_enablerules % will be relaxed
+ \edef\currentbar{#1}%
\expandafter\let\expandafter\c_node_rules_index\csname\??barindex#1\endcsname
\advance\c_node_rules_index\plusone
\usebarstyleandcolor\c!foregroundstyle\c!foregroundcolor
@@ -157,6 +161,8 @@
\unexpanded\def\setbar[#1]%
{\node_rules_set{#1}}
+\let\directsetbar\node_rules_set
+
% ungrouped
\newcount\c_node_rules_nesting % todo: same as colors
@@ -279,31 +285,27 @@
\to \everydefineshift
\unexpanded\def\node_shifts_define
- {\setevalue{\??shiftattribute\currentshift}{\number\ctxlua{nodes.shifts.define {
- method = \shiftparameter\c!method,
- continue = "\shiftparameter\c!continue",
- dy = \shiftparameter\c!dy,
- unit = "\shiftparameter\c!unit",
- }}}}
+ {\setevalue{\??shiftattribute\currentshift}{\number
+ \clf_defineshift
+ continue {\shiftparameter\c!continue}%
+ unit {\shiftparameter\c!unit}%
+ method \shiftparameter\c!method
+ dy \shiftparameter\c!dy % number
+ \relax}}
\unexpanded\def\node_shifts_redefine#1%
{\def\currentshift{#1}\node_shifts_define}
-\unexpanded\def\node_shifts_set
- {\ctxlua{nodes.shifts.enable()}%
- \glet\node_shifts_set\node_shifts_set_indeed
- \node_shifts_set}
-
-% \unexpanded\def\node_shifts_direct#1%
-% {\doisolatedgroupedalign{\node_shifts_set{#1}}\donothing}
-
-\unexpanded\def\node_shifts_direct#1%
- {\groupedcommand
- {\begingroup\dostartisolation\begingroup\node_shifts_set{#1}}
- {\endgroup\dostopisolation\endgroup}}
+% \unexpanded\def\node_shifts_set
+% {\clf_enableshifts
+% \glet\node_shifts_set\node_shifts_set_indeed
+% \node_shifts_set}
+%
+% \def\node_shifts_set_indeed#1% todo: check parent !
-\def\node_shifts_set_indeed#1% todo: check parent !
- {\def\currentshift{#1}%
+\unexpanded\def\node_shifts_set#1% todo: check parent !
+ {\clf_enableshifts
+ \def\currentshift{#1}%
\expandafter\let\expandafter\c_node_shifts_index\csname\??shiftindex#1\endcsname
\advance\c_node_shifts_index\plusone
\attribute\shiftedattribute\numexpr
@@ -320,6 +322,14 @@
\unexpanded\def\stopshift
{\endgroup}
+% \unexpanded\def\node_shifts_direct#1%
+% {\doisolatedgroupedalign{\node_shifts_set{#1}}\donothing}
+
+\unexpanded\def\node_shifts_direct#1%
+ {\groupedcommand
+ {\begingroup\dostartisolation\begingroup\node_shifts_set{#1}}
+ {\endgroup\dostopisolation\endgroup}}
+
\setupshifts
[\c!method=0,
\c!continue=\v!no,
diff --git a/Master/texmf-dist/tex/context/base/node-shp.lua b/Master/texmf-dist/tex/context/base/node-shp.lua
index 6ebfd767fb4..42cc83b8f34 100644
--- a/Master/texmf-dist/tex/context/base/node-shp.lua
+++ b/Master/texmf-dist/tex/context/base/node-shp.lua
@@ -15,6 +15,8 @@ local setmetatableindex = table.setmetatableindex
local nodecodes = nodes.nodecodes
local whatsitcodes = nodes.whatsitcodes
+local disccodes = nodes.disccodes
+
local tasks = nodes.tasks
local handlers = nodes.handlers
@@ -26,11 +28,27 @@ local kern_code = nodecodes.kern
local glue_code = nodecodes.glue
local whatsit_code = nodecodes.whatsit
+local fulldisc_code = disccodes.discretionary
+
local texgetbox = tex.getbox
-local free_node = node.free
-local remove_node = node.remove
-local traverse_nodes = node.traverse
+local implement = interfaces.implement
+
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+local free_node = nuts.free
+local remove_node = nuts.remove
+local traverse_nodes = nuts.traverse
+local find_tail = nuts.tail
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getid = nuts.getid
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getlist = nuts.getlist
+local getsubtype = nuts.getsubtype
local removables = {
[whatsitcodes.open] = true,
@@ -41,38 +59,63 @@ local removables = {
[whatsitcodes.latelua] = true,
}
-local function cleanup_redundant(head)
+-- About 10% of the nodes make no sense for the backend. By (at least)
+-- removing the replace disc nodes, we can omit extensive checking in
+-- the finalizer code (e.g. colors in disc nodes). Removing more nodes
+-- (like marks) is not saving much and removing empty boxes is even
+-- dangerous because we can rely on dimensions (e.g. in references).
+
+local wipedisc = false -- we can use them in the export ... can be option
+
+local function cleanup_redundant(head) -- better name is: flatten_page
local start = head
while start do
- local id = start.id
+ local id = getid(start)
if id == disc_code then
- head, start = remove_node(head,start,true)
- -- elseif id == glue_code then
- -- if start.writable then
- -- start = start.next
- -- elseif some_complex_check_on_glue_spec then
- -- head, start = remove_node(head,start,true)
- -- else
- -- start = start.next
- -- end
- elseif id == kern_code then
- if start.kern == 0 then
- head, start = remove_node(head,start,true)
+ if getsubtype(start) == fulldisc_code then
+ local replace = getfield(start,"replace")
+ if replace then
+ local prev = getprev(start)
+ local next = getnext(start)
+ local tail = find_tail(replace)
+ setfield(start,"replace",nil)
+ if start == head then
+ remove_node(head,start,true)
+ head = replace
+ else
+ remove_node(head,start,true)
+ end
+ if next then
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
+ end
+ if prev then
+ setfield(prev,"next",replace)
+ setfield(replace,"prev",prev)
+ else
+ setfield(replace,"prev",nil) -- to be sure
+ end
+ start = next
+ elseif wipedisc then
+ -- pre and post can have values
+ head, start = remove_node(head,start,true)
+ else
+ start = getnext(start)
+ end
else
- start = start.next
+ start = getnext(start)
end
- elseif id == mark_code then
- head, start = remove_node(head,start,true)
elseif id == hlist_code or id == vlist_code then
- local sl = start.list
+ local sl = getlist(start)
if sl then
- start.list = cleanup_redundant(sl)
- start = start.next
- else
- head, start = remove_node(head,start,true)
+ local rl = cleanup_redundant(sl)
+ if rl ~= sl then
+ setfield(start,"list",rl)
+ end
end
+ start = getnext(start)
else
- start = start.next
+ start = getnext(start)
end
end
return head
@@ -81,54 +124,49 @@ end
local function cleanup_flushed(head) -- rough
local start = head
while start do
- local id = start.id
- if id == whatsit_code and removables[start.subtype] then
- head, start = remove_node(head,start,true)
+ local id = getid(start)
+ if id == whatsit_code then
+ if removables[getsubtype(start)] then
+ head, start = remove_node(head,start,true)
+ else
+ start = getnext(start)
+ end
elseif id == hlist_code or id == vlist_code then
- local sl = start.list
+ local sl = getlist(start)
if sl then
- start.list = cleanup_flushed(sl)
- start = start.next
- else
- head, start = remove_node(head,start,true)
+ local rl = cleanup_flushed(sl)
+ if rl ~= sl then
+ setfield(start,"list",rl)
+ end
end
+ start = getnext(start)
else
- start = start.next
+ start = getnext(start)
end
end
return head
end
function handlers.cleanuppage(head)
- -- about 10% of the nodes make no sense for the backend
- return cleanup_redundant(head), true
+ return tonode(cleanup_redundant(tonut(head))), true
end
function handlers.cleanupbox(head)
- return cleanup_flushed(head), true
+ return tonode(cleanup_flushed(tonut(head))), true
end
-directives.register("backend.cleanup", function()
- tasks.enableaction("shipouts","nodes.handlers.cleanuppage")
-end)
-
local actions = tasks.actions("shipouts") -- no extra arguments
function handlers.finalize(head) -- problem, attr loaded before node, todo ...
return actions(head)
end
-function commands.cleanupbox(n)
- cleanup_flushed(texgetbox(n))
-end
-
-- handlers.finalize = actions
-- interface
-function commands.finalizebox(n)
- actions(texgetbox(n))
-end
+implement { name = "cleanupbox", actions = { texgetbox, cleanup_flushed }, arguments = "integer" }
+implement { name = "finalizebox", actions = { texgetbox, actions }, arguments = "integer" }
-- just in case we want to optimize lookups:
@@ -158,12 +196,12 @@ local function count(head,data,subcategory)
-- no components, pre, post, replace .. can maybe an option .. but
-- we use this for optimization so it makes sense to look the the
-- main node only
- for n in traverse_nodes(head) do
- local id = n.id
- local dn = data[nodecodes[n.id]]
+ for n in traverse_nodes(tonut(head)) do
+ local id = getid(n)
+ local dn = data[nodecodes[id]] -- we could use id and then later convert to nodecodes
dn[subcategory] = dn[subcategory] + 1
if id == hlist_code or id == vlist_code then
- count(n.list,data,subcategory)
+ count(getfield(n,"list"),data,subcategory)
end
end
end
diff --git a/Master/texmf-dist/tex/context/base/node-tex.lua b/Master/texmf-dist/tex/context/base/node-tex.lua
index 2170e0603fd..c9d3091df23 100644
--- a/Master/texmf-dist/tex/context/base/node-tex.lua
+++ b/Master/texmf-dist/tex/context/base/node-tex.lua
@@ -6,33 +6,32 @@ if not modules then modules = { } end modules ['node-tex'] = {
license = "see context related readme files"
}
-local format = string.format
+builders = builders or { }
+local kernel = builders.kernel or { }
+builders.kernel = kernel
-builders = builders or { }
-builders.kernel = builders.kernel or { }
-local kernel = builders.kernel
+local hyphenate = lang.hyphenate
+local ligaturing = node.ligaturing
+local kerning = node.kerning
-local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
-local hyphenate, ligaturing, kerning = lang.hyphenate, node.ligaturing, node.kerning
+kernel.originals = {
+ hyphenate = hyphenate,
+ ligaturing = ligaturing,
+ kerning = kerning,
+}
function kernel.hyphenation(head)
- -- starttiming(kernel)
local done = hyphenate(head)
- -- stoptiming(kernel)
return head, done
end
function kernel.ligaturing(head)
- -- starttiming(kernel)
- local head, tail, done = ligaturing(head) -- todo: check what is returned
- -- stoptiming(kernel)
+ local head, tail, done = ligaturing(head) -- we return 3 values indeed
return head, done
end
function kernel.kerning(head)
- -- starttiming(kernel)
- local head, tail, done = kerning(head) -- todo: check what is returned
- -- stoptiming(kernel)
+ local head, tail, done = kerning(head) -- we return 3 values indeed
return head, done
end
diff --git a/Master/texmf-dist/tex/context/base/node-tra.lua b/Master/texmf-dist/tex/context/base/node-tra.lua
index 08110727705..a7ab7f77f72 100644
--- a/Master/texmf-dist/tex/context/base/node-tra.lua
+++ b/Master/texmf-dist/tex/context/base/node-tra.lua
@@ -78,6 +78,7 @@ local localpar_code = whatcodes.localpar
local dir_code = whatcodes.dir
local dimenfactors = number.dimenfactors
+local fillorders = nodes.fillcodes
local formatters = string.formatters
-- this will be reorganized:
@@ -171,6 +172,7 @@ local function tosequence(start,stop,compact)
end
nodes.tosequence = tosequence
+nuts .tosequence = tosequence
function nodes.report(t,done)
report_nodes("output %a, %changed %a, %s nodes",status.output_active,done,count_nodes(tonut(t)))
@@ -318,8 +320,12 @@ local function listtoutf(h,joiner,textonly,last)
end
function nodes.listtoutf(h,joiner,textonly,last)
- local joiner = joiner == true and utfchar(0x200C) or joiner -- zwnj
- return listtoutf(tonut(h),joiner,textonly,last and tonut(last))
+ if h then
+ local joiner = joiner == true and utfchar(0x200C) or joiner -- zwnj
+ return listtoutf(tonut(h),joiner,textonly,last and tonut(last))
+ else
+ return ""
+ end
end
local what = { [0] = "unknown", "line", "box", "indent", "row", "cell" }
@@ -353,82 +359,175 @@ local stripper = lpeg.patterns.stripzeros
--
-- redefined:
-local dimenfactors = number.dimenfactors
+-- local function nodetodimen(d,unit,fmt,strip)
+-- d = tonut(d) -- tricky: direct nuts are an issue
+-- if unit == true then
+-- unit = "pt"
+-- fmt = "%0.5f%s"
+-- else
+-- unit = unit or 'pt'
+-- if not fmt then
+-- fmt = "%s%s"
+-- elseif fmt == true then
+-- fmt = "%0.5f%s"
+-- end
+-- end
+-- local id = getid(d)
+-- if id == kern_code then
+-- local str = formatters[fmt](getfield(d,"width")*dimenfactors[unit],unit)
+-- return strip and lpegmatch(stripper,str) or str
+-- end
+-- if id == glue_code then
+-- d = getfield(d,"spec")
+-- end
+-- if not d or not getid(d) == gluespec_code then
+-- local str = formatters[fmt](0,unit)
+-- return strip and lpegmatch(stripper,str) or str
+-- end
+-- local width = getfield(d,"width")
+-- local plus = getfield(d,"stretch_order")
+-- local minus = getfield(d,"shrink_order")
+-- local stretch = getfield(d,"stretch")
+-- local shrink = getfield(d,"shrink")
+-- if plus ~= 0 then
+-- plus = " plus " .. stretch/65536 .. fillcodes[plus]
+-- elseif stretch ~= 0 then
+-- plus = formatters[fmt](stretch*dimenfactors[unit],unit)
+-- plus = " plus " .. (strip and lpegmatch(stripper,plus) or plus)
+-- else
+-- plus = ""
+-- end
+-- if minus ~= 0 then
+-- minus = " minus " .. shrink/65536 .. fillcodes[minus]
+-- elseif shrink ~= 0 then
+-- minus = formatters[fmt](shrink*dimenfactors[unit],unit)
+-- minus = " minus " .. (strip and lpegmatch(stripper,minus) or minus)
+-- else
+-- minus = ""
+-- end
+-- local str = formatters[fmt](getfield(d,"width")*dimenfactors[unit],unit)
+-- return (strip and lpegmatch(stripper,str) or str) .. plus .. minus
+-- end
+--
+-- local function numbertodimen(d,unit,fmt,strip)
+-- if not d then
+-- local str = formatters[fmt](0,unit)
+-- return strip and lpegmatch(stripper,str) or str
+-- end
+-- local t = type(d)
+-- if t == 'string' then
+-- return d
+-- elseif t == "number" then
+-- if unit == true then
+-- unit = "pt"
+-- fmt = "%0.5f%s"
+-- else
+-- unit = unit or 'pt'
+-- if not fmt then
+-- fmt = "%s%s"
+-- elseif fmt == true then
+-- fmt = "%0.5f%s"
+-- end
+-- end
+-- local str = formatters[fmt](d*dimenfactors[unit],unit)
+-- return strip and lpegmatch(stripper,str) or str
+-- else
+-- return nodetodimen(d,unit,fmt,strip) -- real node
+-- end
+-- end
-local function nodetodimen(d,unit,fmt,strip)
- d = tonut(d) -- tricky: direct nuts are an issue
- if unit == true then
- unit = "pt"
- fmt = "%0.5f%s"
- else
- unit = unit or 'pt'
- if not fmt then
- fmt = "%s%s"
- elseif fmt == true then
- fmt = "%0.5f%s"
- end
- end
- local id = getid(d)
+local f_f_f = formatters["%0.5Fpt plus %0.5F%s minus %0.5F%s"]
+local f_f_m = formatters["%0.5Fpt plus %0.5F%s minus %0.5Fpt"]
+local f_p_f = formatters["%0.5Fpt plus %0.5Fpt minus %0.5F%s"]
+local f_p_m = formatters["%0.5Fpt plus %0.5Fpt minus %0.5Fpt"]
+local f_f_z = formatters["%0.5Fpt plus %0.5F%s"]
+local f_p_z = formatters["%0.5Fpt plus %0.5Fpt"]
+local f_z_f = formatters["%0.5Fpt minus %0.5F%s"]
+local f_z_m = formatters["%0.5Fpt minus %0.5Fpt"]
+local f_z_z = formatters["%0.5Fpt"]
+
+local tonut = nodes.tonut
+local getfield = nodes.nuts.getfield
+
+local function nodetodimen(n)
+ n = tonut(n)
+ local id = getid(n)
if id == kern_code then
- local str = formatters[fmt](getfield(d,"width")*dimenfactors[unit],unit)
- return strip and lpegmatch(stripper,str) or str
+ local width = getfield(n,"width")
+ if width == 0 then
+ return "0pt"
+ else
+ return f_z_z(width)
+ end
end
if id == glue_code then
- d = getfield(d,"spec")
+ n = getfield(n,"spec")
end
- if not d or not getid(d) == gluespec_code then
- local str = formatters[fmt](0,unit)
- return strip and lpegmatch(stripper,str) or str
+ if not n or not getid(n) == gluespec_code then
+ return "0pt"
end
- local width = getfield(d,"width")
- local plus = getfield(d,"stretch_order")
- local minus = getfield(d,"shrink_order")
- local stretch = getfield(d,"stretch")
- local shrink = getfield(d,"shrink")
- if plus ~= 0 then
- plus = " plus " .. stretch/65536 .. fillcodes[plus]
+ local stretch_order = getfield(n,"stretch_order")
+ local shrink_order = getfield(n,"shrink_order")
+ local stretch = getfield(n,"stretch") / 65536
+ local shrink = getfield(n,"shrink") / 65536
+ local width = getfield(n,"width") / 65536
+ if stretch_order ~= 0 then
+ if shrink_order ~= 0 then
+ return f_f_f(width,stretch,fillorders[stretch_order],shrink,fillorders[shrink_order])
+ elseif shrink ~= 0 then
+ return f_f_m(width,stretch,fillorders[stretch_order],shrink)
+ else
+ return f_f_z(width,stretch,fillorders[stretch_order])
+ end
+ elseif shrink_order ~= 0 then
+ if stretch ~= 0 then
+ return f_p_f(width,stretch,shrink,fillorders[shrink_order])
+ else
+ return f_z_f(width,shrink,fillorders[shrink_order])
+ end
elseif stretch ~= 0 then
- plus = formatters[fmt](stretch*dimenfactors[unit],unit)
- plus = " plus " .. (strip and lpegmatch(stripper,plus) or plus)
- else
- plus = ""
- end
- if minus ~= 0 then
- minus = " minus " .. shrink/65536 .. fillcodes[minus]
+ if shrink ~= 0 then
+ return f_p_m(width,stretch,shrink)
+ else
+ return f_p_z(width,stretch)
+ end
elseif shrink ~= 0 then
- minus = formatters[fmt](shrink*dimenfactors[unit],unit)
- minus = " minus " .. (strip and lpegmatch(stripper,minus) or minus)
+ return f_z_m(width,shrink)
+ elseif width == 0 then
+ return "0pt"
else
- minus = ""
+ return f_z_z(width)
end
- local str = formatters[fmt](getfield(d,"width")*dimenfactors[unit],unit)
- return (strip and lpegmatch(stripper,str) or str) .. plus .. minus
end
-local function numbertodimen(d,unit,fmt,strip)
- if not d then
- local str = formatters[fmt](0,unit)
- return strip and lpegmatch(stripper,str) or str
- end
- local t = type(d)
- if t == 'string' then
- return d
- elseif t == "number" then
- if unit == true then
- unit = "pt"
- fmt = "%0.5f%s"
+
+-- number.todimen(123)
+-- number.todimen(123,"cm")
+-- number.todimen(123,false,"%F))
+
+local f_pt = formatters["%p"]
+local f_un = formatters["%F%s"]
+
+dimenfactors[""] = dimenfactors.pt
+
+local function numbertodimen(d,unit,fmt)
+ if not d or d == 0 then
+ if not unit or unit == "pt" then
+ return "0pt"
+ elseif fmt then
+ return formatters[fmt](0,unit)
else
- unit = unit or 'pt'
- if not fmt then
- fmt = "%s%s"
- elseif fmt == true then
- fmt = "%0.5f%s"
- end
+ return 0 .. unit
+ end
+ elseif fmt then
+ if not unit then
+ unit = "pt"
end
- local str = formatters[fmt](d*dimenfactors[unit],unit)
- return strip and lpegmatch(stripper,str) or str
+ return formatters[fmt](d*dimenfactors[unit],unit)
+ elseif not unit or unit == "pt" then
+ return f_pt(d)
else
- return nodetodimen(d,unit,fmt,strip) -- real node
+ return f_un(d*dimenfactors[unit],unit)
end
end
@@ -469,7 +568,7 @@ local points = function(n)
elseif type(n) == "number" then
return lpegmatch(stripper,format("%.5fpt",n*ptfactor)) -- faster than formatter
else
- return numbertodimen(n,"pt",true,true) -- also deals with nodes
+ return numbertodimen(n,"pt") -- also deals with nodes
end
end
@@ -479,7 +578,7 @@ local basepoints = function(n)
elseif type(n) == "number" then
return lpegmatch(stripper,format("%.5fbp",n*bpfactor)) -- faster than formatter
else
- return numbertodimen(n,"bp",true,true) -- also deals with nodes
+ return numbertodimen(n,"bp") -- also deals with nodes
end
end
@@ -489,7 +588,7 @@ local pts = function(n)
elseif type(n) == "number" then
return format("%.5fpt",n*ptfactor) -- faster than formatter
else
- return numbertodimen(n,"pt",true) -- also deals with nodes
+ return numbertodimen(n,"pt") -- also deals with nodes
end
end
@@ -506,10 +605,10 @@ number.basepoints = basepoints
number.pts = pts
number.nopts = nopts
-nodes.points = function(n) return numbertodimen(n,"pt",true,true) end
-nodes.basepoints = function(n) return numbertodimen(n,"bp",true,true) end
-nodes.pts = function(n) return numbertodimen(n,"pt",true) end
-nodes.nopts = function(n) return format("%.5f",n*ptfactor) end
+nodes.points = function(n) return numbertodimen(n,"pt") end
+nodes.basepoints = function(n) return numbertodimen(n,"bp") end
+nodes.pts = function(n) return numbertodimen(n,"pt") end
+nodes.nopts = function(n) return format("%.5f",n*ptfactor) end
local colors = { }
tracers.colors = colors
diff --git a/Master/texmf-dist/tex/context/base/node-tsk.lua b/Master/texmf-dist/tex/context/base/node-tsk.lua
index dfa570b2479..56a4b18ef24 100644
--- a/Master/texmf-dist/tex/context/base/node-tsk.lua
+++ b/Master/texmf-dist/tex/context/base/node-tsk.lua
@@ -117,6 +117,14 @@ function tasks.disableaction(name,action)
end
end
+function tasks.replaceaction(name,group,oldaction,newaction)
+ local data = valid(name)
+ if data then
+ sequencers.replaceaction(data.list,group,oldaction,newaction)
+ data.runner = false
+ end
+end
+
function tasks.setaction(name,action,value)
if value then
tasks.enableaction(name,action)
diff --git a/Master/texmf-dist/tex/context/base/pack-bck.mkvi b/Master/texmf-dist/tex/context/base/pack-bck.mkvi
index 72eafd282ee..bb4b72252a2 100644
--- a/Master/texmf-dist/tex/context/base/pack-bck.mkvi
+++ b/Master/texmf-dist/tex/context/base/pack-bck.mkvi
@@ -32,7 +32,7 @@
%D \starttyping
%D \setupbackground
%D [backgroundoffset=4pt,
-%D background=screen,
+%D background=color,
%D frame=on,
%D framecolor=red,
%D leftoffset=2pt]
@@ -206,14 +206,9 @@
\c!corner=\v!rectangular,
\c!frame=\v!off,
\c!depth=\zeropoint,
-% \c!color=,
-% \c!background=\v!screen,
-% \c!backgroundcolor=\backgroundparameter\c!color,
-% \c!screen=\defaultbackgroundscreen,
-%
+ % \c!color=,
\c!background=\v!color,
\c!backgroundcolor=lightgray,
-%
\c!before=,
\c!after=]
diff --git a/Master/texmf-dist/tex/context/base/pack-box.mkiv b/Master/texmf-dist/tex/context/base/pack-box.mkiv
index f8b36691c75..6e3bab6f498 100644
--- a/Master/texmf-dist/tex/context/base/pack-box.mkiv
+++ b/Master/texmf-dist/tex/context/base/pack-box.mkiv
@@ -24,10 +24,10 @@
%D which in itself is ok, but can lead to loops due to rounding errors (happened
%D in demo-obv).
-\definelayer[\v!text-2][\c!position=\v!yes,\c!region=,\c!width=\overlaywidth,\c!height=\overlayheight]
-\definelayer[\v!text-1][\c!position=\v!yes,\c!region=,\c!width=\overlaywidth,\c!height=\overlayheight]
-\definelayer[\v!text+1][\c!position=\v!yes,\c!region=,\c!width=\overlaywidth,\c!height=\overlayheight]
-\definelayer[\v!text+2][\c!position=\v!yes,\c!region=,\c!width=\overlaywidth,\c!height=\overlayheight]
+\definelayer[\v!text-2][\c!position=\v!yes,\c!region=,\c!width=\d_overlay_width,\c!height=\d_overlay_height]
+\definelayer[\v!text-1][\c!position=\v!yes,\c!region=,\c!width=\d_overlay_width,\c!height=\d_overlay_height]
+\definelayer[\v!text+1][\c!position=\v!yes,\c!region=,\c!width=\d_overlay_width,\c!height=\d_overlay_height]
+\definelayer[\v!text+2][\c!position=\v!yes,\c!region=,\c!width=\d_overlay_width,\c!height=\d_overlay_height]
\unexpanded\def\internaltextoverlay#1% will become more generic and installable
{\startoverlay % i.e. probably an overlay by itself
@@ -436,7 +436,7 @@
\def\pack_ornament_text[#1][#2]%
{\bgroup
- \doifassignmentelse{#1}
+ \doifelseassignment{#1}
{\letdummyparameter\c!alternative\v!a
\getdummyparameters[#1]%
\doifelse{\directdummyparameter\c!alternative}\v!a
@@ -552,7 +552,7 @@
%
\doifelse{\bleedingparameter\c!stretch}\v!yes\donetrue\donefalse
%
- \xdef\bleedwidth{\dimexpr
+ \xdef\bleedwidth{\the\dimexpr
\ifdone
\ifconditional\c_pack_boxes_l
\scratchwidth+\MPx\currentbgposition-\MPx\currentpageposition
@@ -563,8 +563,9 @@
\fi\fi
\else
\scratchwidth
- \fi+\scratchhoffset}%
- \xdef\bleedheight{\dimexpr
+ \fi+\scratchhoffset
+ \relax}%
+ \xdef\bleedheight{\the\dimexpr
\ifdone
\ifconditional\c_pack_boxes_t
\paperheight -\MPy\currentbgposition+\MPy\currentpageposition % not checked
@@ -575,7 +576,8 @@
\fi\fi
\else
\scratchheight
- \fi+\scratchvoffset}%
+ \fi+\scratchvoffset
+ \relax}%
\dowithnextboxcontentcs\pack_boxes_bleed_settings\pack_boxes_bleed_finish\hbox}
\def\pack_boxes_bleed_settings
@@ -678,7 +680,7 @@
\dowithnextboxcontent
{\forgetall
\hsize\directdummyparameter\c!width
- \normalexpanded{\setupalign[\directdummyparameter\c!align]}%
+ \usealignparameter\directdummyparameter
\dousestyleparameter{\directdummyparameter\c!style}}
{\setlayer[#1][#2]{\strut\dousecolorparameter{\directdummyparameter\c!color}\flushnextbox}% maybe expand the color
\egroup}%
@@ -977,22 +979,43 @@
\box\scratchbox
\egroup}
-% \backgroundimage{1}{\hsize}{\vsize}{\externalfigure[cow][\c!width=3cm]}
+% \backgroundimage{1}{\hsize}{\vsize}{\externalfigure[cow][\c!width=3cm]}
+
+% \framed[offset=overlay,width=6cm,height=3cm]{\backgroundimage {1}{\hsize}{\vsize}{\externalfigure[cow][width=1cm]}}
+% \framed[offset=overlay,width=6cm,height=3cm]{\backgroundimage {2}{\hsize}{\vsize}{\externalfigure[cow][width=1cm]}}
+% \framed[offset=overlay,width=6cm,height=3cm]{\backgroundimage {3}{\hsize}{\vsize}{\externalfigure[cow][width=1cm]}}
+
+% \framed[offset=overlay,width=4cm,height=2cm]{\backgroundimagefill{1}{\hsize}{\vsize}{\externalfigure[cow][width=1cm]}}
+% \framed[offset=overlay,width=4cm,height=2cm]{\backgroundimagefill{2}{\hsize}{\vsize}{\externalfigure[cow][width=1cm]}}
+% \framed[offset=overlay,width=4cm,height=2cm]{\backgroundimagefill{3}{\hsize}{\vsize}{\externalfigure[cow][width=1cm]}}
+% \framed[offset=overlay,width=2cm,height=4cm]{\backgroundimagefill{1}{\hsize}{\vsize}{\externalfigure[cow][width=1cm]}}
+% \framed[offset=overlay,width=2cm,height=4cm]{\backgroundimagefill{2}{\hsize}{\vsize}{\externalfigure[cow][width=1cm]}}
+% \framed[offset=overlay,width=2cm,height=4cm]{\backgroundimagefill{3}{\hsize}{\vsize}{\externalfigure[cow][width=1cm]}}
+%
+% \framed[offset=overlay,width=4cm,height=2cm]{\backgroundimagefill{1}{\hsize}{\vsize}{\externalfigure[mill]}}
+% \framed[offset=overlay,width=4cm,height=2cm]{\backgroundimagefill{2}{\hsize}{\vsize}{\externalfigure[mill]}}
+% \framed[offset=overlay,width=4cm,height=2cm]{\backgroundimagefill{3}{\hsize}{\vsize}{\externalfigure[mill]}}
+% \framed[offset=overlay,width=2cm,height=4cm]{\backgroundimagefill{1}{\hsize}{\vsize}{\externalfigure[mill]}}
+% \framed[offset=overlay,width=2cm,height=4cm]{\backgroundimagefill{2}{\hsize}{\vsize}{\externalfigure[mill]}}
+% \framed[offset=overlay,width=2cm,height=4cm]{\backgroundimagefill{3}{\hsize}{\vsize}{\externalfigure[mill]}}
\unexpanded\def\backgroundimage#1#2#3% repeat hsize vsize
{\bgroup
\forgetall
- \dowithnextbox{\pack_boxes_background_image{#1}{#2}{#3}}\hbox}
+ \scratchcounter#1\relax
+ \scratchwidth #2\relax
+ \scratchheight #3\relax
+ \dowithnextboxcs\pack_boxes_background_image\hbox}
-\def\pack_boxes_background_image#1#2#3%
+\def\pack_boxes_background_image
{\offinterlineskip
- \ifcase#1\relax
+ \ifcase\scratchcounter
% just one
\else
- \scratchdimen#2\divide\scratchdimen\wd\nextbox\scratchnx\scratchdimen\advance\scratchnx\plusone\relax
- \scratchdimen#3\divide\scratchdimen\ht\nextbox\scratchny\scratchdimen\advance\scratchny\plusone\relax
+ \scratchdimen\scratchwidth \divide\scratchdimen\wd\nextbox\scratchnx\scratchdimen\advance\scratchnx\plusone\relax
+ \scratchdimen\scratchheight\divide\scratchdimen\ht\nextbox\scratchny\scratchdimen\advance\scratchny\plusone\relax
% to be considered: methods
- \ifcase#1%
+ \ifcase\scratchcounter
\or % x and y
\setbox\nextbox\hbox{\dorecurse\scratchnx{\copy\nextbox}}%
\setbox\nextbox\vbox{\dorecurse\scratchny{\copy\nextbox\endgraf}}%
@@ -1002,13 +1025,59 @@
\setbox\nextbox\vbox{\dorecurse\scratchny{\copy\nextbox\endgraf}}%
\fi
\fi
- \ifdim\wd\nextbox>#2\relax
- \setbox\nextbox\hbox to #2{\hss\box\nextbox\hss}%
- \setbox\nextbox\hbox{\normalexpanded{\clip[\c!width=#2,\c!height=\the\ht\nextbox]{\box\nextbox}}}%
+ \ifdim\wd\nextbox>\scratchwidth
+ \setbox\nextbox\hbox to \scratchwidth{\hss\box\nextbox\hss}%
+ \setbox\nextbox\hbox{\normalexpanded{\clip[\c!width=\the\scratchwidth,\c!height=\the\ht\nextbox]{\box\nextbox}}}%
+ \fi
+ \ifdim\ht\nextbox>\scratchheight
+ \setbox\nextbox\vbox to \scratchheight{\vss\box\nextbox\vss}%
+ \setbox\nextbox\hbox{\normalexpanded{\clip[\c!width=\the\wd\nextbox,\c!height=\the\scratchheight]{\box\nextbox}}}%
+ \fi
+ \box\nextbox
+ \egroup}
+
+\unexpanded\def\backgroundimagefill#1#2#3% repeat hsize vsize
+ {\bgroup
+ \forgetall
+ \scratchcounter#1\relax
+ \scratchwidth #2\relax
+ \scratchheight #3\relax
+ \dowithnextboxcs\pack_boxes_background_image_fill\hbox}
+
+\def\pack_boxes_background_image_fill
+ {\offinterlineskip
+ \setbox\nextbox\hbox\bgroup
+ \ifdim\scratchwidth>\scratchheight
+ \scale[\c!width=\the\scratchwidth]{\box\nextbox}%
+ \else
+ \scale[\c!height=\the\scratchheight]{\box\nextbox}%
+ \fi
+ \egroup
+ \ifdim\wd\nextbox>\scratchwidth
+ \setbox\nextbox\hbox to \scratchwidth
+ {\ifcase\scratchcounter
+ \hss\box\nextbox\hss
+ \or
+ \box\nextbox\hss
+ \or
+ \hss\box\nextbox
+ \else
+ \hss\box\nextbox\hss
+ \fi}%
+ \setbox\nextbox\hbox{\normalexpanded{\clip[\c!width=\the\scratchwidth,\c!height=\the\ht\nextbox]{\box\nextbox}}}%
\fi
- \ifdim\ht\nextbox>#3\relax
- \setbox\nextbox\vbox to #3{\vss\box\nextbox\vss}%
- \setbox\nextbox\hbox{\normalexpanded{\clip[\c!width=\the\wd\nextbox,\c!height=#3]{\box\nextbox}}}%
+ \ifdim\ht\nextbox>\scratchheight
+ \setbox\nextbox\vbox to \scratchheight
+ {\ifcase\scratchcounter
+ \vss\box\nextbox\vss
+ \or
+ \box\nextbox\vss
+ \or
+ \vss\box\nextbox
+ \else
+ \vss\box\nextbox\vss
+ \fi}%
+ \setbox\nextbox\hbox{\normalexpanded{\clip[\c!width=\the\wd\nextbox,\c!height=\the\scratchheight]{\box\nextbox}}}%
\fi
\box\nextbox
\egroup}
diff --git a/Master/texmf-dist/tex/context/base/pack-com.mkiv b/Master/texmf-dist/tex/context/base/pack-com.mkiv
index 4ca77af1c45..b734d602858 100644
--- a/Master/texmf-dist/tex/context/base/pack-com.mkiv
+++ b/Master/texmf-dist/tex/context/base/pack-com.mkiv
@@ -178,7 +178,7 @@
\unexpanded\def\pack_common_caption_stop {\removeunwantedspaces\egroup}
\unexpanded\def\stopcombination
- {\bgroup\normalexpanded{\egroup{}\ctxcommand{ntimes("{}{}",\number\c_pack_combinations_n)}}% brr
+ {\bgroup\normalexpanded{\egroup{}\ntimes{{}{}}\c_pack_combinations_n}% brr
\dostoptagged
\egroup
\egroup}
@@ -191,19 +191,19 @@
\edef\currentcombination{#1}%
\edef\currentcombinationspec{#2}%
\ifx\currentcombinationspec\empty
- \doifassignmentelse{#1}%
+ \doifelseassignment{#1}%
{\let\currentcombination\empty
\setupcurrentcombination[#1]%
\edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}
- {\doifinstringelse{*}\currentcombination
+ {\doifelseinstring{*}\currentcombination
{\edef\currentcombinationspec{\currentcombination*\plusone*}%
\let\currentcombination\empty}
- {\doifnumberelse\currentcombination
+ {\doifelsenumber\currentcombination
{\edef\currentcombinationspec{\currentcombination*\plusone*}%
\let\currentcombination\empty}
{\edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}}}%
\else
- \doifassignmentelse{#2}%
+ \doifelseassignment{#2}%
{\setupcurrentcombination[#2]%
\edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}
{\edef\currentcombinationspec{\currentcombinationspec*\plusone*}}%
@@ -221,13 +221,12 @@
\edef\p_height {\combinationparameter\c!height}%
\edef\p_width {\combinationparameter\c!width}%
\edef\p_location{\combinationparameter\c!location}%
- \edef\p_align {\combinationparameter\c!align}%
\edef\p_distance{\combinationparameter\c!distance}%
%
\pack_combinations_location_reset
\rawprocesscommacommand[\p_location]\pack_combinations_location_step
%
- \dostarttagged\t!combination\currentcombination
+ \dostarttaggedchained\t!combination\currentcombination\??combination
\vbox \ifx\p_height\v!fit\else to \p_height \fi \bgroup
\let\combination\empty % permits \combination{}{} handy for cld
\normalexpanded{\pack_combinations_start_indeed[\currentcombinationspec]}}
@@ -295,7 +294,7 @@
\def\pack_combinations_alternative_label_indeed
{\dowithnextboxcs\pack_combinations_pickup_caption\vtop\bgroup
\hsize\wd\b_pack_combinations_content
- \ifx\p_align\empty\else\setupalign[\p_align]\fi
+ \usealignparameter\combinationparameter
\usecombinationstyleandcolor\c!style\c!color
\begstrut
\normalexpanded{\strc_labels_command{\v!combination\ifx\currentcombination\empty\else:\currentcombination\fi}}%
@@ -324,15 +323,18 @@
\def\pack_combinations_caption_second
{\ifx\nexttoken\egroup
% the caption is empty
+ \else\ifx\nexttoken\stopcaption
+ % the caption is empty (new per 2014-05-24)
\else
+ % todo: \p_pack_combinations_alternative\v!none: no style, strut etc
\hsize\wd\b_pack_combinations_content
- \ifx\p_align\empty\else\setupalign[\p_align]\fi
+ \usealignparameter\combinationparameter
\usecombinationstyleandcolor\c!style\c!color
\bgroup
\aftergroup\endstrut
\aftergroup\egroup
\begstrut
- \fi}
+ \fi\fi}
\def\pack_combinations_pickup_package_pair % we need to store the caption row
{\vbox
@@ -626,12 +628,12 @@
\unexpanded\def\placepairedbox[#1]%
{\bgroup
\edef\currentpairedbox{#1}%
- \doifnextoptionalcselse\pack_pairedboxes_place\pack_pairedboxes_place_indeed}
+ \doifelsenextoptionalcs\pack_pairedboxes_place\pack_pairedboxes_place_indeed}
\unexpanded\def\startplacepairedbox[#1]%
{\bgroup
\edef\currentpairedbox{#1}%
- \doifnextoptionalcselse\pack_pairedboxes_place\pack_pairedboxes_place_indeed}
+ \doifelsenextoptionalcs\pack_pairedboxes_place\pack_pairedboxes_place_indeed}
\unexpanded\def\stopplacepairedbox
{}
@@ -780,7 +782,7 @@
\fi}
\def\pack_pairedboxes_between
- {\switchtobodyfont[\pairedboxparameter\c!bodyfont]% split under same regime
+ {\usebodyfontparameter\pairedboxparameter
\setbox\b_pack_pairedboxes_first\box\nextbox
\ifconditional\c_pack_pairedboxes_horizontal
\pack_pairedboxes_between_horizontal
diff --git a/Master/texmf-dist/tex/context/base/pack-fen.mkiv b/Master/texmf-dist/tex/context/base/pack-fen.mkiv
index 4253eeaa76c..04a36fa462c 100644
--- a/Master/texmf-dist/tex/context/base/pack-fen.mkiv
+++ b/Master/texmf-dist/tex/context/base/pack-fen.mkiv
@@ -50,12 +50,12 @@
\else
\def\setinstalledframedimensions
- {\edef\overlaywidth {\the\frameddimenwd\space}%
- \edef\overlayheight {\the\dimexpr\frameddimenht+\frameddimendp\relax\space}%
- \edef\overlaydepth {\the\frameddimendp\space}%
+ {\d_overlay_width \frameddimenwd
+ \d_overlay_height \dimexpr\frameddimenht+\frameddimendp\relax
+ \d_overlay_depth \frameddimendp
+ \d_overlay_linewidth \ruledlinewidth
\edef\overlaycolor {\framedparameter\c!backgroundcolor}%
- \edef\overlaylinecolor{\framedparameter\c!framecolor}%
- \edef\overlaylinewidth{\the\ruledlinewidth}}
+ \edef\overlaylinecolor{\framedparameter\c!framecolor}}
\fi
@@ -63,7 +63,7 @@
\def\whateverleftframe#1%
{\setinstalledframedimensions
- \setbox\b_framed_rendered\vbox to \overlayheight{\vss#1\vss}%
+ \setbox\b_framed_rendered\vbox to \d_overlay_height{\vss#1\vss}%
\setbox\b_framed_rendered\hbox to \zeropoint{\box\b_framed_rendered\hss}%
\ht\b_framed_rendered\zeropoint
\dp\b_framed_rendered\zeropoint
@@ -71,7 +71,7 @@
\def\whateverrightframe#1%
{\setinstalledframedimensions
- \setbox\b_framed_rendered\vbox to \overlayheight{\vss#1\vss}%
+ \setbox\b_framed_rendered\vbox to \d_overlay_height{\vss#1\vss}%
\setbox\b_framed_rendered\hbox to \zeropoint{\hss\box\b_framed_rendered}%
\ht\b_framed_rendered\zeropoint
\dp\b_framed_rendered\zeropoint
@@ -79,7 +79,7 @@
\def\whatevertopframe#1%
{\setinstalledframedimensions
- \setbox\b_framed_rendered\hbox to \overlaywidth{\hss#1\hss}%
+ \setbox\b_framed_rendered\hbox to \d_overlay_width{\hss#1\hss}%
\setbox\b_framed_rendered\vbox to \zeropoint{\box\b_framed_rendered\vss}%
\ht\b_framed_rendered\zeropoint
\dp\b_framed_rendered\zeropoint
@@ -88,7 +88,7 @@
\def\whateverbottomframe#1%
{\setinstalledframedimensions
- \setbox\b_framed_rendered\hbox to \overlaywidth{\hss#1\hss}%
+ \setbox\b_framed_rendered\hbox to \d_overlay_width{\hss#1\hss}%
\setbox\b_framed_rendered\vbox to \zeropoint{\vss\box\b_framed_rendered}%
\ht\b_framed_rendered\zeropoint
\dp\b_framed_rendered\zeropoint
diff --git a/Master/texmf-dist/tex/context/base/pack-lyr.mkiv b/Master/texmf-dist/tex/context/base/pack-lyr.mkiv
index a891c998d4a..a847dec67be 100644
--- a/Master/texmf-dist/tex/context/base/pack-lyr.mkiv
+++ b/Master/texmf-dist/tex/context/base/pack-lyr.mkiv
@@ -101,9 +101,6 @@
\def\layeranchor{\currentlayer:\the\realpageno}
-\unexpanded\def\anch_mark_anchor_box#1%
- {\ctxcommand{markregionbox(\number#1,"\layeranchor")}} % needs an hbox
-
\let\p_pack_layers_doublesided\empty
\let\p_pack_layers_state \empty
\let\p_pack_layers_option \empty
@@ -229,7 +226,7 @@
\else\ifthirdargument
\pack_layers_set_indeed[#1][#2][#3]%
\else
- \doifassignmentelse{#2}
+ \doifelseassignment{#2}
{\pack_layers_set_indeed[#1][][#2]}%
{\pack_layers_set_indeed[#1][#2][]}%
\fi\fi}
@@ -323,7 +320,7 @@
{\dodoubleargument\pack_layers_define_preset}
\def\pack_layers_define_preset[#1][#2]%
- {\doifassignmentelse{#2}
+ {\doifelseassignment{#2}
{\setvalue{\??layerpreset#1}{\setupcurrentlayer[#2]}}
{\setvalue{\??layerpreset#1}{\csname\??layerpreset#2\endcsname}}}
@@ -510,6 +507,8 @@
\expandafter\secondoftwoarguments
\fi}
+\let\doiflayerdataelse\doifelselayerdata
+
%D \macros
%D {flushlayer}
%D
@@ -610,7 +609,7 @@
% {\setlayoutcomponentattribute{\v!layer:#2}}%
% \resetlayoutcomponentattribute
% \ifx\p_pack_layers_option\v!test \ruledvbox \else \vbox \fi \ifx\p_pack_layers_method\v!overlay to \overlayheight \fi \layoutcomponentboxattribute
-% {\hbox \ifx\p_pack_layers_method\v!overlay to \overlaywidth \fi
+% {\hbox \ifx\p_pack_layers_method\v!overlay to \d_overlay_width \fi
% {\edef\currentlayer{#2\the\realpageno}% local
% \edef\p_pack_layers_position{\layerparameter\c!position}% local
% \ifx\p_pack_layers_position\v!yes
@@ -669,15 +668,15 @@
\pack_layers_positioned_box_nop
\fi
% todo: method=offset => overlayoffset right/down (handy for backgrounds with offset)
- \doifoverlayelse{#2}%
+ \doifelseoverlay{#2}%
{\setlayoutcomponentattribute{\v!layer:#2}}%
\resetlayoutcomponentattribute
% we have conflicting demands: some mechanisms want ll anchoring .. I need to figure this out
% an dmaybe we will have 'origin=bottom' or so
\setbox\nextbox
- \ifx\p_pack_layers_option\v!test \ruledvbox \else \vbox \fi \ifx\p_pack_layers_method\v!overlay to \overlayheight \fi \layoutcomponentboxattribute
+ \ifx\p_pack_layers_option\v!test \ruledvbox \else \vbox \fi \ifx\p_pack_layers_method\v!overlay to \d_overlay_height \fi \layoutcomponentboxattribute
{\pack_layers_top_fill
- \hbox \ifx\p_pack_layers_method\v!overlay to \overlaywidth \fi
+ \hbox \ifx\p_pack_layers_method\v!overlay to \d_overlay_width \fi
{\box\nextbox
\hss}%
\pack_layers_bottom_fill}%
@@ -687,7 +686,7 @@
\ifx\p_pack_layers_position\v!yes
\edef\p_pack_layers_region{\layerparameter\c!region}%
\ifx\p_pack_layers_region\empty \else
- \anch_mark_anchor_box\nextbox
+ \anch_mark_tagged_box\nextbox\layeranchor
\fi
\fi
\box\nextbox
@@ -724,12 +723,20 @@
\unexpanded\def\composedlayer#1{\flushlayer[#1]}
+% \unexpanded\def\tightlayer[#1]%
+% {\hbox
+% {\def\currentlayer{#1}% todo: left/right
+% \setbox\nextbox\emptybox
+% \hsize\layerparameter\c!width
+% \vsize\layerparameter\c!height
+% \composedlayer{#1}}}
+
\unexpanded\def\tightlayer[#1]%
{\hbox
{\def\currentlayer{#1}% todo: left/right
- \setbox\nextbox\emptybox % hoogte/breedte are \wd\nextbox/\ht\nextbox
- \hsize\layerparameter\c!width % \overlaywidth = \hsize
- \vsize\layerparameter\c!height % \overlaywheight = \vsize
+ \setbox\nextbox\emptybox
+ \d_overlay_width \layerparameter\c!width
+ \d_overlay_height\layerparameter\c!height
\composedlayer{#1}}}
\let\placelayer\flushlayer
diff --git a/Master/texmf-dist/tex/context/base/pack-mis.mkvi b/Master/texmf-dist/tex/context/base/pack-mis.mkvi
index 38fcc18e419..420f9440a2f 100644
--- a/Master/texmf-dist/tex/context/base/pack-mis.mkvi
+++ b/Master/texmf-dist/tex/context/base/pack-mis.mkvi
@@ -46,7 +46,7 @@
\unexpanded\def\pack_placement#tag%
{\bgroup
\edef\currentplacement{#tag}%
- \doifnextoptionalcselse\pack_placement_yes\pack_placement_nop}
+ \doifelsenextoptionalcs\pack_placement_yes\pack_placement_nop}
\def\pack_placement_yes[#settings]%
{\setupcurrentplacement[#settings]%
@@ -67,6 +67,7 @@
%\ifinsidefloat \else
% \page_backgrounds_add_local_to_box\nextbox
%\fi
+\flushnotes % new per 2014-05-29 : todo: move them up in the mvl
\ifgridsnapping
\pack_placement_flush_grid_yes
\else
diff --git a/Master/texmf-dist/tex/context/base/pack-mrl.mkiv b/Master/texmf-dist/tex/context/base/pack-mrl.mkiv
index c0097cb5fa5..a97c9e6f8c8 100644
--- a/Master/texmf-dist/tex/context/base/pack-mrl.mkiv
+++ b/Master/texmf-dist/tex/context/base/pack-mrl.mkiv
@@ -40,7 +40,7 @@
\unexpanded\def\blackrule
{\hbox\bgroup
- \doifnextoptionalcselse\pack_black_rule_pickup\pack_black_rule_indeed}
+ \doifelsenextoptionalcs\pack_black_rule_pickup\pack_black_rule_indeed}
\def\pack_black_rule_pickup[#1]%
{\setupcurrentblackrules[#1]%
@@ -96,7 +96,7 @@
\unexpanded\def\blackrules % probably never used
{\hbox\bgroup
- \doifnextoptionalcselse\pack_black_rules_pickup\pack_black_rules_indeed}
+ \doifelsenextoptionalcs\pack_black_rules_pickup\pack_black_rules_indeed}
\def\pack_black_rules_pickup[#1]%
{\setupcurrentblackrules[#1]%
@@ -145,7 +145,8 @@
%D \showsetup{hl}
\unexpanded\def\pack_rule_vl_indeed#1#2#3%
- {\bgroup
+ {\dontleavehmode
+ \begingroup
\setbox\scratchbox\hbox
{\vrule
\s!width #1\linewidth
@@ -154,13 +155,14 @@
\dp\scratchbox\strutdp
\ht\scratchbox\strutht
\box\scratchbox
- \egroup}
+ \endgroup}
\def\pack_rule_vl[#1]%
{\pack_rule_vl_indeed{#1}{#1}{#1}}
\def\pack_rule_hl[#1]%
- {\hbox
+ {\dontleavehmode
+ \hbox
{\vrule
\s!width #1\emwidth
\s!height\linewidth
@@ -629,7 +631,7 @@
\def\pack_textrule_nop_indeed{\csname\??textrulealternatives\v!middle\endcsname}%
\csname\??textrulealternatives\v!top\endcsname{#1}%
\bgroup
- \doifsomething{\directtextrulesparameter\c!bodyfont}{\switchtobodyfont[\directtextrulesparameter\c!bodyfont]}}
+ \usebodyfontparameter\directtextrulesparameter}
\unexpanded\def\stoptextrule
{\par
diff --git a/Master/texmf-dist/tex/context/base/pack-obj.lua b/Master/texmf-dist/tex/context/base/pack-obj.lua
index 70876a34688..d1cc5bafc67 100644
--- a/Master/texmf-dist/tex/context/base/pack-obj.lua
+++ b/Master/texmf-dist/tex/context/base/pack-obj.lua
@@ -11,19 +11,21 @@ if not modules then modules = { } end modules ['pack-obj'] = {
reusable components.
--ldx]]--
-local commands, context = commands, context
+local context = context
-local allocate = utilities.storage.allocate
+local implement = interfaces.implement
-local collected = allocate()
-local tobesaved = allocate()
+local allocate = utilities.storage.allocate
-local jobobjects = {
+local collected = allocate()
+local tobesaved = allocate()
+
+local jobobjects = {
collected = collected,
tobesaved = tobesaved,
}
-job.objects = jobobjects
+job.objects = jobobjects
local function initializer()
collected = jobobjects.collected
@@ -32,45 +34,60 @@ end
job.register('job.objects.collected', tobesaved, initializer, nil)
-function jobobjects.save(tag,number,page)
+local function saveobject(tag,number,page)
local t = { number, page }
tobesaved[tag], collected[tag] = t, t
end
-function jobobjects.set(tag,number,page)
+local function setobject(tag,number,page)
collected[tag] = { number, page }
end
-function jobobjects.get(tag)
+local function getobject(tag)
return collected[tag] or tobesaved[tag]
end
-function jobobjects.number(tag,default)
+local function getobjectnumber(tag,default)
local o = collected[tag] or tobesaved[tag]
return o and o[1] or default
end
-function jobobjects.page(tag,default)
+local function getobjectpage(tag,default)
local o = collected[tag] or tobesaved[tag]
return o and o[2] or default
end
--- interface
+jobobjects.save = saveobject
+jobobjects.set = setobject
+jobobjects.get = getobject
+jobobjects.number = getobjectnumber
+jobobjects.page = getobjectpage
-commands.saveobject = jobobjects.save
-commands.setobject = jobobjects.set
+implement {
+ name = "saveobject",
+ actions = saveobject
+}
-function commands.objectnumber(tag,default)
- local o = collected[tag] or tobesaved[tag]
- context(o and o[1] or default)
-end
+implement {
+ name = "setobject",
+ actions = setobject,
+ arguments = { "string", "integer", "integer" }
+}
-function commands.objectpage(tag,default)
- local o = collected[tag] or tobesaved[tag]
- context(o and o[2] or default)
-end
+implement {
+ name = "objectnumber",
+ actions = { getobjectnumber, context },
+ arguments = { "string", "string" },
+}
-function commands.doifobjectreferencefoundelse(tag)
- commands.doifelse(collected[tag] or tobesaved[tag])
-end
+implement {
+ name = "objectpage",
+ actions = { getobjectpage, context },
+ arguments = { "string", "string" },
+}
+implement {
+ name = "doifelseobjectreferencefound",
+ actions = { jobobjects.get, commands.doifelse },
+ arguments = "string"
+}
diff --git a/Master/texmf-dist/tex/context/base/pack-obj.mkiv b/Master/texmf-dist/tex/context/base/pack-obj.mkiv
index 356a0b7ebf8..605dd3b9e5a 100644
--- a/Master/texmf-dist/tex/context/base/pack-obj.mkiv
+++ b/Master/texmf-dist/tex/context/base/pack-obj.mkiv
@@ -366,7 +366,7 @@
% no undefined test ! ! ! ! (pdftex fails on undefined objects)
\unexpanded\def\pack_objects_register_reference#1#2#3{\normalexpanded{\noexpand\ctxlatecommand{saveobject("#1::#2",#3,\noexpand\the\realpageno)}}}
-\unexpanded\def\pack_objects_overload_reference#1#2#3{\ctxcommand{setobject("#1::#2",#3,\the\realpageno)}}
+\unexpanded\def\pack_objects_overload_reference#1#2#3{\clf_setobject{#1::#2}#3 \realpageno\relax}
\unexpanded\def\dosetobjectreference
{\ifcase\crossreferenceobject
@@ -382,8 +382,8 @@
\def\defaultobjectreference#1#2{0} % driver dependent
\def\defaultobjectpage #1#2{\realfolio}
-\unexpanded\def\dogetobjectreference #1#2#3{\xdef#3{\ctxcommand{objectnumber("#1::#2","\defaultobjectreference{#1}{#2}")}}}
-\unexpanded\def\dogetobjectreferencepage#1#2#3{\xdef#3{\ctxcommand{objectpage("#1::#2","\defaultobjectpage{#1}{#2}")}}}
+\unexpanded\def\dogetobjectreference #1#2#3{\xdef#3{\clf_objectnumber{#1::#2}{\defaultobjectreference{#1}{#2}}}}
+\unexpanded\def\dogetobjectreferencepage#1#2#3{\xdef#3{\clf_objectpage {#1::#2}{\defaultobjectpage {#1}{#2}}}}
\unexpanded\def\setobject {\driverreferenced\pack_objects_set1}
\unexpanded\def\settightobject{\driverreferenced\pack_objects_set0}
@@ -399,14 +399,17 @@
%D \doifobjectreferencefoundelse{class}{object}{do then}{do else}
%D \stoptyping
-\unexpanded\def\doifobjectfoundelse#1#2%
+\unexpanded\def\doifelseobjectfound#1#2%
{\ifcsname\??objects#1::#2\endcsname
\expandafter\firstoftwoarguments
\else
\expandafter\secondoftwoarguments
\fi}
-\unexpanded\def\doifobjectreferencefoundelse#1#2%
- {\ctxcommand{doifobjectreferencefoundelse("#1::#2")}}
+\unexpanded\def\doifelseobjectreferencefound#1#2%
+ {\clf_doifelseobjectreferencefound{#1::#2}}
+
+\let\doifobjectfoundelse \doifelseobjectfound
+\let\doifobjectreferencefoundelse\doifelseobjectreferencefound
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/pack-pos.mkiv b/Master/texmf-dist/tex/context/base/pack-pos.mkiv
index f92ceb78ab2..c52c01ca4b9 100644
--- a/Master/texmf-dist/tex/context/base/pack-pos.mkiv
+++ b/Master/texmf-dist/tex/context/base/pack-pos.mkiv
@@ -62,7 +62,7 @@
\edef\currentpositioning{#1}%
\setupcurrentpositioning[#2]%
\else\iffirstargument
- \doifassignmentelse{#1}
+ \doifelseassignment{#1}
{\let\currentpositioning\empty
\setupcurrentpositioning[#1]}%
{\edef\currentpositioning{#1}}%
diff --git a/Master/texmf-dist/tex/context/base/pack-rul.lua b/Master/texmf-dist/tex/context/base/pack-rul.lua
index 0c29eb5f1dd..151642c3a1b 100644
--- a/Master/texmf-dist/tex/context/base/pack-rul.lua
+++ b/Master/texmf-dist/tex/context/base/pack-rul.lua
@@ -14,6 +14,12 @@ if not modules then modules = { } end modules ['pack-rul'] = {
-- challenge: adapt glue_set
-- setfield(h,"glue_set", getfield(h,"glue_set") * getfield(h,"width")/maxwidth -- interesting ... doesn't matter much
+-- \framed[align={lohi,middle}]{$x$}
+-- \framed[align={lohi,middle}]{$ $}
+-- \framed[align={lohi,middle}]{\hbox{ }}
+-- \framed[align={lohi,middle}]{\hbox{}}
+-- \framed[align={lohi,middle}]{$\hskip2pt$}
+
local type = type
local hlist_code = nodes.nodecodes.hlist
@@ -24,6 +30,8 @@ local line_code = nodes.listcodes.line
local texsetdimen = tex.setdimen
local texsetcount = tex.setcount
+local implement = interfaces.implement
+
local nuts = nodes.nuts
local getfield = nuts.getfield
@@ -39,7 +47,7 @@ local hpack = nuts.hpack
local traverse_id = nuts.traverse_id
local node_dimensions = nuts.dimensions
-function commands.doreshapeframedbox(n)
+local function doreshapeframedbox(n)
local box = getbox(n)
local noflines = 0
local firstheight = nil
@@ -91,7 +99,7 @@ function commands.doreshapeframedbox(n)
-- vdone = true
end
if not firstheight then
- -- done
+ -- done)
elseif maxwidth ~= 0 then
if hdone then
for h in traverse_id(hlist_code,list) do
@@ -117,6 +125,8 @@ function commands.doreshapeframedbox(n)
-- end
setfield(box,"width",maxwidth)
averagewidth = noflines > 0 and totalwidth/noflines or 0
+ else -- e.g. empty math {$ $} or \hbox{} or ...
+setfield(box,"width",0)
end
end
end
@@ -128,7 +138,7 @@ function commands.doreshapeframedbox(n)
texsetdimen("global","framedaveragewidth",averagewidth)
end
-function commands.doanalyzeframedbox(n)
+local function doanalyzeframedbox(n)
local box = getbox(n)
local noflines = 0
local firstheight = nil
@@ -156,6 +166,8 @@ function commands.doanalyzeframedbox(n)
texsetdimen("global","framedlastdepth",lastdepth or 0)
end
+implement { name = "doreshapeframedbox", actions = doreshapeframedbox, arguments = "integer" }
+implement { name = "doanalyzeframedbox", actions = doanalyzeframedbox, arguments = "integer" }
function nodes.maxboxwidth(box)
local boxwidth = getfield(box,"width")
diff --git a/Master/texmf-dist/tex/context/base/pack-rul.mkiv b/Master/texmf-dist/tex/context/base/pack-rul.mkiv
index 8fcf8f548d2..141d741cf8d 100644
--- a/Master/texmf-dist/tex/context/base/pack-rul.mkiv
+++ b/Master/texmf-dist/tex/context/base/pack-rul.mkiv
@@ -43,23 +43,23 @@
\def\pack_framed_setup_line_width[#1]%
{\assigndimension{#1}\linewidth{.2\points}{.4\points}{.6\points}}
-%D \macros
-%D {setupscreens}
-%D
-%D Sort of obsolete:
-%D
-%D \showsetup{setupscreens}
-
-\installcorenamespace{screens}
-
-\installsetuponlycommandhandler \??screens {screens}
-
-\appendtoks
- \edef\defaultbackgroundscreen{\directscreensparameter\c!screen}
-\to \everysetupscreens
-
-\setupscreens
- [\c!screen=.90] % was .95 but that's hardly visible
+% %D \macros
+% %D {setupscreens}
+% %D
+% %D Sort of obsolete:
+% %D
+% %D \showsetup{setupscreens}
+%
+% \installcorenamespace{screens}
+%
+% \installsetuponlycommandhandler \??screens {screens}
+%
+% \appendtoks
+% \edef\defaultbackgroundscreen{\directscreensparameter\c!screen}
+% \to \everysetupscreens
+%
+% \setupscreens
+% [\c!screen=.90] % was .95 but that's hardly visible
%D The parameter handler:
@@ -155,8 +155,6 @@
%\c!foregroundcolor=,
%\c!foregroundstyle=,
%\c!background=,
- %\c!backgroundscreen=,
- \c!backgroundscreen=\defaultbackgroundscreen,
%\c!backgroundcolor=,
\c!backgroundoffset=\zeropoint,
%\c!framecolor=,
@@ -238,7 +236,6 @@
\let\p_framed_lines \empty
\let\p_framed_empty \empty
\let\p_framed_backgroundcolor \empty
-\let\p_framed_backgroundscreen\empty
\let\p_framed_framecolor \empty
\let\p_framed_component \empty
\let\p_framed_region \empty
@@ -352,14 +349,14 @@
%D The oval box is drawn using a special macro, depending on
%D the driver in use.
-\def\pack_framed_background_box_gray % avoid black rules when no gray
- {\edef\p_framed_backgroundscreen{\framedparameter\c!backgroundscreen}%
- \ifx\p_framed_backgroundscreen\empty \else
- \pack_framed_background_box_gray_indeed
- \fi}
-
-\def\pack_framed_background_box_gray_indeed % can be more direct but who cares, just compatibility
- {\colored[s=\p_framed_backgroundscreen]{\pack_framed_filled_box}}
+% \def\pack_framed_background_box_gray % avoid black rules when no gray
+% {\edef\p_framed_backgroundscreen{\framedparameter\c!backgroundscreen}%
+% \ifx\p_framed_backgroundscreen\empty \else
+% \pack_framed_background_box_gray_indeed
+% \fi}
+%
+% \def\pack_framed_background_box_gray_indeed % can be more direct but who cares, just compatibility
+% {\colored[s=\p_framed_backgroundscreen]{\pack_framed_filled_box}}
%D It won't be a surprise that we not only provide gray boxes, but also colored
%D ones. Here it is:
@@ -429,14 +426,36 @@
%D
%D The resulting box is lowered to the right depth.
-\def\overlaywidth {\the\hsize\space} % We preset the variables
-\def\overlayheight {\the\vsize\space} % to some reasonable default
-\def\overlaydepth {0pt } % values. The attributes
-\let\overlayoffset \overlaydepth % of the frame can be (are)
-\let\overlaylinewidth \overlaydepth % set somewhere else.
+%def\overlaywidth {\the\hsize\space} % We preset the variables
+%def\overlayheight {\the\vsize\space} % to some reasonable default
+%def\overlaydepth {0pt } % values. The attributes
+%let\overlayoffset \overlaydepth % of the frame can be (are)
+%let\overlaylinewidth \overlaydepth % set somewhere else.
\let\overlaycolor \empty
\let\overlaylinecolor \empty
+\newdimen\d_overlay_width
+\newdimen\d_overlay_height
+\newdimen\d_overlay_depth
+\newdimen\d_overlay_offset
+\newdimen\d_overlay_linewidth
+
+% expandable ... in a future version the space will go (in my one can use Overlay*)
+
+\def\overlaywidth {\the\d_overlay_width \space} % We preset the variables
+\def\overlayheight {\the\d_overlay_height \space} % to some reasonable default
+\def\overlaydepth {\the\d_overlay_depth \space} % values.
+\def\overlayoffset {\the\d_overlay_offset \space} % of the frame can be (are)
+\def\overlaylinewidth {\the\d_overlay_linewidth\space} % set somewhere else.
+
+% public but kind of protected
+
+\def\usedoverlaywidth {\dimexpr\d_overlay_width \relax}
+\def\usedoverlayheight {\dimexpr\d_overlay_height \relax}
+\def\usedoverlaydepth {\dimexpr\d_overlay_depth \relax}
+\def\usedoverlayoffset {\dimexpr\d_overlay_offset \relax}
+\def\usedoverlaylinewidth{\dimexpr\d_overlay_linewidth\relax}
+
%D The next register is used to initialize overlays.
\newtoks\everyoverlay
@@ -452,8 +471,8 @@
\to \everyoverlay
\prependtoks
- \hsize\overlaywidth
- \vsize\overlayheight
+ \hsize\d_overlay_width
+ \vsize\d_overlay_height
\to \everyoverlay
\unexpanded\def\defineoverlay
@@ -475,8 +494,8 @@
\egroup
\setlayoutcomponentattribute{\v!overlay:#1}%
\setbox\scratchbox\hbox \layoutcomponentboxattribute
- {\kern -.5\dimexpr\wd\scratchbox-\d_framed_target_wd\relax % was \overlaywidth
- \raise-.5\dimexpr\ht\scratchbox-\d_framed_target_ht\relax % not \overlayheight !
+ {\kern -.5\dimexpr\wd\scratchbox-\d_framed_target_wd\relax % was \d_overlay_width
+ \raise-.5\dimexpr\ht\scratchbox-\d_framed_target_ht\relax % not \d_overlay_height !
\box\scratchbox}%
\wd\scratchbox\d_framed_target_wd
\ht\scratchbox\d_framed_target_ht
@@ -490,19 +509,21 @@
\unexpanded\def\overlayfakebox
{\hbox
{\setbox\scratchbox\emptyhbox
- \wd\scratchbox\overlaywidth
- \ht\scratchbox\overlayheight
+ \wd\scratchbox\d_overlay_width
+ \ht\scratchbox\d_overlay_height
\box\scratchbox}}
%D For testing we provide:
-\def\doifoverlayelse#1% only tests external overlays
+\def\doifelseoverlay#1% only tests external overlays
{\ifcsname\??overlay#1\endcsname
\expandafter\firstoftwoarguments
\else
\expandafter\secondoftwoarguments
\fi}
+\let\doifoverlayelse\doifelseoverlay
+
%D The content of the box will be (temporary) saved in a box. We also have an
%D extra box for backgrounds.
@@ -599,16 +620,28 @@
\hss
\egroup}}
+% \def\pack_framed_overlay_initialize_indeed
+% {\edef\overlaywidth {\the\d_framed_target_wd\space}%
+% \edef\overlayheight {\the\dimexpr\d_framed_target_ht+\d_framed_target_dp\relax\space}%
+% \edef\overlaydepth {\the\d_framed_target_dp\space}%
+% \edef\overlaycolor {\framedparameter\c!backgroundcolor}% let ?
+% \edef\overlaylinecolor{\framedparameter\c!framecolor}% only needed for layers
+% \edef\overlaylinewidth{\the\d_framed_linewidth\space}%
+% %\edef\overlaycorner {\framedparameter\c!backgroundcorner}%
+% %\edef\overlayradius {\framedparameter\c!backgroundradius}%
+% \edef\overlayoffset {\the\framedbackgroundoffset\space}% \backgroundoffset % we steal this one
+% \let\pack_framed_overlay_initialize\relax}
+
\def\pack_framed_overlay_initialize_indeed
- {\edef\overlaywidth {\the\d_framed_target_wd\space}%
- \edef\overlayheight {\the\dimexpr\d_framed_target_ht+\d_framed_target_dp\relax\space}%
- \edef\overlaydepth {\the\d_framed_target_dp\space}%
+ {\d_overlay_width \d_framed_target_wd
+ \d_overlay_height \dimexpr\d_framed_target_ht+\d_framed_target_dp\relax
+ \d_overlay_depth \d_framed_target_dp
+ \d_overlay_linewidth \d_framed_linewidth
+ \d_overlay_offset \framedbackgroundoffset\relax
\edef\overlaycolor {\framedparameter\c!backgroundcolor}% let ?
\edef\overlaylinecolor{\framedparameter\c!framecolor}% only needed for layers
- \edef\overlaylinewidth{\the\d_framed_linewidth\space}%
%\edef\overlaycorner {\framedparameter\c!backgroundcorner}%
%\edef\overlayradius {\framedparameter\c!backgroundradius}%
- \edef\overlayoffset {\the\framedbackgroundoffset\space}% \backgroundoffset % we steal this one
\let\pack_framed_overlay_initialize\relax}
%D One can explictly insert the foreground box. For that purpose we introduce the
@@ -778,6 +811,35 @@
\newcount\c_pack_framed_nesting
+% to be tested (slightly more efficient):
+%
+% \unexpanded\def\pack_frame_common % #1 #2
+% {\bgroup
+% \advance\c_pack_framed_nesting\plusone
+% \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
+% \edef\currentframed{>\the\c_pack_framed_nesting}%
+% \pack_framed_initialize
+% \bgroup
+% \doifnextoptionalcselse} % #1 #2
+%
+% \unexpanded\def\framed {\pack_frame_common\pack_framed_process_framed_pickup\pack_framed_process_indeed}
+% \unexpanded\def\startframed{\pack_frame_common\pack_framed_start_framed_pickup \pack_framed_start_indeed }
+%
+% \def\pack_framed_process_framed_pickup[#1]%
+% {\setupcurrentframed[#1]%
+% \pack_framed_process_indeed}
+%
+% \def\pack_framed_start_framed_pickup[#1]%
+% {\setupcurrentframed[#1]% here !
+% \secondargumenttrue % dirty trick
+% \pack_framed_start_framed_indeed}
+%
+% \def\pack_framed_start_framed_indeed
+% {\pack_framed_process_indeed
+% \bgroup}
+%
+% no longer .. we also accept \startframed[tag]
+
\unexpanded\def\pack_framed_process_framed[#1]%
{\bgroup
\iffirstargument % faster
@@ -793,20 +855,63 @@
\pack_framed_initialize
\dosingleempty\pack_framed_process_framed}
+% \unexpanded\def\startframed
+% {\dosingleempty\pack_framed_start_framed}
+%
+% \def\pack_framed_start_framed[#1]%
+% {\bgroup
+% \advance\c_pack_framed_nesting\plusone
+% \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
+% \edef\currentframed{>\the\c_pack_framed_nesting}%
+% \pack_framed_initialize
+% \bgroup
+% \iffirstargument
+% \secondargumenttrue % dirty trick
+% \setupcurrentframed[#1]% here !
+% \fi
+% \pack_framed_process_indeed
+% \bgroup
+% \ignorespaces}
+
\unexpanded\def\startframed
{\dosingleempty\pack_framed_start_framed}
\def\pack_framed_start_framed[#1]%
{\bgroup
- \advance\c_pack_framed_nesting\plusone
+ \doifelseassignment{#1}\pack_framed_start_framed_yes\pack_framed_start_framed_nop{#1}}
+
+\def\pack_framed_start_framed_yes#1%
+ {\advance\c_pack_framed_nesting\plusone
\expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
\iffirstargument\secondargumenttrue\fi % dirty trick
\edef\currentframed{>\the\c_pack_framed_nesting}%
\pack_framed_initialize
- \pack_framed_process_framed[#1]% can be inlined
- \bgroup}
+ \bgroup
+ \iffirstargument
+ \secondargumenttrue % dirty trick
+ \setupcurrentframed[#1]% here !
+ \fi
+ \pack_framed_process_indeed
+ \bgroup
+ \ignorespaces}
+
+\def\pack_framed_start_framed_nop#1%
+ {\edef\currentframed{#1}%
+ \dosingleempty\pack_framed_start_framed_nop_indeed}
+
+\def\pack_framed_start_framed_nop_indeed[#1]%
+ {\pack_framed_initialize
+ \bgroup
+ \setupcurrentframed[#1]% here !
+ \pack_framed_process_indeed
+ \bgroup
+ \ignorespaces}
+
+% till here
-\let\stopframed\egroup
+\unexpanded\def\stopframed
+ {\removeunwantedspaces
+ \egroup}
\unexpanded\def\normalframedwithsettings[#1]%
{\bgroup
@@ -1304,10 +1409,19 @@
\def\pack_framed_restart
{\aftergroup\pack_framed_finish}
-\def\pack_framed_do_top {\raggedtopcommand\framedparameter\c!top}
-\def\pack_framed_do_bottom{\framedparameter\c!bottom\raggedbottomcommand}
+\def\pack_framed_do_top
+ {\raggedtopcommand
+ \framedparameter\c!top
+ \edef\p_blank{\framedparameter\c!blank}%
+ \ifx\p_blank\v!yes\else % auto or no
+ \doinhibitblank
+ \fi}
+
+\def\pack_framed_do_bottom
+ {\framedparameter\c!bottom
+ \raggedbottomcommand}
-%D Carefull analysis of this macro will learn us that not all branches in the last
+%D Careful analysis of this macro will learn us that not all branches in the last
%D conditionals can be encountered, that is, some assignments to \type{\next} will
%D never occur. Nevertheless we implement the whole scheme, if not for future
%D extensions.
@@ -1385,7 +1499,7 @@
\fi}
\unexpanded\def\pack_framed_finish
- {\pack_framed_stop_orientation % hm, wrong place ! should rotate the result (after reshape)
+ {%\pack_framed_stop_orientation % hm, wrong place ! should rotate the result (after reshape) .. moved down
\pack_framed_locator_before\p_framed_location
\ifconditional\c_framed_has_format
\ifx\p_framed_autowidth\v!force
@@ -1417,6 +1531,7 @@
\ifx\p_framed_empty\v!yes
\pack_framed_fake_box
\fi
+ \pack_framed_stop_orientation % moved here at 2014-05-25
\iftrialtypesetting \else
\edef\p_framed_region{\framedparameter\c!region}%
\ifx\p_framed_region\v!yes % maybe later named
@@ -1910,10 +2025,10 @@
%D \stoplinecorrection
%D
%D \startbuffer
-%D \framed[strut=nee,offset=.5cm] {rule based learning}
-%D \framed[strut=nee,offset=0cm] {rule based learning}
-%D \framed[strut=nee,offset=none] {rule based learning}
-%D \framed[strut=nee,offset=overlay]{rule based learning}
+%D \framed[strut=no,offset=.5cm] {rule based learning}
+%D \framed[strut=no,offset=0cm] {rule based learning}
+%D \framed[strut=no,offset=none] {rule based learning}
+%D \framed[strut=no,offset=overlay]{rule based learning}
%D \stopbuffer
%D
%D \typebuffer
@@ -1923,9 +2038,9 @@
%D \stoplinecorrection
%D
%D \startbuffer
-%D \framed[width=3cm,align=left] {rule\\based\\learning}
-%D \framed[width=3cm,align=middle] {rule\\based\\learning}
-%D \framed[width=3cm,align=right] {rule\\based\\learning}
+%D \framed[width=3cm,align=left] {rule\\based\\learning}
+%D \framed[width=3cm,align=middle] {rule\\based\\learning}
+%D \framed[width=3cm,align=right] {rule\\based\\learning}
%D \framed[width=fit,align=middle] {rule\\based\\learning}
%D \stopbuffer
%D
@@ -1992,7 +2107,6 @@
% \vbox{\hbox{x}}
% \stopTEXpage
-
% \def\pack_framed_forgetall{\forgetall}
\def\pack_framed_set_foregroundcolor
@@ -2008,7 +2122,7 @@
{\vbox to \d_framed_height
\bgroup
\let\postprocessframebox\relax
-% \pack_framed_forgetall
+ % \pack_framed_forgetall
\iftrialtypesetting \else
\pack_framed_set_foregroundcolor
\fi
@@ -2019,7 +2133,7 @@
\raggedcommand
\pack_framed_do_top
\bgroup
-\synchronizeinlinedirection
+ \synchronizeinlinedirection
\localbegstrut
\aftergroup\localendstrut
\aftergroup\pack_framed_do_bottom
@@ -2030,7 +2144,7 @@
{\vbox to \d_framed_height
\bgroup
\let\postprocessframebox\relax
-% \pack_framed_forgetall
+ % \pack_framed_forgetall
\iftrialtypesetting \else
\pack_framed_set_foregroundcolor
\fi
@@ -2041,7 +2155,7 @@
\raggedcenter
\vss
\bgroup
-\synchronizeinlinedirection
+ \synchronizeinlinedirection
\localbegstrut
\aftergroup\localendstrut
\aftergroup\vss
@@ -2052,7 +2166,7 @@
{\vbox to \d_framed_height
\bgroup
\let\postprocessframebox\relax
-% \pack_framed_forgetall
+ % \pack_framed_forgetall
\iftrialtypesetting \else
\pack_framed_set_foregroundcolor
\fi
@@ -2064,7 +2178,7 @@
\aftergroup\localendstrut
\aftergroup\vss
\aftergroup\egroup
-\synchronizeinlinedirection
+ \synchronizeinlinedirection
\localbegstrut
\doformatonelinerbox}
@@ -2072,7 +2186,7 @@
{\vbox
\bgroup
\let\postprocessframebox\relax
-% \pack_framed_forgetall
+ % \pack_framed_forgetall
\iftrialtypesetting \else
\pack_framed_set_foregroundcolor
\fi
@@ -2082,7 +2196,7 @@
\raggedcommand
\pack_framed_do_top
\bgroup
-\synchronizeinlinedirection
+ \synchronizeinlinedirection
\localbegstrut
\aftergroup\localendstrut
\aftergroup\pack_framed_do_bottom
@@ -2093,7 +2207,7 @@
{\vbox to \d_framed_height
\bgroup
\let\postprocessframebox\relax
-% \pack_framed_forgetall
+ % \pack_framed_forgetall
\iftrialtypesetting \else
\pack_framed_set_foregroundcolor
\fi
@@ -2106,7 +2220,7 @@
\hbox
\bgroup
\aftergroup\egroup
-\synchronizeinlinedirection
+ \synchronizeinlinedirection
\localstrut
\doformatonelinerbox}
@@ -2114,13 +2228,13 @@
{\hbox to \d_framed_width
\bgroup
\let\postprocessframebox\relax
-% \pack_framed_forgetall
+ % \pack_framed_forgetall
\iftrialtypesetting \else
\pack_framed_set_foregroundcolor
\fi
\pack_framed_do_setups
\hss
-\synchronizeinlinedirection
+ \synchronizeinlinedirection
\localstrut
\bgroup
\aftergroup\hss
@@ -2135,7 +2249,7 @@
\fi
\let\postprocessframebox\relax
\pack_framed_do_setups
-\synchronizeinlinedirection
+ \synchronizeinlinedirection
\localstrut
\doformatonelinerbox}
@@ -2215,8 +2329,8 @@
\framedmaxwidth \zeropoint
\framedaveragewidth\zeropoint}
-\def\pack_framed_reshape_process{\ifvbox\b_framed_normal\ctxcommand{doreshapeframedbox(\number\b_framed_normal)}\fi}
-\def\pack_framed_reshape_analyze{\ifvbox\b_framed_normal\ctxcommand{doanalyzeframedbox(\number\b_framed_normal)}\fi}
+\def\pack_framed_reshape_process{\ifvbox\b_framed_normal\clf_doreshapeframedbox\b_framed_normal\relax\fi}
+\def\pack_framed_reshape_analyze{\ifvbox\b_framed_normal\clf_doanalyzeframedbox\b_framed_normal\relax\fi}
% torture test / strange case (much depth) / method 2 needed
%
@@ -2514,7 +2628,6 @@
%\c!foregroundstyle=,
%\c!background=,
%\c!backgroundcolor=,
- \c!backgroundscreen=\defaultbackgroundscreen,
\c!linecorrection=\v!on,
\c!depthcorrection=\v!on,
\c!margin=\v!standard]
@@ -2544,7 +2657,7 @@
\dodoubleempty\pack_framed_text_start_indeed}
\def\pack_framed_text_start_indeed[#1][#2]%
- {\doifassignmentelse{#1}
+ {\doifelseassignment{#1}
{\pack_framed_text_start_continue\empty{#1}}
{\pack_framed_text_start_continue{#1}{#2}}}
@@ -2559,7 +2672,7 @@
\startboxedcontent
\hsize\localhsize
% \insidefloattrue % ? better
- \normalexpanded{\switchtobodyfont[\framedtextparameter\c!bodyfont]}%
+ \usebodyfontparameter\framedtextparameter
\letframedtextparameter\c!strut\v!no
\inheritedframedtextframed\bgroup
\let\\=\endgraf
@@ -2570,9 +2683,9 @@
\else
\bgroup
\fi
-\vskip-\strutdp % brrr why is this needed ... needs to be sorted out, see testcase 1
+ \vskip-\strutdp % brrr why is this needed ... needs to be sorted out, see testcase 1
\doinhibitblank
- \setupindenting[\framedtextparameter\c!indenting]%
+ \useindentingparameter\framedtextparameter
\useframedtextstyleandcolor\c!style\c!color
\ignorespaces}
@@ -2675,7 +2788,7 @@
\dosingleempty\pack_framed_text_start_direct}
\def\pack_framed_text_start_direct[#1]%
- {\normalexpanded{\switchtobodyfont[\framedtextparameter\c!bodyfont]}%
+ {\usebodyfontparameter\framedtextparameter
\letframedtextparameter\c!strut\v!no
\iffirstargument
\setupcurrentframedtext[#1]%
diff --git a/Master/texmf-dist/tex/context/base/page-app.mkiv b/Master/texmf-dist/tex/context/base/page-app.mkiv
index e4858d48ffb..2e81f75371f 100644
--- a/Master/texmf-dist/tex/context/base/page-app.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-app.mkiv
@@ -139,6 +139,9 @@
[TEXpage]
[\c!align=\v!normal] % needed, else problems !
+\unexpanded\def\setupTEXpage
+ {\setupfittingpage[TEXpage]}
+
%D For Mojca:
%D
%D \starttyping
diff --git a/Master/texmf-dist/tex/context/base/page-bck.mkiv b/Master/texmf-dist/tex/context/base/page-bck.mkiv
index 0246e8eb61b..01de48e8cda 100644
--- a/Master/texmf-dist/tex/context/base/page-bck.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-bck.mkiv
@@ -55,7 +55,7 @@
%D This is the only spot where we hav ea low level dependency on the way
%D parent chains are defined but we want the speed.
-\def\page_backgrounds_check_background
+\unexpanded\def\page_backgrounds_check_background
{\ifcsname\??framed\currentotrbackground:\c!background\endcsname
\edef\page_background_temp{\csname\??framed\currentotrbackground:\c!background\endcsname}%
\ifx\page_background_temp\empty
@@ -140,13 +140,15 @@
{\edef\currentotrbackground{\??layoutbackgrounds#1}%
\page_backgrounds_check_background}
-\def\doifsomebackgroundelse#1%
+\def\doifelsesomebackground#1%
{\ifcsname\??layoutbackgrounds#1\endcsname
\expandafter\firstoftwoarguments
\else
\expandafter\secondoftwoarguments
\fi}
+\let\doifsomebackgroundelse\doifelsesomebackground
+
\def\doifsomebackground#1%
{\ifcsname\??layoutbackgrounds#1\endcsname
\expandafter\firstofoneargument
@@ -277,7 +279,7 @@
\page_backgrounds_set_boxes
\setbox#1\vbox
{\offinterlineskip
- \doifmarginswapelse{\copy\leftbackground}{\copy\rightbackground}%
+ \doifelsemarginswap{\copy\leftbackground}{\copy\rightbackground}%
\box#1}%
\fi}
@@ -343,7 +345,7 @@
{\dontcomplain
\swapmargins
\ifconditional\swapbackgroundmargins
- \doifmarginswapelse \donothing
+ \doifelsemarginswap \donothing
{\swapmacros\v!rightmargin\v!leftmargin
\swapmacros\v!rightedge \v!leftedge}%
\fi
@@ -501,7 +503,7 @@
\unexpanded\def\page_backgrounds_setup_double[#1][#2][#3]% if needed we can speed this up
{\global\settrue\c_page_backgrounds_some
\def\page_backgrounds_setup_step##1%
- {\doifinsetelse{##1}\v_page_backgrounds_double_set
+ {\doifelseinset{##1}\v_page_backgrounds_double_set
{\page_backgrounds_setup_and_check{##1}{#3}}
{\def\page_backgrounds_setup_step_nested####1{\page_backgrounds_setup_and_check{##1####1}{#3}}%
\processcommacommand[#2]\page_backgrounds_setup_step_nested}}%
@@ -510,7 +512,7 @@
\unexpanded\def\page_backgrounds_setup_single[#1][#2][#3]%
{\global\settrue\c_page_backgrounds_some
- \doifcommonelse{#1}\v_page_backgrounds_single_set
+ \doifelsecommon{#1}\v_page_backgrounds_single_set
{\def\page_backgrounds_setup_step##1{\page_backgrounds_setup_and_check{##1}{#2}}%
\processcommacommand[#1]\page_backgrounds_setup_step
\the\everybackgroundssetup}%
@@ -607,6 +609,48 @@
\setfalse\c_page_backgrounds_some
+%D Sometimes you have a document wide (page) background but need to overload it
+%D locally. In such case (at least in my experience) the only values that get set
+%D are the background and backgroundcolor (if set at all). A full inheritance chain
+%D would complicate things because then we need to use named backgrounds which in
+%D turn will make this mechanism slower. I considered independent local backgrounds
+%D but that also complicates the code (not that much) but isolation means that we
+%D need to set more parameters each time. The following simple approach proabbly
+%D suits most usage.
+%D
+%D \starttyping
+%D \starttext
+%D \setupbackgrounds[page][background=color,backgroundcolor=red]
+%D \input tufte \page
+%D \setupbackgrounds[page][background=,backgroundcolor=]
+%D \input tufte \page
+%D \setupbackgrounds[page][background=color,backgroundcolor=red]
+%D \input tufte \page
+%D \pushbackground[page]
+%D \setupbackgrounds[page][background=color,backgroundcolor=green]
+%D \input tufte \page
+%D \popbackground
+%D \input tufte \page
+%D \stoptext
+%D \stoptyping
+
+\unexpanded\def\pushbackground[#1]%
+ {\pushmacro\popbackground
+ \edef\currentotrbackground{\??layoutbackgrounds#1}%
+ \unexpanded\edef\popbackground
+ {\setupframed
+ [\currentotrbackground]
+ [\c!background=\namedframedparameter{\currentotrbackground}\c!background,
+ \c!backgroundcolor=\namedframedparameter{\currentotrbackground}\c!backgroundcolor]%
+ \page_backgrounds_check_background
+ \popmacro\popbackground}%
+ \setupframed
+ [\currentotrbackground]
+ [\c!background=,\c!backgroundcolor=]%
+ \page_backgrounds_check_background}
+
+\let\popbackground\relax
+
\protect \endinput
% %D The next series is used in local (for instance floating) backgrounds.
diff --git a/Master/texmf-dist/tex/context/base/page-brk.mkiv b/Master/texmf-dist/tex/context/base/page-brk.mkiv
index 11dc04bfda5..f9c93305293 100644
--- a/Master/texmf-dist/tex/context/base/page-brk.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-brk.mkiv
@@ -112,13 +112,13 @@
\endgroup
\fi}
-\def\resetpagebreak % used elsewhere too
+\unexpanded\def\resetpagebreak % used elsewhere too
{\global\settrue\c_page_breaks_enabled}
-\def\simplifypagebreak % to be used grouped !
+\unexpanded\def\simplifypagebreak % to be used grouped !
{\def\page_breaks_process[##1]{\goodbreak}}
-\def\disablepagebreaks % to be used grouped !
+\unexpanded\def\disablepagebreaks % to be used grouped !
{\def\page_breaks_process[##1]{}}
\installpagebreakmethod \s!dummy
@@ -134,11 +134,11 @@
\endgroup}
\installpagebreakmethod \s!unknown
- {\doifinstringelse{+}\page_breaks_current_option
+ {\doifelseinstring{+}\page_breaks_current_option
{\page_otr_flush_all_floats
\page_otr_command_next_page
\dorecurse\page_breaks_current_option\page_otr_insert_dummy_page}
- {\doifnumberelse\page_breaks_current_option
+ {\doifelsenumber\page_breaks_current_option
{\page_otr_flush_all_floats
\page_otr_command_next_page
\doloop
@@ -178,6 +178,8 @@
\global\pageornamentstate\plusone
\fi}
+% also needed: \page \doifoddpageelse\relax{\page[\v!blank,\v!right]
+
\installpagebreakmethod \v!no
{\ifconditional\c_page_breaks_enabled
\dosomebreak\nobreak
@@ -220,11 +222,11 @@
\installpagebreakmethod \v!even
{\page
- \doifoddpageelse\page_reset_marks_and_insert_dummy\donothing}
+ \doifelseoddpage\page_reset_marks_and_insert_dummy\donothing}
\installpagebreakmethod \v!odd
{\page
- \doifoddpageelse\donothing\page_reset_marks_and_insert_dummy}
+ \doifelseoddpage\donothing\page_reset_marks_and_insert_dummy}
\installpagebreakmethod \v!quadruple % not yet ok inside columnsets
{\ifdoublesided
diff --git a/Master/texmf-dist/tex/context/base/page-flt.lua b/Master/texmf-dist/tex/context/base/page-flt.lua
index 7b1afc55cf3..e91285d0a64 100644
--- a/Master/texmf-dist/tex/context/base/page-flt.lua
+++ b/Master/texmf-dist/tex/context/base/page-flt.lua
@@ -242,10 +242,14 @@ function floats.checkedpagefloat(packed)
end
end
-function floats.nofstacked()
+function floats.nofstacked(which)
return #stacks[which or default] or 0
end
+function floats.hasstacked(which)
+ return (#stacks[which or default] or 0) > 0
+end
+
-- todo: check for digits !
local method = C((1-S(", :"))^1)
@@ -273,27 +277,101 @@ end
-- interface
-local context = context
-local context_setvalue = context.setvalue
-
-commands.flushfloat = floats.flush
-commands.savefloat = floats.save
-commands.resavefloat = floats.resave
-commands.pushfloat = floats.push
-commands.popfloat = floats.pop
-commands.consultfloat = floats.consult
-commands.collectfloat = floats.collect
-
-function commands.getfloatvariable (...) local v = floats.getvariable(...) if v then context(v) end end
-function commands.checkedpagefloat (...) local v = floats.checkedpagefloat(...) if v then context(v) end end
-
-function commands.nofstackedfloats (...) context(floats.nofstacked(...)) end
-function commands.doifelsesavedfloat(...) commands.doifelse(floats.nofstacked(...)>0) end
-
-function commands.analysefloatmethod(str) -- currently only one method
- local method, label, row, column = floats.analysemethod(str)
- context_setvalue("floatmethod",method or "")
- context_setvalue("floatlabel", label or "")
- context_setvalue("floatrow", row or "")
- context_setvalue("floatcolumn",column or "")
-end
+local context = context
+local commands = commands
+local implement = interfaces.implement
+local setmacro = interfaces.setmacro
+
+implement {
+ name = "flushfloat",
+ actions = floats.flush,
+ arguments = { "string", "integer" },
+}
+
+implement {
+ name = "flushlabeledfloat",
+ actions = floats.flush,
+ arguments = { "string", "string", true },
+}
+
+implement {
+ name = "savefloat",
+ actions = floats.save,
+ arguments = "string"
+}
+
+implement {
+ name = "savespecificfloat",
+ actions = floats.save,
+ arguments = {
+ "string",
+ {
+ { "specification" },
+ { "label" },
+ }
+ }
+}
+
+implement {
+ name = "resavefloat",
+ actions = floats.resave,
+ arguments = "string"
+}
+
+implement {
+ name = "pushfloat",
+ actions = floats.push
+}
+
+implement {
+ name = "popfloat",
+ actions = floats.pop
+}
+
+implement {
+ name = "consultfloat",
+ actions = floats.consult,
+ arguments = "string",
+}
+
+implement {
+ name = "collectfloat",
+ actions = floats.collect,
+ arguments = { "string", "dimen", "dimen" }
+}
+
+implement {
+ name = "getfloatvariable",
+ actions = { floats.getvariable, context },
+ arguments = "string"
+}
+
+implement {
+ name = "checkedpagefloat",
+ actions = { floats.checkedpagefloat, context },
+ arguments = "string"
+}
+
+implement {
+ name = "nofstackedfloats",
+ actions = { floats.nofstacked, context },
+ arguments = "string"
+}
+
+implement {
+ name = "doifelsestackedfloats",
+ actions = { floats.hasstacked, commands.doifelse },
+ arguments = "string"
+}
+
+implement {
+ name = "analysefloatmethod",
+ actions = function(str)
+ local method, label, row, column = floats.analysemethod(str)
+ setmacro("floatmethod",method or "")
+ setmacro("floatlabel", label or "")
+ setmacro("floatrow", row or "")
+ setmacro("floatcolumn",column or "")
+ end,
+ arguments = "string"
+}
diff --git a/Master/texmf-dist/tex/context/base/page-flt.mkiv b/Master/texmf-dist/tex/context/base/page-flt.mkiv
index d641e1c7d94..16c42713970 100644
--- a/Master/texmf-dist/tex/context/base/page-flt.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-flt.mkiv
@@ -83,49 +83,49 @@
\to \everyfloatscheck
\unexpanded\def\page_floats_flush#1#2%
- {\ctxcommand{flushfloat("#1",\number#2)}%
+ {\clf_flushfloat{#1}#2\relax
\the\everyfloatscheck}
\unexpanded\def\page_floats_flush_by_label#1#2%
- {\ctxcommand{flushfloat("#1","#2",true)}%
+ {\clf_flushlabeledfloat{#1}{#2}\relax
\the\everyfloatscheck}
\unexpanded\def\page_floats_save#1%
- {\ctxcommand{savefloat("#1")}%
+ {\clf_savefloat{#1}\relax
\the\everyfloatscheck}
\unexpanded\def\page_floats_resave#1%
- {\ctxcommand{resavefloat("#1")}%
+ {\clf_resavefloat{#1}\relax
\the\everyfloatscheck}
\unexpanded\def\page_floats_push_saved
- {\ctxcommand{pushfloat()}%
+ {\clf_pushfloat
\the\everyfloatscheck}
\unexpanded\def\page_floats_pop_saved
- {\ctxcommand{popfloat()}%
+ {\clf_popfloat
\the\everyfloatscheck}
\unexpanded\def\page_floats_get_info#1%
- {\ctxcommand{consultfloat("#1")}}
+ {\clf_consultfloat{#1}}
\unexpanded\def\page_floats_if_else#1%
- {\ctxcommand{doifelsesavedfloat("#1")}}
+ {\clf_doifelsestackedfloats{#1}}
\unexpanded\def\page_floats_collect#1#2#3%
- {\ctxcommand{collectfloat("#1",\number\dimexpr#2,\number\dimexpr#3)}}
+ {\clf_collectfloat{#1}\dimexpr#2\relax\dimexpr#3\relax}
-\unexpanded\def\nofstackedfloatincategory#1%
- {\ctxcommand{nofstackedfloats("#1")}}
+\def\nofstackedfloatincategory#1%
+ {\clf_nofstackedfloats{#1}}
\let\page_floats_column_push_saved\page_floats_push_saved % overloaded in page-mul
\let\page_floats_column_pop_saved \page_floats_pop_saved % overloaded in page-mul
\unexpanded\def\page_floats_save_page_float#1#2%
- {\ctxcommand{savefloat("#1", { specification = "#2" })}}
+ {\clf_savespecificfloat{#1}{specification{#2}}\relax}
\unexpanded\def\page_floats_save_somewhere_float#1#2% #1=method
- {\ctxcommand{savefloat("#1", { specification = "#2", label = "\floatlabel" })}}
+ {\clf_savespecificfloat{#1}{specification{#2}label{\floatlabel}}\relax}
%D This is an experimental new feature (for Alan Braslau), a prelude to more:
%D
@@ -256,7 +256,7 @@
\def\page_floats_flush_page_floats_indeed#1% future releases can do more clever things
{\page_floats_flush{#1}\plusone
- \edef\floatspecification{\ctxcommand{getfloatvariable("specification")}}% Is this okay?
+ \edef\floatspecification{\clf_getfloatvariable{specification}}% Is this okay?
\the\everybeforeflushedpagefloat
\vbox to \textheight
{\doifnotinset\v!high\floatspecification\vfill
@@ -265,7 +265,7 @@
\page_otr_fill_and_eject_page}
\unexpanded\def\page_floats_flush_page_floats % used in postpone
- {\edef\m_page_otf_checked_page_float{\ctxcommand{checkedpagefloat()}}% (true) for packed
+ {\edef\m_page_otf_checked_page_float{\clf_checkedpagefloat}%
\ifx\m_page_otf_checked_page_float\empty
% nothing
\else\ifx\m_page_otf_checked_page_float\v!empty
diff --git a/Master/texmf-dist/tex/context/base/page-flw.mkiv b/Master/texmf-dist/tex/context/base/page-flw.mkiv
index ec1fa636df7..56fe32e5b9e 100644
--- a/Master/texmf-dist/tex/context/base/page-flw.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-flw.mkiv
@@ -80,14 +80,14 @@
\def\textflowcollector#1%
{\csname\??textflowbox#1\endcsname}
-\unexpanded\def\doiftextflowcollectorelse#1%
+\unexpanded\def\doifelsetextflowcollector#1%
{\ifcsname\??textflowbox#1\endcsname
\expandafter\firstoftwoarguments
\else
\expandafter\secondoftwoarguments
\fi}
-\unexpanded\def\doiftextflowelse#1%
+\unexpanded\def\doifelsetextflow#1%
{\ifcsname\??textflowbox#1\endcsname
\ifvoid\csname\??textflowbox#1\endcsname
\doubleexpandafter\secondoftwoarguments
@@ -98,6 +98,9 @@
\expandafter\secondoftwoarguments
\fi}
+\let\doiftextflowcollectorelse\doifelsetextflowcollector
+\let\doiftextflowelse \doifelsetextflow
+
% \unexpanded\def\doiftextflow#1%
% {\doiftextflowelse{#1}\firstofoneargument\gobbleoneargument}
diff --git a/Master/texmf-dist/tex/context/base/page-imp.mkiv b/Master/texmf-dist/tex/context/base/page-imp.mkiv
index 230ede570ed..198a982298c 100644
--- a/Master/texmf-dist/tex/context/base/page-imp.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-imp.mkiv
@@ -163,7 +163,7 @@
\donetrue
\fi
\else % testen, aangepast / expanded nodig ?
- \normalexpanded{\doifinsetelse{\the\shippedoutpages}{\pagestoshipout}}\donetrue\donefalse
+ \normalexpanded{\doifelseinset{\the\shippedoutpages}{\pagestoshipout}}\donetrue\donefalse
\fi
\ifdone
\setbox\shipoutscratchbox\hbox{#1}%
@@ -288,7 +288,7 @@
\fi
\setuppapersize
\ifarrangingpages
- \ctxlua{job.disablesave()}%
+ \clf_disablejobsave
%\disabledirective[job.save]%
\fi
\fi}
@@ -355,14 +355,14 @@
{\dosetuparrangement{2}{2}{4}{3}{3}%
\pusharrangedpageSIXTEENTWO\poparrangedpagesAtoD\relax}
-\installpagearrangement 2*2*4 % onother one of Willy Egger
+\installpagearrangement 2*2*4 % another one of Willy Egger
{\dosetuparrangement{2}{1}{8}{3}{2}%
\pusharrangedpageSIXTEENFOUR\poparrangedpagesAtoH\relax}
\installpagearrangement 2TOPSIDE
{\dosetuparrangement{1}{2}{4}{2}{3}%
\pusharrangedpageTWOTOPSIDE\poparrangedpagesTWOTOPSIDE\handlearrangedpageTOP}
-
+
\def\filluparrangedpages % beware: \realpageno is 1 ahead
{\ifarrangingpages
\scratchcounter\numexpr\realpageno-\plusone\relax
@@ -748,7 +748,7 @@
\poparrangedpages
\fi}
-%D Might be used if a printer is printing from a rol or creating mini-books from A4:
+%D Might be used if a printer is printing from a roll or creating mini-books from A4:
%D This section has 16 pages. The folding scheme is first a Z-fold and at the end
%D a final fold in the spine.
%D Coding: [2*8*Z]
@@ -1045,7 +1045,7 @@
%D There should be arrangements for sections made of heavy and thick paper. i.e. the heavier the paper
%D the fewer pages per section:
-%D Section with 8 pages put on to sheets of paper. Each sheet carries recto 2 and verso 2 pages.
+%D Section with 8 pages put on two sheets of paper. Each sheet carries recto 2 and verso 2 pages.
%D Coding: [2*2*2]
\installpagearrangement 2*2*2
@@ -1351,7 +1351,7 @@
\doifelse{#1}\v!page {\let\page_boxes_apply_shift_print\page_boxes_apply_shift}{\let\page_boxes_apply_shift_print\gobbleoneargument}%
\doifelse{#1}\v!paper{\let\page_boxes_apply_shift_paper\page_boxes_apply_shift}{\let\page_boxes_apply_shift_paper\gobbleoneargument}%
\else\ifsecondargument
- \doifinsetelse{#1}{\v!page,\v!paper}
+ \doifelseinset{#1}{\v!page,\v!paper}
{\setuppageshift[#1][#2][#2]}
{\setuppageshift[\v!page][#1][#2]}%
\else\iffirstargument
diff --git a/Master/texmf-dist/tex/context/base/page-ini.mkiv b/Master/texmf-dist/tex/context/base/page-ini.mkiv
index fdffa552d5d..15783a99bc3 100644
--- a/Master/texmf-dist/tex/context/base/page-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-ini.mkiv
@@ -102,6 +102,7 @@
\page_otr_check_for_pending_inserts
% but does not hurt either (we're still in the otr!)
\inpagebodytrue % needed for enabling \blank ! brrr
+ \pagebodymode\plusone % todo: \plustwo when spread
\page_otr_command_flush_saved_floats
\page_otr_command_set_vsize % this is needed for interacting components, like floats and multicolumns
\strc_pagenumbers_increment_counters % should hook into an every
@@ -143,9 +144,15 @@
\newconstant\pageornamentstate % 0=on 1=one-off 2=always-off
+% \appendtoks
+% \ifcase\pageornamentstate \or
+% \pageornamentstate\zerocount
+% \fi
+% \to \everyaftershipout
+
\appendtoks
\ifcase\pageornamentstate \or
- \pageornamentstate\zerocount
+ \global\pageornamentstate\zerocount
\fi
\to \everyaftershipout
@@ -229,7 +236,7 @@
\the\everyafterpagebody
\egroup}
-\def\doiftopofpageelse
+\def\doifelsetopofpage
{\ifdim\pagegoal=\maxdimen
\expandafter\firstoftwoarguments
\else\ifdim\pagegoal=\vsize
@@ -238,6 +245,8 @@
\doubleexpandafter\secondoftwoarguments
\fi\fi}
+\let\doiftopofpageelse\doifelsetopofpage
+
% %D Idea:
%
% \newinsert\thispageinsert % <- installinsertion
diff --git a/Master/texmf-dist/tex/context/base/page-inj.lua b/Master/texmf-dist/tex/context/base/page-inj.lua
index 56e5a234e8b..fd66ead08d1 100644
--- a/Master/texmf-dist/tex/context/base/page-inj.lua
+++ b/Master/texmf-dist/tex/context/base/page-inj.lua
@@ -16,10 +16,9 @@ pagebuilders.injections = injections
local report = logs.reporter("pagebuilder","injections")
local trace = false trackers.register("pagebuilder.injections",function(v) trace = v end)
-local variables = interfaces.variables
-
local context = context
-local commands = commands
+local implement = interfaces.implement
+local variables = interfaces.variables
local texsetcount = tex.setcount
@@ -103,6 +102,24 @@ function injections.flushafter() -- maybe not public, just commands.*
end
end
-commands.page_injections_save = injections.save
-commands.page_injections_flush_after = injections.flushafter
-commands.page_injections_flush_before = injections.flushbefore
+implement {
+ name = "savepageinjections",
+ actions = injections.save,
+ arguments = {
+ {
+ { "name" },
+ { "state" },
+ { "userdata" }
+ }
+ }
+}
+
+implement {
+ name = "flushpageinjectionsbefore",
+ actions = injections.flushbefore
+}
+
+implement {
+ name = "flushpageinjectionsafter",
+ actions = injections.flushafter
+}
diff --git a/Master/texmf-dist/tex/context/base/page-inj.mkvi b/Master/texmf-dist/tex/context/base/page-inj.mkvi
index bee56468346..03472fe5593 100644
--- a/Master/texmf-dist/tex/context/base/page-inj.mkvi
+++ b/Master/texmf-dist/tex/context/base/page-inj.mkvi
@@ -29,8 +29,8 @@
\installframedcommandhandler \??pageinjection {pageinjection} \??pageinjection
\installcommandhandler \??pageinjectionalternative {pageinjectionalternative} \??pageinjectionalternative
-\def\page_boxes_flush_before{\ctxcommand{page_injections_flush_before()}}
-\def\page_boxes_flush_after {\ctxcommand{page_injections_flush_after ()}}
+\let\page_boxes_flush_before\clf_flushpageinjectionsbefore
+\let\page_boxes_flush_after \clf_flushpageinjectionsafter
\def\page_injections_flush_saved#name#parameters%
{\begingroup
@@ -47,11 +47,11 @@
\dodoubleempty\page_injections_direct}
\def\page_injections_direct[#1][#2]% name parameters | settings parameters | name | parameters
- {\doifassignmentelse{#1}
- {\doifassignmentelse{#2}
+ {\doifelseassignment{#1}
+ {\doifelseassignment{#2}
{\page_injections_direct_settings_parameters{#1}{#2}}
{\page_injections_direct_parameters {#1}}}
- {\doifassignmentelse{#2}
+ {\doifelseassignment{#2}
{\page_injections_direct_name_parameters {#1}{#2}}
{\page_injections_direct_name {#1}}}}
@@ -87,11 +87,11 @@
\fi}
\def\page_injections_direct_indeed_yes#parameters%
- {\ctxcommand{page_injections_save{
- name = "\currentpageinjection",
- state = "\p_page_injections_state",
- userdata = \!!bs\normalunexpanded{#parameters}\!!es
- }}%
+ {\clf_savepageinjections
+ name {\currentpageinjection}%
+ state {\p_page_injections_state}%
+ userdata {\normalunexpanded{#parameters}}%
+ \relax
\endgroup}
\def\page_injections_direct_indeed_nop#parameters%
diff --git a/Master/texmf-dist/tex/context/base/page-ins.lua b/Master/texmf-dist/tex/context/base/page-ins.lua
index 7f870735d27..235f586c689 100644
--- a/Master/texmf-dist/tex/context/base/page-ins.lua
+++ b/Master/texmf-dist/tex/context/base/page-ins.lua
@@ -4,19 +4,9 @@ if not modules then modules = { } end modules ['page-ins'] = {
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files",
- -- public = {
- -- functions = {
- -- "inserts.define",
- -- "inserts.getdata",
- -- },
- -- commands = {
- -- "defineinsertion",
- -- "inserttionnumber",
- -- }
- -- }
}
--- Maybe we should only register in lua and forget about the tex end.
+local next = next
structures = structures or { }
structures.inserts = structures.inserts or { }
@@ -36,6 +26,9 @@ local v_firstcolumn = variables.firstcolumn
local v_lastcolumn = variables.lastcolumn
local v_text = variables.text
+local context = context
+local implement = interfaces.implement
+
storage.register("structures/inserts/stored", inserts.stored, "structures.inserts.stored")
local data = inserts.data
@@ -49,7 +42,7 @@ end
function inserts.define(name,specification)
specification.name= name
local number = specification.number or 0
- data[name] = specification
+ data[name] = specification
data[number] = specification
-- only needed at runtime as this get stored in a bytecode register
stored[name] = specification
@@ -90,8 +83,37 @@ end
-- interface
-commands.defineinsertion = inserts.define
-commands.setupinsertion = inserts.setup
-commands.setinsertionlocation = inserts.setlocation
-commands.insertionnumber = function(name) context(data[name].number or 0) end
+implement {
+ name = "defineinsertion",
+ actions = inserts.define,
+ arguments = {
+ "string",
+ {
+ { "number", "integer" }
+ }
+ }
+}
+
+implement {
+ name = "setupinsertion",
+ actions = inserts.setup,
+ arguments = {
+ "string",
+ {
+ { "location" }
+ }
+ }
+}
+
+implement {
+ name = "setinsertionlocation",
+ actions = inserts.setlocation,
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "insertionnumber",
+ actions = function(name) context(data[name].number or 0) end,
+ arguments = "string"
+}
diff --git a/Master/texmf-dist/tex/context/base/page-ins.mkiv b/Master/texmf-dist/tex/context/base/page-ins.mkiv
index a63de0b26f2..c91073a143d 100644
--- a/Master/texmf-dist/tex/context/base/page-ins.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-ins.mkiv
@@ -82,13 +82,15 @@
\insert#1{\unvbox#1}%
\fi}
-\unexpanded\def\doifinsertionelse#1%
+\unexpanded\def\doifelseinsertion#1%
{\ifcsname\??insertionnumber#1\endcsname
\expandafter\firstoftwoarguments
\else
\expandafter\secondoftwoarguments
\fi}
+\let\doifinsertionelse\doifelseinsertion
+
% \unexpanded\def\startinsertion[#1]%
% {\insert\csname\??insertionnumber#1\endcsname\bgroup}
%
@@ -108,7 +110,12 @@
\else
\expandafter\newinsert\csname\??insertionnumber\currentinsertion\endcsname
\page_inserts_synchronize_registers
- \ctxcommand{defineinsertion("\currentinsertion",{ number = \number\currentinsertionnumber })}%
+ \clf_defineinsertion
+ {\currentinsertion}%
+ {%
+ number \currentinsertionnumber
+ }%
+ \relax
\t_page_inserts_list\expandafter\expandafter\expandafter
{\expandafter\the\expandafter\t_page_inserts_list
\expandafter\page_inserts_process\csname\??insertionnumber\currentinsertion\endcsname}%
@@ -123,13 +130,16 @@
\to \everydefineinsertion
\appendtoks
- \ctxcommand{setupinsertion("\currentinsertion",{
- location = "\insertionparameter\c!location",
- })}%
+ \clf_setupinsertion
+ {\currentinsertion}
+ {%
+ location {\insertionparameter\c!location}%
+ }%
+ \relax
\to \everysetupinsertion
\unexpanded\def\page_inserts_set_location#1#2% fast one
- {\ctxcommand{setinsertionlocation("#1","#2")}}
+ {\clf_setinsertionlocation{#1}{#2}}
%D Auxiliary macros:
diff --git a/Master/texmf-dist/tex/context/base/page-lay.mkiv b/Master/texmf-dist/tex/context/base/page-lay.mkiv
index 19f23724247..d1328bb6ba0 100644
--- a/Master/texmf-dist/tex/context/base/page-lay.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-lay.mkiv
@@ -30,6 +30,8 @@
\newdimen\paperheight \paperheight = 297mm
\newdimen\paperwidth \paperwidth = 210mm
\newdimen\paperoffset \paperoffset = \zeropoint
+\newdimen\paperbleed \paperbleed = \zeropoint
+\newdimen\spinewidth \spinewidth = \zeropoint
\newdimen\printpaperheight \printpaperheight = \paperheight
\newdimen\printpaperwidth \printpaperwidth = \paperwidth
@@ -154,13 +156,15 @@
\fi
\to \everysetuplayout
-\def\doiflayoutdefinedelse#1%
+\def\doifelselayoutdefined#1%
{\ifcsname\namedlayouthash{#1}\c!state\endcsname % maybe a helper
\expandafter\firstoftwoarguments
\else
\expandafter\secondoftwoarguments
\fi}
+\let\doiflayoutdefinedelse\doifelselayoutdefined
+
\def\layoutdistance#1#2{\ifdim\zeropoint<#1#2\else\zeropoint\fi}
\def\page_layouts_set_dimensions
@@ -365,7 +369,7 @@
\ifx\currentlayouttarget\empty
% invalid target
\else
- \doifassignmentelse{#2}
+ \doifelseassignment{#2}
{\definelayouttarget[#1][#2]}
{\setevalue{\??layoutpaper#1}{#2}%
\setevalue{\??layoutprint#1}{#3}}%
@@ -390,9 +394,9 @@
\unexpanded\def\page_paper_setup_size[#1][#2]%
{\iffirstargument
- \doifassignmentelse{#1}
+ \doifelseassignment{#1}
{\page_paper_setup_size_settings[#1]}
- {\doifassignmentelse{#2}
+ {\doifelseassignment{#2}
{\page_paper_setup_size_settings_by_name[#1][#2]}
{\page_paper_setup_size_change_size[#1][#2]}}%
\else
@@ -1027,7 +1031,7 @@
\unexpanded\def\startlayout[#1]%
{\page
\globalpushmacro\currentlayout
- \doiflayoutdefinedelse{#1}{\setuplayout[#1]}\donothing} % {\setuplayout[\currentlayout]}}
+ \doifelselayoutdefined{#1}{\setuplayout[#1]}\donothing} % {\setuplayout[\currentlayout]}}
\unexpanded\def\stoplayout
{\page
@@ -1121,13 +1125,15 @@
% #single #left #right
-\def\doifoddpageelse
+\def\doifelseoddpage
{\ifodd\pagenoshift
\expandafter\page_layouts_if_odd_else_yes
\else
\expandafter\page_layouts_if_odd_else_nop
\fi}
+\let\doifoddpageelse\doifelseoddpage
+
\def\page_layouts_if_odd_else_yes
{\ifodd\realpageno
\expandafter\secondoftwoarguments
@@ -1142,9 +1148,7 @@
\expandafter\secondoftwoarguments
\fi}
-\let\doifonevenpaginaelse\doifoddpageelse
-
-\def\page_layouts_if_odd_else_again#1{\doifoddpageelse}
+\def\page_layouts_if_odd_else_again#1{\doifelseoddpage}
\def\doifbothsidesoverruled
{\ifdoublesided
@@ -1171,7 +1175,7 @@
\def\settexthoffset % name will change
{\texthoffset\doifbothsides\backspace\backspace{\dimexpr\paperwidth-\backspace-\makeupwidth\relax}}
-
+
% The next hack is too tricky as we may shipout more pages:
%
% \def\freezepagestatechecks
@@ -1199,11 +1203,13 @@
\def\goleftonpage % name will change (we could cache)
{\hskip-\dimexpr\leftmargindistance+\leftmarginwidth+\leftedgedistance+\leftedgewidth\relax}
-\def\doifmarginswapelse#1#2%
+\def\doifelsemarginswap#1#2%
{\doifbothsides{#1}{#1}{#2}}
+\let\doifmarginswapelse\doifelsemarginswap
+
\def\swapmargins % name will change
- {\doifmarginswapelse\relax\doswapmargins}
+ {\doifelsemarginswap\relax\doswapmargins}
\def\doswapmargins % name will change
{\let\swapmargins \relax % to prevent local swapping
@@ -1221,7 +1227,7 @@
{\ifsinglesided
\expandafter\firstoftwoarguments
\else
- \expandafter\doifoddpageelse
+ \expandafter\doifelseoddpage
\fi}
\def\outermarginwidth {\rightorleftpageaction\rightmarginwidth \leftmarginwidth }
@@ -1377,6 +1383,9 @@
\definepapersize [A9] [\c!width=37mm,\c!height=52mm]
\definepapersize [A10] [\c!width=26mm,\c!height=37mm]
+\definepapersize [A4/2][\c!width=\dimexpr297mm/2\relax,\c!height=210mm] % 148.5mm
+%definepapersize [2A5] [\c!width=296mm,\c!height=210mm] % doublewide
+
\definepapersize [B0] [\c!width=1000mm,\c!height=1414mm]
\definepapersize [B1] [\c!width=707mm,\c!height=1000mm]
\definepapersize [B2] [\c!width=500mm,\c!height=707mm]
@@ -1424,6 +1433,7 @@
\definepapersize [SW] [\c!width=800pt,\c!height=450pt] % wide
\definepapersize [HD] [\c!width=1920pt,\c!height=1080pt]
\definepapersize [HD+] [\c!width=1920pt,\c!height=1200pt]
+\definepapersize [HD-] [\c!width=960pt,\c!height=540pt]
%D These are handy too:
@@ -1491,6 +1501,11 @@
\definepapersize [A3plus] [\c!width=329mm,\c!height=483mm]
+%D For Alan:
+
+\definepapersize [business] [\c!width=85mm,\c!height=55mm]
+\definepapersize [businessUS] [\c!width=3.5in,\c!height=2in]
+
%D We can now default to a reasonable size. We match the print
%D paper size with the typeset paper size. This setting should
%D come after the first layout specification (already done).
@@ -1505,15 +1520,18 @@
% [ \c!width=\paperwidth,
% \c!height=\paperheight]
+\setuppapersize
+ [\c!distance=1.5cm] % offset is already taken
+
\definepapersize
[oversized]
- [ \c!width=\dimexpr\paperwidth +1.5cm\relax,
- \c!height=\dimexpr\paperheight+1.5cm\relax]
+ [ \c!width=\dimexpr\paperwidth +\layouttargetparameter\c!distance\relax,
+ \c!height=\dimexpr\paperheight+\layouttargetparameter\c!distance\relax]
\definepapersize
[undersized]
- [ \c!width=\dimexpr\paperwidth -1.5cm\relax,
- \c!height=\dimexpr\paperheight-1.5cm\relax]
+ [ \c!width=\dimexpr\paperwidth -\layouttargetparameter\c!distance\relax,
+ \c!height=\dimexpr\paperheight-\layouttargetparameter\c!distance\relax]
\definepapersize
[doublesized]
@@ -1522,8 +1540,13 @@
\definepapersize
[doubleoversized]
- [ \c!width=\dimexpr \paperheight+1.5cm\relax,
- \c!height=\dimexpr2\paperwidth +1.5cm\relax]
+ [ \c!width=\dimexpr \paperheight+\layouttargetparameter\c!distance\relax,
+ \c!height=\dimexpr2\paperwidth +\layouttargetparameter\c!distance\relax]
+
+\definepapersize
+ [doublewide]
+ [ \c!width=\dimexpr2\paperwidth \relax,
+ \c!height=\dimexpr \paperheight\relax]
% \setuppapersize
% [A4][A4]
diff --git a/Master/texmf-dist/tex/context/base/page-lin.lua b/Master/texmf-dist/tex/context/base/page-lin.lua
index 0b241240c02..5a447c45840 100644
--- a/Master/texmf-dist/tex/context/base/page-lin.lua
+++ b/Master/texmf-dist/tex/context/base/page-lin.lua
@@ -21,6 +21,8 @@ local attributes = attributes
local nodes = nodes
local context = context
+local implement = interfaces.implement
+
nodes.lines = nodes.lines or { }
local lines = nodes.lines
@@ -163,9 +165,19 @@ function boxed.register(configuration)
return last
end
-function commands.registerlinenumbering(configuration)
- context(boxed.register(configuration))
-end
+implement {
+ name = "registerlinenumbering",
+ actions = { boxed.register, context },
+ arguments = {
+ {
+ { "continue" },
+ { "start", "integer" },
+ { "step", "integer" },
+ { "method" },
+ { "tag" },
+ }
+ }
+}
function boxed.setup(n,configuration)
local d = data[n]
@@ -185,7 +197,20 @@ function boxed.setup(n,configuration)
return n
end
-commands.setuplinenumbering = boxed.setup
+implement {
+ name = "setuplinenumbering",
+ actions = boxed.setup,
+ arguments = {
+ "integer",
+ {
+ { "continue" },
+ { "start", "integer" },
+ { "step", "integer" },
+ { "method" },
+ { "tag" },
+ }
+ }
+}
local function check_number(n,a,skip,sameline)
local d = data[a]
@@ -394,5 +419,14 @@ function boxed.stage_two(n,m)
end
end
-commands.linenumbersstageone = boxed.stage_one
-commands.linenumbersstagetwo = boxed.stage_two
+implement {
+ name = "linenumbersstageone",
+ actions = boxed.stage_one,
+ arguments = { "integer", "boolean" }
+}
+
+implement {
+ name = "linenumbersstagetwo",
+ actions = boxed.stage_two,
+ arguments = { "integer", "integer" }
+}
diff --git a/Master/texmf-dist/tex/context/base/page-lin.mkvi b/Master/texmf-dist/tex/context/base/page-lin.mkvi
index e3b6284876e..dd13a98c38e 100644
--- a/Master/texmf-dist/tex/context/base/page-lin.mkvi
+++ b/Master/texmf-dist/tex/context/base/page-lin.mkvi
@@ -73,38 +73,48 @@
\unexpanded\def\page_postprocessors_linenumbers_deepbox#tag{\page_lines_add_numbers_to_box{#tag}\plusone \plusone \plusone }
\unexpanded\def\page_postprocessors_linenumbers_column #tag{\page_lines_add_numbers_to_box{#tag}\currentcolumn\nofcolumns\zerocount}
-\def\page_lines_parameters_regular
- {continue = "\ifnum\c_page_lines_mode=\zerocount\v!yes\else\v!no\fi",
- start = \number\linenumberingparameter\c!start,
- step = \number\linenumberingparameter\c!step,
- method = "\linenumberingparameter\c!method",
- tag = "\currentlinenumbering"}
-
-\def\page_lines_parameters_update
- {continue = "\ifnum\c_page_lines_mode=\zerocount\v!yes\else\v!no\fi"}
-
\def\page_lines_start_define
- {\setxvalue{\??linenumberinginstance\currentlinenumbering}{\ctxcommand{registerlinenumbering({\page_lines_parameters_regular})}}}
+ {\setxvalue{\??linenumberinginstance\currentlinenumbering}%
+ {\clf_registerlinenumbering
+ continue {\ifnum\c_page_lines_mode=\zerocount\v!yes\else\v!no\fi}%
+ start \linenumberingparameter\c!start
+ step \linenumberingparameter\c!step
+ method {\linenumberingparameter\c!method}%
+ tag {\currentlinenumbering}%
+ }}
\def\page_lines_start_update
- {\ctxcommand{setuplinenumbering(\csname\??linenumberinginstance\currentlinenumbering\endcsname,{\page_lines_parameters_update})}}
+ {\clf_setuplinenumbering
+ \csname\??linenumberinginstance\currentlinenumbering\endcsname
+ {%
+ continue {\ifnum\c_page_lines_mode=\zerocount\v!yes\else\v!no\fi}%
+ }%
+ \relax}
\def\page_lines_setup
{\ifcsname \??linenumberinginstance\currentlinenumbering\endcsname
- \ctxcommand{setuplinenumbering(\csname\??linenumberinginstance\currentlinenumbering\endcsname,{\page_lines_parameters_regular})}%
+ \clf_setuplinenumbering
+ \csname\??linenumberinginstance\currentlinenumbering\endcsname
+ {%
+ continue {\ifnum\c_page_lines_mode=\zerocount\v!yes\else\v!no\fi}%
+ start \linenumberingparameter\c!start
+ step \linenumberingparameter\c!step
+ method {\linenumberingparameter\c!method}%
+ tag {\currentlinenumbering}%
+ }%
+ \relax
\fi}
% we could make this a bit more efficient by putting the end reference
% in the same table as the start one but why make things complex ...
-\let\dofinishlinereference\dofinishfullreference % at lua end
-
\unexpanded\def\page_lines_some_reference#1#2#3%
{\dontleavehmode\begingroup
\global\advance\c_page_lines_reference\plusone
\attribute\linereferenceattribute\c_page_lines_reference
- #3%
+ #3% todo: #3{#1} as there is no need to pass #1 as part of #3
% for the moment we use a simple system i.e. no prefixes etc .. todo: store as number
+ \c_strc_references_bind_state\zerocount % we don't want the prewordbreak and manage it here
\normalexpanded{\strc_references_set_named_reference{line}{#2}{conversion=\linenumberingparameter\c!conversion}{\the\c_page_lines_reference}}% kind labels userdata text
\endgroup}
@@ -195,10 +205,10 @@
\ifx\m_argument\v!empty
\let\currentlinenumbering\empty
\else
- \doifassignmentelse{#1}
+ \doifelseassignment{#1}
{\let\currentlinenumbering\empty
\setupcurrentlinenumbering[#1]}
- {\doifnumberelse\m_argument
+ {\doifelsenumber\m_argument
{\let\currentlinenumbering\empty
\letlinenumberingparameter\c!start\m_argument}
{\let\currentlinenumbering\m_argument}}%
@@ -218,7 +228,7 @@
\else
\c_page_lines_mode\plusone
\ifx\m_argument\v!empty \else
- \doifassignmentelse{#2}
+ \doifelseassignment{#2}
{\setupcurrentlinenumbering[#2]}
{\doifnumber\m_argument
{\letlinenumberingparameter\c!start\m_argument}}%
@@ -301,8 +311,14 @@
\setbox\b_page_lines_scratch\vbox
{\forgetall
\offinterlineskip
- \ctxcommand{linenumbersstageone(\number\b_page_lines_number,\ifcase\c_page_lines_nesting false\else true\fi)}}%
- \ctxcommand{linenumbersstagetwo(\number\b_page_lines_number,\number\b_page_lines_scratch)}% can move to lua code
+ \clf_linenumbersstageone
+ \b_page_lines_number
+ \ifcase\c_page_lines_nesting false\else true\fi
+ \relax}%
+ \clf_linenumbersstagetwo
+ \b_page_lines_number
+ \b_page_lines_scratch
+ \fi
\egroup}
\let\page_lines_make_number_indeed\relax
@@ -321,8 +337,14 @@
\setbox\b_page_lines_scratch\vbox
{\forgetall
\offinterlineskip
- \ctxcommand{linenumbersstageone(\number\b_page_lines_number,\ifcase\c_page_lines_nesting false\else true\fi)}}%
- \ctxcommand{linenumbersstagetwo(\number\b_page_lines_number,\number\b_page_lines_scratch)}% can move to lua code
+ \clf_linenumbersstageone
+ \b_page_lines_number
+ \ifcase\c_page_lines_nesting false\else true\fi
+ \relax}%
+ \clf_linenumbersstagetwo
+ \b_page_lines_number
+ \b_page_lines_scratch
+ \relax
\egroup}
\def\page_lines_make_number#tag#mode#linenumber#shift#width#leftskip#dir% beware, one needs so compensate for this in the \hsize
@@ -534,21 +556,23 @@
% eventually we will do this in lua
-\def\currentreferencelinenumber{\ctxcommand{filterreference("linenumber")}}
+\def\currentreferencelinenumber{\clf_filterreference{linenumber}}
\let\m_page_lines_from\empty
\let\m_page_lines_to \empty
\unexpanded\def\doifelsesamelinereference#1#2#3%
- {\doifreferencefoundelse{lr:b:#1}
+ {\doifelsereferencefound{lr:b:#1}
{\edef\m_page_lines_from{\currentreferencelinenumber}%
- \doifreferencefoundelse{lr:e:#1}
+ \doifelsereferencefound{lr:e:#1}
{\edef\m_page_lines_to{\currentreferencelinenumber}%
%[\m_page_lines_from,\m_page_lines_to]
\ifx\m_page_lines_from\m_page_lines_to#2\else#3\fi}
{#2}}
{#2}}
+\let\doifsamelinereferenceelse\doifelsesamelinereference
+
\unexpanded\def\inline#1[#2]%
{\doifelsenothing{#1}
{\doifelsesamelinereference{#2}
diff --git a/Master/texmf-dist/tex/context/base/page-mak.mkvi b/Master/texmf-dist/tex/context/base/page-mak.mkvi
index c910f281d23..ee144f20a34 100644
--- a/Master/texmf-dist/tex/context/base/page-mak.mkvi
+++ b/Master/texmf-dist/tex/context/base/page-mak.mkvi
@@ -45,7 +45,7 @@
\appendtoks
\setuevalue{\e!start\currentmakeup\e!makeup}{\startmakeup[\currentmakeup]}%
\setuevalue{\e!stop \currentmakeup\e!makeup}{\stopmakeup}%
- \doiflayoutdefinedelse\currentmakeup\donothing{\definelayout[\currentmakeup]}% new
+ \doifelselayoutdefined\currentmakeup\donothing{\definelayout[\currentmakeup]}% new
\to \everydefinemakeup
%D The \type{\start}||\type{\stop} macros are used for both
@@ -126,8 +126,7 @@
% nothing
\endgroup
\else
- \endgroup
- \page[\p_page]%
+ \normalexpanded{\endgroup\page[\p_page]}%
\fi\fi
% some dirty trickery (sorry) for determining if we have
% - a layout definition at all
diff --git a/Master/texmf-dist/tex/context/base/page-mbk.mkvi b/Master/texmf-dist/tex/context/base/page-mbk.mkvi
index 9e3e57193bd..8038771d9c7 100644
--- a/Master/texmf-dist/tex/context/base/page-mbk.mkvi
+++ b/Master/texmf-dist/tex/context/base/page-mbk.mkvi
@@ -98,7 +98,7 @@
\unvbox\b_page_margin_blocks
\marginblockparameter\c!inbetween
\fi
- \setupalign[\marginblockparameter\c!align]%
+ \usealignparameter\marginblockparameter
\usemarginblockstyleandcolor\c!style\c!color
\begstrut
\ignorespaces}
diff --git a/Master/texmf-dist/tex/context/base/page-mix.lua b/Master/texmf-dist/tex/context/base/page-mix.lua
index 0fbaa4e30b4..2bf89f73778 100644
--- a/Master/texmf-dist/tex/context/base/page-mix.lua
+++ b/Master/texmf-dist/tex/context/base/page-mix.lua
@@ -13,7 +13,9 @@ if not modules then modules = { } end modules ["page-mix"] = {
-- local trackers, logs, storage = trackers, logs, storage
-- local number, table = number, table
+local next, type = next, type
local concat = table.concat
+local ceil, floor = math.ceil, math.floor
local trace_state = false trackers.register("mixedcolumns.trace", function(v) trace_state = v end)
local trace_detail = false trackers.register("mixedcolumns.detail", function(v) trace_detail = v end)
@@ -81,6 +83,10 @@ local v_auto = variables.auto
local v_none = variables.none
local v_more = variables.more
local v_less = variables.less
+local v_halfline = variables.halfline
+
+local context = context
+local implement = interfaces.implement
pagebuilders = pagebuilders or { }
pagebuilders.mixedcolumns = pagebuilders.mixedcolumns or { }
@@ -222,7 +228,7 @@ local function stripbottomglue(results,discarded)
return height
end
-local function setsplit(specification) -- a rather large function
+local function preparesplit(specification) -- a rather large function
local box = specification.box
if not box then
report_state("fatal error, no box")
@@ -239,16 +245,16 @@ local function setsplit(specification) -- a rather large function
return
end
slidenodes(head) -- we can have set prev's to nil to prevent backtracking
- local discarded = { }
- local originalhead = head
- local originalwidth = specification.originalwidth or getfield(list,"width")
+ local discarded = { }
+ local originalhead = head
+ local originalwidth = specification.originalwidth or getfield(list,"width")
local originalheight = specification.originalheight or getfield(list,"height")
- local current = head
- local skipped = 0
- local height = 0
- local depth = 0
- local skip = 0
- local splitmethod = specification.splitmethod or false
+ local current = head
+ local skipped = 0
+ local height = 0
+ local depth = 0
+ local skip = 0
+ local splitmethod = specification.splitmethod or false
if splitmethod == v_none then
splitmethod = false
end
@@ -428,6 +434,7 @@ local function setsplit(specification) -- a rather large function
local function checked(advance,where,locked)
local total = skip + height + depth + advance
local delta = total - target
+-- - 65536*3
local state = "same"
local okay = false
local skipped = 0
@@ -716,10 +723,12 @@ local kept = head
return specification
end
-function mixedcolumns.finalize(result)
+local function finalize(result)
if result then
- local results = result.results
- for i=1,result.nofcolumns do
+ local results = result.results
+ local columns = result.nofcolumns
+ local maxtotal = 0
+ for i=1,columns do
local r = results[i]
local h = r.head
if h then
@@ -747,6 +756,16 @@ function mixedcolumns.finalize(result)
r.inserts[c] = t
end
end
+ local total = r.height + r.depth
+ if total > maxtotal then
+ maxtotal = total
+ end
+ r.total = total
+ end
+ result.maxtotal = maxtotal
+ for i=1,columns do
+ local r = results[i]
+ r.extra = maxtotal - r.total
end
end
end
@@ -761,12 +780,12 @@ local function report_deltas(result,str)
report_state("%s, cycles %s, deltas % | t",str,result.cycle or 1,t)
end
-function mixedcolumns.setsplit(specification)
+local function setsplit(specification)
splitruns = splitruns + 1
if trace_state then
report_state("split run %s",splitruns)
end
- local result = setsplit(specification)
+ local result = preparesplit(specification)
if result then
if result.overflow then
if trace_state then
@@ -779,7 +798,7 @@ function mixedcolumns.setsplit(specification)
local cycles = specification.cycles or 100
while result.rest and cycle <= cycles do
specification.extra = cycle * step
- result = setsplit(specification) or result
+ result = preparesplit(specification) or result
if trace_state then
report_state("cycle: %s.%s, original height %p, total height %p",
splitruns,cycle,result.originalheight,result.nofcolumns*result.targetheight)
@@ -801,7 +820,7 @@ function mixedcolumns.setsplit(specification)
end
end
-function mixedcolumns.getsplit(result,n)
+local function getsplit(result,n)
if not result then
report_state("flush, column %s, no result",n)
return
@@ -819,13 +838,14 @@ function mixedcolumns.getsplit(result,n)
local strutht = result.strutht
local strutdp = result.strutdp
local lineheight = strutht + strutdp
+ local isglobal = result.alternative == v_global
local v = new_vlist()
setfield(v,"list",h)
-- local v = vpack(h,"exactly",height)
- if result.alternative == v_global then -- option
+ if isglobal then -- option
result.height = result.maxheight
end
@@ -833,11 +853,56 @@ function mixedcolumns.getsplit(result,n)
local dp = 0
local wd = result.originalwidth
- local grid = result.grid
+ local grid = result.grid
+ local internalgrid = result.internalgrid
+ local httolerance = .25
+ local dptolerance = .50
+ local lineheight = internalgrid == v_halfline and lineheight/2 or lineheight
+
+ local function amount(r,s,t)
+ local l = ceil((r-t)/lineheight)
+ local a = lineheight * l
+ if a > s then
+ return a - s
+ else
+ return s
+ end
+ end
if grid then
- ht = lineheight * math.ceil(result.height/lineheight) - strutdp
- dp = strutdp
+ -- print(n,result.maxtotal,r.total,r.extra)
+ if isglobal then
+ local rh = r.height
+ -- ht = (lineheight * ceil(result.height/lineheight) - strutdp
+ ht = amount(rh,strutdp,0)
+ dp = strutdp
+ else
+ -- natural dimensions
+ local rh = r.height
+ local rd = r.depth
+ if rh > ht then
+ ht = amount(rh,strutdp,httolerance*strutht)
+ end
+ if rd > dp then
+ dp = amount(rd,strutht,dptolerance*strutdp)
+ end
+ -- forced dimensions
+ local rh = result.height or 0
+ local rd = result.depth or 0
+ if rh > ht then
+ ht = amount(rh,strutdp,httolerance*strutht)
+ end
+ if rd > dp then
+ dp = amount(rd,strutht,dptolerance*strutdp)
+ end
+ -- always one line at least
+ if ht < strutht then
+ ht = strutht
+ end
+ if dp < strutdp then
+ dp = strutdp
+ end
+ end
else
ht = result.height
dp = result.depth
@@ -867,19 +932,19 @@ function mixedcolumns.getsplit(result,n)
return v
end
-function mixedcolumns.getrest(result)
+local function getrest(result)
local rest = result and result.rest
result.rest = nil -- to be sure
return rest
end
-function mixedcolumns.getlist(result)
+local function getlist(result)
local originalhead = result and result.originalhead
result.originalhead = nil -- to be sure
return originalhead
end
-function mixedcolumns.cleanup(result)
+local function cleanup(result)
local discarded = result.discarded
for i=1,#discarded do
freenode(discarded[i])
@@ -887,52 +952,100 @@ function mixedcolumns.cleanup(result)
result.discarded = { }
end
+mixedcolumns.setsplit = setsplit
+mixedcolumns.getsplit = getsplit
+mixedcolumns.finalize = finalize
+mixedcolumns.getrest = getrest
+mixedcolumns.getlist = getlist
+mixedcolumns.cleanup = cleanup
+
-- interface --
local result
-function commands.mixsetsplit(specification)
- if result then
- for k, v in next, specification do
- result[k] = v
+implement {
+ name = "mixsetsplit",
+ actions = function(specification)
+ if result then
+ for k, v in next, specification do
+ result[k] = v
+ end
+ result = setsplit(result)
+ else
+ result = setsplit(specification)
end
- result = mixedcolumns.setsplit(result)
- else
- result = mixedcolumns.setsplit(specification)
- end
-end
+ end,
+ arguments = {
+ {
+ { "box", "integer" },
+ { "nofcolumns", "integer" },
+ { "maxheight", "dimen" },
+ { "step", "dimen" },
+ { "cycles", "integer" },
+ { "preheight", "dimen" },
+ { "prebox", "integer" },
+ { "strutht", "dimen" },
+ { "strutdp", "dimen" },
+ { "threshold", "dimen" },
+ { "splitmethod" },
+ { "balance" },
+ { "alternative" },
+ { "internalgrid" },
+ { "grid", "boolean" },
+ }
+ }
+}
-function commands.mixgetsplit(n)
- if result then
- context(tonode(mixedcolumns.getsplit(result,n)))
- end
-end
+implement {
+ name = "mixgetsplit",
+ arguments = "integer",
+ actions = function(n)
+ if result then
+ context(tonode(getsplit(result,n)))
+ end
+ end,
+}
-function commands.mixfinalize()
- if result then
- mixedcolumns.finalize(result)
+implement {
+ name = "mixfinalize",
+ actions = function()
+ if result then
+ finalize(result)
+ end
end
-end
+}
-function commands.mixflushrest()
- if result then
- context(tonode(mixedcolumns.getrest(result)))
+implement {
+ name = "mixflushrest",
+ actions = function()
+ if result then
+ context(tonode(getrest(result)))
+ end
end
-end
+}
-function commands.mixflushlist()
- if result then
- context(tonode(mixedcolumns.getlist(result)))
+implement {
+ name = "mixflushlist",
+ actions = function()
+ if result then
+ context(tonode(getlist(result)))
+ end
end
-end
+}
-function commands.mixstate()
- context(result and result.rest and 1 or 0)
-end
+implement {
+ name = "mixstate",
+ actions = function()
+ context(result and result.rest and 1 or 0)
+ end
+}
-function commands.mixcleanup()
- if result then
- mixedcolumns.cleanup(result)
- result = nil
+implement {
+ name = "mixcleanup",
+ actions = function()
+ if result then
+ cleanup(result)
+ result = nil
+ end
end
-end
+}
diff --git a/Master/texmf-dist/tex/context/base/page-mix.mkiv b/Master/texmf-dist/tex/context/base/page-mix.mkiv
index 57de14b88b4..b545e8f4c97 100644
--- a/Master/texmf-dist/tex/context/base/page-mix.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-mix.mkiv
@@ -69,6 +69,7 @@
\c!maxheight=\textheight,
\c!maxwidth=\makeupwidth,
\c!grid=\v!tolerant,
+ \c!internalgrid=\v!line,
\c!step=.25\lineheight, % needs some experimenting
%\c!splitmethod=\v!fixed, % will be default
\c!method=\ifinner\s!box\else\s!otr\fi] % automatic as suggested by WS
@@ -167,6 +168,8 @@
[\c!n=\itemgroupparameter\c!n,
\c!separator=\v!none,
\c!splitmethod=\v!none,
+ \c!grid=\v!tolerant,
+ \c!internalgrid=\v!halfline, % new, we may still revert to \v!line
\c!balance=\v!yes]
\unexpanded\def\strc_itemgroups_start_columns
@@ -289,18 +292,32 @@
\installcorenamespace{mixedcolumnsseparator}
-\setvalue{\??mixedcolumnsseparator\v!rule}%
- {\starttextproperties
- \usemixedcolumnscolorparameter\c!rulecolor
- \vrule\s!width\mixedcolumnsparameter\c!rulethickness
- \stoptextproperties}
+\unexpanded\def\installmixedcolumnseparator#1#2%
+ {\setvalue{\??mixedcolumnsseparator#1}{#2}}
+
+\installmixedcolumnseparator\v!rule
+ {\vrule
+ \s!width \mixedcolumnsparameter\c!rulethickness
+ \s!height\mixedcolumnseparatorheight
+ \s!depth \mixedcolumnseparatordepth
+ \relax}
\unexpanded\def\page_mix_command_inject_separator
- {\bgroup
+ {\begingroup
+ \setbox\scratchbox\hbox to \zeropoint \bgroup
+ \hss
+ \starttextproperties
+ \usemixedcolumnscolorparameter\c!rulecolor
+ \csname\??mixedcolumnsseparator\p_separator\endcsname % was \c!rule
+ \stoptextproperties
+ \hss
+ \egroup
+ \ht\scratchbox\zeropoint
+ \dp\scratchbox\zeropoint
\hss
- \csname\??mixedcolumnsseparator\mixedcolumnsparameter\c!separator\endcsname % was \c!rule
+ \box\scratchbox
\hss
- \egroup}
+ \endgroup}
%D We've now arrived at the real code. The start command mostly sets up the
%D environment and variables that are used in the splitter. One of the last
@@ -348,13 +365,13 @@
\csname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname}
\def\page_mix_start_columns_b[#1][#2]%
- {\doifassignmentelse{#1}%
+ {\doifelseassignment{#1}%
{\let\currentmixedcolumns\empty
\page_mix_error_b}
{\edef\currentmixedcolumns{#1}%
\firstargumentfalse}%
\edef\currentmixedcolumnsmethod{\mixedcolumnsparameter\c!method}%
- \mixedcolumnsparameter\c!before\relax % so, it doesn't list to local settings !
+ \mixedcolumnsparameter\c!before\relax % so, it doesn't listen to local settings !
\csname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax
\begingroup
\iffirstargument
@@ -452,6 +469,8 @@
%
\usemixedcolumnscolorparameter\c!color
%
+ \insidecolumnstrue % new
+ %
\nofcolumns\c_page_mix_n_of_columns} % public
%D The otr method related hooks are defined next:
@@ -505,6 +524,10 @@
{\c_page_mix_routine\c_page_mix_routine_balance}%
{\penalty-\plustenthousand}% weird hack, we need to trigger the otr sometimes (new per 20140306, see balancing-001.tex)
\page_otr_trigger_output_routine
+ \ifvoid\b_page_mix_preceding \else
+ % empty columns so we need to make sure pending content is flushed
+ \unvbox\b_page_mix_preceding % new per 2014.10.25
+ \fi
\fi}
\setvalue{\??mixedcolumnsafter\s!otr}%
@@ -521,26 +544,52 @@
\unexpanded\def\page_mix_routine_construct#1%
{\d_page_mix_max_height\mixedcolumnsparameter\c!maxheight % can have changed due to header=high
- \ctxcommand{mixsetsplit {
- box = \number\b_page_mix_collected,
- nofcolumns = \number\c_page_mix_n_of_columns,
- maxheight = \number\d_page_mix_max_height,
- step = \number\d_page_mix_balance_step,
- cycles = \number\c_page_mix_balance_cycles,
- preheight = \number\d_page_mix_preceding_height,
- prebox = \number\b_page_mix_preceding,
- strutht = \number\strutht,
- strutdp = \number\strutdp,
- threshold = \number\d_page_mix_threshold,
- splitmethod = "\mixedcolumnsparameter\c!splitmethod",
- balance = "#1",
- alternative = "\mixedcolumnsparameter\c!alternative",
- grid = \ifgridsnapping true\else false\fi,
- }}%
+ \clf_mixsetsplit
+ box \b_page_mix_collected
+ nofcolumns \c_page_mix_n_of_columns
+ maxheight \d_page_mix_max_height
+ step \d_page_mix_balance_step
+ cycles \c_page_mix_balance_cycles
+ preheight \d_page_mix_preceding_height
+ prebox \b_page_mix_preceding
+ strutht \strutht
+ strutdp \strutdp
+ threshold \d_page_mix_threshold
+ splitmethod {\mixedcolumnsparameter\c!splitmethod}%
+ balance {#1}%
+ alternative {\mixedcolumnsparameter\c!alternative}%
+ internalgrid {\mixedcolumnsparameter\c!internalgrid}%
+ grid \ifgridsnapping true\else false\fi
+ \relax
\deadcycles\zerocount}
+\newdimen\mixedcolumnseparatorheight
+\newdimen\mixedcolumnseparatordepth
+\newdimen\mixedcolumnseparatorwidth
+
+\def\page_mix_routine_package_step
+ {% needs packaging anyway
+ \setbox\scratchbox\page_mix_command_package_column
+ \page_marks_synchronize_column\plusone\c_page_mix_n_of_columns\recurselevel\scratchbox
+ % backgrounds
+ \anch_mark_column_box\scratchbox
+ % for the moment a quick and dirty patch .. we need to go into the box (hence the \plusone) .. a slowdowner
+ \page_lines_add_numbers_to_box\scratchbox\recurselevel\c_page_mix_n_of_columns\plusone
+ % the framed needs a reset of strut, align, setups etc
+ \mixedcolumnseparatorheight\ht\scratchbox
+ \mixedcolumnseparatordepth \dp\scratchbox
+ \inheritedmixedcolumnsframedbox\currentmixedcolumns\scratchbox
+ % optional
+ \ifnum\recurselevel<\c_page_mix_n_of_columns
+ \ifcsname\??mixedcolumnsseparator\p_separator\endcsname
+ \page_mix_command_inject_separator
+ \else
+ \hss
+ \fi
+ \fi}
+
\unexpanded\def\page_mix_routine_package
- {\ctxcommand{mixfinalize()}%
+ {\clf_mixfinalize
\setbox\b_page_mix_collected\vbox \bgroup
\ifvoid\b_page_mix_preceding \else
\page_postprocessors_linenumbers_deepbox\b_page_mix_preceding
@@ -550,26 +599,16 @@
\fi
\hskip\d_page_mix_leftskip
\page_mix_hbox to \d_page_mix_max_width \bgroup
- \dorecurse\c_page_mix_n_of_columns{%
- % needs packaging anyway
- \setbox\scratchbox\page_mix_command_package_column
- \page_marks_synchronize_column\plusone\c_page_mix_n_of_columns\recurselevel\scratchbox
- % for the moment a quick and dirty patch .. we need to go into the box (hence the \plusone) .. a slowdowner
- \page_lines_add_numbers_to_box\scratchbox\recurselevel\c_page_mix_n_of_columns\plusone
- % the framed needs a reset of strut, align, setups etc
- \inheritedmixedcolumnsframedbox\currentmixedcolumns\scratchbox
- % optional
- \ifnum\recurselevel<\c_page_mix_n_of_columns
- \page_mix_command_inject_separator
- \fi
- }%
+ \edef\p_separator{\mixedcolumnsparameter\c!separator}%
+ \mixedcolumnseparatorwidth\d_page_mix_distance % \mixedcolumnsparameter\c!rulethickness\relax
+ \dorecurse\c_page_mix_n_of_columns\page_mix_routine_package_step
\egroup
\egroup}
\unexpanded\def\page_mix_command_package_column
{\page_mix_hbox to \d_page_mix_column_width \bgroup
% maybe intercept empty
- \ctxcommand{mixgetsplit(\recurselevel)}%
+ \clf_mixgetsplit\recurselevel\relax
\hskip-\d_page_mix_column_width
\page_mix_hbox to \d_page_mix_column_width \bgroup
\placenoteinserts
@@ -585,8 +624,8 @@
\page_mix_routine_construct\v!no
\page_mix_routine_package
\page_otr_construct_and_shipout\box\b_page_mix_collected
- \ctxcommand{mixflushrest()}%
- \ctxcommand{mixcleanup()}%
+ \clf_mixflushrest
+ \clf_mixcleanup
\egroup}
\unexpanded\def\page_mix_routine_balance
@@ -597,9 +636,9 @@
\doloop
{%writestatus\m!columns{construct continue (\the\htdp\b_page_mix_collected)}%
\page_mix_routine_construct\v!no
- \ifcase\ctxcommand{mixstate()}\relax
+ \ifcase\clf_mixstate\relax
% 0 = okay, we can balance
- \setbox\b_page_mix_collected\vbox{\ctxcommand{mixflushlist()}}% we could avoid this
+ \setbox\b_page_mix_collected\vbox{\clf_mixflushlist}% we could avoid this
%writestatus\m!columns{construct balance}%
\page_mix_routine_construct\v!yes
\page_mix_routine_package
@@ -614,16 +653,16 @@
\par
\nointerlineskip
\prevdepth\strutdp
- \ctxcommand{mixflushrest()}% rubish
- \ctxcommand{mixcleanup()}% rubish
+ \clf_mixflushrest% rubish
+ \clf_mixcleanup % rubish
\exitloop
\or
% 1 = we have stuff left, so flush and rebalance
%writestatus\m!columns{flush continue}%
\page_mix_routine_package
\page_otr_construct_and_shipout\box\b_page_mix_collected
- \setbox\b_page_mix_collected\vbox{\ctxcommand{mixflushrest()}}% we could avoid this
- \ctxcommand{mixcleanup()}%
+ \setbox\b_page_mix_collected\vbox{\clf_mixflushrest}% we could avoid this
+ \clf_mixcleanup
\ifdim\ht\b_page_mix_collected=\zeropoint
\exitloop
\fi
@@ -718,8 +757,8 @@
\page_mix_routine_construct\v!yes
\page_mix_routine_package
\dontleavehmode\box\b_page_mix_collected
- \ctxcommand{mixflushrest()}%
- \ctxcommand{mixcleanup()}%
+ \clf_mixflushrest
+ \clf_mixcleanup
\egroup}
%D As usual, floats complicates matters and this is where experimental code
@@ -760,11 +799,11 @@
% \unexpanded\def\page_mix_command_flush_top_insertions
% {\page_one_command_flush_top_insertions}
-% \unexpanded\def\page_mix_place_float_top
-% {\showmessage\m!columns4\empty\page_one_place_float_here}
+\unexpanded\def\page_mix_place_float_top
+ {\showmessage\m!columns4\empty\page_one_place_float_here}
-% \unexpanded\def\page_mix_place_float_bottom
-% {\showmessage\m!columns5\empty\page_one_place_float_here}
+\unexpanded\def\page_mix_place_float_bottom
+ {\showmessage\m!columns5\empty\page_one_place_float_here}
\unexpanded\def\page_mix_place_float_here
{\page_one_place_float_here}
diff --git a/Master/texmf-dist/tex/context/base/page-mul.mkiv b/Master/texmf-dist/tex/context/base/page-mul.mkiv
index 0063b3311c5..8db5a47732b 100644
--- a/Master/texmf-dist/tex/context/base/page-mul.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-mul.mkiv
@@ -1430,7 +1430,7 @@
% \stopcolumns
% \def\backgroundfinishcolumnbox
- % {\doifinsetelse\@@kloffset{\v!none,\v!overlay}
+ % {\doifelseinset\@@kloffset{\v!none,\v!overlay}
% {\let\@@kloffset\!!zeropoint}
% {\scratchdimen\@@kloffset
% \advance\scratchdimen -\@@klrulethickness
diff --git a/Master/texmf-dist/tex/context/base/page-one.mkiv b/Master/texmf-dist/tex/context/base/page-one.mkiv
index 3f9dcd7c617..4cf59da2dec 100644
--- a/Master/texmf-dist/tex/context/base/page-one.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-one.mkiv
@@ -454,10 +454,13 @@
\fi\fi
\fi}
+
\def\page_one_place_float_here_indeed
- {%\ifgridsnapping \else
- \baselinecorrection
- %\fi
+ {\ifgridsnapping
+ % otherwise real bad outcome
+ \else
+ \baselinecorrection % this has to be done better (and definitely not in column mode)
+ \fi
\doplacefloatbox
\page_floats_report_total
\dohandlenextfloatindent}
@@ -496,12 +499,12 @@
\def\page_one_place_float_bottom {\page_one_place_float_otherwise}
\def\page_one_place_float_otherwise
- {\doifinsetelse\v!here\floatlocationmethod
+ {\doifelseinset\v!here\floatlocationmethod
\page_one_place_float_otherwise_here
\page_one_place_float_otherwise_else}
\def\page_one_place_float_otherwise_here
- {\doifinsetelse\v!always\floatlocationmethod
+ {\doifelseinset\v!always\floatlocationmethod
{\page[\v!preference]%
\page_otr_command_check_if_float_fits
\ifconditional\c_page_floats_room
@@ -525,7 +528,7 @@
\fi}}
\def\page_one_place_float_otherwise_else
- {\doifinsetelse\v!always\floatlocationmethod
+ {\doifelseinset\v!always\floatlocationmethod
{\page_otr_command_check_if_float_fits
\ifconditional\c_page_floats_room
\page_one_place_float_auto_top_bottom
diff --git a/Master/texmf-dist/tex/context/base/page-pst.lua b/Master/texmf-dist/tex/context/base/page-pst.lua
index 50580ae3316..472bdbabed5 100644
--- a/Master/texmf-dist/tex/context/base/page-pst.lua
+++ b/Master/texmf-dist/tex/context/base/page-pst.lua
@@ -8,16 +8,18 @@ if not modules then modules = { } end modules ['page-pst'] = {
-- todo: adapt message
-local tonumber, next = tonumber, next
-local format, validstring = string.format, string.valid
-local sortedkeys = table.sortedkeys
+local tonumber, next, type = tonumber, next, type
+local find, validstring = string.find, string.valid
-local context = context
-local commands = commands
+local context = context
+local implement = interfaces.implement
local texgetcount = tex.getcount
local texsetcount = tex.setcount
+local sortedkeys = table.sortedkeys
+local formatters = string.formatters
+
local cache = { }
local function flush(page)
@@ -25,7 +27,7 @@ local function flush(page)
if c then
for i=1,#c do
-- characters.showstring(c[i])
- context.viafile(c[i],format("page.%s",validstring(page,"nopage")))
+ context.viafile(c[i],formatters["page.%s"](validstring(page,"nopage")))
end
cache[page] = nil
end
@@ -43,11 +45,11 @@ local function setnextpage()
texsetcount("global","c_page_postponed_blocks_next_page",n)
end
-function commands.flushpostponedblocks(page)
+local function flushpostponedblocks(specification)
-- we need to flush previously pending pages as well and the zero
-- slot is the generic one so that one is always flushed
local t = sortedkeys(cache)
- local p = tonumber(page) or texgetcount("realpageno") or 0
+ local p = tonumber(specification.page) or texgetcount("realpageno") or 0
for i=1,#t do
local ti = t[i]
if ti <= p then
@@ -59,9 +61,19 @@ function commands.flushpostponedblocks(page)
setnextpage()
end
-function commands.registerpostponedblock(page)
+implement {
+ name = "flushpostponedblocks",
+ actions = flushpostponedblocks,
+ arguments = {
+ {
+ { "page" }
+ }
+ }
+}
+
+local function registerpostponedblock(page)
if type(page) == "string" then
- if string.find(page,"^+") then
+ if find(page,"^+") then
page = texgetcount("realpageno") + (tonumber(page) or 1) -- future delta page
else
page = tonumber(page) or 0 -- preferred page or otherwise first possible occasion
@@ -80,7 +92,14 @@ function commands.registerpostponedblock(page)
if page == 0 then
interfaces.showmessage("layouts",3,#c)
else
- interfaces.showmessage("layouts",3,string.format("%s (realpage: %s)",#c,page))
+ interfaces.showmessage("layouts",3,formatters["%s (realpage: %s)"](#c,page))
end
setnextpage()
end
+
+implement {
+ name = "registerpostponedblock",
+ actions = registerpostponedblock,
+ arguments = "string"
+}
+
diff --git a/Master/texmf-dist/tex/context/base/page-pst.mkiv b/Master/texmf-dist/tex/context/base/page-pst.mkiv
index 704289246a3..f12663f6665 100644
--- a/Master/texmf-dist/tex/context/base/page-pst.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-pst.mkiv
@@ -57,10 +57,10 @@
\unexpanded\setvalue{\e!start\v!postponing}%
{\bgroup
\obeylines
- \doifnextoptionalelse{\egroup\page_postponed_blocks_start}{\egroup\page_postponed_blocks_start[0]}}
+ \doifelsenextoptional{\egroup\page_postponed_blocks_start}{\egroup\page_postponed_blocks_start[0]}}
\unexpanded\setvalue{\e!stop\v!postponing}%
- {\ctxcommand{registerpostponedblock("\currentpostponedpage")}\relax}
+ {\clf_registerpostponedblock{\currentpostponedpage}\relax}
\def\page_postponed_blocks_start[#1]%
{\edef\currentpostponedpage{#1}%
@@ -80,7 +80,8 @@
\setnormalcatcodes % postponing in verbatim
\uncatcodespacetokens % postponing in startlines
\restoreglobalbodyfont % otherwise problems inside split verbatim
- \ctxcommand{flushpostponedblocks()}%
+ \clf_flushpostponedblocks
+ % page {123}
\relax
\page_otr_command_flush_floats % new but potential dangerous, maybe we need a classification
\endgroup} % of blocks: with and without flush
diff --git a/Master/texmf-dist/tex/context/base/page-run.mkiv b/Master/texmf-dist/tex/context/base/page-run.mkiv
index 1f2551ebc17..9adcb23c7b3 100644
--- a/Master/texmf-dist/tex/context/base/page-run.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-run.mkiv
@@ -74,9 +74,11 @@
\startluacode
local format, concat = string.format, table.concat
+local todimen = number.todimen
+local texdimen = tex.dimen
-local function todimen(name,unit,fmt)
- return number.todimen(tex.dimen[name],unit,fmt)
+local function asdimen(name,unit)
+ return todimen(texdimen[name],unit,"%0.4f") -- 4 is more than enough, even 3 would be okay
end
local function checkedoptions(options)
@@ -122,7 +124,7 @@ function commands.showlayoutvariables(options)
for i=1,#dimensions do
local d = dimensions[i]
if options[d] then
- context("%s%s",todimen(name,d,"%0.4f"),d)
+ context("%s%s",asdimen(name,d),d)
context.NC()
end
end
@@ -143,7 +145,7 @@ function commands.showlayoutvariables(options)
for i=1,#dimensions do
local d = dimensions[i]
if options[d] then
- result[#result+1] = format("%12s%s",todimen(name,d,"%0.4f"),d)
+ result[#result+1] = format("%12s%s",asdimen(name,d),d)
end
end
commands.writestatus("layout",format("%-24s %s",interfaces.interfacedcommand(name),concat(result," ")))
@@ -297,8 +299,8 @@ end
\unexpanded\gdef\showmargins
{\starttabulate
- \NC asynchrone \NC \doifoddpageelse {odd} {even} \NC \NR
- \NC synchrone \NC \doifrightpageelse {right} {left} \NC \NR
+ \NC asynchrone \NC \doifelseoddpage {odd} {even} \NC \NR
+ \NC synchrone \NC \doifelserightpage {right} {left} \NC \NR
\NC right margin \NC \the\rightmarginwidth \NC \NR
\NC left margin \NC \the\leftmarginwidth \NC \NR
\NC outer margin \NC \the\outermarginwidth \NC \NR
diff --git a/Master/texmf-dist/tex/context/base/page-sel.mkvi b/Master/texmf-dist/tex/context/base/page-sel.mkvi
index cb9bcb509eb..ee25a37db4a 100644
--- a/Master/texmf-dist/tex/context/base/page-sel.mkvi
+++ b/Master/texmf-dist/tex/context/base/page-sel.mkvi
@@ -56,7 +56,7 @@
{\dotripleempty\page_selectors_insert}
\def\page_selectors_insert[#filename][#emptylist][#settings]%
- {\doifassignmentelse{#emptylist}
+ {\doifelseassignment{#emptylist}
{\page_selectors_insert_indeed[#filename][][#emptylist]}
{\page_selectors_insert_indeed[#filename][#emptylist][#settings]}}
diff --git a/Master/texmf-dist/tex/context/base/page-set.mkiv b/Master/texmf-dist/tex/context/base/page-set.mkiv
index 9c232f5358b..8f63dd74e22 100644
--- a/Master/texmf-dist/tex/context/base/page-set.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-set.mkiv
@@ -387,7 +387,7 @@
{\advance\scratchcounter\plusone}}%
\popmacro\columnmaxcells}
-\long\def\OTRSETrecurseRL#1%
+\def\OTRSETrecurseRL#1%
{\dostepwiserecurse\nofcolumns\plusone\minusone
{#1\hskip\namedcolumnsetparameter{\currentcolumnset:\recurselevel}\c!distance}}
@@ -2184,11 +2184,11 @@
\def\dodefinecolumntextarea[#1][#2][#3]% y=0 is mogelijke en handig !
{\ifthirdargument
- \doifinsetelse{#2}{\v!both,\v!fixed}
+ \doifelseinset{#2}{\v!both,\v!fixed}
{\definecolumntextarea[#1][\v!left ][\c!type=#2,#3]%
\definecolumntextarea[#1][\v!right][\c!type=#2,#3]}
{\doifelse{#2}\v!next
- {\doifoddpageelse
+ {\doifelseoddpage
{\definecolumntextarea[#1][\v!right][\c!type=#2,#3]}
{\definecolumntextarea[#1][\v!left ][\c!type=#2,#3]}}
{\presetlocalframed
@@ -2214,7 +2214,7 @@
{\setupcolumntextarea[#1][\v!left ][#3]%
\setupcolumntextarea[#1][\v!right][#3]}
{\doifelse{#2}\v!next
- {\doifoddpageelse
+ {\doifelseoddpage
{\setupcolumntextarea[#1][\v!right][#3]}
{\setupcolumntextarea[#1][\v!left][#3]}}
{\getparameters[\??mt#1#2][#3]}}%
@@ -2379,13 +2379,13 @@
\unexpanded\def\setupcolumntextareatext
{\dotripleempty\dosetupcolumntextareatext}
-\long\def\dosetupcolumntextareatext[#1][#2][#3]%
+\def\dosetupcolumntextareatext[#1][#2][#3]%
{\ifthirdargument
\doifelse{#2}\v!both
{\setvalue{\??mt#1\v!left }{#3}%
\setvalue{\??mt#1\v!right}{#3}}
{\doifelse{#2}\v!next
- {\doifoddpageelse
+ {\doifelseoddpage
{\setvalue{\??mt#1\v!right}{#3}}%
{\setvalue{\??mt#1\v!left }{#3}}}%
{\setvalue{\??mt#1#2}{#3}}}%
diff --git a/Master/texmf-dist/tex/context/base/page-sid.mkiv b/Master/texmf-dist/tex/context/base/page-sid.mkiv
index f7a2357bf34..cbdb95fc371 100644
--- a/Master/texmf-dist/tex/context/base/page-sid.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-sid.mkiv
@@ -15,21 +15,18 @@
\unprotect
-% These macro deal with side floats. We started with Daniel
-% Comenetz macros as published in TUGBoat Volume 14 (1993),
-% No.\ 1: Anchored Figures at Either Margin. I extended and
-% patched the macros to suite our needs which results in a
-% messy module. Therefore, this module badly needs an update
-% because it's now a mixture of old and new macros.
+% These macro deal with side floats. We started with Daniel Comenetz macros as published
+% in TUGBoat Volume 14 (1993), No.\ 1: Anchored Figures at Either Margin. I extended and
+% patched the macros to suite our needs which results in a messy module. Therefore, this
+% module badly needs an update because it's now a mixture of old and new macros.
% Interesting cases where it goes wrong:
%
% \placefigure[left]{}{} \dorecurse{3}{\input ward } {\par} \input ward
%
-% Here we get an unwanted carried over hangindent and parindent. A
-% solution is to associate it with the local par node instead. This
-% is something to discuss with Taco as it could be a new luatex
-% feature: explicitly set par properties.
+% Here we get an unwanted carried over hangindent and parindent. A solution is to associate
+% it with the local par node instead. This is something to discuss with Taco as it could be
+% a new luatex/mkiv feature: explicitly set par properties.
% Maybe I should just rewrite the lot.
@@ -202,17 +199,72 @@
\global\setfalse\c_page_sides_short
\global\setfalse\c_page_sides_flag}
+\unexpanded\def\doifelsesidefloat
+ {\par
+ \ifnum\dimexpr\d_page_sides_vsize-\pagetotal\relax>\zeropoint
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifsidefloatelse\doifelsesidefloat
+
+% \def\page_sides_flush_floats_indeed
+% {\global\advance\d_page_sides_vsize-\d_page_sides_bottomskip
+% \begingroup
+% \let\page_sides_flush_floats\relax
+% \forgetall
+% \doloop
+% {\strut
+% \iftracesidefloats
+% \color[darkgray]{\ruledhbox{\strut\kern\d_page_sides_width}}%
+% \fi
+% \par
+% % \ifdim\dimexpr\d_page_sides_vsize-\pagetotal\relax>\zeropoint
+% \ifdim\dimexpr\d_page_sides_vsize-\d_page_sides_bottomskip-\pagetotal\relax>\zeropoint
+% \ifnum\recurselevel>\plushundred % safeguard, sort of deadcycles
+% \exitloop
+% \fi
+% \else
+% \exitloop
+% \fi}%
+% \endgroup
+% \ifdim\parskip>\zeropoint % why this test ?
+% \ifdim\d_page_sides_bottomskip>\parskip
+% % \nowhitespace
+% % \vskip\d_page_sides_bottomskip
+% \blank[\v!nowhite,\the\dimexpr\d_page_sides_bottomskip]
+% \fi
+% \else
+% \blank[\the\d_page_sides_bottomskip]% new, so needs checking
+% \fi}
+
+\installcorenamespace{sidefloatsteps}
+
+\setvalue{\??sidefloatsteps\v!line }{\strut}
+\setvalue{\??sidefloatsteps\v!big }{\strut}
+\setvalue{\??sidefloatsteps\v!medium}{\halfstrut}
+\setvalue{\??sidefloatsteps\v!small }{\quarterstrut}
+\setvalue{\??sidefloatsteps\v!depth }{\depthstrut}
+
+% we don't officially know what kind of float we flush
+
\def\page_sides_flush_floats_indeed
{\global\advance\d_page_sides_vsize-\d_page_sides_bottomskip
\begingroup
\let\page_sides_flush_floats\relax
+ \edef\m_pages_strut{\executeifdefined{\??sidefloatsteps\rootfloatparameter\c!step}\strut}%
\forgetall
\doloop
- {\strut
- \iftracesidefloats
- \color[darkgray]{\ruledhbox{\strut\kern\d_page_sides_width}}%
+ {\iftracesidefloats
+ \dontleavehmode
+ \ruledhbox{\m_pages_strut\kern\d_page_sides_width}%
+ \else
+ \m_pages_strut
\fi
\par
+ \nointerlineskip
+ % \ifdim\dimexpr\d_page_sides_vsize-\d_page_sides_bottomskip-\pagetotal\relax>\zeropoint
\ifdim\dimexpr\d_page_sides_vsize-\pagetotal\relax>\zeropoint
\ifnum\recurselevel>\plushundred % safeguard, sort of deadcycles
\exitloop
@@ -223,11 +275,28 @@
\endgroup
\ifdim\parskip>\zeropoint % why this test ?
\ifdim\d_page_sides_bottomskip>\parskip
- \nowhitespace
- \vskip\d_page_sides_bottomskip
+ % \nowhitespace
+ % \vskip\d_page_sides_bottomskip
+% \blank[\v!nowhite,\the\dimexpr\d_page_sides_bottomskip]
+ \blank[\v!nowhite,\rootfloatparameter\c!sidespaceafter]
\fi
+ \else
+% \blank[\the\d_page_sides_bottomskip]% new, so needs checking
+ \blank[\rootfloatparameter\c!sidespaceafter]% new, so needs checking
\fi}
+% alternative method (unsnapped)
+%
+% \def\page_sides_flush_floats_indeed
+% {\scratchdimen\dimexpr\d_page_sides_vsize-\d_page_sides_bottomskip-\pagetotal\relax
+% \ifdim\parskip>\zeropoint % why this test ?
+% \ifdim\scratchdimen>\parskip
+% \blank[\v!nowhite,\the\scratchdimen] % better in stages
+% \fi
+% \else
+% \blank[\the\scratchdimen]
+% \fi}
+
\def\page_sides_check_floats_after_par
{\page_sides_check_floats_indeed
\ifdim\oldpagetotal=\pagetotal \else
@@ -764,7 +833,7 @@
\def\checksidefloat {\page_sides_check_floats}
\def\flushsidefloats {\page_sides_flush_floats}
\def\flushsidefloatsafterpar{\page_sides_flush_floats_after_par}
-%def\forgetsidefloats {\page_sides_forget_floats}
+\def\forgetsidefloats {\page_sides_forget_floats}
%def\synchronizesidefloats {\page_sides_synchronize_floats}
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/page-str.lua b/Master/texmf-dist/tex/context/base/page-str.lua
index f2ac27cd9c1..56c6167aa56 100644
--- a/Master/texmf-dist/tex/context/base/page-str.lua
+++ b/Master/texmf-dist/tex/context/base/page-str.lua
@@ -17,6 +17,8 @@ local nodes, node = nodes, node
local nodepool = nodes.pool
local tasks = nodes.tasks
+local implement = interfaces.implement
+
local new_kern = nodepool.kern
local new_glyph = nodepool.glyph
@@ -235,6 +237,60 @@ tasks.disableaction("mvlbuilders", "streams.collect")
function streams.initialize()
tasks.enableaction ("mvlbuilders", "streams.collect")
+ function streams.initialize() end
end
-- todo: remove empty last { }'s
+-- todo: better names, enable etc
+
+implement {
+ name = "initializestream",
+ actions = streams.initialize,
+ onlyonce = true,
+}
+
+implement {
+ name = "enablestream",
+ actions = streams.enable,
+ arguments = "string"
+}
+
+implement {
+ name = "disablestream",
+ actions = streams.disable
+}
+
+implement {
+ name = "startstream",
+ actions = streams.start,
+ arguments = "string"
+}
+
+implement {
+ name = "stopstream",
+ actions = streams.stop
+}
+
+implement {
+ name = "flushstream",
+ actions = streams.flush,
+ arguments = "string"
+}
+
+implement {
+ name = "flushstreamcopy",
+ actions = streams.flush,
+ arguments = { "string", true }
+}
+
+implement {
+ name = "synchronizestream",
+ actions = streams.synchronize,
+ arguments = "string"
+}
+
+implement {
+ name = "pushstream",
+ actions = streams.push,
+ arguments = "string"
+}
diff --git a/Master/texmf-dist/tex/context/base/page-str.mkiv b/Master/texmf-dist/tex/context/base/page-str.mkiv
index a8fab9c6cbb..e4b2fa22980 100644
--- a/Master/texmf-dist/tex/context/base/page-str.mkiv
+++ b/Master/texmf-dist/tex/context/base/page-str.mkiv
@@ -34,7 +34,7 @@
\unprotect
\let \currentoutputstream \empty
-\newif \ifinoutputstream % will becoem a conditional or mode
+\newif \ifinoutputstream % will become a conditional or mode
\newtoks \everyenableoutputstream
\appendtoks
@@ -42,7 +42,7 @@
\to \everyenableoutputstream
\unexpanded\def\initializeoutputstreams
- {\ctxlua{streams.initialize()}%
+ {\clf_initializestream
\glet\initializeoutputstreams\relax}
\unexpanded\def\enableoutputstream[#1]% could be \startoutputsubstream
@@ -50,12 +50,12 @@
\the\everyenableoutputstream
\inoutputstreamtrue
\xdef\currentoutputstream{#1}%
- \ctxlua{streams.enable("#1")}}
+ \clf_enablestream{#1}}
\unexpanded\def\disableoutputstream
{\inoutputstreamfalse
\global\let\currentoutputstream\s!default
- \ctxlua{streams.disable()}}
+ \clf_disablestream}
\unexpanded\def\startoutputstream[#1]%
{\begingroup
@@ -63,10 +63,10 @@
\the\everyenableoutputstream
\inoutputstreamtrue
\xdef\currentoutputstream{#1}%
- \ctxlua{streams.start("#1")}}
+ \clf_startstream{#1}}
\unexpanded\def\stopoutputstream
- {\ctxlua{streams.stop()}%
+ {\clf_stopstream
\endgroup}
\unexpanded\def\startoutputsubstream[#1]% just push/pop instead
@@ -77,13 +77,13 @@
{\globalpopmacro\currentoutputstream
\enableoutputstream[\currentoutputstream]}
-\def\flushoutputstream [#1]{\ctxlua{streams.flush("#1")}}
-\def\outputstreamcopy [#1]{\vbox{\ctxlua{streams.flush("#1",true)}}}
-\def\outputstreambox [#1]{\vbox{\ctxlua{streams.flush("#1")}}}
-\def\outputstreamunvcopy[#1]{\ctxlua{streams.flush("#1",true)}}
-\def\outputstreamunvbox [#1]{\ctxlua{streams.flush("#1")}}
-\def\synchronizestreams [#1]{\ctxlua{streams.synchronize("#1")}}
-\def\dopushoutputstream [#1]{\ctxlua{streams.push("#1")}}
+\def\flushoutputstream [#1]{\clf_flushstream{#1}}
+\def\outputstreambox [#1]{\vbox{\clf_flushstream{#1}}}
+\def\outputstreamcopy [#1]{\vbox{\clf_flushstreamcopy{#1}}}
+\def\outputstreamunvbox [#1]{\clf_flushstream{#1}}
+\def\outputstreamunvcopy[#1]{\clf_flushstreamcopy{#1}}
+\def\synchronizestreams [#1]{\clf_synchronizestream{#1}}
+\def\dopushoutputstream [#1]{\clf_pushstream{#1}}
\unexpanded\def\pushoutputstream
{\dosingleempty\dopushoutputstream}
diff --git a/Master/texmf-dist/tex/context/base/page-txt.mkvi b/Master/texmf-dist/tex/context/base/page-txt.mkvi
index 6d8d50028d9..76143a01859 100644
--- a/Master/texmf-dist/tex/context/base/page-txt.mkvi
+++ b/Master/texmf-dist/tex/context/base/page-txt.mkvi
@@ -142,11 +142,11 @@
%D \showsetup{noheaderandfooterlines}
%D \showsetup{notopandbottomlines}
-\def\noheaderandfooterlines
+\unexpanded\def\noheaderandfooterlines
{\setuplayoutelement[\v!header][\c!state=\v!empty]%
\setuplayoutelement[\v!footer][\c!state=\v!empty]}
-\def\notopandbottomlines
+\unexpanded\def\notopandbottomlines
{\setuplayoutelement[\v!top ][\c!state=\v!empty]%
\setuplayoutelement[\v!bottom][\c!state=\v!empty]}
@@ -253,7 +253,7 @@
%D only when double sided typesetting is enabled.
\unexpanded\def\page_layouts_process_element_double
- {\doifoddpageelse
+ {\doifelseoddpage
\page_layouts_process_element_double_odd
\page_layouts_process_element_double_even}
@@ -378,6 +378,9 @@
\doubleexpandafter\firstoftwoarguments
\fi\fi}
+\let\doiflayouttextlineelse\doifelselayouttextline
+\let\doiflayoutsomelineelse\doifelselayoutsomeline
+
\newconditional\resyncaftertextline
\setvalue{\??layouttextsline\v!normal}{\page_layouts_place_text_line_indeed}
@@ -418,7 +421,7 @@
%D The following macro has to be called after a page
%D is flushed.
-\def\resetlayouttextlines % public
+\unexpanded\def\resetlayouttextlines % public
{\csname\??layouttextsreset\v!top \endcsname
\csname\??layouttextsreset\v!header\endcsname
\csname\??layouttextsreset\v!text \endcsname
@@ -435,7 +438,7 @@
% \settext[header][text][middle][xxx][yyy]
-\def\settextcontent
+\unexpanded\def\settextcontent
{\doquintupleempty\page_layouts_set_text_content}
\def\page_layouts_set_text_content[#vertical][#horizontal][#one][#two][#three]% header text middle text/text
@@ -456,7 +459,7 @@
\c!rightstyle\c!rightcolor\c!rightwidth{#one}}%
\fi\fi\fi}
-\def\resettextcontent
+\unexpanded\def\resettextcontent
{\dotripleempty\page_layouts_reset_text_content}
\def\page_layouts_reset_text_content[#vertical][#horizontal][#tag]% header text middle
@@ -756,10 +759,12 @@
\page_layouts_reset_page_number_location
\ifx\p_strc_pagenumbers_location\empty
% set otherwise
+ \else\ifx\p_strc_pagenumbers_location\v!none
+ % set otherwise
\else
\page_layouts_identify_page_number_location
\page_layouts_set_page_number_location
- \fi
+ \fi\fi
\fi}
\def\page_layouts_place_page_number_left % historic
diff --git a/Master/texmf-dist/tex/context/base/phys-dim.lua b/Master/texmf-dist/tex/context/base/phys-dim.lua
index 870cbd29b0e..7430b62d773 100644
--- a/Master/texmf-dist/tex/context/base/phys-dim.lua
+++ b/Master/texmf-dist/tex/context/base/phys-dim.lua
@@ -50,12 +50,11 @@ local utfchar = utf.char
physics = physics or { }
physics.units = physics.units or { }
-local variables = interfaces.variables
-local v_reverse = variables.reverse
local allocate = utilities.storage.allocate
local context = context
local commands = commands
+local implement = interfaces.implement
local trace_units = false
local report_units = logs.reporter("units")
@@ -173,8 +172,8 @@ local p_c = (ddigitspace^1 * dskipperiod)^0 -- ___.
local p_c_dparser = math_one + math_two + dleader * p_c * dtrailer * dfinal
local c_p_dparser = math_one + math_two + dleader * c_p * dtrailer * dfinal
-function commands.digits(str,p_c)
- if p_c == v_reverse then
+local function makedigits(str,reverse)
+ if reverse then
matchlpeg(p_c_dparser,str)
else
matchlpeg(c_p_dparser,str)
@@ -287,18 +286,29 @@ local long_units = {
-- synonyms
- ["Metric Ton"] = "tonne",
+ MetricTon = "tonne",
Litre = "liter",
+ ["Metric Ton"] = "tonne",
+
-- non-SI units whose values must be obtained experimentally (Table 7)
- ["Electron Volt"] = "electronvolt",
+ AtomicMassUnit = "atomicmassunit",
+ AstronomicalUnit = "astronomicalunit",
+ ElectronVolt = "electronvolt",
Dalton = "dalton",
+
["Atomic Mass Unit"] = "atomicmassunit",
["Astronomical Unit"] = "astronomicalunit",
+ ["Electron Volt"] = "electronvolt",
-- special cases (catch doubles, okay, a bit over the top)
+ DegreesCelsius = "celsius",
+ DegreesFahrenheit = "fahrenheit",
+ DegreeCelsius = "celsius",
+ DegreeFahrenheit = "fahrenheit",
+
["Degrees Celsius"] = "celsius",
["Degrees Fahrenheit"] = "fahrenheit",
["Degree Celsius"] = "celsius",
@@ -323,12 +333,14 @@ local long_units = {
Hg = "mercury",
-- ["Millimetre Of Mercury"] = [[mmHg]],
Angstrom = "angstrom", -- strictly Ångström
- ["Nautical Mile"] = "nauticalmile",
+ NauticalMile = "nauticalmile",
Barn = "barn",
Knot = "knot",
Neper = "neper",
Bel = "bel", -- in practice only decibel used
+ ["Nautical Mile"] = "nauticalmile",
+
-- other non-SI units from CGS system (Table 9)
Erg = "erg",
@@ -601,7 +613,7 @@ labels.units = allocate {
electronvolt = { labels = { en = [[eV]] } },
dalton = { labels = { en = [[Da]] } },
atomicmassunit = { labels = { en = [[u]] } },
- astronomicalunit = { labels = { en = [[ua]] } },
+ astronomicalunit = { labels = { en = [[au]] } },
bar = { labels = { en = [[bar]] } },
angstrom = { labels = { en = [[Å]] } }, -- strictly Ångström
nauticalmile = { labels = { en = [[M]] } },
@@ -799,6 +811,18 @@ local function update_parsers() -- todo: don't remap utf sequences
+ V("nothing") * V("shortunit")
+ V("longprefix") * V("shortunit") -- centi m
+ V("shortprefix") * V("longunit"), -- c meter
+
+-- combination = ( V("longprefix") -- centi meter
+-- + V("nothing")
+-- ) * V("longunit")
+-- + ( V("shortprefix") -- c m
+-- + V("nothing")
+-- + V("longprefix")
+-- ) * V("shortunit") -- centi m
+-- + ( V("shortprefix") -- c meter
+-- ) * V("longunit"),
+
+
dimension = V("somespace")
* (
V("packaged") / dimpre
@@ -812,9 +836,7 @@ local function update_parsers() -- todo: don't remap utf sequences
* V("somespace"),
snippet = V("dimension")
+ V("somesymbol"),
- unit = (
- V("snippet")
- * (V("operator") * V("snippet"))^0
+ unit = ( V("snippet") * (V("operator") * V("snippet"))^0
+ V("somepackaged")
)^1,
}
@@ -854,7 +876,7 @@ local p_c_parser = nil
local c_p_parser = nil
local dirty = true
-function commands.unit(str,p_c)
+local function makeunit(str,reverse)
if dirty then
if trace_units then
report_units("initializing parser")
@@ -863,7 +885,7 @@ function commands.unit(str,p_c)
dirty = false
end
local ok
- if p_c == v_reverse then
+ if reverse then
ok = matchlpeg(p_c_parser,str)
else
ok = matchlpeg(c_p_parser,str)
@@ -909,7 +931,7 @@ local mapping = {
packaged = "packaged",
}
-function commands.registerunit(category,list)
+local function registerunit(category,list)
if not list or list == "" then
list = category
category = "unit"
@@ -922,3 +944,11 @@ function commands.registerunit(category,list)
end
-- inspect(tables)
end
+
+physics.units.registerunit = registerunit
+
+implement { name = "digits_normal", actions = makedigits, arguments = "string" }
+implement { name = "digits_reverse", actions = makedigits, arguments = { "string", true } }
+implement { name = "unit_normal", actions = makeunit, arguments = "string"}
+implement { name = "unit_reverse", actions = makeunit, arguments = { "string", true } }
+implement { name = "registerunit", actions = registerunit, arguments = { "string", "string" } }
diff --git a/Master/texmf-dist/tex/context/base/phys-dim.mkiv b/Master/texmf-dist/tex/context/base/phys-dim.mkiv
index 3de6b23449d..232edc2fc5e 100644
--- a/Master/texmf-dist/tex/context/base/phys-dim.mkiv
+++ b/Master/texmf-dist/tex/context/base/phys-dim.mkiv
@@ -246,12 +246,12 @@
\unexpanded\def\phys_digits_indeed#1%
{\dontleavehmode
\begingroup
- \ctxcommand{digits(\!!bs\detokenize{#1}\!!es,"\ifcase\c_phys_digits_order \v!normal\else\v!reverse\fi")}%
+ \ifcase\c_phys_digits_order\expandafter\clf_digits_normal\else\expandafter\clf_digits_reverse\fi{\detokenize{#1}}%
\endgroup
\settrue\c_phys_units_dospace}
\unexpanded\def\digits
- {\doifnextbgroupelse\phys_digits_argument\phys_digits_spaced}
+ {\doifelsenextbgroup\phys_digits_argument\phys_digits_spaced}
\def\phys_digits_argument#1%
{\phys_digits_indeed{#1}}
@@ -500,7 +500,8 @@
\to \everyunits
\unexpanded\def\phys_units_indeed#1%
- {\ctxcommand{unit(\!!bs\detokenize{#1}\!!es,"\unitparameter\c!order")}}
+ {\edef\p_order{\unitparameter\c!order}%
+ \ifx\p_order\v!reverse\expandafter\clf_unit_reverse\else\expandafter\clf_unit_normal\fi{\detokenize{#1}}}
\unexpanded\def\unitsPUS#1#2#3{\phys_units_next\prefixtext{#1}\unittext{#2}\unitsraise{\suffixtext{#3}}\c_phys_units_state\plusone} % suffix
\unexpanded\def\unitsPU #1#2{\phys_units_next\prefixtext{#1}\unittext{#2}\c_phys_units_state\plusthree} % unit
@@ -578,7 +579,7 @@
\let\unitsNstartindeed\unitsNstart
\unexpanded\def\unitsNstart
- {\doifnextcharelse\unitsNstop\gobbleoneargument\unitsNstartindeed}
+ {\doifelsenextchar\unitsNstop\gobbleoneargument\unitsNstartindeed}
% End of hack.
@@ -682,10 +683,10 @@
\definelabelclass [prefix] [2]
\definelabelclass [suffix] [2] % This is only a label because we want to show them in a table.
-\ctxcommand{definelabels("prefix", "prefixes" )}
-\ctxcommand{definelabels("unit", "units" )}
-\ctxcommand{definelabels("operator","operators")}
-\ctxcommand{definelabels("suffix", "suffixes" )}
+\clf_definelabels{prefix}{prefixes}\s!false\relax
+\clf_definelabels{unit}{units}\s!false\relax
+\clf_definelabels{operator}{operators}\s!false\relax
+\clf_definelabels{suffix}{suffixes}\s!false\relax
%D You can define additional units:
%D
@@ -716,7 +717,7 @@
{\dodoubleempty\phys_units_register}
\def\phys_units_register[#1][#2]%
- {\ctxcommand{registerunit(\!!bs#1\!!es,\!!bs#2\!!es)}}
+ {\clf_registerunit{#1}{#2}}
%D You can generate a list as follows:
%D
diff --git a/Master/texmf-dist/tex/context/base/ppchtex.mkiv b/Master/texmf-dist/tex/context/base/ppchtex.mkiv
index 0f42f91ce9b..d1167d4143a 100644
--- a/Master/texmf-dist/tex/context/base/ppchtex.mkiv
+++ b/Master/texmf-dist/tex/context/base/ppchtex.mkiv
@@ -100,11 +100,11 @@
\newconstant\chemicaldrawingmode
-\doifdefinedelse{beginpicture} % PiCTeX
- {\doifdefinedelse{startMPdrawing}
+\doifelsedefined{beginpicture} % PiCTeX
+ {\doifelsedefined{startMPdrawing}
{\chemicaldrawingmode\plustwo } % MetaPost
{\chemicaldrawingmode\zerocount}} % raw
- {\doifdefinedelse{psaxes}
+ {\doifelsedefined{psaxes}
{\chemicaldrawingmode\plusone } % PSTricks
{\chemicaldrawingmode\plusthree}} % unknown
@@ -387,7 +387,7 @@
{\def\maxchemical{#1}}
\def\doifchemicalnumber#1#2#3%
- {\doifnumberelse{#1}
+ {\doifelsenumber{#1}
{\ifnum#1>\maxchemical\relax
\writestatus{ppchtex}{number #1 is skipped}%
\else
@@ -682,7 +682,7 @@
\edef\@@chemicaltop {\the\!!countc}%
\edef\@@chemicalbottom{\the\!!countd}%
%
- \doifinsetelse\v!on{\@@chemicalframe,\@@chemicalaxis}
+ \doifelseinset\v!on{\@@chemicalframe,\@@chemicalaxis}
{\def\@@chemicalborder{\chemicalframe}}
{\def\@@chemicalborder{\normalchemicalframe}}%
%
@@ -867,14 +867,14 @@
\def\chemicalrepeat {1}
\def\redoprocesschemical[#1#2]%
- {\doifinstringelse{#1}{0123456789.}
+ {\doifelseinstring{#1}{0123456789.}
{\edef\chemicalrepeat{\chemicalrepeat#1}%
\redoprocesschemical[#2]}
{\processchemical[#1#2]%
\def\chemicalrepeat{1}}}
\def\doprocesschemical[#1#2]#3%
- {\doifinstringelse{#1}{0123456789.}
+ {\doifelseinstring{#1}{0123456789.}
{\def\chemicalrepeat{#1}%
\redoprocesschemical[#2]}
{#3}}
@@ -891,9 +891,9 @@
\divide\dimen0 by \@@localchemicalscale
\!!counta=\dimen0
\def\doprocess[##1##2]%
- {\doifinstringelse{##1}{128}
+ {\doifelseinstring{##1}{128}
{\edef\chemicaloffset{\the\!!counta}}
- {\doifinstringelse{##1}{456}
+ {\doifelseinstring{##1}{456}
{\edef\chemicaloffset{-\the\!!counta}}
{\doifelse{##1}{0}
{\edef\chemicaloffset{0}}
@@ -917,9 +917,9 @@
\dimen0=.25\wd0
\divide\dimen0 by \@@localchemicalscale
\!!counta=\dimen0
- \doifinstringelse{#1}{128}
+ \doifelseinstring{#1}{128}
{\edef\chemicaloffset{\the\!!counta}}
- {\doifinstringelse{#1}{456}
+ {\doifelseinstring{#1}{456}
{\edef\chemicaloffset{-\the\!!counta}}
{\doifelse{#1}{0}
{\edef\chemicaloffset{0}}
@@ -959,7 +959,7 @@
\setvalue{\s!angle4.#1}{\dosetchemicalangle{#5}}}
\def\chemicalrotate[#1]%
- {\doifdefinedelse{\s!mirror#1}
+ {\doifelsedefined{\s!mirror#1}
{\getvalue{\s!rotate\chemicalrotation.#1\getvalue{\s!mirror#1}}%
\getvalue{\s!angle\chemicalrotation.#1\getvalue{\s!mirror#1}}}
{\getvalue{\s!rotate\chemicalrotation.#1}%
@@ -984,7 +984,7 @@
\def\processchemicalrotation#1%
{\def\doprocess[##1##2]%
- {\doifnumberelse{##1}
+ {\doifelsenumber{##1}
{\def\chemicalrotation{##1}}
{\unknownchemical{ROT#1}}}%
\doprocess[#1]}
@@ -1067,9 +1067,11 @@
\def\dodoifsinglelocation#1#2\\#3%
{\ifx#2\relax#3\fi}
-\def\doifsinglelocationelse#1%
+\def\doifelsesinglelocation#1%
{\expandafter\dodoifsinglelocationelse#1\relax\\}
+\let\doifsinglelocationelse\doifelsesinglelocation
+
\def\putchemicaltext#1#2%
{\enablechemicalspecials
\ifchemicalpicture
@@ -1706,7 +1708,7 @@
\newif\ifinnerchemical
\def\dosimplechemical#1#2#3%
- {\doifdefinedelse{\??chemical\c!location}
+ {\doifelsedefined{\??chemical\c!location}
{\writestatus{ppchtex}{the {}{}-alternative is not permitted here}}
{\ifinnerchemical
\let\chemicalsign = \chemicalinnersign
@@ -2065,7 +2067,7 @@
HIGH=>\sethighsubscripts,
LOW=>\setlowsubscripts,
\s!default=>,
- \s!unknown=>\doifdefinedelse{\s!executechemical#1}
+ \s!unknown=>\doifelsedefined{\s!executechemical#1}
{\def\chemicalrotation{1}%
\def\chemicaloffset{0}%
\doifdefined{\s!executechemical#1}
@@ -2260,9 +2262,9 @@
{\dosingleargument\dodefinechemical}
\def\getpredefinedchemical#1%
- {\doifdefinedelse{\??chemical#1}
+ {\doifelsedefined{\??chemical#1}
{\getvalue{\??chemical#1}}
- {\doifdefinedelse{#1}
+ {\doifelsedefined{#1}
{\getvalue{#1}}
{\writestatus{ppchtex}{unknown chemical definition #1}}}}
diff --git a/Master/texmf-dist/tex/context/base/publ-aut.lua b/Master/texmf-dist/tex/context/base/publ-aut.lua
index ba492a93bd6..820ac78ff3b 100644
--- a/Master/texmf-dist/tex/context/base/publ-aut.lua
+++ b/Master/texmf-dist/tex/context/base/publ-aut.lua
@@ -11,23 +11,32 @@ if not characters then
dofile(resolvers.findfile("char-ini.lua"))
end
-local context = context
-local chardata = characters.data
+local lpeg = lpeg
-local tostring = tostring
+local type, next, tostring = type, next, tostring
local concat = table.concat
-local lpeg = lpeg
local utfchar = utf.char
+local formatters = string.formatters
+
+local P, C, V, Cs, Ct, Cg, Cf, Cc = lpeg.P, lpeg.C, lpeg.V, lpeg.Cs, lpeg.Ct, lpeg.Cg, lpeg.Cf, lpeg.Cc
+local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
+
+local context = context
+----- commands = commands
-local publications = publications or { }
+local implement = interfaces.implement
+local ctx_setmacro = interfaces.setmacro
-local datasets = publications.datasets or { }
-publications.datasets = datasets
+local publications = publications
-publications.authors = publications.authors or { }
-local authors = publications.authors
+local datasets = publications.datasets
+local getcasted = publications.getcasted
-local P, C, V, Cs, Ct, lpegmatch, lpegpatterns = lpeg.P, lpeg.C, lpeg.V, lpeg.Cs, lpeg.Ct, lpeg.match, lpeg.patterns
+local allocate = utilities.storage.allocate
+
+local chardata = characters.data
+
+local report = logs.reporter("publications","authors")
-- local function makesplitter(separator)
-- return Ct { "start",
@@ -38,17 +47,26 @@ local P, C, V, Cs, Ct, lpegmatch, lpegpatterns = lpeg.P, lpeg.C, lpeg.V, lpeg.Cs
-- }
-- end
-local space = P(" ")
+-- authorlist = { authorspec and authorspec and authorspec }
+-- authorspec = composedname
+-- authorspec = surnames, firstnames
+-- authorspec = von, surnames, firstnames
+-- authorspec = von, surnames, jr, firstnames
+-- authorspec = von, surnames, jr, firstnames, initials
+
+local space = lpegpatterns.whitespace
local comma = P(",")
+local period = P(".")
+local dash = P("-")
local firstcharacter = lpegpatterns.utf8byte
+local utf8character = lpegpatterns.utf8character
+local p_and = space^1 * (P("and") + P("&&") + P("++")) * space^1
+local p_comma = space^0 * comma * space^0
+local p_space = space^1
+local p_shortone = C((utf8character -dash-period)^1)
+local p_longone = C( utf8character) * (1-dash-period)^0
--- local andsplitter = lpeg.tsplitat(space^1 * "and" * space^1)
--- local commasplitter = lpeg.tsplitat(space^0 * comma * space^0)
--- local spacesplitter = lpeg.tsplitat(space^1)
-
-local p_and = space^1 * "and" * space^1
-local p_comma = space^0 * comma * space^0
-local p_space = space^1
+local p_empty = P("{}")/"" * #(p_space^0 * (P(-1) + P(",")))
local andsplitter = Ct { "start",
start = (Cs((V("inner") + (1-p_and))^1) + p_and)^1,
@@ -56,7 +74,7 @@ local andsplitter = Ct { "start",
}
local commasplitter = Ct { "start",
- start = Cs(V("outer")) + (Cs((V("inner") + (1-p_comma))^1) + p_comma)^1,
+ start = Cs(V("outer")) + (p_empty + Cs((V("inner") + (1-p_comma))^1) + p_comma)^1,
outer = (P("{")/"") * ((V("inner") + P(1-P("}")))^1) * (P("}")/""),
inner = P("{") * ((V("inner") + P(1-P("}")))^1) * P("}"),
}
@@ -67,18 +85,40 @@ local spacesplitter = Ct { "start",
inner = P("{") * ((V("inner") + P(1-P("}")))^1) * P("}"),
}
+local p_initial = p_shortone * period * dash^0
+ + p_longone * (period + dash + P(-1))
+local initialsplitter = p_initial * P(-1) + Ct((p_initial)^1)
+
+local optionsplitter = Cf(Ct("") * Cg(C((1-space)^1) * space^0 * Cc(true))^1,rawset)
+
local function is_upper(str)
local first = lpegmatch(firstcharacter,str)
local okay = chardata[first]
return okay and okay.category == "lu"
end
+-- local cleaner = Cs( ( P("{}")/"" + P(1) )^1 )
+
local cache = { } -- 33% reuse on tugboat.bib
local nofhits = 0
local nofused = 0
+publications.authorcache = cache
+
+local function makeinitials(firstnames)
+ if firstnames and #firstnames > 0 then
+ local initials = { }
+ for i=1,#firstnames do
+ initials[i] = lpegmatch(initialsplitter,firstnames[i])
+ end
+ return initials
+ end
+end
+
local function splitauthorstring(str)
- if not str then
+ if str then
+ -- str = lpegmatch(cleaner,str)
+ else
return
end
nofused = nofused + 1
@@ -97,12 +137,15 @@ local function splitauthorstring(str)
-- print("hit 2",author,nofhits,nofused,math.round(100*nofhits/nofused))
end
if not detail then
- local firstnames, vons, surnames, initials, juniors
+ local firstnames, vons, surnames, initials, juniors, options
local split = lpegmatch(commasplitter,author)
--- inspect(split)
local n = #split
+ detail = {
+ original = author,
+ snippets = n,
+ }
if n == 1 then
- -- First von Last
+ -- {First Middle von Last}
local words = lpegmatch(spacesplitter,author)
firstnames, vons, surnames = { }, { }, { }
local i, n = 1, #words
@@ -132,14 +175,17 @@ local function splitauthorstring(str)
else
-- mess
end
- -- safeguard
if #surnames == 0 then
+ -- safeguard
firstnames = { }
vons = { }
surnames = { author }
+ else
+ initials = makeinitials(firstnames)
end
elseif n == 2 then
- -- von Last, First
+ -- {Last, First}
+ -- {von Last, First}
firstnames, vons, surnames = { }, { }, { }
local words = lpegmatch(spacesplitter,split[1])
local i, n = 1, #words
@@ -168,33 +214,44 @@ local function splitauthorstring(str)
while i <= n do
vons[#vons+1], i = words[i], i + 1
end
- else
- -- von Last, Jr ,First
- firstnames = lpegmatch(spacesplitter,split[1])
- juniors = lpegmatch(spacesplitter,split[2])
- surnames = lpegmatch(spacesplitter,split[3])
- if n > 3 then
- -- error
+ if surnames and firstnames and #surnames == 0 then
+ -- safeguard
+ surnames[1] = firstnames[#firstnames]
+ firstnames[#firstnames] = nil
end
- end
- if #surnames == 0 then
- surnames[1] = firstnames[#firstnames]
- firstnames[#firstnames] = nil
- end
- if firstnames then
- initials = { }
- for i=1,#firstnames do
- initials[i] = utfchar(lpegmatch(firstcharacter,firstnames[i]))
+ initials = makeinitials(firstnames)
+ elseif n == 3 then
+ -- {von Last, First, Jr}
+ surnames = lpegmatch(spacesplitter,split[1])
+ juniors = lpegmatch(spacesplitter,split[2])
+ firstnames = lpegmatch(spacesplitter,split[3])
+ initials = makeinitials(firstnames)
+ elseif n == 4 then
+ -- {Von, Last, First, Jr}
+ vons = lpegmatch(spacesplitter,split[1])
+ surnames = lpegmatch(spacesplitter,split[2])
+ juniors = lpegmatch(spacesplitter,split[3])
+ firstnames = lpegmatch(spacesplitter,split[4])
+ initials = makeinitials(firstnames)
+ elseif n >= 5 then
+ -- {Von, Last, First, Jr, F.}
+ -- {Von, Last, First, Jr, Fr., options}
+ vons = lpegmatch(spacesplitter,split[1])
+ surnames = lpegmatch(spacesplitter,split[2])
+ juniors = lpegmatch(spacesplitter,split[3])
+ firstnames = lpegmatch(spacesplitter,split[4])
+ initials = lpegmatch(spacesplitter,split[5])
+ options = split[6]
+ if options then
+ options = lpegmatch(optionsplitter,options)
end
end
- detail = {
- original = author,
- firstnames = firstnames,
- vons = vons,
- surnames = surnames,
- initials = initials,
- juniors = juniors,
- }
+ if firstnames and #firstnames > 0 then detail.firstnames = firstnames end
+ if vons and #vons > 0 then detail.vons = vons end
+ if surnames and #surnames > 0 then detail.surnames = surnames end
+ if initials and #initials > 0 then detail.initials = initials end
+ if juniors and #juniors > 0 then detail.juniors = juniors end
+ if options and next(options) then detail.options = options end
cache[author] = detail
nofhits = nofhits + 1
end
@@ -203,348 +260,326 @@ local function splitauthorstring(str)
return authors
end
--- local function splitauthors(dataset,tag,field)
--- local entries = datasets[dataset]
--- local luadata = entries.luadata
--- if not luadata then
--- return { }
--- end
--- local entry = luadata[tag]
--- if not entry then
--- return { }
--- end
--- return splitauthorstring(entry[field])
--- end
-
-local function the_initials(initials,symbol)
- local t, symbol = { }, symbol or "."
+local function the_initials(initials,symbol,connector)
+ if not symbol then
+ symbol = "."
+ end
+ if not connector then
+ connector = "-"
+ end
+ local result, r = { }, 0
for i=1,#initials do
- t[i] = initials[i] .. symbol
+ local initial = initials[i]
+ if type(initial) == "table" then
+ local set, s = { }, 0
+ for i=1,#initial do
+ if i > 1 then
+ s = s + 1 ; set[s] = connector
+ end
+ s = s + 1 ; set[s] = initial[i]
+ s = s + 1 ; set[s] = symbol
+ end
+ r = r + 1 ; result[r] = concat(set)
+ else
+ r = r + 1 ; result[r] = initial .. symbol
+ end
end
- return t
+ return result
end
--- authors
-
-local settings = { }
-
--- local defaultsettings = {
--- firstnamesep = " ",
--- vonsep = " ",
--- surnamesep = " ",
--- juniorsep = " ",
--- surnamejuniorsep = ", ",
--- juniorjuniorsep = ", ",
--- surnamefirstnamesep = ", ",
--- surnameinitialsep = ", ",
--- namesep = ", ",
--- lastnamesep = " and ",
--- finalnamesep = " and ",
--- etallimit = 1000,
--- etaldisplay = 1000,
--- etaltext = "",
--- }
-
-local defaultsettings = {
- firstnamesep = [[\btxlistvariantparameter{firstnamesep}]],
- vonsep = [[\btxlistvariantparameter{vonsep}]],
- surnamesep = [[\btxlistvariantparameter{surnamesep}]],
- juniorsep = [[\btxlistvariantparameter{juniorsep}]],
- surnamejuniorsep = [[\btxlistvariantparameter{surnamejuniorsep}]],
- juniorjuniorsep = [[\btxlistvariantparameter{juniorjuniorsep}]],
- surnamefirstnamesep = [[\btxlistvariantparameter{surnamefirstnamesep}]],
- surnameinitialsep = [[\btxlistvariantparameter{surnameinitialsep}]],
- namesep = [[\btxlistvariantparameter{namesep}]],
- lastnamesep = [[\btxlistvariantparameter{lastnamesep}]],
- finalnamesep = [[\btxlistvariantparameter{finalnamesep}]],
- --
- etaltext = [[\btxlistvariantparameter{etaltext}]],
- --
- etallimit = 1000,
- etaldisplay = 1000,
-}
-
-function authors.setsettings(s)
+local ctx_btxsetconcat = context.btxsetconcat
+local ctx_btxsetoverflow = context.btxsetoverflow
+local ctx_btxsetinitials = context.btxsetinitials
+local ctx_btxsetfirstnames = context.btxsetfirstnames
+local ctx_btxsetvons = context.btxsetvons
+local ctx_btxsetsurnames = context.btxsetsurnames
+local ctx_btxsetjuniors = context.btxsetjuniors
+local ctx_btxciteauthorsetup = context.btxciteauthorsetup
+local ctx_btxlistauthorsetup = context.btxlistauthorsetup
+local ctx_btxsetauthorvariant = context.btxsetauthorvariant
+local ctx_btxstartauthor = context.btxstartauthor
+local ctx_btxstopauthor = context.btxstopauthor
+
+local concatstate = publications.concatstate
+local f_invalid = formatters[""]
+
+local currentauthordata = nil
+local currentauthorsymbol = nil
+
+local manipulators = typesetters.manipulators
+local splitmanipulation = manipulators.splitspecification
+local applymanipulation = manipulators.applyspecification
+local manipulatormethods = manipulators.methods
+
+local function value(i,field)
+ if currentauthordata then
+ local entry = currentauthordata[i]
+ if entry then
+ local value = entry[field]
+ if value and #value > 0 then
+ return value
+ end
+ end
+ end
end
-authors.splitstring = splitauthorstring
-
--- [firstnames] [firstnamesep] [vons] [vonsep] [surnames] [juniors] [surnamesep] (Taco, von Hoekwater, jr)
-
-function authors.normal(author,settings)
- local firstnames, vons, surnames, juniors = author.firstnames, author.vons, author.surnames, author.juniors
- local result, settings = { }, settings or defaultsettings
- if firstnames and #firstnames > 0 then
- result[#result+1] = concat(firstnames," ")
- result[#result+1] = settings.firstnamesep or defaultsettings.firstnamesep
- end
- if vons and #vons > 0 then
- result[#result+1] = concat(vons," ")
- result[#result+1] = settings.vonsep or defaultsettings.vonsep
- end
- if surnames and #surnames > 0 then
- result[#result+1] = concat(surnames," ")
- if juniors and #juniors > 0 then
- result[#result+1] = settings.surnamejuniorsep or defaultsettings.surnamejuniorsep
- result[#result+1] = concat(juniors," ")
+implement { name = "btxcurrentfirstnames", arguments = "integer", actions = function(i) local v = value(i,"initials") if v then context(concat(the_initials(v,currentauthorsymbol))) end end }
+implement { name = "btxcurrentinitials", arguments = "integer", actions = function(i) local v = value(i,"firstnames") if v then context(concat(v," ")) end end }
+implement { name = "btxcurrentjuniors", arguments = "integer", actions = function(i) local v = value(i,"juniors") if v then context(concat(v," ")) end end }
+implement { name = "btxcurrentsurnames", arguments = "integer", actions = function(i) local v = value(i,"surnames") if v then context(concat(v," ")) end end }
+implement { name = "btxcurrentvons", arguments = "integer", actions = function(i) local v = value(i,"vons") if v then context(concat(v," ")) end end }
+
+local function btxauthorfield(i,field)
+ if currentauthordata then
+ local entry = currentauthordata[i]
+ if entry then
+ local manipulator, field = splitmanipulation(field)
+ local value = entry[field]
+ if not value or #value == 0 then
+ -- value, no need for message
+ elseif manipulator then
+ for i=1,#value do
+ if i > 1 then
+ context(" ")
+ end
+ context(applymanipulation(manipulator,value) or value)
+ end
+ elseif field == "initials" then
+ context(concat(the_initials(value,currentauthorsymbol)))
+ else
+ context(concat(value," "))
+ end
end
- elseif juniors and #juniors > 0 then
- result[#result+1] = concat(juniors," ")
end
- return concat(result)
end
--- [initials] [initialsep] [vons] [vonsep] [surnames] [juniors] [surnamesep] (T, von Hoekwater, jr)
+-- This is somewhat tricky: an author is not always an author but
+-- can also be a title or key, depending on the (optional) set it's
+-- in. Also, authors can be combined with years and so and they
+-- might be called upon mixed with other calls.
+
+local function btxauthor(dataset,tag,field,settings)
+ local split, usedfield, kind = getcasted(dataset,tag,field)
+ if kind == "author" then
+ local max = split and #split or 0
+ if max == 0 then
+ return
+ -- error
+ end
+ local etallimit = tonumber(settings.etallimit) or 1000
+ local etaldisplay = tonumber(settings.etaldisplay) or etallimit
+ local combiner = settings.combiner
+ local symbol = settings.symbol
+ local index = settings.index
+ if not combiner or combiner == "" then
+ combiner = "normal"
+ end
+ if not symbol then
+ symbol = "."
+ end
+ local ctx_btxsetup = settings.kind == "cite" and ctx_btxciteauthorsetup or ctx_btxlistauthorsetup
+ if max > etallimit and etaldisplay < max then
+ max = etaldisplay
+ end
+ currentauthordata = split
+ currentauthorsymbol = symbol
-function authors.normalshort(author,settings)
- local initials, vons, surnames, juniors = author.initials, author.vons, author.surnames, author.juniors
- local result, settings = { }, settings or defaultsettings
- if initials and #initials > 0 then
- result[#result+1] = concat(initials," ")
- result[#result+1] = settings.initialsep or defaultsettings.initialsep
- end
- if vons and #vons > 0 then
- result[#result+1] = concat(vons," ")
- result[#result+1] = settings.vonsep or defaultsettings.vonsep
- end
- if surnames and #surnames > 0 then
- result[#result+1] = concat(surnames," ")
- if juniors and #juniors > 0 then
- result[#result+1] = settings.surnamejuniorsep or defaultsettings.surnamejuniorsep
- result[#result+1] = concat(juniors," ")
+ local function oneauthor(i)
+ local author = split[i]
+ if index then
+ ctx_btxstartauthor(i,1,0)
+ else
+ local state = author.state or 0
+ ctx_btxstartauthor(i,max,state)
+ ctx_btxsetconcat(concatstate(i,max))
+ ctx_btxsetauthorvariant(combiner)
+ end
+ local initials = author.initials
+ if initials and #initials > 0 then
+ ctx_btxsetinitials() -- (concat(the_initials(initials,symbol)," "))
+ end
+ local firstnames = author.firstnames
+ if firstnames and #firstnames > 0 then
+ ctx_btxsetfirstnames() -- (concat(firstnames," "))
+ end
+ local vons = author.vons
+ if vons and #vons > 0 then
+ ctx_btxsetvons() -- (concat(vons," "))
+ end
+ local surnames = author.surnames
+ if surnames and #surnames > 0 then
+ ctx_btxsetsurnames() -- (concat(surnames," "))
+ end
+ local juniors = author.juniors
+ if juniors and #juniors > 0 then
+ ctx_btxsetjuniors() -- (concat(juniors," "))
+ end
+ if not index and i == max then
+ local overflow = #split - max
+ if overflow > 0 then
+ ctx_btxsetoverflow(overflow)
+ end
+ end
+ ctx_btxsetup(combiner)
+ ctx_btxstopauthor()
+ end
+ if index then
+ oneauthor(index)
+ else
+ for i=1,max do
+ oneauthor(i)
+ end
end
- elseif juniors and #juniors > 0 then
- result[#result+1] = concat(juniors," ")
+ else
+ report("ignored field %a of tag %a, used field %a is no author",field,tag,usedfield)
end
- return concat(result)
end
--- vons surnames juniors, firstnames
+implement {
+ name = "btxauthorfield",
+ actions = btxauthorfield,
+ arguments = { "integer", "string" }
+}
--- [vons] [vonsep] [surnames] [surnamejuniorsep] [juniors] [surnamefirstnamesep] [firstnames] (von Hoekwater jr, Taco)
+implement {
+ name = "btxauthor",
+ actions = btxauthor,
+ arguments = {
+ "string",
+ "string",
+ "string",
+ {
+ { "combiner" },
+ { "kind" },
+ { "etallimit" },
+ { "etaldisplay" },
+ { "symbol" },
+ }
+ }
+}
-function authors.inverted(author,settings)
- local firstnames, vons, surnames, juniors = author.firstnames, author.vons, author.surnames, author.juniors
- local result, settings = { }, settings or defaultsettings
- if vons and #vons > 0 then
- result[#result+1] = concat(vons," ")
- result[#result+1] = settings.vonsep or defaultsettings.vonsep
- end
- if surnames and #surnames > 0 then
- result[#result+1] = concat(surnames," ")
- if juniors and #juniors > 0 then
- result[#result+1] = settings.surnamejuniorsep or defaultsettings.surnamejuniorsep
- result[#result+1] = concat(juniors," ")
- end
- elseif juniors and #juniors > 0 then
- result[#result+1] = concat(juniors," ")
- end
- if firstnames and #firstnames > 0 then
- result[#result+1] = settings.surnamefirstnamesep or defaultsettings.surnamefirstnamesep
- result[#result+1] = concat(firstnames," ")
- end
- return concat(result)
+local function components(snippet,short)
+ local vons = snippet.vons
+ local surnames = snippet.surnames
+ local initials = snippet.initials
+ local firstnames = not short and snippet.firstnames
+ local juniors = snippet.juniors
+ return
+ vons and #vons > 0 and concat(vons," ") or "",
+ surnames and #surnames > 0 and concat(surnames," ") or "",
+ initials and #initials > 0 and concat(the_initials(initials)," ") or "",
+ firstnames and #firstnames > 0 and concat(firstnames," ") or "",
+ juniors and #juniors > 0 and concat(juniors, " ") or ""
end
--- [vons] [vonsep] [surnames] [surnamejuniorsep] [juniors] [surnamefirstnamesep] [initials] (von Hoekwater jr, T)
+local collapsers = allocate { }
-function authors.invertedshort(author,settings)
- local vons, surnames, initials, juniors = author.vons, author.surnames, author.initials, author.juniors
- local result, settings = { }, settings or defaultsettings
+publications.authorcollapsers = collapsers
+
+local function default(author)
+ local vons = author.vons
+ local surnames = author.surnames
+ local initials = author.initials
+ local firstnames = author.firstnames
+ local juniors = author.juniors
+ local result = { }
+ local nofresult = 0
if vons and #vons > 0 then
- result[#result+1] = concat(vons," ")
- result[#result+1] = settings.vonsep or defaultsettings.vonsep
+ nofresult = nofresult + 1 ; result[nofresult] = concat(vons," ")
end
if surnames and #surnames > 0 then
- result[#result+1] = concat(surnames," ")
- if juniors and #juniors > 0 then
- result[#result+1] = settings.surnamejuniorsep or defaultsettings.surnamejuniorsep
- result[#result+1] = concat(juniors," ")
- end
- elseif juniors and #juniors > 0 then
- result[#result+1] = concat(juniors," ")
+ nofresult = nofresult + 1 ; result[nofresult] = concat(surnames," ")
end
if initials and #initials > 0 then
- result[#result+1] = settings.surnameinitialsep or defaultsettings.surnameinitialsep
- result[#result+1] = concat(the_initials(initials)," ")
+ nofresult = nofresult + 1 ; result[nofresult] = concat(the_initials(initials)," ")
end
- return concat(result)
-end
-
-local lastconcatsize = 1
-
-local function concatnames(t,settings)
- local namesep = settings.namesep
- local lastnamesep = settings.lastnamesep
- local finalnamesep = settings.finalnamesep
- local lastconcatsize = #t
- if lastconcatsize > 2 then
- local s = { }
- for i=1,lastconcatsize-2 do
- s[i] = t[i] .. namesep
- end
- s[lastconcatsize-1], s[lastconcatsize] = t[lastconcatsize-1] .. finalnamesep, t[lastconcatsize]
- return concat(s)
- elseif lastconcatsize > 1 then
- return concat(t,lastnamesep)
- elseif lastconcatsize > 0 then
- return t[1]
- else
- return ""
+ if firstnames and #firstnames > 0 then
+ nofresult = nofresult + 1 ; result[nofresult] = concat(firstnames," ")
end
+ if juniors and #juniors > 0 then
+ nofresult = nofresult + 1 ; result[nofresult] = concat(juniors," ")
+ end
+ return concat(result," ")
end
-function authors.concat(dataset,tag,field,settings)
- table.setmetatableindex(settings,defaultsettings)
- local combiner = settings.combiner
- if not combiner or type(combiner) == "string" then
- combiner = authors[combiner or "normal"] or authors.normal
- end
- local split = datasets[dataset].details[tag][field]
- local etallimit = settings.etallimit or 1000
- local etaldisplay = settings.etaldisplay or etallimit
- local max = split and #split or 0
- if max == 0 then
- -- error
- end
- if max > etallimit and etaldisplay < max then
- max = etaldisplay
+collapsers.default = default
+
+local function writer(key,snippets)
+ if not key then
+ return ""
end
- local combined = { }
- for i=1,max do
- combined[i] = combiner(split[i],settings)
+ if type(key) == "string" then
+ return key
end
- local result = concatnames(combined,settings)
- if #combined <= max then
- return result
+ local n = #key
+ if n == 0 then
+ return ""
+ elseif n == 1 then
+ local author = key[1]
+ local options = author.options
+ if options then
+ for option in next, options do
+ local collapse = collapsers[option]
+ if collapse then
+ return collapse(author)
+ end
+ end
+ end
+ return default(author)
else
- return result .. settings.etaltext
- end
-end
-
-function commands.btxauthor(...)
- context(authors.concat(...))
-end
-
-function authors.short(author,year)
- -- todo
--- local result = { }
--- if author then
--- local authors = splitauthors(author)
--- for a=1,#authors do
--- local aa = authors[a]
--- local initials = aa.initials
--- for i=1,#initials do
--- result[#result+1] = initials[i]
--- end
--- local surnames = aa.surnames
--- for s=1,#surnames do
--- result[#result+1] = utfchar(lpegmatch(firstcharacter,surnames[s]))
--- end
--- end
--- end
--- if year then
--- result[#result+1] = year
--- end
--- return concat(result)
-end
-
--- We can consider creating a hashtable key -> entry but I wonder if
--- pays off.
-
-local compare = sorters.comparers.basic -- (a,b)
-local strip = sorters.strip
-local splitter = sorters.splitters.utf
-
-function authors.preparedsort(dataset,list,sorttype_a,sorttype_b,sorttype_c)
- local luadata = datasets[dataset].luadata
- local details = datasets[dataset].details
- local valid = { }
- local splitted = { }
- table.setmetatableindex(splitted,function(t,k) -- could be done in the sorter but seldom that many shared
- local v = splitter(k,true) -- in other cases
- t[k] = v
- return v
- end)
- local snippets = { }
- for i=1,#list do
- -- either { tag, tag, ... } or { { tag, index }, { tag, index } }
- local li = list[i]
- local tag = type(li) == "string" and li or li[1]
- local entry = luadata[tag]
- local detail = details[tag]
- local suffix = tostring(i)
- local year = nil
- local assembled = nil
- if entry and detail then
- local key = detail[sorttype_a] or detail[sorttype_b] or detail[sorttype_c]
- if key then
- -- maybe an option is to also sort the authors first
- local n = #key
- local s = 0
- for i=1,n do
- local k = key[i]
- local vons = k.vons
- local surnames = k.surnames
- local initials = k.initials
- if vons and #vons > 0 then
- s = s + 1 ; snippets[s] = concat(vons," ")
- end
- if surnames and #surnames > 0 then
- s = s + 1 ; snippets[s] = concat(surnames," ")
- end
- if initials and #initials > 0 then
- s = s + 1 ; snippets[s] = concat(initials," ")
+ local t = { }
+ local s = 0
+ for i=1,n do
+ local author = key[i]
+ local options = author.options
+ s = s + 1
+ if options then
+ local done = false
+ for option in next, options do
+ local collapse = collapsers[option]
+ if collapse then
+ t[s] = collapse(author)
+ done = true
end
end
- assembled = concat(snippets," ",1,s)
+ if not done then
+ t[s] = default(author)
+ end
else
- assembled = ""
+ t[s] = default(author)
end
- year = entry.year or "9998"
- else
- assembled = ""
- year = "9999"
end
- valid[i] = {
- index = i,
- split = {
- splitted[strip(assembled)],
- splitted[year],
- splitted[suffix],
- },
--- names = assembled,
--- year = year,
--- suffix = suffix,
- }
+ return concat(t," & ")
end
- return valid
end
-function authors.sorted(dataset,list,sorttype) -- experimental
- local valid = authors.preparedsort(dataset,list,sorttype)
- if #valid == 0 or #valid ~= #list then
- return list
- else
- sorters.sort(valid,compare)
- for i=1,#valid do
- valid[i] = valid[i].index
- end
- return valid
- end
-end
+publications.writers .author = writer
+publications.casters .author = splitauthorstring
+publications.components.author = components
--- local dataset = publications.datasets.test
---
--- local function add(str)
--- dataset.details[str] = { author = publications.authors.splitstring(str) }
--- end
---
--- add("Hagen, Hans and Hoekwater, Taco Whoever T. Ex. and Henkel Hut, Hartmut Harald von der")
--- add("Hans Hagen and Taco Whoever T. Ex. Hoekwater and Hartmut Harald von der Henkel Hut")
--- add("de Gennes, P. and Gennes, P. de")
--- add("van't Hoff, J. H. and {van't Hoff}, J. H.")
+-- sharedmethods.author = {
+-- { field = "key", default = "", unknown = "" },
+-- { field = "author", default = "", unknown = "" },
+-- { field = "title", default = "", unknown = "" },
+-- }
+
+-- Analysis of the APA by Alan:
--
--- local list = table.keys(dataset.details)
--- local sort = publications.authors.sorted("test",list,"author")
--- local test = { } for i=1,#sort do test[i] = dataset.details[list[sort[i]]] end
+-- first : key author editor publisher title journal volume number pages
+-- second: year suffix title month day journal volume number
+
+publications.sortmethods.authoryear = {
+ sequence = {
+ { field = "key", default = "", unknown = "" },
+ { field = "author", default = "", unknown = "" },
+ { field = "year", default = "9998", unknown = "9999" },
+ { field = "suffix", default = " ", unknown = " " },
+ { field = "month", default = "13", unknown = "14" },
+ { field = "day", default = "32", unknown = "33" },
+ { field = "journal", default = "", unknown = "" },
+ { field = "volume", default = "", unknown = "" },
+ { field = "number", default = "", unknown = "" },
+ { field = "title", default = "", unknown = "" },
+ { field = "pages", default = "", unknown = "" },
+ },
+}
diff --git a/Master/texmf-dist/tex/context/base/publ-dat.lua b/Master/texmf-dist/tex/context/base/publ-dat.lua
index 6062d0d4cf7..957322f7c2c 100644
--- a/Master/texmf-dist/tex/context/base/publ-dat.lua
+++ b/Master/texmf-dist/tex/context/base/publ-dat.lua
@@ -8,6 +8,8 @@ if not modules then modules = { } end modules ['publ-dat'] = {
-- todo: strip the @ in the lpeg instead of on do_definition and do_shortcut
-- todo: store bibroot and bibrootdt
+-- todo: dataset = datasets[dataset] => current = datasets[dataset]
+-- todo: maybe split this file
--[[ldx--
This is a prelude to integrated bibliography support. This file just loads
@@ -16,32 +18,42 @@ in a convenient way. Actually handling the data takes place elsewhere.
--ldx]]--
if not characters then
- dofile(resolvers.findfile("char-def.lua"))
- dofile(resolvers.findfile("char-ini.lua"))
+ dofile(resolvers.findfile("char-utf.lua"))
dofile(resolvers.findfile("char-tex.lua"))
end
local chardata = characters.data
local lowercase = characters.lower
-local lower, gsub, find = string.lower, string.gsub, string.find
-local concat = table.concat
+local lower, find, sub = string.lower, string.find, string.sub
+local concat, copy, tohash = table.concat, table.copy, table.tohash
local next, type, rawget = next, type, rawget
local utfchar = utf.char
local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
local textoutf = characters and characters.tex.toutf
local settings_to_hash, settings_to_array = utilities.parsers.settings_to_hash, utilities.parsers.settings_to_array
local formatters = string.formatters
-local sortedkeys, sortedhash = table.sortedkeys, table.sortedhash
-local xmlcollected, xmltext, xmlconvert = xml.collected, xml.text, xmlconvert
+local sortedkeys, sortedhash, keys = table.sortedkeys, table.sortedhash, table.keys
+local xmlcollected, xmltext, xmlconvert = xml.collected, xml.text, xml.convert
local setmetatableindex = table.setmetatableindex
-- todo: more allocate
-local P, R, S, V, C, Cc, Cs, Ct, Carg = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Carg
+local P, R, S, V, C, Cc, Cs, Ct, Carg, Cmt, Cp = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Carg, lpeg.Cmt, lpeg.Cp
+
+local p_whitespace = lpegpatterns.whitespace
+local p_utf8character = lpegpatterns.utf8character
+
+local trace = false trackers.register("publications", function(v) trace = v end)
+local trace_duplicates = true trackers.register("publications.duplicates", function(v) trace = v end)
-local trace = false trackers.register("publications", function(v) trace = v end)
local report = logs.reporter("publications")
+local report_duplicates = logs.reporter("publications","duplicates")
+
+local allocate = utilities.storage.allocate
+
+local commands = commands
+local implement = interfaces.implement
publications = publications or { }
local publications = publications
@@ -49,17 +61,120 @@ local publications = publications
local datasets = publications.datasets or { }
publications.datasets = datasets
+local writers = publications.writers or { }
+publications.writers = writers
+
+local tables = publications.tables or { }
+publications.tables = tables
+
publications.statistics = publications.statistics or { }
local publicationsstats = publications.statistics
+local loaders = publications.loaders or { }
+publications.loaders = loaders
+
+local casters = { }
+publications.casters = casters
+
+-- local sorters = { }
+-- publications.sorters = sorters
+--
+-- local indexers = { }
+-- publications.indexers = indexers
+
+local components = { }
+publications.components = components -- register components
+
+local enhancers = publications.enhancers or { }
+publications.enhancers = enhancers
+
+local enhancer = publications.enhancer or utilities.sequencers.new { arguments = "dataset" }
+publications.enhancer = enhancer
+
+utilities.sequencers.appendgroup(enhancer,"system") -- private
+
publicationsstats.nofbytes = 0
publicationsstats.nofdefinitions = 0
publicationsstats.nofshortcuts = 0
publicationsstats.nofdatasets = 0
+local privates = allocate {
+ category = true,
+ tag = true,
+ index = true,
+ suffix = true,
+ specification = true,
+}
+
+local specials = allocate {
+ key = true,
+ crossref = true,
+ keywords = true,
+ language = true,
+ comment = true,
+}
+
+local implicits = allocate {
+ category = "implicit",
+ tag = "implicit",
+ key = "implicit",
+ keywords = "implicit",
+ language = "implicit",
+ crossref = "implicit",
+}
+
+local origins = allocate {
+ "optional",
+ "extra",
+ "required",
+ "virtual",
+}
+
+local virtuals = allocate {
+ "authoryear",
+ "authoryears",
+ "authornum",
+ "num",
+ "suffix",
+}
+
+local defaulttypes = allocate {
+ author = "author",
+ editor = "author",
+ publisher = "author",
+ page = "pagenumber",
+ pages = "pagenumber",
+ keywords = "keyword",
+ doi = "url",
+ url = "url",
+}
+
+local defaultsets = allocate {
+ page = { "page", "pages" },
+}
+
+tables.implicits = implicits
+tables.origins = origins
+tables.virtuals = virtuals
+tables.types = defaulttypes
+tables.sets = defaultsets
+tables.privates = privates
+tables.specials = specials
+
+local variables = interfaces and interfaces.variables or setmetatableindex("self")
+
+local v_all = variables.all
+local v_default = variables.default
+
+if not publications.usedentries then
+ function publications.usedentries()
+ return { }
+ end
+end
+
local xmlplaceholder = "\n "
-local defaultshortcuts = {
+local defaultshortcuts = allocate {
jan = "1",
feb = "2",
mar = "3",
@@ -74,16 +189,144 @@ local defaultshortcuts = {
dec = "12",
}
-local space = lpeg.patterns.whitespace^0
+local space = p_whitespace^0
local separator = space * "+" * space
local l_splitter = lpeg.tsplitat(separator)
local d_splitter = lpeg.splitat (separator)
+local unknownfield = function(t,k)
+ local v = "extra"
+ t[k] = v
+ return v
+end
+
+local unknowncategory = function(t,k)
+ local v = {
+ required = false,
+ optional = false,
+ virtual = false,
+ fields = setmetatableindex(unknownfield), -- this will remember them
+ types = unknowntypes,
+ sets = setmetatableindex(defaultsets), -- new, but rather small
+ }
+ t[k] = v
+ return v
+end
+
+local unknowntype = function(t,k)
+ local v = "string"
+ t[k] = v
+ return v
+end
+
+local default = {
+ name = name,
+ version = "1.00",
+ comment = "unknown specification.",
+ author = "anonymous",
+ copyright = "no one",
+ categories = setmetatableindex(unknowncategory),
+ types = setmetatableindex(defaulttypes,unknowntype),
+}
+
+-- maybe at some point we can have a handlers table with per field
+-- a found, fetch, ... method
+
+local function checkfield(specification,category,data)
+ local list = setmetatableindex({},implicits)
+ data.fields = list
+ data.category = category
+ local sets = data.sets or { }
+ for i=1,#origins do
+ local t = origins[i]
+ local d = data[t]
+ if d then
+ for i=1,#d do
+ local di = d[i]
+ di = sets[di] or di
+ if type(di) == "table" then
+ for i=1,#di do
+ list[di[i]] = t
+ end
+ else
+ list[di] = t
+ end
+ end
+ else
+ data[t] = { }
+ end
+ end
+ return data
+end
+
+local specifications = setmetatableindex(function(t,name)
+ if not name then
+ return default -- initializer
+ end
+ local filename = formatters["publ-imp-%s.lua"](name)
+ local fullname = resolvers.findfile(filename) or ""
+ if fullname == "" then
+ report("no data definition file %a for %a",filename,name)
+ return default
+ end
+ local specification = table.load(fullname)
+ if not specification then
+ report("invalid data definition file %a for %a",fullname,name)
+ return default
+ end
+ --
+ local categories = specification.categories
+ if not categories then
+ categories = { }
+ specification.categories = categories
+ end
+ setmetatableindex(categories,unknowncategory)
+ --
+ local types = specification.types
+ if not types then
+ types = defaulttypes
+ specification.types = types
+ end
+ setmetatableindex(types,unknowntype)
+ --
+ local fields = setmetatableindex(unknownfield)
+ specification.fields = fields
+ --
+ local virtual = specification.virtual
+ if virtual == nil then -- so false is valid
+ virtual = { }
+ elseif virtual == false then
+ virtual = { }
+ elseif type(virtual) ~= table then
+ virtual = virtuals
+ end
+ specification.virtual = virtual
+ specification.virtualfields = tohash(virtual)
+ --
+ for category, data in next, categories do
+ categories[category] = checkfield(specification,category,copy(data)) -- we make sure we have no clones
+ end
+ --
+ t[name] = specification
+ --
+ return specification
+end)
+
+publications.specifications = specifications
+
+function publications.setcategory(target,category,data)
+ local specification = specifications[target]
+ specification.categories[category] = checkfield(specification,category,data)
+end
+
function publications.parenttag(dataset,tag)
- if find(tag,"%+") then
+ if not dataset or not tag then
+ report("error in specification, dataset %a, tag %a",dataset,tag)
+ elseif find(tag,"%+") then
local tags = lpegmatch(l_splitter,tag)
local parent = tags[1]
- local luadata = datasets[dataset].luadata
+ local current = datasets[dataset]
+ local luadata = current.luadata
local first = luadata[parent]
if first then
local combined = first.combined
@@ -109,7 +352,7 @@ function publications.parenttag(dataset,tag)
return parent
end
end
- return tag
+ return tag or ""
end
function publications.new(name)
@@ -121,7 +364,8 @@ function publications.new(name)
luadata = { },
suffixes = { },
xmldata = xmlconvert(xmlplaceholder),
- -- details = { },
+ details = { },
+ ordered = { },
nofbytes = 0,
entries = nil, -- empty == all
sources = { },
@@ -134,29 +378,16 @@ function publications.new(name)
resources = false,
userdata = false,
},
+ specifications = {
+ -- used specifications
+ },
}
-- we delay details till we need it (maybe we just delay the
-- individual fields but that is tricky as there can be some
-- depedencies)
- setmetatableindex(dataset,function(t,k)
- -- will become a plugin
- if k == "details" and publications.enhance then
- dataset.details = { }
- publications.enhance(dataset.name)
- return dataset.details
- end
- end)
return dataset
end
-function publications.markasupdated(name)
- if name == "string" then
- datasets[name].details = nil
- else
- datasets.details = nil
- end
-end
-
setmetatableindex(datasets,function(t,k)
if type(k) == "table" then
return k -- so we can use this accessor as checker
@@ -167,40 +398,6 @@ setmetatableindex(datasets,function(t,k)
end
end)
--- we apply some normalization
-
-local space = S(" \t\n\r\f") -- / " "
-
------ command = P("\\") * Cc("btxcmd{") * (R("az","AZ")^1) * Cc("}")
------ command = P("\\") * (Carg(1) * C(R("az","AZ")^1) / function(list,c) list[c] = (list[c] or 0) + 1 return "btxcmd{" .. c .. "}" end)
-local command = P("\\") * (Carg(1) * C(R("az","AZ")^1) * space^0 / function(list,c) list[c] = (list[c] or 0) + 1 return "btxcmd{" .. c .. "}" end)
-local somemath = P("$") * ((1-P("$"))^1) * P("$") -- let's not assume nested math
-local any = P(1)
-local done = P(-1)
-local one_l = P("{") / ""
-local one_r = P("}") / ""
-local two_l = P("{{") / ""
-local two_r = P("}}") / ""
-local special = P("#") / "\\letterhash"
-
-local filter_0 = S('\\{}')
-local filter_1 = (1-filter_0)^0 * filter_0
-local filter_2 = Cs(
--- {{...}} ... {{...}}
--- two_l * (command + special + any - two_r - done)^0 * two_r * done +
--- one_l * (command + special + any - one_r - done)^0 * one_r * done +
- (somemath + command + special + any )^0
-)
-
--- Currently we expand shortcuts and for large ones (like the acknowledgements
--- in tugboat.bib) this is not that efficient. However, eventually strings get
--- hashed again.
-
-local function do_shortcut(key,value,dataset)
- publicationsstats.nofshortcuts = publicationsstats.nofshortcuts + 1
- dataset.shortcuts[key] = value
-end
-
local function getindex(dataset,luadata,tag)
local found = luadata[tag]
if found then
@@ -214,357 +411,769 @@ end
publications.getindex = getindex
--- todo: categories : metatable that lowers and also counts
--- todo: fields : metatable that lowers
-
-local function do_definition(category,tag,tab,dataset)
- publicationsstats.nofdefinitions = publicationsstats.nofdefinitions + 1
- local fields = dataset.fields
- local luadata = dataset.luadata
- local found = luadata[tag]
- local index = getindex(dataset,luadata,tag)
- local entries = {
- category = lower(category),
- tag = tag,
- index = index,
- }
- for i=1,#tab,2 do
- local original = tab[i]
- local normalized = fields[original]
- if not normalized then
- normalized = lower(original) -- we assume ascii fields
- fields[original] = normalized
- end
- local value = tab[i+1]
- value = textoutf(value)
- if lpegmatch(filter_1,value) then
- value = lpegmatch(filter_2,value,1,dataset.commands) -- we need to start at 1 for { }
- end
- if normalized == "crossref" then
- local parent = luadata[value]
- if parent then
- setmetatableindex(entries,parent)
+do
+
+ -- we apply some normalization
+
+ local space = S(" \t\n\r\f") -- / " "
+ local collapsed = space^1/" "
+ ----- csletter = R("az","AZ")
+ local csletter = lpegpatterns.csletter
+
+ ----- command = P("\\") * Cc("btxcmd{") * (R("az","AZ")^1) * Cc("}")
+ ----- command = P("\\") * (Carg(1) * C(R("az","AZ")^1) / function(list,c) list[c] = (list[c] or 0) + 1 return "btxcmd{" .. c .. "}" end)
+ ----- command = P("\\") * (Carg(1) * C(R("az","AZ")^1) * space^0 / function(list,c) list[c] = (list[c] or 0) + 1 return "btxcmd{" .. c .. "}" end)
+ local command = P("\\") * (Carg(1) * C(csletter^1) * space^0 / function(list,c) list[c] = (list[c] or 0) + 1 return "btxcmd{" .. c .. "}" end)
+ local whatever = P("\\") * P(" ")^1 / " "
+ + P("\\") * ( P("hbox") + P("raise") ) -- bah
+ local somemath = P("$") * ((1-P("$"))^1) * P("$") -- let's not assume nested math
+ ----- character = lpegpatterns.utf8character
+ local any = P(1)
+ local done = P(-1)
+ -- local one_l = P("{") / ""
+ -- local one_r = P("}") / ""
+ -- local two_l = P("{{") / ""
+ -- local two_r = P("}}") / ""
+ local zero_l_r = P("{}") / "" * #P(1)
+ local special = P("#") / "\\letterhash "
+
+ local filter_0 = S('\\{}#')
+ local filter_1 = (1-filter_0)^0 * filter_0
+ local filter_2 = Cs(
+ -- {{...}} ... {{...}}
+ -- two_l * (command + special + any - two_r - done)^0 * two_r * done +
+ -- one_l * (command + special + any - one_r - done)^0 * one_r * done +
+ (
+ somemath +
+ whatever +
+ command +
+ special +
+ collapsed +
+ zero_l_r +
+ any
+ )^0
+ )
+
+ -- Currently we expand shortcuts and for large ones (like the acknowledgements
+ -- in tugboat.bib) this is not that efficient. However, eventually strings get
+ -- hashed again.
+
+ local function do_shortcut(key,value,dataset)
+ publicationsstats.nofshortcuts = publicationsstats.nofshortcuts + 1
+ dataset.shortcuts[key] = value
+ end
+
+ -- todo: categories : metatable that lowers and also counts
+ -- todo: fields : metatable that lowers
+
+ local tags = table.setmetatableindex("table")
+
+ local function do_definition(category,tag,tab,dataset)
+ publicationsstats.nofdefinitions = publicationsstats.nofdefinitions + 1
+ if tag == "" then
+ tag = "no-tag-set"
+ end
+ local fields = dataset.fields
+ local luadata = dataset.luadata
+ local hashtag = tag
+ if luadata[tag] then
+ local t = tags[tag]
+ local d = dataset.name
+ local n = (t[d] or 0) + 1
+ t[d] = n
+ hashtag = tag .. "-" .. n
+ if trace_duplicates then
+ local p = { }
+ for k, v in sortedhash(t) do
+ p[#p+1] = formatters["%s:%s"](k,v)
+ end
+ report_duplicates("tag %a is present multiple times: % t, assigning hashtag %a",tag,p,hashtag)
+ end
+ end
+ local index = getindex(dataset,luadata,hashtag)
+ local entries = {
+ category = lower(category),
+ tag = tag,
+ index = index,
+ }
+ for i=1,#tab,2 do
+ local original = tab[i]
+ local normalized = fields[original]
+ if not normalized then
+ normalized = lower(original) -- we assume ascii fields
+ fields[original] = normalized
+ end
+ -- if entries[normalized] then
+ if rawget(entries,normalized) then
+ if trace_duplicates then
+ report_duplicates("redundant field %a is ignored for tag %a in dataset %a",normalized,tag,dataset.name)
+ end
else
- -- warning
+ local value = tab[i+1]
+ value = textoutf(value)
+ if lpegmatch(filter_1,value) then
+ value = lpegmatch(filter_2,value,1,dataset.commands) -- we need to start at 1 for { }
+ end
+ if normalized == "crossref" then
+ local parent = luadata[value]
+ if parent then
+ setmetatableindex(entries,parent)
+ else
+ -- warning
+ end
+ end
+ entries[normalized] = value
end
end
- entries[normalized] = value
+ luadata[hashtag] = entries
end
- luadata[tag] = entries
-end
-local function resolve(s,dataset)
- return dataset.shortcuts[s] or defaultshortcuts[s] or s -- can be number
-end
+ local function resolve(s,dataset)
+ return dataset.shortcuts[s] or defaultshortcuts[s] or s -- can be number
+ end
-local percent = P("%")
-local start = P("@")
-local comma = P(",")
-local hash = P("#")
-local escape = P("\\")
-local single = P("'")
-local double = P('"')
-local left = P('{')
-local right = P('}')
-local both = left + right
-local lineending = S("\n\r")
-local space = S(" \t\n\r\f") -- / " "
-local spacing = space^0
-local equal = P("=")
------ collapsed = (space^1)/ " "
-local collapsed = (lpegpatterns.whitespace^1)/ " "
-
------ balanced = lpegpatterns.balanced
-local balanced = P {
- [1] = ((escape * (left+right)) + (collapsed + 1 - (left+right)) + V(2))^0,
- [2] = left * V(1) * right
-}
+ local pattern = p_whitespace^0
+ * C(P("message") + P("warning") + P("error") + P("comment")) * p_whitespace^0 * P(":")
+ * p_whitespace^0
+ * C(P(1)^1)
-local keyword = C((R("az","AZ","09") + S("@_:-"))^1)
-local key = C((1-space-equal)^1)
-local tag = C((1-space-comma)^1)
-local reference = keyword
-local category = P("@") * C((1-space-left)^1)
-local s_quoted = ((escape*single) + collapsed + (1-single))^0
-local d_quoted = ((escape*double) + collapsed + (1-double))^0
-
-local b_value = (left /"") * balanced * (right /"")
-local s_value = (single/"") * (b_value + s_quoted) * (single/"")
-local d_value = (double/"") * (b_value + d_quoted) * (double/"")
-local r_value = reference * Carg(1) /resolve
-
-local somevalue = s_value + d_value + b_value + r_value
-local value = Cs((somevalue * ((spacing * hash * spacing)/"" * somevalue)^0))
-
-local assignment = spacing * key * spacing * equal * spacing * value * spacing
-local shortcut = P("@") * (P("string") + P("STRING")) * spacing * left * ((assignment * Carg(1))/do_shortcut * comma^0)^0 * spacing * right
-local definition = category * spacing * left * spacing * tag * spacing * comma * Ct((assignment * comma^0)^0) * spacing * right * Carg(1) / do_definition
-local comment = keyword * spacing * left * (1-right)^0 * spacing * right
-local forget = percent^1 * (1-lineending)^0
-
--- todo \%
-
-local bibtotable = (space + forget + shortcut + definition + comment + 1)^0
-
--- loadbibdata -> dataset.luadata
--- loadtexdata -> dataset.luadata
--- loadluadata -> dataset.luadata
-
--- converttoxml -> dataset.xmldata from dataset.luadata
-
-function publications.loadbibdata(dataset,content,source,kind)
- dataset = datasets[dataset]
- statistics.starttiming(publications)
- publicationsstats.nofbytes = publicationsstats.nofbytes + #content
- dataset.nofbytes = dataset.nofbytes + #content
- if source then
- table.insert(dataset.sources, { filename = source, checksum = md5.HEX(content) })
- dataset.loaded[source] = kind or true
- end
- dataset.newtags = #dataset.luadata > 0 and { } or dataset.newtags
- publications.markasupdated(dataset)
- lpegmatch(bibtotable,content or "",1,dataset)
- statistics.stoptiming(publications)
-end
+ local function do_comment(s,dataset)
+ local how, what = lpegmatch(pattern,s)
+ if how and what then
+ local t = string.splitlines(utilities.strings.striplines(what))
+ local b = file.basename(dataset.fullname or dataset.name or "unset")
+ for i=1,#t do
+ report("%s > %s : %s",b,how,t[i])
+ end
+ end
+ end
+
+ local percent = P("%")
+ local start = P("@")
+ local comma = P(",")
+ local hash = P("#")
+ local escape = P("\\")
+ local single = P("'")
+ local double = P('"')
+ local left = P('{')
+ local right = P('}')
+ local both = left + right
+ local lineending = S("\n\r")
+ local space = S(" \t\n\r\f") -- / " "
+ local spacing = space^0
+ local equal = P("=")
+ ----- collapsed = (space^1)/ " "
+ local collapsed = p_whitespace^1/" "
+ local nospaces = p_whitespace^1/""
+
+ local p_left = (p_whitespace^0 * left) / ""
+ local p_right = (right * p_whitespace^0) / ""
+
+ local balanced = P {
+ [1] = ((escape * (left+right)) + (collapsed + 1 - (left+right))^1 + V(2))^0,
+ [2] = left * V(1) * right,
+ }
+
+ -- local unbalanced = P {
+ -- [1] = left * V(2) * right,
+ -- [2] = ((escape * (left+right)) + (collapsed + 1 - (left+right))^1 + V(1))^0,
+ -- }
+
+ local unbalanced = (left/"") * balanced * (right/"") * P(-1)
+
+ local keyword = C((R("az","AZ","09") + S("@_:-"))^1)
+ local key = C((1-space-equal)^1)
+ local tag = C((1-space-comma)^0)
+ local reference = keyword
+ local category = C((1-space-left)^1)
+ local s_quoted = ((escape*single) + collapsed + (1-single))^0
+ local d_quoted = ((escape*double) + collapsed + (1-double))^0
+
+ local b_value = p_left * balanced * p_right
+ -- local u_value = p_left * unbalanced * p_right -- get rid of outer { }
+ -- local s_value = (single/"") * (u_value + s_quoted) * (single/"")
+ -- local d_value = (double/"") * (u_value + d_quoted) * (double/"")
+ local s_value = (single/"") * (unbalanced + s_quoted) * (single/"")
+ local d_value = (double/"") * (unbalanced + d_quoted) * (double/"")
+ local r_value = reference * Carg(1) /resolve
+
+ local somevalue = d_value + b_value + s_value + r_value
+ local value = Cs((somevalue * ((spacing * hash * spacing)/"" * somevalue)^0))
+
+ value = value / function(s) return lpegmatch(lpegpatterns.stripper,s) end
+
+ local forget = percent^1 * (1-lineending)^0
+ local spacing = spacing * forget^0 * spacing
+ local assignment = spacing * key * spacing * equal * spacing * value * spacing
+ local definition = category * spacing * left * spacing * tag * spacing * comma * Ct((assignment * comma^0)^0) * spacing * right * Carg(1) / do_definition
+
+ local crapword = C((1-space-left)^1)
+ local shortcut = Cmt(crapword,function(_,p,s) return lower(s) == "string" and p end) * spacing * left * ((assignment * Carg(1))/do_shortcut * comma^0)^0 * spacing * right
+ local comment = Cmt(crapword,function(_,p,s) return lower(s) == "comment" and p end) * spacing * lpegpatterns.argument * Carg(1) / do_comment
+
+ local casecrap = #S("sScC") * (shortcut + comment)
+
+ local bibtotable = (space + forget + P("@") * (casecrap + definition) + 1)^0
--- we could use xmlescape again
+ -- todo \%
-local cleaner_0 = S('<>&')
-local cleaner_1 = (1-cleaner_0)^0 * cleaner_0
-local cleaner_2 = Cs ( (
- P("<") / "<" +
- P(">") / ">" +
- P("&") / "&" +
- P(1)
-)^0)
+ -- loadbibdata -> dataset.luadata
+ -- loadtexdata -> dataset.luadata
+ -- loadluadata -> dataset.luadata
-local compact = false -- can be a directive but then we also need to deal with newlines ... not now
+ -- converttoxml -> dataset.xmldata from dataset.luadata
-function publications.converttoxml(dataset,nice) -- we have fields !
- dataset = datasets[dataset]
- local luadata = dataset and dataset.luadata
- if luadata then
+ function publications.loadbibdata(dataset,content,source,kind)
+ if not source then
+ report("invalid source for dataset %a",dataset)
+ return
+ end
+ local current = datasets[dataset]
+ local size = #content
+ if size == 0 then
+ report("empty source %a for dataset %a",source,current.name)
+ else
+ report("adding bib data to set %a from source %a",current.name,source)
+ end
statistics.starttiming(publications)
- statistics.starttiming(xml)
- --
- local result, r = { }, 0
- --
- r = r + 1 ; result[r] = ""
- r = r + 1 ; result[r] = ""
- --
- if nice then
- local f_entry_start = formatters[" "]
- local f_entry_stop = " "
- local f_field = formatters[" %s "]
- for tag, entry in sortedhash(luadata) do
- r = r + 1 ; result[r] = f_entry_start(tag,entry.category,entry.index)
- for key, value in sortedhash(entry) do
- if key ~= "tag" and key ~= "category" and key ~= "index" then
- if lpegmatch(cleaner_1,value) then
- value = lpegmatch(cleaner_2,value)
+ publicationsstats.nofbytes = publicationsstats.nofbytes + size
+ current.nofbytes = current.nofbytes + size
+ if source then
+ table.insert(current.sources, { filename = source, checksum = md5.HEX(content) })
+ current.loaded[source] = kind or true
+ end
+ current.newtags = #current.luadata > 0 and { } or current.newtags
+ lpegmatch(bibtotable,content or "",1,current)
+ statistics.stoptiming(publications)
+ end
+
+end
+
+do
+
+ -- we could use xmlescape again
+
+ local cleaner_0 = S('<>&')
+ local cleaner_1 = (1-cleaner_0)^0 * cleaner_0
+ local cleaner_2 = Cs ( (
+ P("<") / "<" +
+ P(">") / ">" +
+ P("&") / "&" +
+ P(1)
+ )^0)
+
+ local compact = false -- can be a directive but then we also need to deal with newlines ... not now
+
+ function publications.converttoxml(dataset,nice,dontstore,usedonly,subset) -- we have fields !
+ local current = datasets[dataset]
+ local luadata = subset or (current and current.luadata)
+ if luadata then
+ statistics.starttiming(publications)
+ --
+ local result, r, n = { }, 0, 0
+ local usedonly = usedonly and publications.usedentries()
+ --
+ r = r + 1 ; result[r] = ""
+ r = r + 1 ; result[r] = ""
+ --
+ if nice then
+ local f_entry_start = formatters[" "]
+ local s_entry_stop = " "
+ local f_field = formatters[" %s "]
+ for tag, entry in sortedhash(luadata) do
+ if not usedonly or usedonly[tag] then
+ r = r + 1 ; result[r] = f_entry_start(tag,entry.category,entry.index)
+ for key, value in sortedhash(entry) do
+ if key ~= "tag" and key ~= "category" and key ~= "index" then
+ if lpegmatch(cleaner_1,value) then
+ value = lpegmatch(cleaner_2,value)
+ end
+ if value ~= "" then
+ r = r + 1 ; result[r] = f_field(key,value)
+ end
+ end
end
- if value ~= "" then
- r = r + 1 ; result[r] = f_field(key,value)
+ r = r + 1 ; result[r] = s_entry_stop
+ n = n + 1
+ end
+ end
+ else
+ local f_entry_start = formatters[""]
+ local s_entry_stop = " "
+ local f_field = formatters["%s "]
+ for tag, entry in next, luadata do
+ if not usedonly or usedonly[tag] then
+ r = r + 1 ; result[r] = f_entry_start(entry.tag,entry.category,entry.index)
+ for key, value in next, entry do
+ if key ~= "tag" and key ~= "category" and key ~= "index" then
+ if lpegmatch(cleaner_1,value) then
+ value = lpegmatch(cleaner_2,value)
+ end
+ if value ~= "" then
+ r = r + 1 ; result[r] = f_field(key,value)
+ end
+ end
end
+ r = r + 1 ; result[r] = s_entry_stop
+ n = n + 1
end
end
- r = r + 1 ; result[r] = f_entry_stop
end
+ --
+ r = r + 1 ; result[r] = " "
+ --
+ result = concat(result,nice and "\n" or nil)
+ --
+ if dontstore then
+ -- indeed
+ else
+ statistics.starttiming(xml)
+ current.xmldata = xmlconvert(result, {
+ resolve_entities = true,
+ resolve_predefined_entities = true, -- in case we have escaped entities
+ -- unify_predefined_entities = true, -- & -> &
+ utfize_entities = true,
+ } )
+ statistics.stoptiming(xml)
+ if lxml then
+ lxml.register(formatters["btx:%s"](current.name),current.xmldata)
+ end
+ end
+ statistics.stoptiming(publications)
+ return result, n
+ end
+ end
+
+end
+
+do
+
+ local function resolvedname(dataset,filename)
+ local current = datasets[dataset]
+ if type(filename) ~= "string" then
+ report("invalid filename %a",tostring(filename))
+ end
+ local fullname = resolvers.findfile(filename,"bib")
+ if fullname == "" then
+ fullname = resolvers.findfile(filename) -- let's not be too picky
+ end
+ if not fullname or fullname == "" then
+ report("no file %a",filename)
+ current.fullname = filename
+ return current, false
else
- local f_entry_start = formatters[""]
- local f_entry_stop = " "
- local f_field = formatters["%s "]
- for tag, entry in next, luadata do
- r = r + 1 ; result[r] = f_entry_start(entry.tag,entry.category,entry.index)
- for key, value in next, entry do
- if key ~= "tag" and key ~= "category" and key ~= "index" then
- if lpegmatch(cleaner_1,value) then
- value = lpegmatch(cleaner_2,value)
- end
- if value ~= "" then
- r = r + 1 ; result[r] = f_field(key,value)
- end
- end
+ current.fullname = fullname
+ return current, fullname
+ end
+ end
+
+ publications.resolvedname = resolvedname
+
+ local cleaner = false
+ local cleaned = false
+
+ function loaders.registercleaner(what,fullname)
+ if not fullname or fullname == "" then
+ report("no %s file %a",what,fullname)
+ return
+ end
+ local list = table.load(fullname)
+ if not list then
+ report("invalid %s file %a",what,fullname)
+ return
+ end
+ list = list.replacements
+ if not list then
+ report("no replacement table in %a",fullname)
+ return
+ end
+ if cleaned then
+ report("adding replacements from %a",fullname)
+ for k, v in next, list do
+ cleaned[k] = v
+ end
+ else
+ report("using replacements from %a",fullname)
+ cleaned = list
+ end
+ cleaner = true
+ end
+
+ function loaders.bib(dataset,filename,kind)
+ local dataset, fullname = resolvedname(dataset,filename)
+ if not fullname then
+ return
+ end
+ local data = io.loaddata(filename) or ""
+ if data == "" then
+ report("empty file %a, nothing loaded",fullname)
+ return
+ end
+ if cleaner == true then
+ cleaner = Cs((lpeg.utfchartabletopattern(keys(cleaned)) / cleaned + p_utf8character)^1)
+ end
+ if cleaner ~= false then
+ data = lpegmatch(cleaner,data)
+ end
+ if trace then
+ report("loading file %a",fullname)
+ end
+ publications.loadbibdata(dataset,data,fullname,kind)
+ end
+
+ function loaders.lua(dataset,filename) -- if filename is a table we load that one
+ local current, data, fullname
+ if type(filename) == "table" then
+ current = datasets[dataset]
+ data = filename
+ else
+ dataset, fullname = resolvedname(dataset,filename)
+ if not fullname then
+ return
+ end
+ current = datasets[dataset]
+ data = table.load(filename)
+ end
+ if data then
+ local luadata = current.luadata
+ for tag, entry in next, data do
+ if type(entry) == "table" then
+ entry.index = getindex(current,luadata,tag)
+ entry.tag = tag
+ luadata[tag] = entry -- no cleaning yet
end
- r = r + 1 ; result[r] = f_entry_stop
end
end
- --
- r = r + 1 ; result[r] = " "
- --
- result = concat(result,nice and "\n" or nil)
- --
- dataset.xmldata = xmlconvert(result, {
- resolve_entities = true,
- resolve_predefined_entities = true, -- in case we have escaped entities
- -- unify_predefined_entities = true, -- & -> &
- utfize_entities = true,
- } )
- --
- statistics.stoptiming(xml)
- statistics.stoptiming(publications)
- if lxml then
- lxml.register(formatters["btx:%s"](dataset.name),dataset.xmldata)
+ end
+
+ function loaders.buffer(dataset,name) -- if filename is a table we load that one
+ local current = datasets[dataset]
+ local barename = file.removesuffix(name)
+ local data = buffers.getcontent(barename) or ""
+ if data == "" then
+ report("empty buffer %a, nothing loaded",barename)
+ return
+ end
+ if trace then
+ report("loading buffer",barename)
+ end
+ publications.loadbibdata(current,data,barename,"bib")
+ end
+
+ function loaders.xml(dataset,filename)
+ local dataset, fullname = resolvedname(dataset,filename)
+ if not fullname then
+ return
+ end
+ local current = datasets[dataset]
+ local luadata = current.luadata
+ local root = xml.load(filename)
+ for bibentry in xmlcollected(root,"/bibtex/entry") do
+ local attributes = bibentry.at
+ local tag = attributes.tag
+ local entry = {
+ category = attributes.category,
+ tag = tag, -- afterwards also set, to prevent overload
+ index = 0, -- prelocated
+ }
+ for field in xmlcollected(bibentry,"/field") do
+ entry[field.at.name] = field.dt[1] -- no cleaning yet | xmltext(field)
+ end
+ entry.index = getindex(current,luadata,tag)
+ entry.tag = tag
+ luadata[tag] = entry
end
end
-end
-local loaders = publications.loaders or { }
-publications.loaders = loaders
+ setmetatableindex(loaders,function(t,filetype)
+ local v = function(dataset,filename)
+ report("no loader for file %a with filetype %a",filename,filetype)
+ end
+ t[filetype] = v
+ return v
+ end)
-function loaders.bib(dataset,filename,kind)
- dataset = datasets[dataset]
- local data = io.loaddata(filename) or ""
- if data == "" then
- report("empty file %a, nothing loaded",filename)
- elseif trace then
- report("loading file",filename)
+ function publications.load(specification)
+ local current = datasets[specification.dataset or v_default]
+ local files = settings_to_array(specification.filename)
+ local kind = specification.kind
+ local dataspec = specification.specification
+ statistics.starttiming(publications)
+ for i=1,#files do
+ local filetype, filename = string.splitup(files[i],"::")
+ if not filename then
+ filename = filetype
+ filetype = file.suffix(filename)
+ end
+ if filename then
+ if not filetype or filetype == "" then
+ filetype = "bib"
+ end
+ if file.suffix(filename) == "" then
+ file.addsuffix(filename,filetype)
+ end
+ loaders[filetype](current,filename)
+ if kind then
+ current.loaded[current.fullname or filename] = kind
+ end
+ if dataspec then
+ current.specifications[dataspec] = true
+ end
+ end
+ end
+ local runner = enhancer.runner
+ if runner then
+ runner(current)
+ end
+ statistics.stoptiming(publications)
+ return current
end
- publications.loadbibdata(dataset,data,filename,kind)
+
end
-function loaders.lua(dataset,filename) -- if filename is a table we load that one
- dataset = datasets[dataset]
- inspect(filename)
- local data = type(filename) == "table" and filename or table.load(filename)
- if data then
+do
+
+ function enhancers.order(dataset)
+ local luadata = dataset.luadata
+ local ordered = sortedkeys(luadata)
+ local total = #ordered
+ for i=1,total do
+ ordered[i] = luadata[ordered[i]]
+ end
+ dataset.ordered = ordered
+ end
+
+ function enhancers.details(dataset)
local luadata = dataset.luadata
- for tag, entry in next, data do
- if type(entry) == "table" then
- entry.index = getindex(dataset,luadata,tag)
- luadata[tag] = entry -- no cleaning yet
+ local details = dataset.details
+ for tag, entry in next, luadata do
+ if not details[tag] then
+ details[tag] = { }
end
end
end
+
+ utilities.sequencers.appendaction(enhancer,"system","publications.enhancers.order")
+ utilities.sequencers.appendaction(enhancer,"system","publications.enhancers.details")
+
end
-function loaders.xml(dataset,filename)
- dataset = datasets[dataset]
- local luadata = dataset.luadata
- local root = xml.load(filename)
- for bibentry in xmlcollected(root,"/bibtex/entry") do
- local attributes = bibentry.at
- local tag = attributes.tag
- local entry = {
- category = attributes.category
+do
+
+ local checked = function(s,d) d[s] = (d[s] or 0) + 1 end
+ local checktex = ( (1-P("\\"))^1 + P("\\") * ((C(R("az","AZ")^1) * Carg(1))/checked))^0
+
+ function publications.analyze(dataset)
+ local current = datasets[dataset]
+ local data = current.luadata
+ local categories = { }
+ local fields = { }
+ local commands = { }
+ for k, v in next, data do
+ categories[v.category] = (categories[v.category] or 0) + 1
+ for k, v in next, v do
+ fields[k] = (fields[k] or 0) + 1
+ lpegmatch(checktex,v,1,commands)
+ end
+ end
+ current.analysis = {
+ categories = categories,
+ fields = fields,
+ commands = commands,
}
- for field in xmlcollected(bibentry,"/field") do
- -- entry[field.at.name] = xmltext(field)
- entry[field.at.name] = field.dt[1] -- no cleaning yet
- end
- -- local edt = entry.dt
- -- for i=1,#edt do
- -- local e = edt[i]
- -- local a = e.at
- -- if a and a.name then
- -- t[a.name] = e.dt[1] -- no cleaning yet
- -- end
- -- end
- entry.index = getindex(dataset,luadata,tag)
- luadata[tag] = entry
end
+
end
-setmetatableindex(loaders,function(t,filetype)
- local v = function(dataset,filename)
- report("no loader for file %a with filetype %a",filename,filetype)
+function publications.tags(dataset)
+ return sortedkeys(datasets[dataset].luadata)
+end
+
+function publications.sortedentries(dataset)
+ return sortedhash(datasets[dataset].luadata)
+end
+
+-- a helper:
+
+function publications.concatstate(i,n)
+ if i == 0 then
+ return 0
+ elseif i == 1 then
+ return 1
+ elseif i == 2 and n == 2 then
+ return 4
+ elseif i == n then
+ return 3
+ else
+ return 2
end
- t[k] = v
- return v
-end)
+end
+
+-- savers
+
+do
+
+ local savers = { }
+
+ local s_preamble = [[
+% this is an export from context mkiv
-function publications.load(dataset,filename,kind)
- dataset = datasets[dataset]
- statistics.starttiming(publications)
- local files = settings_to_array(filename)
- for i=1,#files do
- local filetype, filename = string.splitup(files[i],"::")
- if not filename then
- filename = filetype
+@preamble{
+ \ifdefined\btxcmd
+ % we're probably in context
+ \else
+ \def\btxcmd#1{\csname#1\endcsname}
+ \fi
+}
+
+]]
+
+ function savers.bib(dataset,filename,tobesaved)
+ local f_start = formatters["@%s{%s,\n"]
+ local f_field = formatters[" %s = {%s},\n"]
+ local s_stop = "}\n\n"
+ local result = { s_preamble }
+ local n, r = 0, 1
+ for tag, data in sortedhash(tobesaved) do
+ r = r + 1 ; result[r] = f_start(data.category or "article",tag)
+ for key, value in sortedhash(data) do
+ if not privates[key] then
+ r = r + 1 ; result[r] = f_field(key,value)
+ end
+ end
+ r = r + 1 ; result[r] = s_stop
+ n = n + 1
+ end
+ report("%s entries from dataset %a saved in %a",n,dataset,filename)
+ io.savedata(filename,concat(result))
+ end
+
+ function savers.lua(dataset,filename,tobesaved)
+ local list = { }
+ local n = 0
+ for tag, data in next, tobesaved do
+ local t = { }
+ for key, value in next, data do
+ if not privates[key] then
+ d[key] = value
+ end
+ end
+ list[tag] = t
+ n = n + 1
+ end
+ report("%s entries from dataset %a saved in %a",n,dataset,filename)
+ table.save(filename,list)
+ end
+
+ function savers.xml(dataset,filename,tobesaved)
+ local result, n = publications.converttoxml(dataset,true,true,false,tobesaved)
+ report("%s entries from dataset %a saved in %a",n,dataset,filename)
+ io.savedata(filename,result)
+ end
+
+ function publications.save(specification)
+ local dataset = specification.dataset
+ local filename = specification.filename
+ local filetype = specification.filetype
+ local criterium = specification.criterium
+ statistics.starttiming(publications)
+ if not filename or filename == "" then
+ report("no filename for saving given")
+ return
+ end
+ if not filetype or filetype == "" then
filetype = file.suffix(filename)
end
- local fullname = resolvers.findfile(filename,"bib")
- if dataset.loaded[fullname] then -- will become better
- -- skip
- elseif fullname == "" then
- report("no file %a",filename)
- else
- loaders[filetype](dataset,fullname)
+ if not criterium or criterium == "" then
+ criterium = v_all
end
- if kind then
- dataset.loaded[fullname] = kind
+ local saver = savers[filetype]
+ if saver then
+ local current = datasets[dataset]
+ local luadata = current.luadata or { }
+ local tobesaved = { }
+ local result = structures.lists.filter({criterium = criterium, names = "btx"}) or { }
+ for i=1,#result do
+ local userdata = result[i].userdata
+ if userdata then
+ local set = userdata.btxset or v_default
+ if set == dataset then
+ local tag = userdata.btxref
+ if tag then
+ tobesaved[tag] = luadata[tag]
+ end
+ end
+ end
+ end
+ saver(dataset,filename,tobesaved)
+ else
+ report("unknown format %a for saving %a",filetype,dataset)
end
+ statistics.stoptiming(publications)
+ return dataset
end
- statistics.stoptiming(publications)
- return dataset
-end
-local checked = function(s,d) d[s] = (d[s] or 0) + 1 end
-local checktex = ( (1-P("\\"))^1 + P("\\") * ((C(R("az","AZ")^1) * Carg(1))/checked))^0
-
-function publications.analyze(dataset)
- dataset = datasets[dataset]
- local data = dataset.luadata
- local categories = { }
- local fields = { }
- local commands = { }
- for k, v in next, data do
- categories[v.category] = (categories[v.category] or 0) + 1
- for k, v in next, v do
- fields[k] = (fields[k] or 0) + 1
- lpegmatch(checktex,v,1,commands)
- end
- end
- dataset.analysis = {
- categories = categories,
- fields = fields,
- commands = commands,
+ implement {
+ name = "btxsavedataset",
+ actions = publications.save,
+ arguments = {
+ {
+ { "dataset" },
+ { "filename" },
+ { "filetype" },
+ { "criterium" },
+ }
+ }
}
+
end
--- str = [[
--- @COMMENT { CRAP }
--- @STRING{ hans = "h a n s" }
--- @STRING{ taco = "t a c o" }
--- @SOMETHING{ key1, abc = "t a c o" , def = "h a n s" }
--- @SOMETHING{ key2, abc = hans # taco }
--- @SOMETHING{ key3, abc = "hans" # taco }
--- @SOMETHING{ key4, abc = hans # "taco" }
--- @SOMETHING{ key5, abc = hans # taco # "hans" # "taco"}
--- @SOMETHING{ key6, abc = {oeps {oeps} oeps} }
--- ]]
-
--- local dataset = publications.new()
--- publications.tolua(dataset,str)
--- publications.toxml(dataset)
--- publications.toxml(dataset)
--- print(dataset.xmldata)
--- inspect(dataset.luadata)
--- inspect(dataset.xmldata)
--- inspect(dataset.shortcuts)
--- print(dataset.nofbytes,statistics.elapsedtime(publications))
-
--- local dataset = publications.new()
--- publications.load(dataset,"IEEEabrv.bib")
--- publications.load(dataset,"IEEEfull.bib")
--- publications.load(dataset,"IEEEexample.bib")
--- publications.toxml(dataset)
--- print(dataset.nofbytes,statistics.elapsedtime(publications))
-
--- local dataset = publications.new()
--- publications.load(dataset,"gut.bib")
--- publications.load(dataset,"komoedie.bib")
--- publications.load(dataset,"texbook1.bib")
--- publications.load(dataset,"texbook2.bib")
--- publications.load(dataset,"texbook3.bib")
--- publications.load(dataset,"texgraph.bib")
--- publications.load(dataset,"texjourn.bib")
--- publications.load(dataset,"texnique.bib")
--- publications.load(dataset,"tugboat.bib")
--- publications.toxml(dataset)
--- print(dataset.nofbytes,statistics.elapsedtime(publications))
-
--- print(table.serialize(dataset.luadata))
--- print(table.serialize(dataset.xmldata))
--- print(table.serialize(dataset.shortcuts))
--- print(xml.serialize(dataset.xmldata))
+-- casters
+
+do
+
+ publications.detailed = setmetatableindex(function(detailed,kind)
+ local values = setmetatableindex(function(values,value)
+ local caster = casters[kind]
+ local cast = caster and caster(value) or value
+ values[value] = cast
+ return cast
+ end)
+ detailed[kind] = values
+ return values
+ end)
+
+ local keywordsplitter = utilities.parsers.groupedsplitat(";,")
+
+ casters.keyword = function(str)
+ return lpegmatch(keywordsplitter,str)
+ end
+
+
+ writers.keyword = function(k)
+ if type(k) == "table" then
+ return concat(p,";")
+ else
+ return k
+ end
+ end
+
+ local pagessplitter = lpeg.splitat(P("-")^1)
+
+ casters.range = function(str)
+ local first, last = lpegmatch(pagessplitter,str)
+ return first and last and { first, last } or str
+ end
+
+ writers.range = function(p)
+ if type(p) == "table" then
+ return concat(p,"-")
+ else
+ return p
+ end
+ end
+
+ casters.pagenumber = casters.range
+ writers.pagenumber = writers.range
+
+end
diff --git a/Master/texmf-dist/tex/context/base/publ-fnd.lua b/Master/texmf-dist/tex/context/base/publ-fnd.lua
index 383bcac73ca..909b102dba2 100644
--- a/Master/texmf-dist/tex/context/base/publ-fnd.lua
+++ b/Master/texmf-dist/tex/context/base/publ-fnd.lua
@@ -6,167 +6,380 @@ if not modules then modules = { } end modules ['publ-fnd'] = {
license = "see context related readme files"
}
-local tonumber, next = tonumber, next
-local P, R, C, Cs, Cp, Carg = lpeg.P, lpeg.R, lpeg.C, lpeg.Cs, lpeg.Cp, lpeg.Carg
-local lpegmatch = lpeg.match
+if not characters then
+ dofile(resolvers.findfile("char-def.lua"))
+ dofile(resolvers.findfile("char-utf.lua"))
+end
+
+-- this tracker is only for real debugging and not for the average user
+
+local trace_match = false trackers.register("publications.match", function(v) trace_match = v end)
+
+local publications = publications
+
+local tonumber, next, type = tonumber, next, type
+local find = string.find
+local P, R, S, C, Cs, Cp, Cc, Carg, Ct, V = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Cp, lpeg.Cc, lpeg.Carg, lpeg.Ct, lpeg.V
+local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
local concat = table.concat
local formatters = string.formatters
local lowercase = characters.lower
+local topattern = string.topattern
+
+publications = publications or { } -- for testing
+
+local report = logs.reporter("publications","match")
local colon = P(":")
local dash = P("-")
local lparent = P("(")
local rparent = P(")")
-local space = lpeg.patterns.whitespace
+local space = lpegpatterns.whitespace
+local utf8char = lpegpatterns.utf8character
local valid = 1 - colon - space - lparent - rparent
----- key = C(valid^1)
local key = C(R("az","AZ")^1)
-local word = Cs(lpeg.patterns.unquoted + valid^1)
+local wildcard = C("*")
+local word = Cs(lpegpatterns.unquoted + lpegpatterns.argument + valid^1)
+local simple = C(valid^1)
local number = C(valid^1)
------ f_string_key = formatters[" local s_%s = entry[%q]"]
-local f_string_key = formatters[" local s_%s = entry[%q] if s_%s then s_%s = lower(s_%s) end "]
-local f_number_key = formatters[" local n_%s = tonumber(entry[%q]) or 0"]
-local f_field_key = formatters[" local f_%s = entry[%q] or ''"]
+----- f_string_key = formatters[" local s_%s = entry[%q] if s_%s then s_%s = lower(s_%s) end "]
+----- f_number_key = formatters[" local n_%s = tonumber(entry[%q]) or 0"]
+----- f_field_key = formatters[" local f_%s = entry[%q] or ''"]
------ f_string_match = formatters["(s_%s and find(lower(s_%s),%q))"]
-local f_string_match = formatters["(s_%s and find(s_%s,%q))"]
-local f_number_match = formatters["(n_%s and n_%s >= %s and n_%s <= %s)"]
-local f_field_match = formatters["f_%s"]
+-- getfuzzy(entry,%q,categories)
-local match = key * (colon/"") * word * Carg(1) / function(key,_,word,keys)
- -- keys[key] = f_string_key(key,key)
- keys[key] = f_string_key(key,key,key,key,key)
- return f_string_match(key,key,lowercase(word))
-end
+-- local f_string_key = formatters[" local s_%s = get(entry,%q)\n if s_%s then s_%s = lower(s_%s) end"]
+-- local f_field_key = formatters[" local f_%s = get(entry,%q) or ''"]
+-- local f_field_key_c = formatters[" local c_%s = get(entry,%q,categories) or ''"]
+-- local f_number_key = formatters[" local n_%s = tonumber(get(entry,%q)) or 0"]
+--
+-- local f_string_match = formatters["(s_%s and find(s_%s,%q))"]
+-- local f_number_match = formatters["(n_%s and n_%s >= %s and n_%s <= %s)"]
+-- local f_field_match = formatters["f_%s"]
+-- local f_field_match_c = formatters["c_%s"]
+--
+-- local f_all_match = formatters["anywhere(entry,%q)"]
-local range = key * (colon/"") * number * (dash/"") * number * Carg(1) / function(key,_,first,_,last,keys)
- keys[key] = f_number_key(key,key)
- return f_number_match(key,key,tonumber(first) or 0,key,tonumber(last) or 0)
-end
+-- topattern(lowercase(word)) : utflowercase + only *?
-local field = (P("field:")/"") * key * Carg(1) / function(_,key,keys)
- keys[key] = f_field_key(key,key)
- return f_field_match(key)
-end
+-- local match = ( (key + wildcard) * (colon/"") ) * word * Carg(1) / function(key,_,word,keys)
+-- if key == "*" or key == "any" then
+-- keys.anywhere = true
+-- if word == "" or word == "*" then
+-- return "true"
+-- else
+-- return f_all_match(topattern(lowercase(word)))
+-- end
+-- else
+-- keys[key] = f_string_key(key,key,key,key,key)
+-- return f_string_match(key,key,topattern(lowercase(word)))
+-- end
+-- end
+--
+-- local default = simple * Carg(1) / function(word,keys)
+-- keys.anywhere = true
+-- if word == "" or word == "*" then
+-- return "true"
+-- else
+-- return f_all_match(topattern(lowercase(word)))
+-- end
+-- end
+--
+-- local range = key * (colon/"") * number * (dash/"") * number * Carg(1) / function(key,_,first,_,last,keys)
+-- keys[key] = f_number_key(key,key)
+-- return f_number_match(key,key,tonumber(first) or 0,key,tonumber(last) or 0)
+-- end
+--
+-- local field = (P("field:")/"") * key * Carg(1) / function(_,key,keys)
+-- keys[key] = f_field_key(key,key)
+-- return f_field_match(key)
+-- end
+--
+-- local cast = (P("cast:")/"") * key * Carg(1) / function(_,key,keys)
+-- keys[key] = f_field_key_c(key,key)
+-- return f_field_match_c(key)
+-- end
+--
+-- local compare = C("==") + P("=")/"==" + P("!=")/"~=" + P("<>")/"~="
+--
+-- local b_match = lparent
+-- local e_match = rparent * space^0 * (#P(-1) + P(",")/" or ") -- maybe also + -> and
+-- local f_match = ((field + cast + range + match + space + compare + P(1))-e_match)^1
+-- local p_match = b_match * default * e_match
+-- + b_match * f_match * e_match
+--
+-- local pattern = Cs(Cc("(") * (P("match")/"" * space^0 * p_match)^1 * Cc(")"))
------ pattern = Cs((field + range + match + P(1))^1)
------ b_match = P("match")/"" * lparent
-local b_match = lparent
-local e_match = rparent * space^0 * P(-1)
-local pattern = Cs(b_match * ((field + range + match + space + P(1))-e_match)^1 * e_match)
+-- field contains fieldname:nonspaces|"whatever"|'whatever'|{whatever}
+-- field exact fieldname=nonspaces|"whatever"|'whatever'|{whatever}
+-- set contains [fieldname]:nonspaces|"whatever"|'whatever'|{whatever}
+-- set exact [fieldname]=nonspaces|"whatever"|'whatever'|{whatever}
+--
+-- with * : any sequence
+-- ? : one character
+--
+-- and match(),match() ... equivalent to () and ()
+--
+-- <123 444> : range
+--
+-- unquoted = field
+-- [..] = set
+--
+-- () and or not
+--
+-- spaces are mandate (at least for now)
--- -- -- -- -- -- -- -- -- -- -- -- --
--- -- -- -- -- -- -- -- -- -- -- -- --
+local key = C(R("az","AZ")^1)
+local contains = S(":~")
+local exact = P("=")
+local valid = (1 - space - lparent -rparent)^1
+local wildcard = P("*") / ".*"
+local single = P("?") / "."
+local dash = P("-") / "%."
+local percent = P("-") / "%%"
+local word = Cs(lpegpatterns.unquoted + lpegpatterns.argument + valid)
+local range = P("<") * space^0 * C((1-space)^1) * space^1 * C((1-space- P(">"))^1) * space^0 * P(">")
-local tolower = lpeg.patterns.tolower
-local lower = string.lower
+local f_key_fld = formatters[" local kf_%s = get(entry,%q) \n if kf_%s then kf_%s = lower(kf_%s) end"]
+local f_key_set = formatters[" local ks_%s = get(entry,%q,categories)\n if ks_%s then ks_%s = lower(ks_%s) end"]
+local f_number_fld = formatters[" local nf_%s = tonumber(get(entry,%q))"]
+local f_number_set = formatters[" local ns_%s = tonumber(get(entry,%q,categories))"]
-local allascii = R("\000\127")^1 * P(-1)
+local f_fld_exact = formatters["(kf_%s == %q)"]
+local f_set_exact = formatters["(ks_%s == %q)"]
+local f_fld_contains = formatters["(kf_%s and find(kf_%s,%q))"]
+local f_set_contains = formatters["(ks_%s and find(ks_%s,%q))"]
+local f_fld_between = formatters["(nf_%s and nf_%s >= %s and nf_%s <= %s)"]
+local f_set_between = formatters["(ns_%s and ns_%s >= %s and ns_%s <= %s)"]
-function characters.checkedlower(str)
- return lpegmatch(allascii,str) and lower(str) or lpegmatch(tolower,str) or str
+local f_all_match = formatters["anywhere(entry,%q)"]
+
+local function test_key_value(keys,where,key,first,last)
+ if not key or key == "" then
+ return "(false)"
+ elseif key == "*" then
+ last = "^.*" .. topattern(lowercase(last)) .. ".*$" -- todo: make an lpeg
+ return f_all_match(last)
+ elseif first == false then
+ -- exact
+ last = lowercase(last)
+ if where == "set" then
+ keys[key] = f_key_set(key,key,key,key,key)
+ return f_set_exact(key,last)
+ else
+ keys[key] = f_key_fld(key,key,key,key,key)
+ return f_fld_exact(key,last)
+ end
+ elseif first == true then
+ -- contains
+ last = "^.*" .. topattern(lowercase(last)) .. ".*$"
+ if where == "set" then
+ keys[key] = f_key_set(key,key,key,key,key)
+ return f_set_contains(key,key,last)
+ else
+ keys[key] = f_key_fld(key,key,key,key,key)
+ return f_fld_contains(key,key,last)
+ end
+ else
+ -- range
+ if where == "set" then
+ keys[key] = f_number_set(key,key)
+ return f_set_between(key,key,tonumber(first),key,tonumber(last))
+ else
+ keys[key] = f_number_fld(key,key)
+ return f_fld_between(key,key,tonumber(first),key,tonumber(last))
+ end
+ end
end
+local p_compare = P { "all",
+ all = (V("one") + V("operator") + V("nested") + C(" "))^1,
+ nested = C("(") * V("all") * C(")"), -- C really needed?
+ operator = C("and")
+ + C("or")
+ + C("not"),
+ one = Carg(1)
+ * V("where")
+ * V("key")
+ * (V("how") * V("word") + V("range"))
+ / test_key_value,
+ key = key
+ + C("*"),
+ where = C("set") * P(":")
+ + Cc(""),
+ how = contains * Cc(true)
+ + exact * Cc(false),
+ word = word,
+ range = range,
+}
+
+-- local p_combine = space^0 * (P(",")/" or ") * space^0
+
+-- local pattern = Cs((P("match")/"" * space^0 * p_compare + p_combine)^1)
+
+local comma = P(",")
+local p_spaces = space^0
+local p_combine = p_spaces * comma * p_spaces / " or "
+local p_expression = P("match")/"" * Cs(p_compare)
+ + Carg(1)
+ * Cc("")
+ * Cc("tag")
+ * Cc(false)
+ * (
+ P("tag") * p_spaces * P("(") * Cs((1-S(")")-space)^1) * p_spaces * P(")")
+ + p_spaces * Cs((1-space-comma)^1) * p_spaces
+ ) / test_key_value
+
+local pattern = Cs {
+ [1] = V(2) * (p_combine * V(2))^0,
+ [2] = p_expression,
+}
+
-- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- --
-local f_template = string.formatters[ [[
+function publications.anywhere(entry,str) -- helpers
+ for k, v in next, entry do
+ if find(lowercase(v),str) then
+ return true
+ end
+ end
+end
+
+-- todo: use an environment instead of
+
+-- table={
+-- { "match", "((kf_editor and find(kf_editor,\"^.*braslau.*$\")))" },
+-- { "hash", "foo1234" },
+-- { "tag", "bar5678" },
+-- }
+
+local f_template = formatters[ [[
local find = string.find
-local lower = characters.checkedlower
+local lower = characters.lower
+local anywhere = publications.anywhere
+local get = publications.getfuzzy
+local specification = publications.currentspecification
+local categories = specification and specification.categories
return function(entry)
%s
-return %s and true or false
+ return %s and true or false
end
]] ]
-local function compile(expr,start)
+local function compile(dataset,expr)
local keys = { }
- local expression = lpegmatch(pattern,expr,start,keys)
- -- print("!!!!",expression)
+ -- local expression = lpegmatch(pattern,expr,start,keys)
+ local expression = lpegmatch(pattern,expr,1,keys)
+ if trace_match then
+ report("compiling expression: %s",expr)
+ end
local definitions = { }
for k, v in next, keys do
definitions[#definitions+1] = v
end
+ if #definitions == 0 then
+ report("invalid expression: %s",expr)
+ elseif trace_match then
+ for i=1,#definitions do
+ report("% 3i : %s",i,definitions[i])
+ end
+ end
definitions = concat(definitions,"\n")
local code = f_template(definitions,expression)
- -- print(code)
- code = loadstring(code)
- if type(code) == "function" then
- code = code()
- if type(code) == "function" then
- return code
+ if trace_match then
+ report("generated code: %s",code)
+ end
+ local finder = loadstring(code) -- use an environment
+ if type(finder) == "function" then
+ finder = finder()
+ if type(finder) == "function" then
+ return finder, code
end
end
- print("no valid expression",expression)
+ report("invalid expression: %s",expr)
return false
end
-local cache = { } -- todo: make weak, or just remember the last one (trial typesetting)
+-- local function test(str)
+-- local keys = { }
+-- local definitions = { }
+-- local expression = lpegmatch(pattern,str,1,keys)
+-- for k, v in next, keys do
+-- definitions[#definitions+1] = v
+-- end
+-- definitions = concat(definitions,"\n")
+-- print(f_template(definitions,expression))
+-- end
-local check = P("match") * space^0 * Cp()
+-- test("match(foo:bar and (foo:bar or foo:bar))")
+-- test("match(foo=bar and (foo=bar or foo=bar))")
+-- test("match(set:foo:bar),match(set:foo:bar)")
+-- test("match(set:foo=bar)")
+-- test("match(foo:{bar bar})")
+-- test("match(foo={bar bar})")
+-- test("match(set:foo:'bar bar')")
+-- test("match(set:foo='bar bar')")
+-- test("match(set:foo<1000 2000>)")
+-- test("match(set:foo<1000 2000>)")
+-- test("match(*:foo)")
+-- test("match(*:*)")
-local function finder(expression)
- local found = cache[expression]
- if found == nil then
- local e = lpegmatch(check,expression)
- found = e and compile(expression,e) or false
- cache[expression] = found
+local trigger = (P("match") + P("tag")) * p_spaces * P("(")
+local check = (1-trigger)^0 * trigger
+
+local function finder(dataset,expression)
+ local found = lpegmatch(check,expression) and compile(dataset,expression) or false
+ if found then
+ local okay, message = pcall(found,{})
+ if not okay then
+ found = false
+ report("error in match: %s",message)
+ end
end
return found
end
+-- finder("match(author:foo)")
+-- finder("match(author:foo and author:bar)")
+-- finder("match(author:foo or (author:bar and page:123))")
+-- finder("match(author:foo),match(author:foo)")
+
publications.finder = finder
function publications.search(dataset,expression)
- local find = finder(expression)
- local source = dataset.luadata
+ local find = finder(dataset,expression)
if find then
- local target = { }
- for k, v in next, source do
- if find(v) then
- target[k] = v
+ local ordered = dataset.ordered
+ local target = { }
+ for i=1,#ordered do
+ local entry = ordered[i]
+ if find(entry) then
+ local tag = entry.tag
+ if not target[tag] then
+ -- we always take the first
+ target[tag] = entry
+ end
end
end
return target
else
- return { source[expression] }
+ return { } -- { dataset.luadata[expression] } -- ?
end
end
-
--- local dataset = publications.new()
--- publications.load(dataset,"t:/manuals/hybrid/tugboat.bib")
---
--- local n = 500
+-- local d = publications.datasets.default
--
--- local function test(dataset,str)
--- local found
--- local start = os.clock()
--- for i=1,n do
--- found = search(dataset,str)
--- end
--- local elapsed = os.clock() - start
--- print(elapsed,elapsed/500,#table.keys(dataset.luadata),str)
--- print(table.concat(table.sortedkeys(found)," "))
--- return found
--- end
+-- local d = publications.load {
+-- dataset = "default",
+-- filename = "t:/manuals/mkiv/hybrid/tugboat.bib"
+-- }
--
--- local found = test(dataset,[[match(author:hagen)]])
--- local found = test(dataset,[[match(author:hagen and author:hoekwater and year:1990-2010)]])
--- local found = test(dataset,[[match(author:"Bogusław Jackowski")]])
--- local found = test(dataset,[[match(author:"Bogusław Jackowski" and (tonumber(field:year) or 0) > 2000)]])
--- local found = test(dataset,[[Hagen:TB19-3-304]])
-
--- 1.328 0.002656 2710 author:hagen
--- Berdnikov:TB21-2-129 Guenther:TB5-1-24 Hagen:TB17-1-54 Hagen:TB19-3-304 Hagen:TB19-3-311 Hagen:TB19-3-317 Hagen:TB22-1-58 Hagen:TB22-3-118 Hagen:TB22-3-136 Hagen:TB22-3-160 Hagen:TB23-1-49 Hagen:TB25-1-108 Hagen:TB25-1-48 Hagen:TB26-2-152
-
--- 1.812 0.003624 2710 author:hagen and author:hoekwater and year:1990-2010
--- Berdnikov:TB21-2-129
-
--- 1.344 0.002688 2710 author:"Bogusław Jackowski"
--- Berdnikov:TB21-2-129 Jackowski:TB16-4-388 Jackowski:TB19-3-267 Jackowski:TB19-3-272 Jackowski:TB20-2-104 Jackowski:TB24-1-64 Jackowski:TB24-3-575 Nowacki:TB19-3-242 Rycko:TB14-3-171
-
--- 1.391 0.002782 2710 author:"Bogusław Jackowski" and (tonumber(field:year) or 0) > 2000
--- Jackowski:TB24-1-64 Jackowski:TB24-3-575
+-- inspect(publications.search(d,[[match(author:hagen)]]))
+-- inspect(publications.search(d,[[match(author:hagen and author:hoekwater and year:1990-2010)]]))
+-- inspect(publications.search(d,[[match(author:"Bogusław Jackowski")]]))
+-- inspect(publications.search(d,[[match(author:"Bogusław Jackowski" and (tonumber(field:year) or 0) > 2000)]]))
+-- inspect(publications.search(d,[[Hagen:TB19-3-304]]))
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-apa.lua b/Master/texmf-dist/tex/context/base/publ-imp-apa.lua
new file mode 100644
index 00000000000..c5d2512fd50
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-apa.lua
@@ -0,0 +1,521 @@
+local specification = {
+ --
+ -- metadata
+ --
+ name = "apa",
+ version = "1.00",
+ comment = "APA specification",
+ author = "Alan Braslau and Hans Hagen",
+ copyright = "ConTeXt development team",
+ --
+ -- derived (combinations of) fields (all share the same default set)
+ --
+ virtual = {
+ "authoryear",
+ "authoryears",
+ "authornum",
+ "num",
+ "suffix",
+ },
+ --
+ -- special datatypes
+ --
+ types = {
+ --
+ -- list of fields that are interpreted as names: "NAME [and NAME]" where
+ -- NAME is one of the following:
+ --
+ -- First vons Last
+ -- vons Last, First
+ -- vons Last, Jrs, First
+ -- Vons, Last, Jrs, First
+ --
+ author = "author", -- interpreted as name(s)
+ editor = "author",
+ artist = "author",
+ composer = "author",
+ producer = "author",
+ director = "author",
+ doi = "url", -- an external link
+ url = "url",
+ page = "pagenumber", -- number or range: f--t
+ pages = "pagenumber",
+ volume = "range",
+ number = "range",
+ keywords = "keyword", -- comma|-|separated list
+ year = "number",
+ },
+ --
+ -- categories with their specific fields
+ --
+ categories = {
+ --
+ -- categories are added below
+ --
+ },
+}
+
+local generic = {
+ --
+ -- A set returns the first field (in order of position below) that is found
+ -- present in an entry. A set having the same name as a field conditionally
+ -- allows the substitution of an alternate field.
+ --
+ -- note that anything can get assigned a doi or be available online.
+ doi = { "doi", "url" },
+ editionset = { "edition", "volume", "number", "pages" },
+}
+
+-- Definition of recognized categories and the fields that they contain.
+-- Required fields should be present; optional fields may also be rendered;
+-- all other fields will be ignored.
+
+-- Sets contain either/or in order of precedence.
+--
+-- For a category *not* defined here yet present in the dataset, *all* fields
+-- are taken as optional. This allows for flexibility in the addition of new
+-- categories.
+
+local categories = specification.categories
+
+-- an article from a journal
+
+categories.article = {
+ sets = {
+ author = { "author", "editor", "title" },
+ doi = generic.doi,
+ },
+ required = {
+ "author"
+ },
+ optional = {
+ "year",
+ "subtitle", "type", "file",
+ "journal", "volume", "number", "pages",
+ "doi", "note",
+ },
+}
+
+-- an article from a magazine
+
+categories.magazine = {
+ sets = categories.article.sets,
+ required = {
+ "author",
+ "year",
+ "journal",
+ },
+ optional = {
+ "subtitle", "type", "file",
+ "number",
+ "month", "day",
+ "doi", "note",
+ },
+}
+
+categories.newspaper = categories.magazine
+
+-- (from jabref) to be identified and setup ...
+
+categories.periodical = {
+ sets = {
+ author = { "editor", "publisher" },
+ doi = generic.doi,
+ },
+ required = {
+ "title",
+ "year",
+ },
+ optional = {
+ "author",
+ "subtitle", "file",
+ "series", "volume", "number", "month",
+ "organization",
+ "doi", "note",
+ },
+}
+
+-- (from jabref) to be identified and setup ...
+
+categories.standard = {
+ sets = {
+ author = { "author", "institution", "organization" },
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "year",
+ "title", "subtitle",
+ "doi", "note",
+ },
+ optional = {
+ },
+}
+
+-- a book with an explicit publisher.
+
+categories.book = {
+ sets = {
+ author = { "author", "editor", "publisher", "title" },
+ editionset = generic.editionset,
+ doi = generic.doi,
+ },
+ required = { "author" },
+ optional = {
+ "year", "month", "day",
+ "subtitle", "type", "file",
+ "editionset", "series",
+ "address",
+ "doi", "note",
+ },
+}
+
+-- a part of a book, which may be a chapter (or section or whatever) and/or a range of pages.
+
+categories.inbook = {
+ sets = {
+ author = { "author", "editor", "publisher", "title", },
+ editionset = generic.editionset,
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "year" ,
+ },
+ optional = {
+ "subtitle", "type", "file",
+ "booktitle",
+ -- APA ignores this: "chapter",
+ "editionset", "series",
+ "month",
+ "address",
+ "doi", "note",
+ },
+}
+
+-- a book having its own title as part of a collection.
+-- (like inbook, but we here make booktitle required)
+
+categories.incollection = {
+ sets = {
+ author = { "author", "editor", "publisher", "title", },
+ editionset = generic.editionset,
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "booktitle",
+ "year",
+ },
+ optional = {
+ "subtitle", "type", "file",
+ "editionset", "series",
+ -- APA ignores this: "chapter",
+ "month",
+ "address",
+ "doi", "note",
+ },
+}
+
+-- a work that is printed and bound, but without a named publisher or sponsoring institution.
+
+categories.booklet = {
+ sets = {
+ author = { "author", "title", },
+ publisher = { "howpublished" }, -- no "publisher"!
+ doi = generic.doi,
+ },
+ required = {
+ "author"
+ },
+ optional = {
+ "publisher",
+ "year", "month",
+ "subtitle", "type", "file",
+ "address",
+ "doi", "note",
+ },
+}
+
+-- the proceedings of a conference.
+
+categories.proceedings = {
+ sets = {
+ author = { "editor", "organization", "publisher", "title" }, -- no "author"!
+ publisher = { "publisher", "organization" },
+ editionset = generic.editionset,
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "year"
+ },
+ optional = {
+ "publisher",
+ "subtitle", "file",
+ "editionset", "series",
+ "month",
+ "address",
+ "doi", "note",
+ },
+}
+
+-- an article in a conference proceedings.
+
+categories.inproceedings = {
+ sets = categories.incollection.sets,
+ required = categories.incollection.required,
+ optional = {
+ "subtitle", "type", "file",
+ "month",
+ "edition", "series",
+ "address", "organization",
+ "doi", "note",
+ },
+}
+
+categories.conference = categories.inproceedings
+
+-- a thesis (of course).
+
+categories.thesis = {
+ sets = {
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "title",
+ "school",
+ "year",
+ "type"
+ },
+ optional = {
+ "subtitle", "file",
+ "month",
+ "address",
+ "doi", "note",
+ },
+}
+
+categories.mastersthesis = {
+ sets = categories.thesis.sets,
+ required = {
+ "author",
+ "title",
+ "school",
+ "year"
+ },
+ optional = {
+ "type",
+ "subtitle", "file",
+ "month",
+ "address",
+ "doi", "note",
+ },
+}
+categories.phdthesis = categories.mastersthesis
+
+-- a report published by a school or other institution, usually numbered within a series.
+
+categories.techreport = {
+ sets = {
+ author = { "author", "institution", "publisher", "title" },
+ publisher = { "publisher", "institution", },
+ editionset = { "type", "volume", "number", "pages" }, -- no "edition"!
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "title",
+ "institution",
+ "year"
+ },
+ optional = {
+ "publisher",
+ "address",
+ "subtitle", "file",
+ "editionset",
+ "month",
+ "doi", "note",
+ },
+}
+
+-- technical documentation.
+
+categories.manual = {
+ sets = {
+ author = { "author", "organization", "publisher", "title" },
+ publisher = { "publisher", "organization", },
+ editionset = generic.editionset,
+ doi = generic.doi,
+ },
+ required = {
+ "title"
+ },
+ optional = {
+ "author", "publisher",
+ "address",
+ "subtitle", "file",
+ "editionset", "month", "year",
+ "doi", "note",
+-- "abstract",
+ },
+}
+
+-- a patent (of course).
+
+categories.patent = {
+ sets = {
+ author = { "author", "assignee", },
+ publisher = { "publisher", "assignee", },
+ year = { "year", "yearfiled", },
+ month = { "month", "monthfiled", },
+ day = { "day", "dayfiled", },
+ doi = generic.doi,
+ },
+ required = {
+ "nationality",
+ "number",
+ "year",
+ },
+ optional = {
+ "type",
+ --check this: "language",
+ "author", "publisher",
+ "title", "subtitle", "file",
+ "address",
+ "day", "month",
+ "doi", "note"
+ },
+}
+
+-- a document having an author and title, but not formally published.
+
+categories.unpublished = {
+ sets = {
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "title",
+ "note"
+ },
+ optional = {
+ "subtitle", "file",
+ "year", "month",
+ "doi"
+ },
+}
+
+-- like misc below but includes organization.
+
+categories.electronic = {
+ sets = {
+ doi = generic.doi,
+ },
+ required = {
+ "title"
+ },
+ optional = {
+ "subtitle", "type", "file",
+ "year", "month",
+ "author",
+ "address",
+ "organization",
+ "howpublished",
+ "doi", "note"
+ },
+}
+
+-- not bibtex categories...
+
+categories.film = {
+ sets = {
+ doi = generic.doi,
+ },
+ required = {
+ "producer", "director",
+ "title", "year",
+ "address", "publisher", -- aka studio
+ },
+ optional = {
+ "type",
+ "note",
+ "doi",
+ },
+}
+
+categories.music = {
+ sets = {
+ doi = generic.doi,
+ author = { "composer", "artist", "title", "album" },
+ title = { "title", "album", },
+ },
+ required = {
+ "author",
+ "title",
+ "year",
+ "address", "publisher", -- aka label
+ },
+ optional = {
+ "type",
+ "note",
+ "doi",
+ },
+}
+
+-- use this type when nothing else fits.
+
+categories.misc = {
+ sets = {
+ doi = generic.doi,
+ },
+ required = {
+ -- nothing is really important here
+ },
+ optional = {
+ "author",
+ "title", "subtitle", "file",
+ "year", "month",
+ "howpublished",
+ "doi", "note",
+ },
+}
+
+-- other (whatever jabref does not know!)
+
+categories.other = {
+ sets = {
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "title",
+ "year"
+ },
+ optional = {
+ "subtitle", "file",
+ "doi", "note",
+ },
+}
+
+-- if all else fails to match:
+
+categories.literal = {
+ sets = {
+ author = { "key" },
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "text"
+ },
+ optional = {
+ "doi", "note"
+ },
+ virtual = false,
+}
+
+-- done
+
+return specification
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-apa.mkiv b/Master/texmf-dist/tex/context/base/publ-imp-apa.mkiv
deleted file mode 100644
index 3f7b119af67..00000000000
--- a/Master/texmf-dist/tex/context/base/publ-imp-apa.mkiv
+++ /dev/null
@@ -1,547 +0,0 @@
-%D \module
-%D [ file=publ-imp-apa,
-%D version=2013.12.12, % based on bibl-apa.tex and later xml variant
-%D title=APA bibliography style,
-%D subtitle=Publications,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is therefore copyrighted
-%D by \PRAGMA. See mreadme.pdf for details.
-
-% common
-
-% \loadbtxdefinitionfile[def]
-
-\startsetups btx:apa:common:wherefrom
- \btxdoifelse {address} {
- \getvariable{btx:temp}{left}
- \btxdoifelse {country} {
- \btxdoifelse {\getvariable{btx:temp}{label}} {
- \btxflush{address}\btxcomma\btxflush{country}: \btxflush{\getvariable{btx:temp}{label}}
- } {
- \btxflush{address}\btxcomma\btxflush{country}
- }
- } {
- \btxdoifelse {\getvariable{btx:temp}{label}} {
- \btxflush{address}\btxcomma\btxflush{\getvariable{btx:temp}{label}}
- } {
- \btxflush{address}
- }
- }
- \getvariable{btx:temp}{right}
- } {
- \btxdoifelse {country} {
- \getvariable{btx:temp}{left}
- \btxdoifelse {\getvariable{btx:temp}{label}} {
- \btxflush{country}: \btxflush{\getvariable{btx:temp}{label}}
- } {
- \btxflush{country}
- }
- \getvariable{btx:temp}{right}
- } {
- \btxdoifelse {\getvariable{btx:temp}{label}} {
- \getvariable{btx:temp}{left}
- \btxflush{\getvariable{btx:temp}{label}}
- \getvariable{btx:temp}{right}
- } {
- \getvariable{btx:temp}{otherwise}
- }
- }
- }
-\stopsetups
-
-% \setvariables[btx:temp][label=,left=,right=,otherwise=]
-
-\startsetups btx:apa:common:publisher
- \begingroup
- \setvariables[btx:temp][label=publisher]\relax
- \btxsetup{btx:apa:common:wherefrom}
- \endgroup
-\stopsetups
-
-\startsetups btx:apa:common:organization
- \begingroup
- \setvariables[btx:temp][label=organization]\relax
- \btxsetup{btx:apa:common:wherefrom}
- \endgroup
-\stopsetups
-
-\startsetups btx:apa:common:school
- \begingroup
- \setvariables[btx:temp][label=school]\relax
- \btxsetup{btx:apa:common:wherefrom}
- \endgroup
-\stopsetups
-
-\startsetups btx:apa:common:institution
- \begingroup
- \setvariables[btx:temp][label=institution]\relax
- \btxsetup{btx:apa:common:wherefrom}
- \endgroup
-\stopsetups
-
-\startsetups btx:apa:common:school:subsentence
- \begingroup
- \setvariables[btx:temp][label=school,left=\btxcomma,right=\btxperiod,otherwise=\btxperiod]\relax
- \btxsetup{btx:apa:common:wherefrom}
- \endgroup
-\stopsetups
-
-\startsetups btx:apa:common:institution:subsentence
- \begingroup
- \setvariables[btx:temp][label=institution,left=\btxcomma,right=\btxperiod,otherwise=\btxperiod]\relax
- \btxsetup{btx:apa:common:wherefrom}
- \endgroup
-\stopsetups
-
-\startsetups btx:apa:common:publisher:sentence
- \begingroup
- \setvariables[btx:temp][label=publisher,left=\btxspace,right=\btxperiod]\relax
- \btxsetup{btx:apa:common:wherefrom}
- \endgroup
-\stopsetups
-
-\startsetups btx:apa:common:organization:sentence
- \begingroup
- \setvariables[btx:temp][label=organization,left=\btxspace,right=\btxperiod]\relax
- \btxsetup{btx:apa:common:wherefrom}
- \endgroup
-\stopsetups
-
-\startsetups btx:apa:common:title-and-series
- \btxdoif {title} {
- \btxflush{title}
- \btxdoif {series} {
- \btxlparent\btxflush{series}\btxrparent
- }
- \btxperiod
- }
-\stopsetups
-
-\startsetups btx:apa:common:title-it-and-series
- \btxdoif {title} {
- \bgroup\it\btxflush{title}\/\egroup
- \btxdoif {series} {
- \btxlparent\btxflush{series}\btxrparent
- }
- \btxperiod
- }
-\stopsetups
-
-\disablemode[btx:apa:edited-book]
-
-\startsetups btx:apa:common:author-and-year
- \btxdoif {author} {
- \btxflushauthor{author}
- }
- \btxdoif {year} {
- \btxlparent\btxflush{year}\btxrparent
- }
- \btxperiod
-\stopsetups
-
-\startsetups btx:apa:common:author-or-key-and-year
- \btxdoifelse {author} {
- \btxflushauthor{author}
- } {
- \btxdoif {key} {
- \btxlbracket\btxsetup{btx:format:key}\btxrbracket
- }
- }
- \btxdoif {year} {
- \btxlparent\btxflush{year}\btxrparent
- }
- \btxperiod
-\stopsetups
-
-\startsetups btx:apa:common:author-editors-crossref-year
- \btxdoif {author} {
- \btxflushauthor{author}
- } {
- \btxdoifelse {editor} {
- \enablemode[btx:apa:edited-book]
- \btxflushauthor{editor}
- \btxcomma\btxsingularplural{editor}{editor}{editors}
- } {
- % weird period
- \btxdoif {crossref} {
- \btxlbracket\btxsetup{btx:format:crossref}\btxrbracket\btxperiod
- }
- }
- }
- \btxdoif {year} {
- \btxlparent\btxflush{year}\btxrparent
- }
- \btxperiod
-\stopsetups
-
-\startsetups btx:apa:common:editor-or-key-and-year
- \btxdoifelse {editor} {
- \enablemode[btx:apa:edited-book]
- \btxflushauthor{editor}
- \btxcomma\btxsingularplural{editor}{editor}{editors}
- } {
- \btxdoif {key} {
- \btxlbracket\btxsetup{btx:format:key}\btxrbracket
- }
- }
- \btxspace
- \btxdoif {year} {
- \btxlparent\btxflush{year}\btxrparent
- }
- \btxperiod
-\stopsetups
-
-\startsetups btx:apa:common:note
- \btxdoif {note} {
- \btxspace\btxflush{note}\btxperiod
- }
-\stopsetups
-
-\startsetups btx:apa:common:comment
- \btxdoif {comment} {
- \btxspace\btxflush{comment}\btxperiod
- }
-\stopsetups
-
-\startsetups btx:apa:common:pages:p
- \btxdoif {pages} {
- \btxspace\btxflush{pages}\btxspace p\btxperiod
- }
-\stopsetups
-
-\startsetups btx:apa:common:pages:pp
- \btxdoif {pages} {
- \btxspace\btxflush{pages}\btxspace pp\btxperiod
- }
-\stopsetups
-
-\startsetups btx:apa:common:pages:pages
- \btxdoif {pages} {
- \btxcomma pages~\btxflush{pages}
- }
-\stopsetups
-
-\startsetups btx:apa:common:edition:sentense
- \btxdoif {edition} {
- \btxspace\btxflush{edition}\btxspace edition\btxperiod
- }
-\stopsetups
-
-% check when the next is used (no period)
-
-% \startsetups btx:apa:common:edition
-% \btxdoif {edition} {
-% \btxspace\btxflush{edition}\btxspace edition
-% }
-% \stopsetups
-
-% we can share more, todo
-
-% specific
-
-\startsetups btx:apa:article
- \btxsetup{btx:apa:common:author-or-key-and-year}
- \btxdoif {title} {
- \btxflush{title}\btxperiod
- }
- \btxdoifelse {journal} {
- \bgroup\it\btxflush{journal}\/\egroup
- } {
- \btxdoif {crossref} {
- In\btxspace\btxflush{crossref}
- }
- }
- \btxdoifelse {volume} {
- \btxcomma\bgroup\it\btxflush{volume}\/\egroup
- \btxdoif {issue} {
- \btxlparent\btxflush{issue}\btxrparent
- }
- \btxdoif {pages} {
- \btxcomma\btxflush{pages}
- }
- \btxperiod
- } {
- \btxsetup{btx:apa:common:pages:pp}
- }
- \btxsetup{btx:apa:common:note}
- \btxsetup{btx:apa:common:comment}
-\stopsetups
-
-\startsetups btx:apa:book
- \btxsetup{btx:apa:common:author-editors-crossref-year}
- \btxdoif {title} {
- \bgroup\it\btxflush{title}\/\egroup
- \doifmodeelse {btx:apa:edited-book} {
- \btxdoifelse {volume} {
- \btxspace Number\nonbreakablespace\btxflush{volume}
- \btxdoifelse {series} {
- \btxspace in\nonbreakablespace\btxflush{series}\btxperiod
- } {
- \btxdoifelse {crossref} {
- \btxspace in\btxlbracket\btxsetup{btx:format:crossref}\btxrbracket
- } {
- \btxperiod
- }
- }
- } {
- \btxdoif {series} {
- \btxspace\btxflush{series}
- }
- \btxperiod
- }
- } {
- \btxdoifelse {crossref} {
- \btxdoif {chapter} {
- \btxcomma\btxflush{chapter}
- }
- \btxsetup{btx:apa:common:pages:pages}
- \btxperiod
- \btxdoif {volume} {
- Volume\nonbreakablespace\btxflush{volume}\btxspace of\nonbreakablespace
- }
- } {
- \btxdoif {volume} {
- \btxcomma volume\nonbreakablespace\btxflush{volume}
- \btxdoif {series} {
- \btxspace of\nonbreakablespace\bgroup\it\btxflush{series}\/\egroup
- }
- \btxdoif {chapter} {
- \btxcomma\btxflush{chapter}
- }
- \btxsetup{btx:apa:common:pages:pages}
- }
- \btxperiod
- }
- }
- }
- \btxsetup{btx:apa:common:edition:sentence}
- \btxsetup{btx:apa:common:publisher:sentence}
- \btxsetup{btx:apa:common:pages:p}% twice?
- \btxsetup{btx:apa:common:note}
-\stopsetups
-
-\startsetups btx:apa:inbook
- \btxsetup{btx:apa:common:author-editors-crossref-year}
- \btxdoifelse {title} {
- \bgroup\it\btxflush{title}\/\egroup
- } {
- \doifmodeelse {btx:apa:edited-book} {
- \btxdoifelse {volume} {
- \btxspace number\nonbreakablespace\btxflush{volume}
- \btxdoifelse {series} {
- \btxspace in\nonbreakablespace\btxflush{series}\btxperiod
- } {
- \btxdoifelse {crossref} {
- \btxspace in\btxlbracket\btxsetup{btx:format:crossref}\btxrbracket
- } {
- \btxperiod
- }
- }
- } {
- \btxdoif {series} {
- \btxspace\btxflush{series}\btxperiod
- }
- }
- } {
- \btxdoifelse {crossref} {
- \btxdoif {chapter} {
- \btxcomma\btxflush{chapter}
- }
- \btxsetup{btx:apa:common:pages:pages}
- \btxdoif {volume} {
- Volume\nonbreakablespace\btxflush{volume}\btxspace of\nonbreakablespace
- }
- \btxdoif {crossref} {
- \btxlbracket\btxsetup{btx:format:crossref}\btxrbracket
- }
- } {
- \btxdoif {volume} {
- \btxcomma volume\nonbreakablespace\btxflush{volume}
- \btxdoif {series} {
- \btxspace of\nonbreakablespace\bgroup\it\btxflush{series}\/\egroup
- }
- \btxdoif {chapter} {
- \btxcomma\btxflush{chapter}
- }
- \btxsetup{btx:apa:common:pages:pages}
- \btxperiod
- }
- }
- }
- }
- \btxspace
- \btxsetup{btx:apa:common:edition:sentence}
- \btxsetup{btx:apa:common:publisher}
- \btxsetup{btx:apa:common:note}
-\stopsetups
-
-\startsetups btx:apa:booklet
- \btxsetup{btx:apa:common:author-or-key-and-year}
- \btxsetup{btx:apa:common:title-it-and-series}
- \btxsetup{btx:apa:common:edition:sentence}
- \btxsetup{btx:apa:common:publication:sentence}
- \btxsetup{btx:apa:common:pages:p}
- \btxsetup{btx:apa:common:note}
-\stopsetups
-
-\startsetups btx:apa:manual
- \btxsetup{btx:apa:common:author-or-key-and-year}
- \btxsetup{btx:apa:common:title-it-and-series}
- \btxsetup{btx:apa:common:edition:sentence}
- \btxsetup{btx:apa:common:organization:sentence}
- \btxsetup{btx:apa:common:pages:p}
- \btxsetup{btx:apa:common:note}
-\stopsetups
-
-\startsetups btx:apa:incollection
- \btxsetup{btx:apa:common:author-and-year}
- \btxdoif {arttitle} {
- \btxflush{arttitle}\btxperiod
- }
- In\btxspace
- \btxdoifelse {title} {
- \btxflushauthor{editor}\btxcomma
- \bgroup\it\btxflush{title}\/\egroup
- \btxdoif {series} {
- \btxdoif {volume} {
- \btxcomma number\btxspace\btxflush{volume}\btxspace in
- }
- \btxspace\btxflush{series}
- }
- \btxdoif {chapter} {
- \btxcomma\btxflush{chapter}\btxspace
- }
- \btxsetup{btx:apa:common:pages:pages}
- \btxdoif {edition} {
- \btxspace\btxflush{edition}\btxspace edition
- }
- \btxsetup{btx:apa:common:publisher:sentence}
- } {
- \btxdoif {crossref} {
- \btxlbracket\btxsetup{btx:format:crossref}\btxrbracket
- }
- \btxdoif {chapter} {
- \btxcomma\btxflush{chapter}
- }
- \btxspace
- \btxsetup{btx:apa:common:pages:pages}
- }
- \btxsetup{btx:apa:common:note}
-\stopsetups
-
-\startsetups btx:apa:inproceedings
- \btxsetup{btx:apa:common:author-and-year}
- \btxdoif {arttitle} {
- \btxflush{arttitle}\btxperiod
- }
- In\btxspace
- \btxdoifelse {title} {
- \btxdoif {editor} {
- \btxflush{btx:apa:format:editors}
- \btxcomma\btxsingularplural{editor}{editor}{editors}\btxcomma
- }
- \bgroup\it\btxflush{title}\/\egroup
- \btxdoif {series} {
- \btxdoif {volume} {
- \btxcomma number~\btxflush{volume} in
- }
- \btxspace
- \btxflush{series}
- }
- \btxdoif {chapter} {
- \btxcomma\btxflush{chapter}\btxspace
- }
- \btxsetup{btx:apa:common:pages:pages}
- \btxperiod
- \btxsetup{btx:apa:common:organization:sentence}
- } {
- \btxdoif {crossref} {
- \btxlbracket\btxsetup{btx:format:crossref}\btxrbracket
- }
- \btxdoif {chapter} {
- \btxcomma\btxflush{chapter}\btxspace
- }
- \btxsetup{btx:apa:common:pages:pages}
- \btxperiod
- }
- \btxsetup{btx:apa:common:note}
-\stopsetups
-
-\startsetups btx:apa:proceedings
- \btxsetup{btx:apa:common:editor-or-key-and-year}
- \btxdoif {title} {
- \bgroup\it\btxflush{title}\/\egroup
- \btxdoif {volume} {
- \btxcomma number\btxspace\btxflush{volume}\btxspace in\btxspace
- }
- \btxdoif {chapter} {
- \btxcomma\btxflush{chapter}\btxspace
- }
- \btxsetup{btx:apa:common:pages:pages}
- \btxperiod
- \btxsetup{btx:apa:common:organization:sentence}
- }
- \btxsetup{btx:apa:common:note}
-\stopsetups
-
-\startsetups btx:apa:common:thesis
- \btxsetup{btx:apa:common:author-and-year}
- \btxsetup{btx:apa:common:title-it-and-series}
- \btxdoifelse {type} {
- \btxflush{type}
- } {
- \getvariable{btx:temp}{label}
- }
- \btxsetup{btx:apa:common:school:subsentence}
- \btxsetup{btx:apa:common:pages:p}
- \btxsetup{btx:apa:common:note}
-\stopsetups
-
-\startsetups btx:apa:mastersthesis
- \setvariables[btx:temp][label=Master's thesis]
- \btxsetup{btx:apa:common:thesis}
-\stopsetups
-
-\startsetups btx:apa:phdthesis
- \setvariables[btx:temp][label=PhD thesis]
- \btxsetup{btx:apa:common:thesis}
-\stopsetups
-
-\startsetups btx:apa:techreport
- \btxsetup{btx:apa:common:author-and-year}
- \btxsetup{btx:apa:common:title-and-series}
- \btxdoifelse {type} {
- \btxflush{type}
- \btxdoif {volume} {
- \btxspace\btxflush{volume}
- }
- } {
- \btxspace Technical Report
- }
- \btxsetup{btx:apa:common:institution:subsentence}
- \btxsetup{btx:apa:common:pages:p}
- \btxsetup{btx:apa:common:note}
-\stopsetups
-
-\startsetups btx:apa:misc
- \btxsetup{btx:apa:common:author-and-year}
- \btxsetup{btx:apa:common:title-and-series}
- \btxsetup{btx:apa:common:publisher:sentence}
- \btxsetup{btx:apa:common:pages:p}
- \btxsetup{btx:apa:common:note}
-\stopsetups
-
-\startsetups btx:apa:unpublished
- \btxsetup{btx:apa:common:author-and-year}
- \btxsetup{btx:apa:common:title-and-series}
- \btxsetup{btx:apa:common:pages:p}
- \btxdoif {type} {
- \btxlparent\btxflush{type}\btxrparent
- }
- \btxsetup{btx:apa:common:note}
-\stopsetups
-
-\endinput
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-apa.mkvi b/Master/texmf-dist/tex/context/base/publ-imp-apa.mkvi
new file mode 100644
index 00000000000..a1814b0a48b
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-apa.mkvi
@@ -0,0 +1,1473 @@
+%D \module
+%D [ file=publ-imp-apa,
+%D version=2013.12.12,
+%D title=APA bibliography style,
+%D subtitle=Publications,
+%D author=Alan Braslau and Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is therefore copyrighted
+%D by \PRAGMA. See mreadme.pdf for details.
+
+\startbtxrenderingdefinitions[apa]
+
+\ifdefined\c!translate \else \def\c!translate{translate} \fi
+
+%D Reference:
+%D \startTEX
+%D @Book{APA2010,
+%D title ={Publication Manual of the American Psychological Association},
+%D year ={2010},
+%D edition ={Sixth},
+%D address ={Washington, DC},
+%D publisher={American Psychological Association},
+%D pages ={291},
+%D url ={http://www.apa.org/books/},
+%D }
+%D \stopTEX
+
+% set ALL specific APA compliant values
+
+\definebtx
+ [apa]
+ [\c!default=default,
+ \c!specification=apa,
+ \c!otherstext={\space\btxlabeltext{apa:others}},
+ %c!journalconversion=\v!normal,
+ \c!monthconversion=\v!month]
+
+% First, define list and rendering parameters
+
+% The APA style sorts the unnumbered rendered list by authoryear
+
+\definebtxrendering
+ [apa]
+ [\c!specification=apa,
+ \c!sorttype=authoryear,
+ \c!numbering=\v!no]
+
+\setupbtxlist
+ [apa]
+ [\c!alternative=\v!paragraph,
+ \c!width=\v!fit,
+ \c!distance=.5\emwidth,
+ \c!margin=3\emwidth]
+
+\definebtx
+ [apa:list]
+ [apa]
+ [\c!otherstext={,\nobreakspace\textellipsis\space},
+ \c!etallimit=7,
+ \c!etaldisplay=6,
+ \c!authorconversion=invertedshort,
+ \c!separator:names:2={,\space}, % aka namesep - in this namespace
+ \c!separator:names:3={,\nobreakspace\textampersand\space}, % comma separated list
+ \c!separator:names:4={\nobreakspace\textampersand\space}] % last of two, no comma!
+
+% First, we define a namespace for a few special fields
+
+\definebtx
+ [apa:list:author]
+ [apa:list]
+
+\definebtx
+ [apa:list:editor]
+ [apa:list:author]
+
+\definebtx
+ [apa:list:suffix]
+ [apa:list]
+
+\definebtx
+ [apa:list:url]
+ [apa:list]
+
+\definebtx
+ [apa:list:doi]
+ [apa:list]
+
+\definebtx
+ [apa:list:invertedshort]
+ [apa:list]
+
+\definebtx
+ [apa:list:short]
+ [apa:list]
+
+% Next, we define a namespace for each category
+
+%D In order to be able to get journals expanded (or normalized or abbreviated) you need
+%D to load a list:
+%D
+%D \starttyping
+%D \btxloadjournallist[journals.txt] % the jabref list
+%D \stoptyping
+
+
+\definebtx
+ [apa:list:journal]
+ [\c!style=\v!italic]
+ %command=\btxexpandedjournal] % btxabbreviatedjournal
+
+\definebtx
+ [apa:list:title]
+ [\c!style=\v!italic,
+ \c!command=\Word,
+ \c!translate=\v!yes]
+
+\definebtx
+ [apa:list:title:article]
+ [apa:list:title]
+ [\c!style=] % journal is set in italics
+
+\definebtx
+ [apa:list:title:magazine]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:newspaper]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:periodical]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:standard]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:book]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:inbook]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:incollection]
+ [apa:list:title]
+ [\c!style=] % booktitle is set in italics
+
+\definebtx
+ [apa:list:title:proceedings]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:inproceedings]
+ [apa:list:title]
+ [\c!style=] % booktitle is set in italics
+
+\definebtx
+ [apa:list:title:conference]
+ [apa:list:title]
+ [\c!style=] % booktitle is set in italics
+
+\definebtx
+ [apa:list:title:thesis]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:phdthesis]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:mastersthesis]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:booklet]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:manual]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:techreport]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:unpublished]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:patent]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:electronic]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:music]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:film]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:other]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:misc]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:title:literal]
+ [apa:list:title]
+
+\definebtx
+ [apa:list:type]
+ [\c!command=\Word]
+
+% We define [page] settings in the apa namespace, inheriting the root
+% settings, in order to eventually allow for modifications without touching
+% root.
+
+\definebtx
+ [apa:page]
+ [\s!page]
+
+\definebtx
+ [apa:page:list]
+ [apa:page]
+ [\c!command={\wordright}]
+
+% Then define and set cite parameters.
+
+\definebtx
+ [apa:cite]
+ [apa]
+ [\c!alternative=authoryear,
+ \c!otherstext={,\space\btxlabeltext{apa:others}},
+ \c!etallimit=5,
+ \c!etaldisplay=1, % TODO: when 2-4, show all first time, etaldisplay subsequently...
+ \c!authorconversion=\v!name,
+ \c!sorttype=authoryear,
+ \c!separator:names:2={,\space},
+ \c!separator:names:3={,\space\btxlabeltext{apa:and}\space}, % not \textampersand
+ \c!separator:names:4={\space\btxlabeltext{apa:and}\space}] % not \textampersand
+
+\definebtx
+ [apa:cite:author]
+ [apa:cite]
+
+\definebtx
+ [apa:cite:authoryear]
+ [apa:cite:author]
+ [\c!left={\removeunwantedspaces\pushpunctuation\btxspace(},
+ \c!right={)\poppunctuation},
+ \c!inbetween={,\space},
+ \c!compress=\v!yes]
+
+\definebtx
+ [apa:cite:default]
+ [apa:cite:authoryear]
+
+\definebtx
+ [apa:cite:authoryears]
+ [apa:cite:authoryear]
+ [\c!left=,
+ \c!right=,
+ \c!inbetween={\space}]
+
+\definebtx
+ [apa:cite:authornum]
+ [apa:cite:author]
+ [\c!left={\removeunwantedspaces\pushpunctuation\btxspace(},
+ \c!right={)\poppunctuation},
+ \c!sorttype=authornum]
+
+\definebtx
+ [apa:cite:authorref]
+ [apa:cite:authornum]
+
+\definebtx
+ [apa:cite:author:num] % todo
+ [apa:cite:authornum]
+ [\c!left={\removeunwantedspaces\pushpunctuation\btxspace[},
+ \c!right={]\poppunctuation}]
+
+\definebtx
+ [apa:cite:author:year] % todo
+ [apa:cite]
+
+\definebtx
+ [apa:cite:author:years] % todo
+ [apa:cite:authoryears]
+ [\c!inbetween=,
+ \c!left=(,
+ \c!right=)]
+
+\definebtx
+ [apa:cite:year]
+ [apa:cite]
+ [\c!separator:2={,\space}, % :0 and :1 - between items of a list
+ \c!separator:3={,\space\btxlabeltext{apa:and}\space}, % not \textampersand
+ \c!separator:4={\space\btxlabeltext{apa:and}\space}, % not \textampersand
+ \c!compress=\v!yes,
+ \c!sorttype=\v!default]
+
+\definebtx
+ [apa:cite:title]
+ [apa:cite]
+ [\c!separator:2={,\space}, % :0 and :1 - between items of a list
+ \c!separator:3={,\space\btxlabeltext{apa:and}\space}, % not \textampersand
+ \c!separator:4={\space\btxlabeltext{apa:and}\space}, % not \textampersand
+ \c!command={\language[\currentbtxlanguage]}, % BAH
+ \c!style=\v!italic]
+
+\definebtx
+ [apa:cite:booktitle]
+ [apa:cite:title]
+
+\definebtx
+ [apa:cite:tag]
+ [apa:cite]
+ [\c!left={\removeunwantedspaces\pushpunctuation\btxspace[},
+ \c!right={]\poppunctuation}]
+
+\definebtx
+ [apa:cite:key]
+ [apa:cite:tag]
+
+\definebtx
+ [apa:cite:serial]
+ [apa:cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [apa:cite:page]
+ [apa:cite]
+ [\c!left=,
+ \c!right=,
+ [\c!separator:2={,\space}, % :0 and :1 - between items of a list
+ \c!separator:3={,\space\btxlabeltext{apa:and}\space}, % not \textampersand
+ \c!separator:4={\space\btxlabeltext{apa:and}\space}] % not \textampersand
+
+\definebtx
+ [apa:cite:pages]
+ [apa:cite:page]
+
+\definebtx
+ [apa:cite:keywords]
+ [apa:cite]
+ [\c!left={(},
+ \c!right={)}]
+
+\definebtx
+ [apa:cite:invertedshort]
+ [apa:cite]
+
+\definebtx
+ [apa:cite:short]
+ [apa:cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [apa:cite:category]
+ [apa:cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [apa:cite:type]
+ [apa:cite:category]
+
+\definebtx
+ [apa:cite:url]
+ [apa:cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [apa:cite:doi]
+ [apa:cite:url]
+
+\definebtx
+ [apa:cite:num]
+ [apa:cite]
+ [\c!compress=\v!yes,
+ \c!left={[},
+ \c!right={]},
+ \c!separator:2={,}, % no space
+ \c!separator:3=\btxparameter{\c!separator:2},
+ \c!separator:4=\btxparameter{\c!separator:2}]
+
+\definebtx
+ [apa:cite:textnum]
+ [apa:cite:num]
+ [\c!left={Ref.\nbsp},
+ \c!right=,
+ \c!separator:2={,\space},
+ \c!separator:3={\space\btxlabeltext{apa:and}\space},
+ \c!separator:4={\space\btxlabeltext{apa:and}\space}]
+
+\definebtx
+ [apa:cite:entry]
+ [apa:cite]
+ [\c!left=,
+ \c!right=,
+ \c!inbetween={\space},
+ \c!separator:2={;\space},
+ \c!separator:3=\btxparameter{\c!separator:2},
+ \c!separator:4=\btxparameter{\c!separator:2}]
+
+% Now we setup for the details of the renderings
+
+%D Sometimes we have verbose injections in an entry and these can be language
+%D dependent, so we use labels.
+%D
+%D Because we want to mix rendering (in the manual) we need a namespace in label
+%D texts:
+
+\setupbtxlabeltext
+ [en]
+ [apa:and=and,
+ apa:number={no.},
+ apa:edition={ed.},
+ apa:Editor={Ed.},
+ apa:Editors={Eds.},
+ apa:Volume={Vol.},
+ apa:Volumes={Vols.},
+ apa:others={et al.},
+ apa:page={p.},
+ apa:pages={pp.},
+ apa:nd={n.d.}, % no date
+ apa:mastersthesis={Master's thesis},
+ apa:phdthesis={Doctoral dissertation},
+ apa:technicalreport={Tech. Rep.}, % Technical report
+ apa:supplement={Suppl.}, % Supplement (not used?)
+ apa:patent=Patent,
+ apa:MotionPicture={Motion picture},
+ apa:Producer=Producer,
+ apa:Producers=Producers,
+ apa:Director=Director,
+ apa:Directors=Directors,
+ apa:Recordedby={Recorded by},
+ apa:Author=Author,
+ apa:Translator={Trans.}, % Translator(s) (not used?)
+ apa:Advanced={Advanced online publication},
+ apa:Retrieved={Available from}, % {Retrieved from},
+ apa:In=In]
+
+\setupbtxlabeltext
+ [nl]
+ [apa:and=en,
+ apa:number={nr.},
+ apa:edition={ed.}, % editie
+ apa:Editor=Editor, % Ed./Eds.
+ apa:Editors=Editors,
+ apa:Volume={Vol.},
+ apa:Volumes={Vols.},
+ apa:others={et al.},
+ apa:page={p.},
+ apa:pages={pp.},
+ apa:nd={g.d.} % geen datum
+ apa:mastersthesis=Masterproef,
+ apa:phdthesis=Proefschrift,
+ apa:technicalreport={Technisch rapport}, % Technical report
+ apa:supplement=Supplement,
+ apa:patent=Octrooi,
+ apa:MotionPicture=Film, % ?
+ apa:Producer=Producent, % ?
+ apa:Producers=Producents, % ?
+ apa:Director=Directeur,
+ apa:Directors=Directeurs,
+ apa:Recordedby={Opgenomen door}, % ?
+ apa:Author=Auteur,
+ apa:Translator=Vertaler,
+ apa:Advanced={Geavanceerde online publicatie},
+ apa:Retrieved={Beschikbaar vanaf}, % {Ontvangen van},
+ apa:In=In]
+
+\setupbtxlabeltext
+ [fr]
+ [apa:and=et,
+ apa:others={et al.},
+ apa:number={n\high{o}},
+ apa:edition={édition},
+ apa:Editor=Éditeur,
+ apa:Editors=Éditeurs,
+ apa:Volume=Volume,
+ apa:Volumes=Volumes,
+ apa:others={et al.},
+ apa:page={p.},
+ apa:pages={pp.},
+ apa:nd={s.d.} % sans date
+ apa:mastersthesis={Thèse de master (DEA, DESS, master)},
+ apa:phdthesis={Thèse de doctorat},
+ apa:technicalreport={Rapport technique},
+ apa:supplement=Supplément,
+ apa:patent=Brevet,
+ apa:MotionPicture={Film cinématographique},
+ apa:Producer=Producteur,
+ apa:Producers=Producteurs,
+ apa:Director=Réalisateur,
+ apa:Directors=Réalisateurs,
+ apa:Recordedby={Enregistré par},
+ apa:Author=Auteur,
+ apa:Translator=Traducteur,
+ apa:Advanced={Publication en ligne anticipée},
+ apa:Retrieved={Disponible à}, % {Téléchargé de},
+ apa:In=Dans]
+
+\setupbtxlabeltext
+ [de]
+ [apa:and=und,
+ apa:number={nr.},
+ apa:edition=Auf\/lage,
+ apa:Editor=Herausgeber, % Hrsg./Hg.
+ apa:Editors=Herausgeber,
+ apa:Volume=Band, % Bd.
+ apa:Volumes={Bände},
+ apa:others={et al.},
+ apa:page={S.},
+ apa:pages={S.},
+ apa:nd={o.D.}, % ohne Datum (mostly: o.J. / ohne Jahr)
+ apa:mastersthesis={Masterarbeit},
+ apa:phdthesis={Dissertation},
+ apa:technicalreport={Technischer Bericht},
+ apa:supplement={Beilage}, % Supplement
+ apa:patent=Patent,
+ apa:MotionPicture=Kinofilm, % ?
+ apa:Producer=Producer, % ?
+ apa:Producers=Produzenten, % ?
+ apa:Director=Director, % ?
+ apa:Directors=Directors, % ?
+ apa:Recordedby={per Einschreiben}, % ?
+ apa:Author=Autor,
+ apa:Translator={Übersetzer}, % Übers.
+ apa:Advanced={Erweiterte Online-Publikation},
+ apa:Retrieved={heruntergeladen von},
+ apa:In=In]
+
+% thanks: Andrea Valle
+
+\setupbtxlabeltext
+ [it]
+ [apa:and=e,
+ apa:number={nº},
+ apa:edition={ed.}, % edizione
+ apa:Editor={A cura di},
+ apa:Editors={A cura di},
+ apa:Volume={Vol.}, % Volume
+ apa:Volumes={Vol.}, % Volumi
+ apa:others={et al.},
+ apa:page={p.},
+ apa:pages={pp.},
+ apa:nd={s.d.}, % senza data
+ apa:mastersthesis={Tesi di laurea},
+ apa:phdthesis={Tesi di dottorato},
+ apa:technicalreport={Relazione tecnica},
+ apa:supplement={Supplemento},
+ apa:patent=Brevetto,
+ apa:MotionPicture=Film, % ?
+ apa:Producer=Produttore,
+ apa:Producers=Produttori,
+ apa:Director=Direttore,
+ apa:Directors=Direttori,
+ apa:Recordedby={Registrato da},
+ apa:Author=Autore,
+ apa:Translator={Trad.}, % Translator(s)
+ apa:Advanced={Pre-pubblicazione on line},
+ apa:Retrieved={Accessible online},
+ apa:In=In]
+
+\setupbtxlabeltext
+ [es]
+ [apa:and=y,
+ apa:number={nº},
+ apa:edition={ed.}, % edición
+ apa:Editor=Editor, % Ed./Eds.
+ apa:Editors=Editores,
+ apa:Volume={Vol.}, % Volumen
+ apa:Volumes={Vols.}, % Volúmenes
+ apa:others={et al.},
+ apa:page={p.},
+ apa:pages={pp.},
+ apa:nd={s.f.}, % sin fecha
+ apa:mastersthesis={Tesis de maestría},
+ apa:phdthesis={Tesis doctoral},
+ apa:technicalreport={Informe técnico},
+ apa:supplement=Suplemento,
+ apa:patent=Patente,
+ apa:MotionPicture=Cinematográfica,
+ apa:Producer=Productor,
+ apa:Producers=Productores,
+ apa:Director=Director,
+ apa:Directors=Directores,
+ apa:Recordedby={Grabada por},
+ apa:Author=Autor,
+ apa:Translator=Traductor,
+ apa:Advanced={Publicación en línea avanzada},
+ apa:Retrieved={Disponible desde}, % {Obtenido de},
+ apa:In=En]
+
+% cite setups
+
+% The following differs from the default returning n.d. if year is empty
+
+\startsetups btx:apa:cite:author:year
+ \texdefinition{\s!btx:\s!cite:concat}
+ \btxparameter\c!left
+ \ifx\currentbtxfirst\empty
+ \btxlabeltext{apa:nd}
+ \else
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \btxcitereference
+ \currentbtxfirst
+ }
+ \ifx\currentbtxsecond\empty \else
+ \btxparameter\v!inbetween
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \currentbtxsecond
+ }
+ \fi
+ \ifx\currentbtxthird\empty \else
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \currentbtxthird
+ }
+ \fi
+ \fi
+ \btxparameter\c!right
+\stopsetups
+
+\startsetups btx:apa:cite:author:years
+ \fastsetup{btx:apa:cite:author:year}
+\stopsetups
+
+% The following differs from the default by including the labels p. and pp.
+
+\startsetups btx:apa:page:list
+ \fastsetup{\s!btx:\s!page:concat}
+ \ifx\currentbtxlastpage\empty
+ \btxlabeltext{apa:page}
+ \else
+ \btxlabeltext{apa:pages}
+ \fi
+ \btxnbsp
+ \ifconditional\btxinteractive
+ \goto {
+ \currentbtxfirstpage
+ } [
+ internal(\currentbtxfirstinternal)
+ ]
+ \ifx\currentbtxlastpage\empty \else
+ \btxparameter\c!pageconnector
+ \goto {
+ \currentbtxlastpage
+ } [
+ internal(\currentbtxlastinternal)
+ ]
+ \fi
+ \else
+ \currentbtxfirstpage
+ \ifx\currentbtxlastpage\empty \else
+ \btxparameter\c!pageconnector
+ \currentbtxlastpage
+ \fi
+ \fi
+\stopsetups
+
+% The sameauthor feature may not be APA compliant
+% (there is nothing in the manual cited above).
+% It can be removed using the command:
+% \resetsetups [apa:list:sameauthor]
+
+% :rule, :empty or :ditto ...
+
+\startsetups apa:list:sameauthor
+ \fastsetup{apa:list:sameauthor:rule}
+\stopsetups
+
+\startsetups apa:list:sameauthor:rule
+ \blackrule
+ [\c!width=\dimexpr\listparameter\c!margin-\interwordspace\relax,
+ \c!height=1.5\linewidth]% \linewidth is just too thin with respect to font strokes...
+\stopsetups
+
+
+\startsetups [apa:list:sameauthor:\v!empty]
+ \kern\dimexpr\listparameter\c!margin-\interwordspace\relax
+\stopsetups
+
+% horrible !
+
+\startsetups apa:list:sameauthor:ditto
+ \inframed
+ [\c!width=\dimexpr\listparameter\c!margin-\interwordspace\relax,
+ \c!frame=\v!off,
+ \c!align=\v!middle]
+ {\doubleprime}
+\stopsetups
+
+%D Instead of texdefinitions without arguments, we could have used setups but in my
+%D editor (hh, scite) the commands stand out better. It also saves an additional
+%D component in the name (e.g. common:) because commands and setups have a different
+%D namespace, so similar calls don't clash. Performance of definitions is somewhat
+%D better.
+
+%D We use "texdefinitions" (with eventual arguments) for helpers that are used
+%D in the rendering "setups" defined for each category below.
+
+%D Note that \btxdoif... and \btxflush rely on the definitions in
+%D publ-imp-apa.lua: fields that are not listed as required nor optional are
+%D IGNORED. We also make heavy use of the notion of sets - comma-separated lists
+%D of alternative fields to be used in hierarchal order. For example:
+%D author = { "author", "editor", "publisher", "title" }, will return the
+%D author field if it exists; if not, the editor field will be returned, if it
+%D exists; if not, the publisher field will be returned, if it exists; if not,
+%D the title field will be returned, it it exists; if not, nothing will be
+%D returned. In lua syntax, it can be understood as
+%D author or editor or publisher or title or ""
+
+% #title can be title or booktitle
+
+\starttexdefinition btx:apa:translated-title #title
+ \ifx\currentbtxlanguage\empty
+ % no need for an extra
+ \else\ifx\mainbtxlanguage\currentbtxlanguage
+ % no need for an extra
+ \else
+ \btxdoif {#title:\mainbtxlanguage} {
+ \begingroup
+ \language[\mainbtxlanguage]
+ \btxleftbracket
+ \btxusecommand[apa:list:title:\currentbtxcategory] {
+ \btxflush{#title:\mainbtxlanguage}
+ }
+ \btxrightbracket
+ \endgroup
+ }
+ \fi\fi
+\stoptexdefinition
+
+\starttexdefinition btx:apa:composed-title #title
+ \begingroup
+ \language[\currentbtxlanguage]
+ \btxusecommand[apa:list:title:\currentbtxcategory] {
+ \btxflush{#title}
+ \btxdoif {sub#title} {
+ \btxcolon
+ \btxflush{sub#title}
+ }
+ }
+ \endgroup
+ \doif{\btxparameter{translate}}\v!yes {
+ \texdefinition{btx:apa:translated-title}{#title}
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:apa:title
+ \setmode{btx:apa:title-placed}
+ % we make the title active, opening "file"
+ \btxdoifelse {file} {
+ \texdefinition{btx:format:inject}
+ {url(file:\btxflush{file})}
+ {
+ \btxstartstyleandcolor [apa:list:title:\currentbtxcategory]
+ \texdefinition{btx:apa:composed-title}{title}
+ \btxstopstyleandcolor
+ }
+ } {
+ \btxstartstyleandcolor [apa:list:title:\currentbtxcategory]
+ \texdefinition{btx:apa:composed-title}{title}
+ \btxstopstyleandcolor
+ }
+ \btxdoif {title} {
+ \btxperiod
+ % TODO: this period may NOT be wanted, as in: Title (2nd ed.).
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:apa:title-if-not-placed
+ \doifelsemode {btx:apa:title-placed} {
+ \resetmode{btx:apa:title-placed}
+ } {
+ \btxdoif {title} {
+ \btxspace
+ \texdefinition {btx:apa:title}
+ }
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:apa:suffixedyear
+ \btxdoifelse {year} {
+ \btxflush{year}
+ \btxflush{suffix}
+ %or \btxflush{suffixedyear}
+ } {
+ \btxlabeltext{apa:nd}
+ }
+\stoptexdefinition
+
+% #author may be author(set) or editor
+
+\starttexdefinition btx:apa:author-or-editor #author
+ \btxdoif {#author} {
+ \btxflush{#author}
+ \doif {\btxfoundname{#author}} {editor} {
+ \btxleftparenthesis
+ \btxsingularorplural {editor} {
+ \btxlabeltext{apa:Editor}
+ } {
+ \btxlabeltext{apa:Editors}
+ }
+ \btxrightparenthesisperiod
+ }
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:apa:authoryear
+ % we make the authoryear active, pointing to the citation
+ \texdefinition{btx:format:inject}
+ {internal(\currentbtxinternal)}
+ {
+ \doifelsesetups{apa:list:sameauthor} {
+ \btxdoifelsesameasprevious {author} {
+ \fastsetup{apa:list:sameauthor}
+ } {
+ \texdefinition{btx:apa:author-or-editor} {author}
+ }
+ } {
+ \texdefinition{btx:apa:author-or-editor} {author}
+ }
+ \btxleftparenthesis
+ \texdefinition{btx:apa:suffixedyear}
+ \btxrightparenthesis
+ }
+ % outside of interaction
+ \btxperiod
+ \doif {\btxfoundname{author}} {title} {
+ \setmode{btx:apa:title-placed}
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:apa:editor-in
+ \btxdoif {booktitle} {
+ \btxlabeltext{apa:In}
+ \doifnot {\btxfoundname{author}} {editor} {
+ \btxspace
+ \texdefinition{btx:apa:author-or-editor} {editor}
+ }
+ \btxspace
+ \btxstartstyleandcolor[apa:list:title]
+ \texdefinition{btx:apa:composed-title} {booktitle}
+ \btxstopstyleandcolor
+ \btxperiod
+ }
+\stoptexdefinition
+
+% TODO: The title is terminated with period. However,
+% we probably don't want this before the parenthesis.
+
+\starttexdefinition btx:apa:leftparenthesis-or-comma
+ \doifelsemode {btx:apa:editionset-is-empty} {
+ \btxleftparenthesis
+ \resetmode{btx:apa:editionset-is-empty}
+ } {
+ \btxcomma
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:apa:editionset
+ \setmode{btx:apa:editionset-is-empty}
+ \doif {\currentbtxcategory} {techreport} {
+ \texdefinition{btx:apa:leftparenthesis-or-comma}
+ \btxdoifelse {type} {
+ \btxusecommand[apa:list:type] {
+ \btxflush{type}
+ }
+ } {
+ \btxlabeltext{apa:technicalreport}
+ }
+ }
+ \btxdoif {volume} {
+ \texdefinition{btx:apa:leftparenthesis-or-comma}
+ \btxoneorrange {volume} {
+ \btxlabeltext{apa:Volume}
+ } {
+ \btxlabeltext{apa:Volumes}
+ }
+ \btxspace
+ \btxflush{volume}
+ }
+ \btxdoif {number} {
+ \texdefinition{btx:apa:leftparenthesis-or-comma}
+ \btxlabeltext{apa:number}
+ \btxspace
+ \btxflush{number}
+ }
+ \btxdoif {edition} {
+ \texdefinition{btx:apa:leftparenthesis-or-comma}
+ \btxflush{edition}
+ \btxspace
+ \btxlabeltext{apa:edition}
+ }
+ \btxdoif {pages} {
+ \texdefinition{btx:apa:leftparenthesis-or-comma}
+ \btxoneorrange {pages} {
+ \btxlabeltext{apa:page}
+ } {
+ \btxlabeltext{apa:pages}
+ }
+ \btxnbsp
+ \btxflush{pages}
+ }
+ \doifnotmode {btx:apa:editionset-is-empty} {
+ \btxrightparenthesisperiod
+ }
+\stoptexdefinition
+
+ % this could be simplified!
+
+\starttexdefinition btx:apa:journal-volume-number-pages
+ \btxdoif {journal} {
+ \btxspace
+ \btxstartstyleandcolor[apa:list:journal]
+ \btxusecommand[apa:list:journal] {
+ \btxflush{journal}
+ }
+ \btxdoifelse {volume} {
+ \btxcomma
+ \btxflush{volume}
+ \btxstopstyleandcolor
+ \btxdoif {number} {
+ %\btxleftparenthesis
+ (\btxflush{number}
+ \btxrightparenthesis
+ }
+ } {
+ \btxstopstyleandcolor
+ \btxdoif {number} {
+ \btxcomma
+ \btxleftparenthesis
+ \btxflush{number}
+ \btxrightparenthesis
+ }
+ }
+ \btxdoif {pages} {
+ \btxcomma
+ \doif {\currentbtxcategory} {newspaper} {
+ \btxoneorrange {pages} {
+ \btxlabeltext{apa:page}
+ } {
+ \btxlabeltext{apa:pages}
+ }
+ \btxnbsp
+ }
+ \btxflush{pages}
+ }
+ \btxperiod
+ \doifnot {\currentbtxcategory} {newspaper} {
+ \btxdoifnot {volume} {
+ \btxdoifnot {number} {
+ \btxdoifnot {pages} {
+ \btxdoif {doi} {%set: doi or url
+ \btxspace
+ \btxlabeltext{apa:Advanced}
+ \btxperiod
+ }
+ }
+ }
+ }
+ }
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:apa:wherefrom-publisher
+ \btxdoifelse {address} {
+ \btxflush{address}
+ \btxdoif {country} {
+ \btxcomma
+ \btxflush{country}
+ }
+ \btxcolon
+ } {
+ \btxdoif {country} {
+ \btxflush{country}
+ \btxcolon
+ }
+ }
+ \doifelse {\btxfoundname{author}} {\btxfoundname{publisher}} {
+ \btxlabeltext{apa:Author}
+ } {
+ \btxdoifelse {publisher} {
+ \btxflush{publisher}
+ } {
+ \btxlabeltext{apa:Author}
+ }
+ }
+ \btxperiod
+\stoptexdefinition
+
+\definebreakpoints[doi]
+\definebreakpoint [doi][:][nleft=3,type=1]
+\definebreakpoint [doi][/][nleft=3,type=1]
+\definebreakpoint [doi][-][nleft=3,type=1]
+\definebreakpoint [doi][.][nleft=3,type=1]
+
+% use \btxentry here?
+
+\starttexdefinition btx:apa:url
+ \btxspace
+ \btxlabeltext{apa:Retrieved}
+ \btxspace
+ \begingroup
+ \setbreakpoints[doi]
+ \ifconditional\btxinteractive
+ \goto {
+ \hyphenatedurl{\btxflush{url}}
+ } [
+ url(\btxflush{url})
+ ]
+ \else
+ \hyphenatedurl{\btxflush{url}}
+ \fi
+ \endgroup
+\stoptexdefinition
+
+% use \btxentry here?
+
+\starttexdefinition btx:apa:doi
+ \btxspace
+ \begingroup
+ \setbreakpoints[doi]
+ \ifconditional\btxinteractive
+ \goto {
+ \hyphenatedurl{doi:\btxflush{doi}}
+ } [
+ url(http://dx.doi.org/\btxflush{doi})
+ ]
+ \else
+ \hyphenatedurl{doi:\btxflush{doi}}
+ \fi
+ \endgroup
+\stoptexdefinition
+
+\starttexdefinition btx:apa:note
+ \btxdoif {note} {
+ \btxleftparenthesis
+ \btxflush{note}
+ \btxrightparenthesis
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:apa:url-doi-note
+ \doif {\btxfoundname{doi}} {url} {
+ \texdefinition{btx:apa:url}
+ }
+ \doif {\btxfoundname{doi}} {doi} {
+ \texdefinition{btx:apa:doi}
+ }
+ \texdefinition{btx:apa:note}
+ \removeunwantedspaces
+\stoptexdefinition
+
+% Then setups, by category
+
+% An article from a journal
+% Required fields: author or editor or title, journal, (year).
+% Optional fields: volume, number, pages, type, doi, url, note.
+% Note that bibtex (and tools) do not include editor (e.g. special issue or section)
+
+\startsetups btx:apa:list:article
+ \texdefinition{btx:apa:authoryear}
+ \texdefinition{btx:apa:title-if-not-placed}
+ \texdefinition{btx:apa:journal-volume-number-pages}
+ \texdefinition{btx:apa:url-doi-note}
+\stopsetups
+
+% An article from a magazine.
+% Required fields: author or title, journal, (year).
+% Optional fields: number, pages, type, month, day, doi, url, note.
+
+\startsetups btx:apa:list:magazine
+ \fastsetup{btx:apa:list:article}
+\stopsetups
+
+% An article from a newspaper.
+% Required fields: author or title, journal, (year).
+% Optional fields: volume, number, pages, type, month, day, doi, url, note.
+
+\startsetups btx:apa:list:newspaper
+ \fastsetup{btx:apa:list:article}
+\stopsetups
+
+% A complete issue of a periodical, such as a special issue of a journal.
+% Required fields: title, year
+% Optional fields: editor, publisher, subtitle, series, volume, number, month, organization, doi, url, issn, note
+
+% needs to be tuned...
+
+\startsetups btx:apa:list:periodical
+ \fastsetup{btx:apa:list:article}
+\stopsetups
+
+% National and international standards issued by a standards body
+% Required fields: author, institution, or organization, year, title
+% Optional fields: subtitle, doi, url, note
+
+\startsetups btx:apa:list:standard
+ \texdefinition{btx:apa:authoryear}
+ \texdefinition{btx:apa:title-if-not-placed}
+ \texdefinition{btx:apa:url-doi-note}
+\stopsetups
+
+% A book with an explicit publisher.
+% Required fields: author or editor or publisher, title, (year).
+% Optional fields: volume or number, series, address, edition, month, day, note.
+% APA ignores: month, day
+
+% todo: series?
+
+\startsetups btx:apa:list:book
+ \texdefinition{btx:apa:authoryear}
+ \texdefinition{btx:apa:title-if-not-placed}
+ \texdefinition{btx:apa:editionset}
+ \texdefinition{btx:apa:wherefrom-publisher}
+ \texdefinition{btx:apa:url-doi-note}
+\stopsetups
+
+% There is some debate about how inbook should differ from incollection
+
+% A part of a book, which may be a chapter (or section or whatever) and/or a range of pages.
+% (note that inbook is handled differently by bibtex and biblatex)
+% Required fields: author or editor, title, chapter and/or pages, publisher, year.
+% Optional fields: volume or number, series, type, address, edition, month, note.
+% We add optional: booktitle.
+% APA ignores: chapter, month
+
+\startsetups btx:apa:list:inbook
+ \texdefinition{btx:apa:authoryear}
+ \texdefinition{btx:apa:title-if-not-placed}
+ \texdefinition{btx:apa:editor-in}
+ \texdefinition{btx:apa:editionset}
+ \texdefinition{btx:apa:wherefrom-publisher}
+ \texdefinition{btx:apa:url-doi-note}
+\stopsetups
+
+% A part of a book having its own title.
+% Required fields: author, title, booktitle, publisher, year.
+% Optional fields: editor, volume or number, series, type, chapter, pages, address, edition, month, note.
+% APA ignores: chapter, month
+
+\startsetups btx:apa:list:incollection
+ \fastsetup{btx:apa:list:inbook}
+\stopsetups
+
+% The proceedings of a conference.
+% Required fields: title, year.
+% Optional fields: editor, volume or number, series, address, month, organization, publisher, note.
+% todo: series?
+
+\startsetups btx:apa:list:proceedings
+ \fastsetup{btx:apa:list:book}
+\stopsetups
+
+% An article in a conference proceedings.
+% Required fields: author, title, booktitle, year.
+% Optional fields: editor, volume or number, series, pages, address, month, organization, publisher, note.
+
+\startsetups btx:apa:list:inproceedings
+ \texdefinition{btx:apa:authoryear}
+ \texdefinition{btx:apa:title-if-not-placed}
+ \texdefinition{btx:apa:editor-in}
+ \texdefinition{btx:apa:editionset}
+ \btxdoif {organization} {
+ \btxspace
+ \btxflush{organization}
+ \btxcomma
+ }
+ \texdefinition{btx:apa:wherefrom-publisher}
+ \texdefinition{btx:apa:url-doi-note}
+\stopsetups
+
+\startsetups btx:apa:list:conference
+ \fastsetup{btx:apa:list:inproceedings}
+\stopsetups
+
+% A thesis.
+% Required fields: author, title, school, year.
+% Optional fields: type, address, month, note.
+
+\startsetups btx:apa:list:thesis
+ \texdefinition{btx:apa:authoryear}
+ \texdefinition{btx:apa:title-if-not-placed}
+ \btxleftparenthesis
+ \btxdoifelse {type} {
+ \btxusecommand[apa:list:type] {
+ \btxflush{type}
+ }
+ } {
+ \btxlabeltext{apa:\currentbtxcategory}
+ }
+ \btxrightparenthesis
+ \btxdoif {school} {
+ \btxperiod
+ \btxflush{school}
+ }
+ \btxdoif {address} {
+ \btxdoifelse {school} {
+ \btxcomma
+ } {
+ \btxperiod
+ }
+ \btxflush{address}
+ \btxdoif {country} {
+ \btxcomma
+ \btxflush{country}
+ }
+ }
+ \btxperiod
+ \texdefinition{btx:apa:url-doi-note}
+\stopsetups
+
+\startsetups btx:apa:list:phdthesis
+ \fastsetup{btx:apa:list:thesis}
+\stopsetups
+
+\startsetups btx:apa:list:mastersthesis
+ \fastsetup{btx:apa:list:thesis}
+\stopsetups
+
+% A work that is printed and bound, but without a named publisher or sponsoring institution.
+% Required field: title.
+% Optional fields: author, howpublished, address, month, year, note.
+
+\startsetups btx:apa:list:booklet
+ \fastsetup{btx:apa:list:book}
+\stopsetups
+
+% Technical documentation.
+% Required field: title.
+% Optional fields: author, organization, address, edition, month, year, note.
+
+\startsetups btx:apa:list:manual
+ \fastsetup{btx:apa:list:book}
+\stopsetups
+
+% A report published by a school or other institution, usually numbered within a series.
+% Required fields: author, title, institution, year.
+% Optional fields: type, number, address, month, note.
+
+\startsetups btx:apa:list:techreport
+ \fastsetup{btx:apa:list:book}
+\stopsetups
+
+% A document having an author and title, but not formally published.
+% Required fields: author, title, note.
+% Optional fields: month, year.
+
+\startsetups btx:apa:list:unpublished
+ \fastsetup{btx:apa:list:book}
+\stopsetups
+
+% A patent. Note that this category was not defined with BIBTEX. Below from JabRef:
+% Required fields: nationality, number, year, yearfiled
+% Optional fields: author, title, assignee, address, type, number, day, dayfiled, month, monthfiled, note, url
+% Also optional: publisher
+
+% todo: yearfiled, monthfiled, dayfiled
+
+\startsetups btx:apa:list:patent
+ \texdefinition{btx:apa:authoryear}
+ \texdefinition{btx:apa:title-if-not-placed}
+ \begingroup
+ \it
+ \btxdoif {nationality} {
+ \btxspace
+ \btxflush{nationality}
+ }
+ \btxspace
+ \btxlabeltext{apa:patent}
+ \btxdoif {number} {
+ \btxspace
+ \btxlabeltext{apa:number}
+ \btxspace
+ \btxflush{number}
+ }
+ \btxperiod
+ \italiccorrection
+ \endgroup
+ \texdefinition{btx:apa:wherefrom-publisher}
+ \texdefinition{btx:apa:url}
+ \texdefinition{btx:apa:note}
+\stopsetups
+
+% Electronic. Note that this category was not defined with BIBTEX. Below from JabRef:
+% Required fields: title
+% Optional fields: address, author, howpublished, month, note, organization, url, year, doi
+% Also optional: type
+
+% Like Misc below but includes organization.
+
+\startsetups btx:apa:list:electronic
+ \texdefinition{btx:apa:authoryear}
+ \texdefinition{btx:apa:title-if-not-placed}
+ \btxdoif {organization} {
+ \btxspace
+ \btxflush{organization}
+ \btxperiod
+ }
+ \btxdoif {howpublished} {
+ \btxspace
+ \btxflush{howpublished}
+ \btxperiod
+ }
+ \texdefinition{btx:apa:url-doi-note}
+\stopsetups
+
+% Film. Note that this category was not defined with BIBTEX.
+% Required fields: producer, director, title, year, address, publisher
+% Optional fields: subtitle, type, note, url, doi
+
+\startsetups btx:apa:list:film
+ \btxdoif {producer} {
+ \btxflush{producer}
+ \btxleftparenthesis
+ \btxsingularorplural {producer} {
+ \btxlabeltext{apa:Producer}
+ } {
+ \btxlabeltext{apa:Producers}
+ }
+ \btxrightparenthesis
+ \btxdoifelse {director} {
+ \removeunwantedspaces
+ \btxparameter{\c!separator:names:3}
+ } {
+ \btxperiod
+ }
+ }
+ \btxdoif {director} {
+ \btxflush{director}
+ \btxleftparenthesis
+ \btxsingularorplural {director} {
+ \btxlabeltext{apa:Director}
+ } {
+ \btxlabeltext{apa:Directors}
+ }
+ \btxrightparenthesisperiod
+ }
+ \btxleftparenthesis
+ \texdefinition{btx:apa:suffixedyear}
+ \btxrightparenthesisperiod
+ \texdefinition {btx:apa:title}
+ \btxleftbracket
+ \btxdoifelse {type} {
+ \btxflush{type}
+ } {
+ \btxlabeltext{apa:MotionPicture}
+ }
+ \btxrightbracketperiod
+ \texdefinition{btx:apa:wherefrom-publisher}
+ \texdefinition{btx:apa:url-doi-note}
+\stopsetups
+
+% Music. Note that this category was not defined with BIBTEX.
+% Required fields: composer, artist, title, album, year, address, publisher
+% Optional fields: subtitle, type, note, url, doi
+
+\startsetups btx:apa:list:music
+ \texdefinition{btx:apa:authoryear}
+ \texdefinition{btx:apa:title-if-not-placed}
+ \doifnot {\btxfoundname{author}} {artist} {
+ \btxdoif {artist} {
+ \btxleftbracket
+ \btxlabeltext{apa:Recordedby}
+ \btxspace
+ \btxflush{artist}
+ \btxrightbracketperiod
+ }
+ }
+ \doifnot {\btxfoundname{title}} {album} {
+ \btxdoif {album} {
+ \btxlabeltext{apa:In}
+ \btxspace
+ \btxflush{album}
+ \btxperiod
+ }
+ }
+ \btxdoif {type} {
+ \btxleftbracket
+ \btxflush{type}
+ \btxrightbracketperiod
+ }
+ \texdefinition{btx:apa:wherefrom-publisher}
+ \texdefinition{btx:apa:url-doi-note}
+\stopsetups
+
+% Other. Note that this category was not defined with BIBTEX. Below from JabRef:
+% Required fields: author or title, year
+% Optional fields: note, doi, url
+
+\startsetups btx:apa:list:other
+ \fastsetup{btx:apa:list:book}
+\stopsetups
+
+% Use this type when nothing else fits.
+% Required fields: none.
+% Optional fields: author, title, howpublished, month, year, note.
+
+\startsetups btx:apa:list:misc
+ \texdefinition{btx:apa:authoryear}
+ \texdefinition{btx:apa:title-if-not-placed}
+ \btxdoif {howpublished} {
+ \btxspace
+ \btxflush{howpublished}
+ \btxperiod
+ }
+ \texdefinition{btx:apa:url-doi-note}
+\stopsetups
+
+% If all else fails to match:
+
+\startsetups btx:apa:list:literal
+ %\btxleftparenthesis
+ \removeunwantedspaces(
+ \btxflush{key}
+ \btxrightparenthesis
+ \btxdoif {text} {
+ \btxflush{text}
+ }
+\stopsetups
+
+% HH: an example of setting up translations using a sub rendering. Keep it here
+% till we find another spot as otherwise I forget about it and I don't want to
+% waste hours reinventing a wheel when something like this is needed.
+%
+% \definebtx
+% [apa:cite:title:translated]
+% [apa:cite:title]
+% [left=\btxleftbracket,
+% right=\btxrightbracket,
+% style=\v!bolditalic]
+%
+% \startsetups btx:apa:cite:title
+% % need to add concat, etc.
+% \btxcitereference
+% \currentbtxfirst
+% \doifmode {btx:apa:translatedtitles} {
+% \ifx\currentbtxlanguage\empty
+% % no need for an extra
+% \else\ifx\mainbtxlanguage\currentbtxlanguage
+% % no need for an extra
+% \else
+% \btxdoif {title:\mainbtxlanguage} {
+% \btxstartciterendering[title:translated]
+% \language[\mainbtxlanguage]
+% \btxflush{title:\mainbtxlanguage}
+% \btxstopciterendering
+% }
+% \fi\fi
+% }
+% \stopsetups
+
+\stopbtxrenderingdefinitions
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-aps.lua b/Master/texmf-dist/tex/context/base/publ-imp-aps.lua
new file mode 100644
index 00000000000..1ec75d7d1df
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-aps.lua
@@ -0,0 +1,479 @@
+local specification = {
+ --
+ -- metadata
+ --
+ name = "aps",
+ version = "1.00",
+ comment = "APS specification",
+ author = "Alan Braslau and Hans Hagen",
+ copyright = "ConTeXt development team",
+ --
+ -- derived (combinations of) fields (all share the same default set)
+ --
+ virtual = {
+ "authoryear",
+ "authoryears",
+ "authornum",
+ "num",
+ "suffix",
+ },
+ --
+ -- special datatypes
+ --
+ types = {
+ --
+ -- list of fields that are interpreted as names: "NAME [and NAME]" where
+ -- NAME is one of the following:
+ --
+ -- First vons Last
+ -- vons Last, First
+ -- vons Last, Jrs, First
+ -- Vons, Last, Jrs, First
+ --
+ author = "author", -- interpreted as name(s)
+ editor = "author",
+ doi = "url", -- an external link
+ url = "url",
+ page = "pagenumber", -- number or range: f--t
+ pages = "pagenumber",
+ volume = "range",
+ number = "range",
+ keywords = "keyword", -- comma|-|separated list
+ year = "number",
+ },
+ --
+ -- categories with their specific fields
+ --
+ categories = {
+ --
+ -- categories are added below
+ --
+ },
+}
+
+local generic = {
+ --
+ -- A set returns the first field (in order of position below) that is found
+ -- present in an entry. A set having the same name as a field conditionally
+ -- allows the substitution of an alternate field.
+ --
+ -- note that anything can get assigned a doi or be available online.
+ editionset = { "edition", "volume", "number", "pages" },
+}
+
+-- Note that the APS specification allows an additional field "collaboration"
+-- to be rendered following the author list (if the collaboration name appears
+-- in the byline of the cited article).
+
+-- Definition of recognized categories and the fields that they contain.
+-- Required fields should be present; optional fields may also be rendered;
+-- all other fields will be ignored.
+
+-- Sets contain either/or in order of precedence.
+--
+-- For a category *not* defined here yet present in the dataset, *all* fields
+-- are taken as optional. This allows for flexibility in the addition of new
+-- categories.
+
+local categories = specification.categories
+
+-- an article from a journal
+
+categories.article = {
+ sets = {
+ author = { "author", "editor" },
+ },
+ required = {
+ "author",
+ },
+ optional = {
+ "collaboration",
+ "year",
+ "title", "subtitle", "type", "file",
+ "journal", "volume", "number", "pages",
+ "doi", "url", "note",
+ },
+}
+
+-- an article from a magazine
+
+categories.magazine = {
+ sets = categories.article.sets,
+ required = {
+ "author",
+ "year",
+ "journal",
+ },
+ optional = {
+ "collaboration",
+ "title", "subtitle", "type", "file",
+ "number", "pages",
+ "month", "day",
+ "doi", "url", "note",
+ },
+}
+
+categories.newspaper = categories.magazine
+
+-- (from jabref) to be identified and setup ...
+
+categories.periodical = {
+ sets = {
+ author = { "editor", "publisher" },
+ },
+ required = {
+ "title",
+ "year",
+ },
+ optional = {
+ "author",
+ "collaboration",
+ "subtitle", "file",
+ "series", "volume", "number", "month",
+ "organization",
+ "doi", "url", "note",
+ },
+}
+
+-- (from jabref) to be identified and setup ...
+
+categories.standard = {
+ sets = {
+ author = { "author", "institution", "organization" },
+ },
+ required = {
+ "author",
+ "year",
+ "title", "subtitle",
+ "doi", "note",
+ },
+ optional = {
+ "collaboration",
+ "url",
+ },
+}
+
+-- a book with an explicit publisher.
+
+categories.book = {
+ sets = {
+ author = { "author", "editor", "publisher" },
+ editionset = generic.editionset,
+ },
+ required = {
+ "author",
+ "title",
+ },
+ optional = {
+ "collaboration",
+ "year", "month", "day",
+ "title", "subtitle", "type", "file",
+ "editionset", "series",
+ "address",
+ "doi", "url", "note",
+ },
+}
+
+-- a part of a book, which may be a chapter (or section or whatever) and/or a range of pages.
+
+categories.inbook = {
+ sets = {
+ author = { "author", "editor", "publisher", },
+ editionset = generic.editionset,
+ },
+ required = {
+ "author",
+ "year" ,
+ "title",
+ },
+ optional = {
+ "collaboration",
+ "subtitle", "type", "file",
+ "booktitle",
+ -- "chapter",
+ "editionset", "series",
+ "month",
+ "address",
+ "doi", "url", "note",
+ },
+}
+
+-- a book having its own title as part of a collection.
+-- (like inbook, but we here make booktitle required)
+
+categories.incollection = {
+ sets = {
+ author = { "author", "editor", "publisher" },
+ editionset = generic.editionset,
+ },
+ required = {
+ "author",
+ "booktitle",
+ "year",
+ },
+ optional = {
+ "collaboration",
+ "title", "subtitle", "type", "file",
+ "editionset", "series",
+ "chapter",
+ "month",
+ "address",
+ "doi", "url", "note",
+ },
+}
+
+-- a work that is printed and bound, but without a named publisher or sponsoring institution.
+
+categories.booklet = {
+ sets = {
+ publisher = { "howpublished" }, -- no "publisher"!
+ },
+ required = {
+ "author",
+ "title",
+ },
+ optional = {
+ "publisher",
+ "collaboration",
+ "year", "month",
+ "subtitle", "type", "file",
+ "address",
+ "doi", "url", "note",
+ },
+}
+
+-- the proceedings of a conference.
+
+categories.proceedings = {
+ sets = {
+ author = { "editor", "organization", "publisher" }, -- no "author"!
+ publisher = { "publisher", "organization" },
+ editionset = generic.editionset,
+ },
+ required = {
+ "author",
+ "year"
+ },
+ optional = {
+ "collaboration",
+ "publisher",
+ "title", "subtitle", "file",
+ "editionset", "series",
+ "month",
+ "address",
+ "doi", "url", "note",
+ },
+}
+
+-- an article in a conference proceedings.
+
+categories.inproceedings = {
+ sets = categories.incollection.sets,
+ required = categories.incollection.required,
+ optional = {
+ "collaboration",
+ "title", "subtitle", "type", "file",
+ "month",
+ "edition", "series",
+ "address", "organization",
+ "doi", "url", "note",
+ },
+}
+
+categories.conference = categories.inproceedings
+
+-- a thesis (of course).
+
+categories.thesis = {
+ required = {
+ "author",
+ "title",
+ "school",
+ "year",
+ "type"
+ },
+ optional = {
+ "collaboration",
+ "subtitle", "file",
+ "month",
+ "address",
+ "doi", "url", "note",
+ },
+}
+
+categories.mastersthesis = {
+ sets = categories.thesis.sets,
+ required = {
+ "author",
+ "title",
+ "school",
+ "year"
+ },
+ optional = {
+ "collaboration",
+ "type",
+ "subtitle", "file",
+ "month",
+ "address",
+ "doi", "url", "note",
+ },
+}
+categories.phdthesis = categories.mastersthesis
+
+-- a report published by a school or other institution, usually numbered within a series.
+
+categories.techreport = {
+ sets = {
+ author = { "author", "institution", "publisher" },
+ publisher = { "publisher", "institution", },
+ editionset = { "type", "volume", "number", "pages" }, -- no "edition"!
+ },
+ required = {
+ "author",
+ "title",
+ "institution",
+ "year"
+ },
+ optional = {
+ "collaboration",
+ "publisher",
+ "address",
+ "subtitle", "file",
+ "editionset",
+ "month",
+ "doi", "url", "note",
+ },
+}
+
+-- technical documentation.
+
+categories.manual = {
+ sets = {
+ author = { "author", "organization", "publisher" },
+ publisher = { "publisher", "organization", },
+ editionset = generic.editionset,
+ },
+ required = {
+ "title"
+ },
+ optional = {
+ "author", "publisher",
+ "collaboration",
+ "address",
+ "subtitle", "file",
+ "editionset", "month", "year",
+ "doi", "url", "note",
+ },
+}
+
+-- a patent (of course).
+
+categories.patent = {
+ sets = {
+ author = { "author", "assignee", },
+ publisher = { "publisher", "assignee", },
+ year = { "year", "yearfiled", },
+ month = { "month", "monthfiled", },
+ day = { "day", "dayfiled", },
+ },
+ required = {
+ "nationality",
+ "number",
+ "year",
+ },
+ optional = {
+ "type",
+ --check this: "language",
+ "author", "publisher",
+ "collaboration",
+ "title", "subtitle", "file",
+ "address",
+ "day", "month",
+ "doi", "url", "note",
+ },
+}
+
+-- a document having an author and title, but not formally published.
+
+categories.unpublished = {
+ required = {
+ "author",
+ "title",
+ "note"
+ },
+ optional = {
+ "collaboration",
+ "subtitle", "file",
+ "year", "month",
+ "doi", "url",
+ },
+}
+
+-- like misc below but includes organization.
+
+categories.electronic = {
+ required = {
+ "title"
+ },
+ optional = {
+ "subtitle", "type", "file",
+ "year", "month",
+ "author",
+ "collaboration",
+ "address",
+ "organization",
+ "howpublished",
+ "doi", "url", "note",
+ },
+}
+
+-- use this type when nothing else fits.
+
+categories.misc = {
+ required = {
+ -- nothing is really important here
+ },
+ optional = {
+ "author",
+ "collaboration",
+ "title", "subtitle", "file",
+ "year", "month",
+ "howpublished",
+ "doi", "url", "note",
+ },
+}
+
+-- other (whatever jabref does not know!)
+
+categories.other = {
+ required = {
+ "author",
+ "title",
+ "year"
+ },
+ optional = {
+ "collaboration",
+ "subtitle", "file",
+ "doi", "url", "note",
+ },
+}
+
+-- if all else fails to match:
+
+categories.literal = {
+ sets = {
+ author = { "key" }, -- need to check this!
+ },
+ required = {
+ "text"
+ },
+ optional = {
+ "author",
+ "doi", "url", "note"
+ },
+ virtual = false,
+}
+
+-- done
+
+return specification
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-aps.mkvi b/Master/texmf-dist/tex/context/base/publ-imp-aps.mkvi
new file mode 100644
index 00000000000..3bc2a1d2184
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-aps.mkvi
@@ -0,0 +1,1156 @@
+%D \module
+%D [ file=publ-imp-aps,
+%D version=2015.03.22,
+%D title=APS bibliography style,
+%D subtitle=Publications,
+%D author=Alan Braslau and Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is therefore copyrighted
+%D by \PRAGMA. See mreadme.pdf for details.
+
+\startbtxrenderingdefinitions[aps]
+
+%D Reference:
+%D \startTEX
+%D @Book{APS2011,
+%D title ={Physical Review Style and Notation Guide}
+%D year ={2011},
+%D month ={June}
+%D edition ={Revised},
+%D editor ={Waldron, A and Judd, P. and Miller, V.},
+%D address ={Ridge, NY},
+%D publisher={American Physical Society},
+%D pages ={26},
+%D url ={http://journals.aps.org/files/styleguide-pr.pdf}
+%D }
+%D \stopTEX
+
+% set ALL specific APS compliant values
+
+\definebtx
+ [aps]
+ [\c!default=default,
+ \c!specification=aps,
+ \c!otherstext={\space\btxlabeltext{aps:others}},
+ \c!etallimit=10,
+ \c!etaldisplay=\btxparameter\c!etallimit,
+ %c!journalconversion=\v!normal,
+ \c!monthconversion=\v!month,
+ optionaltitle=\v!yes,
+ \c!separator:names:2={,\space},
+ \c!separator:names:3={,\space\btxlabeltext{aps:and}\space}, % not \textampersand
+ \c!separator:names:4= {\space\btxlabeltext{aps:and}\space}] % not \textampersand
+
+% First, define and set list and rendering parameters
+
+\definebtxrendering
+ [aps]
+ [\c!specification=aps]
+
+\definebtx
+ [aps:list]
+ [aps]
+ [\c!authorconversion=normalshort]
+
+\definebtx
+ [aps:list:author]
+ [aps:list]
+
+\definebtx
+ [aps:list:editor]
+ [aps:list:author]
+
+\definebtx
+ [aps:list:suffix]
+ [aps:list]
+
+\definebtx
+ [aps:list:url]
+ [aps:list]
+
+\definebtx
+ [aps:list:doi]
+ [aps:list]
+
+\definebtx
+ [aps:list:invertedshort]
+ [aps:list]
+
+% This is for numbering=num
+
+\definebtx
+ [aps:list:num]
+ [aps:list]
+ [left={[},
+ right={]}]
+
+% This is for numbering=yes
+
+\definebtx
+ [aps:list:yes]
+ [aps:list:num]
+
+% This is for numbering=short
+
+\definebtx
+ [aps:list:short]
+ [aps:list:num]
+
+% This is for numbering=bib
+
+\definebtx
+ [aps:list:bib]
+ [aps:list:num]
+
+%D In order to be able to get journals expanded (or normalized or abbreviated) you need
+%D to load a list:
+%D
+%D \starttyping
+%D \btxloadjournallist[journals.txt] % the jabref list
+%D \stoptyping
+
+% TODO
+
+\definebtx
+ [aps:list:journal]
+ [\c!style=\v!italic]
+ %command=\btxexpandedjournal] % btxabbreviatedjournal
+
+\definebtx
+ [aps:list:volume]
+ [\c!style=\v!bold]
+
+\definebtx
+ [aps:list:title]
+ [\c!style=\v!italic,
+ \c!command=\Word]
+
+\definebtx
+ [aps:list:title:article]
+ [aps:list:title]
+ [\c!style=] % journal is set in italics
+
+\definebtx
+ [aps:list:title:magazine]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:newspaper]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:periodical]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:standard]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:book]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:inbook]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:incollection]
+ [aps:list:title]
+ [\c!style=] % booktitle is set in italics
+
+\definebtx
+ [aps:list:title:proceedings]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:inproceedings]
+ [aps:list:title]
+ [\c!style=] % booktitle is set in italics
+
+\definebtx
+ [aps:list:title:conference]
+ [aps:list:title]
+ [\c!style=] % booktitle is set in italics
+
+\definebtx
+ [aps:list:title:thesis]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:phdthesis]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:mastersthesis]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:booklet]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:manual]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:techreport]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:unpublished]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:patent]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:electronic]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:other]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:misc]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:title:literal]
+ [aps:list:title]
+
+\definebtx
+ [aps:list:type]
+ [\c!command=\Word]
+
+% We define [page] settings in the aps namespace, inheriting the root
+% settings, in order to eventually allow for modifications without touching
+% root.
+
+\definebtx
+ [aps:page]
+ [\s!page]
+
+\definebtx
+ [aps:page:list]
+ [aps:page]
+ [\c!command={\wordright}]
+
+% Then define and set all cite parameters
+
+\definebtx
+ [aps:cite]
+ [aps]
+ [\c!authorconversion=\v!name]
+
+\definebtx
+ [aps:cite:author]
+ [aps:cite]
+
+\definebtx
+ [aps:cite:authoryear]
+ [aps:cite:author]
+ [\c!left={(},
+ \c!right={)},
+ \c!inbetween={,\space}]
+
+\definebtx
+ [aps:cite:authoryears]
+ [aps:cite:authoryear]
+ [\c!left=,
+ \c!right=,
+ \c!inbetween={\space}]
+
+\definebtx
+ [aps:cite:authornum]
+ [aps:cite:author]
+ [\c!left={(},
+ \c!right={)},
+ \c!sorttype=authornum]
+
+\definebtx
+ [aps:cite:authorref]
+ [aps:cite:authornum]
+
+\definebtx
+ [aps:cite:author:num] % todo
+ [aps:cite:authornum]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [aps:cite:author:year] % todo
+ [aps:cite:authoryear]
+ [\c!left=,
+ \c!right=]
+
+\definebtx
+ [aps:cite:author:years] % todo
+ [aps:cite:authoryears]
+ [\c!inbetween=,
+ \c!left=(,
+ \c!right=)]
+
+\definebtx
+ [aps:cite:year]
+ [aps:cite]
+ [\c!compress=\v!yes,
+ \c!sorttype=year]
+
+\definebtx
+ [aps:cite:title]
+ [aps:cite]
+ [\c!command={\language[\currentbtxlanguage]}, % BAH
+ \c!style=\v!italic]
+
+\definebtx
+ [aps:cite:booktitle]
+ [aps:cite:title]
+
+\definebtx
+ [aps:cite:tag]
+ [aps:cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [aps:cite:key]
+ [aps:cite:tag]
+
+\definebtx
+ [aps:cite:serial]
+ [aps:cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [aps:cite:page]
+ [aps:cite]
+ [\c!left=,
+ \c!right=,
+ [\c!separator:2={,\space}, % :0 and :1 - between items of a list
+ \c!separator:3={,\space\btxlabeltext{aps:and}\space}, % not \textampersand
+ \c!separator:4= {\space\btxlabeltext{aps:and}\space}] % not \textampersand
+
+\definebtx
+ [aps:cite:pages]
+ [aps:cite:page]
+
+\definebtx
+ [aps:cite:keywords]
+ [aps:cite]
+ [\c!left={(},
+ \c!right={)}]
+
+\definebtx
+ [aps:cite:invertedshort]
+ [aps:cite]
+
+\definebtx
+ [aps:cite:short]
+ [aps:cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [aps:cite:category]
+ [aps:cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [aps:cite:type]
+ [aps:cite:category]
+
+\definebtx
+ [aps:cite:url]
+ [aps:cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [aps:cite:doi]
+ [aps:cite:url]
+
+\definebtx
+ [aps:cite:num]
+ [aps:cite]
+ [\c!compress=\v!yes,
+ \c!left={[},
+ \c!right={]},
+ %\c!left=, % TODO: PRB uses superscript references...
+ %\c!right=, % and after punctuation, PRA, C, D, E, and L are before!
+ %\c!command={\high},
+ \c!separator:2={,}, % no space
+ \c!separator:3=\btxparameter{\c!separator:2},
+ \c!separator:4=\btxparameter{\c!separator:2}]
+
+\definebtx
+ [aps:cite:default]
+ [aps:cite:num]
+
+\definebtx
+ [aps:cite:textnum]
+ [aps:cite:num]
+ [\c!left={Ref.\nbsp},
+ \c!command=,
+ \c!separator:2={,\space},
+ \c!separator:3={\space\btxlabeltext{aps:and}\space},
+ \c!separator:4={\space\btxlabeltext{aps:and}\space}]
+
+\definebtx
+ [aps:cite:entry]
+ [aps:cite]
+ [\c!left=,
+ \c!right=,
+ \c!inbetween={\space},
+ \c!separator:2={;\space},
+ \c!separator:3=\btxparameter{\c!separator:2},
+ \c!separator:4=\btxparameter{\c!separator:2}]
+
+%D Sometimes we have verbose injections in an entry and these can be language
+%D dependent, so we use labels.
+%D
+%D Because we want to mix rendering (in the manual) we need a namespace in label
+%D texts:
+
+\setupbtxlabeltext
+ [en]
+ [aps:and=and,
+ aps:number={no.},
+ aps:edition={ed.},
+ aps:Editor={Ed.},
+ aps:Editors={Eds.},
+ aps:Volume={Vol.},
+ aps:Volumes={Vols.},
+ aps:others={et al.},
+ aps:page={p.},
+ aps:pages={pp.},
+ aps:mastersthesis={Master's thesis},
+ aps:phdthesis={Doctoral dissertation},
+ aps:technicalreport={Tech. Rep.}, % Technical report
+ aps:supplement={Suppl.}, % Supplement (not used?)
+ aps:patent=Patent,
+ aps:inpress={in press},
+ aps:tobe={to be published},
+ aps:unpublished={unpublished},
+ aps:In=In]
+
+% Check this (google translate!!):
+
+\setupbtxlabeltext
+ [nl]
+ [aps:and=en,
+ aps:number={nr.},
+ aps:edition={ed.}, % editie
+ aps:Editor=Editor, % Ed./Eds.
+ aps:Editors=Editors,
+ aps:Volume={Vol.},
+ aps:Volumes={Vols.},
+ aps:others={et al.},
+ aps:page={p.},
+ aps:pages={pp.},
+ aps:mastersthesis=Masterproef,
+ aps:phdthesis=Proefschrift,
+ aps:technicalreport={Technisch rapport}, % Technical report
+ aps:supplement=Supplement,
+ aps:patent=Octrooi,
+ aps:inpress={in press}, % CHECK THESE!
+ aps:tobe={worden gepubliceerd},
+ aps:unpublished={onuitgegeven},
+ aps:In=In]
+
+\setupbtxlabeltext
+ [fr]
+ [aps:and=et,
+ aps:others={et al.},
+ aps:number={n\high{o}},
+ aps:edition={édition},
+ aps:Editor=Éditeur,
+ aps:Editors=Éditeurs,
+ aps:Volume=Volume,
+ aps:Volumes=Volumes,
+ aps:others={et al.},
+ aps:page={p.},
+ aps:pages={pp.},
+ aps:mastersthesis={Thèse de master (DEA, DESS, master)},
+ aps:phdthesis={Thèse de doctorat},
+ aps:technicalreport={Rapport technique},
+ aps:supplement=Supplément,
+ aps:patent=Brevet,
+ aps:inpress={sous impression},
+ aps:tobe={à paraître},
+ aps:unpublished={inédit}, % pour un livre
+ aps:In=Dans]
+
+\setupbtxlabeltext
+ [de]
+ [aps:and=und,
+ aps:number={nr.},
+ aps:edition=Auf\/lage,
+ aps:Editor=Herausgeber, % Hrsg./Hg.
+ aps:Editors=Herausgeber,
+ aps:Volume=Band, % Bd.
+ aps:Volumes={Bände},
+ aps:others={et al.},
+ aps:page={S.},
+ aps:pages={S.},
+ aps:mastersthesis={Masterarbeit},
+ aps:phdthesis={Dissertation},
+ aps:technicalreport={Technischer Bericht},
+ aps:supplement={Beilage}, % Supplement
+ aps:patent=Patent,
+ aps:inpress={in der Presse}, % CHECK THESE!
+ aps:tobe={veröffentlicht werden},
+ aps:unpublished={unveröffentlicht},
+ aps:In=In]
+
+% thanks: Andrea Valle
+
+\setupbtxlabeltext
+ [it]
+ [aps:and=e,
+ aps:number={nº},
+ aps:edition={ed.}, % edizione
+ aps:Editor={A cura di},
+ aps:Editors={A cura di},
+ aps:Volume={Vol.}, % Volume
+ aps:Volumes={Vol.}, % Volumi
+ aps:others={et al.},
+ aps:page={p.},
+ aps:pages={pp.},
+ aps:mastersthesis={Tesi di laurea},
+ aps:phdthesis={Tesi di dottorato},
+ aps:technicalreport={Relazione tecnica},
+ aps:supplement={Supplemento},
+ aps:patent=Brevetto,
+ aps:inpress={in press}, % CHECK THESE!
+ aps:tobe={da pubblicare},
+ aps:unpublished={inedito},
+ aps:In=In]
+
+\setupbtxlabeltext
+ [es]
+ [aps:and=y,
+ aps:number={nº},
+ aps:edition={ed.}, % edición
+ aps:Editor=Editor, % Ed./Eds.
+ aps:Editors=Editores,
+ aps:Volume={Vol.}, % Volumen
+ aps:Volumes={Vols.}, % Volúmenes
+ aps:others={et al.},
+ aps:page={p.},
+ aps:pages={pp.},
+ aps:mastersthesis={Tesis de maestría},
+ aps:phdthesis={Tesis doctoral},
+ aps:technicalreport={Informe técnico},
+ aps:supplement=Suplemento,
+ aps:patent=Patente,
+ aps:inpress={en prensa}, % CHECK THESE!
+ aps:tobe={que se publicará},
+ aps:unpublished={inédito},
+ aps:In=En]
+
+% cite setups
+
+\startsetups btx:aps:nd
+ \doifelse {\currentbtxcategory} {article} {
+ \btxlabeltext{aps:tobe}
+ } {
+ \doifelse {\currentbtxcategory} {book} {
+ \btxlabeltext{aps:inpress}
+ } {
+ \btxlabeltext{aps:unpublished}
+ }
+ }
+\stopsetups
+
+\startsetups btx:aps:cite:author:year
+ \texdefinition{\s!btx:\s!cite:concat}
+ \ifx\currentbtxfirst\empty
+ \fastsetup{btx:aps:nd}
+ \else
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \btxcitereference
+ \currentbtxfirst
+ }
+ \ifx\currentbtxsecond\empty \else
+ \btxparameter\v!inbetween
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \currentbtxsecond
+ }
+ \fi
+ \ifx\currentbtxthird\empty \else
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \currentbtxthird
+ }
+ \fi
+ \fi
+\stopsetups
+
+\startsetups btx:aps:cite:author:years
+ \fastsetup{btx:aps:cite:author:year}
+\stopsetups
+
+\startsetups [btx:aps:page:list]
+ \fastsetup{\s!btx:\s!page:concat}
+ \ifx\currentbtxlastpage\empty
+ \btxlabeltext{aps:page}
+ \else
+ \btxlabeltext{aps:pages}
+ \fi
+ \btxnbsp
+ \ifconditional\btxinteractive
+ \goto {
+ \currentbtxfirstpage
+ } [
+ internal(\currentbtxfirstinternal)
+ ]
+ \ifx\currentbtxlastpage\empty \else
+ \btxparameter\c!pageconnector
+ \goto {
+ \currentbtxlastpage
+ } [
+ internal(\currentbtxlastinternal)
+ ]
+ \fi
+ \else
+ \currentbtxfirstpage
+ \ifx\currentbtxlastpage\empty \else
+ \btxparameter\c!pageconnector
+ \currentbtxlastpage
+ \fi
+ \fi
+\stopsetups
+
+%D Instead of texdefinitions without arguments, we could have used setups but in my
+%D editor (hh, scite) the commands stand out better. It also saves an additional
+%D component in the name (e.g. common:) because commands and setups have a different
+%D namespace, so similar calls don't clash. Performance of definitions is somewhat
+%D better.
+
+%D We use "texdefinitions" (with eventual arguments) for helpers that are used
+%D in the rendering "setups" defined for each category below.
+
+%D Note that \btxdoif... and \btxflush rely on the definitions in
+%D publ-imp-aps.lua: fields that are not listed as required nor optional are
+%D IGNORED. We also make heavy use of the notion of sets - comma-separated lists
+%D of alternative fields to be used in hierarchal order. For example:
+%D author = { "author", "editor", "publisher", "title" }, will return the
+%D author field if it exists; if not, the editor field will be returned, if it
+%D exists; if not, the publisher field will be returned, if it exists; if not,
+%D the title field will be returned, it it exists; if not, nothing will be
+%D returned. In lua syntax, it can be understood as
+%D author or editor or publisher or title or ""
+
+\starttexdefinition btx:aps:composed-title #title
+ \begingroup
+ \language[\currentbtxlanguage]
+ \btxusecommand[aps:list:title:\currentbtxcategory] {
+ \btxflush{#title}
+ \btxdoif {sub#title} {
+ \btxcolon
+ \btxflush{sub#title}
+ }
+ }
+ \endgroup
+\stoptexdefinition
+
+\starttexdefinition btx:aps:title
+ \btxdoif {title} {
+ % we make the title active, opening file
+ \btxdoifelse {file} {
+ \texdefinition{btx:format:inject}
+ {url(file:\btxflush{file})}
+ {
+ \btxstartstyleandcolor [aps:list:title:\currentbtxcategory]
+ \texdefinition{btx:aps:composed-title}{title}
+ \btxstopstyleandcolor
+ }
+ } {
+ \btxstartstyleandcolor [aps:list:title:\currentbtxcategory]
+ \texdefinition{btx:aps:composed-title}{title}
+ \btxstopstyleandcolor
+ }
+ \btxcomma
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:aps:optional-title
+ \doif{\btxparameter{optionaltitle}}\v!yes {
+ \texdefinition {btx:aps:title}
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:aps:year
+ \btxdoifelse {year} {
+ \btxflush{year}
+ } {
+ \fastsetup{btx:aps:nd}
+ }
+\stoptexdefinition
+
+% #author may be author(set) or editor
+
+\starttexdefinition btx:aps:author-or-editor #author
+ \btxdoif {#author} {
+ \btxflush{#author}
+ \doifelse {\btxfoundname{#author}} {editor} {
+ \btxleftparenthesis
+ \btxsingularorplural {editor} {
+ \btxlabeltext{aps:Editor}
+ } {
+ \btxlabeltext{aps:Editors}
+ }
+ \btxrightparenthesis
+ } {
+ \btxdoif {collaboration} {
+ \btxleftparenthesis
+ \btxflush{collaboration}
+ \btxrightparenthesis
+ }
+ }
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:aps:author
+ \btxflush{author}
+ \btxcomma
+\stoptexdefinition
+
+\starttexdefinition btx:aps:editor-in
+ \btxdoif {booktitle} {
+ \btxlabeltext{aps:In}
+ \doifnot {\btxfoundname{author}} {editor} {
+ \btxspace
+ \texdefinition{btx:aps:author-or-editor} {editor}
+ }
+ \btxspace
+ \btxstartstyleandcolor[aps:list:title]
+ \texdefinition{btx:aps:composed-title} {booktitle}
+ \btxstopstyleandcolor
+ \btxcomma
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:aps:editionset
+ \doif {\currentbtxcategory} {techreport} {
+ \btxdoifelse {type} {
+ \btxusecommand[\currentbtx:type] {
+ \btxflush{type}
+ }
+ } {
+ \btxlabeltext{aps:technicalreport}
+ }
+ \btxcomma
+ }
+ \btxdoif {volume} {
+ \btxoneorrange {volume} {
+ \btxlabeltext{aps:Volume}
+ } {
+ \btxlabeltext{aps:Volumes}
+ }
+ \btxspace
+ \btxflush{volume}
+ \btxcomma
+ }
+ \btxdoif {number} {
+ \btxlabeltext{aps:number}
+ \btxspace
+ \btxflush{number}
+ \btxcomma
+ }
+ \btxdoif {edition} {
+ \btxflush{edition}
+ \btxspace
+ \btxlabeltext{aps:edition}
+ \btxcomma
+ }
+ \btxdoif {pages} {
+ \btxoneorrange {pages} {
+ \btxlabeltext{aps:page}
+ } {
+ \btxlabeltext{aps:pages}
+ }
+ \btxnbsp
+ \btxflush{pages}
+ \btxcomma
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:aps:journal-volume-year
+ \btxdoif {journal} {
+ % expandedjournal abbreviatedjournal
+ \btxflush{expandedjournal -> journal}
+ \btxdoifelse {volume} {
+ \btxspace
+ \btxstartstyleandcolor [aps:list:volume]
+ \btxflush{volume}
+ \btxstopstyleandcolor
+ \btxdoif {number} {
+ \removeunwantedspaces(
+ \btxflush{number}
+ \btxrightparenthesiscomma
+ }
+ } {
+ \btxdoif {number} {
+ \btxspace
+ \btxflush{number}
+ \btxcomma
+ }
+ }
+ \btxdoif {pages} {
+ \btxspace
+ \btxflush{pages}
+ }
+ \btxleftparenthesis
+ \texdefinition{btx:aps:year}
+ \btxrightparenthesis
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:aps:publisher-wherefrom-year
+ \removeunwantedspaces
+ \removepunctuation
+ \btxleftparenthesis
+ \btxflush{publisher}
+ \btxdoifelse {address} {
+ \btxdoif {publisher} {
+ \btxcomma
+ }
+ \btxflush{address}
+ \btxdoif {country} {
+ \btxcomma
+ \btxflush{country}
+ }
+ \btxcomma
+ } {
+ \btxdoif {publisher} {
+ \btxcomma
+ }
+ }
+ \texdefinition{btx:aps:year}
+ \btxrightparenthesis
+\stoptexdefinition
+
+\starttexdefinition btx:aps:note
+ \btxperiod
+ \btxdoif {note} {
+ \btxleftparenthesis
+ \btxflush{note}
+ \btxrightparenthesis
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:aps:doi-url #text
+ \ifconditional\btxinteractive
+ \btxdoifelse {doi} {
+ \goto {#text} [url(http://dx.doi.org/\btxflush{doi})]
+ } {
+ \btxdoifelse {url} {
+ \goto {#text} [url(\btxflush{url})]
+ } {
+ #text
+ }
+ }
+ \else
+ #text
+ \fi
+
+\stoptexdefinition
+
+% Then setups, by category
+
+% An article from a journal
+% Required fields: author or editor or title, journal, (year).
+% Optional fields: volume, number, pages, type, doi, url, note.
+% Note that bibtex (and tools) do not include editor (e.g. special issue or section)
+
+\startsetups btx:aps:list:article
+ \texdefinition{btx:aps:author}
+ \texdefinition{btx:aps:optional-title}
+ \texdefinition{btx:aps:doi-url} {\texdefinition{btx:aps:journal-volume-year}}
+ \texdefinition{btx:aps:note}
+\stopsetups
+
+% An article from a magazine.
+% Required fields: author or title, journal, (year).
+% Optional fields: number, pages, type, month, day, doi, url, note.
+
+\startsetups btx:aps:list:magazine
+ \fastsetup{btx:aps:list:article}
+\stopsetups
+
+% An article from a newspaper.
+% Required fields: author or title, journal, (year).
+% Optional fields: number, pages, type, month, day, doi, url, note.
+
+\startsetups btx:aps:list:newspaper
+ \fastsetup{btx:aps:list:article}
+\stopsetups
+
+% A complete issue of a periodical, such as a special issue of a journal.
+% Required fields: title, year
+% Optional fields: editor, publisher, subtitle, series, volume, number, month, organization, doi, url, issn, note
+
+% needs to be tuned...
+\startsetups btx:aps:list:periodical
+ \fastsetup{btx:aps:list:article}
+\stopsetups
+
+% National and international standards issued by a standards body
+% Required fields: author, institution, or organization, year, title
+% Optional fields: subtitle, doi, url, note
+
+\startsetups btx:aps:list:standard
+ \texdefinition{btx:aps:author}
+ \texdefinition{btx:aps:title}
+ \texdefinition{btx:aps:note}
+\stopsetups
+% year?
+
+% A book with an explicit publisher.
+% Required fields: author or editor or publisher, title, (year).
+% Optional fields: volume or number, series, address, edition, month, day, note.
+% APS? ignores: month, day
+
+% todo: series?
+
+\startsetups btx:aps:list:book
+ \texdefinition{btx:aps:author}
+ \texdefinition{btx:aps:title}
+ \texdefinition{btx:aps:editionset}
+ \texdefinition{btx:aps:doi-url} {\texdefinition{btx:aps:publisher-wherefrom-year}}
+ \texdefinition{btx:aps:note}
+\stopsetups
+
+% There is some debate about how inbook should differ from incollection
+
+% A part of a book, which may be a chapter (or section or whatever) and/or a range of pages.
+% (note that inbook is handled differently by bibtex and biblatex)
+% Required fields: author or editor, title, chapter and/or pages, publisher, year.
+% Optional fields: volume or number, series, type, address, edition, month, note.
+% We add optional: booktitle.
+% APS? ignores: chapter, month
+
+\startsetups btx:aps:list:inbook
+ \texdefinition{btx:aps:author}
+ \texdefinition{btx:aps:title}
+ \texdefinition{btx:aps:editor-in}
+ \texdefinition{btx:aps:editionset}
+ \texdefinition{btx:aps:doi-url} {\texdefinition{btx:aps:publisher-wherefrom-year}}
+ \texdefinition{btx:aps:note}
+\stopsetups
+% chapter?
+
+% A part of a book having its own title.
+% Required fields: author, title, booktitle, publisher, year.
+% Optional fields: editor, volume or number, series, type, chapter, pages, address, edition, month, note.
+% APS? ignores: chapter, month
+
+\startsetups btx:aps:list:incollection
+ \fastsetup{btx:aps:list:inbook}
+\stopsetups
+
+% The proceedings of a conference.
+% Required fields: title, year.
+% Optional fields: editor, volume or number, series, address, month, organization, publisher, note.
+% todo: series?
+
+\startsetups btx:aps:list:proceedings
+ \fastsetup{btx:aps:list:book}
+\stopsetups
+
+% An article in a conference proceedings.
+% Required fields: author, title, booktitle, year.
+% Optional fields: editor, volume or number, series, pages, address, month, organization, publisher, note.
+
+\startsetups btx:aps:list:inproceedings
+ \texdefinition{btx:aps:author}
+ \texdefinition{btx:aps:title}
+ \texdefinition{btx:aps:editor-in}
+ \texdefinition{btx:aps:editionset}
+ \btxdoif {organization} {
+ \btxspace
+ \btxflush{organization}
+ \btxcomma
+ }
+ \texdefinition{btx:aps:doi-url} {\texdefinition{btx:aps:publisher-wherefrom-year}}
+ \texdefinition{btx:aps:note}
+\stopsetups
+
+\startsetups btx:aps:list:conference
+ \fastsetup{btx:aps:list:inproceedings}
+\stopsetups
+
+% A thesis.
+% Required fields: author, title, school, year.
+% Optional fields: type, address, month, note.
+
+\startsetups btx:aps:list:thesis
+ \texdefinition{btx:aps:author}
+ \texdefinition{btx:aps:title}
+ \btxleftparenthesis
+ \btxdoifelse {type} {
+ \btxusecommand[aps:list:type] {
+ \btxflush{type}
+ }
+ } {
+ \btxlabeltext{aps:\currentbtxcategory}
+ }
+ \btxrightparenthesis
+ \btxdoif {school} {
+ \btxperiod
+ \btxflush{school}
+ }
+ \btxdoif {address} {
+ \btxdoifelse {school} {
+ \btxcomma
+ } {
+ \btxperiod
+ }
+ \btxflush{address}
+ \btxdoif {country} {
+ \btxcomma
+ \btxflush{country}
+ }
+ }
+ \btxperiod
+ \texdefinition{btx:aps:note}
+\stopsetups
+
+\startsetups btx:aps:list:phdthesis
+ \fastsetup{btx:aps:list:thesis}
+\stopsetups
+
+\startsetups btx:aps:list:mastersthesis
+ \fastsetup{btx:aps:list:thesis}
+\stopsetups
+
+% A work that is printed and bound, but without a named publisher or sponsoring institution.
+% Required field: title.
+% Optional fields: author, howpublished, address, month, year, note.
+
+\startsetups btx:aps:list:booklet
+ \fastsetup{btx:aps:list:book}
+\stopsetups
+
+% Technical documentation.
+% Required field: title.
+% Optional fields: author, organization, address, edition, month, year, note.
+
+\startsetups btx:aps:list:manual
+ \fastsetup{btx:aps:list:book}
+\stopsetups
+
+% A report published by a school or other institution, usually numbered within a series.
+% Required fields: author, title, institution, year.
+% Optional fields: type, number, address, month, note.
+
+\startsetups btx:aps:list:techreport
+ \fastsetup{btx:aps:list:book}
+\stopsetups
+
+% A document having an author and title, but not formally published.
+% Required fields: author, title, note.
+% Optional fields: month, year.
+
+\startsetups btx:aps:list:unpublished
+ \fastsetup{btx:aps:list:book}
+\stopsetups
+
+% A patent. Note that this category was not defined with BIBTEX. Below from JabRef:
+% Required fields: nationality, number, year, yearfiled
+% Optional fields: author, title, assignee, address, type, number, day, dayfiled, month, monthfiled, note, url
+% Also optional: publisher
+
+% todo: yearfiled, monthfiled, dayfiled
+
+\startsetups btx:aps:list:patent
+ \texdefinition{btx:aps:author}
+ \texdefinition{btx:aps:title}
+ \begingroup
+ \it
+ \btxdoif {nationality} {
+ \btxspace
+ \btxflush{nationality}
+ }
+ \btxspace
+ \btxlabeltext{aps:patent}
+ \btxdoif {number} {
+ \btxspace
+ \btxlabeltext{aps:number}
+ \btxspace
+ \btxflush{number}
+ }
+ \btxperiod
+ \italiccorrection
+ \endgroup
+ \texdefinition{btx:aps:doi-url} {\texdefinition{btx:aps:publisher-wherefrom-year}}
+ \texdefinition{btx:aps:url}
+ \texdefinition{btx:aps:note}
+\stopsetups
+
+% Electronic. Note that this category was not defined with BIBTEX. Below from JabRef:
+% Required fields: title
+% Optional fields: address, author, howpublished, month, note, organization, url, year, doi
+% Also optional: type
+
+% Like Misc below but includes organization.
+
+\startsetups btx:aps:list:electronic
+ \texdefinition{btx:aps:author}
+ \texdefinition{btx:aps:title}
+ \btxdoif {organization} {
+ \btxspace
+ \btxflush{organization}
+ \btxperiod
+ }
+ \btxdoif {howpublished} {
+ \btxspace
+ \btxflush{howpublished}
+ \btxperiod
+ }
+ \texdefinition{btx:aps:note}
+\stopsetups
+
+% Other. Note that this category was not defined with BIBTEX. Below from JabRef:
+% Required fields: author or title, year
+% Optional fields: note, doi, url
+
+\startsetups btx:aps:list:other
+ \fastsetup{btx:aps:list:book}
+\stopsetups
+
+% Use this type when nothing else fits.
+% Required fields: none.
+% Optional fields: author, title, howpublished, month, year, note.
+
+\startsetups btx:aps:list:misc
+ \texdefinition{btx:aps:author}
+ \texdefinition{btx:aps:title}
+ \btxdoif {howpublished} {
+ \btxspace
+ \btxflush{howpublished}
+ \btxperiod
+ }
+ \texdefinition{btx:aps:note}
+\stopsetups
+
+% If all else fails to match:
+
+\startsetups btx:aps:list:literal
+ %\btxleftparenthesis
+ \removeunwantedspaces(
+ \btxflush{key}
+ \btxrightparenthesis
+ \btxdoif {text} {
+ \btxflush{text}
+ }
+\stopsetups
+
+\stopbtxrenderingdefinitions
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-author.mkvi b/Master/texmf-dist/tex/context/base/publ-imp-author.mkvi
new file mode 100644
index 00000000000..534d8ce0b29
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-author.mkvi
@@ -0,0 +1,303 @@
+% TODO: MAKE default
+
+%D \module
+%D [ file=publ-imp-author,
+%D version=2014.06.23,
+%D title=\CONTEXT\ Publication Support,
+%D subtitle=Authors,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+% these can be used instead of the macros and they accept manipulator prefixes
+%
+% \currentbtxinitials : \btxauthorfield{initials}
+% \currentbtxfirstnames : \btxauthorfield{firstnames}
+% \currentbtxvons : \btxauthorfield{vons}
+% \currentbtxsurnames : \btxauthorfield{surnames}
+% \currentbtxjuniors : \btxauthorfield{juniors}
+
+\starttexdefinition \s!btx:\s!cite:\s!author:\s!de
+ \ifx\currentbtxlanguage\s!de
+ \setmode{\s!btx:\s!de}
+ \fi
+\stoptexdefinition
+
+\startsetups \s!btx:\s!cite:\s!author:concat
+ \ifcase\currentbtxoverflow
+ \btxparameter{\c!separator:names:\number\currentbtxconcat}
+ \else
+ %\btxparameter{\c!separator:names:2}
+ \fi
+\stopsetups
+
+\startsetups \s!btx:\s!cite:\s!author:others
+ \ifcase\currentbtxoverflow \else
+ \btxparameter\c!otherstext
+ \fi
+\stopsetups
+
+\startsetups \s!btx:\s!cite:\s!author:normal
+ \fastsetup{\s!btx:\s!cite:\s!author:concat}
+ \ifx\currentbtxfirstnames\empty \else
+ \currentbtxfirstnames
+ \btxparameter{\c!separator:firstnames}
+ \fi
+ \ifx\currentbtxvons\empty \else
+ \currentbtxvons
+ \ifx\currentbtxsurnames\empty \else
+ \btxparameter{\c!separator:vons}
+ \fi
+ \fi
+ \ifx\currentbtxsurnames\empty \else
+ \currentbtxsurnames
+ \ifx\currentbtxjuniors\empty \else
+ \btxparameter{\c!separator:juniors}
+ \currentbtxjuniors
+ \fi
+ \fi
+ \fastsetup{\s!btx:\s!cite:\s!author:others}
+\stopsetups
+
+\startsetups \s!btx:\s!cite:\s!author:normalshort
+ \fastsetup{\s!btx:\s!cite:\s!author:concat}
+ \ifx\currentbtxinitials\empty \else
+ \currentbtxinitials
+ \btxparameter{\c!separator:initials}
+ \fi
+ \ifx\currentbtxvons\empty \else
+ \currentbtxvons
+ \ifx\currentbtxsurnames\empty \else
+ \btxparameter{\c!separator:vons}
+ \fi
+ \fi
+ \ifx\currentbtxsurnames\empty \else
+ \currentbtxsurnames
+ \ifx\currentbtxjuniors\empty \else
+ \btxparameter{\c!separator:juniors}
+ \currentbtxjuniors
+ \fi
+ \fi
+ \fastsetup{\s!btx:\s!cite:\s!author:others}
+\stopsetups
+
+\startsetups \s!btx:\s!cite:\s!author:inverted
+ \fastsetup{\s!btx:\s!cite:\s!author:concat}
+ \ifx\currentbtxvons\empty \else
+ \texdefinition{\s!btx:\s!cite:\s!author:\s!de}
+ \doifmode {\s!btx:\s!de} {
+ \currentbtxvons
+ \btxparameter{\c!separator:vons}
+ }
+ \fi
+ \ifx\currentbtxsurnames\empty \else
+ \currentbtxsurnames
+ \ifx\currentbtxjuniors\empty \else
+ \btxparameter{\c!separator:juniors}
+ \currentbtxjuniors
+ \fi
+ \fi
+ \ifx\currentbtxfirstnames\empty
+ % firstnames are optional
+ \else
+ \btxparameter{\c!separator:invertedfirstnames}
+ \currentbtxfirstnames
+ \fi
+ \ifx\currentbtxvons\empty \else
+ \doifnotmode {\s!btx:\s!de} {
+ \btxparameter{\c!separator:vons}
+ \currentbtxvons
+ }
+ \fi
+ \fastsetup{\s!btx:\s!cite:\s!author:others}
+\stopsetups
+
+\startsetups \s!btx:\s!cite:\s!author:invertedshort
+ \fastsetup{\s!btx:\s!cite:\s!author:concat}
+ \ifx\currentbtxvons\empty \else
+ \texdefinition{\s!btx:\s!cite:\s!author:\s!de}
+ \doifnotmode {\s!btx:\s!de} {
+ \currentbtxvons
+ \btxparameter{\c!separator:vons}
+ }
+ \fi
+ \ifx\currentbtxsurnames\empty \else
+ \currentbtxsurnames
+ \ifx\currentbtxjuniors\empty \else
+ \btxparameter{\c!separator:juniors}
+ \currentbtxjuniors
+ \fi
+ \fi
+ \ifx\currentbtxinitials\empty
+ % initials are optional
+ \else
+ \btxparameter{\c!separator:invertedinitials}
+ \currentbtxinitials
+ \fi
+ \ifx\currentbtxvons\empty \else
+ \doifmode {\s!btx:\s!de} {
+ \btxparameter{\c!separator:vons}
+ \currentbtxvons
+ }
+ \fi
+ \fastsetup{\s!btx:\s!cite:\s!author:others}
+\stopsetups
+
+\startsetups \s!btx:\s!cite:\s!author:name
+ \fastsetup{\s!btx:\s!cite:\s!author:concat}
+ % is this treated differently in german?
+ \ifx\currentbtxvons\empty \else
+ \currentbtxvons
+ \btxparameter{\c!separator:vons}
+ \fi
+ \currentbtxsurnames
+ \ifcase\currentbtxauthorstate \else
+ % potential clash of names so we force initials
+ \ifx\currentbtxinitials\empty \else
+ \btxparameter{\c!separator:invertedinitials}
+ \currentbtxinitials
+ \fi
+ \fi
+ \fastsetup{\s!btx:\s!cite:\s!author:others}
+\stopsetups
+
+% list (mostly the same)
+
+\startsetups \s!btx:\s!list:\s!author:concat
+ \ifcase\currentbtxoverflow
+ \btxparameter{\c!separator:names:\number\currentbtxconcat}
+ \else
+ \btxparameter{\c!separator:names:2}
+ \fi
+\stopsetups
+
+\startsetups \s!btx:\s!list:\s!author:others
+ \ifcase\currentbtxoverflow \else
+ \btxparameter\c!otherstext
+ \fi
+\stopsetups
+
+\startsetups \s!btx:\s!list:\s!author:normal
+ \fastsetup{\s!btx:\s!list:\s!author:concat}
+ \ifx\currentbtxfirstnames\empty \else
+ \currentbtxfirstnames
+ \btxparameter{\c!separator:firstnames}
+ \fi
+ \ifx\currentbtxvons\empty \else
+ \currentbtxvons
+ \ifx\currentbtxsurnames\empty \else
+ \btxparameter{\c!separator:vons}
+ \fi
+ \fi
+ \ifx\currentbtxsurnames\empty \else
+ \currentbtxsurnames
+ \ifx\currentbtxjuniors\empty \else
+ \btxparameter{\c!separator:juniors}
+ \currentbtxjuniors
+ \fi
+ \fi
+ \fastsetup{\s!btx:\s!list:\s!author:others}
+\stopsetups
+
+\startsetups \s!btx:\s!list:\s!author:normalshort
+ \fastsetup{\s!btx:\s!list:\s!author:concat}
+ \ifx\currentbtxinitials\empty \else
+ \currentbtxinitials
+ \btxparameter{\c!separator:initials}
+ \fi
+ \ifx\currentbtxvons\empty \else
+ \currentbtxvons
+ \ifx\currentbtxsurnames\empty \else
+ \btxparameter{\c!separator:vons}
+ \fi
+ \fi
+ \ifx\currentbtxsurnames\empty \else
+ \currentbtxsurnames
+ \ifx\currentbtxjuniors\empty \else
+ \btxparameter{\c!separator:juniors}
+ \currentbtxjuniors
+ \fi
+ \fi
+ \fastsetup{\s!btx:\s!list:\s!author:others}
+\stopsetups
+
+\startsetups \s!btx:\s!list:\s!author:inverted
+ \fastsetup{\s!btx:\s!list:\s!author:concat}
+ \ifx\currentbtxvons\empty \else
+ \texdefinition{\s!btx:\s!cite:\s!author:\s!de}
+ \doifnotmode {\s!btx:\s!de} {
+ \currentbtxvons
+ \btxparameter{\c!separator:vons}
+ }
+ \fi
+ \ifx\currentbtxsurnames\empty \else
+ \currentbtxsurnames
+ \ifx\currentbtxjuniors\empty \else
+ \btxparameter{\c!separator:juniors}
+ \currentbtxjuniors
+ \fi
+ \fi
+ \ifx\currentbtxfirstnames\empty
+ % firstnames are optional
+ \else
+ \btxparameter{\c!separator:invertedfirstnames}
+ \currentbtxfirstnames
+ \fi
+ \ifx\currentbtxvons\empty \else
+ \doifmode {\s!btx:\s!de} {
+ \btxparameter{\c!separator:vons}
+ \currentbtxvons
+ }
+ \fi
+ \fastsetup{\s!btx:\s!list:\s!author:others}
+\stopsetups
+
+\startsetups \s!btx:\s!list:\s!author:invertedshort
+ \fastsetup{\s!btx:\s!list:\s!author:concat}
+ \ifx\currentbtxvons\empty \else
+ \texdefinition{\s!btx:\s!cite:\s!author:\s!de}
+ \doifnotmode {\s!btx:\s!de} {
+ \currentbtxvons
+ \btxparameter{\c!separator:vons}
+ }
+ \fi
+ \ifx\currentbtxsurnames\empty \else
+ \currentbtxsurnames
+ \ifx\currentbtxjuniors\empty \else
+ \btxparameter{\c!separator:juniors}
+ \currentbtxjuniors
+ \fi
+ \fi
+ \ifx\currentbtxinitials\empty
+ % initials are optional
+ \else
+ \btxparameter{\c!separator:invertedinitials}
+ \currentbtxinitials
+ \fi
+ \ifx\currentbtxvons\empty \else
+ \doifmode {\s!btx:\s!de} {
+ \btxparameter{\c!separator:vons}
+ \currentbtxvons
+ }
+ \fi
+ \fastsetup{\s!btx:\s!list:\s!author:others}
+\stopsetups
+
+\startsetups \s!btx:\s!list:\s!author:name
+ \fastsetup{\s!btx:\s!list:\s!author:concat}
+ % is this treated differently in german?
+ \ifx\currentbtxvons\empty \else
+ \currentbtxvons
+ \btxparameter{\c!separator:vons}
+ \fi
+ \currentbtxsurnames
+ \fastsetup{\s!btx:\s!list:\s!author:others}
+\stopsetups
+
+\protect
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-cite.mkiv b/Master/texmf-dist/tex/context/base/publ-imp-cite.mkiv
deleted file mode 100644
index 1b3157b4b98..00000000000
--- a/Master/texmf-dist/tex/context/base/publ-imp-cite.mkiv
+++ /dev/null
@@ -1,256 +0,0 @@
-%D \module
-%D [ file=publ-imp-cite,
-%D version=2013.12.24,
-%D title=\CONTEXT\ Publication Support,
-%D subtitle=XML,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\unprotect
-
-% The null case:
-
-\startsetups \s!btx:\s!cite:none
- % dummy
-\stopsetups
-
-% This saves keying:
-
-\startsetups \s!btx:\s!cite:common:normal
- \ifx\currentbtxsecond\empty
- \currentbtxfirst
- \else
- \currentbtxfirst
- \btxcitevariantparameter\v!inbetween
- \currentbtxsecond
- \fi
-\stopsetups
-
-\startsetups \s!btx:\s!cite:common:range
- \ifx\currentbtxsecond\empty
- \currentbtxfirst
- \else
- \currentbtxfirst
- \btxcitevariantparameter\c!range
- \currentbtxsecond
- \fi
-\stopsetups
-
-\startsetups \s!btx:\s!cite:concat
- \ifcase\currentbtxconcat \or \or
- \btxcitevariantparameter\c!pubsep
- \or
- \btxcitevariantparameter\c!finalpubsep
- \or
- \btxcitevariantparameter\c!lastpubsep
- \fi
-\stopsetups
-
-% \startsetups \s!btx:\s!cite:render:normal
-% \directsetup{\s!btx:\s!cite:concat}
-% \ifconditional\btxinteractive
-% \goto {
-% \btxcitereference
-% \directsetup{\s!btx:\s!cite:common:normal}
-% } [
-% \s!internal(\currentbtxinternal)
-% ]
-% \else
-% \directsetup{\s!btx:\s!cite:common:normal}
-% \fi
-% \stopsetups
-%
-% more efficient (less tokens, less expansion):
-
-\startsetups \s!btx:\s!cite:render:normal
- \directsetup{\s!btx:\s!cite:concat}
- \ifconditional\btxinteractive
- \goto {
- \btxcitereference
- \ifx\currentbtxsecond\empty
- \currentbtxfirst
- \else
- \currentbtxfirst
- \btxcitevariantparameter\v!inbetween
- \currentbtxsecond
- \fi
- } [
- \s!internal(\currentbtxinternal)
- ]
- \else
- \ifx\currentbtxsecond\empty
- \currentbtxfirst
- \else
- \currentbtxfirst
- \btxcitevariantparameter\v!inbetween
- \currentbtxsecond
- \fi
- \fi
-\stopsetups
-
-% \startsetups \s!btx:\s!cite:render:range
-% \directsetup{\s!btx:\s!cite:concat}
-% \ifconditional\btxinteractive
-% \goto {
-% \btxcitereference
-% \directsetup{\s!btx:\s!cite:common:range}
-% } [
-% \s!internal(\currentbtxinternal)
-% ]
-% \else
-% \directsetup{\s!btx:\s!cite:common:range}
-% \fi
-% \stopsetups
-%
-% more efficient (less tokens, less expansion):
-
-\startsetups \s!btx:\s!cite:render:range
- \directsetup{\s!btx:\s!cite:concat}
- \ifconditional\btxinteractive
- \goto {
- \btxcitereference
- \ifx\currentbtxsecond\empty
- \currentbtxfirst
- \else
- \currentbtxfirst
- \btxcitevariantparameter\c!range
- \currentbtxsecond
- \fi
- } [
- \s!internal(\currentbtxinternal)
- ]
- \else
- \ifx\currentbtxsecond\empty
- \currentbtxfirst
- \else
- \currentbtxfirst
- \btxcitevariantparameter\c!range
- \currentbtxsecond
- \fi
- \fi
-\stopsetups
-
-\startsetups \s!btx:\s!cite:render:variant
- \directsetup{\s!btx:\s!cite:concat}
- \ifconditional\btxinteractive
- \goto {
- \btxcitereference
- \directsetup{\s!btx:\s!cite:render:\currentbtxcitevariant}
- } [
- \s!internal(\currentbtxinternal)
- ]
- \else
- \directsetup{\s!btx:\s!cite:render:\currentbtxcitevariant}
- \fi
-\stopsetups
-
-% author lists: can be less
-
-\startsetups \s!btx:\s!cite:common:author
- \ifx\currentbtxcitevariant\v!normal
- \currentbtxfirst
- \else
- \currentbtxciteauthor
- \fi
- \ifx\currentbtxsecond\empty \else
- \btxcitevariantparameter\v!inbetween
- \currentbtxsecond
- \fi
-\stopsetups
-
-\startsetups \s!btx:\s!cite:render:author
- \directsetup{\s!btx:\s!cite:common:author}
-\stopsetups
-\startsetups \s!btx:\s!cite:render:authoryear
- \directsetup{\s!btx:\s!cite:common:author}
-\stopsetups
-\startsetups \s!btx:\s!cite:render:authoryears
- \directsetup{\s!btx:\s!cite:common:author}
-\stopsetups
-\startsetups \s!btx:\s!cite:render:authornum
- \directsetup{\s!btx:\s!cite:common:author}
-\stopsetups
-
-\startsetups \s!btx:\s!cite:author:num
- \directsetup{\s!btx:\s!cite:render:range}
-\stopsetups
-\startsetups \s!btx:\s!cite:author:year
- \directsetup{\s!btx:\s!cite:render:range}
-\stopsetups
-\startsetups \s!btx:\s!cite:author:years
- \directsetup{\s!btx:\s!cite:render:range}
-\stopsetups
-
-\startsetups \s!btx:\s!cite:author
- \directsetup{\s!btx:\s!cite:render:variant}
-\stopsetups
-\startsetups \s!btx:\s!cite:authoryear
- \directsetup{\s!btx:\s!cite:render:variant}
-\stopsetups
-\startsetups \s!btx:\s!cite:authoryears
- \directsetup{\s!btx:\s!cite:render:variant}
-\stopsetups
-\startsetups \s!btx:\s!cite:authornum
- \directsetup{\s!btx:\s!cite:render:variant}
-\stopsetups
-
-\startsetups \s!btx:\s!cite:year
- \directsetup{\s!btx:\s!cite:render:range}
-\stopsetups
-\startsetups \s!btx:\s!cite:short
- \directsetup{\s!btx:\s!cite:render:normal}
-\stopsetups
-\startsetups \s!btx:\s!cite:serial
- \directsetup{\s!btx:\s!cite:render:range}
-\stopsetups
-\startsetups \s!btx:\s!cite:tag
- \directsetup{\s!btx:\s!cite:render:normal}
-\stopsetups
-\startsetups \s!btx:\s!cite:key
- \directsetup{\s!btx:\s!cite:render:normal}
-\stopsetups
-%startsetups \s!btx:\s!cite:doi
-% \directsetup{\s!btx:\s!cite:render:normal}
-%stopsetups
-%startsetups \s!btx:\s!cite:url
-% \directsetup{\s!btx:\s!cite:render:normal}
-%stopsetups
-\startsetups \s!btx:\s!cite:category
- \directsetup{\s!btx:\s!cite:render:normal}
-\stopsetups
-\startsetups \s!btx:\s!cite:type
- \directsetup{\s!btx:\s!cite:render:normal}
-\stopsetups
-\startsetups \s!btx:\s!cite:num
- \directsetup{\s!btx:\s!cite:render:range}
-\stopsetups
-\startsetups \s!btx:\s!cite:page
- \directsetup{\s!btx:\s!cite:render:normal}
-\stopsetups
-
-\startsetups \s!btx:\s!cite:doi
- \directsetup{\s!btx:\s!cite:render:variant}
-\stopsetups
-\startsetups \s!btx:\s!cite:render:doi
- \hyphenatedurl{\currentbtxfirst}
-\stopsetups
-
-\startsetups \s!btx:\s!cite:url
- \ifconditional\btxinteractive
- \goto {
- \btxcitereference
- \hyphenatedurl{\currentbtxfirst}
- } [
- url(\currentbtxfirst)
- ]
- \else
- \hyphenatedurl{\currentbtxfirst}
- \fi
-\stopsetups
-
-\protect
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-cite.mkvi b/Master/texmf-dist/tex/context/base/publ-imp-cite.mkvi
new file mode 100644
index 00000000000..dfc16c795ee
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-cite.mkvi
@@ -0,0 +1,314 @@
+%D \module
+%D [ file=publ-imp-cite,
+%D version=2013.12.24,
+%D title=\CONTEXT\ Publication Support,
+%D subtitle=Citations,
+%D author=Alan Braslau and Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+\starttexdefinition btx:cite:inject #content
+ \ifconditional\btxinteractive
+ \ifx\currentbtxinternal\empty
+ #content
+ \else
+ \goto {
+ #content
+ } [
+ \s!internal(\currentbtxinternal)
+ ]
+ \fi
+ \else
+ #content
+ \fi
+\stoptexdefinition
+
+\starttexdefinition btx:cite:checkconcat
+ \ifnum\currentbtxcount>\zerocount
+ \let\currentbtxinternal\empty
+ \let\currentbtxbacklink\empty
+ \fi
+\stoptexdefinition
+
+% The null case:
+
+\startsetups btx:cite:none
+ \btxcitereference
+ % dummy
+\stopsetups
+
+\startsetups btx:cite:nocite
+ \dontleavehmode
+ \btxcitereference
+\stopsetups
+
+\startsetups btx:cite:unknown
+ \begingroup
+ \btxcitereference
+ unknown: \currentbtxfirst
+ \endgroup
+\stopsetups
+
+\startsetups btx:cite:empty
+ \btxcitereference
+
+\stopsetups
+
+\startsetups btx:cite:invalid
+ \btxcitereference
+ {\tt <\currentbtxreference>}
+\stopsetups
+
+% \startsetups btx:cite:normal
+% \ifx\currentbtxfirst\empty
+% \fastsetup{\s!btx:\s!cite:\s!empty}
+% \else\ifx\currentbtxsecond\empty
+% \btxcitereference
+% \currentbtxfirst
+% \ifx\currentbtxthird\empty \else
+% \currentbtxthird
+% \fi
+% \else
+% \btxcitereference
+% \currentbtxfirst
+% \btxparameter\v!inbetween
+% \currentbtxsecond
+% \ifx\currentbtxthird\empty \else
+% \currentbtxthird
+% \fi
+% \fi\fi
+% \stopsetups
+
+%\startsetups btx:cite:range
+% \ifx\currentbtxfirst\empty
+% \fastsetup{\s!btx:\s!cite:\s!empty}
+% \else\ifx\currentbtxsecond\empty
+% \btxcitereference
+% \currentbtxfirst
+% \ifx\currentbtxthird\empty \else
+% \currentbtxthird
+% \fi
+% \else
+% \btxcitereference
+% \currentbtxfirst
+% \btxparameter\c!range
+% \currentbtxsecond
+% \ifx\currentbtxthird\empty \else
+% \currentbtxthird
+% \fi
+% \fi\fi
+%\stopsetups
+
+\starttexdefinition btx:cite:concat
+ \btxparameter{\c!separator:\number\currentbtxconcat}
+\stoptexdefinition
+
+\startsetups btx:cite:normal
+ \texdefinition{\s!btx:\s!cite:concat}
+ \currentbtxlefttext
+ \ifx\currentbtxfirst\empty
+ \fastsetup{\s!btx:\s!cite:\s!empty}
+ \else
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \btxcitereference
+ \btxusecommand[\currentbtxspecification:cite:\currentbtxcitealternative] {
+ \currentbtxfirst
+ }
+ }
+ \ifx\currentbtxsecond\empty \else
+ \btxparameter\v!inbetween
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \btxusecommand[\currentbtxspecification:cite:\currentbtxcitealternative] {
+ \currentbtxsecond
+ }
+ }
+ \fi
+ \ifx\currentbtxthird\empty \else
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \btxusecommand[\currentbtxspecification:cite:\currentbtxcitealternative] {
+ \currentbtxthird
+ }
+ }
+ \fi
+ \fi
+ \currentbtxrighttext
+\stopsetups
+
+\startsetups btx:cite:author
+ \texdefinition{\s!btx:\s!cite:concat}
+ \btxparameter\c!left
+ \currentbtxlefttext
+ \ifx\currentbtxfirst\empty
+ \fastsetup{\s!btx:\s!cite:\s!empty}
+ \else
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \btxcitereference
+ \currentbtxfirst
+ }
+ \fi
+ \ifx\currentbtxsecond\empty \else
+ \relax % keeps a following space
+ \btxparameter\v!inbetween
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \currentbtxsecond
+ }
+ \fi
+ \ifx\currentbtxthird\empty \else
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \currentbtxthird
+ }
+ \fi
+ \currentbtxrighttext
+ \btxparameter\c!right
+\stopsetups
+
+\startsetups btx:cite:range
+ \texdefinition{\s!btx:\s!cite:concat}
+ \currentbtxlefttext
+ \ifx\currentbtxfirst\empty
+ \fastsetup{\s!btx:\s!cite:\s!empty}
+ \else
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \btxcitereference
+ \btxusecommand[\currentbtxspecification:cite:\currentbtxcitealternative] {
+ \currentbtxfirst
+ \ifx\currentbtxsecond\empty \else
+ \btxparameter\c!range
+ \currentbtxsecond
+ \fi
+ \ifx\currentbtxthird\empty \else
+ \currentbtxthird
+ \fi
+ }
+ }
+ \fi
+ \currentbtxrighttext
+\stopsetups
+
+\startsetups btx:cite:listelement
+ \texdefinition{\s!btx:\s!cite:concat}
+ \currentbtxlefttext
+ \ifx\currentbtxfirst\empty
+ \fastsetup{\s!btx:\s!cite:\s!empty}
+ \else
+ \texdefinition {\s!btx:\s!cite:inject} {
+ \btxcitereference
+ \currentbtxfirst
+ }
+ \fi
+ \currentbtxrighttext
+\stopsetups
+
+\startsetups \s!btx:\s!cite:entry
+ \texdefinition{\s!btx:\s!cite:concat}
+ \currentbtxlefttext
+ \btxhandleciteentry
+ \currentbtxrighttext
+\stopsetups
+
+% these three are goodies to get something but are not set up as it makes no
+% sense to have something root for combinations like this (esp not because one
+% gets default anyway
+
+% AB: not so sure about that. Why define them in default rather than here?
+
+\startsetups \s!btx:\s!cite:authoryear
+ \fastsetup{\s!btx:\s!cite:author}
+\stopsetups
+\startsetups \s!btx:\s!cite:authoryears
+ \fastsetup{\s!btx:\s!cite:authoryear}
+\stopsetups
+\startsetups \s!btx:\s!cite:authornum
+ \fastsetup{\s!btx:\s!cite:authoryear}
+\stopsetups
+\startsetups \s!btx:\s!cite:authorref
+ \ifx{\\s!btxparameter\c!alternative}{authoryear}
+ \fastsetup{\s!btx:\s!cite:authoryears}
+ \else\ifx{\btxparameter\c!alternative}{num}
+ \fastsetup{\s!btx:\s!cite:authornum}
+ \else
+ \fastsetup{\s!btx:\s!cite:author}
+ \fi\fi
+\stopsetups
+\startsetups \s!btx:\s!cite:num
+ \fastsetup{\s!btx:\s!cite:range}
+\stopsetups
+\startsetups \s!btx:\s!cite:default
+ \fastsetup{\s!btx:\s!cite:num}
+\stopsetups
+\startsetups \s!btx:\s!cite:textnum
+ \fastsetup{\s!btx:\s!cite:num}
+\stopsetups
+\startsetups \s!btx:\s!cite:year
+ \fastsetup{\s!btx:\s!cite:range}
+\stopsetups
+\startsetups \s!btx:\s!cite:short
+ \fastsetup{\s!btx:\s!cite:range}
+\stopsetups
+\startsetups \s!btx:\s!cite:author:num
+ \fastsetup{\s!btx:\s!cite:range}
+\stopsetups
+\startsetups \s!btx:\s!cite:author:year
+ \fastsetup{\s!btx:\s!cite:range}
+\stopsetups
+\startsetups \s!btx:\s!cite:author:years
+ \fastsetup{\s!btx:\s!cite:concat}%?? in range already?
+ \fastsetup{\s!btx:\s!cite:range}
+\stopsetups
+
+\startsetups \s!btx:\s!cite:serial
+ \fastsetup{\s!btx:\s!cite:range}
+\stopsetups
+\startsetups \s!btx:\s!cite:tag
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+\startsetups \s!btx:\s!cite:key
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+\startsetups \s!btx:\s!cite:category
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+
+% the following correspond to fields, but can be used in many renderings
+
+\startsetups \s!btx:\s!cite:keywords
+ \fastsetup{\s!btx:\s!cite:list}
+\stopsetups
+\startsetups \s!btx:\s!cite:type
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+\startsetups \s!btx:\s!cite:title
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+\startsetups \s!btx:\s!cite:pages
+ \fastsetup{\s!btx:\s!cite:range}
+\stopsetups
+\startsetups \s!btx:\s!cite:page
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+
+% the following is kind of specific, but can be used in many renderings
+
+\startsetups btx:cite:url
+ \ifx\currentbtxfirst\empty
+ \fastsetup{\s!btx:\s!cite:\s!empty}
+ \else\ifconditional\btxinteractive
+ \goto {
+ \btxcitereference
+ \hyphenatedurl{\doif{\currentbtxcitealternative}{doi}{doi:}\currentbtxfirst}
+ } [
+ url(\doif{\currentbtxcitealternative}{doi}{http://dx.doi.org/}\currentbtxfirst)
+ ]
+ \else
+ \btxcitereference
+ \hyphenatedurl{\doif{\currentbtxcitealternative}{doi}{doi:}\currentbtxfirst}
+ \fi\fi
+\stopsetups
+
+\protect
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-commands.mkiv b/Master/texmf-dist/tex/context/base/publ-imp-commands.mkiv
deleted file mode 100644
index 14e2dbae12d..00000000000
--- a/Master/texmf-dist/tex/context/base/publ-imp-commands.mkiv
+++ /dev/null
@@ -1,15 +0,0 @@
-\unprotect
-
-% for tugboat
-
-\definebtxcommand\hbox {\hbox}
-\definebtxcommand\vbox {\vbox}
-\definebtxcommand\llap {\llap}
-\definebtxcommand\rlap {\rlap}
-\definebtxcommand\url #1{\hyphenatedurl{#1}}
-\definebtxcommand\acro #1{\dontleavehmode{\smallcaps#1}}
-
-\let\<<
-\let\<>
-
-\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-commands.mkvi b/Master/texmf-dist/tex/context/base/publ-imp-commands.mkvi
new file mode 100644
index 00000000000..14e2dbae12d
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-commands.mkvi
@@ -0,0 +1,15 @@
+\unprotect
+
+% for tugboat
+
+\definebtxcommand\hbox {\hbox}
+\definebtxcommand\vbox {\vbox}
+\definebtxcommand\llap {\llap}
+\definebtxcommand\rlap {\rlap}
+\definebtxcommand\url #1{\hyphenatedurl{#1}}
+\definebtxcommand\acro #1{\dontleavehmode{\smallcaps#1}}
+
+\let\<<
+\let\<>
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-default.lua b/Master/texmf-dist/tex/context/base/publ-imp-default.lua
new file mode 100644
index 00000000000..61b08f30cef
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-default.lua
@@ -0,0 +1,124 @@
+-- For the moment I put this here as example. When writing the publication modules we
+-- explored several approached: pure tex, pure lua, a mix with xml, etc. In the end
+-- each has advantages and drawbacks so we ended up with readable tex plus helpers in
+-- lua. Anyway here is a lua variant of a setup ... it doesn't look nicer. An alternative
+-- can be to build a table with characters but then we need to pass left, right and
+-- other separators so again no real gain.
+
+-- function publications.maybe.default.journal(currentdataset,currenttag)
+-- if publications.okay(currentdataset,currenttag,"journal") then
+-- context.btxspace()
+-- context.startbtxstyle("italic")
+-- commands.btxflush(currentdataset,currenttag,"expandedjournal -> journal")
+-- context.stopbtxstyle()
+-- if publications.okay(currentdataset,currenttag,"volume") then
+-- context.btxspace()
+-- commands.btxflush(currentdataset,currenttag,"volume")
+-- if publications.okay(currentdataset,currenttag,"number") then
+-- context.ignorespaces()
+-- context.btxleftparenthesis()
+-- commands.btxflush(currentdataset,currenttag,"number")
+-- context.btxrightparenthesis()
+-- end
+-- elseif publications.okay(currentdataset,currenttag,"number") then
+-- context.btxlabeltext("default:number")
+-- context.btxspace()
+-- commands.btxflush(currentdataset,currenttag,"number")
+-- end
+-- if publications.okay(currentdataset,currenttag,"pages") then
+-- context.btxcomma()
+-- commands.btxflush(currentdataset,currenttag,"pages")
+-- end
+-- context.btxcomma()
+-- end
+-- end
+
+return {
+ --
+ -- metadata
+ --
+ name = "default",
+ version = "1.00",
+ comment = "DEFAULT specification",
+ author = "Alan Braslau and Hans Hagen",
+ copyright = "ConTeXt development team",
+ --
+ -- derived (combinations of) fields (all share the same default set)
+ --
+ virtual = {
+ "authoryear",
+ "authoryears",
+ "authornum",
+ "num",
+ "suffix",
+ },
+ --
+ -- special datatypes
+ --
+ types = {
+ author = "author", -- interpreted as name(s)
+ editor = "author", -- interpreted as name(s)
+ page = "pagenumber", -- number or range: f--t -- maybe just range
+ pages = "pagenumber", -- number or range: f--t -- maybe just range
+ volume = "range", -- number or range: f--t
+ number = "range", -- number or range: f--t
+ keywords = "keyword", -- comma|-|separated list
+ },
+ --
+ -- categories with their specific fields
+ --
+ categories = {
+ --
+ -- the following fields are for documentation and testing purposes
+ --
+ ["demo-a"] = {
+ sets = {
+ author = { "author", "institution", "organization" },
+ },
+ required = { "author", "title", "year" },
+ optional = { "subtitle" },
+ },
+ ["demo-b"] = {
+ sets = {
+ authors = { "author", "institution", "organization" },
+ },
+ required = { "authors", "title", "year" },
+ optional = { "subtitle" },
+ },
+ --
+ -- we only provide article and book (maybe a few more later) and we keep it
+ -- real simple. See the apa and aps definitions for more extensive examples
+ --
+ article = {
+ sets = {
+ author = { "author", "editor" },
+ },
+ required = {
+ "author", -- a set
+ "year",
+ },
+ optional = {
+ "title",
+ "keywords",
+ "journal", "volume", "number", "pages",
+ },
+ },
+ book = {
+ sets = {
+ author = { "author", "editor", },
+ editionset = { "edition", "volume", "number" },
+ },
+ required = {
+ "author", -- a set
+ "title",
+ "year",
+ },
+ optional = {
+ "subtitle",
+ "keywords",
+ "publisher", "address",
+ "editionset",
+ },
+ },
+ },
+}
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-default.mkvi b/Master/texmf-dist/tex/context/base/publ-imp-default.mkvi
new file mode 100644
index 00000000000..49a0b9eae85
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-default.mkvi
@@ -0,0 +1,594 @@
+%D \module
+%D [ file=publ-imp-default,
+%D version=2014.02.06,
+%D title=Default bibliography style,
+%D subtitle=Publications,
+%D author=Alan Braslau and Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is therefore copyrighted
+%D by \PRAGMA. See mreadme.pdf for details.
+
+%D This default style defines only a few categories: book and article.
+%D If you want more, you need to load a more complete style such as \type {apa},
+%D \type {aps}, etc. The default style is used in the manuals that ship with
+%D \CONTEXT. This file is always loaded.
+
+\startbtxrenderingdefinitions[\s!default]
+
+% \definebtx [\s!default:\s!page ] [\s!page]
+% \definebtx [\s!default:\s!cite ] [\s!cite]
+% \definebtx [\s!default:\s!list ] [\s!list]
+% \definebtx [\s!default:\s!author] [\s!author]
+
+\definebtxrendering
+ [\s!default]
+ [\c!specification=\s!default]
+
+\definebtx
+ [\s!default]
+ [\c!default=, % we do not want to fall|-|back on ourself.
+ \c!otherstext={\space\btxlabeltext{default:others}},
+ %c!journalconversion=\v!normal,
+ \c!monthconversion=\v!number,
+ \c!separator:names:2={,\space},
+ \c!separator:names:3={\space\btxlabeltext{default:and}\space},
+ \c!separator:names:4={\space\btxlabeltext{default:and}\space}]
+
+\definebtx
+ [\s!default:\s!list]
+ [\s!default]
+ [\c!authorconversion=normalshort]
+
+\definebtx
+ [\s!default:\s!cite]
+ [\s!default]
+ [\c!alternative=num,
+ \c!authorconversion=\v!name]
+
+% We define [page] settings in the default namespace, inheriting the root
+% settings, in order to eventually allow for modifications without touching
+% root.
+
+\definebtx
+ [\s!default:\s!page]
+ [\s!page]
+
+\definebtx
+ [\s!default:\s!page:list]
+ [\s!default:\s!page]
+
+% List variants, some having specific settings:
+
+\definebtx
+ [\s!default:\s!list:author]
+ [\s!default:\s!list]
+
+\definebtx
+ [\s!default:\s!list:editor]
+ [\s!default:\s!list:author]
+
+\definebtx
+ [\s!default:\s!list:url]
+ [\s!default:\s!list]
+
+\definebtx
+ [\s!default:\s!list:doi]
+ [\s!default:\s!list]
+
+\definebtx
+ [\s!default:\s!list:invertedshort]
+ [\s!default:\s!list]
+
+% normalshort?
+
+\definebtx
+ [\s!default:\s!list:short]
+ [\s!default:\s!list]
+
+\definebtx
+ [\s!default:\s!list:journal]
+ [\s!default:\s!list]
+ [\c!style=\v!italic]
+
+\definebtx
+ [\s!default:\s!list:title]
+ [\s!default:\s!list]
+ [\c!style=\v!italic,
+ \c!command=\Word]
+
+\definebtx
+ [\s!default:\s!list:title:article]
+ [\s!default:\s!list:title]
+ [\c!style=, % journal is set in italics
+ \c!command={\quotation\Word}]
+
+\definebtx
+ [\s!default:\s!list:title:book]
+ [\s!default:\s!list:title]
+
+% Citation variants, some having specific settings :
+
+\definebtx
+ [\s!default:\s!cite:author]
+ [\s!default:\s!cite]
+
+\definebtx
+ [\s!default:\s!cite:authornum]
+ [\s!default:\s!cite:author]
+ [\c!left={(},
+ \c!right={)}]
+
+\definebtx
+ [\s!default:\s!cite:authoryear]
+ [\s!default:\s!cite:author]
+ [\c!left={(},
+ \c!right={)},
+ \c!inbetween={,\space}]
+
+\definebtx
+ [\s!default:\s!cite:authorref]
+ [\s!default:\s!cite:authornum]
+
+\definebtx
+ [\s!default:\s!cite:authoryears]
+ [\s!default:\s!cite:author]
+
+\definebtx
+ [\s!default:\s!cite:author:num] % todo
+ [\s!default:\s!cite:authornum]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [\s!default:\s!cite:author:year] % todo
+ [\s!default:\s!cite:authoryear]
+ [\c!left=,
+ \c!right=]
+
+\definebtx
+ [\s!default:\s!cite:author:years] % todo
+ [\s!default:\s!cite:authoryears]
+ [\c!inbetween=,
+ \c!left=(,
+ \c!right=)]
+
+\definebtx
+ [\s!default:\s!cite:year]
+ [\s!default:\s!cite]
+ [\c!compress=\v!yes,
+ \c!sorttype=year]
+
+\definebtx
+ [\s!default:\s!cite:title]
+ [\s!default:\s!cite]
+ [command={\language[\currentbtxlanguage]}, % BAH
+ \c!style=\v!italic]
+
+\definebtx
+ [\s!default:\s!cite:tag]
+ [\s!default:\s!cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [\s!default:\s!cite:key]
+ [\s!default:\s!cite:tag]
+
+\definebtx
+ [\s!default:\s!cite:serial]
+ [\s!default:\s!cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [\s!default:\s!cite:page]
+ [\s!default:\s!cite]
+ [\c!left=,
+ \c!right=]
+
+\definebtx
+ [\s!default:\s!cite:pages]
+ [\s!default:\s!cite:page]
+
+\definebtx
+ [\s!default:\s!cite:keywords]
+ [\s!default:\s!cite]
+ [\c!left={(},
+ \c!right={)}]
+
+\definebtx
+ [\s!default:\s!cite:invertedshort]
+ [\s!default:\s!cite]
+
+\definebtx
+ [\s!default:\s!cite:short]
+ [\s!default:\s!cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [\s!default:\s!cite:category]
+ [\s!default:\s!cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [\s!default:\s!cite:type]
+ [\s!default:\s!cite:category]
+
+\definebtx
+ [\s!default:\s!cite:url]
+ [\s!default:\s!cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [\s!default:\s!cite:doi]
+ [\s!default:\s!cite:url]
+
+\definebtx
+ [\s!default:\s!cite:num]
+ [\s!default:\s!cite]
+ [\c!compress=\v!yes,
+ \c!left={[},
+ \c!right={]},
+ \c!separator:2={,}, % no space
+ \c!separator:3=\btxparameter{\c!separator:2},
+ \c!separator:4=\btxparameter{\c!separator:2}]
+
+\definebtx
+ [\s!default:\s!cite:default]
+ [\s!default:\s!cite:num]
+
+\definebtx
+ [\s!default:\s!cite:textnum]
+ [\s!default:\s!cite:num]
+ [\c!left=, % in apa: {Ref.\nbsp} or so
+ \c!right=,
+ \c!separator:2={,\space},
+ \c!separator:3={,\space\btxlabeltext{default:and}\space},
+ \c!separator:4= {\space\btxlabeltext{default:and}\space}]
+
+\definebtx
+ [\s!default:\s!cite:entry]
+ [\s!default:\s!cite]
+ [\c!left={(},
+ \c!right={)}]
+
+% Multilingual text strings
+
+\setupbtxlabeltext
+ [en]
+ [\s!default:and=and,
+ \s!default:number={no.},
+ \s!default:edition={ed.},
+ \s!default:Editor=Editor, % Ed./Eds.
+ \s!default:Editors=Editors,
+ \s!default:Volume={Vol.},
+ \s!default:Volumes={Vols.},
+ \s!default:others={et al.}]
+
+\setupbtxlabeltext
+ [nl]
+ [\s!default:and=en,
+ \s!default:number={nr.},
+ \s!default:edition={ed.}, % editie
+ \s!default:Editor=Editor, % Ed./Eds.
+ \s!default:Editors=Editors,
+ \s!default:Volume={Vol.},
+ \s!default:Volumes={Vols.},
+ \s!default:others={et al.}]
+
+\setupbtxlabeltext
+ [fr]
+ [\s!default:and=et,
+ \s!default:others={et al.},
+ \s!default:number={n\high{o}},
+ \s!default:edition={édition},
+ \s!default:Editor=Éditeur,
+ \s!default:Editors=Éditeurs,
+ \s!default:Volume=Volume,
+ \s!default:Volumes=Volumes,
+ \s!default:others={et al.}]
+
+\setupbtxlabeltext
+ [de]
+ [\s!default:and=und,
+ \s!default:number={nr.},
+ \s!default:edition=Auf\/lage,
+ \s!default:Editor=Herausgeber, % Hrsg./Hg.
+ \s!default:Editors=Herausgeber,
+ \s!default:Volume=Band, % Bd.
+ \s!default:Volumes={Bände},
+ \s!default:others={et al.}]
+
+\setupbtxlabeltext
+ [it]
+ [\s!default:and=e,
+ \s!default:number={nº},
+ \s!default:edition={ed.}, % edizione
+ \s!default:Editor={A cura di},
+ \s!default:Editors={A cura di},
+ \s!default:Volume={Vol.}, % Volume
+ \s!default:Volumes={Vol.}, % Volumi
+ \s!default:others={et al.}]
+
+\setupbtxlabeltext
+ [es]
+ [\s!default:and=y,
+ \s!default:number={nº},
+ \s!default:edition={ed.}, % edición
+ \s!default:Editor=Editor, % Ed./Eds.
+ \s!default:Editors=Editores,
+ \s!default:Volume={Vol.}, % Volumen
+ \s!default:Volumes={Vols.}, % Volúmenes
+ \s!default:others={et al.}]
+
+% First some helpers:
+
+\starttexdefinition btx:default:composed-title
+ \begingroup
+ \language[\currentbtxlanguage]
+ \btxflush{title}
+ \btxdoif {subtitle} {
+ \btxcolon
+ \btxflush{subtitle}
+ }
+ \endgroup
+\stoptexdefinition
+
+\starttexdefinition btx:default:title
+ \btxdoif {title} {
+ \btxspace
+ \btxstartstyleandcolor [default:list:title:\currentbtxcategory]
+ \btxusecommand[default:list:title:\currentbtxcategory] {
+ \texdefinition{btx:default:composed-title}
+ }
+ \btxstopstyleandcolor
+ \btxcomma
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:default:author
+ \btxdoif {author} {
+ \btxflush{author}
+ \doif {\btxfoundname{author}} {editor} {
+ \btxcomma
+ \btxsingularorplural {editor} {
+ \btxlabeltext{default:Editor}
+ } {
+ \btxlabeltext{default:Editors}
+ }
+ }
+ \btxcomma
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:default:year
+ \btxflush{year}
+ \btxflush{suffix}
+\stoptexdefinition
+
+\starttexdefinition btx:default:journal
+ \btxdoif {journal} {
+ \btxspace
+ \btxstartstyleandcolor [default:list:journal]
+ \btxusecommand[default:list:journal] {
+ \btxflush{journal}
+ }
+ \btxstopstyleandcolor
+ \btxdoifelse {volume} {
+ \btxspace
+ \btxflush{volume}
+ \btxdoif {number} {
+ \ignorespaces % brrr
+ \btxleftparenthesis
+ \btxflush{number}
+ \btxrightparenthesis
+ }
+
+ } {
+ \btxdoif {number} {
+ \btxlabeltext{default:number}
+ \btxspace
+ \btxflush{number}
+ }
+ }
+ \btxdoif {pages} {
+ \btxcomma
+ \btxflush{pages}
+ }
+ \btxcomma
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:default:editionset
+ \btxdoif {editionset} {
+ \removeunwantedspaces
+ \removepunctuation
+ \btxleftparenthesis
+ \doif {\btxfoundname{editionset}} {edition} {
+ \btxflush{edition}
+ \btxspace
+ \btxlabeltext{default:edition}
+ \btxcomma
+ }
+ \btxdoif {volume} {
+ \btxoneorrange {volume} {
+ \btxlabeltext{default:Volume}
+ } {
+ \btxlabeltext{default:Volumes}
+ }
+ \btxspace
+ \btxflush{volume}
+ \btxcomma
+ }
+ \btxdoifelse {number} {
+ \btxlabeltext{default:number}
+ \btxspace
+ \btxflush{number}
+ } {
+ \removeunwantedspaces
+ \removepunctuation
+ }
+ \btxrightparenthesiscomma
+ }
+\stoptexdefinition
+
+\starttexdefinition btx:default:publisher
+ \btxdoif {publisher} {
+ \btxflush{publisher}
+ \btxcomma
+ }
+ \btxdoif {address} {
+ \btxflush{address}
+ \btxcomma
+ }
+\stoptexdefinition
+
+% Then a minimal number of setups:
+
+\startsetups btx:default:list:article
+ \texdefinition{btx:default:author}
+ \texdefinition{btx:default:title}
+ \texdefinition{btx:default:journal}
+ \texdefinition{btx:default:year}
+ \removeunwantedspaces
+ \removepunctuation
+ \btxperiod
+\stopsetups
+
+\startsetups btx:default:list:book
+ \texdefinition{btx:default:author}
+ \texdefinition{btx:default:title}
+ \texdefinition{btx:default:editionset}
+ \texdefinition{btx:default:publisher}
+ \texdefinition{btx:default:year}
+ \removeunwantedspaces
+ \removepunctuation
+ \btxperiod
+\stopsetups
+
+\startsetups btx:default:list:unknown
+ \currentbtxcategory\btxcolon
+ \btxshowentryinline
+\stopsetups
+
+%D Experiment:
+
+\startsetups btx:default:lefttext
+ \currentbtxlefttext
+\stopsetups
+
+\startsetups btx:default:righttext
+ \currentbtxrighttext
+\stopsetups
+
+%D Citations:
+
+% \startsetups \s!btx:\s!default:\s!cite:author
+% \fastsetup{\s!btx:\s!cite:author}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:authoryear
+% \fastsetup{\s!btx:\s!cite:author}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:authoryears
+% \fastsetup{\s!btx:\s!cite:author}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:authornum
+% \fastsetup{\s!btx:\s!cite:author}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:authorref
+% \fastsetup{\s!btx:\s!cite:authorref}
+% \stopsetups
+%
+% \startsetups \s!btx:\s!default:\s!cite:author:num
+% \fastsetup{\s!btx:\s!cite:range}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:author:year
+% \fastsetup{\s!btx:\s!cite:range}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:author:years
+% \fastsetup{\s!btx:\s!cite:concat}
+% \fastsetup{\s!btx:\s!cite:range}
+% \stopsetups
+%
+% \startsetups \s!btx:\s!default:\s!cite:keywords
+% \fastsetup{\s!btx:\s!cite:list}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:year
+% \fastsetup{\s!btx:\s!cite:range}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:short
+% \fastsetup{\s!btx:\s!cite:normal}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:serial
+% \fastsetup{\s!btx:\s!cite:range}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:tag
+% \fastsetup{\s!btx:\s!cite:normal}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:key
+% \fastsetup{\s!btx:\s!cite:normal}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:category
+% \fastsetup{\s!btx:\s!cite:normal}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:type
+% \fastsetup{\s!btx:\s!cite:normal}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:num
+% \fastsetup{\s!btx:\s!cite:range}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:default
+% \fastsetup{\s!btx:\s!default:\s!cite:num}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:textnum
+% \fastsetup{\s!btx:\s!default:\s!cite:num}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:title
+% \fastsetup{\s!btx:\s!cite:normal}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:pages
+% \fastsetup{\s!btx:\s!cite:range}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:page
+% \fastsetup{\s!btx:\s!cite:normal}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:doi
+% \fastsetup{\s!btx:\s!cite:url}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:url
+% \fastsetup{\s!btx:\s!cite:url}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:nocite
+% \fastsetup{\s!btx:\s!cite:nocite}% defined nowhere :
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:entry
+% \fastsetup{\s!btx:\s!cite:entry}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!cite:none
+% \fastsetup{\s!btx:\s!cite:none}
+% \stopsetups
+
+% List
+
+% \startsetups \s!btx:\s!default:\s!list:page
+% \fastsetup{\s!btx:\s!list:page}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!list:yes
+% \fastsetup{\s!btx:\s!list:yes}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!list:num
+% \fastsetup{\s!btx:\s!list:num}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!list:bib
+% \fastsetup{\s!btx:\s!list:bib}
+% \stopsetups
+% \startsetups \s!btx:\s!default:\s!list:short
+% \fastsetup{\s!btx:\s!list:short}
+% \stopsetups
+
+\stopbtxrenderingdefinitions
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-definitions.mkiv b/Master/texmf-dist/tex/context/base/publ-imp-definitions.mkiv
deleted file mode 100644
index 2cf2e3e8efe..00000000000
--- a/Master/texmf-dist/tex/context/base/publ-imp-definitions.mkiv
+++ /dev/null
@@ -1,68 +0,0 @@
-%D \module
-%D [ file=publ-imp-def,
-%D version=2013.12.24,
-%D title=\CONTEXT\ Publication Support,
-%D subtitle=Definitions,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D Here we collect some helper setups. We assume that checking of a field
-%D happens in the calling setup, if only because that is the place where
-%D fences are also dealt with.
-
-\unprotect
-
-\startxmlsetups btx:format:crossref
- \cite[\btxfield{crossref}]
-\stopxmlsetups
-
-\startxmlsetups btx:format:key
- \btxfield{short}
-\stopxmlsetups
-
-\startxmlsetups btx:format:doi
- \edef\currentbtxfielddoi{\btxfield{doi}}
- \ifx\currentbtxfielddoi\empty
- {\tttf no-doi}
- \else\ifconditional\btxinteractive
- \goto{\hyphenatedurl{\currentbtxfielddoi}}[url(http://dx.doi.org/\currentbtxfielddoi)]
- \else
- \hyphenatedurl{\currentbtxfielddoi}
- \fi\fi
-\stopxmlsetups
-
-\startxmlsetups btx:format:url
- \edef\currentbtxfieldurl{\btxfield{url}}
- \ifx\currentbtxfieldurl\empty
- {\tttf no-url}
- \else\ifconditional\btxinteractive
- \goto{\hyphenatedurl{\currentbtxfieldurl}}[url(\currentbtxfieldurl)]
- \else
- \hyphenatedurl{\currentbtxfieldurl}
- \fi\fi
-\stopxmlsetups
-
-\startxmlsetups btx:format:month
- \edef\currentbtxfieldmonth{\btxfield{month}}
- \ifx\currentbtxfieldmonth\empty
- {\tttf no-month}
- \else
- \edef\p_monthconversion{\btxlistvariantparameter\c!monthconversion}
- \ifx\p_monthconversion\empty % month month:mnem
- \currentbtxfieldmonth
- \else
- \doifnumberelse \currentbtxfieldmonth {
- \convertnumber\p_monthconversion\currentbtxfieldmonth
- } {
- \currentbtxfieldmonth
- }
- \fi
- \fi
-\stopxmlsetups
-
-\protect
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-definitions.mkvi b/Master/texmf-dist/tex/context/base/publ-imp-definitions.mkvi
new file mode 100644
index 00000000000..8dfa931b37a
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-definitions.mkvi
@@ -0,0 +1,123 @@
+%D \module
+%D [ file=publ-imp-def,
+%D version=2013.12.24,
+%D title=\CONTEXT\ Publication Support,
+%D subtitle=Definitions,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Here we collect some helper setups. We assume that checking of a field
+%D happens in the calling setup, if only because that is the place where
+%D fences are also dealt with.
+
+% These will become texdefinitions
+
+\unprotect
+
+\startxmlsetups btx:format:crossref
+ \cite[\btxfield{crossref}]
+\stopxmlsetups
+
+\startxmlsetups btx:format:key
+ \btxfield{short}
+\stopxmlsetups
+
+\starttexdefinition btx:format:inject #link #content
+ \ifx\currentbtxinternal\empty
+ #content
+ \else\ifconditional\btxinteractive
+ \goto {#content} [#link]
+ \else
+ #content
+ \fi\fi
+\stoptexdefinition
+
+\startxmlsetups btx:format:doi
+ \edef\currentbtxfielddoi{\btxfield{doi}}
+ \ifx\currentbtxfielddoi\empty
+ {\tttf no-doi}
+ \else\ifconditional\btxinteractive
+ \goto{\hyphenatedurl{\currentbtxfielddoi}}[url(http://dx.doi.org/\currentbtxfielddoi)]
+ \else
+ \hyphenatedurl{\currentbtxfielddoi}
+ \fi\fi
+\stopxmlsetups
+
+\startxmlsetups btx:format:url
+ \edef\currentbtxfieldurl{\btxfield{url}}
+ \ifx\currentbtxfieldurl\empty
+ {\tttf no-url}
+ \else\ifconditional\btxinteractive
+ \goto{\hyphenatedurl{\currentbtxfieldurl}}[url(\currentbtxfieldurl)]
+ \else
+ \hyphenatedurl{\currentbtxfieldurl}
+ \fi\fi
+\stopxmlsetups
+
+\startxmlsetups btx:format:year
+ \edef\currentbtxfieldyear{\btxfield{year}}
+ \ifx\currentbtxfieldyear\empty
+ \btxlabeltext{\currentbtxspecification:nd}
+ \fi
+\stopxmlsetups
+
+\startxmlsetups btx:format:month
+ \edef\currentbtxfieldmonth{\btxfield{month}}
+ \ifx\currentbtxfieldmonth\empty
+ {\tttf no-month}
+ \else
+ \edef\p_monthconversion{\btxparameter\c!monthconversion}
+ \ifx\p_monthconversion\empty % month month:mnem
+ \currentbtxfieldmonth
+ \else
+ \doifelsenumber \currentbtxfieldmonth {
+ \convertnumber\p_monthconversion\currentbtxfieldmonth
+ } {
+ \currentbtxfieldmonth
+ }
+ \fi
+ \fi
+\stopxmlsetups
+
+% macros:
+
+\starttexdefinition btx:style:italic #content
+ \dontleavehmode
+ \begingroup
+ \it
+ #content
+ \italiccorrection
+ \endgroup
+\stoptexdefinition
+
+\starttexdefinition btx:style:bold #content
+ \dontleavehmode
+ \begingroup
+ \bf
+ #content
+ \endgroup
+\stoptexdefinition
+
+\starttexdefinition btx:style:quote #content
+ \dontleavehmode
+ \startquote
+ #content
+ \stopquote
+\stoptexdefinition
+
+\starttexdefinition btx:style #style #content
+ \doifelsedefined {btx:style:#style} {
+ \texdefinition{btx:style:#style} {
+ #content
+ }
+ } {
+ #content
+ }
+\stoptexdefinition
+
+\protect
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-list.mkvi b/Master/texmf-dist/tex/context/base/publ-imp-list.mkvi
new file mode 100644
index 00000000000..e13294f6f5b
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-list.mkvi
@@ -0,0 +1,90 @@
+%D \module
+%D [ file=publ-imp-list,
+%D version=2014.06.16,
+%D title=\CONTEXT\ Publication Support,
+%D subtitle=Lists,
+%D author=Alan Braslau and Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+\starttexdefinition btx:list:inject #content
+ \ifconditional\btxinteractive
+ \ifx\currentbtxinternal\empty
+ #content
+ \else
+ \goto {
+ #content
+ } [
+ \s!internal(\currentbtxinternal)
+ ]
+ \fi
+ \else
+ #content
+ \fi
+\stoptexdefinition
+
+\starttexdefinition btx:list:helpers:concat
+ % \ifcase\currentbtxconcat \or \or
+ % \btxparameter\c!pubsep
+ % \or
+ % \btxparameter\c!finalpubsep
+ % \or
+ % \btxparameter\c!lastpubsep
+ % \fi
+ \space
+\stoptexdefinition
+
+\startsetups \s!btx:\s!list:page
+ \texdefinition{\s!btx:\s!list:concat}
+ \texdefinition{\s!btx:\s!list:inject} {
+ % real pagenumber: todo, userpage
+ \currentbtxfirst
+ % order
+ \high{\currentbtxsecond}
+ }
+\stopsetups
+
+\startsetups \s!btx:\s!list:numbering
+ \btxparameter\c!left
+ \texdefinition {\s!btx:\s!list:inject} {
+ \currentbtxfirst
+ \btxparameter\c!stopper
+ }
+ \btxparameter\c!right
+\stopsetups
+
+\startsetups \s!btx:\s!list:num
+ \btxstartstyleandcolor [\currentbtxspecification:list:num]
+ \btxusecommand[\currentbtxspecification:list:num] {
+ \fastsetup{\s!btx:\s!list:numbering}
+ }
+ \btxstopstyleandcolor
+\stopsetups
+
+\startsetups \s!btx:\s!list:yes
+ \fastsetup{\s!btx:\s!list:num}
+\stopsetups
+
+\startsetups \s!btx:\s!list:short
+ \btxstartstyleandcolor [\currentbtxspecification:list:short]
+ \btxusecommand[\currentbtxspecification:list:short] {
+ \fastsetup{\s!btx:\s!list:numbering}
+ }
+ \btxstopstyleandcolor
+\stopsetups
+
+\startsetups \s!btx:\s!list:bib
+ \btxstartstyleandcolor [\currentbtxspecification:list:bib]
+ \btxusecommand[\currentbtxspecification:list:bib] {
+ \fastsetup{\s!btx:\s!list:numbering}
+ }
+ \btxstopstyleandcolor
+\stopsetups
+
+\protect
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-page.mkvi b/Master/texmf-dist/tex/context/base/publ-imp-page.mkvi
new file mode 100644
index 00000000000..19673c829d8
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-page.mkvi
@@ -0,0 +1,78 @@
+%D \module
+%D [ file=publ-imp-page,
+%D version=2014.11.05,
+%D title=\CONTEXT\ Publication Support,
+%D subtitle=Page numbers,
+%D author=Alan Braslau and Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+\definebtx
+ [\s!page] % or just outer level
+ [\c!pagestate=\v!stop,
+ \c!pageleft=\btxleftparenthesis, % see below!!
+ \c!pageright=\btxrightparenthesis,
+ \c!pagesep={,\space},
+ \c!lastpagesep={,\space\btxlabeltext{\currentbtxspecification:and}\space},
+ \c!finalpagesep={\space\btxlabeltext{\currentbtxspecification:and}\space},
+ \c!pageconnector=\endash]
+
+\definebtx
+ [\s!page:\s!list]
+ [\s!page]
+ [\c!command={\wordright}]
+
+\startsetups \s!btx:\s!page:concat
+ \ifcase\currentbtxoverflow
+ \ifcase\currentbtxconcat
+ \or % first
+ \or % second
+ \btxparameter\c!pagesep
+ \or % second of two
+ \btxparameter\c!lastpagesep
+ \or % last
+ \btxparameter\c!finalpagesep
+ \fi
+ \fi
+\stopsetups
+
+% for the moment we have only one variant
+
+\startsetups [\s!btx:\s!page:\s!list]
+ \fastsetup{\s!btx:\s!page:concat}
+ % \ifx\currentbtxlastpage\empty
+ % p.
+ % \else
+ % pp.
+ % \fi
+ % \btxnbsp
+ \ifconditional\btxinteractive
+ \goto {
+ \currentbtxfirstpage
+ } [
+ internal(\currentbtxfirstinternal)
+ ]
+ \ifx\currentbtxlastpage\empty \else
+ \btxparameter\c!pageconnector
+ \goto {
+ \currentbtxlastpage
+ } [
+ internal(\currentbtxlastinternal)
+ ]
+ \fi
+ \else
+ \currentbtxfirstpage
+ \ifx\currentbtxlastpage\empty \else
+ \btxparameter\c!pageconnector
+ \currentbtxlastpage
+ \fi
+ \fi
+\stopsetups
+
+\protect
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-replacements.lua b/Master/texmf-dist/tex/context/base/publ-imp-replacements.lua
new file mode 100644
index 00000000000..b15b17e30f8
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-replacements.lua
@@ -0,0 +1,13 @@
+return {
+ name = "replacements",
+ version = "1.00",
+ comment = "Good riddance",
+ author = "Alan Braslau and Hans Hagen",
+ copyright = "ConTeXt development team",
+ replacements = {
+ [ [[Th\^e\llap{\raise0.5ex\hbox{\'{\relax}}}]] ] = "Thánh",
+ [ [[Th\^e\llap{\raise 0.5ex\hbox{\'{\relax}}}]] ] = "Thánh",
+ [ [[Th{\^e}\llap{\raise0.5ex\hbox{\'{\relax}}}]] ] = "Thánh",
+ [ [[Th{\^e}\llap{\raise 0.5ex\hbox{\'{\relax}}}]] ] = "Thánh",
+ },
+}
diff --git a/Master/texmf-dist/tex/context/base/publ-imp-test.bib b/Master/texmf-dist/tex/context/base/publ-imp-test.bib
new file mode 100644
index 00000000000..0d81b49ff08
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-imp-test.bib
@@ -0,0 +1,294 @@
+% This is a test bibliography for developing publ-impl-XXX files. Although
+% meant for testing apa styles, it can also be used for other styles.
+%
+% All publication categories have an example entry here. Most have an entry
+% with a "-min" key, containing only the minimal set of fields.
+%
+% Maintained by: Alan Braslau, Hans Hagen, Robin Kirkham
+
+@article {test-article-min,
+ author = "An Author",
+ title = "Title-article",
+ journal = "Journal",
+ year = "Year"
+}
+
+@article {test-article,
+ author = "An Author",
+ title = "Title-article",
+ journal = "Journal",
+ year = "Year",
+ volume = "Volume",
+ number = "Number",
+ pages = "Pages",
+ month = "Month",
+ note = "Note"
+}
+
+% author, editor, or both
+
+@book {test-book-min,
+ author = "An Author",
+ title = "Title-book",
+ publisher = "Publisher",
+ year = "Year"
+}
+
+% author, editor, or both
+% volume, number, or both
+
+@book {test-book,
+ author = "An Author",
+ editor = "An Editor",
+ title = "Title-book",
+ publisher = "Publisher",
+ year = "Year",
+ volume = "Volume",
+ number = "Number",
+ series = "Series",
+ address = "Address",
+ edition = "Edition",
+ month = "Month",
+ note = "Note"
+}
+
+% no author
+
+@book {test-book-edited,
+ editor = "An Editor",
+ title = "Title-book-edited",
+ publisher = "Publisher",
+ year = "Year"
+}
+
+@booklet {test-booklet-min,
+ title = "Title-booklet"
+}
+
+@booklet {test-booklet,
+ title = "Title-booklet",
+ author = "An Author",
+ howpublished = "How-published",
+ address = "Address",
+ month = "Month",
+ year = "Year",
+ note = "Note"
+}
+
+% author, editor, or both
+% chapter, pages, or both
+
+@inbook {test-inbook-min,
+ author = "An Author",
+ editor = "An Editor",
+ title = "Title-inbook",
+ chapter = "Chapter",
+ pages = "Pages",
+ publisher = "Publisher",
+ year = "Year"
+}
+
+% author, editor, or both
+% chapter, pages, or both
+% volume, number, or both
+
+@inbook {test-inbook,
+ author = "An Author",
+ editor = "An Editor",
+ title = "Title-inbook",
+ chapter = "Chapter",
+ pages = "Pages",
+ publisher = "Publisher",
+ year = "Year",
+ volume = "Volume",
+ number = "Number",
+ series = "Series",
+ type = "Type",
+ address = "Address",
+ edition = "Edition",
+ month = "Month",
+ note = "Note"
+}
+
+@incollection {test-incollection-min,
+ author = "An Author",
+ title = "Title-incollection",
+ booktitle = "Booktitle",
+ publisher = "Publisher",
+ year = "Year"
+}
+
+% volume, number, or both
+
+@incollection {test-incollection,
+ author = "An Author",
+ title = "Title-incollection",
+ booktitle = "Booktitle",
+ publisher = "Publisher",
+ year = "Year",
+ editor = "An Editor",
+ volume = "Volume",
+ number = "Number",
+ series = "Series",
+ type = "Type",
+ chapter = "Chapter",
+ pages = "Pages",
+ address = "Address",
+ edition = "Edition",
+ month = "Month",
+ note = "Note"
+}
+
+@inproceedings {test-inproceedings-min,
+ author = "An Author",
+ title = "Title-inproceedings",
+ booktitle = "Booktitle",
+ year = "Year"
+}
+
+% volume, number, or both
+
+@inproceedings {test-inproceedings,
+ author = "An Author",
+ title = "Title-inproceedings",
+ booktitle = "Booktitle",
+ year = "Year",
+ editor = "An Editor",
+ volume = "Volume",
+ number = "Number",
+ series = "Series",
+ pages = "Pages",
+ address = "Address",
+ month = "Month",
+ organization = "Organization",
+ publisher = "Publisher",
+ note = "Note"
+}
+
+@manual {test-manual-min,
+ title = "Title-manual"
+}
+
+@manual {test-manual,
+ title = "Title-manual",
+ author = "An Author",
+ organization = "Organization",
+ address = "Address",
+ edition = "Edition",
+ month = "Month",
+ year = "Year"
+ note = "Note"
+}
+
+
+@mastersthesis {test-mastersthesis-min,
+ author = "An Author",
+ title = "Title-mastersthesis",
+ school = "School",
+ year = "Year",
+}
+
+@mastersthesis {test-mastersthesis,
+ author = "An Author",
+ title = "Title-mastersthesis",
+ school = "School",
+ year = "Year",
+ type = "Type",
+ address = "Address",
+ month = "Month",
+ note = "Note"
+}
+
+@proceedings {test-proceedings-min,
+ title = "Title-proceedings",
+ year = "Year",
+}
+
+% volume, number, or both
+
+@proceedings {test-proceedings,
+ title = "Title-proceedings",
+ year = "Year",
+ editor = "An Editor",
+ volume = "Volume",
+ number = "Number",
+ series = "Series",
+ address = "Address",
+ month = "Month",
+ organization = "Organization",
+ publisher = "Publisher",
+ note = "Note"
+}
+
+@phdthesis {test-phdthesis-min,
+ author = "An Author",
+ title = "Title-phdthesis",
+ school = "School",
+ year = "Year",
+}
+
+@phdthesis {test-phdthesis,
+ author = "An Author",
+ title = "Title-phdthesis",
+ school = "School",
+ year = "Year",
+ type = "Type",
+ address = "Address",
+ month = "Month",
+ note = "Note"
+}
+
+@techreport {test-techreport-min,
+ author = "An Author",
+ title = "Title-techreport",
+ institution = "Institution",
+ year = "Year",
+}
+
+@techreport {test-techreport,
+ author = "An Author",
+ title = "Title-techreport",
+ institution = "Institution",
+ year = "Year",
+ type = "Type",
+ number = "Number",
+ address = "Address",
+ month = "Month",
+ note = "Note"
+}
+
+@misc {test-misc,
+ author = "An Author",
+ title = "Title-misc",
+ howpublished = "How-published",
+ month = "Month",
+ year = "Year",
+ note = "Note"
+}
+
+@unpublished {test-unpublished-min,
+ author = "An Author",
+ title = "Title-unpublished",
+ note = "Note"
+}
+
+@unpublished {test-unpublished,
+ author = "An Author",
+ title = "Title-unpublished",
+ note = "Note",
+ month = "Month",
+ year = "Year"
+}
+
+% some other test entries
+
+@misc {test-manyauthor,
+ author = "A Author and B Author and C Author and D Author and
+ E Author and F Author and G Author and H Author and
+ I Author and J Author and K Author and L Author and
+ M Author and N Author and O Author and P Author and
+ Q Author and R Author and S Author and T Author and
+ U Author and V Author and W Author and X Author and
+ Y Author and Z Author",
+ title = "Title-Many Authors"
+}
diff --git a/Master/texmf-dist/tex/context/base/publ-ini.lua b/Master/texmf-dist/tex/context/base/publ-ini.lua
index 102b2210453..25397727bff 100644
--- a/Master/texmf-dist/tex/context/base/publ-ini.lua
+++ b/Master/texmf-dist/tex/context/base/publ-ini.lua
@@ -6,138 +6,192 @@ if not modules then modules = { } end modules ['publ-ini'] = {
license = "see context related readme files"
}
--- we could store the destinations in the user list entries
+-- bah .. this 200 locals limit again ... so we need to split it as adding more
+-- do ... ends makes it messier
--- will move:
+-- plug the list sorted in the list mechanism (specification.sortorder)
-local lpegmatch = lpeg.match
-local P, R, C, Ct, Cs = lpeg.P, lpeg.R, lpeg.C, lpeg.Ct, lpeg.Cs
+-- If we define two datasets with the same bib file we can consider
+-- sharing the data but that means that we need to have a parent which
+-- in turn makes things messy if we start manipulating entries in
+-- different ways (future) .. not worth the trouble as we will seldom
+-- load big bib files many times and even then ... fonts are larger.
-local lpegmatch = lpeg.match
-local pattern = Cs((1 - P(1) * P(-1))^0 * (P(".")/"" + P(1)))
-
-local manipulators = {
- stripperiod = function(str) return lpegmatch(pattern,str) end,
- uppercase = characters.upper,
- lowercase = characters.lower,
-}
-
-local manipulation = C((1-P("->"))^1) * P("->") * C(P(1)^0)
-
-local pattern = manipulation / function(operation,str)
- local manipulator = manipulators[operation]
- return manipulator and manipulator(str) or str
-end
-
-local function manipulated(str)
- return lpegmatch(pattern,str) or str
-end
-
-utilities.parsers.manipulation = manipulation
-utilities.parsers.manipulators = manipulators
-utilities.parsers.manipulated = manipulated
-
-function commands.manipulated(str)
- context(manipulated(str))
-end
-
--- use: for rest in gmatch(reference,"[^, ]+") do
+-- A potential optimization is to work with current_dataset, current_tag when
+-- fetching fields but the code become real messy that way (many currents). The
+-- gain is not that large anyway because not much publication stuff is flushed.
local next, rawget, type, tostring, tonumber = next, rawget, type, tostring, tonumber
-local match, gmatch, format, gsub = string.match, string.gmatch, string.format, string.gsub
+local match, find = string.match, string.find
local concat, sort, tohash = table.concat, table.sort, table.tohash
local utfsub = utf.sub
+local mod = math.mod
local formatters = string.formatters
local allocate = utilities.storage.allocate
local settings_to_array, settings_to_set = utilities.parsers.settings_to_array, utilities.parsers.settings_to_set
local sortedkeys, sortedhash = table.sortedkeys, table.sortedhash
local setmetatableindex = table.setmetatableindex
local lpegmatch = lpeg.match
-local P, C, Ct = lpeg.P, lpeg.C, lpeg.Ct
-
-local report = logs.reporter("publications")
-local report_cite = logs.reporter("publications","cite")
-local report_reference = logs.reporter("publications","reference")
-
-local trace = false trackers.register("publications", function(v) trace = v end)
-local trace_cite = false trackers.register("publications.cite", function(v) trace_cite = v end)
-local trace_missing = false trackers.register("publications.cite.missing", function(v) trace_missing = v end)
-local trace_references = false trackers.register("publications.cite.references", function(v) trace_references = v end)
-
-local datasets = publications.datasets
-
-local variables = interfaces.variables
-
-local v_local = variables["local"]
-local v_global = variables["global"]
-
-local v_force = variables.force
-local v_standard = variables.standard
-local v_start = variables.start
-local v_none = variables.none
-local v_left = variables.left
-local v_right = variables.right
-local v_middle = variables.middle
-local v_inbetween = variables.inbetween
-local v_yes = variables.yes
-local v_short = variables.short
-local v_cite = variables.cite
-local v_default = variables.default
-local v_reference = variables.reference
-local v_dataset = variables.dataset
-local v_author = variables.author or "author"
-local v_editor = variables.editor or "editor"
-
-local numbertochar = converters.characters
-
-local logsnewline = logs.newline
-local logspushtarget = logs.pushtarget
-local logspoptarget = logs.poptarget
-local csname_id = token.csname_id
-
-local basicsorter = sorters.basicsorter -- (a,b)
-local sortcomparer = sorters.comparers.basic -- (a,b)
-local sortstripper = sorters.strip
-local sortsplitter = sorters.splitters.utf
-
-local settings_to_array = utilities.parsers.settings_to_array
+local P, S, C, Ct, R, Carg = lpeg.P, lpeg.S, lpeg.C, lpeg.Ct, lpeg.R, lpeg.Carg
+local upper = utf.upper
+
+local report = logs.reporter("publications")
+local report_cite = logs.reporter("publications","cite")
+local report_list = logs.reporter("publications","list")
+local report_reference = logs.reporter("publications","reference")
+local report_shorts = logs.reporter("publications","shorts")
+
+local trace = false trackers.register("publications", function(v) trace = v end)
+local trace_cite = false trackers.register("publications.cite", function(v) trace_cite = v end)
+local trace_missing = false trackers.register("publications.cite.missing", function(v) trace_missing = v end)
+local trace_references = false trackers.register("publications.cite.references", function(v) trace_references = v end)
+local trace_detail = false trackers.register("publications.detail", function(v) trace_detail = v end)
+local trace_shorts = false trackers.register("publications.shorts", function(v) trace_shorts = v end)
+
+publications = publications or { }
+local datasets = publications.datasets
+local writers = publications.writers
+local casters = publications.casters
+local detailed = publications.detailed
+local enhancer = publications.enhancer
+local enhancers = publications.enhancers
+
+local tracers = publications.tracers or { }
+publications.tracers = tracers
+
+local variables = interfaces.variables
+
+local v_local = variables["local"]
+local v_global = variables["global"]
+
+local v_force = variables.force
+local v_none = variables.none
+local v_yes = variables.yes
+local v_all = variables.all
+local v_always = variables.always
+local v_doublesided = variables.doublesided
+local v_default = variables.default
+local v_dataset = variables.dataset
+
+local conditionals = tex.conditionals
+
+local numbertochar = converters.characters
+
+local logsnewline = logs.newline
+local logspushtarget = logs.pushtarget
+local logspoptarget = logs.poptarget
+
+local isdefined = tex.isdefined
+
+----- basicsorter = sorters.basicsorter -- (a,b)
+----- sortstripper = sorters.strip
+----- sortsplitter = sorters.splitters.utf
+
+local manipulators = typesetters.manipulators
+local splitmanipulation = manipulators.splitspecification
+local applymanipulation = manipulators.applyspecification
+local manipulatormethods = manipulators.methods
+
+-- this might move elsewhere
+
+manipulatormethods.Word = converters.Word
+manipulatormethods.WORD = converters.WORD
+manipulatormethods.Words = converters.Words
+manipulatormethods.WORDS = converters.WORDS
local context = context
+local commands = commands
+local implement = interfaces.implement
+local ctx_setmacro = interfaces.setmacro
+
+local ctx_doifelse = commands.doifelse
+local ctx_doif = commands.doif
+local ctx_doifnot = commands.doifnot
+local ctx_gobbletwoarguments = context.gobbletwoarguments
-local ctx_setvalue = context.setvalue
-local ctx_firstoftwoarguments = context.firstoftwoarguments
-local ctx_secondoftwoarguments = context.secondoftwoarguments
-local ctx_firstofoneargument = context.firstofoneargument
-local ctx_gobbleoneargument = context.gobbleoneargument
------ ctx_directsetup = context.directsetup
-
-local ctx_btxlistparameter = context.btxlistparameter
-local ctx_btxcitevariantparameter = context.btxcitevariantparameter
-local ctx_btxlistvariantparameter = context.btxlistvariantparameter
-local ctx_btxdomarkcitation = context.btxdomarkcitation
local ctx_btxdirectlink = context.btxdirectlink
local ctx_btxhandlelistentry = context.btxhandlelistentry
+local ctx_btxhandlelisttextentry = context.btxhandlelisttextentry
local ctx_btxchecklistentry = context.btxchecklistentry
local ctx_btxchecklistcombi = context.btxchecklistcombi
-local ctx_btxsetcitereference = context.btxsetcitereference
-local ctx_btxsetlistreference = context.btxsetlistreference
-local ctx_btxmissing = context.btxmissing
+local ctx_btxsetdataset = context.btxsetdataset
local ctx_btxsettag = context.btxsettag
+local ctx_btxsetnumber = context.btxsetnumber
+local ctx_btxsetlanguage = context.btxsetlanguage
+local ctx_btxsetcombis = context.btxsetcombis
+local ctx_btxsetcategory = context.btxsetcategory
local ctx_btxcitesetup = context.btxcitesetup
+local ctx_btxsubcitesetup = context.btxsubcitesetup
+local ctx_btxpagesetup = context.btxpagesetup
local ctx_btxsetfirst = context.btxsetfirst
local ctx_btxsetsecond = context.btxsetsecond
+local ctx_btxsetthird = context.btxsetthird
local ctx_btxsetinternal = context.btxsetinternal
+local ctx_btxsetlefttext = context.btxsetlefttext
+local ctx_btxsetrighttext = context.btxsetrighttext
+local ctx_btxsetbefore = context.btxsetbefore
+local ctx_btxsetafter = context.btxsetafter
+local ctx_btxsetbacklink = context.btxsetbacklink
+local ctx_btxsetbacktrace = context.btxsetbacktrace
+local ctx_btxsetcount = context.btxsetcount
local ctx_btxsetconcat = context.btxsetconcat
+local ctx_btxsetoveflow = context.btxsetoverflow
+local ctx_btxsetfirstpage = context.btxsetfirstpage
+local ctx_btxsetlastpage = context.btxsetlastpage
+local ctx_btxsetfirstinternal = context.btxsetfirstinternal
+local ctx_btxsetlastinternal = context.btxsetlastinternal
+local ctx_btxstartcite = context.btxstartcite
+local ctx_btxstopcite = context.btxstopcite
+local ctx_btxstartciteauthor = context.btxstartciteauthor
+local ctx_btxstopciteauthor = context.btxstopciteauthor
local ctx_btxstartsubcite = context.btxstartsubcite
local ctx_btxstopsubcite = context.btxstopsubcite
+local ctx_btxstartlistentry = context.btxstartlistentry
+local ctx_btxstoplistentry = context.btxstoplistentry
+local ctx_btxlistsetup = context.btxlistsetup
+local ctx_btxflushauthor = context.btxflushauthor
+local ctx_btxsetnoflistentries = context.btxsetnoflistentries
+local ctx_btxsetcurrentlistentry = context.btxsetcurrentlistentry
+local ctx_btxsetcurrentlistindex = context.btxsetcurrentlistindex
+
+languages.data = languages.data or { }
+local data = languages.data
+
+local specifications = publications.specifications
+local currentspecification = specifications[false]
+local ignoredfields = { }
+publications.currentspecification = currentspecification
+
+local function setspecification(name)
+ currentspecification = specifications[name]
+ if trace then
+ report("setting specification %a",type(name) == "string" and name or "anything")
+ end
+ publications.currentspecification = currentspecification
+end
+
+publications.setspecification = setspecification
+
+implement {
+ name = "btxsetspecification",
+ actions = setspecification,
+ arguments = "string",
+}
+
+local optionalspace = lpeg.patterns.whitespace^0
+local prefixsplitter = optionalspace * lpeg.splitat(optionalspace * P("::") * optionalspace)
statistics.register("publications load time", function()
local publicationsstats = publications.statistics
local nofbytes = publicationsstats.nofbytes
if nofbytes > 0 then
return string.format("%s seconds, %s bytes, %s definitions, %s shortcuts",
- statistics.elapsedtime(publications),nofbytes,publicationsstats.nofdefinitions,publicationsstats.nofshortcuts)
+ statistics.elapsedtime(publications),
+ nofbytes,
+ publicationsstats.nofdefinitions or 0,
+ publicationsstats.nofshortcuts or 0
+ )
else
return nil
end
@@ -145,7 +199,6 @@ end)
luatex.registerstopactions(function()
local done = false
- local undefined = csname_id("undefined*crap")
for name, dataset in sortedhash(datasets) do
for command, n in sortedhash(dataset.commands) do
if not done then
@@ -155,16 +208,12 @@ luatex.registerstopactions(function()
logsnewline()
done = true
end
- local c = csname_id(command)
- if c and c ~= undefined then
+ if isdefined[command] then
report("%-20s %-20s % 5i %s",name,command,n,"known")
+ elseif isdefined[upper(command)] then
+ report("%-20s %-20s % 5i %s",name,command,n,"KNOWN")
else
- local u = csname_id(utf.upper(command))
- if u and u ~= undefined then
- report("%-20s %-20s % 5i %s",name,command,n,"KNOWN")
- else
- report("%-20s %-20s % 5i %s",name,command,n,"unknown")
- end
+ report("%-20s %-20s % 5i %s",name,command,n,"unknown")
end
end
end
@@ -182,638 +231,1244 @@ end)
local collected = allocate()
local tobesaved = allocate()
--- we use a a dedicated (and efficient as it know what it deals with) serializer,
--- also because we need to ignore the 'details' field
-
-local function serialize(t)
- local f_key_table = formatters[" [%q] = {"]
- local f_key_string = formatters[" %s = %q,"]
- local r = { "return {" }
- local m = 1
- for tag, entry in sortedhash(t) do
- m = m + 1
- r[m] = f_key_table(tag)
- local s = sortedkeys(entry)
- for i=1,#s do
- local k = s[i]
- -- if k ~= "details" then
+do
+
+ local function serialize(t)
+ local f_key_table = formatters[" [%q] = {"]
+ local f_key_string = formatters[" %s = %q,"]
+ local r = { "return {" }
+ local m = 1
+ for tag, entry in sortedhash(t) do
+ m = m + 1
+ r[m] = f_key_table(tag)
+ local s = sortedkeys(entry)
+ for i=1,#s do
+ local k = s[i]
m = m + 1
r[m] = f_key_string(k,entry[k])
- -- end
+ end
+ m = m + 1
+ r[m] = " },"
end
- m = m + 1
- r[m] = " },"
- end
- r[m] = "}"
- return concat(r,"\n")
-end
-
-local function finalizer()
- local prefix = tex.jobname -- or environment.jobname
- local setnames = sortedkeys(datasets)
- for i=1,#setnames do
- local name = setnames[i]
- local dataset = datasets[name]
- local userdata = dataset.userdata
- local checksum = nil
- local username = file.addsuffix(file.robustname(formatters["%s-btx-%s"](prefix,name)),"lua")
- if userdata and next(userdata) then
- if job.passes.first then
- local newdata = serialize(userdata)
- checksum = md5.HEX(newdata)
- io.savedata(username,newdata)
+ r[m] = "}"
+ return concat(r,"\n")
+ end
+
+ local function finalizer()
+ local prefix = tex.jobname -- or environment.jobname
+ local setnames = sortedkeys(datasets)
+ for i=1,#setnames do
+ local name = setnames[i]
+ local dataset = datasets[name]
+ local userdata = dataset.userdata
+ local checksum = nil
+ local username = file.addsuffix(file.robustname(formatters["%s-btx-%s"](prefix,name)),"lua")
+ if userdata and next(userdata) then
+ if job.passes.first then
+ local newdata = serialize(userdata)
+ checksum = md5.HEX(newdata)
+ io.savedata(username,newdata)
+ end
+ else
+ os.remove(username)
+ username = nil
end
- else
- os.remove(username)
- username = nil
- end
- local loaded = dataset.loaded
- local sources = dataset.sources
- local used = { }
- for i=1,#sources do
- local source = sources[i]
- if loaded[source.filename] ~= "previous" then -- or loaded[source.filename] == "current"
- used[#used+1] = source
- end
- end
- tobesaved[name] = {
- usersource = {
- filename = username,
- checksum = checksum,
- },
- datasources = used,
- }
+ local loaded = dataset.loaded
+ local sources = dataset.sources
+ local used = { }
+ for i=1,#sources do
+ local source = sources[i]
+ -- if loaded[source.filename] ~= "previous" then -- needs checking
+ if loaded[source.filename] ~= "previous" or loaded[source.filename] == "current" then
+ used[#used+1] = source
+ end
+ end
+ tobesaved[name] = {
+ usersource = {
+ filename = username,
+ checksum = checksum,
+ },
+ datasources = used,
+ }
+ end
end
-end
-local function initializer()
- statistics.starttiming(publications)
-collected = publications.collected or collected -- for the moment as we load runtime
- for name, state in next, collected do
- local dataset = datasets[name]
- local datasources = state.datasources
- local usersource = state.usersource
- if datasources then
- for i=1,#datasources do
- local filename = datasources[i].filename
- publications.load(dataset,filename,"previous")
+ local function initializer()
+ statistics.starttiming(publications)
+ for name, state in next, collected do
+ local dataset = datasets[name]
+ local datasources = state.datasources
+ local usersource = state.usersource
+ if datasources then
+ for i=1,#datasources do
+ local filename = datasources[i].filename
+ publications.load {
+ dataset = dataset,
+ filename = filename,
+ kind = "previous"
+ }
+ end
+ end
+ if usersource then
+ dataset.userdata = table.load(usersource.filename) or { }
end
end
- if usersource then
- dataset.userdata = table.load(usersource.filename) or { }
- end
+ statistics.stoptiming(publications)
+ function initializer() end -- will go, for now, runtime loaded
end
- statistics.stoptiming(publications)
- function initializer() end -- will go, for now, runtime loaded
-end
-job.register('publications.collected',tobesaved,initializer,finalizer)
+ job.register('publications.collected',tobesaved,initializer,finalizer)
-if not publications.authors then
- initializer() -- for now, runtime loaded
end
-local usedentries = { }
-local initialized = false
-
--- {
--- ["metadata"]=1,
--- ["references"]={
--- ["block"]="bodypart",
--- ["internal"]=2,
--- ["realpage"]=1,
--- ["section"]=0,
--- },
--- ["userdata"]={
--- ["btxref"]="Cleveland1985",
--- ["btxset"]="standard",
--- },
--- },
-
-setmetatableindex(usedentries,function(t,k)
- if not initialized then
- usedentries = { }
+-- we want to minimize references as there can be many (at least
+-- when testing)
+
+local nofcitations = 0
+local usedentries = nil
+local citetolist = nil
+local listtocite = nil
+local listtolist = nil
+
+do
+
+ local initialize = nil
+
+ initialize = function(t)
+ usedentries = allocate { }
+ citetolist = allocate { }
+ listtocite = allocate { }
+ listtolist = allocate { }
+ local names = { }
local internals = structures.references.internals
+ local p_collect = (C(R("09")^1) * Carg(1) / function(s,entry) listtocite[tonumber(s)] = entry end + P(1))^0
+ local nofunique = 0
+ local nofreused = 0
for i=1,#internals do
local entry = internals[i]
- local metadata = entry.metadata
- if metadata.kind == "full" then
- local userdata = entry.userdata
- if userdata then
- local set = userdata.btxset
- if set then
- local tag = userdata.btxref
- local s = usedentries[set]
- if s then
- local u = s[tag]
- if u then
- u[#u+1] = entry
- else
- u = { entry }
- s[tag] = u
+ if entry then
+ local metadata = entry.metadata
+ if metadata then
+ local kind = metadata.kind
+ if kind == "full" then
+ -- reference (in list)
+ local userdata = entry.userdata
+ if userdata then
+ local tag = userdata.btxref
+ if tag then
+ local set = userdata.btxset or v_default
+ local s = usedentries[set]
+ if s then
+ local u = s[tag]
+ if u then
+ u[#u+1] = entry
+ else
+ s[tag] = { entry }
+ end
+ nofreused = nofreused + 1
+ else
+ usedentries[set] = { [tag] = { entry } }
+ nofunique = nofunique + 1
+ end
+ -- alternative: collect prev in group
+ local bck = userdata.btxbck
+ if bck then
+ lpegmatch(p_collect,bck,1,entry) -- for s in string.gmatch(bck,"[^ ]+") do listtocite[tonumber(s)] = entry end
+ local lst = tonumber(userdata.btxlst)
+ if lst then
+ listtolist[lst] = entry
+ end
+ else
+ local int = tonumber(userdata.btxint)
+ if int then
+ listtocite[int] = entry
+ end
+ end
+ local detail = datasets[set].details[tag]
+-- todo: these have to be pluggable
+ if detail then
+ local author = detail.author
+ if author then
+ for i=1,#author do
+ local a = author[i]
+ local s = a.surnames
+ if s then
+ local c = concat(s,"+")
+ local n = names[c]
+ if n then
+ n[#n+1] = a
+ break
+ else
+ names[c] = { a }
+ end
+ end
+ end
+ end
+ end
end
- else
- usedentries[set] = { [tag] = { entry } }
end
+ elseif kind == "btx" or kind == "userdata" then -- will go: kind == "userdata"
+ -- list entry (each cite)
+ local userdata = entry.userdata
+ if userdata then
+ local int = tonumber(userdata.btxint)
+ if int then
+ citetolist[int] = entry
+ end
+ end
+ end
+ end
+ else
+ -- weird
+ end
+ end
+ for k, v in next, names do
+ local n = #v
+ if n > 1 then
+ local original = v[1].original
+ for i=2,n do
+ if original ~= v[i].original then
+ report("potential clash in name %a",k)
+ for i=1,n do
+ v[i].state = 1
+ end
+ break
end
end
end
end
- return usedentries[k]
+ if trace_detail then
+ report("%s unique bibentries: %s reused entries",nofunique,nofreused)
+ end
+ initialize = nil
end
-end)
--- local subsets = nil
--- local block = tex.count.btxblock
--- local collected = references.collected
--- local prefix = nil -- todo: dataset ?
--- if prefix and prefix ~= "" then
--- subsets = { collected[prefix] or collected[""] }
--- else
--- local components = references.productdata.components
--- local subset = collected[""]
--- if subset then
--- subsets = { subset }
--- else
--- subsets = { }
--- end
--- for i=1,#components do
--- local subset = collected[components[i]]
--- if subset then
--- subsets[#subsets+1] = subset
--- end
--- end
--- end
--- if #subsets == 0 then
--- subsets = { collected[""] }
--- end
--- local list = type(reference) == "string" and settings_to_array(reference) or reference
--- local todo = table.tohash(list)
--- if #subsets > 0 then
--- local result, nofresult, done = { }, 0, { }
--- for i=1,#subsets do
--- local subset = subsets[i]
--- for i=1,#list do
--- local rest = list[i]
--- local blk, tag, found = block, nil, nil
--- if block then
--- tag = f_destination(dataset,blk,rest)
--- found = subset[tag]
--- if not found then
--- for i=block-1,1,-1 do
--- tag = f_destination(dataset,i,rest)
--- found = subset[tag]
--- if found then
--- blk = i
--- break
--- end
--- end
--- end
--- end
--- if not found then
--- blk = "*"
--- tag = f_destination(dataset,blk,rest)
--- found = subset[tag]
--- end
--- if found then
--- local entries = found.entries
--- if entries then
--- local current = tonumber(entries.text) -- todo: no ranges when no tonumber
--- if current and not done[current] then
--- nofresult = nofresult + 1
--- result[nofresult] = { blk, rest, current, found.references.internal }
--- done[current] = true
--- end
--- end
--- end
--- end
--- end
-
-local reported = { }
-local finder = publications.finder
-
-local function findallused(dataset,reference,block,section)
-local finder = publications.finder
- local find = finder and finder(reference)
- local tags = not find and settings_to_array(reference)
- local todo = { }
- local okay = { } -- only if mark
- local set = usedentries[dataset]
- local valid = datasets[dataset].luadata
- if set then
- local function register(tag)
- local entry = set[tag]
- if entry then
- -- only once in a list
- if #entry == 1 then
- entry = entry[1]
+ usedentries = setmetatableindex(function(_,k) if initialize then initialize() end return usedentries[k] end)
+ citetolist = setmetatableindex(function(_,k) if initialize then initialize() end return citetolist [k] end)
+ listtocite = setmetatableindex(function(_,k) if initialize then initialize() end return listtocite [k] end)
+ listtolist = setmetatableindex(function(_,k) if initialize then initialize() end return listtolist [k] end)
+
+ function publications.usedentries()
+ if initialize then
+ initialize()
+ end
+ return usedentries
+ end
+
+end
+
+-- match:
+--
+-- [current|previous|following] section
+-- [current|previous|following] block
+-- [current|previous|following] component
+--
+-- by prefix
+-- by dataset
+
+local findallused do
+
+ local reported = { }
+ local finder = publications.finder
+
+ findallused = function(dataset,reference,internal)
+ local current = datasets[dataset]
+ local finder = publications.finder -- for the moment, not yet in all betas
+ local find = finder and finder(current,reference)
+ local tags = not find and settings_to_array(reference)
+ local todo = { }
+ local okay = { } -- only if mark
+ local set = usedentries[dataset]
+ local valid = current.luadata
+ local ordered = current.ordered
+ if set then
+ local registered = { }
+ local function register(tag)
+ if registered[tag] then
+ return
else
- -- find best match (todo)
- entry = entry[1] -- for now
+ registered[tag] = true
+ end
+ local entry = set[tag]
+ if entry then
+ -- only once in a list but at some point we can have more (if we
+ -- decide to duplicate)
+ if #entry == 1 then
+ entry = entry[1]
+ else
+ -- same block and section
+ local done = false
+ if internal and internal > 0 then
+ -- first following in list
+ for i=1,#entry do
+ local e = entry[i]
+ if e.references.internal > internal then
+ done = e
+ break
+ end
+ end
+ if not done then
+ -- last preceding in list
+ for i=1,#entry do
+ local e = entry[i]
+ if e.references.internal < internal then
+ done = e
+ else
+ break
+ end
+ end
+ end
+ end
+ if done then
+ entry = done
+ else
+ entry = entry[1]
+ end
+ end
+ okay[#okay+1] = entry
end
- okay[#okay+1] = entry
+ todo[tag] = true
end
- todo[tag] = true
- end
- if find then
- tags = { }
- for tag, entry in next, valid do
- local found = find(entry)
- if found then
+ if reference == "*" then
+ tags = { }
+ for i=1,#ordered do
+ local tag = ordered[i].tag
register(tag)
tags[#tags+1] = tag
end
- end
- else
- for i=1,#tags do
- local tag = tags[i]
- if valid[tag] then
- register(tag)
- elseif not reported[tag] then
- reported[tag] = true
- report_cite("non-existent entry %a in %a",tag,dataset)
+ elseif find then
+-- print("case 1.1")
+ tags = { }
+ for i=1,#ordered do
+ local entry = ordered[i]
+ if find(entry) then
+ local tag = entry.tag
+ register(tag)
+ tags[#tags+1] = tag
+ end
end
- end
- end
- else
- if find then
- tags = { }
- for tag, entry in next, valid do
- local found = find(entry)
- if found then
- todo[tag] = true
- tags[#tags+1] = tag
+ if #tags == 0 and not reported[reference] then
+ tags[1] = reference
+ reported[reference] = true
+ end
+ else
+-- print("case 1.2")
+ for i=1,#tags do
+ local tag = tags[i]
+ if valid[tag] then
+ register(tag)
+ elseif not reported[tag] then
+ reported[tag] = true
+ report_cite("non-existent entry %a in %a",tag,dataset)
+ end
end
end
else
- for i=1,#tags do
- local tag = tags[i]
- if valid[tag] then
- todo[tag] = true
- elseif not reported[tag] then
- reported[tag] = true
- report_cite("non-existent entry %a in %a",tag,dataset)
+ if find then
+-- print("case 2.1")
+ tags = { }
+ for i=1,#ordered do
+ local entry = ordered[i]
+ if find(entry) then
+ local tag = entry.tag
+ tags[#tags+1] = tag
+ todo[tag] = true
+ end
+ end
+ if #tags == 0 and not reported[reference] then
+ tags[1] = reference
+ reported[reference] = true
+ end
+ else
+-- print("case 2.2")
+ for i=1,#tags do
+ local tag = tags[i]
+ if valid[tag] then
+ todo[tag] = true
+ elseif not reported[tag] then
+ reported[tag] = true
+ report_cite("non-existent entry %a in %a",tag,dataset)
+ end
end
end
end
+ return okay, todo, tags
end
- return okay, todo, tags
+
end
-local function flushcollected(flush,nofcollected)
- if nofcollected > 0 then
- flush(1,1)
- if nofcollected > 2 then
- for i=2,nofcollected-1 do
- flush(i,2)
- end
- flush(nofcollected,3)
- elseif nofcollected > 1 then
- flush(nofcollected,4)
- end
+local function unknowncite(reference)
+ ctx_btxsettag(reference)
+ if trace_detail then
+ report("expanding %a cite setup %a","unknown","unknown")
+ end
+ ctx_btxcitesetup("unknown")
+end
+
+local concatstate = publications.concatstate
+
+local tobemarked = nil
+
+local function marknocite(dataset,tag,nofcitations,setup)
+ ctx_btxstartcite()
+ ctx_btxsetdataset(dataset)
+ ctx_btxsettag(tag)
+ ctx_btxsetbacklink(nofcitations)
+ if trace_detail then
+ report("expanding cite setup %a",setup)
end
+ ctx_btxcitesetup(setup)
+ ctx_btxstopcite()
end
-local function markcite(dataset,tag)
- if trace_cite then
- report_cite("mark, dataset: %s, tag: %s",dataset,tag)
+local function markcite(dataset,tag,flush)
+ if not tobemarked then
+ return 0
+ end
+ local citation = tobemarked[tag]
+ if not citation then
+ return 0
+ end
+ if citation == true then
+ nofcitations = nofcitations + 1
+ if trace_cite then
+ report_cite("mark, dataset: %s, tag: %s, number: %s, state: %s",dataset,tag,nofcitations,"cited")
+ end
+ if flush then
+ marknocite(dataset,tag,nofcitations,"nocite")
+ end
+ tobemarked[tag] = nofcitations
+ return nofcitations
+ else
+ return citation
end
- ctx_btxdomarkcitation(dataset,tag)
end
+local marked_dataset = nil
+local marked_list = nil
+
local function flushmarked(dataset,list,todo)
- if todo then
- for i=1,#list do
- local tag = list[i]
- if todo[tag] then
- markcite(dataset,tag)
+ marked_dataset = dataset
+ marked_list = list
+end
+
+local function btxflushmarked()
+ if marked_list and tobemarked then
+ for i=1,#marked_list do
+ -- keep order
+ local tag = marked_list[i]
+ local tbm = tobemarked[tag]
+ if tbm == true or not tbm then
+ nofcitations = nofcitations + 1
+ marknocite(marked_dataset,tag,nofcitations,tbm and "nocite" or "invalid")
+ if trace_cite then
+ report_cite("mark, dataset: %s, tag: %s, number: %s, state: %s",marked_dataset,tag,nofcitations,tbm and "unset" or "invalid")
+ end
end
end
end
+ tobemarked = nil
+ marked_dataset = nil
+ marked_list = nil
end
+implement { name = "btxflushmarked", actions = btxflushmarked }
+
-- basic access
-local function getfield(dataset,tag,name)
+local function getfield(dataset,tag,name) -- for the moment quick and dirty
local d = datasets[dataset].luadata[tag]
return d and d[name]
end
-local function getdetail(dataset,tag,name)
+local function getdetail(dataset,tag,name) -- for the moment quick and dirty
local d = datasets[dataset].details[tag]
return d and d[name]
end
-function commands.btxsingularorplural(dataset,tag,name) -- todo: make field dependent
- local d = datasets[dataset].details[tag]
- if d then
- d = d[name]
- end
- if d then
- d = #d <= 1
- end
- commands.doifelse(d)
-end
-
--- basic loading
-
-function commands.usebtxdataset(name,filename)
- publications.load(datasets[name],filename,"current")
-end
-
-function commands.convertbtxdatasettoxml(name,nice)
- publications.converttoxml(datasets[name],nice)
-end
-
--- enhancing
-
-local splitauthorstring = publications.authors.splitstring
-
-local pagessplitter = lpeg.splitat(P("-")^1)
-
--- maybe not redo when already done
-
-function publications.enhance(dataset) -- for the moment split runs (maybe publications.enhancers)
- statistics.starttiming(publications)
- if type(dataset) == "string" then
- dataset = datasets[dataset]
- end
- local luadata = dataset.luadata
- local details = dataset.details
- -- author, editor
- for tag, entry in next, luadata do
- local author = entry.author
- local editor = entry.editor
- details[tag] = {
- author = author and splitauthorstring(author),
- editor = editor and splitauthorstring(editor),
- }
- end
- -- short
- local shorts = { }
- for tag, entry in next, luadata do
- local author = details[tag].author
- if author then
- -- number depends on sort order
- local t = { }
- if #author == 0 then
- -- what
- else
- local n = #author == 1 and 3 or 1
- for i=1,#author do
- local surnames = author[i].surnames
- if not surnames or #surnames == 0 then
- -- error
- else
- t[#t+1] = utfsub(surnames[1],1,n)
+local function getcasted(dataset,tag,field,specification)
+ local current = datasets[dataset]
+ if current then
+ local data = current.luadata[tag]
+ if data then
+ local category = data.category
+ if not specification then
+ specification = currentspecification
+ end
+ local catspec = specification.categories[category]
+ if not catspec then
+ return false
+ end
+ local fields = catspec.fields
+ if fields then
+ local sets = catspec.sets
+ if sets then
+ local set = sets[field]
+ if set then
+ for i=1,#set do
+ local field = set[i]
+ local value = fields[field] and data[field] -- redundant check
+ if value then
+ local kind = specification.types[field]
+ return detailed[kind][value], field, kind
+ end
+ end
end
end
+ local value = fields[field] and data[field] -- redundant check
+ if value then
+ local kind = specification.types[field]
+ return detailed[kind][value], field, kind
+ end
end
- local year = tonumber(entry.year) or 0
- local short = formatters["%t%02i"](t,math.mod(year,100))
- local s = shorts[short]
- if not s then
- shorts[short] = tag
- elseif type(s) == "string" then
- shorts[short] = { s, tag }
- else
- s[#s+1] = tag
+ local data = current.details[tag]
+ if data then
+ local kind = specification.types[field]
+ return data[field], field, kind -- no check
end
- else
- --
end
end
- for short, tags in next, shorts do
- if type(tags) == "table" then
- sort(tags)
- for i=1,#tags do
- -- details[tags[i]].short = short .. numbertochar(i)
- local detail = details[tags[i]]
- detail.short = short
- detail.suffix = numbertochar(i)
+end
+
+local function getfaster(current,data,details,field,categories,types)
+ local category = data.category
+ local catspec = categories[category]
+ if not catspec then
+ return false
+ end
+ local fields = catspec.fields
+ if fields then
+ local sets = catspec.sets
+ if sets then
+ local set = sets[field]
+ if set then
+ for i=1,#set do
+ local field = set[i]
+ local value = fields[field] and data[field] -- redundant check
+ if value then
+ local kind = types[field]
+ return detailed[kind][value], field, kind
+ end
+ end
end
- else
- details[tags].short = short
end
- end
- -- pages
- for tag, entry in next, luadata do
- local pages = entry.pages
- if pages then
- local first, last = lpegmatch(pagessplitter,pages)
- details[tag].pages = first and last and { first, last } or pages
+ local value = fields[field] and data[field] -- redundant check
+ if value then
+ local kind = types[field]
+ return detailed[kind][value]
end
end
- -- keywords
- for tag, entry in next, luadata do
- local keyword = entry.keyword
- if keyword then
- details[tag].keyword = settings_to_set(keyword)
- end
+ if details then
+ local kind = types[field]
+ return details[field]
end
- statistics.stoptiming(publications)
end
-function commands.addbtxentry(name,settings,content)
- local dataset = datasets[name]
- if dataset then
- publications.addtexentry(dataset,settings,content)
+local function getdirect(dataset,data,field,catspec) -- no field check, no dataset check
+ local catspec = (catspec or currentspecification).categories[data.category]
+ if not catspec then
+ return false
end
-end
-
-function commands.setbtxdataset(name)
- local dataset = rawget(datasets,name)
- if dataset then
- context(name)
- else
- report("unknown dataset %a",name)
+ local fields = catspec.fields
+ if fields then
+ local sets = catspec.sets
+ if sets then
+ local set = sets[field]
+ if set then
+ for i=1,#set do
+ local field = set[i]
+ local value = fields[field] and data[field] -- redundant check
+ if value then
+ return value
+ end
+ end
+ end
+ end
+ return fields[field] and data[field] or nil -- redundant check
end
end
-function commands.setbtxentry(name,tag)
- local dataset = rawget(datasets,name)
- if dataset then
- if dataset.luadata[tag] then
- context(tag)
- else
- report("unknown tag %a in dataset %a",tag,name)
+local function getfuzzy(data,field,categories) -- no field check, no dataset check
+ local catspec
+ if categories then
+ local category = data.category
+ if category then
+ catspec = categories[data.category]
end
- else
- report("unknown dataset %a",name)
+ end
+ if not field then
+ return
+ elseif not catspec then
+ return data[field]
+ end
+ local fields = catspec.fields
+ if fields then
+ local sets = catspec.sets
+ if sets then
+ local set = sets[field]
+ if set then
+ for i=1,#set do
+ local field = set[i]
+ local value = fields[field] and data[field] -- redundant check
+ if value then
+ return value
+ end
+ end
+ end
+ end
+ return fields[field] and data[field] or nil -- redundant check
end
end
--- rendering of fields (maybe multiple manipulators)
+publications.getfield = getfield
+publications.getdetail = getdetail
+publications.getcasted = getcasted
+publications.getfaster = getfaster
+publications.getdirect = getdirect
+publications.getfuzzy = getfuzzy
--- local manipulation = utilities.parsers.manipulation
--- local manipulators = utilities.parsers.manipulators
---
--- local function checked(field)
--- local m, f = lpegmatch(manipulation,field)
--- if m then
--- return manipulators[m], f or field
+-- this needs to be checked: a specific type should have a checker
+
+-- author pagenumber keyword url
+
+-- function commands.btxsingularorplural(dataset,tag,name)
+-- local d = getcasted(dataset,tag,name)
+-- if type(d) == "table" then
+-- d = #d <= 1
-- else
--- return nil, field
+-- d = true
-- end
+-- ctx_doifelse(d)
-- end
-local manipulation = Ct((C((1-P("->"))^1) * P("->"))^1) * C(P(1)^0)
-local manipulators = utilities.parsers.manipulators
+-- function commands.oneorrange(dataset,tag,name)
+-- local d = datasets[dataset].luadata[tag] -- details ?
+-- if d then
+-- d = d[name]
+-- end
+-- if type(d) == "string" then
+-- d = find(d,"%-")
+-- else
+-- d = false
+-- end
+-- ctx_doifelse(not d) -- so singular is default
+-- end
-local function checked(field)
- local m, f = lpegmatch(manipulation,field)
- if m then
- return m, f or field
- else
- return nil, field
- end
+-- function commands.firstofrange(dataset,tag,name)
+-- local d = datasets[dataset].luadata[tag] -- details ?
+-- if d then
+-- d = d[name]
+-- end
+-- if type(d) == "string" then
+-- context(match(d,"([^%-]+)"))
+-- end
+-- end
+
+local inspectors = allocate()
+local nofmultiple = allocate()
+local firstandlast = allocate()
+
+publications.inspectors = inspectors
+inspectors.nofmultiple = nofmultiple
+inspectors.firstandlast = firstandlast
+
+function nofmultiple.author(d)
+ return type(d) == "table" and #d or 0
end
-local function manipulated(actions,str)
- for i=1,#actions do
- local action = manipulators[actions[i]]
- if action then
- str = action(str) or str
+function publications.singularorplural(dataset,tag,name)
+ local data, field, kind = getcasted(dataset,tag,name)
+ if data then
+ local test = nofmultiple[kind]
+ if test then
+ local n = test(data)
+ return not n or n < 2
end
end
- return str
+ return true
end
-function commands.btxflush(name,tag,field)
- local dataset = rawget(datasets,name)
- if dataset then
- local fields = dataset.luadata[tag]
- if fields then
- local manipulator, field = checked(field)
- local value = fields[field]
- if type(value) == "string" then
- local suffixes = dataset.suffixes[tag]
- if suffixes then
- local suffix = suffixes[field]
- if suffix then
- value = value .. converters.characters(suffix)
- end
- end
- context(manipulator and manipulated(manipulator,value) or value)
- return
- end
- local details = dataset.details[tag]
- if details then
- local value = details[field]
- if type(value) == "string" then
- local suffixes = dataset.suffixes[tag]
- if suffixes then
- local suffix = suffixes[field]
- if suffix then
- value = value .. converters.characters(suffix)
- end
- end
- context(manipulator and manipulated(manipulator,value) or value)
- return
- end
- end
- report("unknown field %a of tag %a in dataset %a",field,tag,name)
- else
- report("unknown tag %a in dataset %a",tag,name)
- end
- else
- report("unknown dataset %a",name)
+function firstandlast.range(d)
+ if type(d) == "table" then
+ return d[1], d[2]
end
end
-function commands.btxdetail(name,tag,field)
- local dataset = rawget(datasets,name)
- if dataset then
- local details = dataset.details[tag]
- if details then
- local manipulator, field = checked(field)
- local value = details[field]
- if type(value) == "string" then
- local suffixes = dataset.suffixes[tag]
- if suffixes then
- local suffix = suffixes[field]
- if suffix then
- value = value .. converters.characters(suffix)
- end
- end
- context(manipulator and manipulated(manipulator,value) or value)
- else
- report("unknown detail %a of tag %a in dataset %a",field,tag,name)
- end
- else
- report("unknown tag %a in dataset %a",tag,name)
+firstandlast.pagenumber = firstandlast.range
+
+function publications.oneorrange(dataset,tag,name)
+ local data, field, kind = getcasted(dataset,tag,name)
+ if data then
+ local test = firstandlast[kind]
+ if test then
+ local first, last = test(data)
+ return not (first and last)
end
- else
- report("unknown dataset %a",name)
end
+ return nil -- nothing at all
end
-function commands.btxfield(name,tag,field)
- local dataset = rawget(datasets,name)
- if dataset then
- local fields = dataset.luadata[tag]
- if fields then
- local manipulator, field = checked(field)
- local value = fields[field]
- if type(value) == "string" then
- local suffixes = dataset.suffixes[tag]
- if suffixes then
- local suffix = suffixes[field]
- if suffix then
- value = value .. converters.characters(suffix)
- end
- end
- context(manipulator and manipulated(manipulator,value) or value)
- else
- report("unknown field %a of tag %a in dataset %a",field,tag,name)
+function publications.firstofrange(dataset,tag,name)
+ local data, field, kind = getcasted(dataset,tag,name)
+ if data then
+ local test = firstandlast[kind]
+ if test then
+ local first = test(data)
+ if first then
+ return first
end
- else
- report("unknown tag %a in dataset %a",tag,name)
end
- else
- report("unknown dataset %a",name)
end
end
--- testing: to be speed up with testcase
-
-function commands.btxdoifelse(name,tag,field)
- local dataset = rawget(datasets,name)
- if dataset then
- local data = dataset.luadata[tag]
- local value = data and data[field]
- if value and value ~= "" then
- ctx_firstoftwoarguments()
- return
+function publications.lastofrange(dataset,tag,name)
+ local data, field, kind = getcasted(dataset,tag,name)
+ if data then
+ local test = firstandlast[kind]
+ if test then
+ local first, last = test(data)
+ if last then
+ return last
+ end
end
end
- ctx_secondoftwoarguments()
end
-function commands.btxdoif(name,tag,field)
- local dataset = rawget(datasets,name)
- if dataset then
- local data = dataset.luadata[tag]
- local value = data and data[field]
- if value and value ~= "" then
- ctx_firstofoneargument()
- return
- end
- end
- ctx_gobbleoneargument()
-end
+local three_strings = { "string", "string", "string" }
-function commands.btxdoifnot(name,tag,field)
- local dataset = rawget(datasets,name)
- if dataset then
- local data = dataset.luadata[tag]
- local value = data and data[field]
- if value and value ~= "" then
- ctx_gobbleoneargument()
- return
+implement {
+ name = "btxsingularorplural",
+ actions = { publications.singularorplural, ctx_doifelse },
+ arguments = three_strings
+}
+
+implement {
+ name = "btxoneorrange",
+ actions = { publications.oneorrange, function(b) if b == nil then ctx_gobbletwoarguments() else ctx_doifelse(b) end end },
+ arguments = three_strings
+}
+
+implement {
+ name = "btxfirstofrange",
+ actions = { publications.firstofrange, context },
+ arguments = three_strings
+}
+
+implement {
+ name = "btxlastofrange",
+ actions = { publications.lastofrange, context },
+ arguments = three_strings
+}
+
+-- basic loading
+
+function publications.usedataset(specification)
+ specification.kind = "current"
+ publications.load(specification)
+end
+
+implement {
+ name = "btxusedataset",
+ actions = publications.usedataset,
+ arguments = {
+ {
+ { "specification" },
+ { "dataset" },
+ { "filename" },
+ }
+ }
+}
+
+implement {
+ name = "convertbtxdatasettoxml",
+ arguments = { "string", true },
+ actions = publications.converttoxml
+}
+
+-- enhancing
+
+do
+
+ -- maybe not redo when already done
+
+ local function shortsorter(a,b)
+ local ay, by = a[2], b[2]
+ if ay ~= by then
+ return ay < by
+ end
+ local ay, by = a[3], b[3]
+ if ay ~= by then
+ -- bah, bah, bah
+ local an, bn = tonumber(ay), tonumber(by)
+ if an and bn then
+ return an < bn
+ else
+ return ay < by
+ end
+ end
+ return a[4] < b[4]
+ end
+
+ -- We could avoid loops by combining enhancers but that makes it only
+ -- more messy and for documents that use publications the few extra milli
+ -- seconds are irrelevant (there is for sure more to gain by proper coding
+ -- of the source and or style).
+
+ local f_short = formatters["%t%02i"]
+
+ function publications.enhancers.suffixes(dataset)
+ if not dataset then
+ return -- bad news
+ else
+ report("analyzing previous publication run for %a",dataset.name)
+ end
+ local used = usedentries[dataset.name]
+ if not used then
+ return -- probably a first run
+ end
+ local luadata = dataset.luadata
+ local details = dataset.details
+ local ordered = dataset.ordered
+ if not luadata or not details or not ordered then
+ report("nothing to be analyzed in %a",dataset.name)
+ return -- also bad news
+ end
+ local field = "author" -- currently only author
+ local shorts = { }
+ for i=1,#ordered do
+ local entry = ordered[i]
+ if entry then
+ local tag = entry.tag
+ if tag then
+ local use = used[tag]
+ if use then
+ -- use is a table of used list entries (so there can be more) and we just look at
+ -- the first one for btx properties
+ local listentry = use[1]
+ local userdata = listentry.userdata
+ local btxspc = userdata and userdata.btxspc
+ if btxspc then
+ -- this will become a specification entry
+ local author = getcasted(dataset,tag,field,specifications[btxspc])
+ if type(author) == "table" then
+ -- number depends on sort order
+ local t = { }
+ if #author > 0 then
+ local n = #author == 1 and 3 or 1
+ for i=1,#author do
+ local surnames = author[i].surnames
+ if not surnames or #surnames == 0 then
+ -- error
+ else
+ t[#t+1] = utfsub(surnames[1],1,n)
+ end
+ end
+ end
+ local year = tonumber(entry.year) or 0
+ local short = f_short(t,mod(year,100))
+ local s = shorts[short]
+ -- we could also sort on reference i.e. entries.text
+ if u then
+ u = listentry.entries.text -- hm
+ else
+ u = "0"
+ end
+ if not s then
+ shorts[short] = { { tag, year, u, i } }
+ else
+ s[#s+1] = { tag, year, u, i }
+ end
+ else
+ report("author typecast expected for field %a",field)
+ end
+ else
+ --- no spec so let's forget about it
+ end
+ end
+ end
+ end
+ end
+ -- for short, tags in next, shorts do -- ordered ?
+ for short, tags in sortedhash(shorts) do -- ordered ?
+ local n = #tags
+ if n == 0 then
+ -- skip
+ elseif n == 1 then
+ local tagdata = tags[1]
+ local tag = tagdata[1]
+ local detail = details[tag]
+ local entry = luadata[tag]
+ local year = entry.year
+ detail.short = short
+ if year then
+ detail.suffixedyear = year
+ end
+ if trace_shorts then
+ report_shorts("year %a, suffix %a, short %a, tag %a",year or "-","-",short,tag)
+ end
+ elseif n > 1 then
+ sort(tags,shortsorter)
+ for i=1,n do
+ local tagdata = tags[i]
+ local tag = tagdata[1]
+ local detail = details[tag]
+ local suffix = numbertochar(i)
+ local entry = luadata[tag]
+ local year = entry.year
+ detail.short = short
+ detail.suffix = suffix
+ if year then
+ detail.suffixedyear = year .. suffix
+ end
+ if trace_shorts then
+ report_shorts("year %a, suffix %a, short %a, tag %a",year or "-",suffix or "-",short,tag)
+ end
+ end
+ end
+ end
+ end
+
+ utilities.sequencers.appendaction(enhancer,"system","publications.enhancers.suffixes")
+
+end
+
+implement {
+ name = "btxaddentry",
+ actions = function(name,settings,content)
+ local dataset = datasets[name]
+ if dataset then
+ publications.addtexentry(dataset,settings,content)
+ end
+ end,
+ arguments = { "string", "string", "string" }
+}
+
+function publications.checkeddataset(name,default)
+ local dataset = rawget(datasets,name)
+ if dataset then
+ return name
+ elseif default and default ~= "" then
+ return default
+ else
+ report("unknown dataset %a, forcing %a",name,v_default)
+ return v_default
+ end
+end
+
+implement {
+ name = "btxsetdataset",
+ actions = { publications.checkeddataset, context },
+ arguments = { "string", "string"}
+}
+
+implement {
+ name = "btxsetentry",
+ actions = function(name,tag)
+ local dataset = rawget(datasets,name)
+ if dataset then
+ if dataset.luadata[tag] then
+ context(tag)
+ else
+ report("unknown tag %a in dataset %a",tag,name)
+ end
+ else
+ report("unknown dataset %a",name)
+ end
+ end,
+ arguments = { "string", "string" },
+}
+
+-- rendering of fields
+
+do
+
+ local typesetters = { }
+ publications.typesetters = typesetters
+
+ local function defaulttypesetter(field,value,manipulator)
+ if value and value ~= "" then
+ value = tostring(value)
+ context(manipulator and applymanipulation(manipulator,value) or value)
+ end
+ end
+
+ setmetatableindex(typesetters,function(t,k)
+ local v = defaulttypesetter
+ t[k] = v
+ return v
+ end)
+
+ function typesetters.string(field,value,manipulator)
+ if value and value ~= "" then
+ context(manipulator and applymanipulation(manipulator,value) or value)
+ end
+ end
+
+ function typesetters.author(field,value,manipulator)
+ ctx_btxflushauthor(field)
+ end
+
+ -- function typesetters.url(field,value,manipulator)
+ -- ....
+ -- end
+
+ -- if there is no specification then we're in trouble but there is
+ -- always a default anyway
+ --
+ -- there's also always a fields table but it can be empty due to
+ -- lack of specifications
+ --
+ -- then there can be cases where we have no specification for instance
+ -- when we have a special kind of database
+
+ local splitter = lpeg.splitat(":")
+
+ local function permitted(category,field)
+ local catspec = currentspecification.categories[category]
+ if not catspec then
+ report("invalid category %a, %s",category,"no specification") -- can't happen
+ return false
+ end
+ local fields = catspec.fields
+ if not fields then
+ report("invalid category %a, %s",category,"no fields") -- can't happen
+ return false
+ end
+ if ignoredfields and ignoredfields[field] then
+ return false
+ end
+ local virtualfields = currentspecification.virtualfields
+ if virtualfields and virtualfields[field] then
+ return true
+ end
+ local sets = catspec.sets
+ if sets then
+ local set = sets[field]
+ if set then
+ return set
+ end
+ end
+ if fields[field] then
+ return true
+ end
+ local f, l = lpegmatch(splitter,field)
+ if f and l and fields[f] then
+ return true -- language specific one
+ end
+ end
+
+ local function found(dataset,tag,field,valid,fields)
+ if valid == true then
+ -- local fields = dataset.luadata[tag]
+ local okay = fields[field]
+ if okay then
+ return field, okay
+ end
+ local details = dataset.details[tag]
+ local value = details[field]
+ if value then
+ return field, value
+ end
+ elseif valid then
+ -- local fields = dataset.luadata[tag]
+ for i=1,#valid do
+ local field = valid[i]
+ local value = fields[field]
+ if value then
+ return field, value
+ end
+ end
+ local details = dataset.details[tag]
+ for i=1,#valid do
+ local value = details[field]
+ if value then
+ return field, value
+ end
+ end
+ end
+ end
+
+ local function get(dataset,tag,field,what,check,catspec) -- somewhat more extensive
+ local current = rawget(datasets,dataset)
+ if current then
+ local data = current.luadata[tag]
+ if data then
+ local category = data.category
+ local catspec = (catspec or currentspecification).categories[category]
+ if not catspec then
+ return false
+ end
+ local fields = catspec.fields
+ if fields then
+ local sets = catspec.sets
+ if sets then
+ local set = sets[field]
+ if set then
+ if check then
+ for i=1,#set do
+ local field = set[i]
+ local kind = (not check or data[field]) and fields[field]
+ if kind then
+ return what and kind or field
+ end
+ end
+ elseif what then
+ local t = { }
+ for i=1,#set do
+ t[i] = fields[set[i]] or "unknown"
+ end
+ return concat(t,",")
+ else
+ return concat(set,",")
+ end
+ end
+ end
+ local kind = (not check or data[field]) and fields[field]
+ if kind then
+ return what and kind or field
+ end
+ end
+ end
+ end
+ return ""
+ end
+
+ publications.permitted = permitted
+ publications.found = found
+ publications.get = get
+
+ local function btxflush(name,tag,field)
+ local dataset = rawget(datasets,name)
+ if dataset then
+ local fields = dataset.luadata[tag]
+ if fields then
+ local manipulator, field = splitmanipulation(field)
+ local category = fields.category
+ local valid = permitted(category,field)
+ if valid then
+ local name, value = found(dataset,tag,field,valid,fields)
+ if value then
+ typesetters[currentspecification.types[name]](field,value,manipulator)
+ elseif trace_detail then
+ report("%s %s %a in category %a for tag %a in dataset %a","unknown","entry",field,category,tag,name)
+ end
+ elseif trace_detail then
+ report("%s %s %a in category %a for tag %a in dataset %a","invalid","entry",field,category,tag,name)
+ end
+ else
+ report("unknown tag %a in dataset %a",tag,name)
+ end
+ else
+ report("unknown dataset %a",name)
+ end
+ end
+
+ local function btxfield(name,tag,field)
+ local dataset = rawget(datasets,name)
+ if dataset then
+ local fields = dataset.luadata[tag]
+ if fields then
+ local category = fields.category
+ local manipulator, field = splitmanipulation(field)
+ if permitted(category,field) then
+ local value = fields[field]
+ if value then
+ typesetters[currentspecification.types[field]](field,value,manipulator)
+ elseif trace_detail then
+ report("%s %s %a in category %a for tag %a in dataset %a","unknown","field",field,category,tag,name)
+ end
+ elseif trace_detail then
+ report("%s %s %a in category %a for tag %a in dataset %a","invalid","field",field,category,tag,name)
+ end
+ else
+ report("unknown tag %a in dataset %a",tag,name)
+ end
+ else
+ report("unknown dataset %a",name)
+ end
+ end
+
+ local function btxdetail(name,tag,field)
+ local dataset = rawget(datasets,name)
+ if dataset then
+ local fields = dataset.luadata[tag]
+ if fields then
+ local details = dataset.details[tag]
+ if details then
+ local category = fields.category
+ local manipulator, field = splitmanipulation(field)
+ if permitted(category,field) then
+ local value = details[field]
+ if value then
+ typesetters[currentspecification.types[field]](field,value,manipulator)
+ elseif trace_detail then
+ report("%s %s %a in category %a for tag %a in dataset %a","unknown","detail",field,category,tag,name)
+ end
+ elseif trace_detail then
+ report("%s %s %a in category %a for tag %a in dataset %a","invalid","detail",field,category,tag,name)
+ end
+ else
+ report("no details for tag %a in dataset %a",tag,name)
+ end
+ else
+ report("unknown tag %a in dataset %a",tag,name)
+ end
+ else
+ report("unknown dataset %a",name)
+ end
+ end
+
+ local function btxdirect(name,tag,field)
+ local dataset = rawget(datasets,name)
+ if dataset then
+ local fields = dataset.luadata[tag]
+ if fields then
+ local manipulator, field = splitmanipulation(field)
+ local value = fields[field]
+ if value then
+ context(typesetters.default(field,value,manipulator))
+ elseif trace_detail then
+ report("field %a of tag %a in dataset %a has no value",field,tag,name)
+ end
+ else
+ report("unknown tag %a in dataset %a",tag,name)
+ end
+ else
+ report("unknown dataset %a",name)
+ end
+ end
+
+ local function okay(name,tag,field)
+ local dataset = rawget(datasets,name)
+ if dataset then
+ local fields = dataset.luadata[tag]
+ if fields then
+ local category = fields.category
+ local valid = permitted(category,field)
+ if valid then
+ local value, field = found(dataset,tag,field,valid,fields)
+ return value and value ~= ""
+ end
+ end
end
end
- ctx_firstofoneargument()
+
+ publications.okay = okay
+
+ implement { name = "btxfield", actions = btxfield, arguments = { "string", "string", "string" } }
+ implement { name = "btxdetail", actions = btxdetail, arguments = { "string", "string", "string" } }
+ implement { name = "btxflush", actions = btxflush, arguments = { "string", "string", "string" } }
+ implement { name = "btxdirect", actions = btxdirect, arguments = { "string", "string", "string" } }
+
+ implement { name = "btxfieldname", actions = { get, context }, arguments = { "string", "string", "string", false, false } }
+ implement { name = "btxfieldtype", actions = { get, context }, arguments = { "string", "string", "string", true, false } }
+ implement { name = "btxfoundname", actions = { get, context }, arguments = { "string", "string", "string", false, true } }
+ implement { name = "btxfoundtype", actions = { get, context }, arguments = { "string", "string", "string", true, true } }
+
+ implement { name = "btxdoifelse", actions = { okay, ctx_doifelse }, arguments = { "string", "string", "string" } }
+ implement { name = "btxdoif", actions = { okay, ctx_doif }, arguments = { "string", "string", "string" } }
+ implement { name = "btxdoifnot", actions = { okay, ctx_doifnot }, arguments = { "string", "string", "string" } }
+
end
-- -- alternative approach: keep data at the tex end
@@ -826,1124 +1481,1616 @@ function publications.singularorplural(singular,plural)
end
end
-local patterns = { "publ-imp-%s.mkiv", "publ-imp-%s.tex" }
+-- loading
-local function failure(name)
- report("unknown library %a",name)
-end
+do
-local function action(name,foundname)
- context.input(foundname)
-end
+ local patterns = {
+ "publ-imp-%s.mkvi",
+ "publ-imp-%s.mkiv",
+ "publ-imp-%s.tex",
+ }
+
+ local function failure(name)
+ report("unknown library %a",name)
+ end
-function commands.loadbtxdefinitionfile(name) -- a more specific name
- commands.uselibrary {
- name = gsub(name,"^publ%-",""),
- patterns = patterns,
- action = action,
- failure = failure,
- onlyonce = false,
+ local function action(name,foundname)
+ context.input(foundname)
+ end
+
+ function publications.loaddefinitionfile(name) -- a more specific name
+ resolvers.uselibrary {
+ name = string.gsub(name,"^publ%-",""),
+ patterns = patterns,
+ action = action,
+ failure = failure,
+ onlyonce = true,
+ }
+ end
+
+ local patterns = {
+ "publ-imp-%s.lua",
}
-end
--- lists:
+ function publications.loadreplacementfile(name) -- a more specific name
+ resolvers.uselibrary {
+ name = string.gsub(name,"^publ%-",""),
+ patterns = patterns,
+ action = publications.loaders.registercleaner,
+ failure = failure,
+ onlyonce = true,
+ }
+ end
+
+ implement { name = "btxloaddefinitionfile", actions = publications.loaddefinitionfile, arguments = "string" }
+ implement { name = "btxloadreplacementfile", actions = publications.loadreplacementfile, arguments = "string" }
-publications.lists = publications.lists or { }
-local lists = publications.lists
+end
-local context = context
-local structures = structures
+-- lists
-local references = structures.references
-local sections = structures.sections
+do
--- per rendering
+ publications.lists = publications.lists or { }
+ local lists = publications.lists
-local renderings = { } --- per dataset
+ local context = context
+ local structures = structures
-setmetatableindex(renderings,function(t,k)
- local v = {
- list = { },
- done = { },
- alldone = { },
- used = { },
- registered = { },
- ordered = { },
- shorts = { },
- method = v_none,
- currentindex = 0,
- }
- t[k] = v
- return v
-end)
+ local references = structures.references
+ local sections = structures.sections
--- why shorts vs tags: only for sorting
+ -- per rendering
-function lists.register(dataset,tag,short) -- needs checking now that we split
- local r = renderings[dataset]
- if not short or short == "" then
- short = tag
- end
- if trace then
- report("registering publication entry %a with shortcut %a",tag,short)
- end
- local top = #r.registered + 1
- -- do we really need these
- r.registered[top] = tag
- r.ordered [tag] = top
- r.shorts [tag] = short
-end
+ local renderings = { } --- per dataset
-function lists.nofregistered(dataset)
- return #renderings[dataset].registered
-end
+ setmetatableindex(renderings,function(t,k)
+ local v = {
+ list = { },
+ done = { },
+ alldone = { },
+ used = { },
+ registered = { },
+ ordered = { },
+ shorts = { },
+ method = v_none,
+ texts = setmetatableindex("table"),
+ currentindex = 0,
+ }
+ t[k] = v
+ return v
+ end)
-function lists.setmethod(dataset,method)
- local r = renderings[dataset]
- r.method = method or v_none
- r.list = { }
- r.done = { }
-end
+ -- helper
-local function validkeyword(dataset,tag,keyword)
- local ds = datasets[dataset]
- if not ds then
- report("unknown dataset %a",dataset)
- return
+ function lists.register(dataset,tag,short) -- needs checking now that we split
+ local r = renderings[dataset]
+ if not short or short == "" then
+ short = tag
+ end
+ if trace then
+ report("registering publication entry %a with shortcut %a",tag,short)
+ end
+ local top = #r.registered + 1
+ -- do we really need these
+ r.registered[top] = tag
+ r.ordered [tag] = top
+ r.shorts [tag] = short
end
- local dt = ds.details[tag]
- if not dt then
- report("no details for tag %a",tag)
- return
+
+ function lists.nofregistered(dataset)
+ return #renderings[dataset].registered
end
- local kw = dt.keyword
- if kw then
- for k in next, keyword do
- if kw[k] then
- return true
+
+ local function validkeyword(dataset,tag,keyword,specification) -- todo: pass specification
+ local kw = getcasted(dataset,tag,"keywords",specification)
+ if kw then
+ for i=1,#kw do
+ if keyword[kw[i]] then
+ return true
+ end
end
end
end
-end
-function lists.collectentries(specification)
- local dataset = specification.btxdataset
- if not dataset then
- return
+ local function registerpage(pages,tag,result,listindex)
+ local p = pages[tag]
+ local r = result[listindex].references
+ if p then
+ local last = p[#p][2]
+ local real = last.realpage
+ if real ~= r.realpage then
+ p[#p+1] = { listindex, r }
+ end
+ else
+ pages[tag] = { { listindex, r } }
+ end
end
- local rendering = renderings[dataset]
- local method = rendering.method
- if method == v_none then
- return
+
+ local methods = { }
+ lists.methods = methods
+
+ methods[v_dataset] = function(dataset,rendering,keyword)
+ -- why only once unless criterium=all?
+ local current = datasets[dataset]
+ local luadata = current.luadata
+ local list = rendering.list
+ for tag, data in sortedhash(luadata) do
+ if not keyword or validkeyword(dataset,tag,keyword) then
+ list[#list+1] = { tag, false, 0, false, false, data.index or 0}
+ end
+ end
end
- local result = structures.lists.filter(specification)
- --
- local keyword = specification.keyword
- if keyword and keyword ~= "" then
- keyword = settings_to_set(keyword)
- else
- keyword = nil
- end
- lists.result = result
- local section = sections.currentid()
- local list = rendering.list
- local done = rendering.done
- local alldone = rendering.alldone
- if method == v_local then
+
+ -- todo: names = { "btx" }
+
+ methods[v_force] = function (dataset,rendering,keyword)
+ -- only for checking, can have duplicates, todo: collapse page numbers, although
+ -- we then also needs deferred writes
+ local result = structures.lists.filter(rendering.specifications) or { }
+ local list = rendering.list
+ local current = datasets[dataset]
+ local luadata = current.luadata
for listindex=1,#result do
local r = result[listindex]
- local u = r.userdata
- if u and u.btxset == dataset then
- local tag = u.btxref
- if tag and done[tag] ~= section then
- if not keyword or validkeyword(dataset,tag,keyword) then
- done[tag] = section
- alldone[tag] = true
- list[#list+1] = { tag, listindex }
+ local u = r.userdata -- better check on metadata.kind == "btx"
+ if u then
+ local set = u.btxset or v_default
+ if set == dataset then
+ local tag = u.btxref
+ if tag and (not keyword or validkeyword(dataset,tag,keyword)) then
+ local data = luadata[tag]
+ list[#list+1] = { tag, listindex, 0, u, u.btxint, data and data.index or 0 }
end
end
end
end
- elseif method == v_global then
+ lists.result = result
+ end
+
+ -- local : if tag and done[tag] ~= section then ...
+ -- global : if tag and not alldone[tag] and done[tag] ~= section then ...
+
+ methods[v_local] = function(dataset,rendering,keyword)
+ local result = structures.lists.filter(rendering.specifications) or { }
+ local section = sections.currentid()
+ local list = rendering.list
+ local repeated = rendering.repeated == v_yes
+ local r_done = rendering.done
+ local r_alldone = rendering.alldone
+ local done = repeated and { } or r_done
+ local alldone = repeated and { } or r_alldone
+ local doglobal = rendering.method == v_global
+ local traced = { } -- todo: only if interactive (backlinks) or when tracing
+ local pages = { }
+ local current = datasets[dataset]
+ local luadata = current.luadata
+ -- handy for tracing :
+ rendering.result = result
+ --
for listindex=1,#result do
local r = result[listindex]
local u = r.userdata
- if u and u.btxset == dataset then
- local tag = u.btxref
- if tag and not alldone[tag] and done[tag] ~= section then
- if not keyword or validkeyword(dataset,tag,keyword) then
- done[tag] = section
- alldone[tag] = true
- list[#list+1] = { tag, listindex }
+ if u then -- better check on metadata.kind == "btx"
+ local set = u.btxset or v_default
+ if set == dataset then
+ local tag = u.btxref
+ if not tag then
+ -- problem
+ elseif done[tag] == section then -- a bit messy for global and all and so
+ -- skip
+ elseif doglobal and alldone[tag] then
+ -- skip
+ elseif not keyword or validkeyword(dataset,tag,keyword) then
+ if traced then
+ local l = traced[tag]
+ if l then
+ l[#l+1] = u.btxint
+ else
+ local data = luadata[tag]
+ local l = { tag, listindex, 0, u, u.btxint, data and data.index or 0 }
+ list[#list+1] = l
+ traced[tag] = l
+ end
+ else
+ done[tag] = section
+ alldone[tag] = true
+ local data = luadata[tag]
+ list[#list+1] = { tag, listindex, 0, u, u.btxint, data and data.index or 0 }
+ end
+ end
+ if tag then
+ registerpage(pages,tag,result,listindex)
end
end
end
end
- elseif method == v_force then
- -- only for checking, can have duplicates, todo: collapse page numbers, although
- -- we then also needs deferred writes
- for listindex=1,#result do
- local r = result[listindex]
- local u = r.userdata
- if u and u.btxset == dataset then
- local tag = u.btxref
- if tag then
- if not keyword or validkeyword(dataset,tag,keyword) then
- list[#list+1] = { tag, listindex }
+ if traced then
+ for tag in next, traced do
+ done[tag] = section
+ alldone[tag] = true
+ end
+ end
+ lists.result = result
+ structures.lists.result = result
+ rendering.pages = pages -- or list.pages
+ end
+
+ methods[v_global] = methods[v_local]
+
+ function lists.collectentries(specification)
+ local dataset = specification.dataset
+ if not dataset then
+ return
+ end
+ local rendering = renderings[dataset]
+ if not rendering then
+ return
+ end
+ local method = specification.method or v_none
+ local ignored = specification.ignored or ""
+ rendering.method = method
+ rendering.ignored = ignored ~= "" and settings_to_set(ignored) or nil
+ rendering.list = { }
+ rendering.done = { }
+ rendering.sorttype = specification.sorttype or v_default
+ rendering.criterium = specification.criterium or v_none
+ rendering.repeated = specification.repeated or v_no
+ rendering.group = specification.group or ""
+ rendering.specifications = specification
+ local filtermethod = methods[method]
+ if not filtermethod then
+ report_list("invalid method %a",method or "")
+ return
+ end
+ lists.result = { } -- kind of reset
+ local keyword = specification.keyword
+ if keyword and keyword ~= "" then
+ keyword = settings_to_set(keyword)
+ else
+ keyword = nil
+ end
+ filtermethod(dataset,rendering,keyword)
+ local list = rendering.list
+ ctx_btxsetnoflistentries(list and #list or 0)
+ end
+
+ -- for determining width
+
+ local groups = setmetatableindex("number")
+
+ function lists.prepareentries(dataset)
+ local rendering = renderings[dataset]
+ local list = rendering.list
+ local used = rendering.used
+ local forceall = rendering.criterium == v_all
+ local repeated = rendering.repeated == v_yes
+ local sorttype = rendering.sorttype or v_default
+ local group = rendering.group or ""
+ local sorter = lists.sorters[sorttype]
+ local current = datasets[dataset]
+ local luadata = current.luadata
+ local details = current.details
+ local newlist = { }
+ local lastreferencenumber = groups[group] -- current.lastreferencenumber or 0
+ for i=1,#list do
+ local li = list[i]
+ local tag = li[1]
+ local entry = luadata[tag]
+ if entry then
+ if forceall or repeated or not used[tag] then
+ newlist[#newlist+1] = li
+ -- already here:
+ if not repeated then
+ used[tag] = true -- beware we keep the old state (one can always use criterium=all)
+ end
+ local detail = details[tag]
+ if detail then
+ local referencenumber = detail.referencenumber
+ if not referencenumber then
+ lastreferencenumber = lastreferencenumber + 1
+ referencenumber = lastreferencenumber
+ detail.referencenumber = lastreferencenumber
+ end
+ li[3] = referencenumber
+ else
+ report("missing details for tag %a in dataset %a (enhanced: %s)",tag,dataset,current.enhanced and "yes" or "no")
+ -- weird, this shouldn't happen .. all have a detail
+ lastreferencenumber = lastreferencenumber + 1
+ details[tag] = { referencenumber = lastreferencenumber }
+ li[3] = lastreferencenumber
end
end
end
end
- elseif method == v_dataset then
- local luadata = datasets[dataset].luadata
- for tag, data in table.sortedhash(luadata) do
- if not keyword or validkeyword(dataset,tag,keyword) then
- list[#list+1] = { tag }
+ groups[group] = lastreferencenumber
+ if type(sorter) == "function" then
+ rendering.list = sorter(dataset,rendering,newlist,sorttype) or newlist
+ else
+ rendering.list = newlist
+ end
+ end
+
+ function lists.fetchentries(dataset)
+ local rendering = renderings[dataset]
+ local list = rendering.list
+ if list then
+ for i=1,#list do
+ local li = list[i]
+ ctx_btxsettag(li[1])
+ ctx_btxsetnumber(li[3])
+ ctx_btxchecklistentry()
end
end
end
-end
-lists.sorters = {
- [v_short] = function(dataset,rendering,list)
- local shorts = rendering.shorts
- local function compare(a,b)
- local aa, bb = a and a[1], b and b[1]
- if aa and bb then
- aa, bb = shorts[aa], shorts[bb]
- return aa and bb and aa < bb
+ -- for rendering
+
+ -- setspecification
+
+ local function btxflushpages(dataset,tag)
+ -- todo: interaction
+ local rendering = renderings[dataset]
+ local pages = rendering.pages
+ if not pages then
+ return
+ else
+ pages = pages[tag]
+ end
+ if not pages then
+ return
+ end
+ local nofpages = #pages
+ if nofpages == 0 then
+ return
+ end
+ local first_p = nil
+ local first_r = nil
+ local last_p = nil
+ local last_r = nil
+ local ranges = { }
+ local nofdone = 0
+ local function flush()
+ if last_r and first_r ~= last_r then
+ ranges[#ranges+1] = { first_p, last_p }
+ else
+ ranges[#ranges+1] = { first_p }
end
- return false
end
- sort(list,compare)
- end,
- [v_reference] = function(dataset,rendering,list)
- local function compare(a,b)
- local aa, bb = a and a[1], b and b[1]
- if aa and bb then
- return aa and bb and aa < bb
+ for i=1,nofpages do
+ local next_p = pages[i]
+ local next_r = next_p[2].realpage
+ if not first_r then
+ first_p = next_p
+ first_r = next_r
+ elseif last_r + 1 == next_r then
+ -- continue
+ elseif first_r then
+ flush()
+ first_p = next_p
+ first_r = next_r
end
- return false
+ last_p = next_p
+ last_r = next_r
end
- sort(list,compare)
- end,
- [v_dataset] = function(dataset,rendering,list)
- local function compare(a,b)
- local aa, bb = a and a[1], b and b[1]
- if aa and bb then
- aa, bb = list[aa].index or 0, list[bb].index or 0
- return aa and bb and aa < bb
+ if first_r then
+ flush()
+ end
+ local nofranges = #ranges
+ for i=1,nofranges do
+ local r = ranges[i]
+ ctx_btxsetconcat(concatstate(i,nofranges))
+ local first, last = r[1], r[2]
+ ctx_btxsetfirstinternal(first[2].internal)
+ ctx_btxsetfirstpage(first[1])
+ if last then
+ ctx_btxsetlastinternal(last[2].internal)
+ ctx_btxsetlastpage(last[1])
end
- return false
+ if trace_detail then
+ report("expanding page setup")
+ end
+ ctx_btxpagesetup()
end
- sort(list,compare)
- end,
- -- [v_default] = function(dataset,rendering,list) -- not really needed
- -- local ordered = rendering.ordered
- -- local function compare(a,b)
- -- local aa, bb = a and a[1], b and b[1]
- -- if aa and bb then
- -- aa, bb = ordered[aa], ordered[bb]
- -- return aa and bb and aa < bb
- -- end
- -- return false
- -- end
- -- sort(list,compare)
- -- end,
- [v_author] = function(dataset,rendering,list)
- local valid = publications.authors.preparedsort(dataset,list,v_author,v_editor)
- if #valid == 0 or #valid ~= #list then
- -- nothing to sort
- else
- -- if needed we can wrap compare and use the list directly but this is cleaner
- sorters.sort(valid,sortcomparer)
- for i=1,#valid do
- local v = valid[i]
- valid[i] = list[v.index]
+ end
+
+ implement {
+ name = "btxflushpages",
+ actions = btxflushpages,
+ arguments = { "string", "string" }
+ }
+
+ function lists.sameasprevious(dataset,i,name,order,method)
+ local rendering = renderings[dataset]
+ local list = rendering.list
+ local n = tonumber(i)
+ if n and n > 1 and n <= #list then
+ local luadata = datasets[dataset].luadata
+ local current = getdirect(dataset,luadata[list[n ][1]],name)
+ local previous = getdirect(dataset,luadata[list[n-1][1]],name)
+ -- if not order then
+ -- order = gettexcounter("c_btx_list_reference")
+ -- end
+ if order and order > 0 and (method == v_always or method == v_doublesided) then
+ local clist = listtolist[order]
+ local plist = listtolist[order-1]
+ if clist and plist then
+ local crealpage = clist.references.realpage
+ local prealpage = plist.references.realpage
+ if crealpage ~= prealpage then
+ if method == v_always or not conditionals.layoutisdoublesided then
+ if trace_detail then
+ report("previous %a, current %a, different page",previous,current)
+ end
+ return false
+ elseif crealpage % 2 == 0 then
+ if trace_detail then
+ report("previous %a, current %a, different page",previous,current)
+ end
+ return false
+ end
+ end
+ end
end
- return valid
+ local sameentry = current and current == previous
+ if trace_detail then
+ if sameentry then
+ report("previous %a, current %a, same entry",previous,current)
+ else
+ report("previous %a, current %a, different entry",previous,current)
+ end
+ end
+ return sameentry
+ else
+ return false
end
- end,
-}
+ end
-function lists.flushentries(dataset,sortvariant)
- local rendering = renderings[dataset]
- local list = rendering.list
- local sort = lists.sorters[sortvariant] or lists.sorters[v_default]
- if type(sort) == "function" then
- list = sort(dataset,rendering,list) or list
- end
- for i=1,#list do
- -- we can pass i here too ... more efficient to avoid the setvalue
- local tag = list[i][1]
- local entry = datasets[dataset].luadata[tag]
- if entry then
- ctx_setvalue("currentbtxindex",i) -- todo: helper
+ function lists.flushentry(dataset,i,textmode)
+ local rendering = renderings[dataset]
+ local list = rendering.list
+ local luadata = datasets[dataset].luadata
+ local li = list[i]
+ if li then
+ local tag = li[1]
+ local listindex = li[2]
+ local n = li[3]
+ local entry = luadata[tag]
+ --
+ ctx_btxstartlistentry()
+ ctx_btxsetcurrentlistentry(i) -- redundant
+ ctx_btxsetcurrentlistindex(listindex or 0)
local combined = entry.combined
+ local language = entry.language
if combined then
- ctx_setvalue("currentbtxcombis",concat(combined,","))
+ ctx_btxsetcombis(concat(combined,","))
+ end
+ ctx_btxsetcategory(entry.category or "unknown")
+ ctx_btxsettag(tag)
+ ctx_btxsetnumber(n)
+ if language then
+ ctx_btxsetlanguage(language)
+ end
+ local bl = li[5]
+ if bl and bl ~= "" then
+ ctx_btxsetbacklink(bl)
+ ctx_btxsetbacktrace(concat(li," ",5))
+ local uc = citetolist[tonumber(bl)]
+ if uc then
+ ctx_btxsetinternal(uc.references.internal or "")
+ end
else
- ctx_setvalue("currentbtxcombis","")
+ -- nothing
end
- ctx_btxhandlelistentry(tag) -- pas i instead
- end
- end
-end
-
-function lists.fetchentries(dataset)
- local list = renderings[dataset].list
- for i=1,#list do
- local tag = list[i][1]
- local entry = datasets[dataset].luadata[tag]
- if entry then
- ctx_btxchecklistentry(tag) -- integrate doifalreadyplaced here
+ local userdata = li[4]
+ if userdata then
+ local b = userdata.btxbtx
+ local a = userdata.btxatx
+ if b then
+ ctx_btxsetbefore(b)
+ end
+ if a then
+ ctx_btxsetafter(a)
+ end
+ end
+ rendering.userdata = userdata
+ if textmode then
+ ctx_btxhandlelisttextentry()
+ else
+ ctx_btxhandlelistentry()
+ end
+ ctx_btxstoplistentry()
+ --
+ -- context(function()
+ -- -- wrapup
+ -- rendering.ignoredfields = nil
+ -- end)
end
end
-end
-function lists.filterall(dataset)
- local r = renderings[dataset]
- local list = r.list
- local registered = r.registered
- for i=1,#registered do
- list[i] = { registered[i], i }
+ local function getuserdata(dataset,key)
+ local rendering = renderings[dataset]
+ if rendering then
+ local userdata = rendering.userdata
+ if userdata then
+ local value = userdata[key]
+ if value and value ~= "" then
+ return value
+ end
+ end
+ end
end
-end
-function lists.registerplaced(dataset,tag)
- renderings[dataset].used[tag] = true
-end
-
-function lists.doifalreadyplaced(dataset,tag)
- commands.doifelse(renderings[dataset].used[tag])
-end
+ lists.uservariable = getuserdata
--- we ask for :tag but when we can't find it we go back
--- to look for previous definitions, and when not found again
--- we look forward
+ function lists.filterall(dataset)
+ local r = renderings[dataset]
+ local list = r.list
+ local registered = r.registered
+ for i=1,#registered do
+ list[i] = { registered[i], i, 0, false, false }
+ end
+ end
-local function compare(a,b)
- local aa, bb = a and a[3], b and b[3]
- return aa and bb and aa < bb
-end
+ implement {
+ name = "btxuservariable",
+ actions = { getuserdata, context },
+ arguments = { "string", "string" }
+ }
--- rendering ?
+ implement {
+ name = "btxdoifelseuservariable",
+ actions = { getuserdata, ctx_doifelse },
+ arguments = { "string", "string" }
+ }
--- todo: nicer refs
+ -- implement {
+ -- name = "btxresolvelistreference",
+ -- actions = lists.resolve,
+ -- arguments = { "string", "string" }
+ -- }
+
+ implement {
+ name = "btxcollectlistentries",
+ actions = lists.collectentries,
+ arguments = {
+ {
+ { "names" },
+ { "criterium" },
+ { "reference" },
+ { "method" },
+ { "dataset" },
+ { "keyword" },
+ { "sorttype" },
+ { "repeated" },
+ { "ignored" },
+ { "group" },
+ }
+ }
+ }
--- local f_citereference = formatters["btx:%s:%s"] -- dataset, instance (block), tag, order
--- local f_listreference = formatters["btx:%s:%s:%s:%s"] -- dataset, instance (block), tag, order
---
--- -- local done = { }
--- local last = 0
---
--- function commands.btxcitereference(internal)
--- last = last + 1
--- local ref = f_citereference(internal,last) -- we just need a unique key
--- -- local don = done[ref]
--- -- if don == nil then
--- if trace_references then
--- report_reference("cite: %s",ref)
--- end
--- -- done[ref] = true
--- ctx_btxsetcitereference(ref,internal)
--- -- elseif don then
--- -- report_reference("duplicate cite: %s, skipped",ref)
--- -- done[ref] = false
--- -- -- else
--- -- -- no more messages
--- -- end
--- end
---
--- -- we just need a unique key, so we could also use btx: but this
--- -- way we have a bit of a check for duplicates
---
--- -- local done = { }
--- local last = 0
---
--- function commands.btxlistreference(dataset,block,tag,data)
--- last = last + 1
--- local ref = f_listreference(dataset,block,tag,last)
--- -- local don = done[ref]
--- -- if don == nil then
--- if trace_references then
--- report_reference("list: %s",ref)
--- end
--- -- done[ref] = true
--- ctx_btxsetlistreference(dataset,tag,ref,data)
--- -- elseif don then
--- -- report_reference("duplicate link: %s, skipped",ref)
--- -- done[ref] = false
--- -- -- else
--- -- -- no more messages
--- -- end
--- end
+ implement {
+ name = "btxpreparelistentries",
+ actions = lists.prepareentries,
+ arguments = { "string" },
+ }
+ implement {
+ name = "btxfetchlistentries",
+ actions = lists.fetchentries,
+ arguments = { "string" },
+ }
-local f_citereference = formatters["btx:cite:%s"]
-local f_listreference = formatters["btx:list:%s"]
+ implement {
+ name = "btxflushlistentry",
+ actions = lists.flushentry,
+ arguments = { "string", "integer" }
+ }
-local nofcite = 0
-local noflist = 0
+ implement {
+ name = "btxdoifelsesameasprevious",
+ actions = { lists.sameasprevious, ctx_doifelse },
+ arguments = { "string", "integer", "string", "integer", "string" }
+ }
-function commands.btxcitereference(internal)
- nofcite = nofcite + 1
- local ref = f_citereference(nofcite)
- if trace_references then
- report_reference("cite: %s",ref)
- end
- ctx_btxsetcitereference(ref,internal)
end
-function commands.btxlistreference(dataset,block,tag,data)
- noflist = noflist + 1
- local ref = f_listreference(noflist)
- if trace_references then
- report_reference("list: %s",ref)
- end
- ctx_btxsetlistreference(dataset,tag,ref,data)
-end
+do
+ local citevariants = { }
+ publications.citevariants = citevariants
-commands.btxsetlistmethod = lists.setmethod
-commands.btxresolvelistreference = lists.resolve
-commands.btxregisterlistentry = lists.registerplaced
-commands.btxaddtolist = lists.addentry
-commands.btxcollectlistentries = lists.collectentries
-commands.btxfetchlistentries = lists.fetchentries
-commands.btxflushlistentries = lists.flushentries
-commands.btxdoifelselistentryplaced = lists.doifalreadyplaced
-
-local citevariants = { }
-publications.citevariants = citevariants
-
--- helper
-
-local function sortedtags(dataset,list,sorttype)
- local luadata = datasets[dataset].luadata
- local valid = { }
- for i=1,#list do
- local tag = list[i]
- local entry = luadata[tag]
- if entry then
- local key = entry[sorttype]
- if key then
- valid[#valid+1] = {
- tag = tag,
- split = sortsplitter(sortstripper(key))
- }
- else
- end
+ local function btxhandlecite(specification)
+ local dataset = specification.dataset or v_default
+ local reference = specification.reference
+ local variant = specification.variant
+ if not variant or variant == "" then
+ variant = "default"
end
- end
- if #valid == 0 or #valid ~= #list then
- return list
- else
- sorters.sort(valid,basicsorter)
- for i=1,#valid do
- valid[i] = valid[i].tag
+ if not reference or reference == "" then
+ return
end
- return valid
- end
-end
-
--- if sorttype and sorttype ~= "" then
--- tags = sortedtags(dataset,tags,sorttype)
--- end
-
-local optionalspace = lpeg.patterns.whitespace^0
-local prefixsplitter = optionalspace * lpeg.splitat(optionalspace * P("::") * optionalspace)
-
-function commands.btxhandlecite(specification)
- local tag = specification.reference
- if not tag or tag == "" then
- return
- end
- --
- local dataset = specification.dataset or ""
- local mark = specification.markentry ~= false
- local variant = specification.variant or "num"
- local sorttype = specification.sorttype
- local compress = specification.compress == v_yes
- --
- local prefix, rest = lpegmatch(prefixsplitter,tag)
- if rest then
- dataset = prefix
- else
- rest = tag
- end
- local action = citevariants[variant] -- there is always fallback on default
- if trace_cite then
- report_cite("inject, dataset: %s, tag: %s, variant: %s, compressed",dataset or "-",rest,variant)
+ --
+ specification.variant = variant
+ specification.compress = specification.compress == v_yes
+ specification.markentry = specification.markentry ~= false
+ --
+ local prefix, rest = lpegmatch(prefixsplitter,reference)
+ if prefix and rest then
+ dataset = prefix
+ specification.dataset = prefix
+ specification.reference = rest
+ end
+ --
+ if trace_cite then
+ report_cite("inject, dataset: %s, tag: %s, variant: %s, compressed",
+ specification.dataset or "-",
+ specification.reference,
+ specification.variant
+ )
+ end
+ --
+ ctx_btxsetdataset(dataset)
+ --
+ citevariants[variant](specification) -- we always fall back on default
end
- ctx_setvalue("currentbtxdataset",dataset)
- action(dataset,rest,mark,compress,variant)
-end
-function commands.btxhandlenocite(specification)
- local mark = specification.markentry ~= false
- if not mark then
- return
- end
- local tag = specification.reference
- if not tag or tag == "" then
- return
- end
- local dataset = specification.dataset or ""
- local prefix, rest = lpegmatch(prefixsplitter,tag)
- if rest then
- dataset = prefix
- else
- rest = tag
- end
- ctx_setvalue("currentbtxdataset",dataset)
- local tags = settings_to_array(rest)
- if trace_cite then
- report_cite("mark, dataset: %s, tags: % | t",dataset or "-",tags)
- end
- for i=1,#tags do
- markcite(dataset,tags[i])
+ local function btxhandlenocite(specification)
+ local dataset = specification.dataset or v_default
+ local reference = specification.reference
+ if not reference or reference == "" then
+ return
+ end
+ --
+ local markentry = specification.markentry ~= false
+ local internal = specification.internal or ""
+ --
+ local prefix, rest = lpegmatch(prefixsplitter,reference)
+ if rest then
+ dataset = prefix
+ reference = rest
+ end
+ --
+ if trace_cite then
+ report_cite("mark, dataset: %s, tags: %s",dataset or "-",reference)
+ end
+ --
+ local reference = publications.parenttag(dataset,reference)
+ --
+ local found, todo, list = findallused(dataset,reference,internal)
+ --
+ tobemarked = markentry and todo
+ if found and tobemarked then
+ flushmarked(dataset,list)
+ btxflushmarked() -- here (could also be done in caller)
+ end
end
-end
--- function commands.btxcitevariant(dataset,block,tags,variant) -- uses? specification ?
--- local action = citevariants[variant]
--- if action then
--- action(dataset,tags,variant)
--- end
--- end
+ implement {
+ name = "btxhandlecite",
+ actions = btxhandlecite,
+ arguments = {
+ {
+ { "dataset" },
+ { "reference" },
+ { "markentry", "boolean" },
+ { "variant" },
+ { "sorttype" },
+ { "compress" },
+ { "author" },
+ { "lefttext" },
+ { "righttext" },
+ { "before" },
+ { "after" },
+ }
+ }
+ }
--- sorter
+ implement {
+ name = "btxhandlenocite",
+ actions = btxhandlenocite,
+ arguments = {
+ {
+ { "dataset" },
+ { "reference" },
+ { "markentry", "boolean" },
+ }
+ }
+ }
-local keysorter = function(a,b) return a.sortkey < b.sortkey end
+ -- sorter
-local function compresslist(source)
- for i=1,#source do
- if type(source[i].sortkey) ~= "number" then
- return source
+ local keysorter = function(a,b)
+ local ak = a.sortkey
+ local bk = b.sortkey
+ if ak == bk then
+ local as = a.suffix -- alphabetic
+ local bs = b.suffix -- alphabetic
+ if as and bs then
+ return (as or "") < (bs or "")
+ else
+ return false
+ end
+ else
+ return ak < bk
end
end
- local first, last, firstr, lastr
- local target, noftarget, tags = { }, 0, { }
- sort(source,keysorter)
- -- suffixes
- local oldvalue = nil
- local suffix = 0
- local function setsuffix(entry,suffix,sortfld)
- entry.suffix = suffix
- local dataset = datasets[entry.dataset]
- if dataset then
- local suffixes = dataset.suffixes[entry.tag]
- if suffixes then
- suffixes[sortfld] = suffix
+
+ local function compresslist(source)
+ for i=1,#source do
+ local t = type(source[i].sortkey)
+ if t == "number" then
+ -- okay
+ -- elseif t == "string" then
+ -- -- okay
else
- dataset.suffixes[entry.tag] = { [sortfld] = suffix }
+ return source
end
end
- end
- for i=1,#source do
- local entry = source[i]
- local sortfld = entry.sortfld
- if sortfld then
- local value = entry.sortkey
- if value == oldvalue then
- if suffix == 0 then
- suffix = 1
- local entry = source[i-1]
- setsuffix(entry,suffix,sortfld)
- end
- suffix = suffix + 1
- setsuffix(entry,suffix,sortfld)
+ local first, last, firstr, lastr
+ local target, noftarget, tags = { }, 0, { }
+ sort(source,keysorter)
+ local oldvalue = nil
+ local function flushrange()
+ noftarget = noftarget + 1
+ if last > first + 1 then
+ target[noftarget] = {
+ first = firstr,
+ last = lastr,
+ tags = tags,
+ }
else
- oldvalue = value
- suffix = 0
+ target[noftarget] = firstr
+ if last > first then
+ noftarget = noftarget + 1
+ target[noftarget] = lastr
+ end
end
- else
- break
+ tags = { }
end
- end
- --
- local function flushrange()
- noftarget = noftarget + 1
- if last > first + 1 then
- target[noftarget] = {
- first = firstr,
- last = lastr,
- tags = tags,
- }
- else
- target[noftarget] = firstr
- if last > first then
- noftarget = noftarget + 1
- target[noftarget] = lastr
+ for i=1,#source do
+ local entry = source[i]
+ local current = entry.sortkey
+ local suffix = entry.suffix -- todo but what
+ if not first then
+ first, last, firstr, lastr = current, current, entry, entry
+ elseif current == last + 1 then
+ last, lastr = current, entry
+ else
+ flushrange()
+ first, last, firstr, lastr = current, current, entry, entry
end
+ tags[#tags+1] = entry.tag
end
- tags = { }
- end
- for i=1,#source do
- local entry = source[i]
- local current = entry.sortkey
- if not first then
- first, last, firstr, lastr = current, current, entry, entry
- elseif current == last + 1 then
- last, lastr = current, entry
- else
+ if first and last then
flushrange()
- first, last, firstr, lastr = current, current, entry, entry
end
- tags[#tags+1] = entry.tag
- end
- if first and last then
- flushrange()
+ return target
end
- return target
-end
--- local source = {
--- { tag = "one", internal = 1, value = "foo", page = 1 },
--- { tag = "two", internal = 2, value = "bar", page = 2 },
--- { tag = "three", internal = 3, value = "gnu", page = 3 },
--- }
---
--- local target = compresslist(source)
-
-local numberonly = R("09")^1 / tonumber + P(1)^0
-local f_missing = formatters["<%s>"]
-
--- maybe also sparse (e.g. pages)
-
-local function processcite(dataset,reference,mark,compress,setup,getter,setter,compressor)
- reference = publications.parenttag(dataset,reference)
- local found, todo, list = findallused(dataset,reference)
- if found and setup then
- local source = { }
- local badkey = false
- for i=1,#found do
- local entry = found[i]
- local tag = entry.userdata.btxref
- local internal = entry.references.internal
- local data = getter(dataset,tag,entry,internal)
- if compress and not compressor then
- local sortkey = data.sortkey
- if sortkey then
- local key = lpegmatch(numberonly,sortkey)
- if key then
- data.sortkey = key
+ -- local source = {
+ -- { tag = "one", internal = 1, value = "foo", page = 1 },
+ -- { tag = "two", internal = 2, value = "bar", page = 2 },
+ -- { tag = "three", internal = 3, value = "gnu", page = 3 },
+ -- }
+ --
+ -- local target = compresslist(source)
+
+ local numberonly = R("09")^1 / tonumber + P(1)^0
+ local f_missing = formatters["<%s>"]
+
+ -- maybe also sparse (e.g. pages)
+
+ -- a bit redundant access to datasets
+
+ local function processcite(presets,specification)
+ --
+ if specification then
+ setmetatableindex(specification,presets)
+ else
+ specification = presets
+ end
+ --
+ local dataset = specification.dataset
+ local reference = specification.reference
+ local internal = specification.internal
+ local setup = specification.variant
+ local compress = specification.compress
+ local getter = specification.getter
+ local setter = specification.setter
+ local compressor = specification.compressor
+ --
+ local reference = publications.parenttag(dataset,reference)
+ --
+ local found, todo, list = findallused(dataset,reference,internal)
+ tobemarked = specification.markentry and todo
+ --
+ if not found or #found == 0 then
+ report("nothing found for %a",reference)
+ elseif not setup then
+ report("invalid reference for %a",reference)
+ else
+ if trace_cite then
+ report("processing reference %a",reference)
+ end
+ local source = { }
+ local badkey = false
+ local luadata = datasets[dataset].luadata
+ for i=1,#found do
+ local entry = found[i]
+ local tag = entry.userdata.btxref
+ local ldata = luadata[tag]
+ local data = {
+ internal = entry.references.internal,
+ language = ldata.language,
+ dataset = dataset,
+ tag = tag,
+ -- luadata = ldata,
+ }
+ setter(data,dataset,tag,entry)
+ if compress and not compressor then
+ local sortkey = data.sortkey
+ if sortkey then
+ local key = lpegmatch(numberonly,sortkey)
+ if key then
+ data.sortkey = key
+ else
+ badkey = true
+ end
else
badkey = true
end
+ end
+ if type(data) == "table" then
+ source[#source+1] = data
else
- badkey = true
+ report("error in cite rendering %a",setup or "?")
end
end
- source[i] = data
- end
- if compress and not badkey then
- local target = (compressor or compresslist)(source)
- local function flush(i,state)
- local entry = target[i]
- local first = entry.first
- if first then
- local tags = entry.tags
- if mark then
- for i=1,#tags do
- local tag = tags[i]
- markcite(dataset,tag)
- todo[tag] = false
- end
- end
- ctx_btxsettag(tags[1])
- local internal = first.internal
- if internal then
- ctx_btxsetinternal(internal)
- end
- if not setter(first,entry.last) then
- ctx_btxsetfirst(f_missing(first.tag))
- end
+
+ local lefttext = specification.lefttext
+ local righttext = specification.righttext
+ local before = specification.before
+ local after = specification.after
+
+ if lefttext and lefttext ~= "" then lefttext = settings_to_array(lefttext) end
+ if righttext and righttext ~= "" then righttext = settings_to_array(righttext) end
+ if before and before ~= "" then before = settings_to_array(before) end
+ if after and after ~= "" then after = settings_to_array(after) end
+
+ -- local oneleft = lefttext and #lefttext == 1 and lefttext [1]
+ -- local oneright = righttext and #righttext == 1 and righttext[1]
+ --
+ -- if not oneleft or not oneright then
+ -- compress = false -- very hard coded, or should we have compreess == auto?
+ -- end
+
+ local function flush(i,n,entry,last)
+ local tag = entry.tag
+ local currentcitation = markcite(dataset,tag)
+ --
+ ctx_btxstartcite()
+ ctx_btxsettag(tag)
+ ctx_btxsetcategory(entry.category or "unknown")
+ --
+ -- if oneleft then
+ -- if i == 1 then
+ -- ctx_btxsetlefttext(oneleft)
+ -- end
+ -- elseif lefttext then
+ -- ctx_btxsetlefttext(lefttext[i] or "")
+ -- end
+ -- if oneright then
+ -- if i == n then
+ -- ctx_btxsetrighttext(oneright)
+ -- end
+ -- elseif righttext then
+ -- ctx_btxsetrighttext(righttext[i] or "")
+ -- end
+ -- if before then
+ -- ctx_btxsetbefore(before[i] or (#before == 1 and before[1]) or "")
+ -- end
+ -- if after then
+ -- ctx_btxsetafter(after[i] or (#after == 1 and after[1]) or "")
+ -- end
+ --
+ if lefttext then local text = lefttext [i] ; if text and text ~= "" then ctx_btxsetlefttext (text) end end
+ if righttext then local text = righttext[i] ; if text and text ~= "" then ctx_btxsetrighttext(text) end end
+ if before then local text = before [i] ; if text and text ~= "" then ctx_btxsetbefore (text) end end
+ if after then local text = after [i] ; if text and text ~= "" then ctx_btxsetafter (text) end end
+ --
+ ctx_btxsetbacklink(currentcitation)
+ local bl = listtocite[currentcitation]
+ if bl then
+ -- we refer to a coming list entry
+ ctx_btxsetinternal(bl.references.internal or "")
else
- local tag = entry.tag
- if mark then
- markcite(dataset,tag)
- todo[tag] = false
- end
- ctx_btxsettag(tag)
- local internal = entry.internal
- if internal then
- ctx_btxsetinternal(internal)
- end
- if not setter(entry) then
- ctx_btxsetfirst(f_missing(tag))
- end
+ -- we refer to a previous list entry
+ ctx_btxsetinternal(entry.internal or "")
end
- ctx_btxsetconcat(state)
- ctx_btxcitesetup(setup)
- end
- flushcollected(flush,#target)
- else
- local function flush(i,state)
- local entry = source[i]
- local tag = entry.tag
- if mark then
- markcite(dataset,tag)
- todo[tag] = false
+ local language = entry.language
+ if language then
+ ctx_btxsetlanguage(language)
end
- ctx_btxsettag(tag)
- local internal = entry.internal
- if internal then
- ctx_btxsetinternal(internal)
+ if not getter(entry,last) then
+ ctx_btxsetfirst("") -- (f_missing(tag))
end
- ctx_btxsetconcat(state)
- if not setter(entry) then
- ctx_btxsetfirst(f_missing(entry.tag))
+ ctx_btxsetconcat(concatstate(i,n))
+ if trace_detail then
+ report("expanding cite setup %a",setup)
end
ctx_btxcitesetup(setup)
+ ctx_btxstopcite()
+ end
+
+ if compress and not badkey then
+ local target = (compressor or compresslist)(source)
+ local nofcollected = #target
+ if nofcollected == 0 then
+ report("nothing found for %a",reference)
+ unknowncite(reference)
+ else
+ for i=1,nofcollected do
+ local entry = target[i]
+ local first = entry.first
+ if first then
+ flush(i,nofcollected,first,entry.last)
+ else
+ flush(i,nofcollected,entry)
+ end
+ end
+ end
+ else
+ local nofcollected = #source
+ if nofcollected == 0 then
+ unknowncite(reference)
+ else
+ for i=1,nofcollected do
+ flush(i,nofcollected,source[i])
+ end
+ end
end
- flushcollected(flush,#source)
+ end
+ if tobemarked then
+ flushmarked(dataset,list)
+ btxflushmarked() -- here (could also be done in caller)
end
end
- if mark then
- flushmarked(dataset,list,todo)
- end
-end
-local function simplegetter(first,last,field)
- local value = first[field]
- if value then
- ctx_btxsetfirst(value)
- if last then
- ctx_btxsetsecond(last[field])
+ --
+
+ local function simplegetter(first,last,field)
+ local value = first[field]
+ if value then
+ ctx_btxsetfirst(value)
+ if last then
+ ctx_btxsetsecond(last[field])
+ end
+ return true
end
- return true
end
-end
-local setters = setmetatableindex({},function(t,k)
- local v = function(dataset,tag,entry,internal)
- local value = getfield(dataset,tag,k)
- return {
- tag = tag,
- internal = internal,
- [k] = value,
- sortkey = value,
- sortfld = k,
- }
+ local setters = setmetatableindex({},function(t,k)
+ local v = function(data,dataset,tag,entry)
+ local value = getcasted(dataset,tag,k)
+ data.value = value -- not really needed
+ data[k] = value
+ data.sortkey = value
+ data.sortfld = k
+ end
+ t[k] = v
+ return v
+ end)
+
+ local getters = setmetatableindex({},function(t,k)
+ local v = function(first,last)
+ return simplegetter(first,last,k)
+ end
+ t[k] = v
+ return v
+ end)
+
+ setmetatableindex(citevariants,function(t,k)
+ local p = defaultvariant or "default"
+ local v = rawget(t,p)
+ report_cite("variant %a falls back on %a setter and getter with setup %a",k,p,k)
+ t[k] = v
+ return v
+ end)
+
+ function citevariants.default(presets)
+ local variant = presets.variant
+ processcite(presets,{
+ setup = variant,
+ setter = setters[variant],
+ getter = getters[variant],
+ })
end
- t[k] = v
- return v
-end)
-local getters = setmetatableindex({},function(t,k)
- local v = function(first,last)
- return simplegetter(first,last,k)
+ -- category | type
+
+ do
+
+ local function setter(data,dataset,tag,entry)
+ data.category = getfield(dataset,tag,"category")
+ end
+
+ local function getter(first,last)
+ return simplegetter(first,last,"category")
+ end
+
+ function citevariants.category(presets)
+ processcite(presets,{
+ -- variant = presets.variant or "serial",
+ setter = setter,
+ getter = getter,
+ })
+ end
+
+ function citevariants.type(presets)
+ processcite(presets,{
+ -- variant = presets.variant or "type",
+ setter = setter,
+ getter = getter,
+ })
+ end
+
end
- t[k] = v
- return v
-end)
--- default
-setmetatableindex(citevariants,function(t,k)
- local v = t.default
- t[k] = v
- return v
-end)
+ -- entry (we could provide a generic one)
-function citevariants.default(dataset,reference,mark,compress,variant,setup)
- processcite(dataset,reference,mark,compress,setup or variant,setters[variant],getters[variant])
-end
+ do
--- short
+ local function setter(data,dataset,tag,entry)
+ -- nothing
+ end
-local function setter(dataset,tag,entry,internal)
- return {
- tag = tag,
- internal = internal,
- short = getfield(dataset,tag,"short"),
- suffix = getfield(dataset,tag,"suffix"),
- }
-end
+ local function getter(first,last) -- last not used
+ ctx_btxsetfirst(first.tag)
+ end
-local function getter(first,last) -- last not used
- local short = first.short
- if short then
- local suffix = first.suffix
- if suffix then
- ctx_btxsetfirst(short .. suffix)
- else
- ctx_btxsetfirst(short)
+ function citevariants.entry(presets)
+ processcite(presets,{
+ compress = false,
+ -- variant = presets.variant or "entry",
+ setter = setter,
+ getter = getter,
+ })
end
- return true
+
end
-end
-function citevariants.short(dataset,reference,mark,compress)
- processcite(dataset,reference,mark,false,"short",setter,getter)
-end
+ -- short
--- pages (no compress)
+ do
-local function setter(dataset,tag,entry,internal)
- return {
- dataset = dataset,
- tag = tag,
- internal = internal,
- pages = getdetail(dataset,tag,"pages"),
- }
-end
+ local function setter(data,dataset,tag,entry)
+ data.short = getdetail(dataset,tag,"short")
+ data.suffix = getdetail(dataset,tag,"suffix")
+ end
-local function getter(first,last)
- local pages = first.pages
- if pages then
- if type(pages) == "table" then
- ctx_btxsetfirst(pages[1])
- ctx_btxsetsecond(pages[2])
- else
- ctx_btxsetfirst(pages)
+ local function getter(first,last) -- last not used
+ local short = first.short
+ if short then
+ local suffix = first.suffix
+ if suffix then
+ ctx_btxsetfirst(short .. suffix)
+ else
+ ctx_btxsetfirst(short)
+ end
+ return true
+ end
+ end
+
+ function citevariants.short(presets)
+ processcite(presets,{
+ compress = false,
+ -- variant = presets.variant or "short",
+ setter = setter,
+ getter = getter,
+ })
end
- return true
+
end
-end
-function citevariants.page(dataset,reference,mark,compress)
- processcite(dataset,reference,mark,compress,"page",setter,getter)
-end
+ -- pages (no compress)
--- num
+ do
-local function setter(dataset,tag,entry,internal)
- local text = entry.entries.text
- return {
- dataset = dataset,
- tag = tag,
- internal = internal,
- num = text,
- sortkey = text,
- }
-end
+ local function setter(data,dataset,tag,entry)
+ data.pages = getcasted(dataset,tag,"pages")
+ end
-local function getter(first,last)
- return simplegetter(first,last,"num")
-end
+ local function getter(first,last)
+ local pages = first.pages
+ if pages then
+ if type(pages) == "table" then
+ ctx_btxsetfirst(pages[1])
+ ctx_btxsetsecond(pages[2])
+ else
+ ctx_btxsetfirst(pages)
+ end
+ return true
+ end
+ end
-function citevariants.num(dataset,reference,mark,compress)
- processcite(dataset,reference,mark,compress,"num",setter,getter)
-end
+ function citevariants.page(presets)
+ processcite(presets,{
+ -- variant = presets.variant or "page",
+ setter = setter,
+ getter = getter,
+ })
+ end
--- year
-
-local function setter(dataset,tag,entry,internal)
- local year = getfield(dataset,tag,"year")
- return {
- dataset = dataset,
- tag = tag,
- internal = internal,
- year = year,
- sortkey = year,
- sortfld = "year",
- }
-end
+ end
-local function getter(first,last)
- return simplegetter(first,last,"year")
-end
+ -- num
-function citevariants.year(dataset,reference,mark,compress)
- processcite(dataset,reference,mark,compress,"year",setter,getter)
-end
+ do
--- index | serial
+ local function setter(data,dataset,tag,entry)
+ local entries = entry.entries
+ local text = entries and entries.text or "?"
+ data.num = text
+ data.sortkey = text
+ end
-local function setter(dataset,tag,entry,internal)
- local index = getfield(dataset,tag,"index")
- return {
- dataset = dataset,
- tag = tag,
- internal = internal,
- index = index,
- sortkey = index,
- }
-end
+ local function getter(first,last)
+ return simplegetter(first,last,"num")
+ end
-local function getter(first,last)
- return simplegetter(first,last,"index")
-end
+ function citevariants.num(presets)
+ processcite(presets,{
+ -- variant = presets.variant or "num",
+ setter = setter,
+ getter = getter,
+ })
+ end
-function citevariants.index(dataset,reference,mark,compress)
- processcite(dataset,reference,mark,compress,"index",setter,getter)
-end
+ end
-function citevariants.serial(dataset,reference,mark,compress)
- processcite(dataset,reference,mark,compress,"serial",setter,getter)
-end
+ -- year
--- category | type
+ do
-local function setter(dataset,tag,entry,internal)
- return {
- dataset = dataset,
- tag = tag,
- internal = internal,
- category = getfield(dataset,tag,"category"),
- }
-end
+ local function setter(data,dataset,tag,entry)
+ local year = getfield (dataset,tag,"year")
+ local suffix = getdetail(dataset,tag,"suffix")
+ data.year = year
+ data.suffix = suffix
+ data.sortkey = tonumber(year) or 9999
+ end
-local function getter(first,last)
- return simplegetter(first,last,"category")
-end
+ local function getter(first,last)
+ return simplegetter(first,last,"year")
+ end
-function citevariants.category(dataset,reference,mark,compress)
- processcite(dataset,reference,mark,compress,"category",setter,getter)
-end
+ function citevariants.year(presets)
+ processcite(presets,{
+ -- variant = presets.variant or "year",
+ setter = setter,
+ getter = getter,
+ })
+ end
-function citevariants.type(dataset,reference,mark,compress)
- processcite(dataset,reference,mark,compress,"type",setter,getter)
-end
+ end
--- key | tag
+ -- index | serial
-local function setter(dataset,tag,entry,internal)
- return {
- dataset = dataset,
- tag = tag,
- internal = internal,
- }
-end
+ do
-local function getter(first,last)
- ctx_btxsetfirst(first.tag)
- return true
-end
+ local function setter(data,dataset,tag,entry)
+ local index = getfield(dataset,tag,"index")
+ data.index = index
+ data.sortkey = index
+ end
-function citevariants.key(dataset,reference,mark,compress) return
- processcite(dataset,reference,mark,compress,"key",setter,getter)
-end
+ local function getter(first,last)
+ return simplegetter(first,last,"index")
+ end
-function citevariants.tag(dataset,reference,mark,compress) return
- processcite(dataset,reference,mark,compress,"tag",setter,getter)
-end
+ function citevariants.index(presets)
+ processcite(presets,{
+ -- variant = presets.variant or "index",
+ setter = setter,
+ getter = getter,
+ })
+ end
--- author
+ function citevariants.serial(presets)
+ processcite(presets,{
+ -- variant = presets.variant or "serial",
+ setter = setter,
+ getter = getter,
+ })
+ end
-local function setter(dataset,tag,entry,internal)
- return {
- dataset = dataset,
- tag = tag,
- internal = internal,
- author = getfield(dataset,tag,"author"),
- }
-end
+ end
-local function getter(first,last)
- ctx_btxsetfirst(first.author) -- todo: formatted
- return true
-end
+ -- key | tag
-function citevariants.author(dataset,reference,mark,compress)
- processcite(dataset,reference,mark,false,"author",setter,getter)
-end
+ do
--- todo : sort
--- todo : choose between publications or commands namespace
--- todo : use details.author
--- todo : sort details.author
--- (name, name and name) .. how names? how sorted?
--- todo: we loop at the tex end .. why not here
--- \cite[{hh,afo},kvm]
-
--- common
-
-local function authorcompressor(found,key)
- local result = { }
- local entries = { }
- for i=1,#found do
- local entry = found[i]
- local author = entry.author
- local aentries = entries[author]
- if aentries then
- aentries[#aentries+1] = entry
- else
- entries[author] = { entry }
+ local function setter(data,dataset,tag,entry)
+ -- nothing
+ end
+
+ local function getter(first,last)
+ ctx_btxsetfirst(first.tag)
+ return true
+ end
+
+ function citevariants.key(presets)
+ return processcite(presets,{
+ variant = "key",
+ setter = setter,
+ getter = getter,
+ })
+ end
+
+ function citevariants.tag(presets)
+ return processcite(presets,{
+ variant = "tag",
+ setter = setter,
+ getter = getter,
+ })
end
+
end
- for i=1,#found do
- local entry = found[i]
- local author = entry.author
- local aentries = entries[author]
- if not aentries then
- result[#result+1] = entry
- elseif aentries == true then
- -- already done
- else
- result[#result+1] = entry
- entry.entries = aentries
- entries[author] = true
+
+ -- keyword
+
+ do
+
+ local function listof(list)
+ local size = type(list) == "table" and #list or 0
+ if size > 0 then
+ return function()
+ for i=1,size do
+ ctx_btxsetfirst(list[i])
+ ctx_btxsetconcat(concatstate(i,size))
+ ctx_btxcitesetup("listelement")
+ end
+ return true
+ end
+ else
+ return "?" -- unknown
+ end
+ end
+
+ local function setter(data,dataset,tag,entry)
+ data.keywords = getcasted(dataset,tag,"keywords")
+ end
+
+ local function getter(first,last)
+ context(listof(first.keywords))
end
+
+ function citevariants.keywords(presets)
+ return processcite(presets,{
+ variant = "keywords",
+ setter = setter,
+ getter = getter,
+ })
+ end
+
end
- -- todo: add letters (should we then tag all?)
- return result
-end
-local function authorconcat(target,key,setup)
- local function flush(i,state)
- local entry = target[i]
- local first = entry.first
- if first then
- local internal = first.internal
- if internal then
- ctx_btxsetinternal(internal)
- end
- ctx_btxsetfirst(first[key] or f_missing(first.tag))
- local suffix = entry.suffix
- local value = entry.last[key]
+ -- authors
+
+ do
+
+ local currentbtxciteauthor = function()
+ context.currentbtxciteauthor()
+ return true -- needed?
+ end
+
+ local function authorcompressor(found)
+ local result = { }
+ local entries = { }
+ for i=1,#found do
+ local entry = found[i]
+ local author = entry.author
+ if author then
+ local aentries = entries[author]
+ if aentries then
+ aentries[#aentries+1] = entry
+ else
+ entries[author] = { entry }
+ end
+ end
+ end
+ -- beware: we usetables as hash so we get a cycle when inspecting (unless we start
+ -- hashing with strings)
+ for i=1,#found do
+ local entry = found[i]
+ local author = entry.author
+ if author then
+ local aentries = entries[author]
+ if not aentries then
+ result[#result+1] = entry
+ elseif aentries == true then
+ -- already done
+ else
+ result[#result+1] = entry
+ entry.entries = aentries
+ entries[author] = true
+ end
+ end
+ end
+ -- todo: add letters (should we then tag all?)
+ return result
+ end
+
+ local function authorconcat(target,key,setup)
+ ctx_btxstartsubcite(setup)
+ local nofcollected = #target
+ if nofcollected == 0 then
+ unknowncite(tag)
+ else
+ for i=1,nofcollected do
+ local entry = target[i]
+ local first = entry.first
+ local tag = entry.tag
+ local currentcitation = markcite(entry.dataset,tag)
+ ctx_btxstartciteauthor()
+ ctx_btxsettag(tag)
+ ctx_btxsetbacklink(currentcitation)
+ local bl = listtocite[currentcitation]
+ ctx_btxsetinternal(bl and bl.references.internal or "")
+ if first then
+ ctx_btxsetfirst(first[key] or "") -- f_missing(first.tag))
+ local suffix = entry.suffix
+ local value = entry.last[key]
+ if value then
+ ctx_btxsetsecond(value)
+ end
+ if suffix then
+ ctx_btxsetthird(suffix)
+ end
+ else
+ local suffix = entry.suffix
+ local value = entry[key] or "" -- f_missing(tag)
+ ctx_btxsetfirst(value)
+ if suffix then
+ ctx_btxsetthird(suffix)
+ end
+ end
+ ctx_btxsetconcat(concatstate(i,nofcollected))
+ if trace_detail then
+ report("expanding %a cite setup %a","multiple author",setup)
+ end
+ ctx_btxsubcitesetup(setup)
+ ctx_btxstopciteauthor()
+ end
+ end
+ ctx_btxstopsubcite()
+ end
+
+ local function authorsingle(entry,key,setup)
+ ctx_btxstartsubcite(setup)
+ ctx_btxstartciteauthor()
+ local tag = entry.tag
+ ctx_btxsettag(tag)
+ -- local currentcitation = markcite(entry.dataset,tag)
+ -- ctx_btxsetbacklink(currentcitation)
+ -- local bl = listtocite[currentcitation]
+ -- ctx_btxsetinternal(bl and bl.references.internal or "")
+ ctx_btxsetfirst(entry[key] or "") -- f_missing(tag)
if suffix then
- ctx_btxsetsecond(value .. converters.characters(suffix))
+ ctx_btxsetthird(entry.suffix)
+ end
+ if trace_detail then
+ report("expanding %a cite setup %a","single author",setup)
+ end
+ ctx_btxcitesetup(setup)
+ ctx_btxstopciteauthor()
+ ctx_btxstopsubcite()
+ end
+
+ local partialinteractive = false
+
+ local function authorgetter(first,last,key,setup) -- only first
+ -- ctx_btxsetfirst(first.author) -- unformatted
+ -- ctx_btxsetfirst(currentbtxciteauthor) -- formatter (much slower)
+ if first.type == "author" then
+ ctx_btxsetfirst(currentbtxciteauthor) -- formatter (much slower)
else
- ctx_btxsetsecond(value)
+ ctx_btxsetfirst(first.author) -- unformatted
end
- else
- local internal = entry.internal
- if internal then
- ctx_btxsetinternal(internal)
+ local entries = first.entries
+ -- alternatively we can use a concat with one ... so that we can only make the
+ -- year interactive, as with the concat
+ if partialinteractive and not entries then
+ entries = { first }
end
- local suffix = entry.suffix
- local value = entry[key] or f_missing(entry.tag)
- if suffix then
- ctx_btxsetfirst(value .. converters.characters(suffix))
+ if entries then
+ -- happens with year
+ local c = compresslist(entries)
+ local f = function() authorconcat(c,key,setup) return true end -- indeed return true?
+ ctx_btxsetcount(#c)
+ ctx_btxsetsecond(f)
+ elseif first then
+ -- happens with num
+ local f = function() authorsingle(first,key,setup) return true end -- indeed return true?
+ ctx_btxsetcount(0)
+ ctx_btxsetsecond(f)
+ end
+ return true
+ end
+
+ -- author
+
+ local function setter(data,dataset,tag,entry)
+ data.author, data.field, data.type = getcasted(dataset,tag,"author")
+ end
+
+ local function getter(first,last,_,setup)
+ if first.type == "author" then
+ ctx_btxsetfirst(currentbtxciteauthor) -- formatter (much slower)
else
- ctx_btxsetfirst(value)
+ ctx_btxsetfirst(first.author) -- unformatted
end
+ return true
end
- ctx_btxsetconcat(state)
- ctx_btxcitesetup(setup)
- end
- ctx_btxstartsubcite(setup)
- flushcollected(flush,#target)
- ctx_btxstopsubcite()
-end
-local function authorsingle(entry,key,setup)
- ctx_btxstartsubcite(setup)
- local internal = entry.internal
- if internal then
- ctx_btxsetinternal(internal)
- end
- ctx_btxsetfirst(entry[key] or f_missing(entry.tag))
- ctx_btxcitesetup(setup) -- ??
- ctx_btxstopsubcite()
-end
+ function citevariants.author(presets)
+ processcite(presets,{
+ compress = false,
+ variant = "author",
+ setter = setter,
+ getter = getter,
+ })
+ end
-local function authorgetter(first,last,key,setup) -- only first
- ctx_btxsetfirst(first.author) -- todo: reformat
- local entries = first.entries
- if entries then
- local c = compresslist(entries)
- ctx_btxsetsecond(function() authorconcat(c,key,setup) end)
- else
- ctx_btxsetsecond(function() authorsingle(first,key,setup) end)
- end
- return true
-end
+ -- authornum
--- authornum
-
-local function setter(dataset,tag,entry,internal)
- local text = entry.entries.text
- return {
- dataset = dataset,
- tag = tag,
- internal = internal,
- author = getfield(dataset,tag,"author"),
- num = text,
- sortkey = text and lpegmatch(numberonly,text)
- }
-end
+ local function setter(data,dataset,tag,entry)
+ local entries = entry.entries
+ local text = entries and entries.text or "?"
+ data.author, data.field, data.type = getcasted(dataset,tag,"author")
+ data.num = text
+ data.sortkey = text and lpegmatch(numberonly,text)
+ end
-local function getter(first,last)
- authorgetter(first,last,"num","author:num")
- return true
-end
+ local function getter(first,last)
+ authorgetter(first,last,"num","author:num")
+ return true
+ end
-local function compressor(found)
- return authorcompressor(found,"num")
-end
+ function citevariants.authornum(presets)
+ processcite(presets,{
+ variant = "authornum",
+ setter = setter,
+ getter = getter,
+ compressor = authorcompressor,
+ })
+ end
-function citevariants.authornum(dataset,reference,mark,compress)
- processcite(dataset,reference,mark,compress,"authornum",setter,getter,compressor)
-end
+ -- authoryear | authoryears
--- authoryear | authoryears
-
-local function setter(dataset,tag,entry,internal)
- local year = getfield(dataset,tag,"year")
- return {
- dataset = dataset,
- tag = tag,
- internal = internal,
- author = getfield(dataset,tag,"author"),
- year = year,
- sortkey = year and lpegmatch(numberonly,year),
- sortfld = "year",
- }
-end
+ local function setter(data,dataset,tag,entry)
+ data.author, data.field, data.type = getcasted(dataset,tag,"author")
+ local year = getfield (dataset,tag,"year")
+ local suffix = getdetail(dataset,tag,"suffix")
+ data.year = year
+ data.suffix = suffix
+ data.sortkey = tonumber(year) or 9999
+ end
-local function getter(first,last)
- authorgetter(first,last,"year","author:year")
- return true
-end
+ local function getter(first,last)
+ authorgetter(first,last,"year","author:year")
+ return true
+ end
-local function compressor(found)
- return authorcompressor(found,"year")
-end
+ function citevariants.authoryear(presets)
+ processcite(presets,{
+ variant = "authoryear",
+ setter = setter,
+ getter = getter,
+ compressor = authorcompressor,
+ })
+ end
-function citevariants.authoryear(dataset,reference,mark,compress)
- processcite(dataset,reference,mark,compress,"authoryear",setter,getter,compressor)
-end
+ local function getter(first,last)
+ authorgetter(first,last,"year","author:years")
+ return true
+ end
-local function getter(first,last)
- authorgetter(first,last,"year","author:years")
- return true
-end
+ function citevariants.authoryears(presets)
+ processcite(presets,{
+ variant = "authoryears",
+ setter = setter,
+ getter = getter,
+ compressor = authorcompressor,
+ })
+ end
+
+ end
-function citevariants.authoryears(dataset,reference,mark,compress)
- processcite(dataset,reference,mark,compress,"authoryears",setter,getter,compressor)
end
-- List variants
-local listvariants = { }
-publications.listvariants = listvariants
+do
-function commands.btxlistvariant(dataset,block,tag,variant,listindex)
- local action = listvariants[variant] or listvariants.default
- if action then
- action(dataset,block,tag,variant,tonumber(listindex) or 0)
+ local listvariants = { }
+ publications.listvariants = listvariants
+
+ local function btxlistvariant(dataset,block,tag,variant,listindex)
+ local action = listvariants[variant] or listvariants.default
+ if action then
+ action(dataset,block,tag,variant,tonumber(listindex) or 0)
+ end
end
-end
-function listvariants.default(dataset,block,tag,variant)
- context("?")
-end
+ implement {
+ name = "btxlistvariant",
+ actions = btxlistvariant,
+ arguments = { "string", "string", "string", "string", "string" } -- not integer here
+ }
--- function listvariants.num(dataset,block,tag,variant,listindex)
--- local lst = f_listentry(dataset,block,tag)
--- local ref = f_reference(dataset,block,tag)
--- if trace_references then
--- report_reference("list: %s",lst)
--- end
--- -- todo
--- ctx_btxdirectlink(ref,listindex) -- a goto
--- end
+ function listvariants.default(dataset,block,tag,variant)
+ ctx_btxsetfirst("?")
+ if trace_detail then
+ report("expanding %a list setup %a","default",variant)
+ end
+ ctx_btxlistsetup("default")
+ end
-function listvariants.num(dataset,block,tag,variant,listindex)
- context(listindex) -- a goto
-end
+ function listvariants.num(dataset,block,tag,variant,listindex)
+ ctx_btxsetfirst(listindex)
+ if trace_detail then
+ report("expanding %a list setup %a","num",variant)
+ end
+ ctx_btxlistsetup(variant)
+ end
+
+ listvariants[v_yes] = listvariants.num
+ listvariants.bib = listvariants.num
-function listvariants.short(dataset,block,tag,variant,listindex)
- local short = getdetail(dataset,tag,"short","short")
- local suffix = getdetail(dataset,tag,"suffix","suffix")
- if suffix then
- context(short .. suffix)
- elseif short then
- context(short)
+ function listvariants.short(dataset,block,tag,variant,listindex)
+ local short = getdetail(dataset,tag,"short","short")
+ local suffix = getdetail(dataset,tag,"suffix","suffix")
+ if short then
+ ctx_btxsetfirst(short)
+ end
+ if suffix then
+ ctx_btxsetthird(suffix)
+ end
+ if trace_detail then
+ report("expanding %a list setup %a","short",variant)
+ end
+ ctx_btxlistsetup(variant)
+ end
+
+ function listvariants.page(dataset,block,tag,variant,listindex)
+ local rendering = renderings[dataset]
+ local specification = rendering.list[listindex]
+ for i=3,#specification do
+ local backlink = tonumber(specification[i])
+ if backlink then
+ local citation = citetolist[backlink]
+ if citation then
+ local references = citation.references
+ if references then
+ local internal = references.internal
+ local realpage = references.realpage
+ if internal and realpage then
+ ctx_btxsetconcat(i-2)
+ ctx_btxsetfirst(realpage)
+ ctx_btxsetsecond(backlink)
+ if trace_detail then
+ report("expanding %a list setup %a","page",variant)
+ end
+ ctx_btxlistsetup(variant)
+ end
+ end
+ end
+ end
+ end
end
+
end
diff --git a/Master/texmf-dist/tex/context/base/publ-ini.mkiv b/Master/texmf-dist/tex/context/base/publ-ini.mkiv
index fb0d00d03c0..a4452e45193 100644
--- a/Master/texmf-dist/tex/context/base/publ-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/publ-ini.mkiv
@@ -11,6 +11,11 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+
+% TODO: s! vs v! for default and neutral key/values
+% todo: too many refs in list
+
+% todo: tagging
% todo: we cannot use 'default' as this wipes metadata names (maybe no longer do that)
% todo: \v!cite => \s!cite
% todo: interface with (ml)bibtex (export -> call -> import)
@@ -38,171 +43,229 @@
\writestatus{loading}{ConTeXt Publication Support / Initialization}
\registerctxluafile{publ-dat}{1.001}
+\registerctxluafile{publ-ini}{1.001}
+\registerctxluafile{publ-sor}{1.001}
\registerctxluafile{publ-aut}{1.001}
\registerctxluafile{publ-usr}{1.001}
-\registerctxluafile{publ-ini}{1.001}
\registerctxluafile{publ-oth}{1.001} % this could become an option
-
-\doiffileelse{publ-fnd.lua}
- {\registerctxluafile{publ-fnd}{1.001}} % new method (for the moment only local)
- {}
+\registerctxluafile{publ-fnd}{1.001} % new method (for the moment only local)
+\registerctxluafile{publ-jrn}{1.001}
+\registerctxluafile{publ-reg}{1.001}
\unprotect
\startcontextdefinitioncode
-\def\s!btx {btx}
-\def\s!cite {cite}
-\def\s!list {list}
-\def\v!btxcite{btxcite}
-\def\v!btxlist{btxlist}
-
-% a dedicated construction mechanism
-
-\installcorenamespace {btxlist}
+\def\s!btx {btx}
+
+\def\v!btxcite {btxcite}
+\def\v!btxlist {btxlist}
+\def\v!btxrendering {btxrendering}
+
+\def\s!btxset {btxset}
+\def\s!btxref {btxref}
+\def\s!btxint {btxint}
+\def\s!btxbck {btxbck}
+\def\s!btxltx {btxltx}
+\def\s!btxrtx {btxrtx}
+\def\s!btxatx {btxatx}
+\def\s!btxbtx {btxbtx}
+\def\s!btxspc {btxspc}
+\def\s!btxlst {btxlst}
+
+\definelabelclass[btxlabel][2]
+
+% It is not that trivial to come up with a proper organization of setup
+% and control commands for publications. This is because we have complex
+% inline as well as extensive list rendering. The rules are partially
+% driven by somewhat archaic bibtex specifications and evolving journal
+% (or field) specific demands. The logic in the standards is often so
+% complex that it looks like manual rendering is assumed. But, we want to
+% automate the process as much as possible.
+%
+% Another complication is that in manuals we want to demonstrate different
+% properties of the implementation and therefore we need a way to handle
+% independent standards, databases, etc. This has resulted in the following
+% organization:
+%
+% - general setup (rather minimal)
+% - list setup (rendering)
+% - cite setup
+% - dataset setup
+%
+% The rendering is mostly driven by setups. In there we can call for fields
+% in the database but also for virtual fields or combinations.
-\installcommandhandler \??btxlist {btxlist} \??btxlist
+% The main rendering style (standard driven).
-\unexpanded\setvalue{\??constructioninitializer\v!btxlist}%
- {\let\currentbtxlist \currentconstruction
- \let\constructionparameter \btxlistparameter
- \let\detokenizedconstructionparameter\detokenizedbtxlistparameter
- \let\letconstructionparameter \letbtxlistparameter
- \let\useconstructionstyleandcolor \usebtxliststyleandcolor
- \let\setupcurrentconstruction \setupcurrentbtxlist}
+%D We assume that a specification is global or used grouped. It doesn't make much sense
+%D to split between cite and list here as it only complicates matters (timing) and is
+%D not clear either.
-\expandafter\let\csname\??constructionmainhandler \v!btxlist\expandafter\endcsname\csname\??constructionmainhandler \v!construction\endcsname
-\expandafter\let\csname\??constructioncommandhandler\v!btxlist\expandafter\endcsname\csname\??constructioncommandhandler\v!construction\endcsname
-\expandafter\let\csname\??constructiontexthandler \v!btxlist\expandafter\endcsname\csname\??constructiontexthandler \v!construction\endcsname
+\let\currentbtxspecification\empty
-\unexpanded\setvalue{\??constructioncommandhandler\v!btxlist}%
- {\csname\??constructionstarthandler\v!construction\endcsname
- \csname\??constructionstophandler \v!construction\endcsname
- \endgroup}
+\unexpanded\def\startbtxrenderingdefinitions[#1]%
+ {\unprotect
+ \pushmacro\currentbtxspecification
+ \edef\currentbtxspecification{#1}}
-\unexpanded\setvalue{\??constructionstarthandler\v!btxlist}%
- {\csname\??constructionstarthandler\v!construction\endcsname}
+\unexpanded\def\stopbtxrenderingdefinitions
+ {\popmacro\currentbtxspecification
+ \protect}
-\unexpanded\setvalue{\??constructionstophandler\v!btxlist}%
- {\csname\??constructionstophandler\v!construction\endcsname
- \endgroup}
+\unexpanded\def\loadbtxdefinitionfile [#1]{\clf_btxloaddefinitionfile {#1}}
+\unexpanded\def\loadbtxreplacementfile[#1]{\clf_btxloadreplacementfile{#1}}
-\unexpanded\def\startbtxlistentry#1%
- {\begingroup
- \strc_constructions_initialize{#1}%
- \csname\??constructionstarthandler\currentconstructionhandler\endcsname}
+\unexpanded\def\publ_specification_push#1%
+ {\pushmacro\currentbtxspecification
+ \pushmacro\currentbtxspecificationfallback
+ \edef\currentbtxspecification{#1}%
+ \edef\currentbtxspecificationfallback{\namedbtxparameter\currentbtxspecification\c!default}%
+ \ifx\currentbtxspecificationfallback\currentbtxspecification
+ \let\currentbtxspecificationfallback\empty
+ \fi
+ \clf_btxsetspecification{\currentbtxspecification}}
+
+\unexpanded\def\publ_specification_pop
+ {\popmacro\currentbtxspecificationfallback
+ \popmacro\currentbtxspecification
+ \clf_btxsetspecification{\currentbtxspecification}}
+
+\unexpanded\def\publ_specification_set#1% beware: is global
+ {\edef\currentbtxspecification{#1}%
+ \edef\currentbtxspecificationfallback{\namedbtxparameter\currentbtxspecification\c!default}%
+ \ifx\currentbtxspecificationfallback\currentbtxspecification
+ \let\currentbtxspecificationfallback\empty
+ \fi
+ % has to be done explicitly: \loadbtxdefinitionfile[\currentbtxspecification]%
+ \ifx\currentbtxspecification\empty
+ % we set default at the end
+ \else
+ \clf_btxsetspecification{\currentbtxspecification}%
+ \fi}% todo: ,true == also load
-\unexpanded\def\stopbtxlistentry
- {\csname\??constructionstophandler\currentconstructionhandler\endcsname}
+\installcorenamespace {btx}
-\unexpanded\setvalue{\??constructiontexthandler\v!btxlist}%
- {\begingroup
- \useconstructionstyleandcolor\c!headstyle\c!headcolor % move to \currentconstructiontext
- \the\everyconstruction
- \goto
- {\strut\constructionparameter\c!text\btx_list_reference_inject}%
-% [\s!btx:list:\the\numexpr\locationcount+\plusone]% \nextinternalreference
- [internal(\the\numexpr\locationcount+\plusone)]% \nextinternalreference
- \endgroup}
+\installswitchcommandhandler \??btx {btx} \??btx
-\unexpanded\def\strc_constructions_initialize#1% class instance
- {\edef\currentconstruction{#1}%
- \let\currentconstructionlistentry\!!zerocount
- \expandafter\let\expandafter\currentconstructionmain \csname\??constructionmain \currentconstruction\endcsname
- \expandafter\let\expandafter\currentconstructionlevel \csname\??constructionlevel\currentconstruction\endcsname
- \expandafter\let\expandafter\currentconstructionhandler\csname\??constructionclass\currentconstruction\endcsname
- \csname\??constructioninitializer\currentconstructionhandler\endcsname}
+\appendtoks
+ \ifnum\btxsetupmode=\doingrootsetuproot
+ \publ_specification_set{\btxparameter\c!specification}%
+ \else\ifnum\btxsetupmode=\doingrootsetupnamed
+ \publ_specification_set{\btxparameter\c!specification}%
+ \fi\fi
+\to \everysetupbtx
\appendtoks
- % \ifx\currentbtxlistparent\empty
- % \defineconstruction[\currentbtxlist][\currentbtxlistparent][\s!handler=\v!btxlist,\c!level=1]%
- % \else
- % \defineconstruction[\currentbtxlist][\s!handler=\v!btxlist,\c!level=1]%
- % \fi
- \ifx\currentbtxlistparent\empty
- \letvalue{\??constructionmain\currentbtxlist}\currentbtxlist
- \else
- \letvalue{\??constructionmain\currentbtxlist}\currentbtxlistparent
+ \ifnum\btxsetupmode=\doingrootsetuproot
+ \edef\currentbtxdataset{\clf_btxsetdataset{\btxparameter\c!dataset}{\currentbtxdataset}}%
\fi
- \setevalue{\??constructionlevel\currentbtxlist}{\number\btxlistparameter\c!level}%
- \setevalue{\??constructionclass\currentbtxlist}{\btxlistparameter\s!handler}%
-\to \everydefinebtxlist
-
-\setupbtxlist
- [\s!handler=\v!btxlist,
- \c!level=1]
-
-\setupbtxlist
- [\c!alternative=\v!left,
- \c!headstyle=,
- \c!titlestyle=,
- %\c!style=,
- %\c!color=,
- %\c!headcolor=,
- %\c!titlecolor=,
- \c!width=4\emwidth,
- \c!distance=\emwidth,
- %\c!titledistance=.5\emwidth,
- %\c!hang=,
- %\c!sample=,
- %\c!align=,
- %\c!headalign=,
- \c!margin=\v!no,
- \c!before=\blank,
- \c!inbetween=\blank,
- \c!after=\blank,
- %\c!indentnext=\v!yes,
- %\c!indenting=\v!never,
- %\c!titleleft=(,
- %\c!titleright=),
- %\c!closesymbol=,
- %\c!closecommand=\wordright,
- \c!display=\v!yes,
- \c!command=,
- %\c!titlecommand=,
- %\c!expansion=\v!no,
- %\c!xmlsetup=,
- %\s!catcodes=,
- %\c!title=\v!yes,
- %\c!text=,
- ]
+\to \everysetupbtx
+
+\appendtoks
+ \publ_specification_set{\btxparameter\c!specification}%
+\to \everyjob
+
+\unexpanded\def\startusingbtxspecification[#1]%
+ {\publ_specification_push{#1}}
+
+\let\stopusingbtxspecification\publ_specification_pop
+
+% \setupbtxlist[alternative=paragraph,width=auto,distance=\emwidth]
+% \setupbtxlist[alternative=paragraph,width=auto,distance=\emwidth,margin=2em] % useless
+% \setupbtxlist[alternative=paragraph,width=fit,distance=\emwidth]
+% \setupbtxlist[alternative=paragraph,width=fit,distance=\emwidth,margin=2em]
% here starts the bib stuff
\installcorenamespace {btxdataset}
-\installcorenamespace {btxlistvariant}
-\installcorenamespace {btxcitevariant}
\installcorenamespace {btxrendering}
+\installcorenamespace {btxregister}
\installcorenamespace {btxcommand}
-\installcorenamespace {btxnumbering}
-
-\installcommandhandler \??btxdataset {btxdataset} \??btxdataset
-\installcommandhandler \??btxlistvariant {btxlistvariant} \??btxlistvariant
-\installcommandhandler \??btxcitevariant {btxcitevariant} \??btxcitevariant
-\installcommandhandler \??btxrendering {btxrendering} \??btxrendering
+\installcorenamespace {btxrenderingdefinition}
+
+\installcommandhandler \??btxdataset {btxdataset} \??btxdataset
+\installcommandhandler \??btxregister {btxregister} \??btxregister
+\installcommandhandler \??btxrendering {btxrendering} \??btxrendering
+
+\let\currentbtxcitealternative\empty
+
+\let\currentbtxspecificationfallback\empty
+
+\unexpanded\def\setbtxparameterset#1#2%
+ {\edef\currentbtx
+ {\ifcsname\??btx\currentbtxspecification:#1:#2:\s!parent\endcsname
+ \currentbtxspecification:%
+ \else\ifx\currentbtxspecificationfallback\empty
+ \else\ifcsname\??btx\currentbtxspecificationfallback:#1:#2:\s!parent\endcsname
+ \currentbtxspecificationfallback:%
+ \fi\fi\fi#1:#2}}
+
+\unexpanded\def\setbtxparametersetroot#1%
+ {\edef\currentbtx
+ {\ifcsname\??btx\currentbtxspecification:#1:\s!parent\endcsname
+ \currentbtxspecification:#1%
+ \else\ifx\currentbtxspecificationfallback\empty
+ \else\ifcsname\??btx\currentbtxspecificationfallback:#1:\s!parent\endcsname
+ \currentbtxspecificationfallback:#1%
+ \fi\fi\fi}}
+
+\unexpanded\def\setbtxrendering
+ {\edef\currentbtxrendering
+ {\ifcsname\??btx\currentbtxspecification:\s!parent\endcsname
+ \currentbtxspecification
+ \else\ifx\currentbtxspecificationfallback\empty
+ \else\ifcsname\??btx\currentbtxspecificationfallback:\s!parent\endcsname
+ \currentbtxspecificationfallback
+ \fi\fi\fi}}
+
+\unexpanded\def\setbtxlist % maybe simplify this one, always list=rendering?
+ {\edef\currentbtxlist
+ {\ifcsname\??btx\currentbtxrendering:\s!parent\endcsname
+ \currentbtxrendering
+ \else\ifcsname\??btx\currentbtxspecification:\s!parent\endcsname
+ \currentbtxspecification
+ \else\ifx\currentbtxspecificationfallback\empty
+ \else\ifcsname\??btx\currentbtxspecificationfallback:\s!parent\endcsname
+ \currentbtxspecificationfallback
+ \fi\fi\fi\fi}%
+ \edef\currentlist{\s!btx:\currentbtxlist}}
\unexpanded\def\usebtxdataset
- {\dodoubleargument\publ_use_dataset}
+ {\begingroup
+ \dotripleempty\publ_use_dataset}
-\def\publ_use_dataset[#1][#2]%
- {\ifsecondargument
- \ctxcommand{usebtxdataset("#1","#2")}%
- \else
- \ctxcommand{usebtxdataset("\v!standard","#1")}%
- \fi}
+\def\publ_use_dataset[#1][#2][#3]%
+ {\getdummyparameters[\c!specification=\currentbtxspecification,#3]%
+ \ifsecondargument
+ \clf_btxusedataset
+ specification {\dummyparameter\c!specification}%
+ dataset {#1}%
+ filename {#2}%
+ \relax
+ \else\iffirstargument
+ \clf_btxusedataset
+ specification {\dummyparameter\c!specification}%
+ dataset {\v!default}%
+ filename {#1}%
+ \relax
+ \fi\fi
+ \endgroup}
\definebtxdataset
- [\v!standard]
+ [\v!default]
+% [\c!language=] % nothing set so use current
% \usebtxdataset
-% [standard]
+% [default]
% [mybibs.bib]
+\let\startpublication\relax
+\let\stoppublication \relax
+
\unexpanded\def\startpublication
{\dodoubleempty\publ_set_publication}
-\let\stoppublication\relax
-
\def\publ_set_publication[#1][#2]%
{\begingroup
\catcode\commentasciicode\othercatcode
@@ -215,15 +278,15 @@
\fi\fi{#1}{#2}}
\def\publ_set_publication_default#1#2%
- {\publ_set_publication_indeed\v!standard{#1}}
+ {\publ_set_publication_indeed\v!default{#1}}
\def\publ_set_publication_checked#1#2%
- {\doifassignmentelse{#1}
- {\publ_set_publication_indeed\v!standard{#1}}
+ {\doifelseassignment{#1}
+ {\publ_set_publication_indeed\v!default{#1}}
{\publ_set_publication_indeed{#1}{}}}
\def\publ_set_publication_indeed#1#2#3\stoppublication
- {\ctxcommand{addbtxentry("#1",\!!bs#2\!!es,\!!bs\detokenize{#3}\!!es)}%
+ {\clf_btxaddentry{#1}{#2}{\detokenize{#3}}%
\endgroup
\ignorespaces}
@@ -259,29 +322,45 @@
\unexpanded\def\definebtxcommand#1% {body} #1..#n{body}
{\setuvalue{\??btxcommand\strippedcsname#1}}%
+% tracing
+
+\installtextracker
+ {publications.crosslinks}
+ {\let\btx_trace_list_cross\strc_references_tracer}
+ {\let\btx_trace_list_cross\gobbletwoarguments}
+
+\let\btx_trace_list_cross\gobbletwoarguments
+
% access
\let\currentbtxtag \empty
-\let\currentbtxdataset\v!standard
+\let\currentbtxdataset\v!default
-\unexpanded\def\setbtxdataset[#1]%
- {\edef\currentbtxdataset{\ctxcommand{setbtxdataset("#1")}}}
-
-\unexpanded\def\setbtxentry[#1]%
- {\edef\currentbtxtag{\ctxcommand{setbtxentry("\currentbtxdataset","#1")}}}
+\unexpanded\def\setbtxentry[#1]% or maybe btxsetentry
+ {\edef\currentbtxtag{\clf_btxsetentry{\currentbtxdataset}{#1}}}
% \let\btxsetdataset\setbtxdataset
% \let\btxsetentry \setbtxentry
-\def\btxfield #1{\ctxcommand{btxfield("\currentbtxdataset","\currentbtxtag","#1")}}
-\def\btxdetail #1{\ctxcommand{btxdetail("\currentbtxdataset","\currentbtxtag","#1")}}
-\def\btxflush #1{\ctxcommand{btxflush("\currentbtxdataset","\currentbtxtag","#1")}}
-%def\btxrendering#1{\ctxcommand{btxrendering("\currentbtxdataset","\currentbtxtag","#1","\btxrenderingparameter\c!interaction")}}
-\def\btxdoifelse #1{\ctxcommand{btxdoifelse("\currentbtxdataset","\currentbtxtag","#1")}}
-\def\btxdoif #1{\ctxcommand{btxdoif("\currentbtxdataset","\currentbtxtag","#1")}}
-\def\btxdoifnot #1{\ctxcommand{btxdoifnot("\currentbtxdataset","\currentbtxtag","#1")}}
-
-\let\btxsetup \directsetup
+% todo: no need for the currents as we can keep them at the lua end so we will have
+%
+% \btxfield : current
+% \btxspecificfield : dataset,tag,key
+
+\def\btxfield #1{\clf_btxfield {\currentbtxdataset}{\currentbtxtag}{#1}}
+\def\btxdetail #1{\clf_btxdetail {\currentbtxdataset}{\currentbtxtag}{#1}}
+\def\btxflush #1{\clf_btxflush {\currentbtxdataset}{\currentbtxtag}{#1}}
+\def\btxdirect #1{\clf_btxdirect {\currentbtxdataset}{\currentbtxtag}{#1}}
+\def\btxfieldname #1{\clf_btxfieldname {\currentbtxdataset}{\currentbtxtag}{#1}}
+\def\btxfieldtype #1{\clf_btxfieldtype {\currentbtxdataset}{\currentbtxtag}{#1}}
+\def\btxfoundname #1{\clf_btxfoundname {\currentbtxdataset}{\currentbtxtag}{#1}}
+\def\btxfoundtype #1{\clf_btxfoundtype {\currentbtxdataset}{\currentbtxtag}{#1}}
+\def\btxauthorfield#1{\clf_btxauthorfield \currentbtxauthorindex{#1}}
+\def\btxdoifelse #1{\clf_btxdoifelse {\currentbtxdataset}{\currentbtxtag}{#1}}
+\def\btxdoif #1{\clf_btxdoif {\currentbtxdataset}{\currentbtxtag}{#1}}
+\def\btxdoifnot #1{\clf_btxdoifnot {\currentbtxdataset}{\currentbtxtag}{#1}}
+
+\let\btxsetup\fastsetup
%D How complex will we go? Can we assume that e.g. an apa style will not be mixed
%D with another one? I think this assumption is okay. For manuals we might want to
@@ -289,93 +368,280 @@
%D Rendering.
-\unexpanded\def\btxspace {\removeunwantedspaces\space}
-\unexpanded\def\btxperiod {\removeunwantedspaces.\space}
-\unexpanded\def\btxcomma {\removeunwantedspaces,\space}
-\unexpanded\def\btxlparent {\removeunwantedspaces\space(}
-\unexpanded\def\btxrparent {\removeunwantedspaces)\space}
-\unexpanded\def\btxlbracket{\removeunwantedspaces\space[}
-\unexpanded\def\btxrbracket{\removeunwantedspaces]\space}
+\unexpanded\def\btxspace {\removeunwantedspaces\space}
+\unexpanded\def\btxnobreakspace {\removeunwantedspaces\nobreakspace} % these two are
+\unexpanded\def\btxnbsp {\removeunwantedspaces\nbsp} % the same anyway
+\unexpanded\def\btxperiod {\removeunwantedspaces.\space}
+\unexpanded\def\btxcomma {\removeunwantedspaces,\space}
+\unexpanded\def\btxcolon {\removeunwantedspaces:\space}
+\unexpanded\def\btxsemicolon {\removeunwantedspaces;\space}
+\unexpanded\def\btxlparent {\removeunwantedspaces\space(} % obsolete
+\unexpanded\def\btxrparent {\removeunwantedspaces)\space} % obsolete
+\unexpanded\def\btxleftparenthesis {\removeunwantedspaces\space(}
+\unexpanded\def\btxrightparenthesis {\removeunwantedspaces)\space}
+\unexpanded\def\btxrightparenthesisperiod{\removeunwantedspaces).\space}
+\unexpanded\def\btxrightparenthesiscomma {\removeunwantedspaces),\space}
+\unexpanded\def\btxleftbracket {\removeunwantedspaces\space[}
+\unexpanded\def\btxrightbracket {\removeunwantedspaces]\space}
+\unexpanded\def\btxrightbracketperiod {\removeunwantedspaces].\space}
+\unexpanded\def\btxrightbracketcomma {\removeunwantedspaces],\space}
+
+%D Variables:
+
+\let\currentbtxbacklink \empty \unexpanded\def\btxsetbacklink {\def\currentbtxbacklink}
+\let\currentbtxbacktrace \empty \unexpanded\def\btxsetbacktrace {\def\currentbtxbacktrace}
+\let\currentbtxcategory \empty \unexpanded\def\btxsetcategory {\def\currentbtxcategory}
+\let\currentbtxcombis \empty \unexpanded\def\btxsetcombis {\def\currentbtxcombis}
+\let\currentbtxdataset \empty \unexpanded\def\btxsetdataset {\def\currentbtxdataset}
+\let\currentbtxfirst \empty \unexpanded\def\btxsetfirst {\def\currentbtxfirst}
+\let\currentbtxsecond \empty \unexpanded\def\btxsetsecond {\def\currentbtxsecond}
+\let\currentbtxthird \empty \unexpanded\def\btxsetthird {\def\currentbtxthird}
+\let\currentbtxinternal \empty \unexpanded\def\btxsetinternal {\def\currentbtxinternal}
+\let\currentbtxlefttext \empty \unexpanded\def\btxsetlefttext {\def\currentbtxlefttext}
+\let\currentbtxrighttext \empty \unexpanded\def\btxsetrighttext {\def\currentbtxrighttext}
+\let\currentbtxbefore \empty \unexpanded\def\btxsetbefore {\def\currentbtxbefore}
+\let\currentbtxafter \empty \unexpanded\def\btxsetafter {\def\currentbtxafter}
+\let\currentbtxlanguage \empty \unexpanded\def\btxsetlanguage {\def\currentbtxlanguage}
+\let\currentbtxtag \empty \unexpanded\def\btxsettag {\def\currentbtxtag}
+\let\currentbtxnumber \empty \unexpanded\def\btxsetnumber {\def\currentbtxnumber}
+\let\currentbtxauthorvariant\v!normal \unexpanded\def\btxsetauthorvariant{\def\currentbtxauthorvariant}
+
+\let\currentbtxfirstnames \empty \unexpanded\def\btxsetfirstnames{\let\currentbtxfirstnames\currentbtxfirstnames_indeed}
+\let\currentbtxinitials \empty \unexpanded\def\btxsetinitials {\let\currentbtxinitials \currentbtxinitials_indeed }
+\let\currentbtxjuniors \empty \unexpanded\def\btxsetjuniors {\let\currentbtxjuniors \currentbtxjuniors_indeed }
+\let\currentbtxsurnames \empty \unexpanded\def\btxsetsurnames {\let\currentbtxsurnames \currentbtxsurnames_indeed }
+\let\currentbtxvons \empty \unexpanded\def\btxsetvons {\let\currentbtxvons \currentbtxvons_indeed }
+
+\newconstant\currentbtxoverflow \unexpanded\def\btxsetoverflow #1{\currentbtxoverflow #1\relax}
+\newconstant\currentbtxconcat \unexpanded\def\btxsetconcat #1{\currentbtxconcat #1\relax}
+\newconstant\currentbtxcount \unexpanded\def\btxsetcount #1{\currentbtxcount #1\relax}
+\newconstant\currentbtxauthorindex %unexpanded\def\btxsetauthorindex#1{\currentbtxauthorindex#1\relax} % passed directly
+\newconstant\currentbtxauthorcount %unexpanded\def\btxsetauthorcount#1{\currentbtxauthorcount#1\relax} % passed directly
+\newconstant\currentbtxauthorstate \unexpanded\def\btxsetauthorstate#1{\currentbtxauthorstate#1\relax}
+
+\unexpanded\def\currentbtxfirstnames_indeed{\clf_btxcurrentfirstnames\numexpr\currentbtxauthorindex\relax}
+\unexpanded\def\currentbtxinitials_indeed {\clf_btxcurrentinitials \numexpr\currentbtxauthorindex\relax}
+\unexpanded\def\currentbtxjuniors_indeed {\clf_btxcurrentjuniors \numexpr\currentbtxauthorindex\relax}
+\unexpanded\def\currentbtxsurnames_indeed {\clf_btxcurrentsurnames \numexpr\currentbtxauthorindex\relax}
+\unexpanded\def\currentbtxvons_indeed {\clf_btxcurrentvons \numexpr\currentbtxauthorindex\relax}
+
+\def\currentbtxauthorvariant{normal}
+
+\unexpanded\def\btxlistreset
+ {\let\currentbtxcombis \empty
+ \let\currentbtxcategory \empty
+ \let\currentbtxinternal \empty
+ \let\currentbtxlefttext \empty
+ \let\currentbtxrighttext\empty
+ \let\currentbtxbefore \empty
+ \let\currentbtxafter \empty
+ \let\currentbtxbacklink \empty
+ \let\currentbtxbacktrace\empty
+ \let\currentbtxlanguage \empty
+ \let\currentbtxtag \empty
+ \let\currentbtxnumber \empty
+ \let\currentbtxdataset \empty}
+
+\unexpanded\def\btxcitereset % check for less .. not all resets needed
+ {\let \currentbtxfirst \empty
+ \let \currentbtxsecond \empty
+ \let \currentbtxinternal \empty
+ \let \currentbtxlefttext \empty
+ \let \currentbtxrighttext \empty
+ \let \currentbtxbefore \empty
+ \let \currentbtxafter \empty
+ \let \currentbtxbacklink \empty
+ \let \currentbtxbacktrace \empty % not used here
+ \let \currentbtxlanguage \empty
+ \let \currentbtxdataset \empty
+ \let \currentbtxtag \empty
+ \let \currentbtxnumber \empty
+ \setconstant\currentbtxoverflow \zerocount
+ \setconstant\currentbtxconcat \zerocount
+ \setconstant\currentbtxcount \zerocount}
+
+%D Language:
+
+\def\mainbtxlanguage{\currentmainlanguage}
+
+\unexpanded\def\btx_check_language
+ {\let\mainbtxlanguage\currentlanguage
+ \ifx\currentbtxlanguage\empty
+ \let\currentbtxlanguage\currentlanguage
+ \else
+ \btx_check_language_indeed
+ \fi}
-%D Rendering lists and citations.
+\unexpanded\def\btx_check_language_indeed
+ {\edef\currentbtxlanguage{\reallanguagetag\currentbtxlanguage}%
+ \ifx\currentbtxlanguage\empty
+ \let\currentbtxlanguage\currentlanguage
+ \else\ifx\currentbtxlanguage\currentlanguage\else
+ \setcurrentlanguage\currentmainlanguage\currentbtxlanguage
+ \fi\fi}
+
+%D Tracing
-\newconditional\c_btx_trace
+\newconditional\c_btx_trace % not used yet
\installtextracker
{btxrendering}
{\settrue \c_btx_trace}
{\setfalse\c_btx_trace}
-\unexpanded\def\startbtxrendering
- {\begingroup
- \dosingleempty\btx_start_rendering}
-
-\def\btx_start_rendering[#1]%
- {\edef\currentbtxrendering{#1}}
-
-\unexpanded\def\stopbtxrendering
- {\endgroup}
+%D Rendering lists and citations.
\unexpanded\def\btxtodo#1%
{[#1]}
-%D Specific rendering definitions (like apa):
-
-\unexpanded\def\loadbtxdefinitionfile[#1]%
- {\ctxcommand{loadbtxdefinitionfile("#1")}}
-
%D Lists:
\newdimen\d_publ_number_width
%newdimen\d_publ_number_distance
\ifdefined\btxblock \else \newcount\btxblock \fi \btxblock\plusone
-\ifdefined\btxlistcounter \else \newcount\btxlistcounter \fi
-\ifdefined\btxcitecounter \else \newcount\btxcitecounter \fi
+\ifdefined\btxcitecounter \else \newcount\btxcitecounter \fi % maybe pass this to lua
\newtoks \everysetupbtxlistplacement % name will change
\newtoks \everysetupbtxciteplacement % name will change
-% \def\publ_list_processor % bibref -> btx (old method, keep as reference)
-% {\ctxcommand{btxaddtolist("\currentbtxrendering",\currentlistindex,"btxref")}}
-
\definelist % only used for selecting
[\s!btx]
\setuplist
- [\s!btx]%
- [\c!state=\v!start]%
+ [\s!btx]
+ [\c!prefixstopper=:,
+ \c!state=\v!start,
+ \c!alternative=\v!paragraph,
+ \c!before=\blank,
+ \c!after=\blank,
+ \c!width=\v!auto,
+ \c!distance=\emwidth]
+
+\unexpanded\def\setupbtxlist
+ {\dodoubleempty\publ_setup_list}
+
+\unexpanded\def\publ_setup_list[#1][#2]%
+ {\ifsecondargument
+ \setuplist[\s!btx:#1][#2]%
+ \else\iffirstargument
+ \setuplist[\s!btx][#1]%
+ \fi\fi}
\appendtoks
\ifx\currentbtxrenderingparent\empty
- \definebtxlist
- [\currentbtxrendering]%
+ \definelist
+ [\s!btx:\currentbtxrendering]%
+ [\s!btx]%
+ \else\ifx\currentbtxrenderingparent\s!btx
+ \definelist
+ [\s!btx:\currentbtxrendering]%
+ [\s!btx]%
\else
- \definebtxlist
- [\currentbtxrendering]%
- [\currentbtxrenderingparent]%
- \fi
+ \definelist
+ [\s!btx:\currentbtxrendering]%
+ [\s!btx:\currentbtxrenderingparent]%
+ \fi\fi
\to \everydefinebtxrendering
-\let\currentbtxcombis\empty % goes into the setups
+\newconditional\c_btx_list_texts
+
+\appendtoks
+ \doifelse{\btxrenderingparameter\c!textstate}\v!start
+ \settrue\setfalse\c_btx_list_texts
+\to \everysetupbtxlistplacement
+
+% page stuff (for thomas)
+
+\let\currentbtxfirstpage \empty \unexpanded\def\btxsetfirstpage #1{\def\currentbtxfirstpage{\btx_page_number{#1}}}
+\let\currentbtxlastpage \empty \unexpanded\def\btxsetlastpage #1{\def\currentbtxlastpage {\btx_page_number{#1}}}
+\let\currentbtxfirstinternal\empty \unexpanded\def\btxsetfirstinternal {\def\currentbtxfirstinternal}
+\let\currentbtxlastinternal \empty \unexpanded\def\btxsetlastinternal {\def\currentbtxlastinternal}
+
+\unexpanded\def\btx_page_number#1%
+ {\def\currentlistindex{#1}%
+ \structurelistpagenumber}
+
+\unexpanded\def\btxpagereset
+ {\let \currentbtxfirstpage \empty
+ \let \currentbtxlastpage \empty
+ \let \currentbtxfirstinternal\empty
+ \let \currentbtxlastinternal \empty
+ \setconstant\currentbtxoverflow \zerocount
+ \setconstant\currentbtxconcat \zerocount
+ \setconstant\currentbtxcount \zerocount}
+
+\newconditional\c_btx_list_pages
+
+\appendtoks
+ \doifelse{\btxrenderingparameter\c!pagestate}\v!start
+ \settrue\setfalse\c_btx_list_pages
+\to \everysetupbtxlistplacement
+
+\unexpanded\def\btx_entry_inject_pages % for the moment only normal
+ {\dontleavehmode
+ \begingroup
+ \setbtxlist % probably already set
+ \btxpagereset
+ \setbtxparameterset\s!page\s!list
+ \btxparameter\c!command
+ {\usebtxstyleandcolor\c!style\c!color
+ \btxparameter\c!pageleft
+ \clf_btxflushpages{\currentbtxdataset}{\currentbtxtag}%
+ \btxparameter\c!pageright}%
+ \endgroup}
+
+\unexpanded\def\btxpagesetup
+ {\btxsetuptype\plusfour
+ \fastbtxsetup\s!page\s!list
+ \btxpagereset}
+
+% end of page stuff
\unexpanded\def\btx_entry_inject
{\begingroup
\edef\currentbtxcategory{\btxfield{category}}%
\ignorespaces
- \directsetup{\s!btx:\currentbtxalternative:\currentbtxcategory}%
+ \ifconditional\c_btx_list_texts
+ \currentbtxbefore
+ \fi
+ \begingroup
+ \usebtxstyleandcolor\c!style\c!color
+ \ignorespaces
+ \btxsetuptype\plusthree
+ \fastbtxsetup\s!list\currentbtxcategory
\removeunwantedspaces
+ \endgroup
+ \ifconditional\c_btx_list_pages
+ \btx_entry_inject_pages
+ \fi
\ifx\currentbtxcombis\empty \else
\btxrenderingparameter\c!separator
\processcommacommand[\currentbtxcombis]\btx_entry_inject_combi
\fi
+ \ifconditional\c_btx_list_texts
+ \currentbtxafter
+ \fi
\endgroup}
+\unexpanded\def\btxshowentryinline
+ {\dodoubleempty\btx_entry_show_inline}
+
+\unexpanded\def\btx_entry_show_inline[#1][#2]%
+ {\ifsecondargument
+ \ctxcommand{showbtxentry("#1","#2")}
+ \else\iffirstargument
+ \ctxcommand{showbtxentry("\currentbtxdataset","#1")}
+ \else
+ \ctxcommand{showbtxentry("\currentbtxdataset","\currentbtxtag")}
+ \fi\fi}
+
\def\btx_entry_inject_combi#1%
{\begingroup
\def\currentbtxtag{#1}%
\ignorespaces
- \directsetup{\s!btx:\currentbtxalternative:\currentbtxcategory}%
+ \btxsetuptype\plusthree
+ \fastbtxsetup\s!list\currentbtxcategory
\removeunwantedspaces
\endgroup}
@@ -385,183 +651,329 @@
\let\completelistofpublications\completebtxrendering
\let\placelistofpublications \placebtxrendering
-\def\publ_place_list_check_criterium
- {\edef\currentbtxcriterium{\btxrenderingparameter\c!criterium}% \v!cite will become \s!cite
- \ifx\currentbtxcriterium\empty
- \let\currentbtxcriterium\v!previous
- \else\ifx\currentbtxcriterium\v!cite
- \let\currentbtxcriterium\v!here
- \fi\fi}
+\newtoks\everybtxlistrendering
-\def\publ_place_list_complete[#1][#2]% title might become obsolete, just headtext
- {\begingroup
- \edef\currentbtxrendering{#1}%
- \setupcurrentbtxrendering[#2]%
- \let\currentlist\s!btx
- \let\currentbtxlist\currentbtxrendering
- \publ_place_list_check_criterium
- \edef\currentbtxrenderingtitle{\btxrenderingparameter\c!title}%
- \ifx\currentbtxrenderingtitle\empty
- \normalexpanded{\startnamedsection[\v!chapter][\c!reference=\currentbtxrendering,\c!title={\headtext{\currentbtxrendering}}]}%
- \else
- \normalexpanded{\startnamedsection[\v!chapter][\c!reference=\currentbtxrendering,\c!title={\currentbtxrenderingtitle}]}%
- \fi
- \publ_place_list_indeed
- \stopnamedsection
- \endgroup}
+\appendtoks
+ \setbtxlist
+ %
+ \edef\currentbtxcriterium{\btxrenderingparameter\c!criterium}% \v!cite will become \s!cite
+ \ifx\currentbtxcriterium\empty
+ \let\currentbtxcriterium\v!previous
+ \else\ifx\currentbtxcriterium\v!cite
+ \let\currentbtxcriterium\v!here
+ \fi\fi
+ %
+ \iflocation
+ \letinteractionparameter\c!style\empty
+ \fi
+\to \everybtxlistrendering
-\def\publ_place_list_standard[#1][#2]%
- {\begingroup
- \edef\currentbtxrendering{#1}%
- \setupcurrentbtxrendering[#2]%
- \let\currentlist\s!btx
- \let\currentbtxlist\currentbtxrendering
- \publ_place_list_check_criterium
- \publ_place_list_indeed
- \endgroup}
+\def\nofbtxlistentries {0}
+\def\currentbtxlistentry{0}
+\def\currentbtxlistindex{0} % only for internal use (points back to big list)
-\newconditional\c_publ_place_all
-\newconditional\c_publ_place_register % to be interfaced
-\newconditional\c_publ_place_check % to be interfaced
+\newconditional\c_publ_prefixed
-\appendtoks
- \ifx\currentbtxcriterium\v!all % move this check to lua ... easier to test there anyway
- \settrue\c_publ_place_all
+\unexpanded\def\btxsetnoflistentries #1{\edef\nofbtxlistentries {#1}}
+\unexpanded\def\btxsetcurrentlistentry#1{\edef\currentbtxlistentry{#1}}
+\unexpanded\def\btxsetcurrentlistindex#1{\edef\currentbtxlistindex{#1}}
+
+\unexpanded\def\btxdoifelsesameaspreviouschecked#1#2% #1 == always | doublesided
+ {\clf_btxdoifelsesameasprevious
+ {\currentbtxdataset}%
+ \currentbtxlistentry%
+ {#2}%
+ \c_btx_list_reference
+ {#1}}
+
+\unexpanded\def\btxdoifelsesameasprevious
+ {\btxdoifelsesameaspreviouschecked\v!doublesided}
+
+\let\btxdoifsameaspreviouscheckedelse\btxdoifelsesameaspreviouschecked
+\let\btxdoifsameaspreviouselse \btxdoifelsesameasprevious
+
+\def\publ_place_list_indeed#1[#2][#3]%
+ {\begingroup
+ \ifsecondargument
+ % [rendering] [settings]
+ \edef\currentbtxrendering{#2}%
+ \setupcurrentbtxrendering[#3]%
+ \edef\p_specification{\btxrenderingparameter\c!specification}%
+ \ifx\p_specification\empty\else
+ \let\currentbtxspecification\p_specification
+ \fi
+ \else\iffirstargument
+ \doifelseassignment{#2}
+ {% [settings]
+ \let\currentbtxrendering\currentbtxspecification
+ \setupcurrentbtxrendering[#2]%
+ \edef\p_specification{\btxrenderingparameter\c!specification}%
+ \ifx\p_specification\empty\else
+ \let\currentbtxspecification\p_specification
+ \let\currentbtxrendering\currentbtxspecification % tricky
+ \fi}
+ {\edef\currentbtxrendering{#2}%
+ \edef\p_specification{\btxrenderingparameter\c!specification}%
+ \ifx\p_specification\empty\else
+ \let\currentbtxspecification\p_specification
+ \fi}%
\else
- \setfalse\c_publ_place_all
+ \let\currentbtxrendering\currentbtxspecification
+ \fi\fi
+ \setbtxparameterset\currentbtxspecification\s!list
+ \the\everybtxlistrendering
+ \ifconditional#1\relax
+ \edef\currentbtxrenderingtitle{\btxrenderingparameter\c!title}%
+ \ifx\currentbtxrenderingtitle\empty
+ \normalexpanded{\startnamedsection[\v!chapter][\c!reference=\currentbtxrendering,\c!title={\headtext{\currentbtxrendering}}]}%
+ \else
+ \normalexpanded{\startnamedsection[\v!chapter][\c!reference=\currentbtxrendering,\c!title={\currentbtxrenderingtitle}]}%
+ \fi
\fi
-\to \everysetupbtxlistplacement
-
-\def\publ_place_list_indeed
- {\startbtxrendering[\currentbtxrendering]%
- \directsetup{\btxrenderingparameter\c!setups}%
- % \determinelistcharacteristics[\currentbtxrendering]%
- \edef\currentbtxalternative{\btxrenderingparameter\c!alternative}%
- \edef\currentbtxdataset{\btxrenderingparameter\c!dataset}%
- \let\currentlist\s!btx
- \let\currentbtxlist\currentbtxrendering
- \the\everysetupbtxlistplacement
- \forgetall
- \ctxcommand{btxsetlistmethod("\currentbtxdataset","\btxrenderingparameter\c!method")}%
+ \ifx\currentbtxrendering\empty
+ \setbtxrendering % hm
+ \fi
+ \btxrenderingparameter\c!before
+ \edef\currentbtxdataset{\btxrenderingparameter\c!dataset}%
+ \uselanguageparameter\btxdatasetparameter % new
+ \setbtxlist
+ \the\everystructurelist
+ \the\everysetupbtxlistplacement
+ \forgetall
+ % why not pass this with collect .. todo
+ % here we just collect items
+ \clf_btxcollectlistentries
+ names {\s!btx}%
+ criterium {\currentbtxcriterium}%
+ reference {\btxrenderingparameter\c!reference}%
+ method {\btxrenderingparameter\c!method}%
+ dataset {\currentbtxdataset}%
+ keyword {\btxrenderingparameter\c!keyword}%
+ sorttype {\btxrenderingparameter\c!sorttype}%
+ repeated {\btxrenderingparameter\c!repeat}%
+ ignored {\btxrenderingparameter\c!ignore}%
+ group {\btxrenderingparameter\c!group}%
+ \relax
+ \ifnum\nofbtxlistentries>\zerocount
\startpacked[\v!blank]%
- % here we just collect items
- \ctxcommand{btxcollectlistentries {
- names = "btx",
- criterium = "\currentbtxcriterium",
- number = "\btxrenderingparameter\c!number",
- btxdataset = "\currentbtxdataset",
- keyword = "\btxrenderingparameter\c!keyword",
- }}%
- % next we analyze the width
- \ifx\btx_list_reference_inject_indeed\relax
- \else
- \edef\p_width{\btxrenderingparameter\c!width}%
- \ifx\p_width\v!auto
- \scratchcounter\btxlistcounter
- \setbox\scratchbox\vbox{\settrialtypesetting\ctxcommand{btxfetchlistentries("\currentbtxdataset")}}%
- \d_publ_number_width\wd\scratchbox
- \global\btxlistcounter\scratchcounter
- \letbtxlistparameter\c!width\d_publ_number_width
- \fi
+ % sorting and so
+ \clf_btxpreparelistentries{\currentbtxdataset}% could be put in collect
+ % next we analyze the width
+ \ifx\currentbtxnumbering\empty \else
+ \edef\p_width{\listparameter\c!width}%
+ \ifx\p_width\v!auto
+ \setbox\scratchbox\vbox \bgroup
+ \settrialtypesetting
+ \clf_btxfetchlistentries{\currentbtxdataset}%
+ \egroup
+ \d_publ_number_width\wd\scratchbox
+ \letlistparameter\c!width\d_publ_number_width
\fi
- % this actually typesets them
- \ctxcommand{btxflushlistentries("\currentbtxdataset","\btxrenderingparameter\c!sorttype")}%
+ \fi
+ \doifelse{\listparameter\c!prefix}\v!yes\settrue\setfalse\c_publ_prefixed
+ % this actually typesets them, we loop here as otherwise the whole
+ % bunch gets flushed at once
+ \dorecurse\nofbtxlistentries
+ {\let\currentbtxlistentry\recurselevel
+ \clf_btxflushlistentry{\currentbtxdataset}\currentbtxlistentry\relax}%
\stoppacked
- \stopbtxrendering
- \global\advance\btxblock\plusone}
+ \fi
+ \btxrenderingparameter\c!after
+ \global\advance\btxblock\plusone
+ \ifconditional#1\relax
+ \stopnamedsection
+ \fi
+ \endgroup}
-\def\currentbtxblock{\number\btxblock}
+\def\publ_place_list_complete{\publ_place_list_indeed\conditionaltrue}
+\def\publ_place_list_standard{\publ_place_list_indeed\conditionalfalse}
-\def\publ_place_list_entry_checked
- {\ctxcommand{btxdoifelselistentryplaced("\currentbtxdataset","\currentbtxtag")}\donothing\publ_place_list_entry}
+\def\currentbtxblock{\number\btxblock}
-\def\publ_place_list_entry_register
- {\ctxcommand{btxregisterlistentry("\currentbtxdataset","\currentbtxtag")}}
+% called at the lua end, for determining the width
-\unexpanded\def\btxhandlelistentry#1% called at the lua end
+\unexpanded\def\btxchecklistentry
{\begingroup
- \edef\currentbtxtag{#1}%
- \ifconditional\c_publ_place_all
- \publ_place_list_entry
- \else\ifconditional\c_publ_place_check
- \publ_place_list_entry_checked
- \else
- \publ_place_list_entry
- \fi\fi
+ % todo, switch to font
+ \hbox{\btx_reference_checked}%
+ \par
\endgroup}
-\unexpanded\def\publ_place_list_entry
- {\global\advance\btxlistcounter\plusone
- \ifconditional\c_publ_place_register
- \publ_place_list_entry_register
- \fi
- \let\currentlist\s!btx
- \startbtxlistentry\currentbtxrendering
- \btx_entry_inject
- \stopbtxlistentry}
+% called at the lua end, the real rendering
+
+% we could have a yes and no where o nils the btx_reference_indeed ... saves a check there
+
+\installstructurelistprocessor{\s!btx}
+ {\let\currentlistentrynumber \btx_reference_indeed
+ \let\currentlistentrytitle \btx_entry_indeed
+ \let\currentlistentrypagenumber\btx_page_indeed
+ \strc_lists_apply_renderingsetup}
+
+\def\btx_entry_indeed
+ {\btx_list_reference_inject
+ \btx_entry_inject}
-\unexpanded\def\btxchecklistentry#1% called at the lua end
+\def\btx_page_indeed
+ {}
+
+\unexpanded\def\btxhandlelistentry
+ {\strc_lists_entry_process}
+
+\unexpanded\def\btxstartlistentry % maybe pass i
{\begingroup
- \edef\currentbtxtag{#1}%
- \ifx\currentbtxcriterium\v!all % move this check to lua ... easier to test there anyway
- \publ_check_list_entry
- \else
- \ctxcommand{btxdoifelselistentryplaced("\currentbtxdataset","\currentbtxtag")}\donothing\publ_check_list_entry
+ \global\advance\c_btx_list_reference\plusone}
+
+\unexpanded\def\btxstoplistentry
+ {\iftrialtypesetting
+ \global\advance\c_btx_list_reference\minusone
\fi
\endgroup}
-\unexpanded\def\publ_check_list_entry
- {\global\advance\btxlistcounter\plusone
- % todo, switch to font
- \hbox{\btx_reference_checked}%
- \par}
+\newtoks\everybtxlistentry
-\unexpanded\def\btx_list_reference_inject % we can use a faster \reference
- {\dontleavehmode\begingroup % no box
- \iftrialtypesetting\else
- \ctxcommand{btxlistreference("\currentbtxdataset","\currentbtxblock","\currentbtxtag","\number\btxlistcounter")}%
- \fi
- \btx_list_reference_inject_indeed
+\unexpanded\def\btxlistsetup#1% used for the reference in the list
+ {\the\everybtxlistentry
+ \everybtxlistentry\emptytoks % so only once per entry to be sure
+ \btxsetuptype\plusthree
+ \fastbtxsetup\s!list{#1}}
+
+\appendtoks
+ \btx_check_language
+\to \everybtxlistentry
+
+\unexpanded\def\btx_reference_indeed
+ {\begingroup
+ %let\currentbtxlistvariant\currentbtxnumbering
+ \setbtxparameterset\c!list\currentbtxnumbering
+ \ifx\currentbtxnumbering\empty
+ % nothing
+ \else\ifx\currentbtxnumbering\v!no
+ % nothing
+ \else
+ \usebtxstyleandcolor\c!style\c!color % new, needed?
+ % \btxparameter\c!left
+ \ifconditional\c_publ_prefixed\btxlistprefixednumber\fi
+ \clf_btxlistvariant % some can go
+ {\currentbtxdataset}%
+ {\currentbtxblock}%
+ {\currentbtxtag}%
+ {\currentbtxnumbering}%
+ {\currentbtxnumber}%
+ \relax
+ % \btxparameter\c!right
+ \fi\fi
\endgroup}
+\unexpanded\def\btxlistprefixednumber % hack but alan needs it
+ {\clf_listprefixednumber
+ {\currentlist}%
+ \currentbtxlistindex
+ {%
+ prefix {\listparameter\c!prefix}%
+ separatorset {\listparameter\c!prefixseparatorset}%
+ conversionset {\listparameter\c!prefixconversionset}%
+ starter {\listparameter\c!prefixstarter}%
+ stopper {\listparameter\c!prefixstopper}%
+ set {\listparameter\c!prefixset}%
+ segments {\listparameter\c!prefixsegments}%
+ connector {\listparameter\c!prefixconnector}%
+ }%
+ \relax}
+
\unexpanded\def\btx_reference_checked
{\dontleavehmode\hbox\bgroup
- \btx_list_reference_inject_indeed
+ \btx_reference_indeed
\egroup}
-\unexpanded\def\btx_cite_reference_inject % todo: wrap whole content?
+\newcount\c_btx_list_reference
+
+\unexpanded\def\btx_list_reference_inject
{\dontleavehmode\begingroup % no box
\iftrialtypesetting\else
-% \ifx\currentbtxinternal\empty\else
- % \global\advance\btxcitecounter\plusone
- \ctxcommand{btxcitereference(\number\currentbtxinternal)}%
-% \fi
+ \btx_list_reference_inject_now
\fi
- % \btx_list_reference_inject_indeed
+ % \btx_reference_indeed % else double entry in list
\endgroup}
+\def\btx_list_reference_inject_now
+ {\btx_trace_list_cross\empty\currentbtxbacktrace
+ \strc_references_direct_full_user
+ {\ifx\currentbtxdataset\v!default\else\s!btxset=\currentbtxdataset,\fi%
+ \s!btxref=\currentbtxtag,%
+ \s!btxspc=\currentbtxspecification,%
+ \s!btxlst=\number\c_btx_list_reference,% check if needed
+ \ifx\currentbtxbefore\empty\else\s!btxbtx={\currentbtxbefore},\fi%
+ \ifx\currentbtxafter \empty\else\s!btxatx={\currentbtxafter },\fi%
+ \ifx\currentbtxbacklink\currentbtxbacktrace\s!btxint=\currentbtxbacklink\else\s!btxbck=\currentbtxbacktrace\fi}%
+ {\s!btx::\v!list::\number\c_btx_list_reference}%
+ {\currentbtxnumber}}
+
+\newconditional\c_btx_cite_reference_injected
+
+\unexpanded\def\btx_cite_reference_inject
+ {\ifconditional\c_btx_cite_reference_injected
+ \else
+ \dontleavehmode
+ \iftrialtypesetting \else
+ \ifx\currentbtxbacklink\empty
+ % can be made empty when combining author / year
+ \else
+ \btx_cite_reference_inject_indeed
+ \settrue\c_btx_cite_reference_injected
+ \fi
+ \fi
+ \fi}
+
+\newtoks\t_btx_reference_inject
+
+% \def\btx_cite_reference_inject_indeed
+% {\btx_trace_list_cross\currentbtxbacklink\empty
+% \the\t_btx_reference_inject
+% \normalexpanded{\writedatatolist % can be done faster .. just merge code here (not much) / also type btx
+% [\s!btx]%
+% [\ifx\currentbtxdataset\v!default\else\s!btxset=\currentbtxdataset,\fi%
+% \s!btxref=\currentbtxtag,%
+% \ifx\currentbtxbefore\empty\else\s!btxbtx=\!!bs\currentbtxbefore\!!es,\fi%
+% \ifx\currentbtxafter \empty\else\s!btxatx=\!!bs\currentbtxafter \!!es,\fi%
+% \s!btxint=\number\currentbtxbacklink
+% \ifx\currentbtxciteuservariables\empty\else,\currentbtxciteuservariables\fi]}}
+
+\def\btx_cite_reference_inject_indeed
+ {\btx_trace_list_cross\currentbtxbacklink\empty
+ \the\t_btx_reference_inject
+ \strc_lists_inject_direct % todo: make like \btx_list_reference_inject_now with { }
+ [\s!btx]%
+ [\c!type=\s!btx]% \c!location=\v!none
+ [\ifx\currentbtxdataset\v!default\else\s!btxset=\currentbtxdataset,\fi%
+ \s!btxref=\currentbtxtag,%
+ \ifx\currentbtxbefore\empty\else\s!btxbtx=\!!bs\currentbtxbefore\!!es,\fi%
+ \ifx\currentbtxafter \empty\else\s!btxatx=\!!bs\currentbtxafter \!!es,\fi%
+ \s!btxint=\number\currentbtxbacklink
+ \ifx\currentbtxciteuservariables\empty\else,\currentbtxciteuservariables\fi]}
+
+\def\currentbtxuservariable #1{\clf_btxuservariable {\currentbtxdataset}{#1}}
+\def\btxdoifelseuservariable#1{\clf_btxdoifelseuservariable{\currentbtxdataset}{#1}}
+
+\let\btxdoifuservariableelse\btxdoifelseuservariable
+
\let\btxcitereference\btx_cite_reference_inject
-\setuvalue{\??btxnumbering\v!short }{\btxlistvariant{short}} % these will be setups
-\setuvalue{\??btxnumbering\v!bib }{\btxlistvariant{num}} % these will be setups
-\setuvalue{\??btxnumbering\s!unknown}{\btxlistvariant{num}} % these will be setups
-\setuvalue{\??btxnumbering\v!yes }{\btxlistvariant{num}} % these will be setups
+\let\currentbtxnumbering\empty
\appendtoks
- \edef\p_btx_numbering{\btxrenderingparameter\c!numbering}%
- \letlistparameter\c!numbercommand\firstofoneargument % for the moment, no doubling needed
- \ifx\p_btx_numbering\v!no
- \letlistparameter\c!textcommand\outdented % needed? we can use titlealign
- \letlistparameter\c!symbol \v!none
- \letlistparameter\c!aligntitle \v!yes
- \let\btx_list_reference_inject_indeed\relax
- \else
- \ifcsname\??btxnumbering\p_btx_numbering\endcsname \else
- \let\p_btx_numbering\s!unknown
- \fi
- \letlistparameter\c!headnumber\v!always
- \expandafter\let\expandafter\btx_list_reference_inject_indeed\csname\??btxnumbering\p_btx_numbering\endcsname
- \fi
+ \edef\currentbtxnumbering{\btxrenderingparameter\c!numbering}%
+ \edef\p_numbering{\btxrenderingparameter\c!numbering}% link to headnumber
+ \ifx\p_numbering\v!no
+ \letlistparameter\c!headnumber\v!no
+ \let\currentbtxnumbering\empty
+ % \letlistparameter\c!textcommand\outdented % needed? we can use titlealign
+ \letlistparameter\c!symbol \v!none
+ \letlistparameter\c!aligntitle \v!yes
+ \letlistparameter\c!numbercommand\firstofoneargument % for the moment, no doubling needed
+ \else
+ \letlistparameter\c!headnumber\v!always
+ \fi
+ \let\currentlistmethod\s!btx
\to \everysetupbtxlistplacement
% \appendtoks
@@ -569,135 +981,139 @@
% \to \everysetupbtxlistplacement
\unexpanded\def\btxflushauthor
- {\doifnextoptionalcselse\btx_flush_author_yes\btx_flush_author_nop}
+ {\doifelsenextoptionalcs\btx_flush_author_yes\btx_flush_author_nop}
\def\btx_flush_author_yes[#1]{\btx_flush_author{#1}}
-\def\btx_flush_author_nop {\btx_flush_author{\btxlistvariantparameter\c!author}}
+\def\btx_flush_author_nop {\btx_flush_author{\btxparameter\c!authorconversion}}
\unexpanded\def\btx_flush_author#1#2%
- {\edef\currentbtxfield{#2}%
- \let\currentbtxlistvariant\currentbtxfield
- \ctxcommand{btxauthor("\currentbtxdataset","\currentbtxtag","\currentbtxfield",{
- combiner = "#1",
- etallimit = \number\btxlistvariantparameter\c!etallimit,
- etaldisplay = \number\btxlistvariantparameter\c!etaldisplay,
- })}}
+ {\begingroup
+ \edef\currentbtxfield{#2}%
+ \setbtxparameterset\s!list\currentbtxfield
+ %let\currentbtxlistvariant\currentbtxfield
+ \clf_btxauthor
+ {\currentbtxdataset}%
+ {\currentbtxtag}%
+ {\currentbtxfield}%
+ {%
+ combiner {#1}%
+ kind {list}%
+ etallimit {\btxparameter\c!etallimit}%
+ etaldisplay {\btxparameter\c!etaldisplay}%
+ symbol {\btxparameter{\c!stopper:initials}}%
+ }%
+ \relax
+ \endgroup}
+
+% yes or no: maybe just \flushauthor{...}{...}
+\unexpanded\def\btxflushauthorname {\btx_flush_author{name}} % #1
\unexpanded\def\btxflushauthornormal {\btx_flush_author{normal}} % #1
\unexpanded\def\btxflushauthornormalshort {\btx_flush_author{normalshort}} % #1
\unexpanded\def\btxflushauthorinverted {\btx_flush_author{inverted}} % #1
\unexpanded\def\btxflushauthorinvertedshort{\btx_flush_author{invertedshort}} % #1
\unexpanded\def\currentbtxciteauthor % always author
- {\ctxcommand{btxauthor("\currentbtxdataset","\currentbtxtag","author",{
- combiner = "\btxcitevariantparameter\c!author",
- etallimit = \number\btxcitevariantparameter\c!etallimit,
- etaldisplay = \number\btxcitevariantparameter\c!etaldisplay,
- })}}
+ {\begingroup
+ \setbtxparameterset\s!cite\s!author
+ \clf_btxauthor
+ {\currentbtxdataset}%
+ {\currentbtxtag}%
+ {\s!author}%
+ {%
+ combiner {\btxparameter\c!authorconversion}%
+ kind {cite}%
+ etallimit {\btxparameter\c!etallimit}%
+ etaldisplay {\btxparameter\c!etaldisplay}%
+ symbol {\btxparameter{\c!stopper:initials}}%
+ }%
+ \relax
+ \endgroup}
+
+\unexpanded\def\btxstartauthor#1#2#3% a state > 0 signals that some authors can clash
+ {\begingroup
+ \currentbtxauthorindex#1\relax
+ \currentbtxauthorcount#2\relax
+ \currentbtxauthorstate#3\relax}
+
+\unexpanded\def\btxstopauthor
+ {\endgroup}
+
+\unexpanded\def\btxciteauthorsetup#1{\fastsetup{\s!btx:\s!cite:\s!author:#1}}
+\unexpanded\def\btxlistauthorsetup#1{\fastsetup{\s!btx:\s!list:\s!author:#1}}
% \btxflushauthor{author}
-% \btxflushauthor{artauthor}
% \btxflushauthor{editor}
%
+% \btxflushauthor[name]{author}
% \btxflushauthor[normal]{author}
% \btxflushauthor[normalshort]{author}
% \btxflushauthor[inverted]{author}
% \btxflushauthor[invertedshort]{author}
-% Interaction: only list
+% \btxflushauthor{author}
+% \btxflushauthor{editor}
+%
+% \btxflushauthor[name]{author}
+% \btxflushauthor[normal]{author}
+% \btxflushauthor[normalshort]{author}
+% \btxflushauthor[inverted]{author}
+% \btxflushauthor[invertedshort]{author}
+
+% Interaction
\newconditional\btxinteractive
+\newconditional\btx_interactive
-\unexpanded\def\btxdoifelseinteraction{\secondoftwoarguments}
+% of maybe modes?
\appendtoks
\iflocation
- \edef\p_interaction{\btxlistvariantparameter\c!interaction}%
+ \edef\p_interaction{\btxparameter\c!interaction}%
\ifx\p_interaction\v!stop
- \let\btxdoifelseinteraction\secondoftwoarguments
\setfalse\btxinteractive
\else
- \let\btxdoifelseinteraction\firstoftwoarguments
\settrue\btxinteractive
+ \ifx\p_interaction\v!all
+ \settrue\btx_interactive
+ \else
+ \setfalse\btx_interactive
+ \fi
\fi
\else
- \let\btxdoifelseinteraction\secondoftwoarguments
\setfalse\btxinteractive
+ \setfalse\btx_interactive
\fi
\to \everysetupbtxlistplacement
\appendtoks
\iflocation
- \edef\p_interaction{\btxcitevariantparameter\c!interaction}%
+ \edef\p_interaction{\btxparameter\c!interaction}%
\ifx\p_interaction\v!stop
- \let\btxdoifelseinteraction\secondoftwoarguments
\setfalse\btxinteractive
\else
- \let\btxdoifelseinteraction\firstoftwoarguments
\settrue\btxinteractive
\fi
\else
- \let\btxdoifelseinteraction\secondoftwoarguments
\setfalse\btxinteractive
\fi
\to \everysetupbtxciteplacement
-% bib -> btx
+% till here
-\unexpanded\def\btxgotolink#1[#2]{\doifreferencefoundelse{\bibrefprefix#2}{\goto{#1}[\bibrefprefix#2]}{#1}}
-\unexpanded\def\btxatlink [#1]{\doifreferencefoundelse{\bibrefprefix#1}{\at [\bibrefprefix#1]}{#1}}
-\unexpanded\def\btxinlink [#1]{\doifreferencefoundelse{\bibrefprefix#1}{\expanded{\goto{\currentreferencetext}}[\bibrefprefix#1]}{#1}}
-
-\unexpanded\def\btxdirectlink#1#2{\goto{#2 {\tttf[#1]}}[#1]}
-\unexpanded\def\btxdirectlink#1#2{\goto{#2}[#1]}
-
-\let\gotobiblink\btxgotolink
-\let\atbiblink \btxatlink
-\let\inbiblink \btxinlink
-
-\unexpanded\def\btxnumberedreference[#1]% \bibtexnumref (replaced by \cite[num])
- {\dontleavehmode
- \begingroup
- \btxcitevariantparameter\v!left
- \penalty\plustenthousand % todo
- \ctxcommand{btxresolvelistreference("\currentbtxdataset","#1")}% todo: split dataset from #1, so another call
- \btxcitevariantparameter\v!right
- \endgroup}
-
-\appendtoks
- % for old times sake, for a while at least
- \let\maybeyear\gobbleoneargument
- \let\noopsort \gobbleoneargument
-\to \everysetupbtxlistplacement
-
-\appendtoks
- % for old times sake, for a while at least
- \let\maybeyear\gobbleoneargument
- \let\noopsort \gobbleoneargument
-\to \everysetupbtxciteplacement
-
-\appendtoks
- \doifnot{\btxrenderingparameter\c!continue}\v!yes
- {\global\btxlistcounter\zerocount}%
-\to \everysetupbtxlistplacement
+% \unexpanded\def\btxnumberedreference[#1]% \bibtexnumref (replaced by \cite[num])
+% {\dontleavehmode
+% \begingroup
+% \btxparameter\v!left
+% \penalty\plustenthousand % todo
+% \clf_btxresolvelistreference{\currentbtxdataset}{#1}% todo: split dataset from #1, so another call
+% \btxparameter\v!right
+% \endgroup}
%D When a publication is cited, we need to signal that somehow. This is done with the
%D following (not user) command. We could tag without injecting a node but this way
%D we also store the location, which makes it possible to ask local lists.
-\newconditional\c_publ_cite_write
-
-\unexpanded\def\btxdomarkcitation % called from lua end
- {\iftrialtypesetting
- \expandafter\gobbletwoarguments
- \else
- \expandafter\publ_cite_mark_citation
- \fi}
-
-\def\publ_cite_mark_citation#1#2% called from lua end
- {\dontleavehmode
- \writedatatolist[btx][btxset=#1,btxref=#2]} % \c!location=\v!here
-
%D \macros{cite,nocite,citation,nocitation,usecitation}
%D
%D The inline \type {\cite} command creates a (often) short reference to a publication
@@ -716,98 +1132,120 @@
% [base::tags]
% [settings|variant][base::tags]
-\unexpanded\def\btxcite
+% these need to be sort of protected:
+
+\let\p_publ_cite_before \empty
+\let\p_publ_cite_after \empty
+\let\p_publ_cite_lefttext \empty
+\let\p_publ_cite_righttext\empty
+
+\let\currentbtxciteuservariables\empty
+
+\unexpanded\def\btxhybridcite % so one can alias the old
{\dontleavehmode
\begingroup
- \strictdoifnextoptionalelse\publ_cite_tags_options\publ_cite_tags_indeed}
+ \strictdoifelsenextoptional\publ_cite_tags_options\publ_cite_tags_indeed}
+
+\unexpanded\def\publ_cite_tags_options[#1]%
+ {\strictdoifelsenextoptional{\publ_cite_tags_options_indeed{#1}}{\publ_cite_tags_indeed{#1}}}
\unexpanded\def\publ_cite_tags_indeed#1%
{\letinteractionparameter\c!style\empty
- \edef\currentbtxcitevariant{\btxcitevariantparameter\c!alternative}%
+ \setbtxparametersetroot\s!cite % we need to get the default
+ \edef\currentbtxcitealternative{\btxparameter\c!alternative}%
+ \setbtxparameterset\s!cite\currentbtxcitealternative
\edef\currentbtxcitetag{#1}%
\the\everysetupbtxciteplacement
\publ_cite_variant
\endgroup}
-\let\publ_citation_tags_indeed\publ_cite_tags_indeed
+\unexpanded\def\publ_cite_tags_options_indeed#1%
+ {\doifelseassignment{#1}\publ_cite_tags_settings_indeed\publ_cite_tags_variants_indeed{#1}}
-\unexpanded\def\publ_cite_tags_options[#1]%
- {\strictdoifnextoptionalelse{\publ_cite_tags_options_indeed{#1}}{\publ_cite_tags_indeed{#1}}}
-
-\unexpanded\def\publ_cite_tags_options_indeed#1[#2]%
- {\edef\currentbtxcitetag{#2}%
- \doifassignmentelse{#1}\publ_cite_tags_settings_indeed\publ_cite_tags_variants_indeed{#1}}
-
-\def\publ_cite_tags_settings_indeed#1%
+\def\publ_cite_tags_settings_indeed#1[#2]%
{\letinteractionparameter\c!style\empty
%\letinteractionparameter\c!color\empty
+ \letdummyparameter\c!reference \empty
+ \letdummyparameter\c!alternative\empty
\letdummyparameter\c!before \empty
\letdummyparameter\c!after \empty
- \letdummyparameter\c!extras \empty
- \letdummyparameter\c!alternative\empty
+ \letdummyparameter\c!lefttext \empty
+ \letdummyparameter\c!righttext \empty
\getdummyparameters[#1]%
+ \edef\p_reference{\dummyparameter\c!reference}%
+ \ifx\p_reference\empty
+ \edef\currentbtxcitetag{#2}%
+ \else
+ \let\currentbtxcitetag\p_reference
+ \edef\currentbtxciteuservariables{#2}%
+ \fi
\edef\p_alternative{\dummyparameter\c!alternative}%
\ifx\p_alternative\empty
- \edef\currentbtxcitevariant{\btxcitevariantparameter\c!alternative}%
+ \setbtxparametersetroot\s!cite
+ \edef\currentbtxcitealternative{\btxparameter\c!alternative}%
\else
- \let\currentbtxcitevariant\p_alternative
+ \let\currentbtxcitealternative\p_alternative
\fi
- \setupcurrentbtxcitevariant[#1]%
- \edef\p_extras{\dummyparameter\c!extras}%
- \ifx\p_extras\empty \else
- \edef\p_right{\btxcitevariantparameter\c!right}%
- \ifx\p_right\empty \else
- \setexpandedbtxcitevariantparameter\p_right{\p_extras\p_right}%
- \fi
- \fi
- \edef\p_before{\dummyparameter\c!before}%
- \edef\p_after {\dummyparameter\c!after}%
+ \setbtxparameterset\s!cite\currentbtxcitealternative
+ \setupcurrentbtx[#1]%
+ %
+ \edef\p_publ_cite_before {\dummyparameter\c!before}%
+ \edef\p_publ_cite_after {\dummyparameter\c!after}%
+ \edef\p_publ_cite_lefttext {\dummyparameter\c!lefttext}%
+ \edef\p_publ_cite_righttext{\dummyparameter\c!righttext}%
+ %
\the\everysetupbtxciteplacement
- \ifx\p_before\empty \else
- \p_before
- \space
- \fi
\publ_cite_variant
- \ifx\p_after\empty \else
- \optionalspace
- \p_after
- \fi
\endgroup}
-\def\publ_cite_tags_variants_indeed#1%
+\def\publ_cite_tags_variants_indeed#1[#2]%
{\letinteractionparameter\c!style\empty
- \edef\currentbtxcitevariant{#1}%
+ \edef\currentbtxcitealternative{#1}%
+ \edef\currentbtxcitetag{#2}%
+ \setbtxparameterset\s!cite\currentbtxcitealternative
\the\everysetupbtxciteplacement
\publ_cite_variant
\endgroup}
\newconditional\btxcitecompress
+\let\currentbtxreference\empty
+
\def\publ_cite_variant
{\begingroup
- \settrue\c_publ_cite_write
\publ_cite_handle_variant_indeed[\currentbtxcitetag]}
\unexpanded\def\publ_cite_handle_variant#1%
{\begingroup
- \edef\currentbtxcitevariant{#1}%
+ \edef\currentbtxcitealternative{#1}%
+ \setbtxparameterset\s!cite\currentbtxcitealternative
\the\everysetupbtxciteplacement
\dosingleargument\publ_cite_handle_variant_indeed}
+\unexpanded\def\publ_cite_handle_variant_blob
+ {%\btxparameter\v!left\relax
+ \clf_btxhandlecite
+ dataset {\currentbtxdataset}%
+ reference {\currentbtxreference}%
+ markentry \iftrialtypesetting\s!false\else\s!true\fi\space
+ variant {\currentbtxcitealternative}%
+ sorttype {\btxparameter\c!sorttype}%
+ compress {\btxparameter\c!compress}%
+ author {\btxparameter\c!author}%
+ lefttext {\p_publ_cite_lefttext}%
+ righttext {\p_publ_cite_righttext}%
+ before {\p_publ_cite_before}%
+ after {\p_publ_cite_after}%
+ \relax
+ \clf_btxflushmarked % maybe: \iftrialtypesetting\else ... \fi
+ }%\btxparameter\v!right\relax}
+
\def\publ_cite_handle_variant_indeed[#1]%
- {\usebtxcitevariantstyleandcolor\c!style\c!color
- \letbtxcitevariantparameter\c!alternative\currentbtxcitevariant
- \btxcitevariantparameter\v!left
- \ctxcommand{btxhandlecite{%
- dataset = "\currentbtxdataset",%
- reference = "#1",%
- markentry = \iftrialtypesetting false\else true\fi,%
- variant = "\currentbtxcitevariant",%
- sorttype = "\btxcitevariantparameter\c!sorttype",%
- compress = "\btxcitevariantparameter\c!compress",%
- author = "\btxcitevariantparameter\c!author",%
- }}%
- \btxcitevariantparameter\v!right
+ {\letbtxparameter\c!alternative\currentbtxcitealternative
+ \edef\currentbtxreference{#1}%
+ \usebtxstyleandcolor\c!style\c!color
+ \uselanguageparameter\btxdatasetparameter % new
+ \btxparameter\c!command{\publ_cite_handle_variant_blob}%
\endgroup}
\unexpanded\def\btxcitation
@@ -822,281 +1260,460 @@
\publ_cite_tags_indeed{#1}%
\fi}
-\unexpanded\def\btxnocite
+\unexpanded\def\btxnocitation
{\dosingleempty\publ_cite_no}
\unexpanded\def\publ_cite_no[#1]%
{\iftrialtypesetting \else
- \ctxcommand{btxhandlecite{%
- dataset = "\currentbtxdataset",%
- reference = "#1",%
- markentry = \iftrialtypesetting false\else true\fi,%
- }}%
+ \begingroup
+ \edef\currentbtxreference{#1}%
+ \clf_btxhandlenocite
+ dataset {\currentbtxdataset}%
+ reference {\currentbtxreference}%
+ markentry true%
+ \relax
+ % \clf_btxflushmarked
+ \endgroup
\fi}
\unexpanded\def\btxmissing#1%
- {{\tttf<#1>}}
+ {\dontleavehmode{\tttf<#1>}}
%D Compatibility:
-\let\cite \btxcite
+\let\cite \btxcitation
\let\citation \btxcitation
-\let\nocite \btxnocite
-\let\nocitation \btxnocite
-\let\usepublication\btxnocite
+\let\nocite \btxnocitation
+\let\nocitation \btxnocitation
+%let\usepublication\btxnocitation
+
+%D Setup helpers, beware, we need to wrap this .. now we need to know
+%D how setups are implemented.
+
+\setvalue{\??setup:\s!btx:\s!unknown}#1{\inframed{\tttf#1}}
+
+\def\fastbtxsetup_yes#1#2%
+ {\csname\??setup:\s!btx:%
+ \ifcsname\??setup:\s!btx:\currentbtxspecification:#1:#2\endcsname
+ \currentbtxspecification:#1:#2%
+ \else\ifcsname\??setup:\s!btx:\currentbtxspecificationfallback:#1:#2\endcsname
+ \currentbtxspecificationfallback:#1:#2%
+ \else\ifcsname\??setup:\s!btx:#1:#2\endcsname
+ #1:#2%
+ \else\ifcsname\??setup:\s!btx:\currentbtxspecification:#1:\s!unknown\endcsname
+ \currentbtxspecification:#1:\s!unknown
+ \else\ifcsname\??setup:\s!btx:\currentbtxspecificationfallback:#1:\s!unknown\endcsname
+ \currentbtxspecificationfallback:#1:\s!unknown
+ \else
+ #1:\s!unknown
+ \fi\fi\fi\fi\fi
+ \endcsname{#2}}
+
+\def\fastbtxsetup_nop#1#2%
+ {\csname\??setup:\s!btx:%
+ \ifcsname\??setup:\s!btx:\currentbtxspecification:#1:#2\endcsname
+ \currentbtxspecification:#1:#2%
+ \else\ifcsname\??setup:\s!btx:#1:#2\endcsname
+ #1:#2%
+ \else\ifcsname\??setup:\s!btx:\currentbtxspecification:#1:\s!unknown\endcsname
+ \currentbtxspecification:#1:\s!unknown
+ \else
+ #1:\s!unknown
+ \fi\fi\fi
+ \endcsname{#2}}
+
+\def\fastbtxsetup
+ {\ifx\currentbtxspecificationfallback\empty
+ \expandafter\fastbtxsetup_nop
+ \else
+ \expandafter\fastbtxsetup_yes
+ \fi}
-%D Cite helpers:
+\let\publ_fastbtxsetup_normal\fastbtxsetup
+
+\newconstant\btxsetuptype
+
+% 0 = unknown darkred
+% 1 = cite darkblue
+% 2 = subcite darkgreen
+% 3 = list darkcyan
+% 4 = page darkmagenta
+% 5 = unknown darkred
+
+\unexpanded\def\publ_fastbtxsetup_chain_inbetween
+ {\allowbreak->\allowbreak}
+
+\unexpanded\def\publ_fastbtxsetup_chain_yes#1#2%
+ {\dontleavehmode\begingroup
+ \infofont
+ \ifcase\btxsetuptype\darkred\or\darkblue\or\darkgreen\or\darkcyan\or\darkmagenta\else\darkred\fi
+ [%
+ \currentbtxspecification :#1:#2\ifcsname\??setup:\s!btx:\currentbtxspecification :#1:#2\endcsname\else
+ \publ_fastbtxsetup_chain_inbetween
+ \currentbtxspecificationfallback:#1:#2\ifcsname\??setup:\s!btx:\currentbtxspecificationfallback :#1:#2\endcsname\else
+ \publ_fastbtxsetup_chain_inbetween
+ #1:#2\ifcsname\??setup:\s!btx :#1:#2\endcsname\else
+ \publ_fastbtxsetup_chain_inbetween
+ \currentbtxspecification :#1:\s!unknown\ifcsname\??setup:\s!btx:\currentbtxspecification :#1:\s!unknown\endcsname\else
+ \publ_fastbtxsetup_chain_inbetween
+ \currentbtxspecificationfallback:#1:\s!unknown\ifcsname\??setup:\s!btx:\currentbtxspecificationfallback:#1:\s!unknown\endcsname\else
+ \publ_fastbtxsetup_chain_inbetween
+ unset\fi\fi\fi\fi\fi
+ ]%
+ \endgroup}
-\newconstant\currentbtxconcat
+\unexpanded\def\publ_fastbtxsetup_chain_nop#1#2%
+ {\dontleavehmode\begingroup
+ \infofont
+ \darkred
+ [%
+ \currentbtxspecification :#1:#2\ifcsname\??setup:\s!btx:\currentbtxspecification :#1:#2\endcsname\else
+ \publ_fastbtxsetup_chain_inbetween
+ #1:#2\ifcsname\??setup:\s!btx :#1:#2\endcsname\else
+ \publ_fastbtxsetup_chain_inbetween
+ \currentbtxspecification :#1:\s!unknown\ifcsname\??setup:\s!btx:\currentbtxspecification :#1:\s!unknown\endcsname\else
+ \publ_fastbtxsetup_chain_inbetween
+ unset\fi\fi\fi
+ ]%
+ \endgroup}
-\unexpanded\def\btxcitereset
- {\let\currentbtxfirst \empty
- \let\currentbtxsecond \empty
- \let\currentbtxinternal\empty
- \let\currentbtxtag \empty
- \setconstant\currentbtxconcat\zerocount}
+\unexpanded\def\publ_fastbtxsetup_chain
+ {\ifx\currentbtxspecificationfallback\empty
+ \expandafter\publ_fastbtxsetup_chain_nop
+ \else
+ \expandafter\publ_fastbtxsetup_chain_yes
+ \fi}
-\btxcitereset
+\unexpanded\def\publ_fastbtxsetup_visual#1#2%
+ {\publ_fastbtxsetup_chain{#1}{#2}%
+ \publ_fastbtxsetup_normal{#1}{#2}}
-\unexpanded\def\btxcitesetup#1%
- {\directsetup{btx:cite:#1}%
- \btxcitereset}
+\installtextracker
+ {publications.setups}
+ {\let\fastbtxsetup\publ_fastbtxsetup_visual}
+ {\let\fastbtxsetup\publ_fastbtxsetup_normal}
-\unexpanded\def\btxsetfirst {\def\currentbtxfirst}
-\unexpanded\def\btxsetsecond {\def\currentbtxsecond}
-\unexpanded\def\btxsettag {\def\currentbtxtag}
-\unexpanded\def\btxsetinternal{\def\currentbtxinternal}
-\unexpanded\def\btxsetconcat#1{\setconstant\currentbtxconcat#1\relax}
+%D Cite helpers:
-\unexpanded\def\btxsetlistreference#1#2% #3#4%
- {\strc_references_direct_full_user{btxset="#1",btxref="#2"}}
+\newtoks\everybtxciteentry
-\unexpanded\def\btxsetcitereference#1#2%
- {\ifx\currentbtxinternal\empty \else
- \strc_references_direct_full_user{btxint=#2}{#1}\empty
- \fi}
+\prependtoks
+ \setfalse\c_btx_cite_reference_injected
+\to \everybtxciteentry
-\unexpanded\def\btxstartsubcite#1%
- {\bgroup
- \btxcitereset
- \def\currentbtxcitevariant{#1}%
- \btxcitevariantparameter\c!left}
+\unexpanded\def\btxcitesetup#1%
+ {\the\everybtxciteentry
+ \btxsetuptype\plusone
+ \everybtxciteentry\emptytoks % tricky maybe not when subcites
+ \fastbtxsetup\s!cite{#1}} % no \btxcitereset as we loose dataset and such
-\unexpanded\def\btxstopsubcite
- {\btxcitevariantparameter\c!right
- \egroup}
+\unexpanded\def\btxsubcitesetup#1%
+ {\the\everybtxciteentry
+ \btxsetuptype\plustwo
+ \everybtxciteentry\emptytoks % tricky maybe not when subcites
+ \fastbtxsetup\s!cite{#1}} % no \btxcitereset as we loose dataset and such
-%D List helpers:
+\appendtoks
+ \btx_check_language
+\to \everybtxciteentry
-\def\currentbtxindex{0}
+\unexpanded\def\btxstartsubcite#1%
+ {\begingroup
+ \btxcitereset % todo: limited set
+ \def\currentbtxcitealternative{#1}%
+ \setbtxparameterset\s!cite\currentbtxcitealternative
+ \usebtxstyleandcolor\c!style\c!color
+ % \btxparameter\c!left
+ \relax}
+
+\unexpanded\def\btxstopsubcite
+ {%\relax
+ % \btxparameter\c!right
+ \endgroup}
-\unexpanded\def\btxlistvariant#1% was \currentbtxindex
+\unexpanded\def\btxstartciterendering[#1]%
{\begingroup
- \edef\currentbtxlistvariant{#1}%
- \btxlistvariantparameter\c!left
- \ctxcommand{btxlistvariant("\currentbtxdataset","\currentbtxblock","\currentbtxtag","#1","\number\btxlistcounter")}% some can go
- \btxlistvariantparameter\c!right
+ \edef\currentbtxcitealternative{#1}%
+ \setbtxparameterset\s!cite\currentbtxcitealternative
+ \usebtxstyleandcolor\c!style\c!color
+ % \btxparameter\c!left
+ }%\relax}
+
+\unexpanded\def\btxstopciterendering
+ {\relax
+ % \btxparameter\c!right
\endgroup}
+\let\btxstartcite \begingroup
+\let\btxstopcite \endgroup
+\let\btxstartciteauthor\begingroup
+\let\btxstopciteauthor \endgroup
+
%D Whatever helpers:
-\unexpanded\def\btxsingularplural#1%
- {\ctxcommand{btxsingularorplural("\currentbtxdataset","\currentbtxtag","#1")}}
+\unexpanded\def\btxsingularplural#1{\clf_btxsingularorplural{\currentbtxdataset}{\currentbtxtag}{#1}}
+\unexpanded\def\btxoneorrange #1{\clf_btxoneorrange {\currentbtxdataset}{\currentbtxtag}{#1}}
+\unexpanded\def\btxfirstofrange #1{\clf_btxfirstofrange {\currentbtxdataset}{\currentbtxtag}{#1}}
\let\btxsingularorplural\btxsingularplural
-%D Loading variants:
+\stopcontextdefinitioncode
+
+%D Journals
+
+\unexpanded\def\btxloadjournallist [#1]{\clf_btxloadjournallist{#1}}
+\unexpanded\def\btxsavejournallist [#1]{\clf_btxsavejournallist{#1}}
+\unexpanded\def\btxaddjournal [#1][#2]{\clf_btxaddjournal{#1}{#2}}
+ \def\btxexpandedjournal #1{\clf_btxexpandedjournal{#1}} % \unexpanded ?
+ \def\btxabbreviatedjournal#1{\clf_btxabbreviatedjournal{#1}} % \unexpanded ?
+
+% \installcorenamespace{btxjournal}
+%
+% \letvalue{\s!btxjournal\v!long }\btxexpandedjournal
+% \letvalue{\s!btxjournal\v!short }\btxabbreviatedjournal
+% \letvalue{\s!btxjournal\v!normal}\firstofoneargument
+%
+% \unexpanded\def\btxcheckedjournal
+% {\expandnamespaceparameter\s!btxjournal\btxrenderingparameter\c!journalconversion}
+
+% \btxloadjournallist[list.txt] % Foo Journal of Bars = FBJ \n ....
+%
+% \btxexpandedjournal[fbj]
+% \btxabbreviatedjournal[foo journal of bars]
+
+%D Saving data:
+
+\unexpanded\def\savebtxdataset
+ {\dotripleargument\publ_save_dataset}
+
+\unexpanded\def\publ_save_dataset[#1][#2][#3]%
+ {\ifthirdargument
+ \publ_save_dataset_indeed[#1][#2][#3]%
+ \else\ifsecondargument
+ \doifelseassignment{#2}%
+ {\publ_save_dataset_indeed[\s!default][#1][#2]}%
+ {\publ_save_dataset_indeed[#1][#2][]}%
+ \else\iffirstargument
+ \doifelseassignment{#1}%
+ {\publ_save_dataset_indeed[\s!default][\jobname-saved.bib][#1]}%
+ {\publ_save_dataset_indeed[\s!default][#1][]}%
+ % \else
+ % % bad news
+ \fi\fi\fi}
+
+\unexpanded\def\publ_save_dataset_indeed[#1][#2][#3]%
+ {\begingroup
+ \getdummyparameters
+ [\c!criterium=\v!all,%
+ \c!type=,%
+ \c!dataset=#1,%
+ \c!file=#2,%
+ #3]% % all or used
+ \clf_btxsavedataset
+ dataset {\dummyparameter\c!dataset}%
+ filename {\dummyparameter\c!file}%
+ filetype {\dummyparameter\c!type}%
+ criterium {\dummyparameter\c!criterium}%
+ \relax
+ \endgroup}
+
+% \savebtxdataset[default][e:/tmp/foo.bib]
+% \savebtxdataset[default][e:/tmp/foo.lua]
+% \savebtxdataset[default][e:/tmp/foo.xml]
+
+%D In-text entries:
+
+\unexpanded\def\placecitation{\citation[entry]} % [#1]
+
+\unexpanded\def\btxhandleciteentry
+ {\dontleavehmode
+ \begingroup
+ \def\currentbtxcitealternative{entry}%
+ \setbtxparameterset\s!cite\currentbtxcitealternative % needs checking
+ \btxcitereference
+ \btx_entry_inject
+ \endgroup}
+
+%D Registers
+
+% \setupbtxregister
+% [\c!state=\v!start,
+% \c!dataset=\v!all,
+% \c!method=\v!always]
+
+\unexpanded\def\publ_registers_set
+ {\ifx\currentbtxregister\empty \else
+ \clf_btxsetregister
+ specification {\currentbtxspecification}%
+ name {\currentbtxregister}%
+ state {\btxregisterparameter\c!state}%
+ dataset {\btxregisterparameter\c!dataset}%
+ field {\btxregisterparameter\c!field}%
+ register {\btxregisterparameter\c!register}%
+ method {\btxregisterparameter\c!method}%
+ alternative {\btxregisterparameter\c!alternative}%
+ \relax
+ \fi}
\appendtoks
- \loadbtxdefinitionfile[\btxrenderingparameter\c!alternative]
-\to \everysetupbtxrendering
+ \publ_registers_set
+\to \everydefinebtxregister
-\stopcontextdefinitioncode
+\appendtoks
+ \publ_registers_set
+\to \everysetupbtxregister
+
+\appendtoks
+ \normalexpanded{%
+ \defineprocessor
+ [\s!btx:r:\currentbtxregister]%
+ [\c!style=\noexpand\namedbtxregisterparameter{\currentbtxregister}\noexpand\c!style,
+ \c!color=\noexpand\namedbtxregisterparameter{\currentbtxregister}\noexpand\c!color]}%
+\to \everydefinebtxregister
+
+\appendtoks
+ \clf_btxtoregister{\currentbtxdataset}{\currentbtxtag}%
+\to \t_btx_reference_inject
+
+\unexpanded\def\btxindexedauthor#1#2#3#4#5#6% alternative von last first junior
+ {\begingroup
+ \def\currentbtxcitealternative{#1}%
+ \ifx\currentbtxcitealternative\empty
+ \edef\currentbtxcitealternative{invertedshort}% maybe we need some default here too?
+ \fi
+ %let\currentbtxlistvariant\currentbtxcitealternative % we inherit
+ \the\everysetupbtxciteplacement
+ \def\currentbtxvons {#2}%
+ \def\currentbtxsurnames {#3}%
+ \def\currentbtxinitials {#4}%
+ \def\currentbtxfirstnames {#5}%
+ \def\currentbtxjuniors {#6}%
+ \setbtxparameterset\s!cite\currentbtxcitealternative
+ \fastsetup{\s!btx:\s!cite:\s!author:\currentbtxcitealternative}%
+ \endgroup}
+
+%D We hook some setters in the definition sets:
+
+% \installdefinitionsetmember \??btx {btxspecification} \??btxcitevariant {btxcitevariant}
+% \installdefinitionsetmember \??btx {btxspecification} \??btxlistvariant {btxlistvariant}
+% \installdefinitionsetmember \??btx {btxspecification} \??btxlist {btxlist}
+% \installdefinitionsetmember \??btx {btxspecification} \??btxrendering {btxrendering}
+% \installdefinitionsetmember \??btx {btxspecification} \??btx {btx}
+
+%D And more helpers ... a never ending story these publications:
+
+% \definebtx
+% [btx:apa:list:article:title]
+% [style=bolditalic,
+% command=\WORD]
+%
+% \btxstartstyle[btx:apa:list:article:title]
+% \btxusecommand[btx:apa:list:article:title]{foo}
+% \btxstopstyle
+
+\let\savedcurrentbtx\empty
+
+\unexpanded\def\btxstartstyle[#1]%
+ {\begingroup
+ \let\savedcurrentbtx\currentbtx
+ \def\currentbtx{#1}%
+ \usebtxstyle\c!style
+ \let\currentbtx\savedcurrentbtx}
+
+\unexpanded\def\btxstartcolor[#1]%
+ {\begingroup
+ \let\savedcurrentbtx\currentbtx
+ \def\currentbtx{#1}%
+ \usebtxcolor\c!color
+ \let\currentbtx\savedcurrentbtx}
+
+\unexpanded\def\btxstartstyleandcolor[#1]%
+ {\begingroup
+ \let\savedcurrentbtx\currentbtx
+ \def\currentbtx{#1}%
+ \usebtxstyleandcolor\c!style\c!color
+ \let\currentbtx\savedcurrentbtx}
+
+\let\btxstopstyle \endgroup
+\let\btxstopcolor \endgroup
+\let\btxstopstyleandcolor\endgroup
+
+\unexpanded\def\btxusecommand[#1]%
+ {\namedbtxparameter{#1}\c!command}
%D Defaults:
\setupbtxrendering
- [\c!dataset=\v!standard,
+ [\c!interaction=\v!start, % \v!all
+ \c!specification=\btxparameter\c!specification,
+ \c!dataset=\v!default,
+ \c!repeat=\v!no,
+ \c!continue=\v!no,
\c!method=\v!global,
- \c!setups=btx:rendering:\btxrenderingparameter\c!alternative,
- \c!alternative=apa,
- \c!sorttype=,
- \c!criterium=,
+ % \c!setups=btx:\btxrenderingparameter\c!alternative:initialize, % not the same usage as cite !
+ % \c!sorttype=authoryear,
+ \c!criterium=\v!text,
\c!refcommand=authoryears, % todo
\c!numbering=\v!yes,
-% \c!autohang=\v!no,
+ %\c!saveinlist=\v!no, % maybe for before/after
+ \c!textstate=\v!start,
\c!width=\v!auto,
- \c!separator={; },
+ %\c!pageright=,
+ %\c!pageleft=,
+ \c!separator={;\space},
\c!distance=1.5\emwidth]
-\definebtxrendering
- [\v!standard]
+% Quite some interpunction and labels are the same of at least consistent within
+% a standard when citations and list entries are involved. We assume that each
+% standard defines its own set but it can fall back on these defaults.
-\setupbtxcitevariant
+\setupbtx
[\c!interaction=\v!start,
- \c!setups=btx:cite:\btxcitevariantparameter\c!alternative,
- \c!alternative=num,
- \c!andtext={ and },
- \c!otherstext={ et al.},
- \c!pubsep={, },
- \c!lastpubsep={ and },
- \c!finalpubsep={ and },
+ \c!alternative=num, % default cite form
+ \c!inbetween=\space,
+ \c!range=\endash, % separator:range?
\c!compress=\v!no,
- \c!inbetween={ },
- \c!range=\endash,
- \c!left=,
- \c!middle=,
- \c!right=]
-
-\definebtxcitevariant
- [author]
- [%c!sorttype=,
- \c!left={(},
- \c!middle={, },
- \c!right={)}]
-
-\definebtxcitevariant
- [authornum]
- [author]
- [\c!inbetween={ }]
-
-\definebtxcitevariant
- [authoryear]
- [\c!compress=\v!yes,
- \c!inbetween={, },
- \c!left={(},
- \c!middle={, },
- \c!right={)}]
-
-\definebtxcitevariant
- [authoryears]
- [authoryear]
-
-\definebtxcitevariant
- [author:num]
- [authornum]
- [\c!left={[},
- \c!right={]}]
-
-\definebtxcitevariant
- [author:year]
- [authoryear]
- [\c!left={(},
- \c!right={)}]
-
-\definebtxcitevariant
- [author:years]
- [authoryears]
- [\c!left=,
- \c!right=]
-
-\definebtxcitevariant
- [year]
- [\c!left={(},
- \c!middle={, }, % is middle used?
- \c!right={)}]
-
-\definebtxcitevariant
- [tag]
- [\c!left={[},
- \c!middle={, },
- \c!right={]}]
-
-\definebtxcitevariant
- [key]
- [tag]
-
-\definebtxcitevariant
- [serial]
- [\c!left={[},
- \c!middle={, },
- \c!right={]}]
-
-\definebtxcitevariant
- [page]
- [\c!left={[},
- \c!middle={, },
- \c!right={]}]
-
-\definebtxcitevariant
- [short]
- [\c!left={[},
- \c!middle={, },
- \c!right={]}]
-
-\definebtxcitevariant
- [category]
- [\c!left={[},
- \c!middle={, },
- \c!right={]}]
-
-\definebtxcitevariant
- [type]
- [category]
-
-\definebtxcitevariant
- [doi]
- [\c!left={[},
- \c!middle={, },
- \c!right={]}]
-
-\definebtxcitevariant
- [url]
- [\c!left={[},
- \c!middle={, },
- \c!right={]}]
-
-\definebtxcitevariant
- [page]
- [\c!left=,
- \c!middle={, },
- \c!right=]
-
-\definebtxcitevariant
- [num]
- [\c!compress=\v!yes,
- \c!left={[},
- \c!middle={, },
- \c!right={]}]
-
-\setupbtxlistvariant
- [\c!namesep={, },
- \c!lastnamesep={ and },
- \c!finalnamesep={ and },
- \c!firstnamesep={ },
- \c!juniorsep={ },
- \c!vonsep={ },
- \c!surnamesep={, },
- \c!surnameinitialsep={, },
- \c!surnamefirstnamesep={, },
- \c!etallimit=5,
- \c!etaldisplay=5,
- \c!etaltext={ et al.},
- \c!monthconversion=\v!number,
- \c!authorconversion=\v!normal]
-
-\definebtxlistvariant
- [author]
- [author=invertedshort] % we could also do this in the apa style itself
-
-\definebtxlistvariant
- [editor]
- [author]
-
-\definebtxlistvariant
- [artauthor]
- [author]
-
-\setupbtxcitevariant
- [\c!author =\btxlistvariantparameter\c!author,
- \c!etallimit =\btxlistvariantparameter\c!etallimit,
- \c!etaldisplay =\btxlistvariantparameter\c!etaldisplay]
+ \c!etallimit=3,
+ \c!etaldisplay=\btxparameter\c!etallimit,
+ \c!otherstext={\space et al.},
+ \c!separator:firstnames={\space},
+ \c!separator:juniors={\space},
+ \c!separator:vons={\space},
+ \c!separator:initials={\space},
+ \c!stopper:initials={.},
+ %\c!surnamesep={,\space}, % is this used anywhere?
+ \c!separator:invertedinitials={,\space},
+ \c!separator:invertedfirstnames={,\space},
+ \c!separator:names:2={,\space}, % separates multiple names
+ \c!separator:names:3=\btxparameter{\c!separator:2}, % before last name in a list
+ \c!separator:names:4=\btxparameter{\c!separator:2}, % between only two names
+ \c!separator:2={;\space}, % aka pubsep - separates multiple objects
+ \c!separator:3=\btxparameter{separator:2}, % before last object in a list
+ \c!separator:4=\btxparameter{separator:2}] % between only two objects
% Do we want these in the format? Loading them delayed is somewhat messy.
-\loadbtxdefinitionfile[apa]
-\loadbtxdefinitionfile[cite]
\loadbtxdefinitionfile[commands]
\loadbtxdefinitionfile[definitions]
+\loadbtxdefinitionfile[cite]
+\loadbtxdefinitionfile[list]
+\loadbtxdefinitionfile[page]
+\loadbtxdefinitionfile[author]
+
+% we assume that the users sets up the right specification and if not ... well,
+% hope for the best that something shows up and consult the manual otherwise
+
+\unexpanded\def\usebtxdefinitions[#1]%
+ {\loadbtxdefinitionfile[#1]% % for hh
+ \setupbtx[\c!specification=#1]} % for ab
+
+\setupbtx
+ [\c!specification=\s!default,
+ \c!dataset=\v!default,
+ \c!default=\v!default]
+
+\loadbtxdefinitionfile
+ [\s!default]
+
\protect
diff --git a/Master/texmf-dist/tex/context/base/publ-jrn.lua b/Master/texmf-dist/tex/context/base/publ-jrn.lua
new file mode 100644
index 00000000000..2e040841798
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-jrn.lua
@@ -0,0 +1,188 @@
+if not modules then modules = { } end modules ['publ-jrn'] = {
+ version = 1.001,
+ comment = "this module part of publication support",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- http://jabref.sourceforge.net/journals/journal_abbreviations_general.txt
+--
+-- = [;shortest unique abbreviation[;frequency]].
+
+-- require("char-utf")
+
+-- Abhandlungen aus dem Westfälischen Museum für Naturkunde = Abh. Westfäl. Mus. Nat.kd.
+-- Abhandlungen der Naturforschenden Gesellschaft in Zürich = Abh. Nat.forsch. Ges. Zür.
+-- Abhandlungen des Naturwissenschaftlichen Vereins zu Bremen = Abh. Nat.wiss. Ver. Bremen
+
+local context = context
+local commands = commands
+
+local find = string.find
+local P, C, S, Cs, lpegmatch, lpegpatterns = lpeg.P, lpeg.C, lpeg.S, lpeg.Cs, lpeg.match, lpeg.patterns
+
+local report_journals = logs.reporter("publications","journals")
+
+local publications = publications
+local journals = { }
+publications.journals = journals
+
+local lowercase = characters.lower
+
+local expansions = { }
+local abbreviations = { }
+local nofexpansions = 0
+local nofabbreviations = 0
+
+local valid = 1 - S([[ ."':;,-]])
+local pattern = Cs((valid^1 + P(1)/"")^1)
+
+local function simplify(name)
+ -- we have utf but it doesn't matter much if we lower the bytes
+ return name and lowercase(lpegmatch(pattern,name)) or name
+end
+
+local function add(expansion,abbreviation)
+ if expansion and abbreviation then
+ local se = simplify(expansion)
+ local sa = simplify(abbreviation)
+ if not expansions[sa] then
+ expansions[sa] = expansion
+ nofexpansions = nofexpansions + 1
+ end
+ if not abbreviations[se] then
+ abbreviations[se] = abbreviation
+ nofabbreviations = nofabbreviations + 1
+ end
+ end
+end
+
+-- [#%-] comment
+-- meaning = abbreviations [;.....]
+
+local whitespace = lpegpatterns.whitespace^0
+local assignment = whitespace * P("=") * whitespace
+local separator = P(";")
+local newline = lpegpatterns.newline
+local endofline = lpegpatterns.space^0 * (newline + P(-1) + separator)
+local restofline = (1-newline)^0
+local splitter = whitespace * C((1-assignment)^1) * assignment * C((1-endofline)^1) * restofline
+local comment = S("#-%") * restofline
+local pattern = (comment + splitter / add)^0
+
+function journals.load(filename)
+ if not filename then
+ return
+ end-- error
+ if file.suffix(filename,"txt") then
+ local data = io.loaddata(filename)
+ if type(data) ~= "string" then
+ return
+ elseif find(data,"=") then
+ -- expansion = abbreviation
+ lpegmatch(pattern,data)
+ end
+ elseif file.suffix(filename,"lua") then
+ local data = table.load(filename)
+ if type(data) ~= "table" then
+ return
+ else
+ local de = data.expansions
+ local da = data.abbreviations
+ if de and da then
+ -- { expansions = { a = e }, abbreviations = { e = a } }
+ if next(expansions) then
+ table.merge(expansions,de)
+ else
+ expansions = de
+ end
+ if next(abbreviations) then
+ table.merge(abbreviations,da)
+ else
+ abbreviations = da
+ end
+ elseif #data > 0 then
+ -- { expansion, abbreviation }, ... }
+ for i=1,#data do
+ local d = d[i]
+ add(d[1],d[2])
+ end
+ else
+ -- { expansion = abbreviation, ... }
+ for expansion, abbreviation in data do
+ add(expansion,abbreviation)
+ end
+ end
+ end
+ end
+ report_journals("file %a loaded, %s expansions, %s abbreviations",filename,nofexpansions,nofabbreviations)
+end
+
+function journals.save(filename)
+ table.save(filename,{ expansions = expansions, abbreviations = abbreviations })
+end
+
+function journals.add(expansion,abbreviation)
+ add(expansion,abbreviation)
+end
+
+function journals.expanded(name)
+ local s = simplify(name)
+ return expansions[s] or expansions[simplify(abbreviations[s])] or name
+end
+
+function journals.abbreviated(name)
+ local s = simplify(name)
+ return abbreviations[s] or abbreviations[simplify(expansions[s])] or name
+end
+
+local implement = interfaces and interfaces.implement
+
+if implement then
+
+ implement {
+ name = "btxloadjournallist",
+ arguments = "string",
+ actions = journals.load
+ }
+
+ implement {
+ name = "btxsavejournallist",
+ arguments = "string",
+ actions = journals.save
+ }
+
+ implement {
+ name = "btxaddjournal",
+ arguments = { "string", "string" },
+ actions = { journals.add, context }
+ }
+
+ implement {
+ name = "btxexpandedjournal",
+ arguments = "string",
+ actions = { journals.expanded, context },
+ }
+
+ implement {
+ name = "btxabbreviatedjournal",
+ arguments = "string",
+ actions = { journals.abbreviated, context },
+ }
+
+end
+
+-- journals.load("e:/tmp/journals.txt")
+-- journals.save("e:/tmp/journals.lua")
+
+-- inspect(journals.expanded ("Z. Ökol. Nat.schutz"))
+-- inspect(journals.abbreviated("Z. Ökol. Nat. schutz"))
+
+if typesetters then
+ typesetters.manipulators.methods.expandedjournal = journals.expanded
+ typesetters.manipulators.methods.abbreviatedjournal = journals.abbreviated
+end
+
+-- journals.load("t:/manuals/publications-mkiv/journals.txt")
+-- journals.save("t:/manuals/publications-mkiv/journals.lua")
diff --git a/Master/texmf-dist/tex/context/base/publ-oth.lua b/Master/texmf-dist/tex/context/base/publ-oth.lua
index 14da19f9cb4..55c62c31eba 100644
--- a/Master/texmf-dist/tex/context/base/publ-oth.lua
+++ b/Master/texmf-dist/tex/context/base/publ-oth.lua
@@ -11,8 +11,10 @@ local lpegmatch = lpeg.match
local p_endofline = lpeg.patterns.newline
-local loaders = publications.loaders
-local getindex = publications.getindex
+local publications = publications
+
+local loaders = publications.loaders
+local getindex = publications.getindex
local function addfield(t,k,v,fields)
k = fields[k]
@@ -66,7 +68,10 @@ end
function loaders.endnote(dataset,filename)
-- we could combine the next into checkfield but let's not create too messy code
- loaders.lua(dataset,publications.endnotes_to_btx(io.loaddata(filename) or ""))
+ local dataset, fullname = publications.resolvedname(dataset,filename)
+ if fullname then
+ loaders.lua(dataset,publications.endnotes_to_btx(io.loaddata(fullname) or ""))
+ end
end
-- refman --
@@ -97,7 +102,10 @@ end
function loaders.refman(dataset,filename)
-- we could combine the next into checkfield but let's not create too messy code
- loaders.lua(dataset,publications.refman_to_btx(io.loaddata(filename) or ""))
+ local dataset, fullname = publications.resolvedname(dataset,filename)
+ if fullname then
+ loaders.lua(dataset,publications.refman_to_btx(io.loaddata(fullname) or ""))
+ end
end
-- test --
diff --git a/Master/texmf-dist/tex/context/base/publ-reg.lua b/Master/texmf-dist/tex/context/base/publ-reg.lua
new file mode 100644
index 00000000000..39469e510db
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-reg.lua
@@ -0,0 +1,177 @@
+if not modules then modules = { } end modules ['publ-reg'] = {
+ version = 1.001,
+ comment = "this module part of publication support",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local formatters = string.formatters
+local concat = table.concat
+local sortedhash = table.sortedhash
+local lpegmatch = lpeg.match
+
+local context = context
+
+local implement = interfaces.implement
+local variables = interfaces.variables
+
+local v_once = variables.once
+local v_stop = variables.stop
+local v_all = variables.all
+
+local publications = publications
+local datasets = publications.datasets
+local specifications = publications.specifications
+local writers = publications.writers
+local getcasted = publications.getcasted
+
+local registrations = { }
+local sequence = { }
+local flushers = table.setmetatableindex(function(t,k) local v = t.default t[k] = v return v end)
+
+local function btxsetregister(specification)
+ local name = specification.name
+ local register = specification.register
+ local dataset = specification.dataset
+ local field = specification.field
+ if not field or field == "" or not register or register == "" then
+ return
+ end
+ if not dataset or dataset == "" then
+ dataset = v_all
+ end
+ -- could be metatable magic
+ local s = registrations[register]
+ if not s then
+ s = { }
+ registrations[register] = s
+ end
+ local processors = name ~= register and name or ""
+ if processor == "" then
+ processor = nil
+ elseif processor then
+ processor = "btx:r:" .. processor
+ end
+ local datasets = utilities.parsers.settings_to_array(dataset)
+ for i=1,#datasets do
+ local dataset = datasets[i]
+ local d = s[dataset]
+ if not d then
+ d = { }
+ s[dataset] = d
+ end
+ --
+ -- check all
+ --
+ d.active = specification.state ~= v_stop
+ d.once = specification.method == v_once or false
+ d.field = field
+ d.processor = processor
+ d.alternative = d.alternative or specification.alternative
+ d.register = register
+ d.dataset = dataset
+ d.done = d.done or { }
+ end
+ --
+ sequence = { }
+ for register, s in sortedhash(registrations) do
+ for dataset, d in sortedhash(s) do
+ if d.active then
+ sequence[#sequence+1] = d
+ end
+ end
+ end
+end
+
+local function btxtoregister(dataset,tag)
+ local current = datasets[dataset]
+ for i=1,#sequence do
+ local step = sequence[i]
+ local dset = step.dataset
+ if dset == v_all or dset == dataset then
+ local done = step.done
+ if not done[tag] then
+ local value, field, kind = getcasted(current,tag,step.field,specifications[step.specification])
+ if value then
+ flushers[kind](step,field,value)
+ end
+ done[tag] = true
+ end
+ end
+ end
+end
+
+implement {
+ name = "btxsetregister",
+ actions = btxsetregister,
+ arguments = {
+ {
+ { "specification" },
+ { "name" },
+ { "state" },
+ { "dataset" },
+ { "field" },
+ { "register" },
+ { "method" },
+ { "alternative" },
+ }
+ }
+}
+
+implement {
+ name = "btxtoregister",
+ actions = btxtoregister,
+ arguments = { "string", "string" }
+}
+
+-- context.setregisterentry (
+-- { register },
+-- {
+-- ["entries:1"] = value,
+-- ["keys:1"] = value,
+-- }
+-- )
+
+local ctx_dosetfastregisterentry = context.dosetfastregisterentry -- register entry key
+
+----- p_keywords = lpeg.tsplitat(lpeg.patterns.whitespace^0 * lpeg.P(";") * lpeg.patterns.whitespace^0)
+local components = publications.components.author
+local f_author = formatters[ [[\btxindexedauthor{%s}{%s}{%s}{%s}{%s}{%s}]] ]
+
+function flushers.string(step,field,value)
+ if type(value) == "string" and value ~= "" then
+ ctx_dosetfastregisterentry(step.register,value or "","",step.processor or "","")
+ end
+end
+
+flushers.default = flushers.string
+
+local shorts = {
+ normalshort = "normalshort",
+ invertedshort = "invertedshort",
+}
+
+function flushers.author(step,field,value)
+ if type(value) == "table" and #value > 0 then
+ local register = step.register
+ local processor = step.processor
+ local alternative = shorts[step.alternative or "invertedshort"] or "invertedshort"
+ for i=1,#value do
+ local a = value[i]
+ local k = writers[field] { a }
+ local e = f_author(alternative,components(a,short))
+ ctx_dosetfastregisterentry(register,e,k,processor or "","")
+ end
+ end
+end
+
+function flushers.keyword(step,field,value)
+ if type(value) == "table" and #value > 0 then
+ local register = step.register
+ local processor = step.processor
+ for i=1,#value do
+ ctx_dosetfastregisterentry(register,value[i],"",processor or "","")
+ end
+ end
+end
diff --git a/Master/texmf-dist/tex/context/base/publ-sor.lua b/Master/texmf-dist/tex/context/base/publ-sor.lua
new file mode 100644
index 00000000000..c3fcdb0eed1
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/publ-sor.lua
@@ -0,0 +1,276 @@
+if not modules then modules = { } end modules ['publ-sor'] = {
+ version = 1.001,
+ comment = "this module part of publication support",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- if needed we can optimize this one: chekc if it's detail or something else
+-- and use direct access, but in practice it's fast enough
+
+local type = type
+local concat = table.concat
+local formatters = string.formatters
+local compare = sorters.comparers.basic -- (a,b)
+local sort = table.sort
+
+local toarray = utilities.parsers.settings_to_array
+local utfchar = utf.char
+
+local publications = publications
+local writers = publications.writers
+
+local variables = interfaces.variables
+local v_short = variables.short
+local v_default = variables.default
+local v_reference = variables.reference
+local v_dataset = variables.dataset
+
+local report = logs.reporter("publications","sorters")
+
+local trace_sorters trackers.register("publications.sorters",function(v) trace_sorters = v end)
+
+-- authors(s) | year | journal | title | pages
+
+local template = [[
+local type, tostring = type, tostring
+
+local writers = publications.writers
+local datasets = publications.datasets
+local getter = publications.getfaster -- (current,data,details,field,categories,types)
+local strip = sorters.strip
+local splitter = sorters.splitters.utf
+
+local function newsplitter(splitter)
+ return table.setmetatableindex({},function(t,k) -- could be done in the sorter but seldom that many shared
+ local v = splitter(k,true) -- in other cases
+ t[k] = v
+ return v
+ end)
+end
+
+return function(dataset,list,method) -- indexer
+ local current = datasets[dataset]
+ local luadata = current.luadata
+ local details = current.details
+ local specification = publications.currentspecification
+ local categories = specification.categories
+ local types = specification.types
+ local splitted = newsplitter(splitter) -- saves mem
+ local snippets = { } -- saves mem
+ local result = { }
+
+%helpers%
+
+ for i=1,#list do
+ -- either { tag, tag, ... } or { { tag, index }, { tag, index } }
+ local li = list[i]
+ local tag = type(li) == "string" and li or li[1]
+ local index = tostring(i)
+ local entry = luadata[tag]
+ if entry then
+ local detail = details[tag]
+ result[i] = {
+ index = i,
+ split = {
+
+%getters%
+
+ },
+ }
+ else
+ result[i] = {
+ index = i,
+ split = {
+
+%unknowns%
+
+ },
+ }
+ end
+ end
+ return result
+end
+]]
+
+local f_getter = formatters["splitted[strip(getter(current,entry,detail,%q,categories,types) or %q)], -- %s"]
+local f_writer = formatters["splitted[strip(writer_%s(getter(current,entry,detail,%q,categories,types) or %q,snippets))], -- %s"]
+local f_helper = formatters["local writer_%s = writers[%q] -- %s: %s"]
+local f_value = formatters["splitted[%q], -- %s"]
+local s_index = "splitted[index], -- the order in the list, always added"
+
+-- there is no need to cache this in specification
+
+local sharedmethods = { }
+publications.sortmethods = sharedmethods
+
+local function sortsequence(dataset,list,sorttype)
+
+ if not list or #list == 0 then
+ return
+ end
+
+ local specification = publications.currentspecification
+ local types = specification.types
+ local sortmethods = specification.sortmethods
+ local method = sortmethods and sortmethods[sorttype] or sharedmethods[sorttype]
+ local sequence = method and method.sequence
+
+ local s_default = ""
+ local s_unknown = ""
+
+ local c_default = utfchar(0xFFFE)
+ local c_unknown = utfchar(0xFFFF)
+
+ if not sequence and type(sorttype) == "string" then
+ local list = toarray(sorttype)
+ if #list > 0 then
+ sequence = { }
+ for i=1,#list do
+ local entry = toarray(list[i])
+ local field = entry[1]
+ local default = entry[2]
+ local unknown = entry[3] or default
+ sequence[i] = {
+ field = field,
+ default = default == s_default and c_default or default or c_default,
+ unknown = unknown == s_unknown and c_unknown or unknown or c_unknown,
+ }
+ end
+ end
+ if trace_sorters then
+ report("creating sequence from method %a",sorttype)
+ end
+ end
+
+ if sequence then
+
+ local getters = { }
+ local unknowns = { }
+ local helpers = { }
+
+ if trace_sorters then
+ report("initializing method %a",sorttype)
+ end
+
+ for i=1,#sequence do
+ local step = sequence[i]
+ local field = step.field or "?"
+ local default = step.default or c_default
+ local unknown = step.unknown or c_unknown
+ local fldtype = types[field]
+ local writer = fldtype and writers[fldtype]
+
+ if trace_sorters then
+ report("% 3i : field %a, type %a, default %a, unknown %a",i,field,fldtype,
+ default == c_default and s_default or default,
+ unknown == c_unknown and s_unknown or unknown
+ )
+ end
+
+ if writer then
+ local h = #helpers + 1
+ getters[i] = f_writer(h,field,default,field)
+ helpers[h] = f_helper(h,fldtype,field,fldtype)
+ else
+ getters[i] = f_getter(field,default,field)
+ end
+ unknowns[i] = f_value(unknown,field)
+ end
+
+ unknowns[#unknowns+1] = s_index
+ getters [#getters +1] = s_index
+
+ local code = utilities.templates.replace(template, {
+ helpers = concat(helpers, "\n"),
+ getters = concat(getters, "\n"),
+ unknowns = concat(unknowns,"\n"),
+ })
+
+ -- print(code)
+
+ local action, error = loadstring(code)
+ if type(action) == "function" then
+ action = action()
+ else
+ report("error when compiling sort method %a: %s",sorttype,error or "unknown")
+ end
+ if type(action) == "function" then
+ local valid = action(dataset,list,method)
+ if valid and #valid > 0 then
+ sorters.sort(valid,compare)
+ return valid
+ else
+ report("error when applying sort method %a",sorttype)
+ end
+ else
+ report("error in sort method %a",sorttype)
+ end
+ else
+ report("invalid sort method %a",sorttype)
+ end
+
+end
+
+local sorters = {
+ [v_short] = function(dataset,rendering,list)
+ local shorts = rendering.shorts
+ local function compare(a,b)
+ local aa, bb = a and a[1], b and b[1]
+ if aa and bb then
+ aa, bb = shorts[aa], shorts[bb]
+ return aa and bb and aa < bb
+ end
+ return false
+ end
+ sort(list,compare)
+ end,
+ [v_reference] = function(dataset,rendering,list)
+ local function compare(a,b)
+ local aa, bb = a and a[1], b and b[1]
+ if aa and bb then
+ return aa and bb and aa < bb
+ end
+ return false
+ end
+ sort(list,compare)
+ end,
+ [v_dataset] = function(dataset,rendering,list)
+ local function compare(a,b)
+-- inspect(a,b)
+ local aa, bb = a and a[6], b and b[6]
+ if aa and bb then
+ -- aa, bb = list[aa].index or 0, list[bb].index or 0
+ return aa and bb and aa < bb
+ end
+ return false
+ end
+ sort(list,compare)
+ end,
+ [v_default] = function(dataset,rendering,list,sorttype) -- experimental
+ if sorttype == "" or sorttype == v_default then
+ local function compare(a,b)
+ local aa, bb = a and a[3], b and b[3]
+ if aa and bb then
+ return aa and bb and aa < bb
+ end
+ return false
+ end
+ sort(list,compare)
+ else
+ local valid = sortsequence(dataset,list,sorttype)
+ if valid and #valid > 0 then
+ for i=1,#valid do
+ local v = valid[i]
+ valid[i] = list[v.index]
+ end
+ return valid
+ end
+ end
+ end
+}
+
+table.setmetatableindex(sorters,function(t,k) return t[v_default] end)
+
+publications.lists.sorters = sorters
diff --git a/Master/texmf-dist/tex/context/base/publ-tra.lua b/Master/texmf-dist/tex/context/base/publ-tra.lua
index 98c81d800dd..65e9b7ff486 100644
--- a/Master/texmf-dist/tex/context/base/publ-tra.lua
+++ b/Master/texmf-dist/tex/context/base/publ-tra.lua
@@ -6,291 +6,475 @@ if not modules then modules = { } end modules ['publ-tra'] = {
license = "see context related readme files"
}
-local sortedhash = table.sortedhash
-
-local tracers = { }
-publications.tracers = tracers
-local datasets = publications.datasets
-
-local context = context
-local NC, NR = context.NC, context.NR
-local bold = context.bold
-local darkgreen, darkred, darkblue = context.darkgreen, context.darkred, context.darkblue
-
-local fields = table.sorted {
- "abstract",
- "address",
- "annotate",
- "author",
- "booktitle",
- "chapter",
- "comment",
- "country",
- "doi",
- "edition",
- "editor",
- "eprint",
- "howpublished",
- "institution",
- "isbn",
- "issn",
- "journal",
- "key",
- "keyword",
- "keywords",
- "language",
- "lastchecked",
- "month",
- "names",
- "note",
- "notes",
- "number",
- "organization",
- "pages",
- "publisher",
- "school",
- "series",
- "size",
- "title",
- "type",
- "url",
- "volume",
- "year",
- "nationality",
- "assignee",
- "bibnumber",
- "day",
- "dayfiled",
- "monthfiled",
- "yearfiled",
- "revision",
-}
+-- todo: use context.tt .. more efficient, less code
-local citevariants = table.sorted {
- "author",
- "authoryear",
- "authoryears",
- "authornum",
- "year",
- "short",
- "serial",
- "key",
- "doi",
- "url",
- "type",
- "page",
- "none",
- "num",
-}
+local next, type = next, type
-local listvariants = table.sorted {
- "author",
- "editor",
- "artauthor",
-}
+local sortedhash = table.sortedhash
+local sortedkeys = table.sortedkeys
+local settings_to_array = utilities.parsers.settings_to_array
+local formatters = string.formatters
+local concat = table.concat
--- local categories = table.sorted {
--- "article",
--- "book",
--- "booklet",
--- "conference",
--- "inbook",
--- "incollection",
--- "inproceedings",
--- "manual",
--- "mastersthesis",
--- "misc",
--- "phdthesis",
--- "proceedings",
--- "techreport",
--- "unpublished",
--- }
-
-local categories = {
- article = {
- required = { "author", "title", "journal", "year" },
- optional = { "volume", "number", "pages", "month", "note" },
- },
- book = {
- required = { { "author", "editor" }, "title", "publisher", "year" },
- optional = { { "volume", "number" }, "series", "address", "edition", "month","note" },
- },
- booklet = {
- required = { "title" },
- optional = { "author", "howpublished", "address", "month", "year", "note" },
- },
- inbook = {
- required = { { "author", "editor" }, "title", { "chapter", "pages" }, "publisher","year" },
- optional = { { "volume", "number" }, "series", "type", "address", "edition", "month", "note" },
- },
- incollection = {
- required = { "author", "title", "booktitle", "publisher", "year" },
- optional = { "editor", { "volume", "number" }, "series", "type", "chapter", "pages", "address", "edition", "month", "note" },
- },
- inproceedings = {
- required = { "author", "title", "booktitle", "year" },
- optional = { "editor", { "volume", "number" }, "series", "pages", "address", "month","organization", "publisher", "note" },
- },
- manual = {
- required = { "title" },
- optional = { "author", "organization", "address", "edition", "month", "year", "note" },
- },
- mastersthesis = {
- required = { "author", "title", "school", "year" },
- optional = { "type", "address", "month", "note" },
- },
- misc = {
- required = { "author", "title", "howpublished", "month", "year", "note" },
- optional = { "author", "title", "howpublished", "month", "year", "note" },
- },
- phdthesis = {
- required = { "author", "title", "school", "year" },
- optional = { "type", "address", "month", "note" },
- },
- proceedings = {
- required = { "title", "year" },
- optional = { "editor", { "volume", "number" }, "series", "address", "month", "organization", "publisher", "note" },
- },
- techreport = {
- required = { "author", "title", "institution", "year" },
- optional = { "type", "number", "address", "month", "note" },
- },
- unpublished = {
- required = { "author", "title", "note" },
- optional = { "month", "year" },
- },
-}
+local context = context
+local commands = commands
+
+local v_default = interfaces.variables.default
+
+local publications = publications
+local tracers = publications.tracers
+local tables = publications.tables
+local datasets = publications.datasets
+local specifications = publications.specifications
+local citevariants = publications.citevariants
+local getfield = publications.getfield
+local getcasted = publications.getcasted
-publications.tracers.fields = fields
-publications.tracers.categories = categories
-publications.tracers.citevariants = citevariants
-publications.tracers.listvariants = listvariants
--- -- --
+local ctx_NC, ctx_NR, ctx_HL, ctx_FL, ctx_ML, ctx_LL, ctx_EQ = context.NC, context.NR, context.HL, context.FL, context.ML, context.LL, context.EQ
-function tracers.showdatasetfields(dataset)
- local luadata = datasets[dataset].luadata
+local ctx_starttabulate = context.starttabulate
+local ctx_stoptabulate = context.stoptabulate
+
+local ctx_formatted = context.formatted
+local ctx_bold = ctx_formatted.monobold
+local ctx_monobold = ctx_formatted.monobold
+local ctx_verbatim = ctx_formatted.verbatim
+
+local ctx_rotate = context.rotate
+local ctx_llap = context.llap
+local ctx_rlap = context.rlap
+local ctx_page = context.page
+
+local privates = tables.privates
+local specials = tables.specials
+
+local report = logs.reporter("publications","tracers")
+
+function tracers.showdatasetfields(settings)
+ local dataset = settings.dataset
+ local current = datasets[dataset]
+ local luadata = current.luadata
+ local specification = settings.specification
+ local fielddata = specification and specifications[specification] or specifications.apa
+ local categories = fielddata.categories
if next(luadata) then
- context.starttabulate { "|lT|lT|pT|" }
- NC() bold("tag")
- NC() bold("category")
- NC() bold("fields")
- NC() NR() context.FL() -- HL()
- for k, v in sortedhash(luadata) do
- NC() context(k)
- NC() context(v.category)
- NC()
- for k, v in sortedhash(v) do
- if k ~= "details" and k ~= "tag" and k ~= "category" then
- context("%s ",k)
+ ctx_starttabulate { "|lT|lT|pTl|" }
+ ctx_NC() ctx_bold("tag")
+ ctx_NC() ctx_bold("category")
+ ctx_NC() ctx_bold("fields")
+ ctx_NC() ctx_NR()
+ ctx_FL()
+ for tag, entry in sortedhash(luadata) do
+ local category = entry.category
+ local catedata = categories[category]
+ local fields = catedata and catedata.fields or { }
+ ctx_NC() context(tag)
+ ctx_NC() context(category)
+ ctx_NC() -- grouping around colors needed
+ for key, value in sortedhash(entry) do
+ if privates[key] then
+ -- skip
+ elseif specials[key] then
+ context("{\\darkblue %s} ",key)
+ else
+ local kind = fields[key]
+ if kind == "required" then
+ context("{\\darkgreen %s} ",key)
+ elseif kind == "optional" then
+ context("%s ",key)
+ else
+ context("{\\darkyellow %s} ",key)
+ end
end
end
- NC() NR()
+ ctx_NC() ctx_NR()
end
- context.stoptabulate()
+ ctx_stoptabulate()
end
end
-function tracers.showdatasetcompleteness(dataset)
+function tracers.showdatasetcompleteness(settings)
+ local dataset = settings.dataset
+ local current = datasets[dataset]
+ local luadata = current.luadata
+ local specification = settings.specification
+ local fielddata = specification and specifications[specification] or specifications.apa
+ local categories = fielddata.categories
- dataset = datasets[dataset]
+ -- local lpegmatch = lpeg.match
+ -- local texescape = lpeg.patterns.texescape
- local preamble = { "|lBTw(10em)|p|" }
+ local preamble = { "|lTBw(5em)|lBTp(10em)|plT|" }
- local function required(key,value,indirect)
- NC() darkgreen(key)
- NC() if indirect then
- darkblue(value)
- elseif value then
- context(value)
+ local function identified(tag,category,crossref)
+ ctx_NC()
+ ctx_NC() ctx_monobold(category)
+ ctx_NC() if crossref then
+ ctx_monobold("%s\\hfill\\darkblue => %s",tag,crossref)
else
- darkred("\\tttf [missing]")
+ ctx_monobold(tag)
end
- NC() NR()
+ ctx_NC() ctx_NR()
end
- local function optional(key,value,indirect)
- NC() context(key)
- NC() if indirect then
- darkblue(value)
- elseif value then
- context(value)
- end
- NC() NR()
+ local function required(done,foundfields,key,value,indirect)
+ ctx_NC() if not done then ctx_monobold("required") end
+ ctx_NC() context(key)
+ ctx_NC()
+ if indirect then
+ if value then
+ context("\\darkblue")
+ ctx_verbatim(value)
+ else
+ context("\\darkred\\tttf [missing crossref]")
+ end
+ elseif value then
+ ctx_verbatim(value)
+ else
+ context("\\darkred\\tttf [missing value]")
+ end
+ ctx_NC() ctx_NR()
+ foundfields[key] = nil
+ return done or true
end
- local function identified(tag,crossref)
- NC() context("tag")
- NC() if crossref then
- context("\\tttf %s\\hfill\\darkblue => %s",tag,crossref)
- else
- context("\\tttf %s",tag)
- end
- NC() NR()
+ local function optional(done,foundfields,key,value,indirect)
+ ctx_NC() if not done then ctx_monobold("optional") end
+ ctx_NC() context(key)
+ ctx_NC()
+ if indirect then
+ context("\\darkblue")
+ ctx_verbatim(value)
+ elseif value then
+ ctx_verbatim(value)
+ end
+ ctx_NC() ctx_NR()
+ foundfields[key] = nil
+ return done or true
end
- local luadata = datasets[dataset].luadata
+ local function special(done,key,value)
+ ctx_NC() if not done then ctx_monobold("special") end
+ ctx_NC() context(key)
+ ctx_NC() ctx_verbatim(value)
+ ctx_NC() ctx_NR()
+ return done or true
+ end
+
+ local function extra(done,key,value)
+ ctx_NC() if not done then ctx_monobold("extra") end
+ ctx_NC() context(key)
+ ctx_NC() ctx_verbatim(value)
+ ctx_NC() ctx_NR()
+ return done or true
+ end
if next(luadata) then
- for tag, entry in table.sortedhash(luadata) do
- local category = entry.category
- local fields = categories[category]
+ for tag, entry in sortedhash(luadata) do
+ local category = entry.category
+ local fields = categories[category]
+ local foundfields = { }
+ for k, v in next, entry do
+ foundfields[k] = true
+ end
+ ctx_starttabulate(preamble)
+ identified(tag,category,entry.crossref)
+ ctx_FL()
if fields then
- context.starttabulate(preamble)
- identified(tag,entry.crossref)
- context.HL()
local requiredfields = fields.required
- local optionalfields = fields.optional
- for i=1,#requiredfields do
- local r = requiredfields[i]
- if type(r) == "table" then
- local okay = true
- for i=1,#r do
- local ri = r[i]
- if rawget(entry,ri) then
- required(ri,entry[ri])
- okay = true
- elseif entry[ri] then
- required(ri,entry[ri],true)
- okay = true
+ local sets = fields.sets or { }
+ local done = false
+ if requiredfields then
+ for i=1,#requiredfields do
+ local r = requiredfields[i]
+ local r = sets[r] or r
+ if type(r) == "table" then
+ local okay = false
+ for i=1,#r do
+ local ri = r[i]
+ if rawget(entry,ri) then
+ done = required(done,foundfields,ri,entry[ri])
+ okay = true
+ elseif entry[ri] then
+ done = required(done,foundfields,ri,entry[ri],true)
+ okay = true
+ end
end
+ if not okay then
+ done = required(done,foundfields,table.concat(r," {\\letterbar} "))
+ end
+ elseif rawget(entry,r) then
+ done = required(done,foundfields,r,entry[r])
+ elseif entry[r] then
+ done = required(done,foundfields,r,entry[r],true)
+ else
+ done = required(done,foundfields,r)
end
- if not okay then
- required(table.concat(r,"\\letterbar "))
- end
- elseif rawget(entry,r) then
- required(r,entry[r])
- elseif entry[r] then
- required(r,entry[r],true)
- else
- required(r)
end
end
- for i=1,#optionalfields do
- local o = optionalfields[i]
- if type(o) == "table" then
- for i=1,#o do
- local oi = o[i]
- if rawget(entry,oi) then
- optional(oi,entry[oi])
- elseif entry[oi] then
- optional(oi,entry[oi],true)
+ local optionalfields = fields.optional
+ local done = false
+ if optionalfields then
+ for i=1,#optionalfields do
+ local o = optionalfields[i]
+ local o = sets[o] or o
+ if type(o) == "table" then
+ for i=1,#o do
+ local oi = o[i]
+ if rawget(entry,oi) then
+ done = optional(done,foundfields,oi,entry[oi])
+ elseif entry[oi] then
+ done = optional(done,foundfields,oi,entry[oi],true)
+ end
end
+ elseif rawget(entry,o) then
+ done = optional(done,foundfields,o,entry[o])
+ elseif entry[o] then
+ done = optional(done,foundfields,o,entry[o],true)
end
- elseif rawget(entry,o) then
- optional(o,entry[o])
- elseif entry[o] then
- optional(o,entry[o],true)
end
end
- context.stoptabulate()
+ end
+ local done = false
+ for k, v in sortedhash(foundfields) do
+ if privates[k] then
+ -- skip
+ elseif specials[k] then
+ done = special(done,k,entry[k])
+ end
+ end
+ local done = false
+ for k, v in sortedhash(foundfields) do
+ if privates[k] then
+ -- skip
+ elseif not specials[k] then
+ done = extra(done,k,entry[k])
+ end
+ end
+ ctx_stoptabulate()
+ end
+ end
+
+end
+
+function tracers.showfields(settings)
+ local rotation = settings.rotation
+ local specification = settings.specification
+ local fielddata = specification and specifications[specification] or specifications.apa
+ local categories = fielddata.categories
+ local validfields = { }
+ for category, data in next, categories do
+ local sets = data.sets
+ local fields = data.fields
+ for name, list in next, fields do
+ validfields[name] = true
+ end
+ end
+ local s_categories = sortedkeys(categories)
+ local s_fields = sortedkeys(validfields)
+ ctx_starttabulate { "|l" .. string.rep("|c",#s_categories) .. "|" }
+ ctx_FL()
+ ctx_NC()
+ if rotation then
+ rotation = { rotation = rotation }
+ end
+ for i=1,#s_categories do
+ ctx_NC()
+ local txt = formatters["\\bf %s"](s_categories[i])
+ if rotation then
+ ctx_rotate(rotation,txt)
+ else
+ context(txt)
+ end
+ end
+ ctx_NC() ctx_NR()
+ ctx_FL()
+ for i=1,#s_fields do
+ local field = s_fields[i]
+ ctx_NC()
+ ctx_bold(field)
+ for j=1,#s_categories do
+ ctx_NC()
+ local kind = categories[s_categories[j]].fields[field]
+ if kind == "required" then
+ context("\\darkgreen*")
+ elseif kind == "optional" then
+ context("*")
+ end
+ end
+ ctx_NC() ctx_NR()
+ end
+ ctx_LL()
+ ctx_stoptabulate()
+end
+
+function tracers.showtables(settings)
+ for name, list in sortedhash(tables) do
+ ctx_starttabulate { "|Tl|Tl|" }
+ ctx_FL()
+ ctx_NC()
+ ctx_rlap(function() ctx_bold(name) end)
+ ctx_NC()
+ ctx_NC()
+ ctx_NR()
+ ctx_FL()
+ for k, v in sortedhash(list) do
+ ctx_NC()
+ context(k)
+ ctx_NC()
+ if type(v) == "table" then
+ context("% t",v)
else
- -- error
+ context(tostring(v))
+ end
+ ctx_NC()
+ ctx_NR()
+ end
+ ctx_LL()
+ ctx_stoptabulate()
+ end
+end
+
+function tracers.showdatasetauthors(settings)
+
+ local dataset = settings.dataset
+ local field = settings.field
+
+ local sortkey = publications.writers.author
+
+ if not dataset or dataset == "" then dataset = v_default end
+ if not field or field == "" then field = "author" end
+
+ local function row(i,k,v)
+ ctx_NC()
+ if i then
+ ctx_verbatim(i)
+ end
+ ctx_NC()
+ ctx_verbatim(k)
+ ctx_EQ()
+ if type(v) == "table" then
+ local t = { }
+ for i=1,#v do
+ local vi = v[i]
+ if type(vi) == "table" then
+ t[i] = concat(vi,"-")
+ else
+ t[i] = vi
+ end
+ end
+ ctx_verbatim(concat(t, " | "))
+ else
+ ctx_verbatim(v)
+ end
+ ctx_NC()
+ ctx_NR()
+ end
+
+ local function authorrow(ai,k,i)
+ local v = ai[k]
+ if v then
+ row(i,k,v)
+ end
+ end
+
+ local function commonrow(key,value)
+ ctx_NC() ctx_rlap(function() ctx_verbatim(key) end)
+ ctx_NC()
+ ctx_EQ() ctx_verbatim(value)
+ ctx_NC() ctx_NR()
+ end
+
+ local d = datasets[dataset].luadata
+
+ local trialtypesetting = context.trialtypesetting()
+
+ for tag, entry in sortedhash(d) do
+
+ local a, f, k = getcasted(dataset,tag,field)
+
+ if type(a) == "table" and #a > 0 and k == "author" then
+ context.start()
+ context.tt()
+ ctx_starttabulate { "|B|Bl|p|" }
+ ctx_FL()
+ local original = getfield(dataset,tag,field)
+ commonrow("tag",tag)
+ commonrow("field",field)
+ commonrow("original",original)
+ commonrow("sortkey",sortkey(a))
+ for i=1,#a do
+ ctx_ML()
+ local ai = a[i]
+ if ai then
+ authorrow(ai,"original",i)
+ authorrow(ai,"snippets")
+ authorrow(ai,"initials")
+ authorrow(ai,"firstnames")
+ authorrow(ai,"vons")
+ authorrow(ai,"surnames")
+ authorrow(ai,"juniors")
+ local options = ai.options
+ if options then
+ row(false,"options",sortedkeys(options))
+ end
+ elseif not trialtypesetting then
+ report("bad author name: %s",original or "?")
+ end
+ end
+ ctx_LL()
+ ctx_stoptabulate()
+ context.stop()
+ end
+
+ end
+
+end
+
+function tracers.showentry(dataset,tag)
+ local dataset = datasets[dataset]
+ if dataset then
+ local entry = dataset.luadata[tag]
+ local done = false
+ for k, v in sortedhash(entry) do
+ if not privates[k] then
+ ctx_verbatim("%w[%s: %s]",done and 1 or 0,k,v)
+ done = true
end
end
end
+end
+
+local skipped = { index = true, default = true }
+function tracers.showvariants(dataset,pages)
+ local variants = sortedkeys(citevariants)
+ for tag in publications.sortedentries(dataset or v_default) do
+ if pages then
+ ctx_page()
+ end
+ ctx_starttabulate { "|T||" }
+ for i=1,#variants do
+ local variant = variants[i]
+ if not skipped[variant] then
+ ctx_NC() context(variant)
+ -- ctx_EQ() citevariants[variant] { dataset = v_default, reference = tag, variant = variant }
+ ctx_EQ() context.cite({variant},{dataset .. "::" .. tag})
+ ctx_NC() ctx_NR()
+ end
+ end
+ ctx_stoptabulate()
+ if pages then
+ ctx_page()
+ end
+ end
end
commands.showbtxdatasetfields = tracers.showdatasetfields
commands.showbtxdatasetcompleteness = tracers.showdatasetcompleteness
+commands.showbtxfields = tracers.showfields
+commands.showbtxtables = tracers.showtables
+commands.showbtxdatasetauthors = tracers.showdatasetauthors
+commands.showbtxentry = tracers.showentry
+commands.showbtxvariants = tracers.showvariants
diff --git a/Master/texmf-dist/tex/context/base/publ-tra.mkiv b/Master/texmf-dist/tex/context/base/publ-tra.mkiv
index 49fb6d96275..41550519851 100644
--- a/Master/texmf-dist/tex/context/base/publ-tra.mkiv
+++ b/Master/texmf-dist/tex/context/base/publ-tra.mkiv
@@ -20,16 +20,68 @@
\unprotect
-\unexpanded\def\showbtxdatasetfields
- {\dosingleempty\publ_dataset_show_fields}
+\unexpanded\def\showbtxdatasetfields {\dosingleempty\publ_show_dataset_fields}
+\unexpanded\def\showbtxdatasetcompleteness{\dosingleempty\publ_show_dataset_completeness}
+\unexpanded\def\showbtxdatasetauthors {\dosingleempty\publ_show_dataset_authors}
+\unexpanded\def\showbtxfields {\dosingleempty\publ_show_fields}
+\unexpanded\def\showbtxtables {\dosingleempty\publ_show_tables}
-\def\publ_dataset_show_fields[#1]%
- {\ctxcommand{showbtxdatasetfields("\iffirstargument#1\else\currentbtxdataset\fi")}}
+\def\publ_show_dataset_whatever#1[#2]%
+ {\begingroup
+ \letdummyparameter\c!specification\currentbtxspecification
+ \setdummyparameter\c!dataset {\currentbtxdataset}%
+ \letdummyparameter\c!field \empty
+ \iffirstargument
+ \doifelseassignment{#2}
+ {\getdummyparameters[#2]}%
+ {\setdummyparameter\c!dataset{#2}}%
+ \else
+ \getdummyparameters[#2]%
+ \fi
+ % \publ_specification_push{"\dummyparameter\c!specification}%
+ \ctxcommand{#1{
+ dataset = "\dummyparameter\c!dataset",
+ specification = "\dummyparameter\c!specification",
+ field = "\dummyparameter\c!field",
+ }}%
+ % \publ_specification_pop
+ \endgroup}
-\unexpanded\def\showbtxdatasetcompleteness
- {\dosingleempty\publ_dataset_show_completeness}
+\def\publ_show_dataset_fields {\publ_show_dataset_whatever{showbtxdatasetfields}}
+\def\publ_show_dataset_completeness{\publ_show_dataset_whatever{showbtxdatasetcompleteness}}
+\def\publ_show_dataset_authors {\publ_show_dataset_whatever{showbtxdatasetauthors}}
-\def\publ_dataset_show_completeness[#1]%
- {\ctxcommand{showbtxdatasetcompleteness("\iffirstargument#1\else\currentbtxdataset\fi")}}
+\def\publ_show_fields[#1]%
+ {\begingroup
+ \setdummyparameter\c!rotation{90}%
+ \doifelseassignment{#1}%
+ {\letdummyparameter\c!specification\currentbtxspecification
+ \getdummyparameters[#1]}%
+ {\doifelsenothing{#1}%
+ {\letdummyparameter\c!specification\currentbtxspecification}%
+ {\setdummyparameter\c!specification{#1}}}%
+ % \publ_specification_push{"\dummyparameter\c!specification}%
+ \ctxcommand{showbtxfields{
+ rotation = "\dummyparameter\c!rotation",
+ specification = "\dummyparameter\c!specification"
+ }}%
+ % \publ_specification_pop
+ \endgroup}
-\protect \endinput
+\def\publ_show_tables[#1]%
+ {\begingroup
+ \ctxcommand{showbtxtables{}}%
+ \endgroup}
+
+\protect
+
+\continueifinputfile{publ-tra.mkiv}
+
+\starttext
+
+ \showbtxfields[rotation=85] \page
+ \showbtxfields[rotation=90] \page
+
+ \showbtxtables \page
+
+\stoptext
diff --git a/Master/texmf-dist/tex/context/base/publ-usr.lua b/Master/texmf-dist/tex/context/base/publ-usr.lua
index 6bb93ebeef5..f0111227916 100644
--- a/Master/texmf-dist/tex/context/base/publ-usr.lua
+++ b/Master/texmf-dist/tex/context/base/publ-usr.lua
@@ -6,7 +6,15 @@ if not modules then modules = { } end modules ['publ-usr'] = {
license = "see context related readme files"
}
--- local chardata = characters.data
+local P, Cs, R, Cc, C, Carg = lpeg.P, lpeg.Cs, lpeg.R, lpeg.Cc, lpeg.C, lpeg.Carg
+local lpegmatch = lpeg.match
+local settings_to_hash = utilities.parsers.settings_to_hash
+
+local publications = publications
+local datasets = publications.datasets
+
+local report = logs.reporter("publications")
+local trace = false trackers.register("publications",function(v) trace = v end)
-- local str = [[
-- \startpublication[k=Berdnikov:TB21-2-129,t=article,a={{Berdnikov},{}},y=2000,n=2257,s=BHHJ00]
@@ -25,67 +33,94 @@ if not modules then modules = { } end modules ['publ-usr'] = {
-- \stoppublication
-- ]]
-local remapped = {
- artauthor = "author",
- arttitle = "title",
+local lists = {
+ author = true,
+ editor = true,
+ -- artauthor = true,
+ -- arteditor = true,
}
-local P, Cs, R, Cc, Carg = lpeg.P, lpeg.Cs, lpeg.R, lpeg.Cc, lpeg.Carg
-
-local function register(target,key,a,b,c,d,e)
- key = remapped[key] or key
- if b and d and e then
- local s = nil
- if b ~= "" and b then
- s = s and s .. " " .. b or b
- end
- if d ~= "" and d then
- s = s and s .. " " .. d or d
- end
- if e ~= "" and e then
- s = s and s .. " " .. e or e
- end
- if a ~= "" and a then
- s = s and s .. " " .. a or a
- end
- local value = target[key]
- if s then
- if value then
- target[key] = value .. " and " .. s
- else
- target[key] = s
- end
- else
- if not value then
- target[key] = s
- end
- end
- else
- target[key] = b
- end
+local function registervalue(target,key,value)
+ target[key] = value
+end
+
+-- Instead of being generic we just hardcode the old stuff:
+
+local function registerauthor(target,key,juniors,firstnames,initials,vons,surnames)
+ local value = target[key]
+ target[key]= ((value and value .. " and {") or "{") ..
+ vons .. "},{" ..
+ surnames .. "},{" ..
+ juniors .. "},{" ..
+ firstnames .. "},{" ..
+ initials .. "}"
end
local leftbrace = P("{")
local rightbrace = P("}")
local leftbracket = P("[")
local rightbracket = P("]")
+local backslash = P("\\")
+local letter = R("az","AZ")
+
+local skipspaces = lpeg.patterns.whitespace^0
+local key = Cs(letter^1)
+local value = leftbrace * Cs(lpeg.patterns.balanced) * rightbrace
+local optional = leftbracket * Cs((1-rightbracket)^0) * rightbracket
+
+local authorkey = (P("artauthor") + P("author")) / "author"
+ + (P("arteditor") + P("editor")) / "editor"
+local authorvalue = (optional + Cc("{}")) * skipspaces -- [juniors]
+ * (value + Cc("{}")) * skipspaces -- {firstnames}
+ * (optional + Cc("{}")) * skipspaces -- [initials]
+ * (value + Cc("{}")) * skipspaces -- {vons}
+ * (value + Cc("{}")) * skipspaces -- {surnames}
-local key = P("\\") * Cs(R("az","AZ")^1) * lpeg.patterns.space^0
-local mandate = leftbrace * Cs(lpeg.patterns.balanced) * rightbrace + Cc(false)
-local optional = leftbracket * Cs((1-rightbracket)^0) * rightbracket + Cc(false)
-local value = optional^-1 * mandate^-1 * optional^-1 * mandate^-2
+local keyvalue = Carg(1) * authorkey * skipspaces * authorvalue / registerauthor
+ + Carg(1) * key * skipspaces * value / registervalue
-local pattern = ((Carg(1) * key * value) / register + P(1))^0
+local pattern = (backslash * keyvalue + P(1))^0
-function publications.addtexentry(dataset,settings,content)
- settings = utilities.parsers.settings_to_hash(settings)
+local function addtexentry(dataset,settings,content)
+ local current = datasets[dataset]
+ local settings = settings_to_hash(settings)
local data = {
tag = settings.tag or settings.k or "no tag",
category = settings.category or settings.t or "article",
}
- lpeg.match(pattern,content,1,data) -- can set tag too
- dataset.userdata[data.tag] = data
- dataset.luadata[data.tag] = data
- publications.markasupdated(dataset)
+ lpegmatch(pattern,content,1,data) -- can set tag too
+ local tag = data.tag
+ current.userdata[tag] = data
+ current.luadata[tag] = data
+ current.details[tag] = nil
return data
end
+
+local pattern = ( Carg(1)
+ * P("\\startpublication")
+ * skipspaces
+ * optional
+ * C((1 - P("\\stoppublication"))^1)
+ * P("\\stoppublication") / addtexentry
+ + P("%") * (1-lpeg.patterns.newline)^0
+ + P(1)
+)^0
+
+function publications.loaders.bbl(dataset,filename)
+ local dataset, fullname = publications.resolvedname(dataset,filename)
+ if not fullname then
+ return
+ end
+ local data = io.loaddata(filename) or ""
+ if data == "" then
+ report("empty file %a, nothing loaded",fullname)
+ return
+ end
+ if trace then
+ report("loading file %a",fullname)
+ end
+ lpegmatch(pattern,data,1,dataset)
+end
+
+publications.addtexentry = addtexentry
+commands.addbtxentry = addtexentry
diff --git a/Master/texmf-dist/tex/context/base/publ-xml.mkiv b/Master/texmf-dist/tex/context/base/publ-xml.mkiv
index 007f9bb27d2..96375b9cc61 100644
--- a/Master/texmf-dist/tex/context/base/publ-xml.mkiv
+++ b/Master/texmf-dist/tex/context/base/publ-xml.mkiv
@@ -19,7 +19,7 @@
{\dosingleempty\publ_convert_to_xml}
\def\publ_convert_to_xml[#1]%
- {\ctxcommand{convertbtxdatasettoxml("\iffirstargument#1\else\v!standard\fi",true)}} % or current when not empty
+ {\clf_convertbtxdatasettoxml{\iffirstargument#1\else\s!default\fi}} % or current when not empty
% \startxmlsetups btx:initialize
% \xmlregistereddocumentsetups{#1}{}
diff --git a/Master/texmf-dist/tex/context/base/regi-ini.lua b/Master/texmf-dist/tex/context/base/regi-ini.lua
index d5d278b1649..37a88fd5f96 100644
--- a/Master/texmf-dist/tex/context/base/regi-ini.lua
+++ b/Master/texmf-dist/tex/context/base/regi-ini.lua
@@ -15,7 +15,7 @@ runtime.
local commands, context = commands, context
local utfchar = utf.char
-local P, Cs, lpegmatch = lpeg.P, lpeg.Cs, lpeg.match
+local P, Cs, Cc, lpegmatch = lpeg.P, lpeg.Cs, lpeg.Cc, lpeg.match
local char, gsub, format, gmatch, byte, match = string.char, string.gsub, string.format, string.gmatch, string.byte, string.match
local next = next
local insert, remove, fastcopy = table.insert, table.remove, table.fastcopy
@@ -27,6 +27,9 @@ local sequencers = utilities.sequencers
local textlineactions = resolvers.openers.helpers.textlineactions
local setmetatableindex = table.setmetatableindex
+local implement = interfaces.implement
+local setmacro = interfaces.setmacro
+
--[[ldx--
We will hook regime handling code into the input methods.
--ldx]]--
@@ -99,6 +102,8 @@ local synonyms = { -- backward compatibility list
["windows"] = "cp1252",
+ ["pdf"] = "pdfdoc",
+
}
local currentregime = "utf"
@@ -132,7 +137,7 @@ end
setmetatableindex(mapping, loadregime)
setmetatableindex(backmapping,loadreverse)
-local function translate(line,regime)
+local function fromregime(regime,line)
if line and #line > 0 then
local map = mapping[regime and synonyms[regime] or regime or currentregime]
if map then
@@ -178,12 +183,15 @@ local function toregime(vector,str,default) -- toregime('8859-1',"abcde Ä","?")
local r = c[d]
if not r then
local t = fastcopy(backmapping[vector])
- setmetatableindex(t, function(t,k)
- local v = d
- t[k] = v
- return v
- end)
- r = utf.remapper(t)
+ -- r = utf.remapper(t) -- not good for defaults here
+ local pattern = Cs((lpeg.utfchartabletopattern(t)/t + lpeg.patterns.utf8character/d + P(1)/d)^0)
+ r = function(str)
+ if not str or str == "" then
+ return ""
+ else
+ return lpegmatch(pattern,str)
+ end
+ end
c[d] = r
end
return r(str)
@@ -192,6 +200,7 @@ end
local function disable()
currentregime = "utf"
sequencers.disableaction(textlineactions,"regimes.process")
+ return currentregime
end
local function enable(regime)
@@ -202,12 +211,14 @@ local function enable(regime)
currentregime = regime
sequencers.enableaction(textlineactions,"regimes.process")
end
+ return currentregime
end
-regimes.toregime = toregime
-regimes.translate = translate
-regimes.enable = enable
-regimes.disable = disable
+regimes.toregime = toregime
+regimes.fromregime = fromregime
+regimes.translate = function(str,regime) return fromregime(regime,str) end
+regimes.enable = enable
+regimes.disable = disable
-- The following function can be used when we want to make sure that
-- utf gets passed unharmed. This is needed for modules.
@@ -216,7 +227,7 @@ local level = 0
function regimes.process(str,filename,currentline,noflines,coding)
if level == 0 and coding ~= "utf-8" then
- str = translate(str,currentregime)
+ str = fromregime(currentregime,str)
if trace_translating then
report_translating("utf: %s",str)
end
@@ -243,40 +254,62 @@ end
regimes.push = push
regimes.pop = pop
-sequencers.prependaction(textlineactions,"system","regimes.process")
-sequencers.disableaction(textlineactions,"regimes.process")
+if sequencers then
+
+ sequencers.prependaction(textlineactions,"system","regimes.process")
+ sequencers.disableaction(textlineactions,"regimes.process")
+
+end
-- interface:
-commands.enableregime = enable
-commands.disableregime = disable
+implement {
+ name = "enableregime",
+ arguments = "string",
+ actions = function(regime) setmacro("currentregime",enable(regime)) end
+}
-commands.pushregime = push
-commands.popregime = pop
+implement {
+ name = "disableregime",
+ actions = function() setmacro("currentregime",disable()) end
+}
-function commands.currentregime()
- context(currentregime)
-end
+implement {
+ name = "pushregime",
+ actions = push
+}
+
+implement {
+ name = "popregime",
+ actions = pop
+}
local stack = { }
-function commands.startregime(regime)
- insert(stack,currentregime)
- if trace_translating then
- report_translating("start using %a",regime)
+implement {
+ name = "startregime",
+ arguments = "string",
+ actions = function(regime)
+ insert(stack,currentregime)
+ if trace_translating then
+ report_translating("start using %a",regime)
+ end
+ setmacro("currentregime",enable(regime))
end
- enable(regime)
-end
+}
-function commands.stopregime()
- if #stack > 0 then
- local regime = remove(stack)
- if trace_translating then
- report_translating("stop using %a",regime)
+implement {
+ name = "stopregime",
+ actions = function()
+ if #stack > 0 then
+ local regime = remove(stack)
+ if trace_translating then
+ report_translating("stop using %a",regime)
+ end
+ setmacro("currentregime",enable(regime))
end
- enable(regime)
end
-end
+}
-- Next we provide some hacks. Unfortunately we run into crappy encoded
-- (read : mixed) encoded xml files that have these ë ä ö ü sequences
@@ -311,48 +344,82 @@ local patterns = { }
--
-- twice as fast and much less lpeg bytecode
+-- function regimes.cleanup(regime,str)
+-- if not str or str == "" then
+-- return str
+-- end
+-- local p = patterns[regime]
+-- if p == nil then
+-- regime = regime and synonyms[regime] or regime or currentregime
+-- local vector = regime ~= "utf" and regime ~= "utf-8" and mapping[regime]
+-- if vector then
+-- local utfchars = { }
+-- local firsts = { }
+-- for k, uchar in next, vector do
+-- local stream = { }
+-- local split = totable(uchar)
+-- local nofsplits = #split
+-- if nofsplits > 1 then
+-- local first
+-- for i=1,nofsplits do
+-- local u = vector[split[i]]
+-- if not first then
+-- first = firsts[u]
+-- if not first then
+-- first = { }
+-- firsts[u] = first
+-- end
+-- end
+-- stream[i] = u
+-- end
+-- local nofstream = #stream
+-- if nofstream > 1 then
+-- first[#first+1] = concat(stream,2,nofstream)
+-- utfchars[concat(stream)] = uchar
+-- end
+-- end
+-- end
+-- p = P(false)
+-- for k, v in next, firsts do
+-- local q = P(false)
+-- for i=1,#v do
+-- q = q + P(v[i])
+-- end
+-- p = p + P(k) * q
+-- end
+-- p = Cs(((p+1)/utfchars)^1)
+-- -- lpeg.print(p) -- size: 1042
+-- else
+-- p = false
+-- end
+-- patterns[regime] = p
+-- end
+-- return p and lpegmatch(p,str) or str
+-- end
+--
+-- 5 times faster:
+
function regimes.cleanup(regime,str)
+ if not str or str == "" then
+ return str
+ end
local p = patterns[regime]
if p == nil then
regime = regime and synonyms[regime] or regime or currentregime
- local vector = regime ~= "utf" and mapping[regime]
+ local vector = regime ~= "utf" and regime ~= "utf-8" and mapping[regime]
if vector then
- local utfchars = { }
- local firsts = { }
- for k, uchar in next, vector do
- local stream = { }
- local split = totable(uchar)
- local nofsplits = #split
- if nofsplits > 1 then
- local first
- for i=1,nofsplits do
- local u = vector[split[i]]
- if not first then
- first = firsts[u]
- if not first then
- first = { }
- firsts[u] = first
- end
- end
- stream[i] = u
- end
- local nofstream = #stream
- if nofstream > 1 then
- first[#first+1] = concat(stream,2,nofstream)
- utfchars[concat(stream)] = uchar
- end
+ local mapping = { }
+ for k, v in next, vector do
+ local split = totable(v)
+ for i=1,#split do
+ split[i] = utfchar(byte(split[i]))
end
- end
- p = P(false)
- for k, v in next, firsts do
- local q = P(false)
- for i=1,#v do
- q = q + P(v[i])
+ split = concat(split)
+ if v ~= split then
+ mapping[split] = v
end
- p = p + P(k) * q
end
- p = Cs(((p+1)/utfchars)^1)
- -- lpeg.print(p) -- size: 1042
+ p = Cs((lpeg.utfchartabletopattern(mapping)/mapping+P(1))^0)
else
p = false
end
@@ -361,28 +428,9 @@ function regimes.cleanup(regime,str)
return p and lpegmatch(p,str) or str
end
--- local map = require("regi-cp1252")
-- local old = [[test ë ä ö ü crap]]
--- local new = correctencoding(map,old)
---
--- print(old,new)
-
--- obsolete:
---
--- function regimes.setsynonym(synonym,target)
--- synonyms[synonym] = target
--- end
---
--- function regimes.truename(regime)
--- return regime and synonyms[regime] or regime or currentregime
--- end
---
--- commands.setregimesynonym = regimes.setsynonym
---
--- function commands.trueregimename(regime)
--- context(regimes.truename(regime))
--- end
---
--- function regimes.load(regime)
--- return mapping[synonyms[regime] or regime]
--- end
+-- local new = regimes.cleanup("cp1252",old)
+-- report_translating("%s -> %s",old,new)
+-- local old = "Pozn" .. char(0xE1) .. "mky"
+-- local new = fromregime("cp1250",old)
+-- report_translating("%s -> %s",old,new)
diff --git a/Master/texmf-dist/tex/context/base/regi-ini.mkiv b/Master/texmf-dist/tex/context/base/regi-ini.mkiv
index 651e2f13cb1..6190393d804 100644
--- a/Master/texmf-dist/tex/context/base/regi-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/regi-ini.mkiv
@@ -16,34 +16,18 @@
\unprotect
%D \macros
-%D {enableregime,disableregime,currentregime}
+%D {enableregime,disableregime,
+%D startregime,stopregime,
+%D currentregime}
%D
%D Beware, the enable and disable commands are global switches, so
%D best use the start|/|stop commands.
-\unexpanded\def\enableregime[#1]{\ctxcommand{enableregime("#1")}}
-\unexpanded\def\disableregime {\ctxcommand{disableregime()}}
-\unexpanded\def\startregime [#1]{\ctxcommand{startregime("#1")}}
-\unexpanded\def\stopregime {\ctxcommand{stopregime()}}
- \def\currentregime {\ctxcommand{currentregime()}}
+\let\currentregime\empty
-% D \macros
-% D {defineregimesynonym,trueregimename}
-%
-% \unexpanded\def\defineregimesynonym % more or less obsolete
-% {\dodoubleargument\dodefineregimesynonym}
-%
-% \def\dodefineregimesynonym[#1][#2]%
-% {\ctxcommand{setregimesynonym("#1","#2")}}
-%
-% \def\trueregimename#1%
-% {\ctxcommand{trueregimename("#1")}}
-
-% D \macros
-% D {useregime}
-% D
-% D This one is sort of obsolete but we keep them around.
-
-\unexpanded\def\useregime[#1]{}
+\unexpanded\def\enableregime[#1]{\clf_enableregime{#1}}
+\unexpanded\def\disableregime {\clf_disableregime}
+\unexpanded\def\startregime [#1]{\clf_startregime{#1}}
+\unexpanded\def\stopregime {\clf_stopregime}
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/regi-pdfdoc.lua b/Master/texmf-dist/tex/context/base/regi-pdfdoc.lua
new file mode 100644
index 00000000000..363d3ae0da3
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/regi-pdfdoc.lua
@@ -0,0 +1,26 @@
+if not modules then modules = { } end modules ['regi-pdfdoc'] = {
+ version = 1.001,
+ comment = "companion to regi-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+return { [0] =
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x02D8, 0x02C7, 0x02C6, 0x02D9, 0x02DD, 0x02DB, 0x02DA, 0x02DC, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C, 0x201D, 0x2018,
+ 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x0141, 0x0152, 0x0160, 0x0178, 0x017D, 0x0131, 0x0142, 0x0153, 0x0161, 0x017E, 0x009F,
+ 0x20AC, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0xFFFD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+}
diff --git a/Master/texmf-dist/tex/context/base/s-abr-01.tex b/Master/texmf-dist/tex/context/base/s-abr-01.tex
index 733eebf7b95..00a1a5c1e2f 100644
--- a/Master/texmf-dist/tex/context/base/s-abr-01.tex
+++ b/Master/texmf-dist/tex/context/base/s-abr-01.tex
@@ -46,6 +46,7 @@
\logo [ARABTEX] {Arab\TeX}
\logo [ASCII] {ascii}
\logo [ASCIITEX] {ascii\TeX}
+\logo [ASCIIMATH] {AsciiMath}
\logo [BACHOTEX] {Bacho\TeX}
\logo [BIBTEX] {bib\TeX}
\logo [MLBIBTEX] {MLbib\TeX}
@@ -66,6 +67,8 @@
\logo [CMYK] {cmyk}
\logo [CODHOST] {CodHost}
\logo [CONTEXT] {\ConTeXt}
+\logo [CONTEXTWIKI] {\ConTeXt\ Wiki}
+\logo [CONTEXTGROUP] {\ConTeXt\ Group}
\logo [CSS] {css}
\logo [CTAN] {ctan}
\logo [CTXTOOLS] {ctxtools}
@@ -94,6 +97,7 @@
\logo [EMTEX] {em\TeX}
\logo [ENCODING] {enc}
\logo [ENCTEX] {enc\TeX}
+\logo [EPUB] {ePub}
\logo [EPS] {eps}
\logo [ETEX] {\eTeX}
\logo [EUROBACHOTEX] {EuroBacho\TeX}
@@ -235,6 +239,7 @@
\logo [SSD] {ssd}
\logo [SVG] {svg}
\logo [STIX] {Stix}
+\logo [SUMATRAPDF] {SumatraPDF}
\logo [SWIG] {swig}
\logo [SWIGLIB] {SwigLib}
\logo [TABLE] {\TaBlE}
@@ -262,6 +267,7 @@
\logo [TEXTOOLS] {\TeX tools}
\logo [TEXUTIL] {\TeX util}
\logo [TEXWORK] {\TeX work}
+\logo [TEXWORKS] {\TeX works}
\logo [TEXXET] {\TeX\XeT} \def\XeT{XeT}
\logo [TFM] {tfm}
\logo [TIF] {tif}
diff --git a/Master/texmf-dist/tex/context/base/s-art-01.mkiv b/Master/texmf-dist/tex/context/base/s-art-01.mkiv
index e2584a35784..601ee1adc80 100644
--- a/Master/texmf-dist/tex/context/base/s-art-01.mkiv
+++ b/Master/texmf-dist/tex/context/base/s-art-01.mkiv
@@ -2,7 +2,7 @@
\startmodule[art-01]
-\definemeasure [article:margin] [\paperheight/15]
+\definemeasure [article:margin] [\paperheight/20] % was 15, see xtables-mkiv for results
\definemeasure [overview:margin] [\paperheight/30]
\definelayout
@@ -10,7 +10,7 @@
[\c!topspace=\measure{article:margin},
\c!bottomspace=\measure{article:margin},
\c!backspace=\measure{article:margin},
- \c!header=\measure{overview:margin},
+ \c!header=\measure{article:margin},
\c!footer=0pt,
\c!width=\v!middle,
\c!height=\v!middle]
diff --git a/Master/texmf-dist/tex/context/base/s-figures-names.mkiv b/Master/texmf-dist/tex/context/base/s-figures-names.mkiv
new file mode 100644
index 00000000000..a2782efc95d
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/s-figures-names.mkiv
@@ -0,0 +1,99 @@
+%D \module
+%D [ file=s-figures-names.mkiv,
+%D version=2017.07.17,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Show Figure Names,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Normally this module will be run someplace at the end of a document in some kind of tracing
+%D mode. We could hook it into \type {\stoptext} but better leave it up to the user. Loading
+%D this module upfront will not show anything useful. The main reason for making this module
+%D was that we wanted to report weird figurenames: spaces, multiple hyphens in a row, mixed
+%D hyphens and underscores, inconsistently mixed upper and lowercase, etc.
+%D
+%D If you only want info in the logfile, you can use:
+%D
+%D \starttyping
+%D \enabletrackers[graphics.lognames]
+%D \stoptyping
+%D
+%D This directive is persistent and can be issued any time before the end of the run.
+
+\startmodule[figures-names]
+
+\startluacode
+
+local context = context
+local ctx_NC = context.NC
+local ctx_NR = context.NR
+local ctx_red = context.red
+local ctx_starttabulate = context.starttabulate
+local ctx_stoptabulate = context.stoptabulate
+local ctx_hyphenatedname = context.hyphenatedfilename
+
+trackers.enable("graphics.lognames")
+
+context.start()
+
+ context.switchtobodyfont { "tt,small" }
+
+ local template = { "|Bl|p|" }
+
+ for _, data in table.sortedhash(figures.found) do
+ ctx_starttabulate(template)
+ local badname = data.badname
+ local found = data.found
+ ctx_NC()
+ context("asked name")
+ ctx_NC()
+ if badname then
+ ctx_red()
+ end
+ context(data.askedname)
+ ctx_NC() ctx_NR()
+ if found then
+ ctx_NC()
+ context("format")
+ ctx_NC()
+ context(data.format)
+ ctx_NC() ctx_NR()
+ ctx_NC()
+ context("found file")
+ ctx_NC()
+ ctx_hyphenatedname(data.foundname)
+ -- context(data.foundname)
+ ctx_NC() ctx_NR()
+ ctx_NC()
+ context("used file")
+ ctx_NC()
+ ctx_hyphenatedname(data.fullname)
+ -- context(data.fullname)
+ ctx_NC() ctx_NR()
+ if badname then
+ ctx_NC()
+ context("comment")
+ ctx_NC()
+ context("bad name")
+ ctx_NC() ctx_NR()
+ end
+ else
+ ctx_NC()
+ context("comment")
+ ctx_NC()
+ context(data.comment or "not found")
+ ctx_NC() ctx_NR()
+ end
+ ctx_stoptabulate()
+ end
+
+context.stop()
+
+\stopluacode
+
+\stopmodule
diff --git a/Master/texmf-dist/tex/context/base/s-fnt-10.mkiv b/Master/texmf-dist/tex/context/base/s-fnt-10.mkiv
index 9b6211c2b57..2fe82e0794b 100644
--- a/Master/texmf-dist/tex/context/base/s-fnt-10.mkiv
+++ b/Master/texmf-dist/tex/context/base/s-fnt-10.mkiv
@@ -100,7 +100,7 @@ function fonts.tracers.show_glyphs()
end
\stopluacode
-\def\ShowCompleteFont#1#2#3%
+\unexpanded\def\ShowCompleteFont#1#2#3%
{\bgroup
\page
\font\TestFont=#1 at #2
@@ -118,7 +118,7 @@ end
\page
\egroup}
-\def\ShowAllGlyphs#1#2#3%
+\unexpanded\def\ShowAllGlyphs#1#2#3%
{\bgroup
\page
\def\showglyph##1{\dontleavehmode\strut\char##1\relax\par}
diff --git a/Master/texmf-dist/tex/context/base/s-fnt-21.mkiv b/Master/texmf-dist/tex/context/base/s-fnt-21.mkiv
index 588c9801676..10d5a462394 100644
--- a/Master/texmf-dist/tex/context/base/s-fnt-21.mkiv
+++ b/Master/texmf-dist/tex/context/base/s-fnt-21.mkiv
@@ -47,7 +47,7 @@
\endinput
-% \usemodule[fnt-20]
+% \usemodule[fnt-21]
%
% \starttext
%
diff --git a/Master/texmf-dist/tex/context/base/s-fonts-coverage.lua b/Master/texmf-dist/tex/context/base/s-fonts-coverage.lua
index db47e57c43f..dd772d5f09b 100644
--- a/Master/texmf-dist/tex/context/base/s-fonts-coverage.lua
+++ b/Master/texmf-dist/tex/context/base/s-fonts-coverage.lua
@@ -29,6 +29,7 @@ function moduledata.fonts.coverage.showcomparison(specification)
local present = { }
local names = { }
local files = { }
+ local chars = { }
if not pattern then
-- skip
@@ -56,6 +57,7 @@ function moduledata.fonts.coverage.showcomparison(specification)
end
names[#names+1] = fontname
files[#files+1] = fontfile
+ chars[#names] = fontdata.characters
end
end
@@ -91,7 +93,11 @@ function moduledata.fonts.coverage.showcomparison(specification)
NR()
HL()
for k, v in table.sortedpairs(present) do
- if k > 0 then
+ if k <= 0 then
+ -- ignore
+ elseif k >= 0x110000 then
+ logs.report("warning","weird character %U",k)
+ else
local description = chardata[k].description
if not pattern or (pattern == k) or (description and lpegmatch(pattern,description)) then
NC()
@@ -99,7 +105,11 @@ function moduledata.fonts.coverage.showcomparison(specification)
NC()
for i=1,#names do
getvalue(names[i])
- char(k)
+ if chars[i][k] then
+ char(k)
+ else
+ -- missing
+ end
NC()
end
context(description)
diff --git a/Master/texmf-dist/tex/context/base/s-fonts-ligatures.mkiv b/Master/texmf-dist/tex/context/base/s-fonts-ligatures.mkiv
new file mode 100644
index 00000000000..e6ff2461e8c
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/s-fonts-ligatures.mkiv
@@ -0,0 +1,292 @@
+%D \module
+%D [ file=s-fonts-ligatures,
+%D version=2014.12.14,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Show Fonts Ligatures,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% begin info
+%
+% title : show some ligature building in fonts
+%
+% comment : we trace some ligatures that have rather different implementations in fontss
+% status : experimental, used for luatex testing
+%
+% end info
+
+\definefontfeature
+ [otfligaturetest]
+ [analyze=off,
+ ccmp=yes, % brill uses that .. not really ligatures !
+ %clig=yes,
+ script=latn,
+ language=dflt]
+
+\hyphenation{xf-fi-a}
+\hyphenation{xff-i-b}
+\hyphenation{xffi-c}
+\hyphenation{xffid}
+
+\registerhyphenationexception[xf-fi-a]
+\registerhyphenationexception[xff-i-b]
+\registerhyphenationexception[xffi-c]
+\registerhyphenationexception[xffid]
+
+\starttexdefinition showotfligaturescaption #1
+ \bTD [align={flushleft,lohi},nx=3]
+ \nohyphens
+ \ttbf
+ #1
+ \eTD
+\stoptexdefinition
+
+\starttexdefinition showotfligatureslegend #1
+ \bTD [width=6em,align={flushleft,lohi}]
+ \nohyphens \ttxx original
+ \eTD
+ \bTD [width=6em,align={flushleft,lohi}]
+ \nohyphens \ttxx expanded
+ \eTD
+ \bTD [width=6em,align={flushleft,lohi}]
+ \nohyphens \ttxx traditional
+ \eTD
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesline #1#2
+ \bTD[toffset=.5ex,frame=off]
+ \starthyphenation[#1]
+ \LigatureFont
+ \showfontkerns
+ \showdiscretionaries
+ \begstrut#2\endstrut
+ \par
+ \stophyphenation
+ \eTD
+\stoptexdefinition
+
+\def\showotfligaturescells{3}
+%def\showotfligaturesnx {12}
+%def\showotfligatureswidth{18em}
+\def\showotfligaturesnx {\the\numexpr 4*\showotfligaturescells}
+\def\showotfligatureswidth{\the\dimexpr6em*\showotfligaturescells}
+
+\starttexdefinition showotfligaturesbanner #1
+ \bTR[frame=off]
+ \bTD [nx=\showotfligaturesnx,width=\showotfligatureswidth,align={middle,lohi},height=4ex]
+ \tttf #1
+ \eTD
+ \eTR
+\stoptexdefinition
+
+\starttexdefinition showotfligaturescaptions #1
+ \bTR[height=3ex,align={middle,lohi},bottomframe=off]
+ \processcommalist[#1]\showotfligaturescaption
+ \eTR
+ \bTR[height=3ex,align={middle,lohi},topframe=off]
+ \processcommalist[#1]\showotfligatureslegend
+ \eTR
+\stoptexdefinition
+
+\starttexdefinition showotfligatureslineset #1
+ \showotfligaturesline{original} {#1}
+ \showotfligaturesline{expanded} {#1}
+ \showotfligaturesline{traditional}{#1}
+\stoptexdefinition
+
+
+\starttexdefinition showotfligaturesparagraphset #1
+ \showotfligatureslineset {
+ \hsize \zeropoint
+ \lefthyphenmin \plustwo
+ \righthyphenmin\plustwo
+ #1
+ }
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesextremeset #1
+ \showotfligatureslineset {
+ \hsize \zeropoint
+ \lefthyphenmin \plusone
+ \righthyphenmin\plusone
+ #1
+ }
+\stoptexdefinition
+
+\starttexdefinition showotfligatureslines #1
+ \bTR[height=4ex,bottomframe=off]
+ \processcommalist[#1]\showotfligatureslineset
+ \eTR
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesparagraphs #1
+ \bTR[topframe=off]
+ \processcommalist[#1]\showotfligaturesparagraphset
+ \eTR
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesextremes #1
+ \bTR[topframe=off]
+ \processcommalist[#1]\showotfligaturesextremeset
+ \eTR
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesdefaults
+ \bTR
+ \bTD [nx=\showotfligaturesnx,width=\showotfligatureswidth,align=middle,height=4ex,frame=off]
+ \start \LigatureFont fb \stop \quad
+ \start \LigatureFont ff \stop \quad
+ \start \LigatureFont fi \stop \quad
+ \start \LigatureFont fk \stop \quad
+ \start \LigatureFont fl \stop \quad
+ \start \LigatureFont ft \stop \quad
+ \start \LigatureFont ffb \stop \quad
+ \start \LigatureFont fff \stop \quad
+ \start \LigatureFont ffi \stop \quad
+ \start \LigatureFont ffl \stop \quad
+ \start \LigatureFont ffk \stop \quad
+ \start \LigatureFont fft \stop
+ \eTD
+ \eTR
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesexample #1#2
+ \showotfligaturescaptions {#1}
+ \showotfligatureslines {#2}
+ \showotfligaturesparagraphs{#2}
+ \showotfligaturesextremes {#2}
+\stoptexdefinition
+
+% todo: n -> and split in lua
+
+\starttexdefinition showotfligaturesexamples
+ \showotfligaturesexample
+ {leafing,baffling,efficient,shifffahrt}
+ {leafing,baffling,efficient,shifffahrt}
+ \showotfligaturesexample
+ {offbeat,effect,ef-fective,ef\-fective}
+ {offbeat,effect,ef-fective,ef\-fective}
+ \showotfligaturesexample
+ {xf+fi+a,xff+i+b,xffi+c,xffid}
+ {xffia, xffib, xffic, xffid}
+\stoptexdefinition
+
+\starttexdefinition showotfligatures [#1]
+ \begingroup
+ \getdummyparameters[font=Regular,features=default,#1]
+ \definefont[LigatureFont][\dummyparameter{font}*\dummyparameter{features},otfligaturetest ht 2ex]
+ \bTABLE[leftframe=off,rightframe=off]
+ \showotfligaturesbanner{\dummyparameter{font} * \dummyparameter{features}}
+ \showotfligaturesdefaults
+ \showotfligaturesexamples
+ \eTABLE
+ \endgroup
+\stoptexdefinition
+
+\continueifinputfile{s-fonts-ligatures.mkiv}
+
+\starttext
+
+ \startTEXpage[offset=10pt] \showotfligatures[font=lmroman10-regular.otf, features=default] \stopTEXpage
+ \startTEXpage[offset=10pt] \showotfligatures[font=dejavu-serif.ttf, features=default] \stopTEXpage
+ \startTEXpage[offset=10pt] \showotfligatures[font=minionpro.otf, features=default] \stopTEXpage
+ \startTEXpage[offset=10pt] \showotfligatures[font=minionpro.otf, features=smallcaps] \stopTEXpage
+ \startTEXpage[offset=10pt] \showotfligatures[font=brill.otf, features=default] \stopTEXpage
+ \startTEXpage[offset=10pt] \showotfligatures[font=gentiumplus-r.ttf, features=default] \stopTEXpage
+ \startTEXpage[offset=10pt] \showotfligatures[font=cambria, features=default] \stopTEXpage
+
+\stoptext
+
+% \startluacode
+%
+% local f = fonts.hashes.identifiers[true]
+%
+% local sequences = f.resources.sequences
+% local descriptions = f.shared.rawdata.descriptions
+% local lookuptypes = f.resources.lookuptypes
+% local lookups = f.resources.lookups
+%
+% local ligatures = { "liga", "dlig", "rlig", "clig", "tlig", "ccmp" }
+% local found = { }
+%
+% for i=1,#sequences do
+% local sequence = sequences[i]
+% local features = sequence.features
+% for i=1,#ligatures do
+% local l = ligatures[i]
+% if features[l] then
+% local subtables = sequence.subtables
+% if subtables then
+% for i=1,#subtables do
+% local subtable = subtables[i]
+% local lookup = found[subtable]
+% if lookup then
+% lookup[l] = true
+% else
+% found[subtable] = { [l] = true }
+% end
+% end
+% end
+% end
+% end
+% end
+%
+% context.starttabulate { "|||T|T|T|" }
+%
+% local function flush(l,v,start,unicode,data,done)
+% local features = found[l]
+% if features then
+% local lookuptype = lookuptypes[l]
+% if lookuptype == "ligature" then
+% local t = { }
+% for i=1,#v do
+% t[i] = utf.char(v[i])
+% end
+% t = table.concat(t," ")
+% if not done[t] then
+% context.NC()
+% context(t)
+% context.NC()
+% context(utf.char(unicode))
+% context.NC()
+% context(" %t",table.sortedkeys(features))
+% context.NC()
+% local name = data.name
+% if name then
+% context(name)
+% end
+% context.NC()
+% context("%U",unicode)
+% context.NC()
+% context.NR()
+% done[t] = true
+% end
+% end
+% end
+% end
+%
+% for unicode, data in table.sortedhash(descriptions) do
+% local slookups = data.slookups
+% local mlookups = data.mlookups
+% local done = { }
+% if slookups then
+% for l, v in next, slookups do
+% flush(l,v,1,unicode,data,done)
+% end
+% end
+% if mlookups then
+% for i=1,#mlookups do
+% local v = mlookups[i]
+% flush(v[1],v,2,unicode,data,done)
+% end
+% end
+% end
+%
+% context.stoptabulate()
+%
+% \stopluacode
diff --git a/Master/texmf-dist/tex/context/base/s-fonts-shapes.lua b/Master/texmf-dist/tex/context/base/s-fonts-shapes.lua
index b387c11ddd7..bca860f3fb8 100644
--- a/Master/texmf-dist/tex/context/base/s-fonts-shapes.lua
+++ b/Master/texmf-dist/tex/context/base/s-fonts-shapes.lua
@@ -16,24 +16,32 @@ local NC, NR = context.NC, context.NR
local space, dontleavehmode, glyph, getvalue = context.space, context.dontleavehmode, context.glyph, context.getvalue
local formatters = string.formatters
-function moduledata.fonts.shapes.showlist(specification) -- todo: ranges
- specification = interfaces.checkedspecification(specification)
- local id, cs = fonts.definers.internal(specification,"")
- local chrs = fontdata[id].characters
- function char(k)
- dontleavehmode()
- glyph(id,k)
- end
- local function special(v)
- local specials = v.specials
- if specials and #specials > 1 then
- context("%s:",specials[1])
+function char(id,k)
+ dontleavehmode()
+ glyph(id,k)
+end
+
+local function special(id,specials)
+ if specials and #specials > 1 then
+ context("%s:",specials[1])
+ if #specials > 5 then
+ space() char(id,specials[2])
+ space() char(id,specials[3])
+ space() context("...")
+ space() char(id,specials[#specials-1])
+ space() char(id,specials[#specials])
+ else
for i=2,#specials do
- space()
- char(specials[i])
+ space() char(id,specials[i])
end
end
end
+end
+
+function moduledata.fonts.shapes.showlist(specification) -- todo: ranges
+ specification = interfaces.checkedspecification(specification)
+ local id, cs = fonts.definers.internal(specification,"")
+ local chrs = fontdata[id].characters
context.begingroup()
context.tt()
context.starttabulate { "|l|c|c|c|c|l|l|" }
@@ -50,11 +58,11 @@ function moduledata.fonts.shapes.showlist(specification) -- todo: ranges
for k, v in next, characters.data do
if chrs[k] then
NC() context("0x%05X",k)
- NC() char(k) -- getvalue(cs) context.char(k)
- NC() char(v.shcode)
- NC() char(v.lccode or k)
- NC() char(v.uccode or k)
- NC() special(v)
+ NC() char(id,k) -- getvalue(cs) context.char(k)
+ NC() char(id,v.shcode)
+ NC() char(id,v.lccode or k)
+ NC() char(id,v.uccode or k)
+ NC() special(id,v.specials)
NC() context.tx(v.description)
NC() NR()
end
@@ -67,20 +75,6 @@ function moduledata.fonts.shapes.showlist(specification) -- todo: ranges
specification = interfaces.checkedspecification(specification)
local id, cs = fonts.definers.internal(specification,"")
local chrs = fontdata[id].characters
- function char(k)
- dontleavehmode()
- glyph(id,k)
- end
- local function special(v)
- local specials = v.specials
- if specials and #specials > 1 then
- context("%s:",specials[1])
- for i=2,#specials do
- space()
- char(specials[i])
- end
- end
- end
context.begingroup()
context.tt()
context.starttabulate { "|l|c|c|c|c|l|l|" }
@@ -97,11 +91,11 @@ function moduledata.fonts.shapes.showlist(specification) -- todo: ranges
for k, v in next, characters.data do
if chrs[k] then
NC() context("0x%05X",k)
- NC() char(k)
- NC() char(v.shcode)
- NC() char(v.lccode or k)
- NC() char(v.uccode or k)
- NC() special(v)
+ NC() char(id,k)
+ NC() char(id,v.shcode)
+ NC() char(id,v.lccode or k)
+ NC() char(id,v.uccode or k)
+ NC() special(id,v.specials)
NC() context.tx(v.description)
NC() NR()
end
@@ -137,7 +131,8 @@ local function showglyphshape(specification)
local top_accent, bot_accent = (d.top_accent or 0)*factor, (d.bot_accent or 0)*factor
local anchors, math = d.anchors, d.math
context.startMPcode()
- context("pickup pencircle scaled .25bp ;")
+ context("numeric lw ; lw := .125bp ;")
+ context("pickup pencircle scaled lw ;")
context('picture p ; p := image(draw textext.drt("\\getuvalue{%s}\\gray\\char%s");); draw p ;',cs,charnum)
context('draw (%s,%s)--(%s,%s)--(%s,%s)--(%s,%s)--cycle withcolor green ;',llx,lly,urx,lly,urx,ury,llx,ury)
context('draw (%s,%s)--(%s,%s) withcolor green ;',llx,0,urx,0)
@@ -153,11 +148,11 @@ local function showglyphshape(specification)
l[#l+1] = formatters["((%s,%s) shifted (%s,%s))"](xsign*k*factor,ysign*h*factor,dx,dy)
end
end
- context("draw ((%s,%s) shifted (%s,%s))--%s dashed (evenly scaled .25) withcolor .5white;", xsign*v[1].kern*factor,lly,dx,dy,l[1])
+ context("draw ((%s,%s) shifted (%s,%s))--%s dashed (evenly scaled 1/16) withcolor .5white;", xsign*v[1].kern*factor,lly,dx,dy,l[1])
context("draw laddered (%s) withcolor .5white ;",table.concat(l,".."))
- context("draw ((%s,%s) shifted (%s,%s))--%s dashed (evenly scaled .25) withcolor .5white;", xsign*v[#v].kern*factor,ury,dx,dy,l[#l])
+ context("draw ((%s,%s) shifted (%s,%s))--%s dashed (evenly scaled 1/16) withcolor .5white;", xsign*v[#v].kern*factor,ury,dx,dy,l[#l])
for k, v in ipairs(l) do
- context("draw %s withcolor blue withpen pencircle scaled 1bp;",v)
+ context("draw %s withcolor blue withpen pencircle scaled 2lw ;",v)
end
end
end
@@ -203,7 +198,7 @@ local function showglyphshape(specification)
end
local function show(x,y,txt)
local xx, yy = x*factor, y*factor
- context("draw (%s,%s) withcolor blue withpen pencircle scaled 1bp;",xx,yy)
+ context("draw (%s,%s) withcolor blue withpen pencircle scaled 2lw ;",xx,yy)
context('label.top("\\type{%s}",(%s,%s-2bp)) ;',txt,xx,yy)
context('label.bot("(%s,%s)",(%s,%s+2bp)) ;',x,y,xx,yy)
end
@@ -242,9 +237,9 @@ local function showglyphshape(specification)
end
end
if italic ~= 0 then
- context('draw (%s,%s-1bp)--(%s,%s-0.5bp) withcolor blue;',width,ury,width,ury)
- context('draw (%s,%s-1bp)--(%s,%s-0.5bp) withcolor blue;',width+italic,ury,width+italic,ury)
- context('draw (%s,%s-1bp)--(%s,%s-1bp) withcolor blue;',width,ury,width+italic,ury)
+ context('draw (%s,%s-1bp)--(%s,%s-0.5bp) withcolor blue ;',width,ury,width,ury)
+ context('draw (%s,%s-1bp)--(%s,%s-0.5bp) withcolor blue ;',width+italic,ury,width+italic,ury)
+ context('draw (%s,%s-1bp)--(%s,%s-1bp) withcolor blue ;',width,ury,width+italic,ury)
context('label.lft("\\type{%s}",(%s+2bp,%s-1bp));',"italic",width,ury)
context('label.rt("%s",(%s-2bp,%s-1bp));',d.italic,width+italic,ury)
end
@@ -258,7 +253,7 @@ local function showglyphshape(specification)
context('label.top("\\type{%s}",(%s,%s-1bp));',"bot_accent",top_accent,ury)
context('label.bot("%s",(%s,%s+1bp));',d.bot_accent,bot_accent,lly)
end
- context('draw origin withcolor red withpen pencircle scaled 1bp;')
+ context('draw origin withcolor red withpen pencircle scaled 2lw;')
context("setbounds currentpicture to boundingbox currentpicture enlarged 1bp ;")
context("currentpicture := currentpicture scaled 8 ;")
context.stopMPcode()
diff --git a/Master/texmf-dist/tex/context/base/s-fonts-tables.lua b/Master/texmf-dist/tex/context/base/s-fonts-tables.lua
index 5c91d5ee72c..b3dac7d0630 100644
--- a/Master/texmf-dist/tex/context/base/s-fonts-tables.lua
+++ b/Master/texmf-dist/tex/context/base/s-fonts-tables.lua
@@ -21,6 +21,12 @@ local digits = {
dflt = {
dflt = "1234567890 1/2",
},
+ arab = {
+ dflt = "",
+ },
+ latn = {
+ dflt = "1234567890 1/2",
+ }
}
local punctuation = {
@@ -65,6 +71,9 @@ local lowercase = {
cyrl= {
dflt = "абвгдежзиійклмнопрстуфхцчшщъыьѣэюяѳ"
},
+ arab = {
+ dflt = "ابجدهوزحطيكلمنسعفصقرشتثخذضظغ"
+ },
}
local samples = {
diff --git a/Master/texmf-dist/tex/context/base/s-inf-01.mkvi b/Master/texmf-dist/tex/context/base/s-inf-01.mkvi
index 8263413ace3..2c0c1681e12 100644
--- a/Master/texmf-dist/tex/context/base/s-inf-01.mkvi
+++ b/Master/texmf-dist/tex/context/base/s-inf-01.mkvi
@@ -126,6 +126,8 @@
return max, what, function(n) return (max == 0 and 0) or (n == 0 and 0) or n/max end
end
+ local f_norm = string.formatters["%0.3f"]
+
function document.context_state_1(what)
local max, what, norm = prepare(what)
context.starttabulate { "|Tl|T|T|T|T|T|" }
@@ -154,9 +156,15 @@
(used.mkvi[k] and "vi") or "~~",
k
)
+ -- context("%s\\enspace %s\\quad %s\\quad %s",
+ -- (used.mkii[k] and "ii") or "\\quad",
+ -- (used.mkiv[k] and "iv") or "\\quad",
+ -- (used.mkvi[k] and "vi") or "\\quad",
+ -- k
+ -- )
context.NC()
for i=1,#types do
- context.Bar(types[i],v[i],c[i],norm(v[i]))
+ context.Bar(types[i],v[i],c[i],f_norm(norm(v[i])))
context.NC()
end
context.NR()
@@ -170,7 +178,7 @@
local c = (what == size and comp[k]) or nope
context.StartUp(k)
for i=1,#types do
- context.Up(types[i],norm(v[i]))
+ context.Up(types[i],f_norm(norm(v[i])))
end
context.StopUp()
end
diff --git a/Master/texmf-dist/tex/context/base/s-inf-03.mkiv b/Master/texmf-dist/tex/context/base/s-inf-03.mkiv
index 48449d6900b..a253bed773c 100644
--- a/Master/texmf-dist/tex/context/base/s-inf-03.mkiv
+++ b/Master/texmf-dist/tex/context/base/s-inf-03.mkiv
@@ -8,7 +8,7 @@
\setupbodyfont[dejavu]
-\doifmodeelse {tablet} {
+\doifelsemode {tablet} {
\setuppapersize
[S6,landscape]
@@ -159,16 +159,16 @@ local skipglobal = table.tohash {
"_G", "_M", "_ENV", "",
"context", "modules", "global", "arg", "utf", 1,
"_ptbs_", "_pcol_", "_plib_", "_clib_", "_tlib_",
- "kpse",
+ "kpse", "commands",
}
local skipkeys = table.tohash {
"_pcol_", "_plib_", "_clib_", "_tlib_", "_bpnf_", "_ptbs_",
- "_cldf_", "_cldn_",
+ "_cldf_", "_cldn_", "_cldo_",
"_clmb_", "_clme_", "_clmm_", "_clmn_", "_clma_", "_clmh_",
"_G", "_M", "_ENV", "",
+ -- "global", "shortcuts",
"_VERSION", "_COPYRIGHT", "_DESCRIPTION", "_NAME", "_PACKAGE", "__unload",
-
}
local sameglobal = {
@@ -196,6 +196,8 @@ local variant = 1 -- all parents
local variant = 2 -- parent name too
local variant = 3 -- no parents
+local done = { }
+
local function childtables(key,tab,handler,depth)
depth = depth or 1
local keys = sortedkeys(tab) -- no sorted_pairs
@@ -214,6 +216,10 @@ local function childtables(key,tab,handler,depth)
t = "data"
handler(s,t,depth)
else
+if done[v] then
+ -- logs.report("inf-03","key %a in %a already done",k,v)
+else
+ done[v] = true
handler(s,t,depth)
if variant == 3 then
childtables(false,v,handler,depth+1)
@@ -223,6 +229,7 @@ local function childtables(key,tab,handler,depth)
childtables(s,v,handler,depth+1)
end
end
+end
else
handler(s,t,depth)
end
@@ -245,6 +252,7 @@ end
local function show(title,subtitle,alias,builtin,t,lib,libcolor,glo,glocolor,mark,obsolete)
-- todo: table as argument
+-- print(title,subtitle,alias,builtin,t,lib,libcolor,glo,glocolor,mark,obsolete)
local keys = sortedkeys(t) -- no sorted_pairs
if #keys > 0 then
local fulltitle = title
@@ -341,6 +349,8 @@ end
show("global","",sameglobal.global,false,_G,builtin,"darkgreen",globals,"darkblue",false,obsolete)
+-- inspect(table.sortedkeys(context))
+
for k, v in table.sortedpairs(_G) do
if not skipglobal[k] and not obsolete[k] and type(v) == "table" and not marked(v) then
@@ -351,7 +361,8 @@ for k, v in table.sortedpairs(_G) do
elseif extralua[k] then show(k,"extra lua",sameglobal[k],extralua[k],v,builtin[k],"darkred", false,false,true)
elseif basictex[k] then show(k,"basic tex",sameglobal[k],basictex[k],v,builtin[k],"darkred", false,false,true)
elseif extratex[k] then show(k,"extra tex",sameglobal[k],extratex[k],v,builtin[k],"darkred", false,false,true)
- else show(k,"context", sameglobal[k],false, v,builtin[k],"darkyellow",false,false,true)
+ else
+ show(k,"context", sameglobal[k],false, v,builtin[k],"darkyellow",false,false,true)
end
end
end
diff --git a/Master/texmf-dist/tex/context/base/s-languages-hyphenation.lua b/Master/texmf-dist/tex/context/base/s-languages-hyphenation.lua
index c16c5bd2d94..c5a4f91f1e9 100644
--- a/Master/texmf-dist/tex/context/base/s-languages-hyphenation.lua
+++ b/Master/texmf-dist/tex/context/base/s-languages-hyphenation.lua
@@ -13,8 +13,8 @@ local a_colormodel = attributes.private('colormodel')
local nodecodes = nodes.nodecodes
local nodepool = nodes.pool
-local disc = nodecodes.disc
-local glyph = nodecodes.glyph
+local disc_code = nodecodes.disc
+local glyph_code = nodecodes.glyph
local emwidths = fonts.hashes.emwidths
local exheights = fonts.hashes.exheights
local newkern = nodepool.kern
@@ -23,7 +23,7 @@ local newglue = nodepool.glue
local insert_node_after = node.insert_after
local traverse_by_id = node.traverse_id
-local hyphenate = lang.hyphenate
+local hyphenate = languages.hyphenators.handler -- lang.hyphenate
local find_tail = node.tail
local remove_node = nodes.remove
@@ -36,11 +36,11 @@ local function identify(head,marked)
while current do
local id = current.id
local next = current.next
- if id == disc then
- if prev and next.id == glyph then -- catch other usage of disc
+ if id == disc_code then
+ if prev and next then -- and next.id == glyph_code then -- catch other usage of disc
marked[#marked+1] = prev
end
- elseif id == glyph then
+ elseif id == glyph_code then
prev = current
end
current = next
@@ -81,10 +81,10 @@ function moduledata.languages.hyphenation.showhyphens(head)
local m = { }
local l = langs[i]
marked[i] = m
- for n in traverse_by_id(glyph,head) do
+ for n in traverse_by_id(glyph_code,head) do
n.lang = l
end
- hyphenate(head,find_tail(head))
+ languages.hyphenators.methods.original(head)
identify(head,m)
strip(head,m)
end
diff --git a/Master/texmf-dist/tex/context/base/s-languages-hyphenation.mkiv b/Master/texmf-dist/tex/context/base/s-languages-hyphenation.mkiv
index 769c3d05904..6662dbf2f32 100644
--- a/Master/texmf-dist/tex/context/base/s-languages-hyphenation.mkiv
+++ b/Master/texmf-dist/tex/context/base/s-languages-hyphenation.mkiv
@@ -26,7 +26,7 @@
{\begingroup
\par
% \language\zerocount
- \setupalign[\v!nothyphenated]%
+ % \setupalign[\v!nothyphenated]%
\ctxlua{moduledata.languages.hyphenation.startcomparepatterns("#1")}}
\unexpanded\def\stopcomparepatterns
@@ -56,13 +56,15 @@
\starttext
+\def|#1|{-}
+
\startsubject{Normal text}
\input tufte
\stopsubject
\startsubject{Compare hyphenation points of \showcomparepatternslegend[en,de]}
\startcomparepatterns
- \input tufte \quad (\showcomparepatternslegend)
+ \input tufte \quad (\showcomparepatternslegend)
\stopcomparepatterns
\stopsubject
diff --git a/Master/texmf-dist/tex/context/base/s-languages-system.lua b/Master/texmf-dist/tex/context/base/s-languages-system.lua
index 5afc4d4036f..3b422db9f2e 100644
--- a/Master/texmf-dist/tex/context/base/s-languages-system.lua
+++ b/Master/texmf-dist/tex/context/base/s-languages-system.lua
@@ -10,26 +10,53 @@ moduledata.languages = moduledata.languages or { }
moduledata.languages.system = moduledata.languages.system or { }
local NC, NR, HL = context.NC, context.NR, context.HL
+local sortedhash = table.sortedhash
+local registered = languages.registered
+local context = context
+local ctx_NC = context.NC
+local ctx_NR = context.NR
+local ctx_bold = context.bold
+
+function moduledata.languages.system.loadinstalled()
+ context.start()
+ for k, v in table.sortedhash(registered) do
+ context.language{ k }
+ end
+ context.stop()
+end
function moduledata.languages.system.showinstalled()
- local numbers = languages.numbers
- local registered = languages.registered
- context.starttabulate { "|r|l|l|l|l|" }
- NC() context("id")
- NC() context("tag")
- NC() context("synonyms")
- NC() context("parent")
- NC() context("loaded")
- NC() NR() HL()
- for i=1,#numbers do
- local tag = numbers[i]
- local data = registered[tag]
- NC() context(data.number)
- NC() context(tag)
- NC() context("% t",table.sortedkeys(data.synonyms))
- NC() context(data.parent)
- NC() context("%+t",table.sortedkeys(data.used))
- NC() NR()
+ --
+ context.starttabulate { "|l|r|l|l|p(7em)|r|p|" }
+ context.FL()
+ ctx_NC() ctx_bold("tag")
+ ctx_NC() ctx_bold("n")
+ ctx_NC() ctx_bold("parent")
+ ctx_NC() ctx_bold("file")
+ ctx_NC() ctx_bold("synonyms")
+ ctx_NC() ctx_bold("patterns")
+ ctx_NC() ctx_bold("characters")
+ ctx_NC() ctx_NR()
+ context.FL()
+ for k, v in sortedhash(registered) do
+ local parent = v.parent
+ local resources = v.resources
+ local patterns = resources and resources.patterns
+ ctx_NC() context(k)
+ ctx_NC() context(v.number)
+ ctx_NC() context(v.parent)
+ ctx_NC() context(v.patterns)
+ ctx_NC() for k, v in sortedhash(v.synonyms) do context("%s\\par",k) end
+ if patterns then
+ ctx_NC() context(patterns.n)
+ ctx_NC() context("% t",utf.split(patterns.characters))
+ else
+ ctx_NC()
+ ctx_NC()
+ end
+ ctx_NC() ctx_NR()
end
+ context.LL()
context.stoptabulate()
+ --
end
diff --git a/Master/texmf-dist/tex/context/base/s-languages-system.mkiv b/Master/texmf-dist/tex/context/base/s-languages-system.mkiv
index 36372037433..22991f264f8 100644
--- a/Master/texmf-dist/tex/context/base/s-languages-system.mkiv
+++ b/Master/texmf-dist/tex/context/base/s-languages-system.mkiv
@@ -16,6 +16,7 @@
\registerctxluafile{s-languages-system}{}
\installmodulecommandluasingle \showinstalledlanguages {moduledata.languages.system.showinstalled}
+\installmodulecommandluasingle \loadinstalledlanguages {moduledata.languages.system.loadinstalled}
\stopmodule
@@ -25,6 +26,7 @@
\starttext
+ \loadinstalledlanguages
\showinstalledlanguages
\stoptext
diff --git a/Master/texmf-dist/tex/context/base/s-languages-words.lua b/Master/texmf-dist/tex/context/base/s-languages-words.lua
new file mode 100644
index 00000000000..ea7aee87bcd
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/s-languages-words.lua
@@ -0,0 +1,32 @@
+if not modules then modules = { } end modules ['s-languages-words'] = {
+ version = 1.001,
+ comment = "companion to s-languages-words.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+moduledata.languages = moduledata.languages or { }
+moduledata.languages.words = moduledata.languages.words or { }
+
+function moduledata.languages.words.showwords(specification)
+ local filename = specification.filename or file.addsuffix(tex.jobname,"words")
+ if lfs.isfile(filename) then
+ local w = dofile(filename)
+ if w then
+ -- table.print(w)
+ for cname, category in table.sortedpairs(w.categories) do
+ for lname, language in table.sortedpairs(category.languages) do
+ context.bold(string.format("category: %s, language: %s, total: %s, unique: %s:",
+ cname, lname, language.total or 0, language.unique or 0)
+ )
+ for word, n in table.sortedpairs(language.list) do
+ context(" %s (%s)",word,n)
+ end
+ context.par()
+ end
+ end
+ end
+ end
+end
+
diff --git a/Master/texmf-dist/tex/context/base/s-languages-words.mkiv b/Master/texmf-dist/tex/context/base/s-languages-words.mkiv
new file mode 100644
index 00000000000..4e350bf34d2
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/s-languages-words.mkiv
@@ -0,0 +1,22 @@
+%D \module
+%D [ file=s-languages-words,
+%D version=2010.10.21,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Language Environment 3,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This is used in the test suite.
+
+\startmodule[languages-words]
+
+\registerctxluafile{s-languages-words}{}
+
+\installmodulecommandluasingle \showwords {moduledata.languages.words.showwords}
+
+\stopmodule
diff --git a/Master/texmf-dist/tex/context/base/s-map-10.mkiv b/Master/texmf-dist/tex/context/base/s-map-10.mkiv
index b1218f6e276..c7541babc81 100644
--- a/Master/texmf-dist/tex/context/base/s-map-10.mkiv
+++ b/Master/texmf-dist/tex/context/base/s-map-10.mkiv
@@ -172,7 +172,7 @@
\def\hfontii{\ssbf}
\def\hfontiii{\rm\it}
-\doifmodeelse{nosubsub}{%
+\doifelsemode{nosubsub}{%
\setuphead [section][%
style=\hfontii,
before={\blank[line]},
@@ -201,7 +201,7 @@
before={\blank[halfline]}%
]}
-\doifmodeelse{nosubsub}{%
+\doifelsemode{nosubsub}{%
\setuphead [subject][%
style=\hfontii,
before={\blank[halfline]},
@@ -348,10 +348,10 @@
#1]%
\doifnothing{\MapsPeriod}{%
\ifnum \normalmonth<6 \gdef\MapsPeriod{VOORJAAR}\else \gdef\MapsPeriod{NAJAAR}\fi}
- \doifinstringelse{oorjaar}{\MapsPeriod}{\gdef\MapsPeriod{VOORJAAR}}{}%
- \doifinstringelse{pring}{\MapsPeriod}{\gdef\MapsPeriod{VOORJAAR}}{}%
- \doifinstringelse{ajaar}{\MapsPeriod}{\gdef\MapsPeriod{NAJAAR}}{}%
- \doifinstringelse{utumn}{\MapsPeriod}{\gdef\MapsPeriod{NAJAAR}}{}%
+ \doifelseinstring{oorjaar}{\MapsPeriod}{\gdef\MapsPeriod{VOORJAAR}}{}%
+ \doifelseinstring{pring}{\MapsPeriod}{\gdef\MapsPeriod{VOORJAAR}}{}%
+ \doifelseinstring{ajaar}{\MapsPeriod}{\gdef\MapsPeriod{NAJAAR}}{}%
+ \doifelseinstring{utumn}{\MapsPeriod}{\gdef\MapsPeriod{NAJAAR}}{}%
\doifnothing{\MapsYear}{\gdef\MapsYear{\the\year}}%
\doifnothing{\MapsNumber}{%
\ifnum \normalmonth<6
@@ -441,9 +441,9 @@
%%%%%%%%%%%
-\doifmodeelse{onecolumn}{%
+\doifelsemode{onecolumn}{%
\setuplayout[width=340pt]
- \doifmodeelse{asym}{% one col, asymmetric
+ \doifelsemode{asym}{% one col, asymmetric
\setuplayout[backspace=187.3pt]%
\setuptyping [widetyping][oddmargin=-117pt]
\setuppagenumbering [alternative={singlesided,doublesided}]
diff --git a/Master/texmf-dist/tex/context/base/s-math-characters.lua b/Master/texmf-dist/tex/context/base/s-math-characters.lua
index b0a79fcb6e5..8ff3a8660df 100644
--- a/Master/texmf-dist/tex/context/base/s-math-characters.lua
+++ b/Master/texmf-dist/tex/context/base/s-math-characters.lua
@@ -16,23 +16,26 @@ local lower = string.lower
local utfchar = utf.char
local round = math.round
-local fontdata = fonts.hashes.identifiers
-local chardata = characters.data
+local fontdata = fonts.hashes.identifiers
+local chardata = characters.data
+local blocks = characters.blocks
local no_description = "no description, private to font"
-local limited = true
-local fillinthegaps = true
-local upperlimit = 0x0007F
-local upperlimit = 0xF0000
+local limited = true
+local fillinthegaps = true
+local upperlimit = 0x0007F
+local upperlimit = 0xF0000
-local f_unicode = string.formatters["%U"]
-local f_slot = string.formatters["%s/%0X"]
+local f_unicode = string.formatters["%U"]
+local f_slot = string.formatters["%s/%0X"]
function moduledata.math.characters.showlist(specification)
- specification = interfaces.checkedspecification(specification)
- local id = specification.number -- or specification.id
- local list = specification.list
+ specification = interfaces.checkedspecification(specification)
+ local id = specification.number -- or specification.id
+ local list = specification.list
+ local showvirtual = specification.virtual == "all"
+ local check = specification.check == "yes"
if not id then
id = font.current()
end
@@ -70,137 +73,170 @@ function moduledata.math.characters.showlist(specification)
names[k] = (name and file.basename(name)) or id
end
end
- context.showmathcharactersstart()
- for _, unicode in next, sorted do
- if not limited or unicode < upperlimit then
- local code = gaps[unicode] or unicode
- local char = characters[code]
- local desc = descriptions[code]
- local info = chardata[code]
- if char then
- local next_sizes = char.next
- local v_variants = char.vert_variants
- local h_variants = char.horiz_variants
- local commands = char.commands
- local slookups = desc and desc.slookups
- local mlookups = desc and desc.mlookups
- local mathclass = info.mathclass
- local mathspec = info.mathspec
- local mathsymbol = info.mathsymbol
- local description = info.description or no_description
- context.showmathcharactersstartentry()
- context.showmathcharactersreference(f_unicode(unicode))
- context.showmathcharactersentryhexdectit(f_unicode(code),code,lower(description))
- context.showmathcharactersentrywdhtdpic(round(char.width or 0),round(char.height or 0),round(char.depth or 0),round(char.italic or 0))
- if virtual and commands then
- local t = { }
- for i=1,#commands do
- local ci = commands[i]
- if ci[1] == "slot" then
- local fnt, idx = ci[2], ci[3]
- t[#t+1] = f_slot(names[fnt] or fnt,idx)
+ if check then
+ for k, v in table.sortedhash(blocks) do
+ if v.math then
+ local first = v.first
+ local last = v.last
+ local f, l = 0, 0
+ if first and last then
+ for unicode=first,last do
+ local code = gaps[unicode] or unicode
+ local char = characters[code]
+ if char and not (char.commands and not showvirtual) then
+ f = unicode
+ break
end
end
- if #t > 0 then
- context.showmathcharactersentryresource(concat(t,", "))
- end
- end
- if mathclass or mathspec then
- context.showmathcharactersstartentryclassspec()
- if mathclass then
- context.showmathcharactersentryclassname(mathclass,info.mathname or "no name")
- end
- if mathspec then
- for i=1,#mathspec do
- local mi = mathspec[i]
- context.showmathcharactersentryclassname(mi.class,mi.name or "no name")
+ for unicode=last,first,-1 do
+ local code = gaps[unicode] or unicode
+ local char = characters[code]
+ if char and not (char.commands and not showvirtual) then
+ l = unicode
+ break
end
end
- context.showmathcharactersstopentryclassspec()
+ context.showmathcharacterssetrange(k,f,l)
end
- if mathsymbol then
- context.showmathcharactersentrysymbol(f_unicode(mathsymbol),mathsymbol)
- end
- if next_sizes then
- local n, done = 0, { }
- context.showmathcharactersstartnext()
- while next_sizes do
- n = n + 1
- if done[next_sizes] then
- context.showmathcharactersnextcycle(n)
- break
- else
- done[next_sizes] = true
- context.showmathcharactersnextentry(n,f_unicode(next_sizes),next_sizes)
- next_sizes = characters[next_sizes]
- v_variants = next_sizes.vert_variants or v_variants
- h_variants = next_sizes.horiz_variants or h_variants
- if next_sizes then
- next_sizes = next_sizes.next
+ end
+ end
+ else
+ context.showmathcharactersstart()
+ for _, unicode in next, sorted do
+ if not limited or unicode < upperlimit then
+ local code = gaps[unicode] or unicode
+ local char = characters[code]
+ local desc = descriptions[code]
+ local info = chardata[code]
+ if char then
+ local commands = char.commands
+ if commands and not showvirtual then
+ -- skip
+ else
+ local next_sizes = char.next
+ local v_variants = char.vert_variants
+ local h_variants = char.horiz_variants
+ local slookups = desc and desc.slookups
+ local mlookups = desc and desc.mlookups
+ local mathclass = info.mathclass
+ local mathspec = info.mathspec
+ local mathsymbol = info.mathsymbol
+ local description = info.description or no_description
+ context.showmathcharactersstartentry()
+ context.showmathcharactersreference(f_unicode(unicode))
+ context.showmathcharactersentryhexdectit(f_unicode(code),code,lower(description))
+ context.showmathcharactersentrywdhtdpic(round(char.width or 0),round(char.height or 0),round(char.depth or 0),round(char.italic or 0))
+ if virtual and commands then
+ local t = { }
+ for i=1,#commands do
+ local ci = commands[i]
+ if ci[1] == "slot" then
+ local fnt, idx = ci[2], ci[3]
+ t[#t+1] = f_slot(names[fnt] or fnt,idx)
+ end
+ end
+ if #t > 0 then
+ context.showmathcharactersentryresource(concat(t,", "))
end
end
- end
- context.showmathcharactersstopnext()
- if h_variants or v_variants then
- context.showmathcharactersbetweennextandvariants()
- end
- end
- if h_variants then
- context.showmathcharactersstarthvariants()
- for i=1,#h_variants do -- we might go top-down in the original
- local vi = h_variants[i]
- context.showmathcharactershvariantsentry(i,f_unicode(vi.glyph),vi.glyph)
- end
- context.showmathcharactersstophvariants()
- elseif v_variants then
- context.showmathcharactersstartvvariants()
- for i=1,#v_variants do
- local vi = v_variants[#v_variants-i+1]
- context.showmathcharactersvvariantsentry(i,f_unicode(vi.glyph),vi.glyph)
- end
- context.showmathcharactersstopvvariants()
- end
- if slookups or mlookups then
- local variants = { }
- if slookups then
- for lookupname, lookupdata in next, slookups do
- local lookuptype = lookuptypes[lookupname]
- if lookuptype == "substitution" then
- variants[lookupdata] = "sub"
- elseif lookuptype == "alternate" then
- for i=1,#lookupdata do
- variants[lookupdata[i]] = "alt"
+ if mathclass or mathspec then
+ context.showmathcharactersstartentryclassspec()
+ if mathclass then
+ context.showmathcharactersentryclassname(mathclass,info.mathname or "no name")
+ end
+ if mathspec then
+ for i=1,#mathspec do
+ local mi = mathspec[i]
+ context.showmathcharactersentryclassname(mi.class,mi.name or "no name")
end
end
+ context.showmathcharactersstopentryclassspec()
end
- end
- if mlookups then
- for lookupname, lookuplist in next, mlookups do
- local lookuptype = lookuptypes[lookupname]
- for i=1,#lookuplist do
- local lookupdata = lookuplist[i]
- local lookuptype = lookuptypes[lookupname]
- if lookuptype == "substitution" then
- variants[lookupdata] = "sub"
- elseif lookuptype == "alternate" then
- for i=1,#lookupdata do
- variants[lookupdata[i]] = "alt"
+ if mathsymbol then
+ context.showmathcharactersentrysymbol(f_unicode(mathsymbol),mathsymbol)
+ end
+ if next_sizes then
+ local n, done = 0, { }
+ context.showmathcharactersstartnext()
+ while next_sizes do
+ n = n + 1
+ if done[next_sizes] then
+ context.showmathcharactersnextcycle(n)
+ break
+ else
+ done[next_sizes] = true
+ context.showmathcharactersnextentry(n,f_unicode(next_sizes),next_sizes)
+ next_sizes = characters[next_sizes]
+ v_variants = next_sizes.vert_variants or v_variants
+ h_variants = next_sizes.horiz_variants or h_variants
+ if next_sizes then
+ next_sizes = next_sizes.next
end
end
end
+ context.showmathcharactersstopnext()
+ if h_variants or v_variants then
+ context.showmathcharactersbetweennextandvariants()
+ end
end
+ if h_variants then
+ context.showmathcharactersstarthvariants()
+ for i=1,#h_variants do -- we might go top-down in the original
+ local vi = h_variants[i]
+ context.showmathcharactershvariantsentry(i,f_unicode(vi.glyph),vi.glyph)
+ end
+ context.showmathcharactersstophvariants()
+ elseif v_variants then
+ context.showmathcharactersstartvvariants()
+ for i=1,#v_variants do
+ local vi = v_variants[#v_variants-i+1]
+ context.showmathcharactersvvariantsentry(i,f_unicode(vi.glyph),vi.glyph)
+ end
+ context.showmathcharactersstopvvariants()
+ end
+ if slookups or mlookups then
+ local variants = { }
+ if slookups then
+ for lookupname, lookupdata in next, slookups do
+ local lookuptype = lookuptypes[lookupname]
+ if lookuptype == "substitution" then
+ variants[lookupdata] = "sub"
+ elseif lookuptype == "alternate" then
+ for i=1,#lookupdata do
+ variants[lookupdata[i]] = "alt"
+ end
+ end
+ end
+ end
+ if mlookups then
+ for lookupname, lookuplist in next, mlookups do
+ local lookuptype = lookuptypes[lookupname]
+ for i=1,#lookuplist do
+ local lookupdata = lookuplist[i]
+ local lookuptype = lookuptypes[lookupname]
+ if lookuptype == "substitution" then
+ variants[lookupdata] = "sub"
+ elseif lookuptype == "alternate" then
+ for i=1,#lookupdata do
+ variants[lookupdata[i]] = "alt"
+ end
+ end
+ end
+ end
+ end
+ context.showmathcharactersstartlookupvariants()
+ local i = 0
+ for variant, lookuptype in table.sortedpairs(variants) do
+ i = i + 1
+ context.showmathcharacterslookupvariant(i,f_unicode(variant),variant,lookuptype)
+ end
+ context.showmathcharactersstoplookupvariants()
+ end
+ context.showmathcharactersstopentry()
end
- context.showmathcharactersstartlookupvariants()
- local i = 0
- for variant, lookuptype in table.sortedpairs(variants) do
- i = i + 1
- context.showmathcharacterslookupvariant(i,f_unicode(variant),variant,lookuptype)
- end
- context.showmathcharactersstoplookupvariants()
end
- context.showmathcharactersstopentry()
end
end
+ context.showmathcharactersstop()
end
- context.showmathcharactersstop()
end
diff --git a/Master/texmf-dist/tex/context/base/s-math-characters.mkiv b/Master/texmf-dist/tex/context/base/s-math-characters.mkiv
index 1c415954453..3b273cb6c21 100644
--- a/Master/texmf-dist/tex/context/base/s-math-characters.mkiv
+++ b/Master/texmf-dist/tex/context/base/s-math-characters.mkiv
@@ -46,6 +46,7 @@
\let\showmathcharactersstartlookupvariants \relax
\let\showmathcharacterslookupvariant \gobblefourarguments
\let\showmathcharactersstoplookupvariants \relax
+ \let\showmathcharacterssetrange \gobblethreearguments
\stopsetups
@@ -126,15 +127,23 @@
\def\module_math_characters_show[#1]%
{\begingroup
- \getdummyparameters[\c!bodyfont=,\c!list=,\c!alternative=default,#1]%
+ \getdummyparameters
+ [\c!bodyfont=,
+ \c!list=,
+ \c!check=,
+ \c!alternative=default,
+ \c!option=\v!all,
+ #1]%
\directsetup{s-math-characters:\dummyparameter\c!alternative}%
\doifelsenothing{\dummyparameter\c!bodyfont}
{\definedfont[MathRoman*math-text]}
{\definedfont[\dummyparameter\c!bodyfont]}%
\dontcomplain
\ctxlua{moduledata.math.characters.showlist {
- number = false,
- list = "\dummyparameter\c!list",
+ number = false,
+ check = "\dummyparameter\c!check",
+ list = "\dummyparameter\c!list",
+ option = "\dummyparameter\c!option",
}}%
\endgroup}
diff --git a/Master/texmf-dist/tex/context/base/s-math-coverage.lua b/Master/texmf-dist/tex/context/base/s-math-coverage.lua
index 56880f76db0..3c6080dc36e 100644
--- a/Master/texmf-dist/tex/context/base/s-math-coverage.lua
+++ b/Master/texmf-dist/tex/context/base/s-math-coverage.lua
@@ -9,45 +9,50 @@ if not modules then modules = { } end modules ['s-math-coverage'] = {
local utfchar, utfbyte = utf.char, utf.byte
local formatters, lower = string.formatters, string.lower
local concat = table.concat
+local sortedhash = table.sortedhash
-moduledata.math = moduledata.math or { }
-moduledata.math.coverage = moduledata.math.coverage or { }
+moduledata.math = moduledata.math or { }
+moduledata.math.coverage = moduledata.math.coverage or { }
-local context = context
+local context = context
-local ctx_NC = context.NC
-local ctx_NR = context.NR
-local ctx_HL = context.HL
+local ctx_NC = context.NC
+local ctx_NR = context.NR
+local ctx_HL = context.HL
-local ctx_rawmathematics = context.formatted.rawmathematics
-local ctx_mathematics = context.formatted.mathematics
-local ctx_startimath = context.startimath
-local ctx_stopimath = context.stopimath
-local ctx_setmathattribute = context.setmathattribute
-local ctx_underbar = context.underbar
-local ctx_getglyph = context.getglyph
+local ctx_startmixedcolumns = context.startmixedcolumns
+local ctx_stopmixedcolumns = context.stopmixedcolumns
+local ctx_setupalign = context.setupalign
+local ctx_starttabulate = context.starttabulate
+local ctx_stoptabulate = context.stoptabulate
+local ctx_rawmathematics = context.formatted.rawmathematics
+local ctx_mathematics = context.formatted.mathematics
+local ctx_startimath = context.startimath
+local ctx_stopimath = context.stopimath
+local ctx_setmathattribute = context.setmathattribute
+local ctx_underbar = context.underbar
+local ctx_getglyph = context.getglyph
-local styles = mathematics.styles
-local alternatives = mathematics.alternatives
-local charactersets = mathematics.charactersets
+local styles = mathematics.styles
+local alternatives = mathematics.alternatives
+local charactersets = mathematics.charactersets
-local getboth = mathematics.getboth
-local remapalphabets = mathematics.remapalphabets
+local getboth = mathematics.getboth
+local remapalphabets = mathematics.remapalphabets
-local chardata = characters.data
-local superscripts = characters.superscripts
-local subscripts = characters.subscripts
+local chardata = characters.data
+local superscripts = characters.superscripts
+local subscripts = characters.subscripts
context.writestatus("math coverage","underline: not remapped")
function moduledata.math.coverage.showalphabets()
- context.starttabulate { "|lT|l|Tl|" }
+ ctx_starttabulate { "|lT|l|Tl|" }
for i=1,#styles do
local style = styles[i]
for i=1,#alternatives do
local alternative = alternatives[i]
- for i=1,#charactersets do
- local alphabet = charactersets[i]
+ for _, alphabet in sortedhash(charactersets) do
ctx_NC()
if i == 1 then
context("%s %s",style,alternative)
@@ -80,14 +85,14 @@ function moduledata.math.coverage.showalphabets()
end
end
end
- context.stoptabulate()
+ ctx_stoptabulate()
end
function moduledata.math.coverage.showcharacters()
- context.startmixedcolumns()
- context.setupalign { "nothyphenated" }
- context.starttabulate { "|T|i2|Tpl|" }
- for u, d in table.sortedhash(chardata) do
+ ctx_startmixedcolumns { balance = "yes" }
+ ctx_setupalign { "nothyphenated" }
+ ctx_starttabulate { "|T|i2|Tpl|" }
+ for u, d in sortedhash(chardata) do
local mathclass = d.mathclass
local mathspec = d.mathspec
if mathclass or mathspec then
@@ -110,15 +115,15 @@ function moduledata.math.coverage.showcharacters()
ctx_NR()
end
end
- context.stoptabulate()
- context.stopmixedcolumns()
+ ctx_stoptabulate()
+ ctx_stopmixedcolumns()
end
-- This is a somewhat tricky table as we need to bypass the math machinery.
function moduledata.math.coverage.showscripts()
- context.starttabulate { "|cT|c|cT|c|c|c|l|" }
- for k, v in table.sortedhash(table.merged(superscripts,subscripts)) do
+ ctx_starttabulate { "|cT|c|cT|c|c|c|l|" }
+ for k, v in sortedhash(table.merged(superscripts,subscripts)) do
local ck = utfchar(k)
local cv = utfchar(v)
local ss = superscripts[k] and "^" or "_"
@@ -131,14 +136,14 @@ function moduledata.math.coverage.showscripts()
ctx_NC() context(lower(chardata[k].description))
ctx_NC() ctx_NR()
end
- context.stoptabulate()
+ ctx_stoptabulate()
end
-- Handy too.
function moduledata.math.coverage.showbold()
- context.starttabulate { "|lT|cm|lT|cm|lT|" }
- for k, v in table.sortedhash(mathematics.boldmap) do
+ ctx_starttabulate { "|lT|cm|lT|cm|lT|" }
+ for k, v in sortedhash(mathematics.boldmap) do
ctx_NC() context("%U",k)
ctx_NC() context("%c",k)
ctx_NC() context("%U",v)
@@ -146,5 +151,47 @@ function moduledata.math.coverage.showbold()
ctx_NC() context(chardata[k].description)
ctx_NC() ctx_NR()
end
- context.stoptabulate()
+ ctx_stoptabulate()
end
+
+-- function moduledata.math.coverage.showentities()
+-- ctx_startmixedcolumns { balance = "yes" }
+-- ctx_starttabulate { "|Tl|c|Tl|" }
+-- for k, v in sortedhash(characters.entities) do
+-- local b = utf.byte(v)
+-- local d = chardata[b]
+-- local m = d.mathname
+-- local c = d.contextname
+-- local s = ((m and "\\"..m) or (c and "\\".. c) or v) .. "{}{}{}"
+-- ctx_NC()
+-- context("%U",b)
+-- ctx_NC()
+-- ctx_mathematics(s)
+-- ctx_NC()
+-- context(k)
+-- ctx_NC()
+-- ctx_NR()
+-- end
+-- ctx_stoptabulate()
+-- ctx_stopmixedcolumns()
+-- end
+
+function moduledata.math.coverage.showentities()
+ ctx_startmixedcolumns { balance = "yes" }
+ ctx_starttabulate { "|T||T|T|" }
+ for k, v in sortedhash(characters.entities) do
+ local d = chardata[v]
+ if d then
+ local m = d.mathclass or d.mathspec
+ local u = d.unicodeslot
+ ctx_NC() context(m and "m" or "t")
+ ctx_NC() ctx_getglyph("MathRoman",u)
+ ctx_NC() context("%05X",u)
+ ctx_NC() context(k)
+ ctx_NC() ctx_NR()
+ end
+ end
+ ctx_stoptabulate()
+ ctx_stopmixedcolumns()
+end
+
diff --git a/Master/texmf-dist/tex/context/base/s-math-coverage.mkiv b/Master/texmf-dist/tex/context/base/s-math-coverage.mkiv
index 9f084b2841c..e318c9effdd 100644
--- a/Master/texmf-dist/tex/context/base/s-math-coverage.mkiv
+++ b/Master/texmf-dist/tex/context/base/s-math-coverage.mkiv
@@ -15,10 +15,11 @@
\registerctxluafile{s-math-coverage}{}
-\installmodulecommandluasingle \showmathalphabets {moduledata.math.coverage.showalphabets}
-\installmodulecommandluasingle \showmathcharacters {moduledata.math.coverage.showcharacters}
-\installmodulecommandluasingle \showmathscripts {moduledata.math.coverage.showscripts}
-\installmodulecommandluasingle \showmathbold {moduledata.math.coverage.showbold}
+\installmodulecommandluasingle \showmathalphabets {moduledata.math.coverage.showalphabets}
+\installmodulecommandluasingle \showmathcharacters{moduledata.math.coverage.showcharacters}
+\installmodulecommandluasingle \showmathscripts {moduledata.math.coverage.showscripts}
+\installmodulecommandluasingle \showmathbold {moduledata.math.coverage.showbold}
+\installmodulecommandluasingle \showmathentities {moduledata.math.coverage.showentities}
\stopmodule
@@ -32,5 +33,6 @@
\showmathcharacters \page
\showmathscripts \page
\showmathbold \page
+ \showmathentities \page
\stoptext
diff --git a/Master/texmf-dist/tex/context/base/s-math-repertoire.mkiv b/Master/texmf-dist/tex/context/base/s-math-repertoire.mkiv
index 314d23868e5..230eb513ebe 100644
--- a/Master/texmf-dist/tex/context/base/s-math-repertoire.mkiv
+++ b/Master/texmf-dist/tex/context/base/s-math-repertoire.mkiv
@@ -39,7 +39,8 @@
% \setuplayout
% [page]
-\setuppapersize[HD+]
+\setuppapersize
+ [HD+]
\setuplayout
[backspace=0pt,
@@ -102,6 +103,16 @@
color=textcolor,
contrastcolor=nonecolor]
+\def\showmathcharacterssetrange#1#2#3%
+ {\writestatus{range}{#1: \unihex{#2} - \unihex{#3}}%
+ \ifcase#2\relax
+ \definereference[#1][notpresent]%
+ \else\ifcase#3\relax
+ \definereference[#1][notpresent]%
+ \else
+ \normalexpanded{\definereference[#1][\unihex{#2}]}%
+ \fi\fi}
+
\startinteractionmenu[bottom]
\startgot [firstpage] first \stopgot \quad
\startgot [deltapage(-100)] -100 \stopgot \quad
@@ -159,6 +170,22 @@
\startgot [U+1D7AA] grk ss bolditalic \stopgot
\stopinteractionmenu
+% \startinteractionmenu[symbols]
+% \startgot [U+00030] dig normal \stopgot \quad
+% \startgot [U+1D7CE] dig bold \stopgot \quad
+% \startgot [U+1D7D8] dig doublestruck \stopgot \quad
+% \startgot [U+1D7E2] dig ss normal \stopgot \quad
+% \startgot [U+1D7EC] dig ss bold \stopgot \quad
+% \startgot [U+1D7F6] dig monospace \stopgot \quad
+% \startgot [U+02200] operators \stopgot \quad
+% \startgot [U+02701] symbols a \stopgot \quad
+% \startgot [U+02901] symbols b \stopgot \quad
+% \startgot [U+02A00] supplemental \stopgot \quad
+% \startgot [U+027F0] arrows a \stopgot \quad
+% \startgot [U+02900] arrows b \stopgot \quad
+% \startgot [U+1F800] arrows c \stopgot
+% \stopinteractionmenu
+
\startinteractionmenu[symbols]
\startgot [U+00030] dig normal \stopgot \quad
\startgot [U+1D7CE] dig bold \stopgot \quad
@@ -167,9 +194,13 @@
\startgot [U+1D7EC] dig ss bold \stopgot \quad
\startgot [U+1D7F6] dig monospace \stopgot \quad
\startgot [U+02200] operators \stopgot \quad
- \startgot [U+02701] symbols a \stopgot \quad
- \startgot [U+02901] symbols b \stopgot \quad
- \startgot [U+02A00] supplemental \stopgot
+ \startgot [miscellaneousmathematicalsymbolsa] symbols a \stopgot \quad
+ \startgot [miscellaneousmathematicalsymbolsb] symbols b \stopgot \quad
+ \startgot [supplementalmathematicaloperators] supplemental \stopgot \quad
+ \startgot [supplementalarrowsa] arrows a \stopgot \quad
+ \startgot [supplementalarrowsb] arrows b \stopgot \quad
+ \startgot [supplementalarrowsc] arrows c \stopgot \quad
+ \removeunwantedspaces
\stopinteractionmenu
\defineframed
@@ -227,7 +258,7 @@
\showmathcharactersmth{10}{#1}%
\endgroup
\vfilll
- \doifmodeelse{crosslink}
+ \doifelsemode{crosslink}
{\goto{\strut\textcolor\showmathcharacterstxt{#2}}[#2::#1]}%
{\strut\textcolor\showmathcharacterstxt{#2}}}%
\hskip1ex}
@@ -404,13 +435,17 @@
% main
+% this is a one-run style so we can forget about an alternative
+% just assume that the previous definitions are global
+
\unprotect
\unexpanded\def\showmathfontrepertoire
{\dosingleempty\module_math_repertoire_show}
-\def\module_math_repertoire_show[#1]% % this is a one-run style so we can forget about an alternative
- {\showmathfontcharacters[\c!alternative=,#1]} % just assume that the previous definitions are global
+\def\module_math_repertoire_show[#1]%
+ {\showmathfontcharacters[alternative=,option=,check=yes,#1]
+ \showmathfontcharacters[alternative=,option=,#1]}
\protect
@@ -418,7 +453,7 @@
\continueifinputfile{s-math-repertoire.mkiv}
-\showmathcharacterssetbodyfonts{lucidanova,cambria,xits,modern,pagella,termes,bonum,schola}
+\showmathcharacterssetbodyfonts{lucidaot,cambria,xits,modern,pagella,termes,bonum,schola,dejavu}
\starttext
@@ -434,10 +469,11 @@
% \setupbodyfont[stix, 12pt]
% \setupbodyfont[xits, 12pt]
% \setupbodyfont[lucida, 12pt]
- % \setupbodyfont[lucidanova,12pt]
+ % \setupbodyfont[lucidaot, 12pt]
% \setupbodyfont[pagella, 12pt]
% \setupbodyfont[bonum, 12pt]
- \setupbodyfont[schola, 12pt]
+ % \setupbodyfont[schola, 12pt]
+ \setupbodyfont[dejavu, 12pt]
} {
diff --git a/Master/texmf-dist/tex/context/base/s-pre-17.mkiv b/Master/texmf-dist/tex/context/base/s-pre-17.mkiv
index 9505faa6b76..9c46b4ed7a4 100644
--- a/Master/texmf-dist/tex/context/base/s-pre-17.mkiv
+++ b/Master/texmf-dist/tex/context/base/s-pre-17.mkiv
@@ -194,7 +194,7 @@
\egroup
\setbox\scratchbox\vbox\bgroup
\vskip100pt
- \doifmodeelse {SpreadPage} {
+ \doifelsemode {SpreadPage} {
\hbox spread 200pt
} {
\hbox to \wd\scratchbox
diff --git a/Master/texmf-dist/tex/context/base/s-references-show.mkiv b/Master/texmf-dist/tex/context/base/s-references-show.mkiv
new file mode 100644
index 00000000000..72cccce54f1
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/s-references-show.mkiv
@@ -0,0 +1,132 @@
+%D \module
+%D [ file=s-references-show.mkiv,
+%D version=2015.04.13,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Reference Checking,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\startmodule[references-show]
+
+\unprotect
+
+% \enabletrackers[nodes.references,nodes.destinations] % also shows areas
+
+\enabletrackers[nodes.references.show,nodes.destinations.show]
+
+\enablehiddenbackground % trick
+
+\edef\hiddenbackgroundlist{\hiddenbackgroundlist,trace-references}
+
+\defineoverlay
+ [trace-references]
+ [\directsetup{trace:references:onpage}]
+
+\startluacode
+ local pagelist = structures.references.tracedpages
+
+ function commands.getreferencesonpage(n)
+ n = tonumber(n)
+ if n then
+ local pagedata = pagelist[n]
+ if pagedata then
+ context("%s references",#pagedata)
+ context.blank()
+ for i=1,#pagedata do
+ local details = pagedata[i]
+ local prefix = details[1]
+ local reference = details[2]
+ -- local internal = details[3]
+ -- context("%04i = %s : %s",internal,prefix == "" and "-" or prefix,reference)
+ context("%s : %s",prefix == "" and "-" or prefix,reference)
+ context.par()
+ end
+ else
+ context("no references")
+ end
+ else
+ context("no valid page")
+ end
+ end
+
+\stopluacode
+
+\definecolor
+ [trace:references:onpage]
+ [b=.5,a=1,t=.25]
+
+\defineframed
+ [trace:references:onpage]
+ [\c!offset=2\exheight,
+ %\c!foregroundstyle=\infofont,
+ \c!frame=\v!off,
+ \c!background=\v!color,
+ \c!backgroundcolor=trace:references:onpage,
+ \c!align=\v!normal]
+
+\startsetups trace:references:onpage
+ \vbox to \vsize \bgroup
+ \infofont
+ \vskip\dimexpr-\topspace-\headerheight+2\exheight\relax
+ \hbox to \hsize \bgroup
+ \doifoddpageelse\hss{\hskip\dimexpr-\cutspace+2\exheight\relax}%
+ \directlocalframed [
+ trace:references:onpage
+ ] {
+ \ctxcommand{getreferencesonpage(\the\realpageno)}
+ }
+ \doifoddpageelse{\hskip\dimexpr-\cutspace+2\exheight\relax}\hss
+ \egroup
+ \vss
+ \egroup
+\stopsetups
+
+\protect
+
+\continueifinputfile{s-references-show.mkiv}
+
+\usemodule[art-01]
+
+\setupinteraction
+ [state=start]
+
+\setuppagenumbering
+ [alternative=doublesided]
+
+\starttext
+
+\title {Contents}
+
+\placelist[chapter]
+
+\setupreferenceprefix[zero]
+
+\chapter[crap]{foo}
+
+\setupreferenceprefix[one]
+
+test \pagereference[whatever]
+
+\dorecurse{5}{
+ \placefigure
+ [here][bar 1.#1]
+ {xx}{\framed{xx #1}}
+}
+
+\setupreferenceprefix[two]
+
+\dorecurse{5}{
+ \placefigure
+ [here][bar 2.#1]
+ {xx}{\framed{xx #1}}
+}
+
+\in{checked}[bar 1.1]
+\in{checked}[bar 2.1]
+
+\stoptext
diff --git a/Master/texmf-dist/tex/context/base/s-structure-sections.mkiv b/Master/texmf-dist/tex/context/base/s-structure-sections.mkiv
new file mode 100644
index 00000000000..daaab5abcd0
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/s-structure-sections.mkiv
@@ -0,0 +1,80 @@
+%D \module
+%D [ file=s-structure-sections,
+%D version=2015.02.02,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Show Structure Sections,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+\startluacode
+ local context = context
+ local ctx_NC, ctx_NR = context.NC, context.NR
+ local ctx_bold = context.bold
+
+ structures.tracers = structures.tracers or { }
+
+ function structures.tracers.showsections()
+
+ local list = structures.sections.registered
+ local keys = table.keys(list)
+ table.sort(keys,function(a,b)
+ local la, lb = list[a].level, list[b].level
+ if la == lb then
+ return a < b
+ else
+ return la < lb
+ end
+ end)
+ context.start()
+ context.switchtobodyfont { "tt" }
+ context.starttabulate { "||c||||" }
+ context.FL()
+ ctx_NC() ctx_bold("name")
+ ctx_NC() ctx_bold("level")
+ ctx_NC() ctx_bold("parent")
+ ctx_NC() ctx_bold("section")
+ ctx_NC() ctx_bold("coupling")
+ ctx_NC() context.NR()
+ context.ML()
+ for i=1,#keys do
+ local k = keys[i]
+ local v = list[k]
+ ctx_NC() ctx_bold(k)
+ ctx_NC() context(v.level)
+ ctx_NC() context(v.parent)
+ ctx_NC() context(v.section)
+ ctx_NC() context(v.coupling)
+ ctx_NC() context.NR()
+ end
+ context.LL()
+ context.stoptabulate()
+ context.stop()
+
+ end
+\stopluacode
+
+
+\starttexdefinition showstructuresections
+
+ % no settings yet
+
+ \ctxlua{structures.tracers.showsections()}
+
+\stoptexdefinition
+
+\protect
+
+\continueifinputfile{s-structure-sections.mkiv}
+
+\starttext
+
+ \showstructuresections
+
+\stoptext
diff --git a/Master/texmf-dist/tex/context/base/s-syn-01.tex b/Master/texmf-dist/tex/context/base/s-syn-01.tex
deleted file mode 100644
index 01c8f6653dd..00000000000
--- a/Master/texmf-dist/tex/context/base/s-syn-01.tex
+++ /dev/null
@@ -1,54 +0,0 @@
-%D \module
-%D [ file=s-syn-01,
-%D version=0000.00.00,
-%D title=\CONTEXT\ Style File,
-%D subtitle=Preliminary Syntax Stuff,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D This is needed for the \METAFUN\ manual (this module was
-%D called \type {p-syn-01} on my machine).
-
-\unprotect
-
-\def\Indent #1{\ifvmode\noindent\hbox to 2em{\hss#1}\else#1\fi}
-\def\Sugar #1{\ifhmode\unskip\unskip\unskip\fi\kern.25em{#1}\kern.25em\ignorespaces}
-\def\Something#1{\Sugar{\mathematics{\langle\hbox{#1}\rangle}}}
-\def\Lbrace {\Sugar{\tttf\leftargument}}
-\def\Rbrace {\Sugar{\tttf\rightargument}}
-\def\Or {\Sugar{\mathematics{\vert}}}
-\def\Optional #1{\Sugar{\mathematics{[\hbox{#1}]}}}
-\def\Means {\Sugar{\mathematics{\rightarrow}}}
-\def\Tex #1{\Sugar{\type{#1}}}
-\def\Literal #1{\Sugar{\type{#1}}}
-\def\Syntax #1{\strut\kern-.25em{#1}\kern-.25em}
-\def\Next {\crlf\hbox to 2em{}\nobreak}
-\def\Whatever #1{\Sugar{\mathematics{(\hbox{#1})}}}
-\def\Quote #1{\Sugar{\quote{#1}}}
-
-\def\Or {\Sugar{\Indent{\mathematics{\vert}}}}
-\def\Means {\Sugar{\Indent{\mathematics{\rightarrow}}}}
-
-\def\StartSyntax
- {\goodbreak
- \startlines
- \catcode`\#=12
- \let\L \Literal
- \let\S \Something
- \def\FL##1{\color[darkred]{\L{##1}}}
- \def\FS##1{\S{\color[darkred]{##1}}}
- \let\M \Means
- \let\O \Or
- \let\Q \Quote
- \let\LB\Lbrace
- \let\RB\Rbrace}
-
-\def\StopSyntax
- {\stoplines}
-
-\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/s-syntax.mkii b/Master/texmf-dist/tex/context/base/s-syntax.mkii
new file mode 100644
index 00000000000..6d1d59697ec
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/s-syntax.mkii
@@ -0,0 +1,54 @@
+%D \module
+%D [ file=s-syntax, % was: s-syn-01,
+%D version=0000.00.00,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Preliminary Syntax Stuff,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This is needed for the \METAFUN\ manual (this module was
+%D called \type {p-syn-01} on my machine).
+
+\unprotect
+
+\def\Indent #1{\ifvmode\noindent\hbox to 2em{\hss#1}\else#1\fi}
+\def\Sugar #1{\ifhmode\unskip\unskip\unskip\fi\kern.25em{#1}\kern.25em\ignorespaces}
+\def\Something#1{\Sugar{\mathematics{\langle\hbox{#1}\rangle}}}
+\def\Lbrace {\Sugar{\tttf\leftargument}}
+\def\Rbrace {\Sugar{\tttf\rightargument}}
+\def\Or {\Sugar{\mathematics{\vert}}}
+\def\Optional #1{\Sugar{\mathematics{[\hbox{#1}]}}}
+\def\Means {\Sugar{\mathematics{\rightarrow}}}
+\def\Tex #1{\Sugar{\type{#1}}}
+\def\Literal #1{\Sugar{\type{#1}}}
+\def\Syntax #1{\strut\kern-.25em{#1}\kern-.25em}
+\def\Next {\crlf\hbox to 2em{}\nobreak}
+\def\Whatever #1{\Sugar{\mathematics{(\hbox{#1})}}}
+\def\Quote #1{\Sugar{\quote{#1}}}
+
+\def\Or {\Sugar{\Indent{\mathematics{\vert}}}}
+\def\Means {\Sugar{\Indent{\mathematics{\rightarrow}}}}
+
+\def\StartSyntax
+ {\goodbreak
+ \startlines
+ \catcode`\#=12
+ \let\L \Literal
+ \let\S \Something
+ \def\FL##1{\color[darkred]{\L{##1}}}
+ \def\FS##1{\S{\color[darkred]{##1}}}
+ \let\M \Means
+ \let\O \Or
+ \let\Q \Quote
+ \let\LB\Lbrace
+ \let\RB\Rbrace}
+
+\def\StopSyntax
+ {\stoplines}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/s-syntax.mkiv b/Master/texmf-dist/tex/context/base/s-syntax.mkiv
new file mode 100644
index 00000000000..96312f77179
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/s-syntax.mkiv
@@ -0,0 +1,96 @@
+%D \module
+%D [ file=s-syntax, % was: s-syn-01,
+%D version=0000.00.00,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Preliminary Syntax Stuff,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This is needed for the \METAFUN\ manual: quite old code that I would do
+%D differently nowadays.
+
+\unprotect
+
+\unexpanded\def\module_syntax_Indent #1{\ifvmode\noindent\hbox to 2em{\hss#1}\else#1\fi}
+\unexpanded\def\module_syntax_Sugar #1{\removeunwantedspaces\kern.25em{#1}\kern.25em\ignorespaces}
+\unexpanded\def\module_syntax_Something #1{\Sugar{\mathematics{\langle\hbox{#1}\rangle}}}
+\unexpanded\def\module_syntax_Lbrace {\Sugar{\tttf\leftargument}}
+\unexpanded\def\module_syntax_Rbrace {\Sugar{\tttf\rightargument}}
+\unexpanded\def\module_syntax_Lparent {\Sugar{\tttf(}}
+\unexpanded\def\module_syntax_Rparent {\Sugar{\tttf)}}
+\unexpanded\def\module_syntax_Lbracket {\Sugar{\tttf[}}
+\unexpanded\def\module_syntax_Rbracket {\Sugar{\tttf]}}
+\unexpanded\def\module_syntax_Or {\Sugar{\mathematics{\vert}}}
+\unexpanded\def\module_syntax_Optional #1{\Sugar{\mathematics{[\hbox{#1}]}}}
+\unexpanded\def\module_syntax_Means {\Sugar{\mathematics{\rightarrow}}}
+\unexpanded\def\module_syntax_Tex #1{\Sugar{\type{#1}}}
+\unexpanded\def\module_syntax_Literal #1{\Sugar{\type{#1}}}
+\unexpanded\def\module_syntax_Syntax #1{\strut\kern-.25em{#1}\kern-.25em}
+\unexpanded\def\module_syntax_Next {\crlf\hbox to 2em{}\nobreak}
+\unexpanded\def\module_syntax_Whatever #1{\Sugar{\mathematics{(\hbox{#1})}}}
+\unexpanded\def\module_syntax_Quote #1{\Sugar{\quote{#1}}}
+\unexpanded\def\module_syntax_Or {\Sugar{\module_syntax_Indent{\mathematics{\vert}}}}
+\unexpanded\def\module_syntax_Means {\Sugar{\module_syntax_Indent{\mathematics{\rightarrow}}}}
+\unexpanded\def\module_syntax_FlaggedLiteral #1{\color[darkred]{\module_syntax_Literal{#1}}}
+\unexpanded\def\module_syntax_FlaggedSomething#1{\module_syntax_Something{\color[darkred]{#1}}}
+
+\unexpanded\def\StartSyntax
+ {\startlines
+ % formatters
+ \let\Indent \module_syntax_Indent
+ \let\Sugar \module_syntax_Sugar
+ \let\Something \module_syntax_Something
+ \let\Lbrace \module_syntax_Lbrace
+ \let\Rbrace \module_syntax_Rbrace
+ \let\Lparent \module_syntax_Lparent
+ \let\Rparent \module_syntax_Rparent
+ \let\Lbracket \module_syntax_Lbracket
+ \let\Rbracket \module_syntax_Rbracket
+ \let\Or \module_syntax_Or
+ \let\Optional \module_syntax_Optional
+ \let\Means \module_syntax_Means
+ \let\Tex \module_syntax_Tex
+ \let\Literal \module_syntax_Literal
+ \let\Syntax \module_syntax_Syntax
+ \let\Next \module_syntax_Next
+ \let\Whatever \module_syntax_Whatever
+ \let\Quote \module_syntax_Quote
+ \let\Or \module_syntax_Or
+ \let\Means \module_syntax_Means
+ \let\FlaggedLiteral \module_syntax_FlaggedLiteral
+ \let\FlaggedSomething\module_syntax_FlaggedSomething
+ % shortcuts
+ \let\FL \module_syntax_FlaggedLiteral
+ \let\FS \module_syntax_FlaggedSomething
+ \let\L \module_syntax_Literal
+ \let\S \module_syntax_Something
+ \let\M \module_syntax_Means
+ \let\O \module_syntax_Or
+ \let\Q \module_syntax_Quote
+ \let\LB \module_syntax_Lbrace
+ \let\RB \module_syntax_Rbrace
+ \let\LP \module_syntax_Lparent
+ \let\RP \module_syntax_Rparent
+ \let\LS \module_syntax_Lbracket
+ \let\RS \module_syntax_Rbracket
+ \let\{ \module_syntax_Lbrace
+ \let\} \module_syntax_Rbrace
+ \let\( \module_syntax_Lparent
+ \let\) \module_syntax_Rparent
+ \let\[ \module_syntax_Lbracket
+ \let\] \module_syntax_Rbracket
+ % precaution
+ \catcode`\#\othercatcode}
+
+\unexpanded\def\StopSyntax
+ {\stoplines}
+
+\unexpanded\def\SyntaxCommand#1%
+ {\csname module_syntax_#1\endcsname}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/s-typesetting-kerning.mkiv b/Master/texmf-dist/tex/context/base/s-typesetting-kerning.mkiv
new file mode 100644
index 00000000000..48d81ce3602
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/s-typesetting-kerning.mkiv
@@ -0,0 +1,209 @@
+%D \module
+%D [ file=s-typesetting-kerning,
+%D version=2014.12.14,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Show Character Kerning,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+\definecharacterkerning
+ [typesetting-kerning-demo]
+ [factor=.5]
+
+\startbuffer[showcharacterkerning:boxes]
+ \starttextrule{boxes}
+ \showfontkerns
+ \dontcomplain
+ \startlines
+ test \hbox{!} test
+ test\hbox{!} test
+ test \hbox{!}test
+ test:$x$ test
+ \setcharacterkerning[typesetting-kerning-demo]
+ test \hbox{!} test
+ test\hbox{!} test
+ test \hbox{!}test
+ test:$x$ test
+ \stoplines
+ \stoptextrule
+\stopbuffer
+
+\startbuffer[showcharacterkerning:ligatures]
+ \starttextrule{ligatures}
+ \dontcomplain
+ \startlines
+ effe flink effectief efficient fietsen
+ \blank
+ \setcharacterkerning[typesetting-kerning-demo]
+ effe flink effectief efficient fietsen
+ \blank \hsize\zeropoint
+ effe
+ flink
+ effectief
+ efficient
+ fietsen
+ \stoplines
+ \stoptextrule
+\stopbuffer
+
+\startbuffer[showcharacterkerning:discretionaries]
+ \starttextrule{discretionary}
+ \dontcomplain
+ \startlines
+ \hbox{\samplediscretionary}
+ \hbox{xxx\samplediscretionary}
+ \hbox{\samplediscretionary xxx}
+ \hbox{xxx\samplediscretionary xxx}
+ \blank
+ \setcharacterkerning[typesetting-kerning-demo]
+ \hbox{\samplediscretionary}
+ \hbox{xxx\samplediscretionary}
+ \hbox{\samplediscretionary xxx}
+ \hbox{xxx\samplediscretionary xxx}
+ \blank \hsize\zeropoint
+ \samplediscretionary
+ xxx\samplediscretionary
+ \samplediscretionary xxx
+ xxx\samplediscretionary xxx
+ \stoplines
+ \stoptextrule
+\stopbuffer
+
+\startbuffer[showcharacterkerning:explicits]
+ \starttextrule{explicits}
+ \exhyphenchar \hyphenasciicode
+ \preexhyphenchar \lessthanasciicode
+ \postexhyphenchar\morethanasciicode
+ \def\TestDisc
+ {\discretionary
+ {\kern\emwidth<}%
+ {>\kern\emwidth}%
+ {\kern\emwidth=\kern\emwidth}%
+ }
+ \dontcomplain
+ \startlines
+ \hbox{super-charged}
+ \hbox{super\-charged}
+ \hbox{super\TestDisc charged}
+ \hbox{super\discretionary{[}{]}{[]}charged}
+ \blank
+ \setcharacterkerning[typesetting-kerning-demo]
+ \hbox{super-charged}
+ \hbox{super\-charged}
+ \hbox{super\TestDisc charged}
+ \hbox{super\discretionary{[}{]}{[]}charged}
+ \blank \hsize\zeropoint
+ super-charged
+ super\-charged
+ super\TestDisc charged
+ super\discretionary{[}{]}{[]}charged
+ \stoplines
+ \stoptextrule
+\stopbuffer
+
+\starttexdefinition unexpanded showcharacterkerning
+ \getbuffer[showcharacterkerning:boxes]
+ \getbuffer[showcharacterkerning:ligatures]
+ \getbuffer[showcharacterkerning:discretionaries]
+ \getbuffer[showcharacterkerning:explicits]
+\stoptexdefinition
+
+
+\starttexdefinition showcharacterkerningstepscompared #1
+ \definecharacterkerning[crap][factor=\KerningStepFactor]%
+ \setbox0=\ruledhbox{\color[color-1]{#1}\hss}
+ \setbox2=\ruledhbox{\setcharacterkerning[crap]\color[color-2]{#1}}
+ \setbox4=\ruledhbox{\setcharacterkerning[crap]\showfontkerns\showglyphs#1}
+ \xdef\KerningStepPercentage{\ctxlua{context("\letterpercent 0.2f",(1-\number\wd0/\number\wd2)*100)}}
+ \scratchwidth\wd0
+ \vtop\bgroup
+ \hbox{\box0\hskip-\scratchwidth\box2}
+ \par
+ \box4
+ \egroup
+\stoptexdefinition
+
+\starttexdefinition showcharacterkerningsteps [#1]
+
+ \start
+
+ \getdummyparameters
+ [\s!font=Regular,
+ \c!sample={Wat een bende, rommelen met het font design!},
+ \c!text={rommelen},
+ \c!first=00,
+ \c!last=95,
+ \c!step=05,
+ \c!option=, % \v!page
+ #1]
+
+ \doif{\dummyparameter\c!option}\v!page {
+ \startTEXpage[\c!offset=1ex]
+ }
+
+ \definecolor[color-1][r=1,t=.5,a=1]
+ \definecolor[color-2][b=1,t=.5,a=1]
+
+ \definedfont[\dummyparameter\s!font*default sa 1]
+
+ \doif {\dummyparameter\c!option}\v!page {
+ \begingroup
+ \tttf \dummyparameter\s!font\space @ default
+ \endgroup
+ \blank
+ }
+
+ \starttabulate[|cT|l|cT|l|cT|]
+
+ \NC \tt\bf factor \NC \tt\bf sample \NC \tt\bf \letterpercent \NC \tt\bf text \NC \tt\bf \letterpercent \NC \NR \HL
+
+ \dostepwiserecurse {\dummyparameter\c!first} {\dummyparameter\c!last} {\dummyparameter\c!step} {
+ \NC
+ \xdef\KerningStepFactor{\ctxlua{context("\letterpercent 0.3f",####1/1000)}}
+ \KerningStepFactor
+ \NC
+ \showcharacterkerningstepscompared{\dummyparameter\c!sample}
+ \NC
+ \KerningStepPercentage
+ \NC
+ \showcharacterkerningstepscompared{\dummyparameter\c!text}
+ \NC
+ \KerningStepPercentage
+ \NC \NR
+ }
+
+ \stoptabulate
+
+ \doif{\dummyparameter\c!option}\v!page {
+ \stopTEXpage
+ }
+
+ \stop
+
+\stoptexdefinition
+
+\protect
+
+\continueifinputfile{s-typesetting-kerning.mkiv}
+
+\starttext
+
+ % \showcharacterkerning
+
+ \showcharacterkerningsteps[font=file:FuturaStd-Book.otf,option=page]
+ \showcharacterkerningsteps[font=file:FuturaStd-Medium.otf,option=page]
+ \showcharacterkerningsteps[font=file:FuturaStd-Bold.otf,option=page]
+ \showcharacterkerningsteps[font=file:FuturaStd-heavy.otf,option=page]
+
+\stoptext
+
+% {\hsize1mm efficient\discretionary{\kern1pt!\kern1pt}{\kern1pt!\kern1pt}{\kern1pt!\kern1pt}efficient\par}
+% {\hsize1mm\definedfont[Regular]\setcharacterkerning[typesetting-kerning-demo]efficient\-efficient\par}
+
diff --git a/Master/texmf-dist/tex/context/base/s-youless.mkiv b/Master/texmf-dist/tex/context/base/s-youless.mkiv
index 247eb5f648f..e15973b9c63 100644
--- a/Master/texmf-dist/tex/context/base/s-youless.mkiv
+++ b/Master/texmf-dist/tex/context/base/s-youless.mkiv
@@ -59,9 +59,10 @@
for y=year,year do
- local year = years[y]
- local scale = 20
- local mark = 3
+ local year = years[y]
+ local scale = 20
+ local mark = 3
+ local maxwatt = specification.maxwatt or year.maxwatt
for m=1,12 do
local month = year.months[m]
@@ -69,7 +70,7 @@
context.startMPpage { offset = "10pt" }
context("linecap := butt; pickup pencircle scaled .5")
- for i=0,(math.div(year.maxwatt,1000)+1)*1000,100 do
+ for i=0,(math.div(maxwatt,1000)+1)*1000,100 do
context("draw (%s,%s) -- (%s,%s) withcolor .6white ;",0,i/scale,31 * 24,i/scale)
end
@@ -123,7 +124,7 @@
context("draw (%s,%s) -- (%s,%s) withcolor darkgray ; ",xoffset,0,xoffset,-10)
end
- local max = (math.div(year.maxwatt,1000)+1)
+ local max = (math.div(maxwatt,1000)+1)
for i=0,max*1000,1000 do
context([[draw textext.lft("%s") shifted (%s,%s) ; ]],i,-10,i/scale)
diff --git a/Master/texmf-dist/tex/context/base/scrn-bar.mkvi b/Master/texmf-dist/tex/context/base/scrn-bar.mkvi
index 1dadc26f38f..8a2f9441c80 100644
--- a/Master/texmf-dist/tex/context/base/scrn-bar.mkvi
+++ b/Master/texmf-dist/tex/context/base/scrn-bar.mkvi
@@ -67,7 +67,7 @@
\def\scrn_bar_direct[#tag][#settings]% somewhat messy
{\iflocation
\begingroup
- \doifassignmentelse{#tag}
+ \doifelseassignment{#tag}
{\let\currentinteractionbar\empty
\setupcurrentinteractionbar[#tag]%
\edef\currentinteractionbar{\interactionbarparameter\c!alternative}}%
diff --git a/Master/texmf-dist/tex/context/base/scrn-but.lua b/Master/texmf-dist/tex/context/base/scrn-but.lua
index 74f6e0cd9af..7d883c910b7 100644
--- a/Master/texmf-dist/tex/context/base/scrn-but.lua
+++ b/Master/texmf-dist/tex/context/base/scrn-but.lua
@@ -6,12 +6,10 @@ if not modules then modules = { } end modules ['scrn-but'] = {
license = "see context related readme files"
}
-local commands = commands
local context = context
-
local f_two_colon = string.formatters["%s:%s"]
-function commands.registerbuttons(tag,register,language)
+local function registerbuttons(tag,register,language)
local data = sorters.definitions[language]
local orders = daya and data.orders or sorters.definitions.default.orders
local tag = tag == "" and { "" } or { tag }
@@ -20,3 +18,9 @@ function commands.registerbuttons(tag,register,language)
context.menubutton(tag,f_two_colon(register,order),order)
end
end
+
+interfaces.implement {
+ name = "registerbuttons",
+ actions = registerbuttons,
+ arguments = { "string", "string", "string" }
+}
diff --git a/Master/texmf-dist/tex/context/base/scrn-but.mkvi b/Master/texmf-dist/tex/context/base/scrn-but.mkvi
index f8b236c522a..3fdaf2c5d75 100644
--- a/Master/texmf-dist/tex/context/base/scrn-but.mkvi
+++ b/Master/texmf-dist/tex/context/base/scrn-but.mkvi
@@ -93,7 +93,7 @@
[\c!state=\v!start,
\c!width=\v!fit,
\c!height=\v!broad,
- \c!offset=0.25em,
+ \c!offset=0.25\emwidth,
\c!frame=\v!on,
\c!background=,
\c!backgroundcolor=,
@@ -159,7 +159,7 @@
\attribute\referenceattribute\attributeunsetvalue
\global\setfalse\c_scrn_button_skipped
\chardef\locationboxpagestate\csname\??buttonlocation#currentparameter\c!samepage\endcsname % ?? bt: todo
- \doifreferencefoundelse{#action}\scrn_button_make_yes\scrn_button_make_nop
+ \doifelsereferencefound{#action}\scrn_button_make_yes\scrn_button_make_nop
#currentparameter%
#inheritedframed%
#letparameter%
@@ -217,12 +217,12 @@
{\global\settrue\c_scrn_button_skipped}
\def\scrn_button_make_normal#currentparameter#inheritedframed#letparameter#setparameter#text%
- {\ctxcommand{injectcurrentreference()}%
+ {\clf_injectcurrentreference
\hbox attr \referenceattribute \lastreferenceattribute
{#inheritedframed{\ignorespaces#text\removeunwantedspaces}}}
\def\scrn_button_make_contrast#currentparameter#inheritedframed#letparameter#setparameter#text%
- {\ctxcommand{injectcurrentreference()}%
+ {\clf_injectcurrentreference
\hbox attr \referenceattribute \lastreferenceattribute
{#setparameter\c!foregroundcolor{#currentparameter\c!contrastcolor}%
#inheritedframed{\ignorespaces#text\removeunwantedspaces}}}
@@ -343,12 +343,12 @@
\def\scrn_menu_define[#tag][#category][#settings]% category reflects location, settings can be parent
{\ifthirdargument
- \doifassignmentelse{#settings}%
+ \doifelseassignment{#settings}%
{\scrn_menu_define_original[#tag][#category][\c!category=#category,#settings]}% child definition
{\scrn_menu_define_original[#tag][#settings][\c!category=#category]}% % child definition
\scrn_menu_register{#tag}{#category}%
\else\ifsecondargument
- \doifassignmentelse{#category}%
+ \doifelseassignment{#category}%
{\scrn_menu_define_original[#tag][#category]}% % root definition
{\scrn_menu_define_original[#tag][#category][\c!category=#category]% % child definition
\scrn_menu_register{#tag}{#category}}%
@@ -368,7 +368,7 @@
%D Fill menus:
-\normalexpanded{\long\def\expandafter\noexpand\csname\e!start\v!interactionmenu\endcsname[#tag]#content\expandafter\noexpand\csname\e!stop\v!interactionmenu\endcsname}%
+\normalexpanded{\def\expandafter\noexpand\csname\e!start\v!interactionmenu\endcsname[#tag]#content\expandafter\noexpand\csname\e!stop\v!interactionmenu\endcsname}%
{\def\currentinteractionmenu{#tag}%
\expandafter\settrue\csname\??menustate\interactionmenuparameter\c!category\endcsname
\setinteractionmenuparameter\c!menu{#content}}
@@ -691,7 +691,7 @@
\def\scrn_button_make_position#currentparameter#inheritedframed#letparameter#setparameter#text#action%
{\global\advance\c_scrn_menu_position\plusone
- \doifreferencefoundelse{#action}% 0=not found, 1=same page, >1=elsewhere
+ \doifelsereferencefound{#action}% 0=not found, 1=same page, >1=elsewhere
{\c_scrn_menu_page_mode\ifnum\currentreferencerealpage=\realpageno\plusone\else\plustwo\fi}%
{\c_scrn_menu_page_mode\plustwo}%
\doglobal\appendetoks
@@ -709,7 +709,8 @@
\unexpanded\def\scrn_menu_got_start[#action]#text\stopgot
{\scrn_menu_action_start
- \setupcurrentinteractionmenu[\c!frame=\v!off,\c!background=]% needs checking, was buttons
+ \letinteractionmenuparameter\c!frame\v!off
+ \letinteractionmenuparameter\c!background\empty
\scrn_button_make
\interactionmenuparameter
\inheritedinteractionmenuframed
@@ -967,7 +968,7 @@
\scrn_menu_menu_button_a
{#menutag}{#settings}{#text}{#action}%
\else
- \doifassignmentelse{#menutag}\scrn_menu_menu_button_b\scrn_menu_menu_button_c
+ \doifelseassignment{#menutag}\scrn_menu_menu_button_b\scrn_menu_menu_button_c
{#menutag}{#text}{#action}%
\fi}
@@ -1022,9 +1023,14 @@
\def\scrn_menu_register_menu_buttons[#menu][#register]%
{\ifsecondargument
- \ctxcommand{registerbuttons("menu","#register","\currentlanguage")}
+ \clf_registerbuttons{menu}{#register}{\currentlanguage}%
\else
- \ctxcommand{registerbuttons("","#menu","\currentlanguage")}
+ \clf_registerbuttons{}{#menu}{\currentlanguage}%
\fi}
+% or less readable:
+%
+% \def\scrn_menu_register_menu_buttons[#menu][#register]%
+% {\clf_registerbuttons\ifsecondargument{menu}{#register}\else{}{#menu}\fi{\currentlanguage}}
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/scrn-fld.lua b/Master/texmf-dist/tex/context/base/scrn-fld.lua
index 69480b88794..1563b9005d7 100644
--- a/Master/texmf-dist/tex/context/base/scrn-fld.lua
+++ b/Master/texmf-dist/tex/context/base/scrn-fld.lua
@@ -8,6 +8,10 @@ if not modules then modules = { } end modules ['scrn-fld'] = {
-- we should move some code from lpdf-fld to here
+local context = context
+local ctx_doifelse = commands.doifelse
+local implement = interfaces.implement
+
local variables = interfaces.variables
local v_yes = variables.yes
@@ -40,48 +44,141 @@ fields.defineset = defineset
fields.clone = clone
fields.insert = insert
-commands.definefield = define
-commands.definefieldset = defineset
-commands.clonefield = clone
+-- codeinjections are not yet defined
+
+implement {
+ name = "definefield",
+ actions = define,
+ arguments = {
+ {
+ { "name" },
+ { "alternative" },
+ { "type" },
+ { "category" },
+ { "values" },
+ { "default" },
+ }
+ }
+}
-function commands.insertfield(name,specification)
- texsetbox("b_scrn_field_body",insert(name,specification))
-end
+implement {
+ name = "definefieldset",
+ actions = defineset,
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "clonefield",
+ actions = clone,
+ arguments = {
+ {
+ { "children" },
+ { "alternative" },
+ { "parent" },
+ { "category" },
+ { "values" },
+ { "default" },
+ }
+ }
+}
+
+implement {
+ name = "insertfield",
+ actions = function(name,specification)
+ texsetbox("b_scrn_field_body",insert(name,specification))
+ end,
+ arguments = {
+ "string",
+ {
+ { "title" },
+ { "width", "dimen" },
+ { "height", "dimen" },
+ { "depth", "dimen" },
+ { "align" },
+ { "length" },
+ { "fontstyle" },
+ { "fontalternative" },
+ { "fontsize" },
+ { "fontsymbol" },
+ { "colorvalue", "integer" },
+ { "color" },
+ { "backgroundcolorvalue", "integer" },
+ { "backgroundcolor" },
+ { "framecolorvalue", "integer" },
+ { "framecolor" },
+ { "layer" },
+ { "option" },
+ { "align" },
+ { "clickin" },
+ { "clickout" },
+ { "regionin" },
+ { "regionout" },
+ { "afterkey" },
+ { "format" },
+ { "validate" },
+ { "calculate" },
+ { "focusin" },
+ { "focusout" },
+ { "openpage" },
+ { "closepage" },
+ }
+ }
+}
-- (for the monent) only tex interface
-function commands.getfieldcategory(name)
- local g = codeinjections.getfieldcategory(name)
- if g then
- context(g)
+implement {
+ name = "getfieldcategory",
+ arguments = "string",
+ actions = function(name)
+ local g = codeinjections.getfieldcategory(name)
+ if g then
+ context(g)
+ end
end
-end
+}
-function commands.getdefaultfieldvalue(name)
- local d = codeinjections.getdefaultfieldvalue(name)
- if d then
- context(d)
+implement {
+ name = "getdefaultfieldvalue",
+ arguments = "string",
+ actions = function(name)
+ local d = codeinjections.getdefaultfieldvalue(name)
+ if d then
+ context(d)
+ end
end
-end
+}
-function commands.exportformdata(export)
- if export == v_yes then
- codeinjections.exportformdata()
+implement {
+ name = "exportformdata",
+ arguments = "string",
+ actions = function(export)
+ if export == v_yes then
+ codeinjections.exportformdata()
+ end
end
-end
-
-function commands.setformsmethod(method)
- codeinjections.setformsmethod(method)
-end
+}
-function commands.doiffieldcategoryelse(name)
- commands.doifelse(codeinjections.validfieldcategory(name))
-end
+implement {
+ name = "setformsmethod",
+ arguments = "string",
+ actions = function(method)
+ codeinjections.setformsmethod(method)
+ end
+}
-function commands.doiffieldsetelse(tag)
- commands.doifelse(codeinjections.validfieldset(name))
-end
+implement {
+ name = "doifelsefieldcategory",
+ arguments = "string",
+ actions = function(name)
+ ctx_doifelse(codeinjections.validfieldcategory(name))
+ end
+}
-function commands.doiffieldelse(name)
- commands.doifelse(codeinjections.validfield(name))
-end
+implement {
+ name = "doiffieldsetelse",
+ arguments = "string",
+ actions = function(name)
+ ctx_doifelse(codeinjections.validfieldset(name))
+ end
+}
diff --git a/Master/texmf-dist/tex/context/base/scrn-fld.mkvi b/Master/texmf-dist/tex/context/base/scrn-fld.mkvi
index 049ac92c353..4b4c9d0eeca 100644
--- a/Master/texmf-dist/tex/context/base/scrn-fld.mkvi
+++ b/Master/texmf-dist/tex/context/base/scrn-fld.mkvi
@@ -105,7 +105,7 @@
\installdirectcommandhandler \??forms {forms}
\appendtoks
- \ctxcommand{setformsmethod("\formsparameter\c!method")}%
+ \clf_setformsmethod{\formsparameter\c!method}%
\to \everysetupforms
\setupforms
@@ -113,7 +113,7 @@
\appendtoks
\iflocation
- \ctxcommand{exportformdata("\formsparameter\c!export")}%
+ \clf_exportformdata{\formsparameter\c!export}%
\fi
\to \everystoptext
@@ -127,7 +127,7 @@
{\processcommalist[#set]\scrn_symbols_preset_indeed}%
\def\scrn_symbols_preset_indeed#tag%
- {\doifobjectfoundelse{SYM}{#tag}
+ {\doifelseobjectfound{SYM}{#tag}
{}
{\settightobject{SYM}{#tag}\hbox{\symbol[#tag]}% % todo: set this as immediate xform
\page_otr_add_special_content{\hskip-\maxdimen\getobject{SYM}{#tag}}}} % and then force it into the file
@@ -177,23 +177,23 @@
\appendtoks % we cannot use parent .. maybe s!parent has to change
\ifx\currentfieldbodyparent\empty
\scrn_field_check_category
- \ctxcommand{definefield{
- name = "\currentfieldbody",
- alternative = "normal",
- type = "\fieldbodyparameter\c!type",
- category = "\fieldbodyparameter\c!category",
- values = \!!bs\fieldbodyparameter\c!values\!!es,
- default = \!!bs\fieldbodyparameter\c!default\!!es
- }}%
+ \clf_definefield
+ name {\currentfieldbody}%
+ alternative {normal}%
+ type {\fieldbodyparameter\c!type}%
+ category {\fieldbodyparameter\c!category}%
+ values {\fieldbodyparameter\c!values}%
+ default {\fieldbodyparameter\c!default}%
+ \relax
\else
- \ctxcommand{clonefield{
- children = "\currentfieldbody",
- alternative = "clone",
- parent = "\currentfieldbodyparent",
- category = "\fieldbodyparameter\c!category",
- values = \!!bs\fieldbodyparameter\c!values\!!es,
- default = \!!bs\fieldbodyparameter\c!default\!!es
- }}%
+ \clf_clonefield
+ children {\currentfieldbody}%
+ alternative {clone}%
+ parent {\currentfieldbodyparent}%
+ category {\fieldbodyparameter\c!category}%
+ values {\fieldbodyparameter\c!values}%
+ default {\fieldbodyparameter\c!default}%
+ \relax
\fi
\to \everydefinefieldbody
@@ -224,43 +224,46 @@
% == \edef\currentfieldbackgroundcolorvalue{\thecolorattribute\currentfieldbackgroundcolor}%
\fi
\usefieldbodystyleandcolor\c!style\c!color
- \ctxcommand{insertfield("\currentfieldbody", {
- title = "\currentfieldbody",
- width = \number\dimexpr\fieldbodyparameter\c!width \relax,
- height = \number\dimexpr\fieldbodyparameter\c!height\relax,
- depth = \number\dimexpr\fieldbodyparameter\c!depth \relax,
- align = "\fieldbodyparameter\c!align",
- length = "\fieldbodyparameter\c!n",
- fontstyle = "\fontstyle",
- fontalternative = "\fontalternative",
- fontsize = "\fontbody",
- fontsymbol = "\fieldbodyparameter\c!symbol",
- color = "\fieldbodyparameter\c!color",
- colorvalue = \number\attribute\colorattribute,
- \ifx\currentfieldbackgroundcolor\empty \else
- backgroundcolor = "\currentfieldbackgroundcolor",
- backgroundcolorvalue = "\currentfieldbackgroundcolorvalue",
- \fi
- \ifx\currentfieldframecolor\empty \else
- framecolor = "\currentfieldframecolor",
- framecolorvalue = "\currentfieldframecolorvalue",
- \fi
- layer = "\fieldbodyparameter\c!fieldlayer",
- option = "\fieldbodyparameter\c!option",
- align = "\fieldbodyparameter\c!align",
- clickin = "\fieldbodyparameter\c!clickin",
- clickout = "\fieldbodyparameter\c!clickout",
- regionin = "\fieldbodyparameter\c!regionin",
- regionout = "\fieldbodyparameter\c!regionout",
- afterkey = "\fieldbodyparameter\c!afterkey",
- format = "\fieldbodyparameter\c!format",
- validate = "\fieldbodyparameter\c!validate",
- calculate = "\fieldbodyparameter\c!calculate",
- focusin = "\fieldbodyparameter\c!focusin",
- focusout = "\fieldbodyparameter\c!focusout",
- openpage = "\fieldbodyparameter\c!openpage",
- closepage = "\fieldbodyparameter\c!closepage",
- })}}
+ \clf_insertfield
+ {\currentfieldbody}%
+ {%
+ title {\currentfieldbody}
+ width \dimexpr\fieldbodyparameter\c!width \relax
+ height \dimexpr\fieldbodyparameter\c!height\relax
+ depth \dimexpr\fieldbodyparameter\c!depth \relax
+ align {\fieldbodyparameter\c!align}%
+ length {\fieldbodyparameter\c!n}%
+ fontstyle {\fontstyle}%
+ fontalternative {\fontalternative}%
+ fontsize {\fontbody}%
+ fontsymbol {\fieldbodyparameter\c!symbol}%
+ color {\fieldbodyparameter\c!color}%
+ colorvalue \attribute\colorattribute
+ \ifx\currentfieldbackgroundcolor\empty \else
+ backgroundcolor {\currentfieldbackgroundcolor}%
+ backgroundcolorvalue \numexpr\currentfieldbackgroundcolorvalue\relax
+ \fi
+ \ifx\currentfieldframecolor\empty \else
+ framecolor {\currentfieldframecolor}%
+ framecolorvalue \numexpr\currentfieldframecolorvalue\relax
+ \fi
+ layer {\fieldbodyparameter\c!fieldlayer}%
+ option {\fieldbodyparameter\c!option}%
+ align {\fieldbodyparameter\c!align}%
+ clickin {\fieldbodyparameter\c!clickin}%
+ clickout {\fieldbodyparameter\c!clickout}%
+ regionin {\fieldbodyparameter\c!regionin}%
+ regionout {\fieldbodyparameter\c!regionout}%
+ afterkey {\fieldbodyparameter\c!afterkey}%
+ format {\fieldbodyparameter\c!format}%
+ validate {\fieldbodyparameter\c!validate}%
+ calculate {\fieldbodyparameter\c!calculate}%
+ focusin {\fieldbodyparameter\c!focusin}%
+ focusout {\fieldbodyparameter\c!focusout}%
+ openpage {\fieldbodyparameter\c!openpage}%
+ closepage {\fieldbodyparameter\c!closepage}%
+ }%
+ \relax}
%D The sets are used in grouped calculations.
%D
@@ -270,16 +273,20 @@
{\dodoubleempty\scrn_field_define_set}
\def\scrn_field_define_set[#tag][#list]%
- {\ctxcommand{definefieldset("#tag","#list")}}
+ {\clf_definefieldset{#tag}{#list}}
\let\dodefinefieldset\definefieldbodyset % compatibility
%D A few testing macros:
-\def\doiffieldbodyelse #tag{\ctxcommand{doiffieldelse("#tag")}}
-\def\doiffieldcategoryelse#tag{\ctxcommand{doiffieldcategoryelse("#tag")}}
+\def\doifelsefieldbody #tag{\clf_doifelsefield{#tag}}
+\def\doifelsefieldcategory#tag{\clf_doifelsefieldcategory{#tag}}
+
+\let\doiffieldbodyelse \doifelsefieldbody
+\let\doiffieldcategoryelse\doifelsefieldcategory
-\let\doiffieldelse\doiffieldbodyelse % compatibility
+\let\doiffieldelse \doifelsefieldbody % compatibility / will be dropped
+\let\doifelsefield \doifelsefieldbody % compatibility / will be dropped
%D We still support the traditional method of defining fields:
%D
@@ -365,7 +372,7 @@
\def\scrn_field_fit[#tag][#settings]%
{\iflocation
\begingroup
- \edef\currentdefaultfieldvalue{\ctxcommand{getdefaultfieldvalue("#tag")}}%
+ \edef\currentdefaultfieldvalue{\clf_getdefaultfieldvalue{#tag}}%
\setbox\b_scrn_field_fit_symbol\hbox{\symbol[\currentdefaultfieldvalue]}%
\fitfieldframed
{\fieldbody[#tag]
@@ -494,7 +501,7 @@
\scrn_field_load_scripts
\edef\currentfieldbody {#tag}%
\edef\currentfieldlabel {#label}%
- \edef\currentfieldcategory{\ctxcommand{getfieldcategory("#tag")}}%
+ \edef\currentfieldcategory{\clf_getfieldcategory{#tag}}%
\ifx\currentfieldlabel\empty
\let\currentfieldlabel\currentfieldbody
\fi
@@ -679,7 +686,7 @@
\edef\currenttooltipname{tooltip:\number\c_scrn_tooltip_n}%
\setbox\b_scrn_tooltip_anchor\hbox
{\strut#anchortext}%
- \doifassignmentelse{#settings}
+ \doifelseassignment{#settings}
{\setupcurrenttooltip[#settings]}%
{\setupcurrenttooltip[\c!location=#settings]}%
\setbox\b_scrn_tooltip_text\hbox
@@ -740,6 +747,8 @@
%D \goto{walk field}[Walk{mine}]
%D \stoptyping
+% todo: expand #symbols
+
\unexpanded\def\definefieldstack
{\dotripleargument\scrn_fieldstack_define}
@@ -868,7 +877,7 @@
\setvalue{pushbutton:#tag}{\scrn_pushbutton_handle{#tag}{#settings}}}
\def\scrn_pushbutton_define_variant#tag#variant#content%
- {\doifsymboldefinedelse{pushsymbol:#tag:#variant}
+ {\doifelsesymboldefined{pushsymbol:#tag:#variant}
\donothing
{\definesymbol[pushsymbol:#tag:#variant][{#content}]}}
@@ -975,7 +984,7 @@
\setupcurrentinteractionmenu[#settings]%
\let\scrn_rollbutton_symbol\scrn_rollbutton_symbol_m
\else
- \doifassignmentelse{#tag}
+ \doifelseassignment{#tag}
{\let\currentbutton\empty
\setupcurrentbutton[#tag]%
\let\scrn_rollbutton_symbol\scrn_rollbutton_symbol_b}%
diff --git a/Master/texmf-dist/tex/context/base/scrn-hlp.lua b/Master/texmf-dist/tex/context/base/scrn-hlp.lua
index d344ce2802c..99c0565a8b7 100644
--- a/Master/texmf-dist/tex/context/base/scrn-hlp.lua
+++ b/Master/texmf-dist/tex/context/base/scrn-hlp.lua
@@ -6,13 +6,15 @@ if not modules then modules = { } end modules ['scrn-hlp'] = {
license = "see context related readme files"
}
-local format = string.format
+local tonumber = tonumber
local help = { }
interactions.help = help
local context = context
-local commands = commands
+local implement = interfaces.implement
+
+local formatters = string.formatters
local a_help = attributes.private("help")
@@ -48,21 +50,26 @@ local helpscript = [[
local template = "javascript(Hide_All_Help{help:}),action(show{help:%s})"
-function help.register(number,name,box)
- if helpscript then
- interactions.javascripts.setpreamble("HelpTexts",helpscript)
- helpscript = false
- end
- local b = copy_nodelist(texgetbox(box))
- register_list(b)
- data[number] = b
- if name and name ~= "" then
- references[name] = number
- structures.references.define("",name,format(template,number))
+local function register(specification)
+ local number = specification.number
+ local name = specification.name
+ local box = specification.box
+ if number and name and box then
+ if helpscript then
+ interactions.javascripts.setpreamble("HelpTexts",helpscript)
+ helpscript = false
+ end
+ local b = copy_nodelist(texgetbox(box))
+ register_list(b)
+ data[number] = b
+ if name and name ~= "" then
+ references[name] = number
+ structures.references.define("",name,formatters[template](number))
+ end
end
end
-local function collect(head,used)
+local function collectused(head,used)
while head do
local id = head.id
if id == hlist_code then
@@ -74,51 +81,77 @@ local function collect(head,used)
used[#used+1] = a
end
else
- used = collect(head.list,used)
+ used = collectused(head.list,used)
end
elseif id == vlist_code then
- used = collect(head.list,used)
+ used = collectused(head.list,used)
end
head = head.next
end
return used
end
-function help.collect(box)
+local function collect(box)
if next(data) then
- return collect(texgetbox(box).list)
+ return collectused(texgetbox(box).list)
end
end
-commands.registerhelp = help.register
-
-function commands.collecthelp(box)
- local used = help.collect(box)
- if used then
- local done = { }
- context.startoverlay()
- for i=1,#used do
- local d = data[used[i]]
- if d and not done[d] then
- local box = hpack_nodelist(copy_nodelist(d))
- context(false,box)
- done[d] = true
- else
- -- error
+local function reference(name)
+ return references[name] or tonumber(name) or 0
+end
+
+help.register = register
+help.collect = collect
+help.reference = reference
+
+implement {
+ name = "registerhelp",
+ actions = register,
+ arguments = {
+ {
+ { "number", "integer" },
+ { "name" },
+ { "box" , "integer" }
+ }
+ }
+}
+
+implement {
+ name = "collecthelp",
+ arguments = "integer",
+ actions = function(box)
+ local used = collect(box)
+ if used then
+ local done = { }
+ context.startoverlay()
+ for i=1,#used do
+ local d = data[used[i]]
+ if d and not done[d] then
+ local box = hpack_nodelist(copy_nodelist(d))
+ context(false,box)
+ done[d] = true
+ else
+ -- error
+ end
end
+ context.stopoverlay()
end
- context.stopoverlay()
end
-end
-
-function help.reference(name)
- return references[name] or tonumber(name) or 0
-end
+}
-function commands.helpreference(name)
- context(references[name] or tonumber(name) or 0)
-end
+implement {
+ name = "helpreference",
+ arguments = "string",
+ actions = function(name)
+ context(reference(name))
+ end
+}
-function commands.helpaction(name)
- context(template,references[name] or tonumber(name) or 0)
-end
+implement {
+ name = "helpaction",
+ arguments = "string",
+ actions = function(name)
+ context(template,reference(name))
+ end
+}
diff --git a/Master/texmf-dist/tex/context/base/scrn-hlp.mkvi b/Master/texmf-dist/tex/context/base/scrn-hlp.mkvi
index f5a78fb0891..eca79c90a5b 100644
--- a/Master/texmf-dist/tex/context/base/scrn-hlp.mkvi
+++ b/Master/texmf-dist/tex/context/base/scrn-hlp.mkvi
@@ -130,25 +130,31 @@
\c!values=\currenthelpname]%
\setbox\b_scrn_help_box\hbox
{\fieldbody[\currenthelpname]}%
- \ctxcommand{registerhelp(\number\c_scrn_help_n,"\currenthelpreference",\number\b_scrn_help_box)}}
+ \clf_registerhelp
+ number \c_scrn_help_n
+ name {\currenthelpreference}%
+ box \b_scrn_help_box
+ \relax}
-\def\doifelsehelp
+\unexpanded\def\doifelsehelp
{\ifcase\c_scrn_help_n
\expandafter\firstoftwoarguments
\else
\expandafter\secondoftwoarguments
\fi}
-\def\placehelp % was \helpdata
+\let\doifhelpelse\doifelsehelp
+
+\unexpanded\def\placehelp % was \helpdata
{\ifinpagebody\ifcase\c_scrn_help_n\else
- \ctxcommand{collecthelp(255)}% rather hard coded ... bad
+ \clf_collecthelp\normalpagebox
\fi\fi}
\def\helpreference#category%
- {\ctxcommand{helpreference("#category")}}
+ {\clf_helpreference{#category}}
\def\helpaction#category%
- {\ctxcommand{helpaction("#category")}}
+ {\clf_helpaction{#category}}
\unexpanded\def\helpsignal#category%
{\hbox attr \helpattribute \helpreference{#category}{}}
diff --git a/Master/texmf-dist/tex/context/base/scrn-ini.lua b/Master/texmf-dist/tex/context/base/scrn-ini.lua
index 4831408f983..ce9f9f71b06 100644
--- a/Master/texmf-dist/tex/context/base/scrn-ini.lua
+++ b/Master/texmf-dist/tex/context/base/scrn-ini.lua
@@ -16,7 +16,7 @@ local codeinjections = backends.codeinjections
local identitydata = { }
-local function setupidentity(specification)
+function general.setupidentity(specification)
for k, v in next, specification do
identitydata[k] = v
end
@@ -27,6 +27,17 @@ function general.getidentity()
return identitydata
end
-general.setupidentity = setupidentity
-
-commands.setupidentity = setupidentity
+interfaces.implement {
+ name = "setupidentity",
+ actions = general.setupidentity,
+ arguments = {
+ {
+ { "title" },
+ { "subtitle" },
+ { "author" },
+ { "creator" },
+ { "date" },
+ { "keywords" },
+ }
+ }
+}
diff --git a/Master/texmf-dist/tex/context/base/scrn-ini.mkvi b/Master/texmf-dist/tex/context/base/scrn-ini.mkvi
index f5b29462436..2ed822c6e96 100644
--- a/Master/texmf-dist/tex/context/base/scrn-ini.mkvi
+++ b/Master/texmf-dist/tex/context/base/scrn-ini.mkvi
@@ -51,6 +51,8 @@
\expandafter\secondoftwoarguments
\fi}
+\let\doiflocationelse\doifelselocation
+
\setupinteraction
[\c!state=\v!stop]
@@ -176,14 +178,14 @@
%D Identity
\def\scrn_identity_synchronize
- {\ctxcommand{setupidentity{
- title = \!!bs\interactionparameter\c!title\!!es,
- subtitle = \!!bs\interactionparameter\c!subtitle\!!es,
- author = \!!bs\interactionparameter\c!author\!!es,
- creator = \!!bs ConTeXt - \contextversion\!!es,
- date = \!!bs\interactionparameter\c!date\!!es,
- keywords = \!!bs\interactionparameter\c!keyword\!!es,
- }}}
+ {\clf_setupidentity
+ title {\interactionparameter\c!title}%
+ subtitle {\interactionparameter\c!subtitle}%
+ author {\interactionparameter\c!author}%
+ creator { ConTeXt - \contextversion}%
+ date {\interactionparameter\c!date}%
+ keywords {\interactionparameter\c!keyword}%
+ \relax}
\appendtoks
\scrn_identity_synchronize
diff --git a/Master/texmf-dist/tex/context/base/scrn-pag.lua b/Master/texmf-dist/tex/context/base/scrn-pag.lua
index 7003d028508..4d7b388ee0c 100644
--- a/Master/texmf-dist/tex/context/base/scrn-pag.lua
+++ b/Master/texmf-dist/tex/context/base/scrn-pag.lua
@@ -10,18 +10,43 @@ interactions = interactions or { }
interactions.pages = interactions.pages or { }
local pages = interactions.pages
+local implement = interfaces.implement
+
local codeinjections = backends.codeinjections
-local function setupcanvas(specification)
+function pages.setupcanvas(specification)
codeinjections.setupcanvas(specification)
end
-local function setpagetransition(specification)
+function pages.setpagetransition(specification)
codeinjections.setpagetransition(specification)
end
-pages.setupcanvas = setupcanvas
-pages.setpagetransition = setpagetransition
+implement {
+ name = "setupcanvas",
+ actions = pages.setupcanvas,
+ arguments = {
+ {
+ { "mode" },
+ { "singlesided", "boolean" },
+ { "doublesided", "boolean" },
+ { "leftoffset", "dimen" },
+ { "topoffset", "dimen" },
+ { "width", "dimen" },
+ { "height", "dimen" },
+ { "paperwidth", "dimen" },
+ { "paperheight", "dimen" },
+ }
+ }
+}
-commands.setupcanvas = setupcanvas
-commands.setpagetransition = setpagetransition
+implement {
+ name = "setpagetransition",
+ actions = pages.setpagetransition,
+ arguments = {
+ {
+ { "n" },
+ { "delay", "integer" },
+ }
+ }
+}
diff --git a/Master/texmf-dist/tex/context/base/scrn-pag.mkvi b/Master/texmf-dist/tex/context/base/scrn-pag.mkvi
index 5bbdadda885..3dfcd65c5ff 100644
--- a/Master/texmf-dist/tex/context/base/scrn-pag.mkvi
+++ b/Master/texmf-dist/tex/context/base/scrn-pag.mkvi
@@ -124,30 +124,49 @@
%
% \starttext \input ward \stoptext
-\def\scrn_canvas_synchronize_simple
- {\ctxcommand{setupcanvas{
- paperwidth = \number\printpaperwidth,
- paperheight = \number\printpaperheight
- }}}
+\let\scrn_canvas_synchronize_simple \relax
+\let\scrn_canvas_synchronize_complex\relax
-\def\scrn_canvas_synchronize_complex
+\appendtoks
+ \global\let\scrn_canvas_synchronize_simple \scrn_canvas_synchronize_simple_indeed
+ \global\let\scrn_canvas_synchronize_complex\scrn_canvas_synchronize_complex_indeed
+\to \everysetuplayout
+
+\def\scrn_canvas_synchronize_simple_indeed
+ {\clf_setupcanvas
+ paperwidth \printpaperwidth
+ paperheight \printpaperheight
+ \relax
+ %\global\let\scrn_canvas_synchronize_simple \relax
+ \global\let\scrn_canvas_synchronize_complex\relax}
+
+\def\scrn_canvas_synchronize_complex_indeed
{\scrn_canvas_calculate % otherwise we need to hook it into setuppage etc
- \ctxcommand{setupcanvas{
- mode = "\interactionscreenparameter\c!option",
- singlesided = \ifsinglesided true\else false\fi,
- doublesided = \ifdoublesided true\else false\fi,
- leftoffset = \number\canvasbackoffset,
- topoffset = \number\canvastopoffset,
- width = \number\canvaswidth,
- height = \number\canvasheight,
- paperwidth = \number\canvasmaxwidth,
- paperheight = \number\canvasmaxheight
- }}}
+ \clf_setupcanvas
+ mode {\interactionscreenparameter\c!option}%
+ singlesided \ifsinglesided true\else false\fi\space
+ doublesided \ifdoublesided true\else false\fi\space
+ leftoffset \canvasbackoffset
+ topoffset \canvastopoffset
+ width \canvaswidth
+ height \canvasheight
+ paperwidth \canvasmaxwidth
+ paperheight \canvasmaxheight
+ \relax
+ %\global\let\scrn_canvas_synchronize_simple \relax
+ \global\let\scrn_canvas_synchronize_complex\relax}
\appendtoks
- \doifcommonelse{\interactionscreenparameter\c!option}{\v!max,\v!fit}%
- {\global\settrue \c_scrn_canvas_tight_page}%
- {\global\setfalse\c_scrn_canvas_tight_page}%
+ \begingroup
+ \edef\p_option{\interactionscreenparameter\c!option}%
+ \ifx\p_option\v!max
+ \global\settrue \c_scrn_canvas_tight_page
+ \else\ifx\p_option\v!fit
+ \global\settrue \c_scrn_canvas_tight_page
+ \else
+ \global\setfalse\c_scrn_canvas_tight_page
+ \fi\fi
+ \endgroup
\to \everysetupinteractionscreen
\setupinteractionscreen
@@ -159,6 +178,11 @@
\c!topspace=\topspace,
\c!option=\v!auto]
+\appendtoks
+ \global\let\scrn_canvas_synchronize_simple \scrn_canvas_synchronize_simple
+ \global\let\scrn_canvas_synchronize_complex\scrn_canvas_synchronize_complex
+\to \everysetupinteractionscreen
+
%D Conditional page breaks:
\unexpanded\def\screen
@@ -177,7 +201,10 @@
{\dosingleempty\scrn_transitions_setup}
\def\scrn_transitions_setup[#list]%
- {\edef\scrn_transitions_list{#list}}
+ {\edef\scrn_transitions_list{#list}%
+ \ifx\scrn_transitions_list\v!reset
+ \let\scrn_transitions_list\empty
+ \fi}
\def\scrn_transitions_set
{\iflocation \ifx\scrn_transitions_list\empty \else
@@ -187,10 +214,10 @@
\def\scrn_transitions_set_indeed
{\begingroup
\edef\currentinteractionscreendelay{\interactionscreenparameter\c!delay}%
- \ctxcommand{setpagetransition{
- n = "\scrn_transitions_list",
- delay = "\ifx\currentinteractionscreendelay\v!none 0\else\currentinteractionscreendelay\fi"
- }}%
+ \clf_setpagetransition
+ n {\scrn_transitions_list}%
+ delay \ifx\currentinteractionscreendelay\v!none \zerocount\else\currentinteractionscreendelay\fi
+ \relax
\endgroup}
\prependtoks
diff --git a/Master/texmf-dist/tex/context/base/scrn-ref.lua b/Master/texmf-dist/tex/context/base/scrn-ref.lua
index df71b6a97fe..c1fc9487138 100644
--- a/Master/texmf-dist/tex/context/base/scrn-ref.lua
+++ b/Master/texmf-dist/tex/context/base/scrn-ref.lua
@@ -15,6 +15,8 @@ local codeinjections = backends.codeinjections
local expandcurrent = structures.references.expandcurrent
local identify = structures.references.identify
+local implement = interfaces.implement
+
local function check(what)
if what and what ~= "" then
local set, bug = identify("",what)
@@ -54,12 +56,12 @@ local function setclosepageaction(close)
end
end
-references.setopendocument = setopendocumentaction
-references.setclosedocument = setclosedocumentaction
-references.setopenpage = setopenpageaction
-references.setclosepage = setclosepageaction
+references.setopendocument = setopendocumentaction
+references.setclosedocument = setclosedocumentaction
+references.setopenpage = setopenpageaction
+references.setclosepage = setclosepageaction
-commands.setopendocumentaction = setopendocumentaction
-commands.setclosedocumentaction = setclosedocumentaction
-commands.setopenpageaction = setopenpageaction
-commands.setclosepageaction = setclosepageaction
+implement { name = "setopendocumentaction", arguments = "string", actions = setopendocumentaction }
+implement { name = "setclosedocumentaction", arguments = "string", actions = setclosedocumentaction }
+implement { name = "setopenpageaction", arguments = "string", actions = setopenpageaction }
+implement { name = "setclosepageaction", arguments = "string", actions = setclosepageaction }
diff --git a/Master/texmf-dist/tex/context/base/scrn-ref.mkvi b/Master/texmf-dist/tex/context/base/scrn-ref.mkvi
index a06ba1ad8fc..2b15b46778e 100644
--- a/Master/texmf-dist/tex/context/base/scrn-ref.mkvi
+++ b/Master/texmf-dist/tex/context/base/scrn-ref.mkvi
@@ -25,7 +25,7 @@
\to \everysetupinteraction
\def\scrn_reference_enable_page_destinations % no reset
- {\ctxlua{structures.references.setinnermethod("\interactionparameter\c!page")}}
+ {\clf_setinnerreferencemethod{\interactionparameter\c!page}}
\setupinteraction % start fit page and reset form
[\c!page=\v!no,
@@ -34,7 +34,7 @@
\c!focus=\v!fit,
\c!calculate=,
% rendering:
- \c!width=1em,
+ \c!width=\emwidth,
\c!height=\zeropoint,
\c!depth=\zeropoint,
\c!symbolset=]
@@ -46,10 +46,10 @@
\edef\currentinteractionopenaction {\interactionparameter\c!openaction }%
\edef\currentinteractioncloseaction{\interactionparameter\c!closeaction}%
\ifx\currentinteractionopenaction\empty \else
- \ctxcommand{setopendocumentaction("\currentinteractionopenaction")}%
+ \clf_setopendocumentaction{\currentinteractionopenaction}%
\fi
\ifx\currentinteractioncloseaction\empty \else
- \ctxcommand{setclosedocumentaction("\currentinteractioncloseaction")}%
+ \clf_setclosedocumentaction{\currentinteractioncloseaction}%
\fi
\glet\scrn_reference_set_text_actions\relax
\fi}
@@ -59,10 +59,10 @@
\edef\currentinteractionopenpageaction {\interactionparameter\c!openpageaction }%
\edef\currentinteractionclosepageaction{\interactionparameter\c!closepageaction}%
\ifx\currentinteractionopenpageaction\empty \else
- \ctxcommand{setopenpageaction("\currentinteractionopenpageaction")}%
+ \clf_setopenpageaction{\currentinteractionopenpageaction}%
\fi
\ifx\currentinteractionclosepageaction\empty \else
- \ctxcommand{setclosepageaction("\currentinteractionclosepageaction")}%
+ \clf_setclosepageaction{\currentinteractionclosepageaction}%
\fi
\fi}
@@ -73,7 +73,7 @@
\def\scrn_reference_enable_references
{\ifproductionrun
- \ctxlua{structures.references.enableinteraction()}%
+ \clf_enableinteraction % only once anyway
\glet\scrn_reference_enable_references\relax
\fi}
diff --git a/Master/texmf-dist/tex/context/base/scrn-wid.lua b/Master/texmf-dist/tex/context/base/scrn-wid.lua
index 5b319b07ea7..72c9bc733aa 100644
--- a/Master/texmf-dist/tex/context/base/scrn-wid.lua
+++ b/Master/texmf-dist/tex/context/base/scrn-wid.lua
@@ -10,6 +10,7 @@ interactions = interactions or { }
local interactions = interactions
local context = context
+local implement = interfaces.implement
local allocate = utilities.storage.allocate
@@ -42,9 +43,13 @@ local report_attachments = logs.reporter("widgets","attachments")
-- Symbols
-function commands.presetsymbollist(list)
- codeinjections.presetsymbollist(list)
-end
+implement {
+ name = "presetsymbollist",
+ arguments = "string",
+ actions = function(list)
+ codeinjections.presetsymbollist(list)
+ end
+}
-- Attachments
--
@@ -108,11 +113,51 @@ function attachments.insert(specification)
return nodeinjections.attachfile(specification)
end
-commands.registerattachment = attachments.register
+implement {
+ name = "registerattachment",
+ actions = attachments.register,
+ arguments = {
+ {
+ { "tag" },
+ { "registered" },
+ { "title" },
+ { "subtitle" },
+ { "author" },
+ { "file" },
+ { "name" },
+ { "buffer" },
+ }
+ }
+}
-function commands.insertattachment(specification)
- texsetbox("b_scrn_attachment_link",(attachments.insert(specification)))
-end
+implement {
+ name = "insertattachment",
+ actions = function(specification)
+ texsetbox("b_scrn_attachment_link",(attachments.insert(specification)))
+ end,
+ arguments = {
+ {
+ { "tag" },
+ { "registered" },
+ { "method" },
+ { "width", "dimen" },
+ { "height", "dimen" },
+ { "depth", "dimen" },
+ { "colormodel", "integer" },
+ { "colorvalue", "integer" },
+ { "color" },
+ { "transparencyvalue", "integer" },
+ { "symbol" },
+ { "layer" },
+ { "title" },
+ { "subtitle" },
+ { "author" },
+ { "file" },
+ { "name" },
+ { "buffer" },
+ }
+ }
+}
-- Comment
@@ -124,9 +169,32 @@ function comments.insert(specification)
return nodeinjections.comment(specification)
end
-function commands.insertcomment(specification)
- texsetbox("b_scrn_comment_link",(comments.insert(specification)))
-end
+implement {
+ name = "insertcomment",
+ actions = function(specification)
+ texsetbox("b_scrn_comment_link",(comments.insert(specification)))
+ end,
+ arguments = {
+ {
+ { "tag" },
+ { "title" },
+ { "subtitle" },
+ { "author" },
+ { "width", "dimen" },
+ { "height", "dimen" },
+ { "depth", "dimen" },
+ { "nx" },
+ { "ny" },
+ { "colormodel", "integer" },
+ { "colorvalue", "integer" },
+ { "transparencyvalue", "integer" },
+ { "option" },
+ { "symbol" },
+ { "buffer" },
+ { "layer" },
+ }
+ }
+}
-- Soundclips
@@ -153,8 +221,27 @@ function soundclips.insert(tag)
end
end
-commands.registersoundclip = soundclips.register
-commands.insertsoundclip = soundclips.insert
+implement {
+ name = registersoundclip,
+ actions = soundclips.register,
+ arguments = {
+ {
+ { "tag" },
+ { "file" }
+ }
+ }
+}
+
+implement {
+ name = insertsoundclip,
+ actions = soundclips.insert,
+ arguments = {
+ {
+ { "tag" },
+ { "repeat" }
+ }
+ }
+}
-- Renderings
@@ -175,48 +262,84 @@ function renderings.rendering(label)
end
end
-local function var(label,key)
+function renderings.var(label,key)
local rn = renderings[label]
return rn and rn[key] or ""
end
-renderings.var = var
-
-function commands.renderingvar(label,key)
- context(var(label,key))
-end
+implement {
+ name = "renderingvar",
+ actions = { renderings.var, context },
+ arguments = { "string", "string" }
+}
-commands.registerrendering = renderings.register
+implement {
+ name = "registerrendering",
+ actions = renderings.register,
+ arguments = {
+ {
+ { "type" },
+ { "label" },
+ { "mime" },
+ { "filename" },
+ { "option" },
+ }
+ }
+}
-- Rendering:
-function commands.insertrenderingwindow(specification)
- codeinjections.insertrenderingwindow(specification)
-end
+implement {
+ name = "insertrenderingwindow",
+ actions = function(specification)
+ codeinjections.insertrenderingwindow(specification)
+ end,
+ arguments = {
+ {
+ { "label" },
+ { "width", "dimen" },
+ { "height", "dimen" },
+ { "option" },
+ { "page", "integer" },
+ }
+ }
+}
-- Linkedlists (only a context interface)
-function commands.definelinkedlist(tag)
- -- no need
-end
+implement {
+ name = "definelinkedlist",
+ arguments = "string",
+ actions = function(tag)
+ -- no need
+ end
+}
-function commands.enhancelinkedlist(tag,n)
- local ll = jobpasses.gettobesaved(tag)
- if ll then
- ll[n] = texgetcount("realpageno")
- end
-end
+implement {
+ name = "enhancelinkedlist",
+ arguments = { "string", "integer" },
+ actions = function(tag,n)
+ local ll = jobpasses.gettobesaved(tag)
+ if ll then
+ ll[n] = texgetcount("realpageno")
+ end
+ end
+}
-function commands.addlinklistelement(tag)
- local tobesaved = jobpasses.gettobesaved(tag)
- local collected = jobpasses.getcollected(tag) or { }
- local currentlink = #tobesaved + 1
- local noflinks = #collected
- tobesaved[currentlink] = 0
- local f = collected[1] or 0
- local l = collected[noflinks] or 0
- local p = collected[currentlink-1] or f
- local n = collected[currentlink+1] or l
- context.setlinkedlistproperties(currentlink,noflinks,f,p,n,l)
- -- context.ctxlatelua(function() commands.enhancelinkedlist(tag,currentlink) end)
-end
+implement {
+ name = "addlinklistelement",
+ arguments = "string",
+ actions = function(tag)
+ local tobesaved = jobpasses.gettobesaved(tag)
+ local collected = jobpasses.getcollected(tag) or { }
+ local currentlink = #tobesaved + 1
+ local noflinks = #collected
+ tobesaved[currentlink] = 0
+ local f = collected[1] or 0
+ local l = collected[noflinks] or 0
+ local p = collected[currentlink-1] or f
+ local n = collected[currentlink+1] or l
+ context.setlinkedlistproperties(currentlink,noflinks,f,p,n,l)
+ -- context.ctxlatelua(function() commands.enhancelinkedlist(tag,currentlink) end)
+ end
+}
diff --git a/Master/texmf-dist/tex/context/base/scrn-wid.mkvi b/Master/texmf-dist/tex/context/base/scrn-wid.mkvi
index 8dcc7a86a23..57a4be27639 100644
--- a/Master/texmf-dist/tex/context/base/scrn-wid.mkvi
+++ b/Master/texmf-dist/tex/context/base/scrn-wid.mkvi
@@ -100,16 +100,16 @@
\begingroup
\def\currentattachment{_}%
\setupcurrentattachment[#settings,\s!parent=\??attachment]%
- \ctxcommand{registerattachment{
- tag = "#tag",
- registered = "#tag",
- title = "\attachmentparameter\c!title",
- subtitle = "\attachmentparameter\c!subtitle",
- author = "\attachmentparameter\c!author",
- file = "\attachmentparameter\c!file",
- name = "\attachmentparameter\c!name",
- buffer = "\attachmentparameter\c!buffer",
- }}%
+ \clf_registerattachment
+ tag {#tag}%
+ registered {#tag}%
+ title {\attachmentparameter\c!title}%
+ subtitle {\attachmentparameter\c!subtitle}%
+ author {\attachmentparameter\c!author}%
+ file {\attachmentparameter\c!file}%
+ name {\attachmentparameter\c!name}%
+ buffer {\attachmentparameter\c!buffer}%
+ \relax
\endgroup
\else
% todo
@@ -136,7 +136,7 @@
{\bgroup
\doifelsenothing{#registered}
{\scrn_attachment_inject[\v!auto][]}
- {\doifassignmentelse{#registered}
+ {\doifelseassignment{#registered}
{\scrn_attachment_inject[\v!auto][#registered]}
{\scrn_attachment_inject[#registered][#settings]}}%
\egroup}
@@ -162,7 +162,7 @@
{\bgroup
\doifelsenothing{#registered}
{\def\scrn_attachment_stop{\scrn_attachment_inject[\v!auto][\c!buffer=\v!attachment]\egroup}}%
- {\doifassignmentelse{#registered}
+ {\doifelseassignment{#registered}
{\def\scrn_attachment_stop{\scrn_attachment_inject[\v!auto][\c!buffer=\v!attachment,#registered]\egroup}}%
{\def\scrn_attachment_stop{\scrn_attachment_inject[#registered][\c!buffer=\v!attachment,#settings]\egroup}}}%
\grabbufferdatadirect\v!attachment{\e!start\currentattachment}{\e!stop\currentattachment}}
@@ -181,37 +181,37 @@
\edef\currentattachmentheight{\attachmentparameter\c!height}%
\edef\currentattachmentdepth {\attachmentparameter\c!depth }%
\ifx\currentattachmentsymbol\empty
- \ifx\currentattachmentwidth \v!fit\edef\currentattachmentwidth {.5em}\fi
- \ifx\currentattachmentheight\v!fit\edef\currentattachmentheight{.5em}\fi
+ \ifx\currentattachmentwidth \v!fit\edef\currentattachmentwidth {.5\emwidth}\fi
+ \ifx\currentattachmentheight\v!fit\edef\currentattachmentheight{.5\emwidth}\fi
\ifx\currentattachmentdepth \v!fit\let \currentattachmentdepth \zeropoint\fi
\else
- \ctxcommand{presetsymbollist("\attachmentparameter\c!symbol")}%
+ \clf_presetsymbollist{\attachmentparameter\c!symbol}%
% we cannot yet ask for the wd/ht/dp of an xform else we could use those
\setbox\b_scrn_attachment_symbol\hbox{\symbol[\lastpredefinedsymbol]}%
\ifx\currentattachmentwidth \v!fit\edef\currentattachmentwidth {\wd\b_scrn_attachment_symbol}\fi
\ifx\currentattachmentheight\v!fit\edef\currentattachmentheight{\ht\b_scrn_attachment_symbol}\fi
\ifx\currentattachmentdepth \v!fit\edef\currentattachmentdepth {\dp\b_scrn_attachment_symbol}\fi
\fi
- \ctxcommand{insertattachment{
- tag = "\currentattachment",
- registered = "\currentattachmentregistered",
- width = \number\dimexpr\currentattachmentwidth \relax,
- height = \number\dimexpr\currentattachmentheight\relax,
- depth = \number\dimexpr\currentattachmentdepth \relax,
- color = "\attachmentparameter\c!color",
- colormodel = \number\attribute\colormodelattribute,
- colorvalue = \thecolorattribute{\attachmentparameter\c!color},
- transparencyvalue = \thetransparencyattribute{\attachmentparameter\c!color},
- symbol = "\currentattachmentsymbol",
- layer = "\attachmentparameter\c!textlayer",
+ \clf_insertattachment
+ tag {\currentattachment}%
+ registered {\currentattachmentregistered}%
+ width \dimexpr\currentattachmentwidth \relax
+ height \dimexpr\currentattachmentheight\relax
+ depth \dimexpr\currentattachmentdepth \relax
+ color {\attachmentparameter\c!color}%
+ colormodel \attribute\colormodelattribute
+ colorvalue \numexpr\thecolorattribute{\attachmentparameter\c!color}\relax % or are these chardefs
+ transparencyvalue \numexpr\thetransparencyattribute{\attachmentparameter\c!color}\relax % or are these chardefs
+ symbol {\currentattachmentsymbol}%
+ layer {\attachmentparameter\c!textlayer}%
% these will be overloaded by registered when available
- title = "\attachmentparameter\c!title",
- subtitle = "\attachmentparameter\c!subtitle",
- author = "\attachmentparameter\c!author",
- file = "\attachmentparameter\c!file",
- name = "\attachmentparameter\c!name",
- buffer = "\attachmentparameter\c!buffer",
- }}%
+ title {\attachmentparameter\c!title}%
+ subtitle {\attachmentparameter\c!subtitle}%
+ author {\attachmentparameter\c!author}%
+ file {\attachmentparameter\c!file}%
+ name {\attachmentparameter\c!name}%
+ buffer {\attachmentparameter\c!buffer}%
+ \relax
\setbox\b_scrn_attachment_link\hbox{\scrn_attachment_place}%
\wd\b_scrn_attachment_link\currentattachmentwidth
\ht\b_scrn_attachment_link\currentattachmentheight
@@ -219,11 +219,11 @@
\box\b_scrn_attachment_link}
\setvalue{\??attachmentmethod\v!hidden}%
- {\ctxcommand{insertattachment{
- tag = "\currentattachment",
- registered = "\currentattachmentregistered",
- method = "\v!hidden"
- }}}
+ {\clf_insertattachment
+ tag {\currentattachment}%
+ registered {\currentattachmentregistered}%
+ method {\v!hidden}%
+ \relax}
\def\scrn_attachment_place
{\executeifdefined
@@ -398,10 +398,10 @@
\scrn_comment_argument_ignore}
\def\scrn_comment_argument_indeed[#title][#settings]#text%
- {\doifassignmentelse{#title}
+ {\doifelseassignment{#title}
{\setupcurrentcomment[#title]}
{\setupcurrentcomment[\c!title=#title,#settings]}%
- \ctxcommand{assignbuffer("\v!comment",\!!bs#text\!!es)}% todo: expansion control, but expanded by default (xml)
+ \clf_assignbuffer{\v!comment}{#text}\catcodetable\relax% todo: expansion control, but expanded by default (xml)
\scrn_comment_inject
\ignorespaces}
@@ -421,7 +421,7 @@
\def\scrn_comment_start_indeed[#title][#settings]%
{\bgroup
- \doifassignmentelse{#title}
+ \doifelseassignment{#title}
{\setupcurrentcomment[#title]}
{\setupcurrentcomment[\c!title=#title,#settings]}%
\unexpanded\def\scrn_comment_stop{\scrn_comment_inject\egroup}%
@@ -447,35 +447,35 @@
\edef\currentcommentheight{\commentparameter\c!height}%
\edef\currentcommentdepth {\commentparameter\c!depth }%
\ifx\currentcommentsymbol\empty
- \ifx\currentcommentwidth \v!fit\edef\currentcommentwidth {.5em}\fi
- \ifx\currentcommentheight\v!fit\edef\currentcommentheight{.5em}\fi
+ \ifx\currentcommentwidth \v!fit\edef\currentcommentwidth {.5\emwidth}\fi
+ \ifx\currentcommentheight\v!fit\edef\currentcommentheight{.5\emwidth}\fi
\ifx\currentcommentdepth \v!fit\let \currentcommentdepth \zeropoint\fi
\else
- \ctxcommand{presetsymbollist("\commentparameter\c!symbol")}%
+ \clf_presetsymbollist{\commentparameter\c!symbol}%
% we cannot yet ask for the wd/ht/dp of an xform else we could use those
\setbox\b_scrn_comment_symbol\hbox{\symbol[\lastpredefinedsymbol]}%
\ifx\currentcommentwidth \v!fit\edef\currentcommentwidth {\wd\b_scrn_comment_symbol}\fi
\ifx\currentcommentheight\v!fit\edef\currentcommentheight{\ht\b_scrn_comment_symbol}\fi
\ifx\currentcommentdepth \v!fit\edef\currentcommentdepth {\dp\b_scrn_comment_symbol}\fi
\fi
- \ctxcommand{insertcomment{
- tag = "\currentcomment",
- title = "\commentparameter\c!title",
- subtitle = "\commentparameter\c!subtitle",
- author = "\commentparameter\c!author",
- width = \number\dimexpr\currentcommentwidth,
- height = \number\dimexpr\currentcommentheight,
- depth = \number\dimexpr\currentcommentdepth,
- nx = \commentparameter\c!nx,
- ny = \commentparameter\c!ny,
- colormodel = \number\attribute\colormodelattribute,
- colorvalue = \thecolorattribute{\commentparameter\c!color},
- transparencyvalue = \thetransparencyattribute{\commentparameter\c!color},
- option = "\commentparameter\c!option", % todo
- symbol = "\commentparameter\c!symbol",
- buffer = "\v!comment",
- layer = "\commentparameter\c!textlayer"
- }}%
+ \clf_insertcomment
+ tag {\currentcomment}%
+ title {\commentparameter\c!title}%
+ subtitle {\commentparameter\c!subtitle}%
+ author {\commentparameter\c!author}%
+ width \dimexpr\currentcommentwidth\relax
+ height \dimexpr\currentcommentheight\relax
+ depth \dimexpr\currentcommentdepth\relax
+ nx {\commentparameter\c!nx}%
+ ny {\commentparameter\c!ny}%
+ colormodel \attribute\colormodelattribute
+ colorvalue \numexpr\thecolorattribute{\commentparameter\c!color}\relax
+ transparencyvalue \numexpr\thetransparencyattribute{\commentparameter\c!color}\relax
+ option {\commentparameter\c!option}% % todo
+ symbol {\commentparameter\c!symbol}%
+ buffer {\v!comment}%
+ layer {\commentparameter\c!textlayer}%
+ \relax
\wd\b_scrn_comment_link\currentcommentwidth
\ht\b_scrn_comment_link\currentcommentheight
\dp\b_scrn_comment_link\currentcommentdepth
@@ -542,17 +542,17 @@
{\dodoubleargument\scrn_soundtrack_indeed}
\def\scrn_soundtrack_indeed[#tag][#filename]%
- {\ctxcommand{registersoundclip{
- tag = "#tag",
- file = "#filename"
- }}}
+ {\clf_registersoundclip
+ tag {#tag}%
+ file {#filename}%
+ \relax}
\def\checksoundtrack#tag% yet untested in mkiv (also move management to lua)
{\iflocation
- \ctxcommand{insertsoundclip{
- tag = "#tag",
- ["repeat"] = "\directexternalsoundtrackparameter\c!option", % todo: pass option as-is
- }}%
+ \clf_insertsoundclip
+ tag {#tag}%
+ repeat {\directexternalsoundtrackparameter\c!option}%
+ \relax
\fi}
%D Renderings (not yet tested in mkvi):
@@ -571,31 +571,31 @@
\unexpanded\def\setinternalrendering{\dodoubleempty \scrn_rendering_set}
\def\scrn_rendering_use[#tag][#mime][#file][#option]%
- {\ctxcommand{registerrendering{
- type = "external",
- label = "#tag",
- mime = "#mime",
- filename = "#file",
- option = "#option",
- }}}
+ {\clf_registerrendering
+ type {external}%
+ label {#tag}%
+ mime {#mime}%
+ filename {#file}%
+ option {#option}%
+ \relax}
\def\scrn_rendering_set[#tag][#option]% {content} % crappy
{\bgroup
\dowithnextbox
- {\ctxcommand{registerrendering{
- type = "internal",
- label = "#tag",
- mime = "IRO", % brrr
- filename = "#tag",
- option = "#option",
- }}%
+ {\clf_registerrendering
+ type {internal}%
+ label {#tag}%
+ mime {IRO}% brrr
+ filename {#tag}%
+ option {#option}%
+ \relax
\let\objectoffset\zeropoint
\setobject{IRO}{#tag}\hbox{\box\nextbox}%
\egroup}%
\hbox}
-\def\renderingtype #tag{\ctxcommand{renderingvar("#tag","type")}}
-\def\renderingoption#tag{\ctxcommand{renderingvar("#tag","option")}}
+\def\renderingtype #tag{\clf_renderingvar{#tag}{type}}
+\def\renderingoption#tag{\clf_renderingvar{#tag}{option}}
\newdimen\d_scrn_rendering_width \d_scrn_rendering_width 8cm
\newdimen\d_scrn_rendering_height \d_scrn_rendering_height 6cm
@@ -648,13 +648,14 @@
\letrenderingwindowparameter\c!offset\v!overlay
\inheritedrenderingwindowframed
{\vfill
- \ctxcommand{insertrenderingwindow {
- label = "\currentrendering",
- width = \number\d_scrn_rendering_width,
- height = \number\d_scrn_rendering_height,
- option = "\renderingoption\currentrendering",
- page = \number\m_scrn_rendering_page,
- }}\hfill}%
+ \clf_insertrenderingwindow
+ label {\currentrendering}%
+ width \d_scrn_rendering_width
+ height \d_scrn_rendering_height
+ option {\renderingoption\currentrendering}%
+ page \m_scrn_rendering_page
+ \relax
+ \hfill}%
\egroup}
%D Linkedlists (not tested in mkvi):
@@ -676,7 +677,7 @@
% \let\setupbutton\setuplinkedlists\setuplinkedlist
%
% \appendtoks
-% \ctxcommand{definelinkedlist("\currentlinkedlist")}%
+% \clf_definelinkedlist{\currentlinkedlist}%
% \to \everydefinelinkedlist
%
% \def\setlinkedlistproperties#1#2#3#4#5#6%
@@ -694,8 +695,8 @@
% \edef\currentlinkedlist{#1}%
% \ifcsname\??lk\currentlinkedlist\s!parent\endcsname
% \hskip\linkedlistparameter\c!distance
-% \ctxcommand{addlinklistelement("\currentlinkedlist")}%
-% \expanded{\ctxlatelua{commands.enhancelinkedlist("\currentlinkedlist",\currentlink)}}% can also be done at the lua end
+% \clf_addlinklistelement{\currentlinkedlist}%
+% \expanded{\ctxlatecommand{enhancelinkedlist("\currentlinkedlist",\currentlink)}}% can also be done at the lua end
% \dogotosomepage {\??lk\currentlinkedlist}\gotobegincharacter \firstlink
% \ifnum\noflinks>\plustwo
% \dogotosomepage{\??lk\currentlinkedlist}\gobackwardcharacter\previouslink
diff --git a/Master/texmf-dist/tex/context/base/scrp-ini.lua b/Master/texmf-dist/tex/context/base/scrp-ini.lua
index a6bfe4cf9e3..3c3517542d3 100644
--- a/Master/texmf-dist/tex/context/base/scrp-ini.lua
+++ b/Master/texmf-dist/tex/context/base/scrp-ini.lua
@@ -27,6 +27,8 @@ local texsetattribute = tex.setattribute
local nodecodes = nodes.nodecodes
local unsetvalue = attributes.unsetvalue
+local implement = interfaces.implement
+
local glyph_code = nodecodes.glyph
local glue_code = nodecodes.glue
@@ -475,18 +477,19 @@ function scripts.injectors.handler(head)
normal_process = handler.injector
end
if normal_process then
+ -- wrong: originals are indices !
local f = getfont(start)
if f ~= lastfont then
originals = fontdata[f].resources
if resources then
originals = resources.originals
else
- -- can't happen
+ originals = nil -- can't happen
end
lastfont = f
end
local c = getchar(start)
- if originals then
+ if originals and type(originals) == "number" then
c = originals[c] or c
end
local h = hash[c]
@@ -937,5 +940,22 @@ function autofontfeature.disable()
disableaction("processors","scripts.autofontfeature.handler")
end
-commands.enableautofontscript = autofontfeature.enable
-commands.disableautofontscript = autofontfeature.disable
+implement {
+ name = "enableautofontscript",
+ actions = autofontfeature.enable
+}
+
+implement {
+ name = "disableautofontscript",
+ actions = autofontfeature.disable }
+
+implement {
+ name = "setscript",
+ actions = scripts.set,
+ arguments = { "string", "string", "string" }
+}
+
+implement {
+ name = "resetscript",
+ actions = scripts.reset
+}
diff --git a/Master/texmf-dist/tex/context/base/scrp-ini.mkiv b/Master/texmf-dist/tex/context/base/scrp-ini.mkiv
index 4a27dd8e2bf..cd060c02bbd 100644
--- a/Master/texmf-dist/tex/context/base/scrp-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/scrp-ini.mkiv
@@ -41,14 +41,14 @@
\to \everydefinescript
\unexpanded\def\scripts_basics_set
- {\ctxlua{scripts.set("\currentscript","\scriptparameter\c!method","\scriptparameter\c!preset")}}
+ {\clf_setscript{\currentscript}{\scriptparameter\c!method}{\scriptparameter\c!preset}}
\unexpanded\def\setscript[#1]%
{\edef\currentscript{#1}%
\scripts_basics_set}
\unexpanded\def\resetscript
- {\ctxlua{scripts.reset()}}
+ {\clf_resetscript}
\unexpanded\def\startscript[#1]%
{\begingroup
@@ -86,8 +86,8 @@
\fi
\to \everysetupscript
-\unexpanded\def\enableautofontscript {\ctxcommand{enableautofontscript ()}}
-\unexpanded\def\disableautofontscript{\ctxcommand{disableautofontscript()}}
+\unexpanded\def\enableautofontscript {\clf_enableautofontscript }
+\unexpanded\def\disableautofontscript{\clf_disableautofontscript}
\definefontfeature[latn][script=latn]
\definefontfeature[grek][script=grek]
diff --git a/Master/texmf-dist/tex/context/base/sort-ini.lua b/Master/texmf-dist/tex/context/base/sort-ini.lua
index 9ac020166a8..99597761311 100644
--- a/Master/texmf-dist/tex/context/base/sort-ini.lua
+++ b/Master/texmf-dist/tex/context/base/sort-ini.lua
@@ -39,19 +39,28 @@ relatively easy to do.
how they map onto this mechanism. I've learned that users can come up
with any demand so nothing here is frozen.
+Todo: I ran into the Unicode Collation document and noticed that
+there are some similarities (like the weights) but using that method
+would still demand extra code for language specifics. One option is
+to use the allkeys.txt file for the uc vectors but then we would also
+use the collapsed key (sq, code is now commented). In fact, we could
+just hook those into the replacer code that we reun beforehand.
+
In the future index entries will become more clever, i.e. they will
have language etc properties that then can be used.
]]--
-local gsub, rep, sub, sort, concat = string.gsub, string.rep, string.sub, table.sort, table.concat
+local gsub, rep, sub, sort, concat, tohash, format = string.gsub, string.rep, string.sub, table.sort, table.concat, table.tohash, string.format
local utfbyte, utfchar, utfcharacters, utfvalues = utf.byte, utf.char, utf.characters, utf.values
local next, type, tonumber, rawget, rawset = next, type, tonumber, rawget, rawset
+local P, Cs, R, S, lpegmatch = lpeg.P, lpeg.Cs, lpeg.R, lpeg.S, lpeg.match
local allocate = utilities.storage.allocate
local setmetatableindex = table.setmetatableindex
local trace_tests = false trackers.register("sorters.tests", function(v) trace_tests = v end)
local trace_methods = false trackers.register("sorters.methods", function(v) trace_methods = v end)
+local trace_orders = false trackers.register("sorters.orders", function(v) trace_orders = v end)
local report_sorters = logs.reporter("languages","sorters")
@@ -65,7 +74,9 @@ local digitsoffset = 0x20000 -- frozen
local digitsmaximum = 0xFFFFF -- frozen
local lccodes = characters.lccodes
+local uccodes = characters.uccodes
local lcchars = characters.lcchars
+local ucchars = characters.ucchars
local shchars = characters.shchars
local fscodes = characters.fscodes
local fschars = characters.fschars
@@ -81,7 +92,7 @@ local v_after = variables.after
local v_first = variables.first
local v_last = variables.last
-local validmethods = table.tohash {
+local validmethods = tohash {
"ch", -- raw character (for tracing)
"mm", -- minus mapping
"zm", -- zero mapping
@@ -101,11 +112,11 @@ local predefinedmethods = {
}
sorters = {
- comparers = comparers,
- splitters = splitters,
- definitions = definitions,
- tracers = tracers,
- constants = {
+ comparers = comparers,
+ splitters = splitters,
+ definitions = definitions,
+ tracers = tracers,
+ constants = {
ignoredoffset = ignoredoffset,
replacementoffset = replacementoffset,
digitsoffset = digitsoffset,
@@ -113,6 +124,7 @@ sorters = {
defaultlanguage = v_default,
defaultmethod = v_default,
defaultdigits = v_numbers,
+ validmethods = validmethods,
}
}
@@ -156,6 +168,7 @@ local mte = { -- todo: assign to t
}
local noorder = false
+local nothing = { 0 }
local function preparetables(data)
local orders, lower, m_mappings, z_mappings, p_mappings = data.orders, data.lower, { }, { }, { }
@@ -168,12 +181,12 @@ local function preparetables(data)
__index = function(t,k)
local n, nn
if k then
- if trace_tests then
+ if trace_orders then
report_sorters("simplifing character %C",k)
end
local l = lower[k] or lcchars[k]
if l then
- if trace_tests then
+ if trace_orders then
report_sorters(" 1 lower: %C",l)
end
local ml = rawget(t,l)
@@ -184,7 +197,7 @@ local function preparetables(data)
nn = nn + 1
n[nn] = ml[i] + (t.__delta or 0)
end
- if trace_tests then
+ if trace_orders then
report_sorters(" 2 order: % t",n)
end
end
@@ -192,7 +205,7 @@ local function preparetables(data)
if not n then
local s = shchars[k] -- maybe all components?
if s and s ~= k then
- if trace_tests then
+ if trace_orders then
report_sorters(" 3 shape: %C",s)
end
n = { }
@@ -200,7 +213,7 @@ local function preparetables(data)
for l in utfcharacters(s) do
local ml = rawget(t,l)
if ml then
- if trace_tests then
+ if trace_orders then
report_sorters(" 4 keep: %C",l)
end
if ml then
@@ -212,7 +225,7 @@ local function preparetables(data)
else
l = lower[l] or lcchars[l]
if l then
- if trace_tests then
+ if trace_orders then
report_sorters(" 5 lower: %C",l)
end
local ml = rawget(t,l)
@@ -226,44 +239,45 @@ local function preparetables(data)
end
end
else
- -- -- we probably never enter this branch
- -- -- fschars returns a single char
- --
- -- s = fschars[k]
- -- if s and s ~= k then
- -- if trace_tests then
- -- report_sorters(" 6 split: %s",s)
- -- end
- -- local ml = rawget(t,s)
- -- if ml then
- -- n = { }
- -- nn = 0
- -- for i=1,#ml do
- -- nn = nn + 1
- -- n[nn] = ml[i]
- -- end
- -- end
- -- end
- local b = utfbyte(k)
- n = decomposed[b] or { b }
- if trace_tests then
- report_sorters(" 6 split: %s",utf.tostring(b)) -- todo
+ -- this is a kind of last resort branch that we might want to revise
+ -- one day
+ --
+ -- local b = utfbyte(k)
+ -- n = decomposed[b] or { b }
+ -- if trace_tests then
+ -- report_sorters(" 6 split: %s",utf.tostring(b)) -- todo
+ -- end
+ --
+ -- we need to move way above valid order (new per 2014-10-16) .. maybe we
+ -- need to move it even more up to get numbers right (not all have orders)
+ --
+ if k == "\000" then
+ n = nothing -- shared
+ if trace_orders then
+ report_sorters(" 6 split: space") -- todo
+ end
+ else
+ local b = 2 * #orders + utfbyte(k)
+ n = decomposed[b] or { b } -- could be shared tables
+ if trace_orders then
+ report_sorters(" 6 split: %s",utf.tostring(b)) -- todo
+ end
end
end
if n then
- if trace_tests then
+ if trace_orders then
report_sorters(" 7 order: % t",n)
end
else
n = noorder
- if trace_tests then
+ if trace_orders then
report_sorters(" 8 order: 0")
end
end
end
else
n = noorder
- if trace_tests then
+ if trace_orders then
report_sorters(" 9 order: 0")
end
end
@@ -298,11 +312,11 @@ local function update() -- prepare parent chains, needed when new languages are
end
end
-local function setlanguage(l,m,d,u)
+local function setlanguage(l,m,d,u) -- this will become a specification table
language = (l ~= "" and l) or constants.defaultlanguage
- data = definitions[language or constants.defaultlanguage] or definitions[constants.defaultlanguage]
- method = (m ~= "" and m) or data.method or constants.defaultmethod
- digits = (d ~= "" and d) or data.digits or constants.defaultdigits
+ data = definitions[language or constants.defaultlanguage] or definitions[constants.defaultlanguage]
+ method = (m ~= "" and m) or (data.method ~= "" and data.method) or constants.defaultmethod
+ digits = (d ~= "" and d) or (data.digits ~= "" and data.digits) or constants.defaultdigits
if trace_tests then
report_sorters("setting language %a, method %a, digits %a",language,method,digits)
end
@@ -333,8 +347,8 @@ local function setlanguage(l,m,d,u)
report_sorters("invalid sorter method %a in %a",s,method)
end
end
+ usedinsequence = tohash(sequence)
data.sequence = sequence
- usedinsequence = table.tohash(sequence)
data.usedinsequence = usedinsequence
-- usedinsequence.ch = true -- better just store the string
if trace_tests then
@@ -356,6 +370,8 @@ end
-- tricky: { 0, 0, 0 } vs { 0, 0, 0, 0 } => longer wins and mm, pm, zm can have them
+-- inlining and checking first slot first doesn't speed up (the 400K complex author sort)
+
local function basicsort(sort_a,sort_b)
if sort_a and sort_b then
local na = #sort_a
@@ -363,12 +379,14 @@ local function basicsort(sort_a,sort_b)
if na > nb then
na = nb
end
- for i=1,na do
- local ai, bi = sort_a[i], sort_b[i]
- if ai > bi then
- return 1
- elseif ai < bi then
- return -1
+ if na > 0 then
+ for i=1,na do
+ local ai, bi = sort_a[i], sort_b[i]
+ if ai > bi then
+ return 1
+ elseif ai < bi then
+ return -1
+ end
end
end
end
@@ -378,6 +396,10 @@ end
-- todo: compile compare function
local function basic(a,b) -- trace ea and eb
+ if a == b then
+ -- hashed (shared) entries
+ return 0
+ end
local ea, eb = a.split, b.split
local na, nb = #ea, #eb
if na == 0 and nb == 0 then
@@ -437,31 +459,72 @@ local function basic(a,b) -- trace ea and eb
end
end
+-- if we use sq:
+--
+-- local function basic(a,b) -- trace ea and eb
+-- local ea, eb = a.split, b.split
+-- local na, nb = #ea, #eb
+-- if na == 0 and nb == 0 then
+-- -- simple variant (single word)
+-- return basicsort(ea.sq,eb.sq)
+-- else
+-- -- complex variant, used in register (multiple words)
+-- local result = 0
+-- for i=1,nb < na and nb or na do
+-- local eai, ebi = ea[i], eb[i]
+-- result = basicsort(ea.sq,eb.sq)
+-- if result ~= 0 then
+-- return result
+-- end
+-- end
+-- if result ~= 0 then
+-- return result
+-- elseif na > nb then
+-- return 1
+-- elseif nb > na then
+-- return -1
+-- else
+-- return 0
+-- end
+-- end
+-- end
+
comparers.basic = basic
function sorters.basicsorter(a,b)
return basic(a,b) == -1
end
-local function numify(s)
- s = digitsoffset + tonumber(s) -- alternatively we can create range
- if s > digitsmaximum then
- s = digitsmaximum
+local function numify(old)
+ if digits == v_numbers then -- was swapped, fixed 2014-11-10
+ local new = digitsoffset + tonumber(old) -- alternatively we can create range
+ if new > digitsmaximum then
+ new = digitsmaximum
+ end
+ return utfchar(new)
+ else
+ return old
end
- return utfchar(s)
+end
+
+local pattern = nil
+
+local function prepare()
+ pattern = Cs( (
+ characters.tex.toutfpattern()
+ + lpeg.patterns.whitespace / "\000"
+ + (P("\\") / "") * R("AZ")^0 * (P(-1) + #(1-R("AZ")))
+ + (P("\\") * P(1) * R("az","AZ")^0) / ""
+ + S("[](){}$\"'") / ""
+ + R("09")^1 / numify
+ + P(1)
+ )^0 )
+ return pattern
end
function sorters.strip(str) -- todo: only letters and such
if str and str ~= "" then
- -- todo: make a decent lpeg
- str = gsub(str,"\\[\"\'~^`]*","") -- \"e -- hm, too greedy
- str = gsub(str,"\\%S*","") -- the rest
- str = gsub(str,"%s","\001") -- can be option
- str = gsub(str,"[%s%[%](){}%$\"\']*","") -- %s already done
- if digits == v_numbers then
- str = gsub(str,"(%d+)",numify) -- sort numbers properly
- end
- return str
+ return lpegmatch(pattern or prepare(),str)
else
return ""
end
@@ -529,10 +592,15 @@ function splitters.utf(str,checked) -- we could append m and u but this is clean
else
n = n + 1
local l = lower[sc]
- l = l and utfbyte(l) or lccodes[b]
+ l = l and utfbyte(l) or lccodes[b] or b
+ -- local u = upper[sc]
+ -- u = u and utfbyte(u) or uccodes[b] or b
if type(l) == "table" then
l = l[1] -- there are currently no tables in lccodes but it can be some, day
end
+ -- if type(u) == "table" then
+ -- u = u[1] -- there are currently no tables in lccodes but it can be some, day
+ -- end
z_case[n] = l
if l ~= b then
m_case[n] = l - 1
@@ -591,9 +659,9 @@ function splitters.utf(str,checked) -- we could append m and u but this is clean
-- p_mapping = { p_mappings[fs][1] }
-- end
-- end
-
+ local result
if checked then
- return {
+ result = {
ch = trace_tests and char or nil, -- not in sequence
uc = usedinsequence.uc and byte or nil,
mc = usedinsequence.mc and m_case or nil,
@@ -604,7 +672,7 @@ function splitters.utf(str,checked) -- we could append m and u but this is clean
pm = usedinsequence.pm and p_mapping or nil,
}
else
- return {
+ result = {
ch = char,
uc = byte,
mc = m_case,
@@ -615,7 +683,15 @@ function splitters.utf(str,checked) -- we could append m and u but this is clean
pm = p_mapping,
}
end
-
+ -- local sq, n = { }, 0
+ -- for i=1,#byte do
+ -- for s=1,#sequence do
+ -- n = n + 1
+ -- sq[n] = result[sequence[s]][i]
+ -- end
+ -- end
+ -- result.sq = sq
+ return result
end
local function packch(entry)
@@ -646,11 +722,11 @@ local function packuc(entry)
if #split > 0 then -- useless test
local t = { }
for i=1,#split do
- t[i] = concat(split[i].uc, " ")
+ t[i] = concat(split[i].uc, " ") -- sq
end
return concat(t," + ")
else
- return concat(split.uc," ")
+ return concat(split.uc," ") -- sq
end
end
@@ -677,7 +753,9 @@ function sorters.sort(entries,cmp)
first = " "
else
s = first
- report_sorters(">> %C (%C)",first,letter)
+ if first and letter then
+ report_sorters(">> %C (%C)",first,letter)
+ end
end
report_sorters(" %s | %s",packch(entry),packuc(entry))
end
diff --git a/Master/texmf-dist/tex/context/base/spac-adj.lua b/Master/texmf-dist/tex/context/base/spac-adj.lua
index c87a9d17f62..cdf9b505119 100644
--- a/Master/texmf-dist/tex/context/base/spac-adj.lua
+++ b/Master/texmf-dist/tex/context/base/spac-adj.lua
@@ -56,3 +56,11 @@ function nodes.handlers.graphicvadjust(head,groupcode) -- we can make an actionc
return head, false
end
end
+
+interfaces.implement {
+ name = "enablegraphicvadjust",
+ onlyonce = true,
+ actions = function()
+ nodes.tasks.enableaction("finalizers","nodes.handlers.graphicvadjust")
+ end
+}
diff --git a/Master/texmf-dist/tex/context/base/spac-adj.mkiv b/Master/texmf-dist/tex/context/base/spac-adj.mkiv
index 447dd722963..b8534303df9 100644
--- a/Master/texmf-dist/tex/context/base/spac-adj.mkiv
+++ b/Master/texmf-dist/tex/context/base/spac-adj.mkiv
@@ -16,18 +16,19 @@
\unprotect
% Very nasty but needed for margin stuff inside colored
-% paragraphs. Obsolete anyway.
+% paragraphs. Obsolete for while .
\registerctxluafile{spac-adj}{1.001}
\definesystemattribute [graphicvadjust] [public]
\unexpanded\def\enablegraphicvadjust
- {\ctxlua{nodes.tasks.enableaction("finalizers","nodes.handlers.graphicvadjust")}%
+ {\writestatus\m!systems{graphicvadjusting is no longer needed!}
+ \clf_enablegraphicvadjust %once anyway
\glet\enablegraphicvadjust\relax}
\unexpanded\def\graphicvadjust % currently not enabled ... nasty bidi handling
- {\enablegraphicvadjust % and no longer needed anyway
+ {\clf_enablegraphicvadjust % and probably no longer needed anyway
\dowithnextboxcontentcs\forgetall\spac_vadjust_graphic_finish\vbox}
\def\spac_vadjust_graphic_finish
diff --git a/Master/texmf-dist/tex/context/base/spac-ali.lua b/Master/texmf-dist/tex/context/base/spac-ali.lua
index 08e33c5b87c..880da6213d5 100644
--- a/Master/texmf-dist/tex/context/base/spac-ali.lua
+++ b/Master/texmf-dist/tex/context/base/spac-ali.lua
@@ -133,7 +133,11 @@ function alignments.set(n)
texsetattribute(a_realign,texgetcount("realpageno") * 10 + n)
end
-commands.setrealign = alignments.set
+interfaces.implement {
+ name = "setrealign",
+ actions = alignments.set,
+ arguments = "integer",
+}
statistics.register("realigning", function()
if nofrealigned > 0 then
diff --git a/Master/texmf-dist/tex/context/base/spac-ali.mkiv b/Master/texmf-dist/tex/context/base/spac-ali.mkiv
index c13e4ca7615..fbcce89c46d 100644
--- a/Master/texmf-dist/tex/context/base/spac-ali.mkiv
+++ b/Master/texmf-dist/tex/context/base/spac-ali.mkiv
@@ -38,8 +38,8 @@
\to \everyforgetall
\unexpanded\def\resetrealignsignal{\attribute\realignattribute\attributeunsetvalue}
-\unexpanded\def\signalinnerrealign{\ctxcommand{setrealign(2)}}
-\unexpanded\def\signalouterrealign{\ctxcommand{setrealign(1)}}
+\unexpanded\def\signalinnerrealign{\clf_setrealign\plustwo}
+\unexpanded\def\signalouterrealign{\clf_setrealign\plusone}
\installcorenamespace{aligncommand}
\installcorenamespace{alignhorizontal}
@@ -562,6 +562,12 @@
\spac_align_use_indeed
\fi}
+\unexpanded\def\dousealignparameter#1% faster local variant
+ {\edef\m_spac_align_asked{#1}%
+ \ifx\m_spac_align_asked\empty\else
+ \spac_align_use_indeed
+ \fi}
+
\def\spac_align_use_indeed
{\expandafter\let\expandafter\raggedcommand\csname\??alignmentnormalcache\m_spac_align_asked\endcsname
\ifx\raggedcommand\relax
@@ -715,7 +721,7 @@
\forgetall
\let\\=\endgraf
\ifdoublesided\signalinnerrealign\fi
- \doifrightpageelse\spac_align_set_horizontal_right\spac_align_set_horizontal_left
+ \doifelserightpage\spac_align_set_horizontal_right\spac_align_set_horizontal_left
\let\next}
\unexpanded\def\obox#1#2#3%
@@ -723,7 +729,7 @@
\forgetall
\let\\=\endgraf
\ifdoublesided\signalouterrealign\fi
- \doifrightpageelse\c_spac_align_state_horizontal_left\spac_align_set_horizontal_right
+ \doifelserightpage\c_spac_align_state_horizontal_left\spac_align_set_horizontal_right
\let\next}
\let\raggedbox\relax
@@ -961,7 +967,7 @@
\hbox}
\def\doxcheckline % used for floats so multipass anyway
- {\signalrightpage\doifrightpageelse\donetrue\donefalse}
+ {\signalrightpage\doifelserightpage\donetrue\donefalse}
\setvalue{\??alignline\v!inner }{\doxalignline\doxcheckline++\zeropoint \relax\hss }
\setvalue{\??alignline\v!outer }{\doxalignline\doxcheckline++\zeropoint \hss \relax}
diff --git a/Master/texmf-dist/tex/context/base/spac-chr.lua b/Master/texmf-dist/tex/context/base/spac-chr.lua
index 5b3a15478ce..e3fa6d09983 100644
--- a/Master/texmf-dist/tex/context/base/spac-chr.lua
+++ b/Master/texmf-dist/tex/context/base/spac-chr.lua
@@ -14,13 +14,14 @@ local byte, lower = string.byte, string.lower
-- to be redone: characters will become tagged spaces instead as then we keep track of
-- spaceskip etc
--- todo: only setattr when export
+-- todo: only setattr when export / use properties
local next = next
-trace_characters = false trackers.register("typesetters.characters", function(v) trace_characters = v end)
+local trace_characters = false trackers.register("typesetters.characters", function(v) trace_characters = v end)
+local trace_nbsp = false trackers.register("typesetters.nbsp", function(v) trace_nbsp = v end)
-report_characters = logs.reporter("typesetting","characters")
+local report_characters = logs.reporter("typesetting","characters")
local nodes, node = nodes, node
@@ -39,6 +40,8 @@ local setattr = nuts.setattr
local getfont = nuts.getfont
local getchar = nuts.getchar
+local setcolor = nodes.tracers.colors.set
+
local insert_node_before = nuts.insert_before
local insert_node_after = nuts.insert_after
local remove_node = nuts.remove
@@ -50,6 +53,8 @@ local tasks = nodes.tasks
local nodepool = nuts.pool
local new_penalty = nodepool.penalty
local new_glue = nodepool.glue
+local new_kern = nodepool.kern
+local new_rule = nodepool.rule
local nodecodes = nodes.nodecodes
local skipcodes = nodes.skipcodes
@@ -107,13 +112,22 @@ local function inject_char_space(unicode,head,current,parent)
end
local function inject_nobreak_space(unicode,head,current,space,spacestretch,spaceshrink)
- local attr = getfield(current,"attr")
- local glue = new_glue(space,spacestretch,spaceshrink)
+ local attr = getfield(current,"attr")
+ local glue = new_glue(space,spacestretch,spaceshrink)
local penalty = new_penalty(10000)
setfield(glue,"attr",attr)
setfield(current,"attr",nil)
- setattr(glue,a_character,unicode)
+ setattr(glue,a_character,unicode) -- bombs
head, current = insert_node_after(head,current,penalty)
+ if trace_nbsp then
+ local rule = new_rule(space)
+ local kern = new_kern(-space)
+ local penalty = new_penalty(10000)
+ setcolor(rule,"orange")
+ head, current = insert_node_after(head,current,rule)
+ head, current = insert_node_after(head,current,kern)
+ head, current = insert_node_after(head,current,penalty)
+ end
head, current = insert_node_after(head,current,glue)
return head, current
end
diff --git a/Master/texmf-dist/tex/context/base/spac-chr.mkiv b/Master/texmf-dist/tex/context/base/spac-chr.mkiv
index f9dc6e16b5f..562fb940ce1 100644
--- a/Master/texmf-dist/tex/context/base/spac-chr.mkiv
+++ b/Master/texmf-dist/tex/context/base/spac-chr.mkiv
@@ -77,6 +77,7 @@
\let\zwnj\zerowidthnonjoiner
\let\zwj \zerowidthjoiner
+\let\nbsp\nobreakspace
\chardef\optionalspace"1F % will be space unless before punctuation
diff --git a/Master/texmf-dist/tex/context/base/spac-hor.lua b/Master/texmf-dist/tex/context/base/spac-hor.lua
index c9d6e2b154b..5d5a43e311c 100644
--- a/Master/texmf-dist/tex/context/base/spac-hor.lua
+++ b/Master/texmf-dist/tex/context/base/spac-hor.lua
@@ -6,14 +6,15 @@ if not modules then modules = { } end modules ['spac-hor'] = {
license = "see context related readme files"
}
-local match = string.match
local utfbyte = utf.byte
+local lpegmatch, P, C = lpeg.match, lpeg.P, lpeg.C
local context = context
-local commands = commands
local chardata = characters.data
+local p_check = P("the ") * (P("letter") + P("character")) * P(" ") * lpeg.patterns.utf8byte -- is a capture already
+
local can_have_space = table.tohash {
"lu", "ll", "lt", "lm", "lo", -- letters
-- "mn", "mc", "me", -- marks
@@ -26,10 +27,18 @@ local can_have_space = table.tohash {
-- "cc", "cf", "cs", "co", "cn", -- others
}
-function commands.autonextspace(str) -- todo: use nexttoken
- local ch = match(str,"the letter (.)") or match(str,"the character (.)")
- ch = ch and chardata[utfbyte(ch)]
- if ch and can_have_space[ch.category] then
- context.space()
+local function autonextspace(str) -- todo: make a real not intrusive lookahead
+ local b = lpegmatch(p_check,str)
+ if b then
+ local d = chardata[b]
+ if d and can_have_space[d.category] then
+ context.space()
+ end
end
end
+
+interfaces.implement {
+ name = "autonextspace",
+ actions = autonextspace,
+ arguments = "string",
+}
diff --git a/Master/texmf-dist/tex/context/base/spac-hor.mkiv b/Master/texmf-dist/tex/context/base/spac-hor.mkiv
index 92491ce3218..54156c3b428 100644
--- a/Master/texmf-dist/tex/context/base/spac-hor.mkiv
+++ b/Master/texmf-dist/tex/context/base/spac-hor.mkiv
@@ -32,7 +32,7 @@
{\doifoutervmode{\ifconditional\c_spac_indentation_indent_first\else\spac_indentation_variant_no\fi}}
\unexpanded\def\setupindenting
- {\doifnextoptionalcselse\spac_indentation_setup_options\spac_indentation_setup_size}
+ {\doifelsenextoptionalcs\spac_indentation_setup_options\spac_indentation_setup_size}
\unexpanded\def\spac_indentation_setup_size
{\assigndimension\v_spac_indentation_current\d_spac_indentation_par{1\emwidth}{1.5\emwidth}{2\emwidth}}
@@ -64,6 +64,12 @@
\def\spac_indentation_set_everypar
{\everypar{\checkindentation}}
+\unexpanded\def\useindentingparameter#1% faster local variant
+ {\edef\m_spac_indentation_options{#1\c!indenting}%
+ \ifx\m_spac_indentation_options\empty \else
+ \spac_indentation_setup_indeed
+ \fi}
+
% \def\spac_indentation_apply_step_one#1%
% {\ifcsname\??indentingmethod#1\endcsname
% % case two
@@ -122,7 +128,7 @@
\fi\fi}
\unexpanded\def\indenting % kind of obsolete
- {\doifnextoptionalcselse\spac_indentation_setup_options\relax}
+ {\doifelsenextoptionalcs\spac_indentation_setup_options\relax}
% use \noindentation to suppress next indentation
@@ -258,7 +264,7 @@
\unexpanded\def\spac_indentation_check_next_indentation
{\global\let\dorechecknextindentation\relax
- \doifnextcharelse\par\donothing\spac_indentation_variant_no} % messy check as next is seldom \par
+ \doifelsenextchar\par\donothing\spac_indentation_variant_no} % messy check as next is seldom \par
\def\spac_indentation_variant_auto
{\global\let\dorechecknextindentation\spac_indentation_check_next_indentation}
@@ -380,7 +386,7 @@
\installspacingmethod \v!broad {\nonfrenchspacing} % more depending on what punctuation
\unexpanded\def\setupspacing
- {\doifnextoptionalcselse\spac_spacecodes_setup_yes\spac_spacecodes_setup_nop}
+ {\doifelsenextoptionalcs\spac_spacecodes_setup_yes\spac_spacecodes_setup_nop}
\def\spac_spacecodes_setup_yes[#1]%
{\csname\??spacecodemethod#1\endcsname
@@ -671,7 +677,7 @@
\fi}
\def\spac_narrower_start_named_one[#1]%
- {\doifassignmentelse{#1}\spac_narrower_start_named_one_yes\spac_narrower_start_named_one_nop[#1]}
+ {\doifelseassignment{#1}\spac_narrower_start_named_one_yes\spac_narrower_start_named_one_nop[#1]}
\def\spac_narrower_start_named_one_yes[#1][#2]% [settings] []
{\setupcurrentnarrower[#1]%
@@ -682,14 +688,14 @@
\spac_narrower_start_apply{\narrowerparameter\v!default}}
\def\spac_narrower_start_named_two[#1]%
- {\doifassignmentelse{#1}\spac_narrower_start_named_settings_how\spac_narrower_start_named_tag_unknown[#1]}
+ {\doifelseassignment{#1}\spac_narrower_start_named_settings_how\spac_narrower_start_named_tag_unknown[#1]}
\def\spac_narrower_start_named_settings_how[#1][#2]% [settings] [how]
{\setupcurrentnarrower[#1]%
\spac_narrower_start_apply{#2}}
\def\spac_narrower_start_named_tag_unknown[#1][#2]% [tag] [...]
- {\doifassignmentelse{#2}\spac_narrower_start_named_tag_settings\spac_narrower_start_named_tag_how[#1][#2]}
+ {\doifelseassignment{#2}\spac_narrower_start_named_tag_settings\spac_narrower_start_named_tag_how[#1][#2]}
\def\spac_narrower_start_named_tag_settings[#1][#2]% [tag] [settings]
{\edef\currentnarrower{#1}%
@@ -733,8 +739,8 @@
\unexpanded\def\dosetleftskipadaption #1{\leftskipadaption \ifcsname\??skipadaptionleft #1\endcsname\csname\??skipadaptionleft #1\endcsname\else#1\fi\relax}
\unexpanded\def\dosetrightskipadaption#1{\rightskipadaption\ifcsname\??skipadaptionright#1\endcsname\csname\??skipadaptionright#1\endcsname\else#1\fi\relax}
-\unexpanded\def\doadaptleftskip #1{\dosetleftskipadaption {#1}\advance\leftskip \leftskipadaption }
-\unexpanded\def\doadaptrightskip#1{\dosetrightskipadaption{#1}\advance\rightskip\rightskipadaption}
+\unexpanded\def\doadaptleftskip #1{\normalexpanded{\dosetleftskipadaption {#1}}\advance\leftskip \leftskipadaption }
+\unexpanded\def\doadaptrightskip#1{\normalexpanded{\dosetrightskipadaption{#1}}\advance\rightskip\rightskipadaption}
\unexpanded\def\forgetbothskips
{\leftskip\zeropoint
@@ -780,7 +786,7 @@
{\dosingleargument\spac_tolerances_setup}
\def\spac_tolerances_setup[#1]%
- {\doifinsetelse\v!vertical{#1}%
+ {\doifelseinset\v!vertical{#1}%
{\processcommacommand[#1]\spac_tolerances_step_vertical }
{\processcommacommand[#1]\spac_tolerances_step_horizontal}}
@@ -850,31 +856,6 @@
%D In \CONTEXT\ however we save some processing time by putting
%D an extra \type{\hbox} around the \type{\strutbox}.
-% moved from page-lin.tex to here (due to visualization added
-% in august 2003)
-%
-% \unexpanded \def\crlf
-% {\ifhmode\unskip\else\strut\fi\ifcase\raggedstatus\hfil\fi\break}
-
-\unexpanded\def\crlf
- {\ifhmode
- \unskip
- \prewordbreak\crlfplaceholder
- \ifcase\raggedstatus\hfil\or\or\or\hfil\fi
- \break
- \else
- \crlfplaceholder
- \endgraf
- \fi}
-
-\unexpanded\def\crlfplaceholder
- {\strut}
-
-\unexpanded\def\settestcrlf
- {\unexpanded\def\crlfplaceholder
- {\hbox to \zeropoint
- {\strut{\infofont\kern.25em}\lohi{\infofont CR}{\infofont LF}\hss}}}
-
%D \starttyping
%D % \setuplayout[gridgrid=yes] \showgrid
%D
@@ -1065,7 +1046,7 @@
{\futurelet\nexttoken\spac_spaces_auto_insert_next}
\def\spac_spaces_auto_insert_next
- {\ctxcommand{autonextspace(\!!bs\meaning\nexttoken\!!es)}} % todo, just consult nexttoken at the lua end
+ {\clf_autonextspace{\meaning\nexttoken}} % todo, just consult nexttoken at the lua end
%D Moved from bib module:
@@ -1100,7 +1081,7 @@
%D A rather unknown one:
\unexpanded\def\widened % moved from cont-new
- {\doifnextoptionalcselse\spac_widened_yes\spac_widened_nop}
+ {\doifelsenextoptionalcs\spac_widened_yes\spac_widened_nop}
\def\spac_widened_yes[#1]#2{\hbox \s!spread #1{\hss#2\hss}}
\def\spac_widened_nop #1{\hbox \s!spread \emwidth{\hss#1\hss}}
diff --git a/Master/texmf-dist/tex/context/base/spac-lin.mkiv b/Master/texmf-dist/tex/context/base/spac-lin.mkiv
index 094e18e0bac..20fec5d4537 100644
--- a/Master/texmf-dist/tex/context/base/spac-lin.mkiv
+++ b/Master/texmf-dist/tex/context/base/spac-lin.mkiv
@@ -88,13 +88,13 @@
\linesparameter\c!before
\pushmacro\checkindentation
\whitespace
- \dostarttagged\t!lines\currentlines
+ \dostarttaggedchained\t!lines\currentlines\??lines
\begingroup
\uselinesstyleandcolor\c!style\c!color
- \setupindenting[\linesparameter\c!indenting]%
- \setupalign[\linesparameter\c!align]%
+ \useindentingparameter\linesparameter
+ \usealignparameter\linesparameter
\typesettinglinestrue
- \setupwhitespace[\v!none]%
+ \setupwhitespace[\v!none]% todo use fast variant
%\obeylines % move upwards to keep spaces in the first line due to optional argument
\ignorespaces
\glet\spac_after_first_obeyed_line\spac_lines_after_first_obeyed_line_a
@@ -128,7 +128,7 @@
\egroup}
\def\spac_lines_between
- {\doifmeaningelse\next\obeyedline % brrr
+ {\doifelsemeaning\next\obeyedline % brrr
{\linesparameter\c!inbetween}
{\spac_after_first_obeyed_line}}
diff --git a/Master/texmf-dist/tex/context/base/spac-pag.mkiv b/Master/texmf-dist/tex/context/base/spac-pag.mkiv
index da4c8e9703b..1ecc31d8cd5 100644
--- a/Master/texmf-dist/tex/context/base/spac-pag.mkiv
+++ b/Master/texmf-dist/tex/context/base/spac-pag.mkiv
@@ -51,7 +51,7 @@
\setpagestaterealpageno{#1}{\number#2}%
\fi}
-\unexpanded\def\doifrightpagestateelse#1#2% not expandable !
+\unexpanded\def\doifelserightpagestate#1#2% not expandable !
{\ifcase\frozenpagestate
\pagestatemismatchfalse
\realpagestateno\realfolio
@@ -100,7 +100,7 @@
\expandafter\secondoftwoarguments
\fi}
-\unexpanded\def\doifforcedrightpagestateelse#1#2%
+\unexpanded\def\doifelseforcedrightpagestate#1#2%
{\ifcase\frozenpagestate
\pagestatemismatchfalse
\realpagestateno\realfolio
@@ -135,6 +135,9 @@
\expandafter\secondoftwoarguments
\fi}
+\let\doifrightpagestateelse \doifelserightpagestate
+\let\doifforcedrightpagestateelse\doifelseforcedrightpagestate
+
\unexpanded\def\freezepagestate {\frozenpagestate\plusone }
\unexpanded\def\defrostpagestate{\frozenpagestate\zerocount}
@@ -147,7 +150,9 @@
\definepagestate[\s!paragraph]
\unexpanded\def\signalrightpage {\dotrackpagestate \s!paragraph\nofraggedparagraphs} % use \dontleavehmode if needed
-\unexpanded\def\doifrightpageelse{\doifrightpagestateelse\s!paragraph\nofraggedparagraphs}
+\unexpanded\def\doifelserightpage{\doifelserightpagestate\s!paragraph\nofraggedparagraphs}
+
+\let\doifrightpageelse\doifelserightpage
\installcorenamespace{pagechanges}
diff --git a/Master/texmf-dist/tex/context/base/spac-par.mkiv b/Master/texmf-dist/tex/context/base/spac-par.mkiv
index 825cdca462b..4dd3db24338 100644
--- a/Master/texmf-dist/tex/context/base/spac-par.mkiv
+++ b/Master/texmf-dist/tex/context/base/spac-par.mkiv
@@ -203,6 +203,8 @@
% \glet\flushpostponednodedata\spac_postponed_data_flush
% \fi}
+\newtoks\everyflushatnextpar
+
\unexpanded\def\pushpostponednodedata
{\globalpushbox\b_spac_postponed_data}
@@ -214,6 +216,7 @@
\unexpanded\def\flushatnextpar
{\begingroup
+ \the\everyflushatnextpar
\glet\flushpostponednodedata\spac_postponed_data_flush
\dowithnextboxcs\spac_postponed_data_finish\hbox}
diff --git a/Master/texmf-dist/tex/context/base/spac-ver.lua b/Master/texmf-dist/tex/context/base/spac-ver.lua
index d5a2b4d5693..fc6fba0eb43 100644
--- a/Master/texmf-dist/tex/context/base/spac-ver.lua
+++ b/Master/texmf-dist/tex/context/base/spac-ver.lua
@@ -8,11 +8,16 @@ if not modules then modules = { } end modules ['spac-ver'] = {
-- we also need to call the spacer for inserts!
+-- somehow lists still don't always have proper prev nodes so i need to
+-- check all of the luatex code some day .. maybe i should replece the
+-- whole mvl handler by lua code .. why not
+
-- todo: use lua nodes with lua data (>0.79)
-- see ** can go when 0.79
-- this code dates from the beginning and is kind of experimental; it
--- will be optimized and improved soon
+-- will be optimized and improved soon .. it's way too complex now but
+-- dates from less possibilities
--
-- the collapser will be redone with user nodes; also, we might get make
-- parskip into an attribute and appy it explicitly thereby getting rid
@@ -33,13 +38,20 @@ local formatters = string.formatters
local P, C, R, S, Cc = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cc
-local nodes, node, trackers, attributes, context, commands, tex = nodes, node, trackers, attributes, context, commands, tex
+local nodes = nodes
+local node = node
+local trackers = trackers
+local attributes = attributes
+local context = context
+local tex = tex
local texlists = tex.lists
local texgetdimen = tex.getdimen
+local texsetdimen = tex.setdimen
local texnest = tex.nest
local variables = interfaces.variables
+local implement = interfaces.implement
-- vertical space handler
@@ -104,6 +116,7 @@ local nodepool = nuts.pool
local new_penalty = nodepool.penalty
local new_kern = nodepool.kern
local new_rule = nodepool.rule
+local new_glue = nodepool.glue
local new_gluespec = nodepool.gluespec
local nodecodes = nodes.nodecodes
@@ -134,11 +147,13 @@ local default = {
strut = true,
hfraction = 1,
dfraction = 1,
+ bfraction = 0.25,
}
local fractions = {
minheight = "hfraction", maxheight = "hfraction",
mindepth = "dfraction", maxdepth = "dfraction",
+ box = "bfraction",
top = "tlines", bottom = "blines",
}
@@ -330,27 +345,58 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
t[#t+1] = formatters["auto: snapht %p snapdp %p"](snapht,snapdp)
end
end
- local h = height or getfield(current,"height")
- local d = depth or getfield(current,"depth")
- local hr, dr, ch, cd = method.hfraction or 1, method.dfraction or 1, h, d
- local tlines, blines = method.tlines or 1, method.blines or 1
- local done, plusht, plusdp = false, snapht, snapdp
+
+ local h = (method.noheight and 0) or height or getfield(current,"height")
+ local d = (method.nodepth and 0) or depth or getfield(current,"depth")
+ local hr = method.hfraction or 1
+ local dr = method.dfraction or 1
+ local br = method.bfraction or 0
+ local ch = h
+ local cd = d
+ local tlines = method.tlines or 1
+ local blines = method.blines or 1
+ local done = false
+ local plusht = snapht
+ local plusdp = snapdp
local snaphtdp = snapht + snapdp
- if method.none then
+ if method.box then
+ local br = 1 - br
+ if br < 0 then
+ br = 0
+ elseif br > 1 then
+ br = 1
+ end
+ local n = ceiled((h+d-br*snapht-br*snapdp)/snaphtdp)
+ local x = n * snaphtdp - h - d
+ plusht = h + x / 2
+ plusdp = d + x / 2
+ elseif method.max then
+ local n = ceiled((h+d)/snaphtdp)
+ local x = n * snaphtdp - h - d
+ plusht = h + x / 2
+ plusdp = d + x / 2
+ elseif method.min then
+ local n = floored((h+d)/snaphtdp)
+ local x = n * snaphtdp - h - d
+ plusht = h + x / 2
+ plusdp = d + x / 2
+ elseif method.none then
plusht, plusdp = 0, 0
if t then
t[#t+1] = "none: plusht 0pt plusdp 0pt"
end
end
if method.halfline then -- extra halfline
- plusht, plusdp = plusht + snaphtdp/2, plusdp + snaphtdp/2
+ plusht = plusht + snaphtdp/2
+ plusdp = plusdp + snaphtdp/2
if t then
t[#t+1] = formatters["halfline: plusht %p plusdp %p"](plusht,plusdp)
end
end
if method.line then -- extra line
- plusht, plusdp = plusht + snaphtdp, plusdp + snaphtdp
+ plusht = plusht + snaphtdp
+ plusdp = plusdp + snaphtdp
if t then
t[#t+1] = formatters["line: plusht %p plusdp %p"](plusht,plusdp)
end
@@ -512,6 +558,12 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
t[#t+1] = formatters["final height: %p -> %p"](h,ch)
t[#t+1] = formatters["final depth: %p -> %p"](d,cd)
end
+-- todo:
+--
+-- if h < 0 or d < 0 then
+-- h = 0
+-- d = 0
+-- end
if t then
report_snapper("trace: %s type %s\n\t%\n\tt",where,nodecodes[getid(current)],t)
end
@@ -879,19 +931,18 @@ local special_penalty_xxx = 0
-- header don't break but also make sure that we have at least a decent
-- break when we have succesive ones (often when testing)
+-- todo: mark headers as such so that we can recognize them
+
local specialmethods = { }
local specialmethod = 1
local properties = nodes.properties.data
-specialmethods[1] = function(start,penalty)
+specialmethods[1] = function(pagehead,pagetail,start,penalty)
--
- if penalty < special_penalty_min or penalty > special_penalty_max then
+ if not pagehead or penalty < special_penalty_min or penalty > special_penalty_max then
return
end
- -- this can move to the caller
- local pagehead = tonut(texlists.page_head)
- local pagetail = find_node_tail(pagehead) -- no texlists.page_tail yet-- no texlists.page_tail yet
local current = pagetail
--
-- nodes.showsimplelist(pagehead,0)
@@ -927,51 +978,84 @@ specialmethods[1] = function(start,penalty)
return
end
elseif trace_specials then
- report_specials(" context %a, higher level, continue",p)
+ report_specials(" context penalty %a, higher level, continue",p)
+ end
+ else
+ local p = getfield(current,"penalty")
+ if p < 10000 then
+ -- assume some other mechanism kicks in so we seem to have content
+ if trace_specials then
+ report_specials(" regular penalty %a, quitting",p)
+ end
+ break
+ else
+ if trace_specials then
+ report_specials(" regular penalty %a, continue",p)
+ end
end
- elseif trace_specials then
- report_specials(" regular penalty, continue")
end
end
current = getprev(current)
end
+ -- none found, so no reson to be special
+ if trace_specials then
+ report_specials(" context penalty, discarding")
+ end
+ return special_penalty_xxx
end
-- specialmethods[2] : always put something before and use that as to-be-changed
+--
+-- we could inject a vadjust to force a recalculation .. a mess
+--
+-- So, the next is far from robust and okay but for the moment this overlaying
+-- has to do. Always test this with the examples in spec-ver.mkvi!
-local function check_experimental_overlay(head,current) -- todo
+local function check_experimental_overlay(head,current)
local p = nil
local c = current
local n = nil
-setfield(head,"prev",nil) -- till we have 0.79 **
-
- local function overlay(p, n, s, mvl)
- local c = getprev(n)
- while c and c ~= p do
- local p = getprev(c)
- free_node(c)
- c = p
- end
- setfield(n,"prev",nil)
- if not mvl then
- setfield(p,"next",n)
+ -- setfield(head,"prev",nil) -- till we have 0.79 **
+
+ local function overlay(p,n,mvl)
+ local p_ht = getfield(p,"height")
+ local p_dp = getfield(p,"depth")
+ local n_ht = getfield(n,"height")
+ local skips = 0
+ --
+ -- We deal with this at the tex end .. we don't see spacing .. enabling this code
+ -- is probably harmless btu then we need to test it.
+ --
+ local c = getnext(p)
+ while c and c ~= n do
+ local id = getid(c)
+ if id == glue_code then
+ skips = skips + getfield(getfield(c,"glue_spec"),"width")
+ elseif id == kern_code then
+ skips = skips + getfield(c,"kern")
+ end
+ c = getnext(c)
end
- local p_ht = getfield(p,"height")
- local p_dp = getfield(p,"depth")
- local n_ht = getfield(n,"height")
- local delta = n_ht + s + p_dp
+ --
+ local delta = n_ht + skips + p_dp
+ texsetdimen("global","d_spac_overlay",-delta) -- for tracing
local k = new_kern(-delta)
- if trace_vspacing then
- report_vspacing("overlaying, prev height: %p, prev depth: %p, next height: %p, skips: %p, move up: %p",p_ht,p_dp,n_ht,s,delta)
- end
if n_ht > p_ht then
- -- we should adapt pagetotal ! (need a hook for that)
+ -- we should adapt pagetotal ! (need a hook for that) .. now we have the wrong pagebreak
setfield(p,"height",n_ht)
end
- return k
+ insert_node_before(head,n,k)
+ if p == head then
+ head = k
+ end
+ if trace_vspacing then
+ report_vspacing("overlaying, prev height: %p, prev depth: %p, next height: %p, skips: %p, move up: %p",p_ht,p_dp,n_ht,skips,delta)
+ end
+ return remove_node(head,current,true)
end
+ -- goto next line
while c do
local id = getid(c)
if id == glue_code or id == penalty_code or id == kern_code then
@@ -985,7 +1069,7 @@ setfield(head,"prev",nil) -- till we have 0.79 **
end
end
if n then
- -- we have a next line
+ -- we have a next line, goto prev line
c = current
while c do
local id = getid(c)
@@ -1002,45 +1086,33 @@ setfield(head,"prev",nil) -- till we have 0.79 **
if a_snapmethod == a_snapvbox then
-- quit, we're not on the mvl
else
- -- messy
local c = tonut(texlists.page_head)
- local s = 0
- while c do
+ while c and c ~= n do
local id = getid(c)
- if id == glue_code then
- if p then
- s = s + getfield(getfield(c,"glue_spec"),"width")
- end
- elseif id == kern_code then
- if p then
- s = s + getfield(c,"kern")
- end
- elseif id == penalty_code then
- -- skip (actually, remove)
- elseif id == hlist_code then
+ if id == hlist_code then
p = c
- s = 0
- else
- p = nil
- s = 0
end
c = getnext(c)
end
if p and p ~= n then
- local k = overlay(p,n,s,true)
- insert_node_before(n,n,k)
- return k, getnext(n)
+ return overlay(p,n,true)
end
end
elseif p ~= n then
- local k = overlay(p,n,0,false )
- insert_node_after(p,p,k)
- return head, getnext(n)
+ return overlay(p,n,false)
end
end
+ -- in fact, we could try again later ... so then no remove (a few tries)
return remove_node(head, current, true)
end
+-- This will be replaced after 0.80+ when we have a more robust look-back and
+-- can look at the bigger picture.
+
+-- todo: look back and when a special is there before a list is seen penalty keep ut
+
+-- we now look back a lot, way too often
+
local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also pass tail
if trace then
reset_tracing(head)
@@ -1052,6 +1124,21 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
--
-- todo: keep_together: between headers
--
+ local function getpagelist()
+ if not pagehead then
+ pagehead = texlists.page_head
+ if pagehead then
+ pagehead = tonut(texlists.page_head)
+ pagetail = find_node_tail(pagehead) -- no texlists.page_tail yet-- no texlists.page_tail yet
+ else
+ pagetail = nil
+ end
+ else
+ pagetail = nil
+ end
+ return pagehead, pagetail
+ end
+ --
local function flush(why)
if penalty_data then
local p = new_penalty(penalty_data)
@@ -1068,7 +1155,14 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
head = insert_node_before(head,current,p)
end
-- if penalty_data > special_penalty_min and penalty_data < special_penalty_max then
- properties[p] = { special_penalty = special_penalty or penalty_data }
+ local props = properties[p]
+ if props then
+ props.special_penalty = special_penalty or penalty_data
+ else
+ properties[p] = {
+ special_penalty = special_penalty or penalty_data
+ }
+ end
-- end
end
if glue_data then
@@ -1089,6 +1183,26 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
penalty_order, penalty_data, natural_penalty = 0, nil, nil
parskip, ignore_parskip, ignore_following, ignore_whitespace = nil, false, false, false
end
+ --
+
+-- quick hack, can be done nicer
+-- local nobreakfound = nil
+-- local function checknobreak()
+-- local pagehead, pagetail = getpagelist()
+-- local current = pagetail
+-- while current do
+-- local id = getid(current)
+-- if id == hlist_code or id == vlist_code then
+-- return false
+-- elseif id == penalty_code then
+-- return getfield(current,"penalty") >= 10000
+-- end
+-- current = getprev(current)
+-- end
+-- return false
+-- end
+
+ --
if trace_vsnapping then
report_snapper("global ht/dp = %p/%p, local ht/dp = %p/%p",
texgetdimen("globalbodyfontstrutheight"), texgetdimen("globalbodyfontstrutdepth"),
@@ -1096,9 +1210,15 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
)
end
if trace then trace_info("start analyzing",where,what) end
+
+-- local headprev = getprev(head)
+
while current do
local id = getid(current)
if id == hlist_code or id == vlist_code then
+-- if nobreakfound == nil then
+-- nobreakfound = false
+-- end
-- needs checking, why so many calls
if snap then
local list = getlist(current)
@@ -1144,6 +1264,17 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
-- natural_penalty = getfield(current,"penalty")
-- if trace then trace_done("removed penalty",current) end
-- head, current = remove_node(head, current, true)
+
+-- if nobreakfound == nil then
+-- nobreakfound = checknobreak()
+-- end
+-- if nobreakfound and getfield(current,"penalty") <= 10000 then
+-- -- if trace then
+-- trace_done("removed penalty",current)
+-- -- end
+-- head, current = remove_node(head, current, true)
+-- end
+
current = getnext(current)
elseif id == kern_code then
if snap and trace_vsnapping and getfield(current,"kern") ~= 0 then
@@ -1159,7 +1290,8 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
local sp = getattr(current,a_skippenalty) -- has no default, no unset (yet)
if sp and sc == penalty then
if where == "page" then
- local p = specialmethods[specialmethod](current,sp)
+ local pagehead, pagetail = getpagelist()
+ local p = specialmethods[specialmethod](pagehead,pagetail,current,sp)
if p then
if trace then
trace_skip("previous special penalty %a is changed to %a using method %a",sp,p,specialmethod)
@@ -1167,6 +1299,12 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
special_penalty = sp
sp = p
end
+
+-- else
+-- if nobreakfound == nil then
+-- nobreakfound = checknobreak()
+-- end
+
end
if not penalty_data then
penalty_data = sp
@@ -1176,6 +1314,14 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
penalty_data = sp
end
if trace then trace_skip("penalty in skip",sc,so,sp,current) end
+
+-- if nobreakfound then
+-- penalty_data = 10000
+-- if trace then
+-- trace_skip("nobreak found before penalty in skip",sc,so,sp,current)
+-- end
+-- end
+
head, current = remove_node(head, current, true)
elseif not sc then -- if not sc then
if glue_data then
@@ -1234,6 +1380,8 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
elseif sc == overlay then
-- todo (overlay following line over previous
if trace then trace_skip("overlay",sc,so,sp,current) end
+ -- beware: head can actually be after the affected nodes as
+ -- we look back ... some day head will the real head
head, current = check_experimental_overlay(head,current,a_snapmethod)
elseif ignore_following then
if trace then trace_skip("disabled",sc,so,sp,current) end
@@ -1431,9 +1579,16 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
local p = new_penalty(penalty_data)
if trace then trace_done("result",p) end
head, tail = insert_node_after(head,tail,p)
--- if penalty_data > special_penalty_min and penalty_data < special_penalty_max then
- properties[p] = { special_penalty = special_penalty or penalty_data }
--- end
+ -- if penalty_data > special_penalty_min and penalty_data < special_penalty_max then
+ local props = properties[p]
+ if props then
+ props.special_penalty = special_penalty or penalty_data
+ else
+ properties[p] = {
+ special_penalty = special_penalty or penalty_data
+ }
+ end
+ -- end
end
if glue_data then
if not tail then tail = find_node_tail(head) end
@@ -1445,7 +1600,7 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
else
head, tail = insert_node_after(head,tail,glue_data)
end
-texnest[texnest.ptr].prevdepth = 0 -- appending to the list bypasses tex's prevdepth handler
+ texnest[texnest.ptr].prevdepth = 0 -- appending to the list bypasses tex's prevdepth handler
end
if trace then
if glue_data or penalty_data then
@@ -1456,6 +1611,13 @@ texnest[texnest.ptr].prevdepth = 0 -- appending to the list bypasses tex's prevd
trace_info("head has been changed from %a to %a",nodecodes[getid(oldhead)],nodecodes[getid(head)])
end
end
+
+-- if headprev then
+-- setprev(head,headprev)
+-- setnext(headprev,head)
+-- end
+-- print("C HEAD",tonode(head))
+
return head, true
end
@@ -1576,10 +1738,51 @@ end
-- interface
-commands.vspacing = vspacing.analyze
-commands.vspacingsetamount = vspacing.setskip
-commands.vspacingdefine = vspacing.setmap
-commands.vspacingcollapse = vspacing.collapsevbox
-commands.vspacingsnap = vspacing.snapbox
-commands.resetprevdepth = vspacing.resetprevdepth
-commands.definesnapmethod = vspacing.definesnapmethod
+implement {
+ name = "vspacing",
+ actions = vspacing.analyze,
+ scope = "private",
+ arguments = "string"
+}
+
+implement {
+ name = "resetprevdepth",
+ actions = vspacing.resetprevdepth,
+ scope = "private"
+}
+
+implement {
+ name = "vspacingsetamount",
+ actions = vspacing.setskip,
+ scope = "private",
+ arguments = "string",
+}
+
+implement {
+ name = "vspacingdefine",
+ actions = vspacing.setmap,
+ scope = "private",
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "vspacingcollapse",
+ actions = vspacing.collapsevbox,
+ scope = "private",
+ arguments = "integer"
+}
+
+implement {
+ name = "vspacingsnap",
+ actions = vspacing.snapbox,
+ scope = "private",
+ arguments = { "integer", "integer" }
+}
+
+implement {
+ name = "definesnapmethod",
+ actions = vspacing.definesnapmethod,
+ scope = "private",
+ arguments = { "string", "string" }
+}
+
diff --git a/Master/texmf-dist/tex/context/base/spac-ver.mkiv b/Master/texmf-dist/tex/context/base/spac-ver.mkiv
index 0c84958beb0..e44056954ad 100644
--- a/Master/texmf-dist/tex/context/base/spac-ver.mkiv
+++ b/Master/texmf-dist/tex/context/base/spac-ver.mkiv
@@ -17,6 +17,8 @@
\registerctxluafile{spac-ver}{1.001}
+% todo: use usernodes ?
+
% todo: itemize : intro ... only when there is one or two lines preceding and then
% keep these together i.e. \blank[intro]
@@ -120,7 +122,7 @@
\setvalue{\??interlinespacerelative\v!auto }{\let\setrelativeinterlinespace\spac_linespacing_set_relative_interlinespace}
\def\spac_linespacing_set_specified_relative_interlinespace#1% fragile?
- {\doifdimenstringelse{#1}
+ {\doifelsedimenstring{#1}
{\setupspecifiedinterlinespace[\c!line=#1]}
{\assignvalue{#1}\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
\spacing\currentrelativeinterlinespace}}
@@ -140,6 +142,20 @@
\spacing\currentrelativeinterlinespace
\fi}
+\unexpanded\def\spac_linespacing_setup_use
+ {\ifcsname\namedinterlinespacehash\m_spac_interlinespace\s!parent\endcsname
+ \let\currentinterlinespace\m_spac_interlinespace
+ \spac_linespacing_setup_specified_interline_space
+ % \else
+ % we only support named interlinespaces
+ \fi}
+
+\unexpanded\def\useinterlinespaceparameter#1% see footnotes
+ {\edef\m_spac_interlinespace{#1\c!interlinespace}%
+ \ifx\m_spac_interlinespace\empty \else
+ \spac_linespacing_setup_use
+ \fi}
+
\newtoks\everysetupglobalinterlinespace
\newtoks\everysetuplocalinterlinespace
@@ -174,7 +190,7 @@
\fi\fi}
\def\spac_linespacing_setup_specified_or_relative[#1]%
- {\doifassignmentelse{#1}\setupspecifiedinterlinespace\setuprelativeinterlinespace[#1]%
+ {\doifelseassignment{#1}\setupspecifiedinterlinespace\setuprelativeinterlinespace[#1]%
\the\iflocalinterlinespace\everysetuplocalinterlinespace\else\everysetupglobalinterlinespace\fi}
\def\spac_linespacing_synchronize_local % adapts to the font
@@ -201,7 +217,7 @@
\fi
\popmacro\currentinterlinespace
\else
- \normalexpanded{\noexpand\doifassignmentelse{\p_spac_checked_interlinespace}%
+ \normalexpanded{\noexpand\doifelseassignment{\p_spac_checked_interlinespace}%
\setupspecifiedinterlinespace\setuprelativeinterlinespace[\p_spac_checked_interlinespace]}%
\iflocalinterlinespace
\the\everysetuplocalinterlinespace
@@ -334,7 +350,7 @@
\let\v_spac_whitespace_current\v!none
\unexpanded\def\setupwhitespace
- {\doifnextoptionalcselse\spac_whitespace_setup_yes\spac_whitespace_setup_nop}
+ {\doifelsenextoptionalcs\spac_whitespace_setup_yes\spac_whitespace_setup_nop}
\def\spac_whitespace_setup_nop
{\ifx\v_spac_whitespace_current\v!none\else
@@ -960,6 +976,35 @@
\let\normalstrut\strut
+\unexpanded\def\halfstrut
+ {\relax
+ \dontleavehmode
+ \begingroup
+ \setbox\scratchbox\copy\strutbox
+ \ht\scratchbox\dimexpr\strutht/\plustwo\relax
+ \dp\scratchbox\dimexpr\strutdp/\plustwo\relax
+ \box\scratchbox
+ \endgroup}
+
+\unexpanded\def\quarterstrut
+ {\relax
+ \dontleavehmode
+ \begingroup
+ \setbox\scratchbox\copy\strutbox
+ \ht\scratchbox\dimexpr\strutht/\plusfour\relax
+ \dp\scratchbox\dimexpr\strutdp/\plusfour\relax
+ \box\scratchbox
+ \endgroup}
+
+\unexpanded\def\depthstrut
+ {\relax
+ \dontleavehmode
+ \begingroup
+ \setbox\scratchbox\copy\strutbox
+ \ht\scratchbox\dimexpr\strutht-\struthtdp/\plustwo\relax % assumes that ht > lineheight/2
+ \box\scratchbox
+ \endgroup}
+
%D Sometimes a capstrut comes in handy
%D
%D \starttabulate[|Tl|l|l|]
@@ -1032,12 +1077,17 @@
\newbox\nostrutbox \setbox\nostrutbox\emptyhbox
+\newtoks\everysetnostrut
+
\unexpanded\def\setnostrut
- {\setbox\strutbox\copy\nostrutbox
- \let\strut\empty
- \let\endstrut\empty
- \let\begstrut\empty
- \let\crlfplaceholder\empty}
+ {\the\everysetnostrut}
+
+\appendtoks
+ \setbox\strutbox\copy\nostrutbox
+ \let\strut\empty
+ \let\endstrut\empty
+ \let\begstrut\empty
+\to \everysetnostrut
% when enabled, sigstruts will remove themselves if nothing
% goes inbetween
@@ -1167,7 +1217,7 @@
\let\normaloffinterlineskip\offinterlineskip % knuth's original
\appendtoks
- \ifvmode\ctxcommand{resetprevdepth()}\fi % a nasty hack (tested for a while now)
+ \ifvmode\clf_resetprevdepth\fi % a nasty hack (tested for a while now)
\to \everyafteroutput
%D My own one:
@@ -1341,7 +1391,7 @@
\unexpanded\def\installsnapvalues#1#2% todo: a proper define
{\edef\currentsnapper{#1:#2}%
\ifcsname\??gridsnapperattributes\currentsnapper\endcsname \else
- \setevalue{\??gridsnapperattributes\currentsnapper}{\ctxcommand{definesnapmethod("#1","#2")}}%
+ \setevalue{\??gridsnapperattributes\currentsnapper}{\clf_definesnapmethod{#1}{#2}}%
\fi
\setevalue{\??gridsnappers#1}{\attribute\snapmethodattribute\csname\??gridsnapperattributes\currentsnapper\endcsname\space}}
@@ -1410,6 +1460,9 @@
\definegridsnapping[\v!none] [\v!none]
\definegridsnapping[\v!line] [\v!line]
\definegridsnapping[\v!strut] [\v!strut]
+\definegridsnapping[\v!box] [\v!box] % centers a box rounded upwards (box:.5 -> tolerance)
+\definegridsnapping[\v!min] [\v!min] % centers a box rounded downwards
+\definegridsnapping[\v!max] [\v!max] % centers a box rounded upwards
\definegridsnapping[\v!max] [\v!maxdepth,\v!maxheight,\v!strut]
\definegridsnapping[\v!min] [\v!mindepth,\v!minheight,\v!strut]
@@ -1495,10 +1548,10 @@
\def\spac_grids_snap_to_finish#1%
{\ifvbox\nextbox % this will go away
- \ctxcommand{vspacingcollapse(\number\nextbox)}% isn't that already done?
+ \clf_vspacingcollapse\nextbox\relax % isn't that already done?
\fi
\doifelsenothing{#1}{\spac_grids_snap_value_set\v!normal}{\spac_grids_snap_value_set{#1}}%
- \ctxcommand{vspacingsnap(\number\nextbox,\number\attribute\snapmethodattribute)}%
+ \clf_vspacingsnap\nextbox\attribute\snapmethodattribute\relax
\ifvbox\nextbox\vbox\else\hbox\fi attr \snapmethodattribute \zerocount {\box\nextbox}%
\egroup}
@@ -1648,7 +1701,7 @@
\def\spac_vspacing_define_amount[#1][#2][#3]% can be combined
{\setvalue{\??vspacingamount#1}{\ifgridsnapping#3\else#2\fi}%
- \ctxcommand{vspacingsetamount("#1")}}
+ \clf_vspacingsetamount{#1}}
% \installcorenamespace{vspacingamountnormal}
% \installcorenamespace{vspacingamountgrid}
@@ -1660,13 +1713,13 @@
% \fi
% \csname n>#1\endcsname{#2}%
% \csname g>#1\endcsname{#3}%
-% \ctxcommand{vspacingsetamount("#1")}}
+% \clf_vspacingsetamount{#1}}
\unexpanded\def\definevspacing
{\dodoubleempty\spac_vspacing_define}
\def\spac_vspacing_define[#1][#2]%
- {\ctxcommand{vspacingdefine("#1","#2")}}
+ {\clf_vspacingdefine{#1}{#2}}
%D The injector code (generated at the \LUA\ end):
@@ -1767,7 +1820,7 @@
% The main spacer:
\unexpanded\def\vspacing
- {\doifnextoptionalcselse\spac_vspacing_yes\spac_vspacing_nop}
+ {\doifelsenextoptionalcs\spac_vspacing_yes\spac_vspacing_nop}
\def\spac_vspacing_yes
{\ifinpagebody % somewhat weird
@@ -1788,21 +1841,21 @@
\fi\fi}
\def\spac_vspacing_yes_indeed[#1]%
- {\ifmmode\else\par\ctxcommand{vspacing("#1")}\fi}
+ {\ifmmode\else\par\clf_vspacing{#1}\fi}
\def\spac_vspacing_yes_ignore[#1]%
{\ifmmode\else\par\fi}
\def\spac_vspacing_nop_indeed
- {\ifmmode\else\par\ctxcommand{vspacing("\currentvspacing")}\fi}
+ {\ifmmode\else\par\clf_vspacing{\currentvspacing}\fi}
\def\spac_vspacing_nop_ignore
{\ifmmode\else\par\fi}
\def\directvspacing#1%
- {\par\ctxcommand{vspacing("#1")}}
+ {\par\clf_vspacing{#1}}
-% handy (and faste):
+% handy (and faster):
\unexpanded\def\directvpenalty#1%
{\begingroup
@@ -1823,7 +1876,7 @@
% these depend on bigskipamount cum suis so we'd better sync them
\unexpanded\def\setupvspacing
- {\doifnextoptionalcselse\setupvspacing_yes\setupvspacing_nop}
+ {\doifelsenextoptionalcs\setupvspacing_yes\setupvspacing_nop}
\let\currentvspacing\s!default % hm, default, standard ...
@@ -1876,6 +1929,21 @@
\fi\fi
\relax}
+% used in itemize ... always test this
+
+\newdimen\d_spac_overlay
+
+\def\spac_overlay_lines
+ {\blank[\v!back,\v!overlay]%
+ \nointerlineskip}
+
+% \startitemize[n]
+% \item \input zapf
+% \item \startitemize[a]
+% \item \input knuth
+% \stopitemize
+% \stopitemize
+%
% \strut \hfill first line \blank[overlay] second line \hfill \strut
%
% \ruledvbox {
@@ -1883,6 +1951,9 @@
% line 2 \hfill \strut \blank[overlay]
% \strut \hfill line 3 \hfill \strut
% }
+%
+% \dorecurse{50}
+% {\startitemize[n] \startitem \startitemize[a] \item #1 \stopitemize \stopitem \stopitemize}
\definevspacing[\v!preference][penalty:-500] % goodbreak
\definevspacing[\v!samepage] [penalty:10000] % nobreak
@@ -1893,7 +1964,7 @@
\definevspacing[\v!back] [category:7]
% together [category:8]
\definevspacing[\v!overlay] [category:9]
-\definevspacing[\v!always] [category:0]
+\definevspacing[\v!always] [category:0] % hm, internally it's discard
\definevspacing[\v!weak] [order:0]
\definevspacing[\v!strong] [order:100]
@@ -1920,8 +1991,20 @@
%D \type {\blank} (we needed the first one while playing with the
%D new code).
+% We keep this one as reference
+%
+% \unexpanded\def\inhibitblank
+% {\vspacing[\v!disable]}
+%
+% but use the following more efficient variant instead:
+
\unexpanded\def\inhibitblank
- {\vspacing[\v!disable]} % can be made faster
+ {\ifvmode
+ \begingroup
+ \attribute\skipcategoryattribute\plusfive
+ \vskip\zeropoint
+ \endgroup
+ \fi}
\let\doinhibitblank\inhibitblank % keep this command, used in styles
@@ -2006,7 +2089,7 @@
\let\m_spac_hanging_location\empty
\def\spac_hanging_start[#1]%
- {\doifassignmentelse{#1}
+ {\doifelseassignment{#1}
{\let\m_spac_hanging_location\empty
\setupcurrenthanging[#1]}%
{\edef\m_spac_hanging_location{#1}}%
@@ -2135,7 +2218,7 @@
% as encountered in forced blank skips (see lua code)
%
% \appendtoks
-% \ifvmode\ctxcommand{resetprevdepth()}\fi
+% \ifvmode\clf_resetprevdepth\fi
% \to \everyafteroutput
%
% this should only happen when there is nothing left over (how to detemine that) .. testcase:
diff --git a/Master/texmf-dist/tex/context/base/status-files.pdf b/Master/texmf-dist/tex/context/base/status-files.pdf
index 24b73242775..dc228ad8ae4 100644
Binary files a/Master/texmf-dist/tex/context/base/status-files.pdf and b/Master/texmf-dist/tex/context/base/status-files.pdf differ
diff --git a/Master/texmf-dist/tex/context/base/status-lua.pdf b/Master/texmf-dist/tex/context/base/status-lua.pdf
index f6ca96bc3cd..02c9447e819 100644
Binary files a/Master/texmf-dist/tex/context/base/status-lua.pdf and b/Master/texmf-dist/tex/context/base/status-lua.pdf differ
diff --git a/Master/texmf-dist/tex/context/base/status-mkiv.lua b/Master/texmf-dist/tex/context/base/status-mkiv.lua
index 07e912a88ba..45c2822565b 100644
--- a/Master/texmf-dist/tex/context/base/status-mkiv.lua
+++ b/Master/texmf-dist/tex/context/base/status-mkiv.lua
@@ -320,7 +320,6 @@ return {
},
{
category = "mkiv",
- comment = "maybe this becomes a runtime module",
filename = "toks-ini",
loading = "always",
status = "okay",
@@ -392,6 +391,12 @@ return {
loading = "always",
status = "okay",
},
+ {
+ category = "mkiv",
+ filename = "typo-sus",
+ loading = "always",
+ status = "okay",
+ },
{
category = "mkiv",
filename = "node-pag",
@@ -540,6 +545,12 @@ return {
loading = "always",
status = "okay",
},
+ {
+ category = "mkiv",
+ filename = "lang-hyp",
+ loading = "always",
+ status = "okay",
+ },
{
category = "mkiv",
filename = "unic-ini",
@@ -613,6 +624,12 @@ return {
loading = "always",
status = "okay",
},
+ {
+ category = "mkiv",
+ filename = "lang-hyp",
+ loading = "always",
+ status = "okay",
+ },
{
category = "mkiv",
filename = "lang-frq",
@@ -2558,6 +2575,12 @@ return {
loading = "always",
status = "pending",
},
+ {
+ category = "mkiv",
+ filename = "publ-jrn",
+ loading = "always",
+ status = "pending",
+ },
{
category = "mkiv",
filename = "publ-xml",
@@ -3488,6 +3511,18 @@ return {
loading = "lang-def",
status = "okay",
},
+ {
+ category = "lua",
+ filename = "lang-dis",
+ loading = "lang-ini",
+ status = "okay",
+ },
+ {
+ category = "lua",
+ filename = "lang-hyp",
+ loading = "lang-hyp",
+ status = "okay",
+ },
{
category = "lua",
filename = "lang-ini",
@@ -3500,6 +3535,12 @@ return {
loading = "lang-lab",
status = "okay",
},
+ {
+ category = "lua",
+ filename = "lang-hyp",
+ loading = "lang-hyp",
+ status = "okay",
+ },
{
category = "lua",
filename = "lang-txt",
@@ -4716,7 +4757,14 @@ return {
{
category = "lua",
filename = "toks-ini",
- status = "todo",
+ loading = "toks-ini",
+ status = "okay",
+ },
+ {
+ category = "lua",
+ filename = "toks-scn",
+ loading = "toks-ini",
+ status = "okay",
},
{
category = "lua",
@@ -4818,6 +4866,11 @@ return {
filename = "typo-bld",
status = "todo",
},
+ {
+ category = "lua",
+ filename = "typo-sus",
+ status = "okay",
+ },
{
category = "lua",
filename = "typo-brk",
@@ -4905,6 +4958,11 @@ return {
filename = "typo-fln",
status = "okay",
},
+ {
+ category = "lua",
+ filename = "typo-man",
+ status = "todo",
+ },
{
category = "lua",
filename = "typo-prc",
@@ -5086,6 +5144,12 @@ return {
loading = "publ-ini.mkiv",
status = "pending",
},
+ {
+ category = "lua",
+ filename = "publ-fnd",
+ loading = "publ-ini.mkiv",
+ status = "pending",
+ },
{
category = "lua",
filename = "publ-tra",
diff --git a/Master/texmf-dist/tex/context/base/strc-bkm.lua b/Master/texmf-dist/tex/context/base/strc-bkm.lua
index c38ab3c2e8c..1ff75aa5f72 100644
--- a/Master/texmf-dist/tex/context/base/strc-bkm.lua
+++ b/Master/texmf-dist/tex/context/base/strc-bkm.lua
@@ -13,14 +13,15 @@ if not modules then modules = { } end modules ['strc-bkm'] = {
-- we should hook the placement into everystoptext ... needs checking
-local format, concat, gsub = string.format, table.concat, string.gsub
+-- todo: make an lpeg for stripped
+
+local next, type = next, type
+local gsub, lower = string.gsub, string.lower
+local concat = table.concat
local utfvalues = utf.values
local settings_to_hash = utilities.parsers.settings_to_hash
-local codeinjections = backends.codeinjections
-
-local trace_bookmarks = false trackers.register("references.bookmarks", function(v) trace_bookmarks = v end)
-
+local trace_bookmarks = false trackers.register("references.bookmarks", function(v) trace_bookmarks = v end)
local report_bookmarks = logs.reporter("structure","bookmarks")
local structures = structures
@@ -30,13 +31,17 @@ structures.bookmarks = structures.bookmarks or { }
local bookmarks = structures.bookmarks
local sections = structures.sections
local lists = structures.lists
-
local levelmap = sections.levelmap
local variables = interfaces.variables
+local implement = interfaces.implement
+local codeinjections = backends.codeinjections
-bookmarks.method = "internal" -- or "page"
+bookmarks.method = "internal" -- or "page"
-local names, opened, forced, numbered = { }, { }, { }, { }
+local names = { }
+local opened = { }
+local forced = { }
+local numbered = { }
function bookmarks.register(settings)
local force = settings.force == variables.yes
@@ -78,8 +83,13 @@ function bookmarks.overload(name,text)
end
end
if ls then
- ls.titledata.bookmark = text
+ local titledata = ls.titledata
+ if titledata then
+ titledata.bookmark = text
+ end
end
+ -- last resort
+ -- context.writetolist({name},text,"")
end
local function stripped(str) -- kind of generic
@@ -101,54 +111,6 @@ function bookmarks.setup(spec)
end
end
--- function bookmarks.place()
--- if next(names) then
--- local list = lists.filtercollected(names,"all",nil,lists.collected,forced)
--- if #list > 0 then
--- local levels, noflevels, lastlevel = { }, 0, 1
--- for i=1,#list do
--- local li = list[i]
--- local metadata = li.metadata
--- local name = metadata.name
--- if not metadata.nolist or forced[name] then -- and levelmap[name] then
--- local titledata = li.titledata
--- if titledata then
--- local structural = levelmap[name]
--- lastlevel = structural or lastlevel
--- local title = titledata.bookmark
--- if not title or title == "" then
--- -- We could typeset the title and then convert it.
--- if not structural then
--- -- placeholder, todo: bookmarklabel
--- title = name .. ": " .. (titledata.title or "?")
--- else
--- title = titledata.title or "?"
--- end
--- end
--- if numbered[name] then
--- local sectiondata = sections.collected[li.references.section]
--- local numberdata = li.numberdata
--- if sectiondata and numberdata and not numberdata.hidenumber then
--- -- we could typeset the number and convert it
--- title = concat(sections.typesetnumber(sectiondata,"direct",numberspec,sectiondata)) .. " " .. title
--- end
--- end
--- noflevels = noflevels + 1
--- levels[noflevels] = {
--- lastlevel,
--- stripped(title), -- can be replaced by converter
--- li.references, -- has internal and realpage
--- allopen or opened[name]
--- }
--- end
--- end
--- end
--- bookmarks.finalize(levels)
--- end
--- function bookmarks.place() end -- prevent second run
--- end
--- end
-
function bookmarks.place()
if next(names) then
local levels = { }
@@ -157,26 +119,51 @@ function bookmarks.place()
local nofblocks = #lists.sectionblocks -- always >= 1
local showblocktitle = toboolean(numberspec.showblocktitle,true)
for i=1,nofblocks do
- local block = lists.sectionblocks[i]
+ local block = lists.sectionblocks[i]
local blockdone = nofblocks == 1
- local list = lists.filtercollected(names,block..":all",nil,lists.collected,forced)
+ local list = lists.filter {
+ names = names,
+ criterium = block .. ":all",
+ forced = forced,
+ }
for i=1,#list do
local li = list[i]
local metadata = li.metadata
local name = metadata.name
if not metadata.nolist or forced[name] then -- and levelmap[name] then
local titledata = li.titledata
+ --
+ if not titledata then
+ local userdata = li.userdata
+ if userdata then
+ local first = userdata.first
+ local second = userdata.second
+ if first then
+ if second then
+ titledata = { title = first .. " " .. second }
+ else
+ titledata = { title = first }
+ end
+ else
+ titledata = { title = second }
+ end
+ end
+ end
+ --
if titledata then
if not blockdone then
if showblocktitle then
-- add block entry
local blockdata = sections.sectionblockdata[block]
noflevels = noflevels + 1
+ local references = li.references
levels[noflevels] = {
- 1, -- toplevel
- stripped(blockdata.bookmark ~= "" and blockdata.bookmark or block),
- li.references,
- allopen or opened[name] -- same as first entry
+ level = 1, -- toplevel
+ title = stripped(blockdata.bookmark ~= "" and blockdata.bookmark or block),
+ reference = references,
+ opened = allopen or opened[name], -- same as first entry
+ realpage = references and references.realpage or 0, -- handy for later
+ usedpage = true,
}
end
blockdone = true
@@ -190,27 +177,36 @@ function bookmarks.place()
local title = titledata.bookmark
if not title or title == "" then
-- We could typeset the title and then convert it.
- if not structural then
- -- placeholder, todo: bookmarklabel
- title = name .. ": " .. (titledata.title or "?")
- else
+ -- if not structural then
+ -- title = titledata.title or "?")
+ -- else
title = titledata.title or "?"
- end
+ -- end
end
if numbered[name] then
local sectiondata = sections.collected[li.references.section]
local numberdata = li.numberdata
- if sectiondata and numberdata and not numberdata.hidenumber then
+ if sectiondata and numberdata then
+ if not numberdata.hidenumber then
-- we could typeset the number and convert it
- title = concat(sections.typesetnumber(sectiondata,"direct",numberspec,sectiondata)) .. " " .. title
+ local number = sections.typesetnumber(sectiondata,"direct",numberspec,sectiondata)
+ if number and #number > 0 then
+ title = concat(number) .. " " .. title
+ end
+ end
end
end
noflevels = noflevels + 1
+ local references = li.references
levels[noflevels] = {
- lastlevel,
- stripped(title), -- can be replaced by converter
- li.references, -- has internal and realpage
- allopen or opened[name]
+ level = lastlevel,
+ title = stripped(title), -- can be replaced by converter
+ reference = references, -- has internal and realpage
+ opened = allopen or opened[name],
+ realpage = references and references.realpage or 0, -- handy for later
+ usedpage = true,
+ structural = structural,
+ name = name,
}
end
end
@@ -222,47 +218,296 @@ function bookmarks.place()
end
function bookmarks.flatten(levels)
+ if not levels then
+ -- a plugin messed up
+ return { }
+ end
-- This function promotes leading structurelements with a higher level
-- to the next lower level. Such situations are the result of lack of
-- structure: a subject preceding a chapter in a sectionblock. So, the
-- following code runs over section blocks as well. (bookmarks-007.tex)
local noflevels = #levels
if noflevels > 1 then
- local skip, start, one = false, 1, levels[1]
- local first, block = one[1], one[3].block
+ local function showthem()
+ for i=1,noflevels do
+ local level = levels[i]
+ -- if level.structural then
+ -- report_bookmarks("%i > %s > %s",level.level,level.reference.block,level.title)
+ -- else
+ report_bookmarks("%i > %s > %s > %s",level.level,level.reference.block,level.name,level.title)
+ -- end
+ end
+ end
+ if trace_bookmarks then
+ report_bookmarks("checking structure")
+ showthem()
+ end
+ local skip = false
+ local done = 0
+ local start = 1
+ local one = levels[1]
+ local first = one.level
+ local block = one.reference.block
for i=2,noflevels do
- local li = levels[i]
- local new, newblock = li[1], li[3].block
+ local current = levels[i]
+ local new = current.level
+ local reference = current.reference
+ local newblock = type(reference) == "table" and current.reference.block or block
if newblock ~= block then
- first, block, start, skip = new, newblock, i, false
+ first = new
+ block = newblock
+ start = i
+ skip = false
elseif skip then
-- go on
elseif new > first then
skip = true
elseif new < first then
for j=start,i-1 do
- local lj = levels[j]
- local old = lj[1]
- lj[1] = new
+ local previous = levels[j]
+ local old = previous.level
+ previous.level = new
if trace_bookmarks then
- report_bookmarks("promoting entry %a from level %a to %a: %s",j,old,new,lj[2])
+ report_bookmarks("promoting entry %a from level %a to %a: %s",j,old,new,previous.title)
end
+ done = done + 1
end
skip = true
end
end
+ if trace_bookmarks then
+ if done > 0 then
+ report_bookmarks("%a entries promoted")
+ showthem()
+ else
+ report_bookmarks("nothing promoted")
+ end
+ end
+ end
+ return levels
+end
+
+local extras = { }
+local lists = { }
+local names = { }
+
+bookmarks.extras = extras
+
+local function cleanname(name)
+ return lower(file.basename(name))
+end
+
+function extras.register(name,levels)
+ if name and levels then
+ name = cleanname(name)
+ local found = names[name]
+ if found then
+ lists[found].levels = levels
+ else
+ lists[#lists+1] = {
+ name = name,
+ levels = levels,
+ }
+ names[name] = #lists
+ end
+ end
+end
+
+function extras.get(name)
+ if name then
+ local found = names[cleanname(name)]
+ if found then
+ return lists[found].levels
+ end
+ else
+ return lists
+ end
+end
+
+function extras.reset(name)
+ local l, n = { }, { }
+ if name then
+ name = cleanname(name)
+ for i=1,#lists do
+ local li = lists[i]
+ local ln = li.name
+ if name == ln then
+ -- skip
+ else
+ local m = #l + 1
+ l[m] = li
+ n[ln] = m
+ end
+ end
+ end
+ lists, names = l, n
+end
+
+local function checklists()
+ for i=1,#lists do
+ local levels = lists[i].levels
+ for j=1,#levels do
+ local entry = levels[j]
+ local pageindex = entry.pageindex
+ if pageindex then
+ entry.reference = figures.getrealpage(pageindex)
+ entry.pageindex = nil
+ end
+ end
end
end
+function extras.tosections(levels)
+ local sections = { }
+ local noflists = #lists
+ for i=1,noflists do
+ local levels = lists[i].levels
+ local data = { }
+ sections[i] = data
+ for j=1,#levels do
+ local entry = levels[j]
+ if entry.usedpage then
+ local section = entry.section
+ local d = data[section]
+ if d then
+ d[#d+1] = entry
+ else
+ data[section] = { entry }
+ end
+ end
+ end
+ end
+ return sections
+end
+
+function extras.mergesections(levels,sections)
+ if not sections or #sections == 0 then
+ return levels
+ elseif not levels then
+ return { }
+ else
+ local merge = { }
+ local noflists = #lists
+ if #levels == 0 then
+ local level = 0
+ local section = 0
+ for i=1,noflists do
+ local entries = sections[i][0]
+ if entries then
+ for i=1,#entries do
+ local entry = entries[i]
+ merge[#merge+1] = entry
+ entry.level = entry.level + level
+ end
+ end
+ end
+ else
+ for j=1,#levels do
+ local entry = levels[j]
+ merge[#merge+1] = entry
+ local section = entry.reference.section
+ local level = entry.level
+ entry.section = section -- for tracing
+ for i=1,noflists do
+ local entries = sections[i][section]
+ if entries then
+ for i=1,#entries do
+ local entry = entries[i]
+ merge[#merge+1] = entry
+ entry.level = entry.level + level
+ end
+ end
+ end
+ end
+ end
+ return merge
+ end
+end
+
+function bookmarks.merge(levels,mode)
+ return extras.mergesections(levels,extras.tosections())
+end
+
+local sequencers = utilities.sequencers
+local appendgroup = sequencers.appendgroup
+local appendaction = sequencers.appendaction
+
+local bookmarkactions = sequencers.new {
+ arguments = "levels,method",
+ returnvalues = "levels",
+ results = "levels",
+}
+
+appendgroup(bookmarkactions,"before") -- user
+appendgroup(bookmarkactions,"system") -- private
+appendgroup(bookmarkactions,"after" ) -- user
+
+appendaction(bookmarkactions,"system",bookmarks.flatten)
+appendaction(bookmarkactions,"system",bookmarks.merge)
+
function bookmarks.finalize(levels)
- -- This function can be overloaded by an optional converter
- -- that uses nodes.toutf on a typeset stream. This is something
- -- that we will support when the main loop has become a coroutine.
- codeinjections.addbookmarks(levels,bookmarks.method)
+ local method = bookmarks.method or "internal"
+ checklists() -- so that plugins have the adapted page number
+ levels = bookmarkactions.runner(levels,method)
+ if levels and #levels > 0 then
+ -- normally this is not needed
+ local purged = { }
+ for i=1,#levels do
+ local l = levels[i]
+ if l.usedpage ~= false then
+ purged[#purged+1] = l
+ end
+ end
+ --
+ codeinjections.addbookmarks(purged,method)
+ else
+ -- maybe a plugin messed up
+ end
+end
+
+function bookmarks.installhandler(what,where,func)
+ if not func then
+ where, func = "after", where
+ end
+ if where == "before" or where == "after" then
+ sequencers.appendaction(bookmarkactions,where,func)
+ else
+ report_tex("installing bookmark %a handlers in %a is not possible",what,tostring(where))
+ end
end
-- interface
-commands.overloadbookmark = bookmarks.overload
-commands.registerbookmark = bookmarks.register
-commands.setupbookmarks = bookmarks.setup
+implement {
+ name = "setupbookmarks",
+ actions = bookmarks.setup,
+ arguments = {
+ {
+ { "separatorset" },
+ { "conversionset" },
+ { "starter" },
+ { "stopper" },
+ { "segments" },
+ { "showblocktitle" },
+ }
+ }
+}
+
+implement {
+ name = "registerbookmark",
+ actions = bookmarks.register,
+ arguments = {
+ {
+ { "names" },
+ { "opened" },
+ { "force" },
+ { "number" },
+ }
+ }
+}
+
+implement {
+ name = "overloadbookmark",
+ actions = bookmarks.overload,
+ arguments = { "string", "string" }
+}
diff --git a/Master/texmf-dist/tex/context/base/strc-bkm.mkiv b/Master/texmf-dist/tex/context/base/strc-bkm.mkiv
index 9d2ebd796c6..9688a1f93b1 100644
--- a/Master/texmf-dist/tex/context/base/strc-bkm.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-bkm.mkiv
@@ -74,7 +74,11 @@
\def\strc_bookmarks_bookmark_yes[#1]#2%
{\begingroup
\simplifycommands
- \ctxcommand{overloadbookmark("#1",\!!bs\detokenize\expandafter{\normalexpanded{#2}}\!!es)}%
+ \ifnum\thenamedheadlevel{#1}>\zerocount
+ \clf_overloadbookmark{#1}{\detokenize\expandafter{\normalexpanded{#2}}}%
+ \else
+ \strc_lists_write_to[#1][]{#2}{}% todo: a dedicated bookmark writer
+ \fi
\endgroup}
\def\strc_bookmarks_bookmark_nop[#1]#2%
@@ -106,27 +110,59 @@
\ifthirdargument
\setupcurrentbookmark[#3]% no every so not all possible
\else\ifsecondargument
- \doifassignmentelse{#2}{\let\m_bookmarks_opened\empty\setupcurrentbookmark[#2]}\donothing
+ \doifelseassignment{#2}{\let\m_bookmarks_opened\empty\setupcurrentbookmark[#2]}\donothing
\fi\fi
- \ctxcommand{registerbookmark {
- names = "\m_bookmarks_names",
- opened = "\m_bookmarks_opened",
- force = "\bookmarkparameter\c!force",
- number = "\bookmarkparameter\c!number",
- }}%
+ \clf_registerbookmark
+ names {\m_bookmarks_names}%
+ opened {\m_bookmarks_opened}%
+ force {\bookmarkparameter\c!force}%
+ number {\bookmarkparameter\c!number}%
+ \relax
\endgroup}
\appendtoks
- \ctxcommand{setupbookmarks {
- separatorset = "\bookmarkparameter\c!numberseparatorset",
- conversionset = "\bookmarkparameter\c!numberconversionset",
- starter = \!!bs\bookmarkparameter\c!numberstarter\!!es,
- stopper = \!!bs\bookmarkparameter\c!numberstopper\!!es,
- segments = "\bookmarkparameter\c!numbersegments",
- showblocktitle = "\bookmarkparameter\c!sectionblock",
- }}%
+ \clf_setupbookmarks
+ separatorset {\bookmarkparameter\c!numberseparatorset}%
+ conversionset {\bookmarkparameter\c!numberconversionset}%
+ starter {\bookmarkparameter\c!numberstarter}%
+ stopper {\bookmarkparameter\c!numberstopper}%
+ segments {\bookmarkparameter\c!numbersegments}%
+ showblocktitle {\bookmarkparameter\c!sectionblock}%
+ \relax
\to \everysetupbookmark
+%D There is a plugin mechanism but this is for experts only. The intermediate
+%D data structures are stable.
+%D
+%D \starttyping
+%D \startluacode
+%D structures.bookmarks.installhandler("check before","before",function(levels)
+%D logs.report("extra bookmarks","before (normal bookmarks)")
+%D inspect(levels)
+%D logs.report("extra bookmarks","before (extra bookmarks)")
+%D inspect(structures.bookmarks.extras.get())
+%D return levels
+%D end)
+%D structures.bookmarks.installhandler("check after", "after", function(levels)
+%D logs.report("extra bookmarks","after (merged bookmarks)")
+%D inspect(levels)
+%D return levels
+%D end)
+%D \stopluacode
+%D \starttyping
+%D
+%D This mechanism was added when bookmark inclusion became (optional) part of graphic
+%D inclusion (which is needed by Taco).
+%D
+%D \starttyping
+%D \getfiguredimensions[somefile.pdf]
+%D \dorecurse {\noffigurepages} {
+%D \startTEXpage
+%D \externalfigure[somefile.pdf][interaction=bookmark,page=\recurselevel]
+%D \stopTEXpage
+%D }
+%D \starttyping
+
\protect \endinput
% \starttext
diff --git a/Master/texmf-dist/tex/context/base/strc-blk.lua b/Master/texmf-dist/tex/context/base/strc-blk.lua
index ce3304d59af..0ababcfc09c 100644
--- a/Master/texmf-dist/tex/context/base/strc-blk.lua
+++ b/Master/texmf-dist/tex/context/base/strc-blk.lua
@@ -16,6 +16,8 @@ local allocate = utilities.storage.allocate
local context = context
local commands = commands
+local implement = interfaces.implement
+
local structures = structures
structures.blocks = structures.blocks or { }
@@ -78,13 +80,19 @@ end
function blocks.select(state,name,tag,criterium)
criterium = criterium or "text"
- if find(tag,"=",1,true) then tag = "" end
- local names = settings_to_set(name)
- local all = tag == ""
- local tags = not all and settings_to_set(tag)
- local hide = state == "process"
- local n = sections.numberatdepth(criterium)
- local result = lists.filtercollected("all", criterium, n, collected, { })
+ if find(tag,"=",1,true) then
+ tag = ""
+ end
+ local names = settings_to_set(name)
+ local all = tag == ""
+ local tags = not all and settings_to_set(tag)
+ local hide = state == "process"
+ local result = lists.filter {
+ names = "all",
+ criterium = criterium,
+ number = sections.numberatdepth(criterium), -- not needed
+ collected = collected,
+ }
for i=1,#result do
local ri = result[i]
local metadata = ri.metadata
@@ -148,8 +156,7 @@ end
-- interface
-
-commands.definestructureblock = blocks.define
-commands.savestructureblock = blocks.save
-commands.selectstructureblock = blocks.select
-commands.setstructureblockstate = blocks.setstate
+implement { name = "definestructureblock", actions = blocks.define, arguments = "string" }
+implement { name = "savestructureblock", actions = blocks.save, arguments = { "string", "string" ,"string" } }
+implement { name = "selectstructureblock", actions = blocks.select, arguments = { "string", "string" ,"string", "string" } }
+implement { name = "setstructureblockstate", actions = blocks.setstate, arguments = { "string", "string" ,"string" } }
diff --git a/Master/texmf-dist/tex/context/base/strc-blk.mkiv b/Master/texmf-dist/tex/context/base/strc-blk.mkiv
index bceb66beb1a..fe259d223ce 100644
--- a/Master/texmf-dist/tex/context/base/strc-blk.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-blk.mkiv
@@ -33,7 +33,7 @@
\installcommandhandler \??block {block} \??block
\appendtoks
- \ctxcommand{definestructureblock("\currentblock")}%
+ \clf_definestructureblock{\currentblock}%
\setuevalue{\e!begin\currentblock}{\dodoubleempty\strc_blocks_begin[\currentblock]}%
\setuevalue{\e!end \currentblock}{}%
\to \everydefineblock
@@ -41,7 +41,7 @@
\unexpanded\def\strc_blocks_begin[#1][#2]%
{\normalexpanded{\buff_pickup{@block@}{\e!begin#1}{\e!end#1}}
{}% before
- {\ctxcommand{savestructureblock("#1","#2","@block@")}}%
+ {\clf_savestructureblock{#1}{#2}{@block@}}%
\plusone}% after
\let\strc_blocks_setup\relax
@@ -72,17 +72,17 @@
\egroup}
\def\strc_blocks_set_state[#1][#2][#3]% state name tag
- {\ctxcommand{setstructureblockstate("#1","#2","#3")}}
+ {\clf_setstructureblockstate{#1}{#2}{#3}}
\def\strc_blocks_select[#1][#2][#3][#4]% state name tag setups
{\bgroup
- \doifassignmentelse{#3}
+ \doifelseassignment{#3}
{\getparameters[\??blocktemp][\c!criterium=\v!text,#3]%
\def\strc_blocks_setup{\setupcurrentblock[#3]}%
- \ctxcommand{selectstructureblock("#1","#2","","\csname\??blocktemp\c!criterium\endcsname")}}
+ \clf_selectstructureblock{#1}{#2}{}{\csname\??blocktemp\c!criterium\endcsname}}
{\getparameters[\??blocktemp][\c!criterium=\v!text,#4]%
\def\strc_blocks_setup{\setupcurrentblock[#4]}%
- \ctxcommand{selectstructureblock("#1","#2","#3","\csname\??blocktemp\c!criterium\endcsname")}}%
+ \clf_selectstructureblock{#1}{#2}{#3}{\csname\??blocktemp\c!criterium\endcsname}}%
\egroup}
% hide : save, if [+] also hidden execute
diff --git a/Master/texmf-dist/tex/context/base/strc-con.mkvi b/Master/texmf-dist/tex/context/base/strc-con.mkvi
index 1862b00a6fd..11f6f758e0e 100644
--- a/Master/texmf-dist/tex/context/base/strc-con.mkvi
+++ b/Master/texmf-dist/tex/context/base/strc-con.mkvi
@@ -159,6 +159,7 @@
\unexpanded\def\strc_constructions_initialize#1% class instance
{\edef\currentconstruction{#1}%
+ \let\currentconstructionhash\??construction
\let\currentconstructionlistentry\!!zerocount
\expandafter\let\expandafter\currentconstructionmain \csname\??constructionmain \currentconstruction\endcsname
\expandafter\let\expandafter\currentconstructionlevel \csname\??constructionlevel\currentconstruction\endcsname
@@ -214,7 +215,7 @@
\constructionparameter\c!headcommand
{\strut
\constructionparameter\c!text
- \ctxcommand{savedlisttitle("\currentconstructionmain",\currentconstructionlistentry)}}%
+ \clf_savedlisttitle{\currentconstructionmain}\currentconstructionlistentry\relax}%
\endgroup}
\unexpanded\def\strc_constructions_stored_start
@@ -262,10 +263,14 @@
\def\strc_constructions_ignore_head
{\constructionsheaddistance\zeropoint
- \constructionsheadwidth \zeropoint}
+ \constructionsheadwidth \zeropoint
+ % we also need to make sure that no stretch creeps in (new per 2015-02-02, for Alan)
+ \settrue\c_strc_constructions_distance_none}
+
+\let\currentconstructionhash\??construction
\unexpanded\setvalue{\??constructionstarthandler\v!construction}% this will be redone (reorganized) .. too much boxing
- {\dostarttagged\t!construction\currentconstruction
+ {\dostarttaggedchained\t!construction\currentconstruction\currentconstructionhash
\dotagsetconstruction
\constructionparameter\c!before
\begingroup
@@ -322,7 +327,7 @@
\else
\strc_constructions_preroll_head\currentconstructionsample
\ifzeropt\wd\constructionheadbox
- \strc_constructions_ignore_head
+ \strc_constructions_ignore_head
\else
\strc_constructions_set_width_and_distance
\fi
@@ -352,10 +357,6 @@
\ifx\p_strc_constructions_align\empty \else
\setupalign[\p_strc_constructions_align]% \use...
\fi
- \edef\p_strc_constructions_indenting{\constructionparameter\c!indenting}%
- \ifx\p_strc_constructions_indenting\empty \else
- \indenting[\p_strc_constructions_indenting]% \use...
- \fi
\ifcase\c_strc_constructions_nested_state
\c_strc_constructions_nested_state\plusone
\or
@@ -366,6 +367,11 @@
\edef\p_strc_constructions_headalign{\constructionparameter\c!headalign}%
%
\directsetup\p_strc_constructions_renderingsetup\relax
+ % moved to here 2014-07-03
+ \edef\p_strc_constructions_indenting{\constructionparameter\c!indenting}%
+ \ifx\p_strc_constructions_indenting\empty \else
+ \indenting[\p_strc_constructions_indenting]% \use...
+ \fi
%
\dostoptagged % tag
\dostarttagged\t!constructioncontent\empty
@@ -502,7 +508,7 @@
\setupalign[\p_strc_constructions_headalign]% use fast one
\fi
\ifhbox\constructionheadbox\unhcopy\else\copy\fi\constructionheadbox}%
-\setbox\constructionheadbox\hbox{\box\constructionheadbox}% needed in case of e.g. a real big head font, see descriptions-006.tex
+ \setbox\constructionheadbox\hbox{\box\constructionheadbox}% needed in case of e.g. a real big head font, see descriptions-006.tex
\ht\constructionheadbox\strutht
\dp\constructionheadbox\strutdp}
@@ -526,9 +532,14 @@
% The setups. These only deal with placement of the descriptor and initializing the
% environment. The wrapping happens elsewhere.
+% todo: optimize the setups with
+%
+% \ifconditional\c_strc_constructions_distance_none : no need for skip
+% \ifzeropt\wd\constructionheadbox : no need for box and skips
+
\startsetups[\??constructionrenderings:\v!left]
\edef\p_strc_constructions_hang{\constructionparameter\c!hang}%
- \doifsetupselse{\??constructionrenderings:\v!left:\p_strc_constructions_hang} {
+ \doifelsesetups{\??constructionrenderings:\v!left:\p_strc_constructions_hang} {
\directsetup{\??constructionrenderings:\v!left:\p_strc_constructions_hang}
} {
\directsetup{\??constructionrenderings:\v!left:\v!hanging}
@@ -537,7 +548,7 @@
\startsetups[\??constructionrenderings:\v!right]
\edef\p_strc_constructions_hang{\constructionparameter\c!hang}
- \doifsetupselse{\??constructionrenderings:\v!right:\p_strc_constructions_hang} {
+ \doifelsesetups{\??constructionrenderings:\v!right:\p_strc_constructions_hang} {
\directsetup{\??constructionrenderings:\v!right:\p_strc_constructions_hang}
} {
\directsetup{\??constructionrenderings:\v!right:\v!hanging}
@@ -556,6 +567,7 @@
\copy\constructionheadbox\hss
}
}
+ \nobreak
\useconstructionstyleandcolor\c!style\c!color
\ignorespaces
\stopsetups
@@ -580,6 +592,7 @@
\copy\constructionheadbox
\hskip\rightconstructionskip
}
+ \nobreak
\advance\rightskip \constructionsheaddistance
\useconstructionstyleandcolor\c!style\c!color
\ignorespaces
@@ -634,6 +647,7 @@
\box\constructionheadbox
}
}
+ \nobreak
\useconstructionstyleandcolor\c!style\c!color
\ignorespaces
\stopsetups
@@ -653,6 +667,7 @@
}
}
}
+ \nobreak
\useconstructionstyleandcolor\c!style\c!color
\ignorespaces
\stopsetups
@@ -730,7 +745,7 @@
\startsetups[\??constructionrenderings:\v!serried]
\edef\p_strc_constructions_width{\constructionparameter\c!width}% CHECK ! ! ! wrong parameter namespace
- \doifsetupselse{\??constructionrenderings:\v!serried:\p_strc_constructions_width} {
+ \doifelsesetups{\??constructionrenderings:\v!serried:\p_strc_constructions_width} {
\directsetup{\??constructionrenderings:\v!serried:\p_strc_constructions_width}
} {
\directsetup{\??constructionrenderings:\v!serried:\v!wide}
@@ -741,7 +756,7 @@
\let\\=\crlf
\noindent
\ifhbox\constructionheadbox\unhcopy\else\copy\fi\constructionheadbox % why copy? leftover?
- \penalty\plustenthousand % new
+ \nobreak
\hskip\constructionsheaddistance\relax
\useconstructionstyleandcolor\c!style\c!color
\ignorespaces
@@ -752,8 +767,8 @@
\noindent
\ifhbox\constructionheadbox\unhcopy\else\copy\fi\constructionheadbox % why copy? leftover?
\ifconditional\c_strc_constructions_distance_none \else
- \penalty\plustenthousand % new
- \hskip\constructionsheaddistance \!!plus .5\constructionsheaddistance \!!minus .25\constructionsheaddistance\relax
+ \nobreak
+ \hskip\constructionsheaddistance \!!plus .5\constructionsheaddistance \!!minus .25\constructionsheaddistance\relax
\fi
\useconstructionstyleandcolor\c!style\c!color
\ignorespaces
@@ -770,6 +785,7 @@
\ifhbox\constructionheadbox\unhcopy\else\copy\fi\constructionheadbox
\hss
}
+ \nobreak
\hskip\constructionsheaddistance\relax
\useconstructionstyleandcolor\c!style\c!color
\ignorespaces
@@ -845,7 +861,7 @@
\let\currentconstructionlistentry\!!zerocount
\def\strc_constructions_register
- {\ctxcommand{doiflisthasentry(\currentconstructionlistentry)}%
+ {\clf_doifelselisthasentry\numexpr\currentconstructionlistentry\relax
\strc_constructions_register_nop
\strc_constructions_register_yes}
@@ -858,7 +874,7 @@
\def\strc_constructions_discard
{\iftrialtypesetting
% \writestatus{constructions}{discarding \currentconstruction: \number\currentconstructionlistentry}%
- \ctxcommand{discardfromlist(\currentconstructionlistentry)}%
+ \clf_discardfromlist\currentconstructionlistentry\relax
\fi}
\let\currentconstructionlistnumber \!!zerocount
@@ -928,59 +944,63 @@
\else
\setnextinternalreferences{construction}\currentconstructionmain % plural
\relax
- \scratchcounter\ctxcommand{addtolist{ % we can set a counter at the lua end
- metadata = {
- kind = "construction",
- name = "\currentconstructionmain",
- level = structures.sections.currentlevel(),
- catcodes = \the\catcodetable,
- % \currentdirectionparameters
- },
- references = {
- internal = \nextinternalreference,
- order = \nextinternalorderreference,
- reference = "\currentconstructionreference",
- referenceprefix = "\referenceprefix",
- block = "\currentsectionblock",
- section = structures.sections.currentid(),
- },
- titledata = {
- label = \!!bs\detokenize\expandafter{\currentconstructionlabel }\!!es,
- title = \!!bs\detokenize\expandafter{\currentconstructiontitle }\!!es,
+ \scratchcounter\clf_addtolist
+ metadata {
+ kind {construction}
+ name {\currentconstructionmain}
+ % level structures.sections.currentlevel()
+ catcodes \catcodetable
+ % \currentdirectionparameters
+ }
+ references {
+ internal \nextinternalreference
+ order \nextinternalorderreference
+ reference {\currentconstructionreference}
+ prefix {\referenceprefix}
+ % block {\currentsectionblock}
+ % section structures.sections.currentid(),
+ }
+ titledata {
+ label {\detokenize\expandafter{\currentconstructionlabel}}
+ title {\detokenize\expandafter{\currentconstructiontitle}}
\ifx\currentconstructionbookmark\currentconstructiontitle \else
- bookmark = \!!bs\detokenize\expandafter{\currentconstructionbookmark}\!!es,
+ bookmark {\detokenize\expandafter{\currentconstructionbookmark}}
\fi
\ifx\currentconstructionlist\currentconstructiontitle \else
- list = \!!bs\detokenize\expandafter{\currentconstructionlist }\!!es,
+ list {\detokenize\expandafter{\currentconstructionlist}}
\fi
- },
+ }
\ifconditional\c_strc_constructions_number_state
- prefixdata = {
- prefix = "\constructionparameter\c!prefix",
- separatorset = "\constructionparameter\c!prefixseparatorset",
- conversion = \!!bs\constructionparameter\c!prefixconversion\!!es,
- conversionset = "\constructionparameter\c!prefixconversionset",
- set = "\constructionparameter\c!prefixset",
- segments = "\constructionparameter\c!prefixsegments",
- connector = \!!bs\constructionparameter\c!prefixconnector\!!es,
- },
- numberdata = {
- numbers = structures.counters.compact("\currentconstructionnumber",nil,true), % ! number can be cloned
- separatorset = "\constructionparameter\c!numberseparatorset",
- conversion = "\constructionparameter\c!numberconversion",
- conversionset = "\constructionparameter\c!numberconversionset",
- starter = \!!bs\constructionparameter\c!numberstarter\!!es,
- stopper = \!!bs\constructionparameter\c!numberstopper\!!es,
- segments = "\constructionparameter\c!numbersegments",
- },
+ prefixdata {
+ prefix {\constructionparameter\c!prefix}
+ separatorset {\constructionparameter\c!prefixseparatorset}
+ conversion {\constructionparameter\c!prefixconversion}
+ conversionset {\constructionparameter\c!prefixconversionset}
+ set {\constructionparameter\c!prefixset}
+ segments {\constructionparameter\c!prefixsegments}
+ connector {\constructionparameter\c!prefixconnector}
+ }
+ numberdata {
+ numbers {\currentconstructionnumber}
+ separatorset {\constructionparameter\c!numberseparatorset}
+ conversion {\constructionparameter\c!numberconversion}
+ conversionset {\constructionparameter\c!numberconversionset}
+ starter {\constructionparameter\c!numberstarter}
+ stopper {\constructionparameter\c!numberstopper}
+ segments {\constructionparameter\c!numbersegments}
+ }
\or
% symbol
\fi
- userdata = \!!bs\detokenize{#2}\!!es % will be converted to table at the lua end
- }
- }\relax
+ userdata {\detokenize{#2}}
+ \relax
% \writestatus{constructions}{registering \currentconstruction: \number\scratchcounter}%
- \ctxcommand{setinternalreference("\referenceprefix","\currentconstructionreference",\nextinternalreference,"\interactionparameter\c!focus")}%
+ \clf_setinternalreference
+ prefix {\referenceprefix}%
+ reference {\currentconstructionreference}%
+ internal \nextinternalreference
+ view {\interactionparameter\c!focus}%
+ \relax
\normalexpanded{%
\endgroup
\edef\noexpand\currentconstructionlistentry {\the\scratchcounter}%
@@ -994,7 +1014,7 @@
% macros.
\def\reinstateconstructionnumberentry#1% was xdef
- {\edef\currentconstructionattribute {\ctxcommand {getinternallistreference(#1)}}%
+ {\edef\currentconstructionattribute {\clf_getinternallistreference#1}%
\edef\currentconstructionsynchronize{\ctxlatecommand{enhancelist(#1)}}}
\installstructurelistprocessor{construction}{\usestructurelistprocessor{number+title}}
diff --git a/Master/texmf-dist/tex/context/base/strc-def.mkiv b/Master/texmf-dist/tex/context/base/strc-def.mkiv
index 0738bdf29d8..b4d2a5feadf 100644
--- a/Master/texmf-dist/tex/context/base/strc-def.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-def.mkiv
@@ -32,6 +32,7 @@
\defineresetset [\s!default] [] [1] % each level
\defineprefixset [\s!default] [section-1,section-2,section-3] []
+\defineconversionset [\v!number] [] [numbers]
\defineconversionset [\v!pagenumber] [] [numbers]
\defineprefixset [\v!all] [section-1,section-2,section-3,section-4,section-5,section-6,section-7,section-8] []
@@ -47,6 +48,9 @@
\setupuserpagenumber
[\c!numberconversionset=\v!pagenumber]
+\setupcounters
+ [\c!numberconversionset=\v!number]
+
% \startsetups defaults:frontpart:pagenumbers:roman
% \defineconversionset[\c!frontpart:\c!pagenumber][][romannumerals]
% \setupuserpagenumber[\c!way=\v!by\v!block]
@@ -220,19 +224,19 @@
[\c!before={\blank[\v!preference,\v!big]}, % sort of mkii compatible, watch columns
\c!after=\blank,
\c!label=\v!yes,
- \c!distance=1em]
+ \c!distance=\emwidth]
\setuplist
[\v!chapter]
[\c!before={\blank[\v!preference,\v!big]}, % sort of mkii compatible, watch columns
\c!after=]
-\setuplist [\v!part] [\c!width=0em]
-\setuplist [\v!chapter] [\c!width=2em]
-\setuplist [\v!section] [\c!width=3em]
-\setuplist [\v!subsection] [\c!width=4em]
-\setuplist [\v!subsubsection] [\c!width=5em]
-\setuplist [\v!subsubsubsection] [\c!width=6em]
-\setuplist [\v!subsubsubsubsection] [\c!width=7em]
+\setuplist [\v!part] [\c!width=0\emwidth]
+\setuplist [\v!chapter] [\c!width=2\emwidth]
+\setuplist [\v!section] [\c!width=3\emwidth]
+\setuplist [\v!subsection] [\c!width=4\emwidth]
+\setuplist [\v!subsubsection] [\c!width=5\emwidth]
+\setuplist [\v!subsubsubsection] [\c!width=6\emwidth]
+\setuplist [\v!subsubsubsubsection] [\c!width=7\emwidth]
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/strc-des.mkvi b/Master/texmf-dist/tex/context/base/strc-des.mkvi
index fa20d3caea9..3557000f91d 100644
--- a/Master/texmf-dist/tex/context/base/strc-des.mkvi
+++ b/Master/texmf-dist/tex/context/base/strc-des.mkvi
@@ -76,6 +76,7 @@
\unexpanded\setvalue{\??constructioninitializer\v!description}%
{\let\currentdescription \currentconstruction
\let\constructionparameter \descriptionparameter
+ \let\constructionnamespace \??description
\let\detokenizedconstructionparameter\detokenizeddescriptionparameter
\let\letconstructionparameter \letdescriptionparameter
\let\useconstructionstyleandcolor \usedescriptionstyleandcolor
@@ -102,10 +103,10 @@
\unexpanded\def\strc_descriptions_start#1%
{\begingroup
\strc_constructions_initialize{#1}%
- \doifnextoptionalcselse\strc_descriptions_start_yes\strc_descriptions_start_nop}
+ \doifelsenextoptionalcs\strc_descriptions_start_yes\strc_descriptions_start_nop}
\unexpanded\def\strc_descriptions_start_yes[#1]%
- {\doifassignmentelse{#1}\strc_descriptions_start_yes_assignment\strc_descriptions_start_yes_reference[#1]}
+ {\doifelseassignment{#1}\strc_descriptions_start_yes_assignment\strc_descriptions_start_yes_reference[#1]}
\unexpanded\def\strc_descriptions_start_yes_assignment[#1]% todo userdata
{\strc_constructions_register[\c!label={\descriptionparameter\c!text},\c!reference=,\c!title=,\c!bookmark=,\c!list=,#1][]%
@@ -119,7 +120,7 @@
\fi}
\unexpanded\def\strc_descriptions_start_yes_titled[#1]%
- {\doifnextbgroupelse
+ {\doifelsenextbgroup
{\strc_descriptions_start_yes_titled_indeed[#1]}%
{\setfalse\c_strc_constructions_title_state
\strc_descriptions_start_yes_normal[#1]}}
@@ -140,7 +141,7 @@
\fi}
\unexpanded\def\strc_descriptions_start_nop_titled
- {\doifnextbgroupelse
+ {\doifelsenextbgroup
{\strc_descriptions_start_nop_titled_indeed}%
{\setfalse\c_strc_constructions_title_state
\strc_descriptions_start_nop_normal}}%
@@ -162,7 +163,7 @@
\unexpanded\def\strc_descriptions_command#1%
{\begingroup
\strc_constructions_initialize{#1}%
- \doifnextoptionalcselse\strc_descriptions_yes\strc_descriptions_nop}
+ \doifelsenextoptionalcs\strc_descriptions_yes\strc_descriptions_nop}
\unexpanded\def\strc_descriptions_yes
{\ifconditional\c_strc_constructions_title_state
@@ -176,7 +177,7 @@
\csname\??constructioncommandhandler\currentconstructionhandler\endcsname}
\unexpanded\def\strc_descriptions_yes_titled[#1]%
- {\doifnextbgroupelse
+ {\doifelsenextbgroup
{\strc_descriptions_yes_titled_indeed[#1]}%
{\setfalse\c_strc_constructions_title_state
\strc_descriptions_yes_normal[#1]}}
@@ -197,7 +198,7 @@
\fi}
\unexpanded\def\strc_descriptions_nop_titled
- {\doifnextbgroupelse
+ {\doifelsenextbgroup
{\strc_descriptions_nop_titled_indeed}%
{\setfalse\c_strc_constructions_title_state
\strc_descriptions_nop_normal}}
diff --git a/Master/texmf-dist/tex/context/base/strc-doc.lua b/Master/texmf-dist/tex/context/base/strc-doc.lua
index 38830a4e77c..029d68a9dc2 100644
--- a/Master/texmf-dist/tex/context/base/strc-doc.lua
+++ b/Master/texmf-dist/tex/context/base/strc-doc.lua
@@ -17,15 +17,18 @@ if not modules then modules = { } end modules ['strc-doc'] = {
local next, type, tonumber, select = next, type, tonumber, select
local format, gsub, find, gmatch, match = string.format, string.gsub, string.find, string.gmatch, string.match
-local concat, fastcopy = table.concat, table.fastcopy
+local concat, fastcopy, insert, remove = table.concat, table.fastcopy, table.insert, table.remove
local max, min = math.max, math.min
local allocate, mark, accesstable = utilities.storage.allocate, utilities.storage.mark, utilities.tables.accesstable
local setmetatableindex = table.setmetatableindex
+local lpegmatch, P, C = lpeg.match, lpeg.P, lpeg.C
local catcodenumbers = catcodes.numbers
local ctxcatcodes = catcodenumbers.ctxcatcodes
local variables = interfaces.variables
+local implement = interfaces.implement
+
local v_last = variables.last
local v_first = variables.first
local v_previous = variables.previous
@@ -59,6 +62,8 @@ local startapplyprocessor = processors.startapply
local stopapplyprocessor = processors.stopapply
local strippedprocessor = processors.stripped
+local convertnumber = converters.convert
+
local a_internal = attributes.private('internal')
local ctx_convertnumber = context.convertnumber
@@ -128,28 +133,48 @@ local registered = sections.registered
storage.register("structures/sections/registered", registered, "structures.sections.registered")
+local function update(name,level,section)
+ for k, v in next, registered do
+ if k ~= name and v.coupling == name then
+ report_structure("updating section level %a to level of %a",k,name)
+ context.doredefinehead(k,name)
+ update(k,level,section)
+ end
+ end
+end
+
function sections.register(name,specification)
registered[name] = specification
+ local level = specification.level
+ local section = specification.section
+ update(name,level,section)
end
function sections.currentid()
return #tobesaved
end
+local lastsaved = 0
+
function sections.save(sectiondata)
-- local sectionnumber = helpers.simplify(section.sectiondata) -- maybe done earlier
local numberdata = sectiondata.numberdata
local ntobesaved = #tobesaved
if not numberdata or sectiondata.metadata.nolist then
- return ntobesaved
+ -- stay
else
ntobesaved = ntobesaved + 1
tobesaved[ntobesaved] = numberdata
if not collected[ntobesaved] then
collected[ntobesaved] = numberdata
end
- return ntobesaved
end
+ lastsaved = ntobesaved
+ return ntobesaved
+end
+
+function sections.currentsectionindex()
+ return lastsaved -- only for special controlled situations
end
function sections.load()
@@ -214,7 +239,7 @@ end
function sections.pushblock(name,settings)
counters.check(0) -- we assume sane usage of \page between blocks
local block = name or data.block
- data.blocks[#data.blocks+1] = block
+ insert(data.blocks,block)
data.block = block
sectionblockdata[block] = settings
documents.reset()
@@ -222,17 +247,18 @@ function sections.pushblock(name,settings)
end
function sections.popblock()
- data.blocks[#data.blocks] = nil
- local block = data.blocks[#data.blocks] or data.block
+ local block = remove(data.blocks) or data.block
data.block = block
documents.reset()
return block
end
-function sections.currentblock()
+local function getcurrentblock()
return data.block or data.blocks[#data.blocks] or "unknown"
end
+sections.currentblock = getcurrentblock
+
function sections.currentlevel()
return data.depth
end
@@ -246,15 +272,33 @@ local saveset = { } -- experiment, see sections/tricky-001.tex
function sections.setentry(given)
-- old number
local numbers = data.numbers
+ --
+ local metadata = given.metadata
+ local numberdata = given.numberdata
+ local references = given.references
+ local directives = given.directives
+ local userdata = given.userdata
+
+ if not metadata then
+ metadata = { }
+ given.metadata = metadata
+ end
+ if not numberdata then
+ numberdata = { }
+ given.numberdata = numberdata
+ end
+ if not references then
+ references = { }
+ given.references = references
+ end
local ownnumbers = data.ownnumbers
local forced = data.forced
local status = data.status
local olddepth = data.depth
- local givenname = given.metadata.name
+ local givenname = metadata.name
local mappedlevel = levelmap[givenname]
local newdepth = tonumber(mappedlevel or (olddepth > 0 and olddepth) or 1) -- hm, levelmap only works for section-*
- local directives = given.directives
local resetset = directives and directives.resetset or ""
-- local resetter = sets.getall("structure:resets",data.block,resetset)
-- a trick to permit userdata to overload title, ownnumber and reference
@@ -264,14 +308,13 @@ function sections.setentry(given)
report_structure("name %a, mapped level %a, old depth %a, new depth %a, reset set %a",
givenname,mappedlevel,olddepth,newdepth,resetset)
end
- local u = given.userdata
- if u then
- -- kind of obsolete as we can pass them directly anyway
- if u.reference and u.reference ~= "" then given.metadata.reference = u.reference ; u.reference = nil end
- if u.ownnumber and u.ownnumber ~= "" then given.numberdata.ownnumber = u.ownnumber ; u.ownnumber = nil end
- if u.title and u.title ~= "" then given.titledata.title = u.title ; u.title = nil end
- if u.bookmark and u.bookmark ~= "" then given.titledata.bookmark = u.bookmark ; u.bookmark = nil end
- if u.label and u.label ~= "" then given.titledata.label = u.label ; u.label = nil end
+ if userdata then
+ -- kind of obsolete as we can pass them directly anyway ... NEEDS CHECKING !
+ if userdata.reference and userdata.reference ~= "" then given.metadata.reference = userdata.reference ; userdata.reference = nil end
+ if userdata.ownnumber and userdata.ownnumber ~= "" then given.numberdata.ownnumber = userdata.ownnumber ; userdata.ownnumber = nil end
+ if userdata.title and userdata.title ~= "" then given.titledata.title = userdata.title ; userdata.title = nil end
+ if userdata.bookmark and userdata.bookmark ~= "" then given.titledata.bookmark = userdata.bookmark ; userdata.bookmark = nil end
+ if userdata.label and userdata.label ~= "" then given.titledata.label = userdata.label ; userdata.label = nil end
end
-- so far for the trick
if saveset then
@@ -309,12 +352,12 @@ function sections.setentry(given)
end
end
counters.check(newdepth)
- ownnumbers[newdepth] = given.numberdata.ownnumber or ""
- given.numberdata.ownnumber = nil
+ ownnumbers[newdepth] = numberdata.ownnumber or ""
+ numberdata.ownnumber = nil
data.depth = newdepth
-- new number
olddepth = newdepth
- if given.metadata.increment then
+ if metadata.increment then
local oldn, newn = numbers[newdepth] or 0, 0
local fd = forced[newdepth]
if fd then
@@ -344,40 +387,31 @@ function sections.setentry(given)
v[2](k)
end
end
- local numberdata= given.numberdata
- if not numberdata then
- -- probably simplified to nothing
- numberdata = { }
- given.numberdata = numberdata
- end
-
local n = { }
for i=1,newdepth do
n[i] = numbers[i]
end
numberdata.numbers = n
--- numberdata.numbers = fastcopy(numbers)
-
+ if not numberdata.block then
+ numberdata.block = getcurrentblock() -- also in references
+ end
if #ownnumbers > 0 then
numberdata.ownnumbers = fastcopy(ownnumbers)
end
if trace_detail then
report_structure("name %a, numbers % a, own numbers % a",givenname,numberdata.numbers,numberdata.ownnumbers)
end
-
- local metadata = given.metadata
- local references = given.references
-
+ if not references.block then
+ references.block = getcurrentblock() -- also in numberdata
+ end
local tag = references.tag or tags.getid(metadata.kind,metadata.name)
if tag and tag ~= "" and tag ~= "?" then
references.tag = tag
end
-
local setcomponent = structures.references.setcomponent
if setcomponent then
setcomponent(given) -- might move to the tex end
end
-
references.section = sections.save(given)
-- given.numberdata = nil
end
@@ -528,10 +562,6 @@ end
sections.depthnumber = depthnumber
-function commands.depthnumber(n)
- return context(depthnumber(n))
-end
-
function sections.autodepth(numbers)
for i=#numbers,1,-1 do
if numbers[i] ~= 0 then
@@ -557,10 +587,9 @@ end
-- sign=positive => also zero
-- sign=hang => llap sign
---~ todo: test this
---~
+-- this can be a local function
-local function process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,index,entry,result,preceding,done)
+local function process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,entry,result,preceding,done,language)
-- todo: too much (100 steps)
local number = numbers and (numbers[index] or 0)
local ownnumber = ownnumbers and ownnumbers[index] or ""
@@ -581,10 +610,10 @@ local function process(index,numbers,ownnumbers,criterium,separatorset,conversio
if ownnumber ~= "" then
result[#result+1] = ownnumber
elseif conversion and conversion ~= "" then -- traditional (e.g. used in itemgroups) .. inherited!
- result[#result+1] = converters.convert(conversion,number)
+ result[#result+1] = convertnumber(conversion,number,language)
else
local theconversion = sets.get("structure:conversions",block,conversionset,index,"numbers")
- result[#result+1] = converters.convert(theconversion,number)
+ result[#result+1] = convertnumber(theconversion,number,language)
end
else
if ownnumber ~= "" then
@@ -616,6 +645,7 @@ function sections.typesetnumber(entry,kind,...) -- kind='section','number','pref
local set = ""
local segments = ""
local criterium = ""
+ local language = ""
for d=1,select("#",...) do
local data = select(d,...) -- can be multiple parametersets
if data then
@@ -629,6 +659,7 @@ function sections.typesetnumber(entry,kind,...) -- kind='section','number','pref
if set == "" then set = data.set or "" end
if segments == "" then segments = data.segments or "" end
if criterium == "" then criterium = data.criterium or "" end
+ if language == "" then language = data.language or "" end
end
end
if separatorset == "" then separatorset = "default" end
@@ -640,6 +671,7 @@ function sections.typesetnumber(entry,kind,...) -- kind='section','number','pref
if connector == "" then connector = nil end
if set == "" then set = "default" end
if segments == "" then segments = nil end
+ if language == "" then language = nil end
--
if criterium == v_strict then
criterium = 0
@@ -651,10 +683,10 @@ function sections.typesetnumber(entry,kind,...) -- kind='section','number','pref
criterium = 0
end
--
- local firstprefix, lastprefix = 0, 16
+ local firstprefix, lastprefix = 0, 16 -- too much, could max found level
if segments then
local f, l = match(tostring(segments),"^(.-):(.+)$")
- if l == "*" then
+ if l == "*" or l == v_all then
l = 100 -- new
end
if f and l then
@@ -688,7 +720,7 @@ function sections.typesetnumber(entry,kind,...) -- kind='section','number','pref
applyprocessor(starter)
end
end
- if prefixlist and (kind == 'section' or kind == 'prefix' or kind == 'direct') then
+ if prefixlist and (kind == "section" or kind == "prefix" or kind == "direct") then
-- find valid set (problem: for sectionnumber we should pass the level)
-- no holes
local b, e, bb, ee = 1, #prefixlist, 0, 0
@@ -732,15 +764,13 @@ function sections.typesetnumber(entry,kind,...) -- kind='section','number','pref
local prefix = prefixlist[k]
local index = sections.getlevel(prefix) or k
if index >= firstprefix and index <= lastprefix then
- -- process(index,result)
- preceding, done = process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,index,entry,result,preceding,done)
+ preceding, done = process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,entry,result,preceding,done,language)
end
end
else
-- also holes check
for index=firstprefix,lastprefix do
- -- process(index,result)
- preceding, done = process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,index,entry,result,preceding,done)
+ preceding, done = process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,entry,result,preceding,done,language)
end
end
--
@@ -756,7 +786,7 @@ function sections.typesetnumber(entry,kind,...) -- kind='section','number','pref
if result then
result[#result+1] = strippedprocessor(groupsuffix)
else
- applyprocessor(groupsuffix)
+ applyprocessor(groupsuffix)
end
end
if stopper then
@@ -901,34 +931,21 @@ end
function sections.getnumber(depth,what) -- redefined here
local sectiondata = sections.findnumber(depth,what)
- context((sectiondata and sectiondata.numbers[depth]) or 0)
+ local askednumber = 0
+ if sectiondata then
+ local numbers = sectiondata.numbers
+ if numbers then
+ askednumber = numbers[depth] or 0
+ end
+ end
+ context(askednumber)
end
-- experimental
local levels = { }
---~ function commands.autonextstructurelevel(level)
---~ if level > #levels then
---~ for i=#levels+1,level do
---~ levels[i] = ""
---~ end
---~ end
---~ local finish = concat(levels,"\n",level) or ""
---~ for i=level+1,#levels do
---~ levels[i] = ""
---~ end
---~ levels[level] = [[\finalizeautostructurelevel]]
---~ context(finish)
---~ end
-
---~ function commands.autofinishstructurelevels()
---~ local finish = concat(levels,"\n") or ""
---~ levels = { }
---~ context(finish)
---~ end
-
-function commands.autonextstructurelevel(level)
+local function autonextstructurelevel(level)
if level > #levels then
for i=#levels+1,level do
levels[i] = false
@@ -944,7 +961,7 @@ function commands.autonextstructurelevel(level)
levels[level] = true
end
-function commands.autofinishstructurelevels()
+local function autofinishstructurelevels()
for i=1,#levels do
if levels[i] then
ctx_finalizeauto()
@@ -953,38 +970,132 @@ function commands.autofinishstructurelevels()
levels = { }
end
--- interface (some are actually already commands, like sections.fullnumber)
+implement {
+ name = "autonextstructurelevel",
+ actions = autonextstructurelevel,
+ arguments = "integer",
+}
-commands.structurenumber = sections.fullnumber
-commands.structuretitle = sections.title
+implement {
+ name = "autofinishstructurelevels",
+ actions = autofinishstructurelevels,
+}
-commands.structurevariable = function(name) sections.structuredata(nil,name) end
-commands.structureuservariable = function(name) sections.userdata (nil,name) end
-commands.structurecatcodedget = function(name) sections.structuredata(nil,name,nil,true) end
-commands.structuregivencatcodedget = function(name,catcode) sections.structuredata(nil,name,nil,catcode) end
-commands.structureautocatcodedget = function(name,catcode) sections.structuredata(nil,name,nil,catcode) end
+-- interface (some are actually already commands, like sections.fullnumber)
-commands.namedstructurevariable = sections.structuredata
-commands.namedstructureuservariable = sections.userdata
+implement {
+ name = "depthnumber",
+ actions = { depthnumber, context },
+ arguments = "integer",
+}
-commands.setsectionlevel = sections.setlevel
-commands.setsectionnumber = sections.setnumber
-commands.getsectionnumber = sections.getnumber
-commands.getfullsectionnumber = sections.fullnumber
-commands.getstructuredata = sections.structuredata
-commands.getcurrentsectionlevel = sections.getcurrentlevel
+implement { name = "structurenumber", actions = sections.fullnumber }
+implement { name = "structuretitle", actions = sections.title }
+
+implement { name = "structurevariable", actions = sections.structuredata, arguments = { false, "string" } }
+implement { name = "structureuservariable", actions = sections.userdata, arguments = { false, "string" } }
+implement { name = "structurecatcodedget", actions = sections.structuredata, arguments = { false, "string", false, true } }
+implement { name = "structuregivencatcodedget", actions = sections.structuredata, arguments = { false, "string", false, "integer" } }
+implement { name = "structureautocatcodedget", actions = sections.structuredata, arguments = { false, "string", false, "string" } }
+
+implement { name = "namedstructurevariable", actions = sections.structuredata, arguments = { "string", "string" } }
+implement { name = "namedstructureuservariable", actions = sections.userdata, arguments = { "string", "string" } }
+
+implement { name = "setstructurelevel", actions = sections.setlevel, arguments = { "string", "string" } }
+implement { name = "getstructurelevel", actions = sections.getcurrentlevel, arguments = { "string" } }
+implement { name = "setstructurenumber", actions = sections.setnumber, arguments = { "integer", "string" } }
+implement { name = "getstructurenumber", actions = sections.getnumber, arguments = { "integer" } }
+implement { name = "getsomestructurenumber", actions = sections.getnumber, arguments = { "integer", "string" } }
+implement { name = "getfullstructurenumber", actions = sections.fullnumber, arguments = { "integer" } }
+implement { name = "getsomefullstructurenumber", actions = sections.fullnumber, arguments = { "integer", "string" } }
+implement { name = "getspecificstructuretitle", actions = sections.structuredata, arguments = { "string", "'titledata.title'",false,"string" } }
+
+implement { name = "reportstructure", actions = sections.reportstructure }
+
+implement {
+ name = "registersection",
+ actions = sections.register,
+ arguments = {
+ "string",
+ {
+ { "coupling" },
+ { "section" },
+ { "level", "integer" },
+ { "parent" },
+ }
+ }
+}
-commands.setsectionblock = sections.setblock
-commands.pushsectionblock = sections.pushblock
-commands.popsectionblock = sections.popblock
+implement {
+ name = "setsectionentry",
+ actions = sections.setentry,
+ arguments = {
+ {
+ { "references", {
+ { "internal", "integer" },
+ { "block" },
+ { "backreference" },
+ { "prefix" },
+ { "reference" },
+ }
+ },
+ { "directives", {
+ { "resetset" }
+ }
+ },
+ { "metadata", {
+ { "kind" },
+ { "name" },
+ { "catcodes", "integer" },
+ { "coding" },
+ { "xmlroot" },
+ { "xmlsetup" },
+ { "nolist", "boolean" },
+ { "increment" },
+ }
+ },
+ { "titledata", {
+ { "label" },
+ { "title" },
+ { "bookmark" },
+ { "marking" },
+ { "list" },
+ }
+ },
+ { "numberdata", {
+ { "block" },
+ { "hidenumber", "boolean" },
+ { "separatorset" },
+ { "conversionset" },
+ { "conversion" },
+ { "starter" },
+ { "stopper" },
+ { "set" },
+ { "segments" },
+ { "ownnumber" },
+ { "language" },
+ },
+ },
+ { "userdata" },
+ }
+ }
+}
-commands.registersection = sections.register
-commands.setsectionentry = sections.setentry
-commands.reportstructure = sections.reportstructure
---
+-- os.exit()
-local byway = "^" .. v_by -- ugly but downward compatible
+implement {
+ name = "setsectionblock",
+ actions = sections.setblock,
+ arguments = { "string", { { "bookmark" } } }
+}
-function commands.way(way)
- context((gsub(way,byway,"")))
-end
+implement {
+ name = "pushsectionblock",
+ actions = sections.pushblock,
+ arguments = { "string", { { "bookmark" } } }
+}
+
+implement {
+ name = "popsectionblock",
+ actions = sections.popblock,
+}
diff --git a/Master/texmf-dist/tex/context/base/strc-doc.mkiv b/Master/texmf-dist/tex/context/base/strc-doc.mkiv
index 98abfd6118e..c453f199ef8 100644
--- a/Master/texmf-dist/tex/context/base/strc-doc.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-doc.mkiv
@@ -20,8 +20,13 @@
%D This will move:
\unexpanded\def\setstructuresynchronization#1% todo: use ctxcontext
- {\ctxcommand{setinternalreference("\currentstructurereferenceprefix","\currentstructurereference",\nextinternalreference,"\interactionparameter\c!focus")}%
+ {\clf_setinternalreference
+ prefix {\currentstructurereferenceprefix}%
+ reference {\currentstructurereference}
+ internal \nextinternalreference
+ view {\interactionparameter\c!focus}%
+ \relax
\xdef\currentstructureattribute {\the\lastdestinationattribute}%
- \xdef\currentstructuresynchronize{\ctxlatecommand{enhancelist(#1)}}}
+ \xdef\currentstructuresynchronize{\strc_lists_inject_enhance{#1}{\nextinternalreference}}}
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/strc-enu.mkvi b/Master/texmf-dist/tex/context/base/strc-enu.mkvi
index 0a01d2637f5..b76bc0067e1 100644
--- a/Master/texmf-dist/tex/context/base/strc-enu.mkvi
+++ b/Master/texmf-dist/tex/context/base/strc-enu.mkvi
@@ -172,7 +172,7 @@
\ifx\p_counter\empty %
\let\p_counter\currentenumeration
\fi
- \doifcounterelse\p_counter\donothing{\strc_enumerations_define_counter\p_counter}%
+ \doifelsecounter\p_counter\donothing{\strc_enumerations_define_counter\p_counter}%
\letenumerationparameter\s!counter\p_counter
%\strc_enumerations_setup_counter\currentenumeration
\to \everydefineenumeration
@@ -183,6 +183,7 @@
\unexpanded\setvalue{\??constructioninitializer\v!enumeration}%
{\let\currentenumeration \currentconstruction
\let\constructionparameter \enumerationparameter
+ \let\constructionnamespace \??enumeration
\let\detokenizedconstructionparameter\detokenizedenumerationparameter
\let\letconstructionparameter \letenumerationparameter
\let\useconstructionstyleandcolor \useenumerationstyleandcolor
@@ -283,7 +284,7 @@
\unexpanded\def\strc_enumerations_inject_extra_text
{\ifconditional\c_strc_constructions_title_state
- \ctxcommand{doiflisthastitleelse("\currentconstructionmain",\currentconstructionlistentry)}
+ \clf_doifelselisthastitle{\currentconstructionmain}\numexpr\currentconstructionlistentry\relax
\donothing
\strc_enumerations_inject_extra_text_indeed
\fi}
@@ -300,7 +301,7 @@
\useconstructionstyleandcolor\c!titlestyle\c!titlecolor
\constructionparameter\c!titlecommand
{\constructionparameter\c!titleleft
- \ctxcommand{savedlisttitle("\currentconstructionmain",\currentconstructionlistentry)}%
+ \clf_savedlisttitle{\currentconstructionmain}\currentconstructionlistentry\relax
\constructionparameter\c!titleright}%
\endgroup}
@@ -312,7 +313,7 @@
\unexpanded\def\strc_enumerations_inject_number
{\constructionparameter\c!left
\constructionparameter\c!starter
- \ctxcommand{savedlistprefixednumber("\currentconstructionmain",\currentconstructionlistentry)}%
+ \clf_savedlistprefixednumber{\currentconstructionmain}\currentconstructionlistentry\relax
\constructionparameter\c!stopper
\constructionparameter\c!right}
@@ -370,6 +371,6 @@
\fi}
\unexpanded\def\strc_enumerations_skip_number_coupling[#tag]% e.g. for questions with no answer
- {\ctxcommand{setnextreferenceorder("construction","#tag")}}
+ {\clf_setnextreferenceorder{construction}{#tag}}
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/strc-flt.mkvi b/Master/texmf-dist/tex/context/base/strc-flt.mkvi
index a939213177d..9a7fc56f6da 100644
--- a/Master/texmf-dist/tex/context/base/strc-flt.mkvi
+++ b/Master/texmf-dist/tex/context/base/strc-flt.mkvi
@@ -17,6 +17,23 @@
\unprotect
+% todo: a keyword for this (and then a settings->hash for speed)
+%
+% \setuplayout[width=middle,backspace=3cm]
+%
+% \appendtoks
+% \settrue\inhibitmargindata
+% \to \everyinsidefloat
+%
+% \starttext
+% \dorecurse{20}{
+% \par \inleft{\red\infofont<#1>} \par
+% \placefigure[leftmargin]{}{\framed[height=1cm,width=2cm]{}}
+% % \placefigure{#1}{\framed[height=1cm,width=2cm]{}}
+% \par line #1.1 \par line #1.2 \par
+% }
+% \stoptext
+
% todo: delay caption creation and make setups for each method instead
% so that we can have a list of methods and redo them as we can
% keep the list or even better: recreate it
@@ -91,8 +108,9 @@
% \c!stopper=\@@kostopper,
\c!suffixseparator=, % currently rather hard coded
\c!suffix=\floatcaptionsuffix,
- \c!distance=1em,
+ \c!distance=\emwidth,
\c!conversion=\v!numbers,
+ \c!maxwidth=\hsize,
\c!command=]
% we can comment some of these
@@ -133,6 +151,7 @@
\c!outermargin=\zeropoint, % idem
\c!leftmargindistance=\zeropoint,
\c!rightmargindistance=\floatparameter\c!leftmargindistance,
+ \c!step=\v!big, % the flish side float step (big=line, medium=halfline, small=quarterline, depth=halfline with normaldepth)
\c!ntop=2,
\c!nbottom=0,
\c!nlines=4, % used?
@@ -186,8 +205,8 @@
{\definefloatcaption[#1][#3]%
\definecounter[#1][#3]%
\definelist[#1][#3]%
- \presetlabeltext[#1=\Word{#3}~]%
- \presetheadtext[#2=\Word{#2}]%
+ \copylabeltext[#1=#3]%
+ %\presetheadtext[#2=\Word{#2}]%
\strc_floats_define_saved[#1][#3]%
\strc_floats_define_commands{#1}{#2}}
@@ -235,8 +254,9 @@
\namedtaggedlabeltexts
\t!floatlabel \currentfloat
\t!floatnumber\currentfloat
- {\ctxcommand{savedlistprefixednumber("\currentfloat",\currentfloatnumber)}%
- \thecurrentfloatnumbersuffix}%
+ {\floatcaptionparameter\c!numbercommand
+ {\clf_savedlistprefixednumber{\currentfloat}\currentfloatnumber\relax
+ \thecurrentfloatnumbersuffix}}%
\fi
\fi \fi}
@@ -244,7 +264,8 @@
{\ifnofloatcaption \else
\ifx\currentfloatnumber\relax\else
\dostarttagged\t!floattext\empty
- \ctxcommand{savedlisttitle("\currentfloat",\currentfloatnumber)}%
+ \floatcaptionparameter\c!textcommand
+ {\clf_savedlisttitle{\currentfloat}\currentfloatnumber\relax}%
\dostoptagged
\fi
\fi}
@@ -489,8 +510,9 @@
\edef\floatlocation{\floatparameter\c!default}% beware of a clash between alignment locations
\fi
\strc_floats_analyze_location
+ % todo: use \lets
\setupcurrentfloatcaption[\c!reference={#reference},\c!title={#caption},\c!marking=,\c!list=,\c!bookmark=]%
- \doifinsetelse\v!split\floatlocation\strc_floats_place_next_box_split\strc_floats_place_next_box_normal}
+ \doifelseinset\v!split\floatlocation\strc_floats_place_next_box_split\strc_floats_place_next_box_normal}
\unexpanded\def\placefloat
{\flushnotes
@@ -535,7 +557,7 @@
\setupcurrentfloatuserdata[#userdata]%
\fi
\strc_floats_analyze_location
- \doifinsetelse\v!split\floatlocation\strc_floats_place_next_box_split\strc_floats_place_next_box_normal
+ \doifelseinset\v!split\floatlocation\strc_floats_place_next_box_split\strc_floats_place_next_box_normal
\bgroup
\ignorespaces}
@@ -547,7 +569,7 @@
{\flushnotes
\page_otr_command_flush_side_floats % here !
\strc_floats_begin_group
- \dodoubleempty\strc_floats_start_place_float}
+ \dotripleempty\strc_floats_start_place_float}
\def\strc_floats_start_place_float[#tag]%
{\strc_floats_set_current_tag{#tag}%
@@ -636,14 +658,14 @@
\unexpanded\def\strc_floats_place_next_box_normal
{\ifconditional\c_page_floats_some_waiting
% this was \checkwaitingfloats spread all over
- \doifinsetelse\v!always\floatlocation
+ \doifelseinset\v!always\floatlocation
{\showmessage\m!floatblocks5\empty}
- {\doifcommonelse\floatlocation\flushfloatslist\page_otr_command_flush_floats\donothing}%
+ {\doifelsecommon\floatlocation\flushfloatslist\page_otr_command_flush_floats\donothing}%
% but which should be done before using box \floatbox
\fi
\page_margin_strc_floats_before % todo: each float handler gets a before
\global\insidefloattrue
- \dostarttagged\t!float\currentfloat
+ \dostarttaggedchained\t!float\currentfloat\??float
\page_margin_strc_floats_set_hsize % todo: each float handler gets a set_hsize
\the\everyinsidefloat
\strc_floats_analyze_variables_one
@@ -681,7 +703,7 @@
{\ifinsidecolumns
\global\setfalse\c_strc_floats_par_float
\else
- \doifcommonelse\floatlocation\flushfloatslist
+ \doifelsecommon\floatlocation\flushfloatslist
{\global\settrue \c_strc_floats_par_float}
{\global\setfalse\c_strc_floats_par_float}%
\fi
@@ -720,12 +742,12 @@
180=>\global\c_strc_floats_rotation\commalistelement\relax,%
270=>\global\c_strc_floats_rotation\commalistelement\relax]%
\fi
- \doifinsetelse\v!nonumber\floatlocation
+ \doifelseinset\v!nonumber\floatlocation
{\global\nofloatnumbertrue}
{\doifelse{\floatcaptionparameter\c!number}\v!yes
{\global\nofloatnumberfalse}
{\global\nofloatnumbertrue}}%
- \doifinsetelse\v!none\floatlocation
+ \doifelseinset\v!none\floatlocation
{\global\nofloatcaptiontrue}
{\global\nofloatcaptionfalse}%
\doif{\floatcaptionparameter\c!number}\v!none % new
@@ -741,7 +763,7 @@
\ifconditional\c_page_floats_center_box_global
\settrue\c_page_floats_center_box_local
\else
- \doifinsetelse\v!local\floatlocation\settrue\setfalse\c_page_floats_center_box_local
+ \doifelseinset\v!local\floatlocation\settrue\setfalse\c_page_floats_center_box_local
\fi
\doifnotcommon{\v!always,\v!here,\v!force}\floatlocation % ! ! ! ! ! !
{\setfalse\c_page_floats_center_box_global
@@ -767,6 +789,8 @@
\expandafter\firstoftwoarguments
\fi}
+\let\doifmainfloatbodyelse\doifelsemainfloatbody
+
% todo: optional user pars
\let\currentfloatattribute\empty % to be checked
@@ -801,7 +825,7 @@
% uses:
\def\strc_floats_group_index
- {\numexpr\ctxcommand{listgroupindex("\currentfloat","\currentfloatgroup")}\relax}
+ {\numexpr\clf_listgroupindex{\currentfloat}{\currentfloatgroup}\relax}
\def\strc_floats_place_packaged_boxes
{\expandafter\strc_floats_place_packaged_boxes_indeed\expandafter{\m_strc_floats_saved_userdata}}
@@ -835,7 +859,7 @@
\relax
\relax
\relax
- [\c!name=\currentfloat,%
+ [\s!name=\currentfloat,% was c!name
\s!counter=\currentfloatcounter,%
\s!hascaption=\ifnofloatcaption \v!no\else\v!yes\fi,%
\s!hasnumber=\ifnofloatnumber \v!no\else\v!yes\fi,%
@@ -896,26 +920,29 @@
\strc_float_load_data
\to \everyinsidefloat
-\def\doifrightpagefloatelse
+\def\doifelserightpagefloat
{\ifdoublesided
\ifsinglesided
\doubleexpandafter\firstoftwoarguments
\else
- \doubleexpandafter\doifoddfloatpageelse
+ \doubleexpandafter\doifelseoddfloatpage
\fi
\else
\expandafter\firstoftwoarguments
\fi}
-\def\doifoddfloatpageelse
+\def\doifelseoddfloatpage
{\ifodd\purenumber\strc_float_realpage\space
\expandafter\firstoftwoarguments
\else
\expandafter\secondoftwoarguments
\fi}
+\let\doifrightpagefloatelse\doifelserightpagefloat
+\let\doifoddpagefloatelse \doifelseoddpagefloat
+
\appendtoks
- \let\rightorleftpageaction\doifrightpagefloatelse
+ \let\rightorleftpageaction\doifelserightpagefloat
\to \everyinsidefloat
% \let\movesidefloat\gobbleoneargument
@@ -926,7 +953,7 @@
\unexpanded\def\movesidefloat[#settings]% (-)n*line|x=,y=
{\global\d_page_sides_downshift \zeropoint
\global\d_page_sides_extrashift\zeropoint
- \doifassignmentelse{#settings}%
+ \doifelseassignment{#settings}%
{\begingroup
\setupcurrentfloat[\c!x=\zeropoint,\c!y=\zeropoint,#settings]%
\ifgridsnapping
@@ -1038,10 +1065,10 @@
\fi
\fi
% we can also support edges .. in that case no common but a fast loop
- \doifinsetelse\v!hanging\floatlocation
- {\doifcommonelse{\v!inleft,\v!leftmargin}\floatlocation
+ \doifelseinset\v!hanging\floatlocation
+ {\doifelsecommon{\v!inleft,\v!leftmargin}\floatlocation
{\let\p_maxwidth\leftmarginwidth}%
- {\doifcommonelse{\v!inright,\v!rightmargin}\floatlocation
+ {\doifelsecommon{\v!inright,\v!rightmargin}\floatlocation
{\let\p_maxwidth\rightmarginwidth}%
{\edef\p_maxwidth{\floatparameter\c!maxwidth}}}}%
{\edef\p_maxwidth{\floatparameter\c!maxwidth}}%
@@ -1050,9 +1077,9 @@
\else
\scratchwidth\p_maxwidth\relax
\ifdim\wd\floatbox>\scratchwidth
- \doifcommonelse{\v!inright,\v!rightmargin,\v!rightedge,\v!inleft,\v!leftmargin,\v!leftedge}\floatlocation
+ \doifelsecommon{\v!inright,\v!rightmargin,\v!rightedge,\v!inleft,\v!leftmargin,\v!leftedge}\floatlocation
{\global\d_page_sides_maximum\scratchwidth}
- {\doifcommonelse{\v!right,\v!left}\floatlocation
+ {\doifelsecommon{\v!right,\v!left}\floatlocation
\strc_floats_realign_floatbox_horizontal_one
\strc_floats_realign_floatbox_horizontal_two}%
\fi
@@ -1104,11 +1131,22 @@
\unexpanded\def\betweenfloatblanko % assumes that spaceafter is present
{\blank[\rootfloatparameter\c!spacebefore]} % or v!back,....
+% \unexpanded\def\doplacefloatbox % used elsewhere
+% {%\forgetall % NO
+% \whitespace
+% \blank[\rootfloatparameter\c!spacebefore]
+% \page_otr_command_flush_float_box
+% \blank[\rootfloatparameter\c!spaceafter]}
+
\unexpanded\def\doplacefloatbox % used elsewhere
{%\forgetall % NO
\whitespace
\blank[\rootfloatparameter\c!spacebefore]
+ \nointerlineskip
+ \flushnotes % new per 2014-05-29 : todo: move them up in the mvl
+ \nointerlineskip
\page_otr_command_flush_float_box
+ \nointerlineskip
\blank[\rootfloatparameter\c!spaceafter]}
% test case:
@@ -1126,7 +1164,7 @@
\global\floatheight \ht\floatbox % forget about the depth
\global\floattextwidth\dimexpr\hsize-\floatwidth-\rootfloatparameter\c!margin\relax
\edef\floatlocation{\floatlocationmethod}% to be sure .. why
- \doifinsetelse\v!tall\floatlocationmethod
+ \doifelseinset\v!tall\floatlocationmethod
{\floattextheight\dimexpr\pagegoal-\pagetotal-\bigskipamount\relax % ugly, this bigskip
\ifdim\floattextheight>\textheight
\floattextheight\textheight
@@ -1151,27 +1189,27 @@
{\floattextheight\ifdim\ht\floattext<\floatheight\floatheight\else\ht\floattext\fi}%
\setbox\floatbox\vbox to \floattextheight
{\hsize\floatwidth
- \doifinsetelse\v!both\floatlocation
- {\doifinsetelse\v!low\floatlocation
+ \doifelseinset\v!both\floatlocation
+ {\doifelseinset\v!low\floatlocation
{\vfill\box\floatbox}
- {\doifinsetelse\v!middle\floatlocation
+ {\doifelseinset\v!middle\floatlocation
{\vfill\box\floatbox\vfill}
{\box\floatbox\vfill}}}
{\box\floatbox\vfill}}%
\setbox\floattext\vbox to \floattextheight
{\hsize\floattextwidth
- \doifinsetelse\v!low\floatlocation
+ \doifelseinset\v!low\floatlocation
{\vfill
\box\floattext
\doifinset\c!offset\floatlocation{\whitespace\blank}}
- {\doifinsetelse\v!middle\floatlocation
+ {\doifelseinset\v!middle\floatlocation
{\vfill
\box\floattext
\vfill}
{\doifinset\v!offset\floatlocation{\whitespace\blank}%
\box\floattext
\vfill}}}%
- \doifinsetelse\v!right\floatlocation
+ \doifelseinset\v!right\floatlocation
{\setbox\floatbox\hbox to \hsize
{\box\floattext
\hfill
@@ -1190,13 +1228,13 @@
\blank[\rootfloatparameter\c!spaceafter]%
\strc_floats_end_text_group
\page_floats_report_total}
-
+
\def\borderedfloatbox
{\begingroup
\setupcurrentfloat[\c!location=\v!normal,\c!width=\v!fit,\c!height=\v!fit]%
\inheritedfloatframed{\box\floatbox}%
\endgroup}
-
+
% minwidth=fit,width=max : no overshoot, as wide as graphic
\def\strc_floats_align_content_indeed
@@ -1366,17 +1404,82 @@
\fi
\strc_floats_make_complete_caption}}
+% \def\strc_floats_prepare_stack_caption_auto
+% {\ifx\p_strc_floats_caption_align\empty \else
+% \doifnotinset\v!middle\p_strc_floats_caption_align{\let\captionovershoot\!!zeropoint}%
+% \fi
+% \edef\captionhsize{\the\wd\b_strc_floats_content}%
+% \ifdim\captionhsize>\hsize
+% % float is wider than \hsize
+% \setbox\b_strc_floats_caption\vbox
+% {\settrialtypesetting
+% \strc_floats_caption_set_align
+% \hsize\captionhsize
+% \notesenabledfalse
+% \strc_floats_make_complete_caption}%
+% \ifdim\ht\scratchbox>\lineheight % more lines
+% \setbox\b_strc_floats_caption\vbox
+% {\strc_floats_caption_set_align
+% \hsize\dimexpr\captionhsize-\captionovershoot\relax
+% \ifdim\hsize<\captionminwidth\relax
+% \hsize\captionhsize
+% \fi
+% \strc_floats_make_complete_caption}%
+% \else
+% \setbox\b_strc_floats_caption\vbox
+% {\strc_floats_caption_set_align
+% \hsize\captionhsize
+% \strc_floats_make_complete_caption}%
+% \fi
+% \else
+% % float is smaller of equal to \hsize
+% \ifdim\captionhsize<\captionminwidth\relax
+% \scratchdimen\captionminwidth % float smaller than min width
+% \edef\captionhsize{\the\scratchdimen}%
+% \fi
+% \setbox\scratchbox\vbox % test with overshoot
+% {\settrialtypesetting
+% \scratchdimen\dimexpr\captionhsize+\captionovershoot+3\emwidth\relax % 3em is an average word length
+% \ifdim\scratchdimen<\hsize
+% \hsize\scratchdimen
+% \fi
+% \notesenabledfalse
+% \strc_floats_make_complete_caption}%
+% \ifdim\ht\scratchbox>\lineheight
+% % at least an average word longer than a line
+% \setbox\b_strc_floats_caption\vbox
+% {\strc_floats_caption_set_align
+% \scratchdimen\dimexpr\captionhsize+\captionovershoot\relax
+% \ifdim\scratchdimen<\hsize
+% \hsize\scratchdimen
+% \fi
+% \strc_floats_make_complete_caption}%
+% \else\ifx\p_strc_floats_caption_align\empty
+% \setbox\b_strc_floats_caption\vbox
+% {\strc_floats_caption_set_align
+% \hsize\captionhsize
+% \raggedcenter % overloads
+% \strc_floats_make_complete_caption}%
+% \else
+% \setbox\b_strc_floats_caption\vbox
+% {\strc_floats_caption_set_align
+% \hsize\captionhsize
+% \strc_floats_make_complete_caption}%
+% \fi\fi
+% \fi}
+
\def\strc_floats_prepare_stack_caption_auto
{\ifx\p_strc_floats_caption_align\empty \else
\doifnotinset\v!middle\p_strc_floats_caption_align{\let\captionovershoot\!!zeropoint}%
\fi
\edef\captionhsize{\the\wd\b_strc_floats_content}%
- \ifdim\captionhsize>\hsize
+ \scratchwidth\floatcaptionparameter\c!maxwidth\relax
+ \ifdim\captionhsize>\scratchwidth
% float is wider than \hsize
\setbox\b_strc_floats_caption\vbox
{\settrialtypesetting
\strc_floats_caption_set_align
- \hsize\captionhsize
+ \hsize\scratchwidth
\notesenabledfalse
\strc_floats_make_complete_caption}%
\ifdim\ht\scratchbox>\lineheight % more lines
@@ -1384,13 +1487,13 @@
{\strc_floats_caption_set_align
\hsize\dimexpr\captionhsize-\captionovershoot\relax
\ifdim\hsize<\captionminwidth\relax
- \hsize\captionhsize
+ \hsize\scratchwidth
\fi
\strc_floats_make_complete_caption}%
\else
\setbox\b_strc_floats_caption\vbox
{\strc_floats_caption_set_align
- \hsize\captionhsize
+ \hsize\scratchwidth
\strc_floats_make_complete_caption}%
\fi
\else
@@ -1456,10 +1559,10 @@
\box\b_strc_floats_content}}
\def\strc_floats_build_box_next_outer
- {\doifrightpagefloatelse\strc_floats_build_box_next_right\strc_floats_build_box_next_left}
+ {\doifelserightpagefloat\strc_floats_build_box_next_right\strc_floats_build_box_next_left}
\def\strc_floats_build_box_next_inner
- {\doifrightpagefloatelse\strc_floats_build_box_next_left\strc_floats_build_box_next_right}
+ {\doifelserightpagefloat\strc_floats_build_box_next_left\strc_floats_build_box_next_right}
\def\strc_floats_build_box_next_right_hang#1%
{\ifconditional\c_strc_floats_par_float \hbox \else \expandafter \strc_floats_align_content \fi
@@ -1510,12 +1613,12 @@
{\strc_floats_build_box_next_left_margin_indeed \leftmargindistance }
\def\strc_floats_build_box_next_outer_margin
- {\doifrightpagefloatelse
+ {\doifelserightpagefloat
{\strc_floats_build_box_next_right_margin_indeed\rightmargindistance}
{\strc_floats_build_box_next_left_margin_indeed \rightmargindistance}}
\def\strc_floats_build_box_next_inner_margin
- {\doifrightpagefloatelse
+ {\doifelserightpagefloat
{\strc_floats_build_box_next_left_margin_indeed \leftmargindistance}
{\strc_floats_build_box_next_right_margin_indeed\leftmargindistance}}
@@ -1552,29 +1655,16 @@
\def\strc_floats_flush_left_caption_hang
{\hsmash{\llap{\box\b_strc_floats_caption\dotfskip{\floatcaptionparameter\c!distance}}}}
-% \def\strc_floats_flush_caption_hang % expanded can go
-% {\expanded{\doifinsetelse{\v!righthanging}{\floatcaptionparameter\c!location}}
-% {\strc_floats_flush_right_caption_hang}
-% {\expanded{\doifinsetelse{\v!lefthanging}{\floatcaptionparameter\c!location}}
-% {\strc_floats_flush_left_caption_hang}
-% {\expanded{\doifinsetelse{\v!hang}{\floatcaptionparameter\c!location}}
-% {\expanded{\doifinsetelse{\v!outer}{\floatcaptionparameter\c!location}}
-% {\doifrightpagefloatelse{\strc_floats_flush_right_caption_hang}{\strc_floats_flush_left_caption_hang}}
-% {\expanded{\doifinsetelse{\v!right}{\floatcaptiondirectives}}
-% {\strc_floats_flush_right_caption_hang}
-% {\strc_floats_flush_left_caption_hang}}}
-% {\box\b_strc_floats_caption}}}}
-
\def\strc_floats_flush_caption_hang % expanded can go
{\edef\p_strc_floats_caption_location{\floatcaptionparameter\c!location}%
- \doifinsetelse\v!righthanging\p_strc_floats_caption_location
+ \doifelseinset\v!righthanging\p_strc_floats_caption_location
{\strc_floats_flush_right_caption_hang}
- {\doifinsetelse\v!lefthanging\p_strc_floats_caption_location
+ {\doifelseinset\v!lefthanging\p_strc_floats_caption_location
{\strc_floats_flush_left_caption_hang}
- {\doifinsetelse\v!hang\p_strc_floats_caption_location
- {\doifinsetelse\v!outer\p_strc_floats_caption_location
- {\doifrightpagefloatelse{\strc_floats_flush_right_caption_hang}{\strc_floats_flush_left_caption_hang}}
- {\doifinsetelse\v!right\floatcaptiondirectives
+ {\doifelseinset\v!hang\p_strc_floats_caption_location
+ {\doifelseinset\v!outer\p_strc_floats_caption_location
+ {\doifelserightpagefloat{\strc_floats_flush_right_caption_hang}{\strc_floats_flush_left_caption_hang}}
+ {\doifelseinset\v!right\floatcaptiondirectives
{\strc_floats_flush_right_caption_hang}
{\strc_floats_flush_left_caption_hang}}}
{\box\b_strc_floats_caption}}}}
@@ -1637,7 +1727,7 @@
\fi}
\def\strc_floats_build_box_top_stack_normal
- {\doifinsetelse\v!overlay{\floatcaptionparameter\c!location}
+ {\doifelseinset\v!overlay{\floatcaptionparameter\c!location}
\strc_floats_build_box_top_stack_normal_overlay
\strc_floats_build_box_top_stack_normal_content}
@@ -1753,8 +1843,8 @@
\processallactionsinset[\floatcaptionparameter\c!location]
[ \v!left=>\let\next\strc_floats_relocate_caption_left,
\v!right=>\let\next\strc_floats_relocate_caption_right,
- \v!inner=>\doifrightpagefloatelse{\let\next\strc_floats_relocate_caption_left }{\let\next\strc_floats_relocate_caption_right},
- \v!outer=>\doifrightpagefloatelse{\let\next\strc_floats_relocate_caption_right}{\let\next\strc_floats_relocate_caption_left }]%
+ \v!inner=>\doifelserightpagefloat{\let\next\strc_floats_relocate_caption_left }{\let\next\strc_floats_relocate_caption_right},
+ \v!outer=>\doifelserightpagefloat{\let\next\strc_floats_relocate_caption_right}{\let\next\strc_floats_relocate_caption_left }]%
\next}
\installfloatboxbuilder \v!none \strc_floats_build_box_default
@@ -1987,7 +2077,7 @@
\definefloat
[\v!graphic]
[\v!graphics]
-
+
% float strategy, replaces some of the above macros
\installcorenamespace{floatmethods}
@@ -1999,7 +2089,7 @@
\let\forcedfloatmethod\empty % set by lua
\def\setfloatmethodvariables#1% \floatmethod \floatlabel \floatrow \floatcolumn
- {\ctxcommand{analysefloatmethod("#1")}}
+ {\clf_analysefloatmethod{#1}}
\def\somesomewherefloat[#1]%
{\page_floats_save_somewhere_float\s!somewhere{#1}}
diff --git a/Master/texmf-dist/tex/context/base/strc-ini.lua b/Master/texmf-dist/tex/context/base/strc-ini.lua
index a48679e6fdf..f736427bb44 100644
--- a/Master/texmf-dist/tex/context/base/strc-ini.lua
+++ b/Master/texmf-dist/tex/context/base/strc-ini.lua
@@ -73,7 +73,7 @@ structures.itemgroups = structures.itemgroups or { }
structures.specials = structures.specials or { }
structures.counters = structures.counters or { }
structures.tags = structures.tags or { }
-structures.formulas = structures.formulas or { }
+structures.formulas = structures.formulas or { } -- not used but reserved
structures.sets = structures.sets or { }
structures.marks = structures.marks or { }
structures.floats = structures.floats or { }
@@ -160,7 +160,7 @@ local function simplify(d,nodefault)
t[k] = simplify(v)
end
elseif tv == "string" then
- if v ~= "" and v ~= "default" then
+ if v ~= "" then
t[k] = v
end
elseif tv == "boolean" then
@@ -336,7 +336,8 @@ function sets.getall(namespace,block,name)
end
end
--- messy (will be another keyword, fixedconversion)
+-- messy (will be another keyword, fixedconversion) .. needs to be documented too
+-- maybe we should cache
local splitter = lpeg.splitat("::")
@@ -376,4 +377,8 @@ end
-- interface
-commands.definestructureset = sets.define
+interfaces.implement {
+ name = "definestructureset",
+ actions = sets.define,
+ arguments = { "string", "string", "string", "string", "boolean" }
+}
diff --git a/Master/texmf-dist/tex/context/base/strc-ini.mkvi b/Master/texmf-dist/tex/context/base/strc-ini.mkvi
index 8488d1dab86..ad83cbc58c2 100644
--- a/Master/texmf-dist/tex/context/base/strc-ini.mkvi
+++ b/Master/texmf-dist/tex/context/base/strc-ini.mkvi
@@ -70,12 +70,12 @@
\unexpanded\def\defineconversionset{\dotripleempty\strc_sets_define_conversion_set}
\unexpanded\def\defineprefixset {\dotripleempty\strc_sets_define_prefix_set}
-% Low level versions (no optional checking). The detokenize and escaping might go away.
+% Low level versions (no optional checking). The detokenize might go away.
-\unexpanded\def\strc_sets_define_reset_set [#name][#set][#default]{\ctxcommand{definestructureset("structure:resets", "#name","\luaescapestring{\detokenize{#set}}","\luaescapestring{\detokenize{#default}}",true)}}
-\unexpanded\def\strc_sets_define_separator_set [#name][#set][#default]{\ctxcommand{definestructureset("structure:separators", "#name","\luaescapestring{\detokenize{#set}}","\luaescapestring{\detokenize{#default}}")}}
-\unexpanded\def\strc_sets_define_conversion_set[#name][#set][#default]{\ctxcommand{definestructureset("structure:conversions","#name","\luaescapestring{\detokenize{#set}}","\luaescapestring{\detokenize{#default}}")}}
-\unexpanded\def\strc_sets_define_prefix_set [#name][#set][#default]{\ctxcommand{definestructureset("structure:prefixes", "#name","\luaescapestring{\detokenize{#set}}","\luaescapestring{\detokenize{#default}}")}}
+\unexpanded\def\strc_sets_define_reset_set [#name][#set][#default]{\clf_definestructureset{structure:resets} {#name}{\detokenize{#set}}{\detokenize{#default}}true\relax}
+\unexpanded\def\strc_sets_define_separator_set [#name][#set][#default]{\clf_definestructureset{structure:separators} {#name}{\detokenize{#set}}{\detokenize{#default}}false\relax}
+\unexpanded\def\strc_sets_define_conversion_set[#name][#set][#default]{\clf_definestructureset{structure:conversions}{#name}{\detokenize{#set}}{\detokenize{#default}}false\relax}
+\unexpanded\def\strc_sets_define_prefix_set [#name][#set][#default]{\clf_definestructureset{structure:prefixes} {#name}{\detokenize{#set}}{\detokenize{#default}}false\relax}
\let\definestructureresetset \defineresetset
\let\definestructureseparatorset \defineseparatorset
diff --git a/Master/texmf-dist/tex/context/base/strc-itm.lua b/Master/texmf-dist/tex/context/base/strc-itm.lua
index 4945c282fba..adec591c1c1 100644
--- a/Master/texmf-dist/tex/context/base/strc-itm.lua
+++ b/Master/texmf-dist/tex/context/base/strc-itm.lua
@@ -6,33 +6,58 @@ if not modules then modules = { } end modules ['strc-itm'] = {
license = "see context related readme files"
}
-local structures = structures
-local itemgroups = structures.itemgroups
-local jobpasses = job.passes
-
-local setvariable = jobpasses.save
-local getvariable = jobpasses.getfield
-
-function itemgroups.register(name,nofitems,maxwidth)
- setvariable("itemgroup", { nofitems, maxwidth })
+local structures = structures
+local itemgroups = structures.itemgroups
+local jobpasses = job.passes
+
+local implement = interfaces.implement
+
+local setvariable = jobpasses.save
+local getvariable = jobpasses.getfield
+
+local texsetcount = tex.setcount
+local texsetdimen = tex.setdimen
+
+local f_stamp = string.formatters["itemgroup:%s:%s"]
+local counts = table.setmetatableindex("number")
+
+-- We keep the counter at the Lua end so we can group the items within
+-- an itemgroup which in turn makes for less passes when one itemgroup
+-- entry is added or removed.
+
+local trialtypesetting = context.trialtypesetting
+
+local function analyzeitemgroup(name,level)
+ local n = counts[name]
+ if level == 1 then
+ n = n + 1
+ counts[name] = n
+ end
+ local stamp = f_stamp(name,n)
+ local n = getvariable(stamp,level,1,0)
+ local w = getvariable(stamp,level,2,0)
+ texsetcount("local","c_strc_itemgroups_max_items",n)
+ texsetdimen("local","d_strc_itemgroups_max_width",w)
end
-function itemgroups.nofitems(name,index)
- return getvariable("itemgroup", index, 1, 0)
+local function registeritemgroup(name,level,nofitems,maxwidth)
+ local n = counts[name]
+ if not trialtypesetting() then
+ -- no trialtypsetting
+ setvariable(f_stamp(name,n), { nofitems, maxwidth }, level)
+ elseif level == 1 then
+ counts[name] = n - 1
+ end
end
-function itemgroups.maxwidth(name,index)
- return getvariable("itemgroup", index, 2, 0)
-end
-
--- interface (might become counter/dimension)
-
-commands.registeritemgroup = itemgroups.register
-
-function commands.nofitems(name,index)
- context(getvariable("itemgroup", index, 1, 0))
-end
+implement {
+ name = "analyzeitemgroup",
+ actions = analyzeitemgroup,
+ arguments = { "string", "integer" }
+}
-function commands.maxitemwidth(name,index)
- context(getvariable("itemgroup", index, 2, 0))
-end
+implement {
+ name = "registeritemgroup",
+ actions = registeritemgroup,
+ arguments = { "string", "integer", "integer", "dimen" }
+}
diff --git a/Master/texmf-dist/tex/context/base/strc-itm.mkvi b/Master/texmf-dist/tex/context/base/strc-itm.mkvi
index 098b863b95a..86fc9d9fd28 100644
--- a/Master/texmf-dist/tex/context/base/strc-itm.mkvi
+++ b/Master/texmf-dist/tex/context/base/strc-itm.mkvi
@@ -15,6 +15,9 @@
\registerctxluafile{strc-itm}{1.001}
+%D As we analyze/register widths and such we could as well push and pop the
+%D numbers at the \LUA\ end (which saves a few calls).
+
%D Cleaning up this module happened around the time when Kate Bush came up
%D with the nicest numbered list of words: 50 Words For Snow. It's therefore
%D no surprise that I had that cd running several times when updating this
@@ -203,7 +206,6 @@
\newdimen \d_strc_itemgroups_max_width % multipass
\newcount \c_strc_itemgroups_max_items % multipass
-\newcount \c_strc_itemgroups_n_of_lists
\newcount \c_strc_itemgroups_n_of_items
\newcount \c_strc_itemgroups_nesting
\newcount \c_strc_itemgroups_column_depth
@@ -227,13 +229,10 @@
\let \currentitemgroupsegments \empty
\def\strc_itemgroups_register_status
- {\iftrialtypesetting \else
- \ctxcommand{registeritemgroup("\currentitemgroup",\number\c_strc_itemgroups_n_of_items,"\itemgroupparameter\c!maxwidth")}%
- \fi}
+ {\clf_registeritemgroup{\currentparentitemgroup}\c_strc_itemgroups_nesting\c_strc_itemgroups_n_of_items\dimexpr\itemgroupparameter\c!maxwidth\relax}
\def\strc_itemgroups_check_n_of_items % we could do this at the lua end and save a call (i.e. will be dimen and counter)
- {\c_strc_itemgroups_max_items\ctxcommand{nofitems("\currentitemgroup",\number\c_strc_itemgroups_n_of_lists)}\relax
- \d_strc_itemgroups_max_width\ctxcommand{maxitemwidth("\currentitemgroup",\number\c_strc_itemgroups_n_of_lists)}\scaledpoint
+ {\clf_analyzeitemgroup{\currentparentitemgroup}\c_strc_itemgroups_nesting\relax
\edef\currentnofitems{\the\c_strc_itemgroups_max_items}}
% todo: \dodosetreference -> \strc_counters_register_component (to be checked)
@@ -249,47 +248,51 @@
\fi \fi}
\def\strc_itemgroups_insert_reference_indeed % maybe we need a 'frozen counter' numberdata blob / quick hack .. .mive this to strc-ref
- {%\setnextinternalreference
+ {% needs testing, gave problems:
+ \setnextinternalreference
% no need to collect nodes in \b_strc_destination_nodes here ... maybe at some point
\strc_references_start_destination_nodes
- % this is somewhat over the top ... we should use the counter's reference
- \ctxcommand{setreferenceattribute("\s!full", "\referenceprefix","\currentitemreference",
- {
- metadata = {
- kind = "item",% ?
- catcodes = \the\catcodetable,
- xmlroot = \ifx\currentreferencecoding\s!xml "\xmldocument" \else nil \fi, % only useful when text
- },
- references = {
- % internal = \nextinternalreference, % no: this spoils references
- block = "\currentsectionblock",
- section = structures.sections.currentid(),
- },
- prefixdata = structures.helpers.simplify {
- prefix = "\namedcounterparameter\v_strc_itemgroups_counter\c!prefix",
- separatorset = "\namedcounterparameter\v_strc_itemgroups_counter\c!prefixseparatorset",
- conversion = \!!bs\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconversion\!!es,
- conversionset = "\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconversionset",
- set = "\namedcounterparameter\v_strc_itemgroups_counter\c!prefixset",
- segments = "\namedcounterparameter\v_strc_itemgroups_counter\c!prefixsegments",
- % segments = "\askedprefixsegments",
- connector = \!!bs\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconnector\!!es,
- },
- numberdata = structures.helpers.simplify {
- numbers = structures.counters.compact("\v_strc_itemgroups_counter",nil,true),
- separatorset = "\namedcounterparameter\v_strc_itemgroups_counter\c!numberseparatorset",
- % conversion = "\namedcounterparameter\v_strc_itemgroups_counter\c!numberconversion",
- % conversion = "\currentitemgroupconversionset",
- % conversionset = "\namedcounterparameter\v_strc_itemgroups_counter\c!numberconversionset",
- % todo: fixedconversion = "\currentitemgroupconversionset", % temp hack:
- conversionset = "fixed::\currentitemgroupconversionset",
- %
- % for the moment no stopper, we need to make references configurable first
- % stopper = \!!bs\namedcounterparameter\v_strc_itemgroups_counter\c!numberstopper\!!es,
- segments = "\namedcounterparameter\v_strc_itemgroups_counter\c!numbersegments",
- },
- })
+ % this is somewhat over the top ... we should use the counter's reference
+ \clf_setreferenceattribute
+ {%
+ metadata {%
+ kind {item}% was item, why?
+ \ifx\currentreferencecoding\s!xml
+ xmlroot {\xmldocument}% only useful when text
+ \fi
+ catcodes \catcodetable
+ }%
+ references {%
+ internal \nextinternalreference % no: this spoils references
+ % block {\currentsectionblock}%
+ view {\interactionparameter\c!focus}%
+ prefix {\referenceprefix}%
+ reference {\currentitemreference}%
+ }%
+ prefixdata {%
+ prefix {\namedcounterparameter\v_strc_itemgroups_counter\c!prefix}%
+ separatorset {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixseparatorset}%
+ conversion {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconversion}%
+ conversionset {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconversionset}%
+ set {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixset}%
+ segments {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixsegments}%
+ % segments {\askedprefixsegments}%
+ connector {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconnector}%
+ }%
+ numberdata {%
+ numbers {\v_strc_itemgroups_counter}%
+ separatorset {\namedcounterparameter\v_strc_itemgroups_counter\c!numberseparatorset}%
+ % conversion {\namedcounterparameter\v_strc_itemgroups_counter\c!numberconversion}%
+ % conversionset {\namedcounterparameter\v_strc_itemgroups_counter\c!numberconversionset}%
+ % fixedconversion {\currentitemgroupconversionset}%
+ conversionset {fixed::\currentitemgroupconversionset}% temp hack
+ %
+ % for the moment no stopper, we need to make references configurable first
+ % stopper {\namedcounterparameter\v_strc_itemgroups_counter\c!numberstopper}%
+ segments {\namedcounterparameter\v_strc_itemgroups_counter\c!numbersegments}%
+ }%
}%
+ \relax
\strc_references_stop_destination_nodes
\xdef\currentdestinationattribute{\number\lastdestinationattribute}%
% will become an option:
@@ -467,7 +470,7 @@
\let\strc_itemgroups_margin_symbol\empty
\let\strc_itemgroups_extra_symbol\empty
%
- \global\letitemgroupparameter\c!maxwidth\!!zerocount
+ \global\letitemgroupparameter\c!maxwidth\!!zeropoint
}
\setvalue{\??itemgroupfirst\v!intro }{\settrue\c_strc_itemgroups_intro }
@@ -482,10 +485,11 @@
\csname\??itemgroupfirst#option\endcsname
\fi}
-\ifdefined\dotagsetitemgroup \else \let\dotagsetitemgroup\relax \fi
+\ifdefined\dotagsetitemgroup \else \let\dotagsetitemgroup\relax \fi
+\ifdefined\dotagsetitem \else \let\dotagsetitem \gobbleoneargument \fi
\def\strc_itemgroups_tag_start_group
- {\dostarttagged\t!itemgroup\currentitemgroup
+ {\dostarttaggedchained\t!itemgroup\currentparentitemgroup\??itemgroup
\dotagsetitemgroup}
\def\strc_itemgroups_tag_stop_group
@@ -576,7 +580,7 @@
% can be made a bit faster
\def\strc_itemgroups_setup_each#category#whatever%
- {\doifassignmentelse{#whatever}
+ {\doifelseassignment{#whatever}
{\strc_itemgroups_normal_setup[#category][#whatever]}
{\strc_itemgroups_normal_setup[#category][\c!option={#whatever}]}}
@@ -587,7 +591,7 @@
{\strc_itemgroups_normal_setup[#category:#level][\c!option={#whatever}]}
\def\strc_itemgroups_setup_list#subcategories#category#whatever%
- {\doifassignmentelse{#whatever}
+ {\doifelseassignment{#whatever}
{\processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_a{#category}{#whatever}}}
{\processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_b{#category}{#whatever}}}}
@@ -639,9 +643,9 @@
\def\strc_itemgroups_set_symbol#symbol%
{\edef\strc_itemgroups_tmp_symbol{#symbol}%
\ifx\strc_itemgroups_tmp_symbol\empty \else
- \doifsymboldefinedelse\strc_itemgroups_tmp_symbol
+ \doifelsesymboldefined\strc_itemgroups_tmp_symbol
\strc_itemgroups_set_symbol_symbol
- {\doifconversiondefinedelse\strc_itemgroups_tmp_symbol
+ {\doifelseconversiondefined\strc_itemgroups_tmp_symbol
\strc_itemgroups_set_symbol_conversion
\donothing}%
\fi}
@@ -706,7 +710,7 @@
\ifthirdargument
\strc_itemgroups_start_indeed[#options][#settings]%
\else\ifsecondargument
- \doifassignmentelse{#options}
+ \doifelseassignment{#options}
{\strc_itemgroups_start_indeed[][#options]}
{\strc_itemgroups_start_indeed[#options][]}%
\else
@@ -745,7 +749,6 @@
\iftrialtypesetting
\strc_counters_save\v_strc_itemgroups_counter
\fi
- \global\advance\c_strc_itemgroups_n_of_lists\plusone
\c_strc_itemgroups_n_of_items\zerocount
\strc_itemgroups_check_n_of_items
\ifx\itemgroupoptions\empty
@@ -811,7 +814,7 @@
\ifinsidecolumns\else\ifcase\c_strc_itemgroups_column_depth
\global\c_strc_itemgroups_column_depth\c_strc_itemgroups_nesting % global ?
\strc_itemgroups_before_command
- \strc_itemgroups_tag_start_group
+ %\strc_itemgroups_tag_start_group
\strc_itemgroups_start_columns
\fi\fi
\fi
@@ -941,8 +944,7 @@
\fi\fi
% new test, needed in sidefloats (surfaced in volker's proceedings)
\iftrialtypesetting
- \strc_counters_restore\v_strc_itemgroups_counter
- \global\advance\c_strc_itemgroups_n_of_lists\minusone
+ \strc_counters_restore\v_strc_itemgroups_counter % could happen in LUA
\fi
\global\advance\c_strc_itemgroups_nesting\minusone
\xdef\currentitemlevel{\number\c_strc_itemgroups_nesting}%
@@ -965,7 +967,7 @@
{\setfalse\c_strc_itemgroups_first
% \begingroup % (3)
\ifcase\c_strc_itemgroups_nesting
- % 0
+ % 0
\or
\strc_itemgroups_start_item_first_one % 1
\else
@@ -1039,15 +1041,11 @@
\strc_itemgroups_start_item_next
\fi
\ifconditional\c_strc_itemgroups_concat
- % \vskip-\lastskip % we cannot use a \dimexpr here because
- % \vskip-\lineheight % then we loose the stretch and shrink
- % \nobreak
- %
- \blank[\v!overlay]% new per 2014-03-27
- %
+ \spac_overlay_lines % see spac-ver.mkvi ... a typical potential problem
\setfalse\c_strc_itemgroups_concat
\fi
\dostarttagged\t!item\empty
+ % \dotagsetitem\empty
\dostarttagged\t!itemtag\empty
\strc_itemgroups_insert_item
\dostoptagged
@@ -1088,17 +1086,24 @@
\fi
\fi
\strc_itemgroups_start_item[#reference]%
- \groupedcommand\strc_itemgroups_start_head_indeed\strc_itemgroups_stop_head_indeed}
+ \pickupgroupedcommand
+ \strc_itemgroups_start_head_indeed
+ \strc_itemgroups_stop_head_indeed
+ \strc_itemgroups_head_body_indeed}
\unexpanded\def\stopitemgrouphead
- {\stopitemgroupitem}
+ {\dostoptagged
+ \stopitemgroupitem}
\unexpanded\def\strc_itemgroups_start_head_indeed
{\settrue\c_strc_itemgroups_head
+ \dotagsetitem\s!head% % weird place
+ \dostarttagged\t!itemhead\empty
\useitemgroupstyleandcolor\c!headstyle\c!headcolor\ignorespaces}
\unexpanded\def\strc_itemgroups_stop_head_indeed
{\removeunwantedspaces
+ \dostoptagged
\ifconditional\c_strc_itemgroups_text
\space
\ignorespaces
@@ -1107,7 +1112,10 @@
\fi
\strc_itemgroups_insert_breakno
\ifconditional\c_strc_itemgroups_pack\else\strc_itemgroups_after_head_command\fi
- \strc_itemgroups_insert_breakno
+ \strc_itemgroups_insert_breakno}
+
+\unexpanded\def\strc_itemgroups_head_body_indeed
+ {\dostarttagged\t!itembody\empty
\noindentation}
% Simple commands.
@@ -1125,30 +1133,37 @@
\unexpanded\def\strc_itemgroups_start_symbol#text%
{\def\strc_itemgroups_extra_symbol{#text}%
\settrue\c_strc_itemgroups_symbol
- \startitemgroupitem}
+ \startitemgroupitem
+ \dotagsetitem\s!symbol}
\unexpanded\def\strc_itemgroups_start_dummy
{\strc_itemgroups_start_symbol\strut\strut} % two ?
\unexpanded\def\strc_itemgroups_start_subitem
{\settrue\c_strc_itemgroups_sub
- \startitemgroupitem}
+ \startitemgroupitem
+ \dotagsetitem\s!sub}
\unexpanded\def\strc_itemgroups_start_edge#text%
{\strc_itemgroups_start_symbol
{\strc_itemgroups_calculate_list_width\c_strc_itemgroups_nesting
+ \dostarttagged\t!ignore\empty % for the moment, maybe an attribute
\hbox to \d_strc_itemgroups_list_width
- {#text\hskip\itemgroupparameter\c!distance}}}
+ {#text\hskip\itemgroupparameter\c!distance}%
+ \dostoptagged}}
\unexpanded\def\strc_itemgroups_start_margin#text%
{\def\strc_itemgroups_margin_symbol % brrr
- {\llap
+ {\dostarttagged\t!ignore\empty % for the moment, maybe an attribute
+ \llap
{\begingroup
\useitemgroupstyleandcolor\c!marstyle\c!marcolor
#text% keep em/ex local
\endgroup
- \hskip\dimexpr\leftskip+\leftmargindistance\relax}}%
- \startitemgroupitem}
+ \hskip\dimexpr\leftskip+\leftmargindistance\relax}%
+ \dostoptagged}%
+ \startitemgroupitem
+ \dotagsetitem\s!margin}
\unexpanded\def\strc_itemgroups_start_text#text%
{\def\strc_itemgroups_extra_symbol{#text}%
@@ -1222,7 +1237,9 @@
{\dontcomplain
\hbox to \d_strc_itemgroups_list_width
{\ifconditional\c_strc_itemgroups_sub
+ \dostarttagged\t!ignore\empty
\llap{+\enspace}%
+ \dostoptagged
\fi
\strc_itemgroups_left_sym_filler
\box\b_strc_itemgroups % can already have a forced widt, only factor handled here
@@ -1232,7 +1249,9 @@
\def\strc_itemgroups_handle_lapped_item_negative
{\llap
{\ifconditional\c_strc_itemgroups_sub
+ \dostarttagged\t!ignore\empty
\llap{+\enspace}%
+ \dostoptagged
\fi
\box\b_strc_itemgroups
\hskip\leftmargindistance}}
@@ -1240,7 +1259,9 @@
\def\strc_itemgroups_handle_groups_text_item
{\hbox
{\ifconditional\c_strc_itemgroups_sub
+ \dostarttagged\t!ignore\empty
+\enspace
+ \dostoptagged
\fi
\box\b_strc_itemgroups
\hskip\interwordspace}%
@@ -1249,7 +1270,9 @@
\def\strc_itemgroups_handle_groups_inline_item
{\hbox to \d_strc_itemgroups_list_width
{\ifconditional\c_strc_itemgroups_sub
+ \dostarttagged\t!ignore\empty
\llap{+\enspace}%
+ \dostoptagged
\fi
\box\b_strc_itemgroups
\hss}} % was: \hfill
@@ -1285,8 +1308,8 @@
\setfalse\c_strc_itemgroups_symbol}
\def\strc_itemgroups_make_fitting_box
- {\ifdim\wd\b_strc_itemgroups>\itemgroupparameter\c!maxwidth\scaledpoint\relax % brr, sp
- \normalexpanded{\global\setitemgroupparameter{\c!maxwidth}{\number\wd\b_strc_itemgroups}}%
+ {\ifdim\wd\b_strc_itemgroups>\itemgroupparameter\c!maxwidth\relax
+ \normalexpanded{\global\setitemgroupparameter{\c!maxwidth}{\the\wd\b_strc_itemgroups}}%
\fi
\ifdim\d_strc_itemgroups_max_width>\zeropoint
\setbox\b_strc_itemgroups\simplealignedbox
@@ -1539,7 +1562,7 @@
{\strc_itemgroups_item_alone}
\def\strc_itemgroups_item_alone[#category]#text\par
- {\doifsomethingelse{#category}{\startitemgroup[#category]}{\startitemgroup[\v!itemize]}%
+ {\doifelsesomething{#category}{\startitemgroup[#category]}{\startitemgroup[\v!itemize]}%
\startitem#text\stopitem
\stopitemgroup}
@@ -1547,7 +1570,7 @@
{\strc_itemgroups_head_alone}
\def\strc_itemgroups_head_alone[#category]#head\par#body\par
- {\doifsomethingelse{#category}{\startitemgroup[#category]}{\startitemgroup[\v!itemize]}%
+ {\doifelsesomething{#category}{\startitemgroup[#category]}{\startitemgroup[\v!itemize]}%
\starthead{#head}#body\stophead
\stopitemgroup}
diff --git a/Master/texmf-dist/tex/context/base/strc-lab.mkiv b/Master/texmf-dist/tex/context/base/strc-lab.mkiv
index 3e661712632..ac49941aaee 100644
--- a/Master/texmf-dist/tex/context/base/strc-lab.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-lab.mkiv
@@ -101,7 +101,7 @@
\ifx\p_counter\empty %
\let\p_counter\currentlabel
\fi
- \doifcounterelse\p_counter\donothing{\strc_labels_define_counter\p_counter}%
+ \doifelsecounter\p_counter\donothing{\strc_labels_define_counter\p_counter}%
\letlabelparameter\s!counter\p_counter
\to \everydefinelabel
@@ -113,6 +113,7 @@
\setvalue{\??constructioninitializer\v!label}%
{\let\currentlabel \currentconstruction
\let\constructionparameter \labelparameter
+ \let\constructionnamespace \??label
\let\detokenizedconstructionparameter\detokenizedlabelparameter
\let\letconstructionparameter \letlabelparameter
\let\useconstructionstyleandcolor \uselabelstyleandcolor
diff --git a/Master/texmf-dist/tex/context/base/strc-lev.lua b/Master/texmf-dist/tex/context/base/strc-lev.lua
index 947889e1e1c..d7ffd6af434 100644
--- a/Master/texmf-dist/tex/context/base/strc-lev.lua
+++ b/Master/texmf-dist/tex/context/base/strc-lev.lua
@@ -8,26 +8,30 @@ if not modules then modules = { } end modules ['strc-lev'] = {
local insert, remove = table.insert, table.remove
-local context = context
-local commands = commands
+local context = context
+local interfaces = interfaces
-local sections = structures.sections
-local default = interfaces.variables.default
+local sections = structures.sections
+local implement = interfaces.implement
-sections.levels = sections.levels or { }
+local v_default = interfaces.variables.default
-local level, levels, categories = 0, sections.levels, { }
+sections.levels = sections.levels or { }
-storage.register("structures/sections/levels", levels, "structures.sections.levels")
+local level = 0
+local levels = sections.levels
+local categories = { }
local f_two_colon = string.formatters["%s:%s"]
-function commands.definesectionlevels(category,list)
+storage.register("structures/sections/levels", levels, "structures.sections.levels")
+
+local function definesectionlevels(category,list)
levels[category] = utilities.parsers.settings_to_array(list)
end
-function commands.startsectionlevel(category)
- category = category ~= "" and category or default
+local function startsectionlevel(category)
+ category = category ~= "" and category or v_default
level = level + 1
local lc = levels[category]
if not lc or level > #lc then
@@ -38,7 +42,7 @@ function commands.startsectionlevel(category)
insert(categories,category)
end
-function commands.stopsectionlevel()
+local function stopsectionlevel()
local category = remove(categories)
if category then
local lc = levels[category]
@@ -52,3 +56,20 @@ function commands.stopsectionlevel()
-- error
end
end
+
+implement {
+ name = "definesectionlevels",
+ actions = definesectionlevels,
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "startsectionlevel",
+ actions = startsectionlevel,
+ arguments = "string"
+}
+
+implement {
+ name = "stopsectionlevel",
+ actions = stopsectionlevel,
+}
diff --git a/Master/texmf-dist/tex/context/base/strc-lev.mkvi b/Master/texmf-dist/tex/context/base/strc-lev.mkvi
index b3ec2a2d5a4..dae3f28e30e 100644
--- a/Master/texmf-dist/tex/context/base/strc-lev.mkvi
+++ b/Master/texmf-dist/tex/context/base/strc-lev.mkvi
@@ -26,17 +26,17 @@
\unexpanded\def\definesectionlevels{\dodoubleargument\strc_levels_define}
\unexpanded\def\startsectionlevel {\dosingleempty \strc_levels_start }
-\unexpanded\def\strc_levels_define[#category][#list]{\ctxcommand{definesectionlevels("#category","#list")}}
-\unexpanded\def\strc_levels_start [#category]{\ctxcommand{startsectionlevel("#category")}}
-\unexpanded\def\stopsectionlevel {\ctxcommand{stopsectionlevel()}}
+\unexpanded\def\strc_levels_define[#category][#list]{\clf_definesectionlevels{#category}{#list}}
+\unexpanded\def\strc_levels_start [#category]{\clf_startsectionlevel{#category}}
+\unexpanded\def\stopsectionlevel {\clf_stopsectionlevel}
\unexpanded\def\nostarthead{\dotripleargument\strc_levels_start_nop} % used at the lua end
\unexpanded\def\nostophead {\dosingleargument\strc_levels_stop_nop } % used at the lua end
\unexpanded\def\strc_levels_start[#category]%
- {\doifassignmentelse{#category}
- {\ctxcommand{startsectionlevel("\v!default")}[#category]}
- {\ctxcommand{startsectionlevel("#category")}}}
+ {\doifelseassignment{#category}
+ {\clf_startsectionlevel{\v!default}[#category]}
+ {\clf_startsectionlevel{#category}}}
\unexpanded\def\strc_levels_start_nop[#category][#settings][#userdata]%
{\blank
diff --git a/Master/texmf-dist/tex/context/base/strc-lnt.mkvi b/Master/texmf-dist/tex/context/base/strc-lnt.mkvi
index f84521002e1..ee7d5dd8854 100644
--- a/Master/texmf-dist/tex/context/base/strc-lnt.mkvi
+++ b/Master/texmf-dist/tex/context/base/strc-lnt.mkvi
@@ -92,10 +92,10 @@
\def\page_lines_in_to {\in[lr:e:\currentlinenotereference]}
\unexpanded\def\strc_linenotes_range_normal#1% order
- {\doifreferencefoundelse{lr:b:\currentlinenotereference}\settrue\setfalse\c_page_lines_current_from
+ {\doifelsereferencefound{lr:b:\currentlinenotereference}\settrue\setfalse\c_page_lines_current_from
\ifconditional\c_page_lines_current_from
\xdef\m_page_lines_current_from{\currentreferencelinenumber}%
- \doifreferencefoundelse{lr:e:\currentlinenotereference}\settrue\setfalse\c_page_lines_current_to
+ \doifelsereferencefound{lr:e:\currentlinenotereference}\settrue\setfalse\c_page_lines_current_to
\ifconditional\c_page_lines_current_to
\xdef\m_page_lines_current_to{\currentreferencelinenumber}%
\page_lines_in_from
@@ -111,10 +111,10 @@
\fi}
\unexpanded\def\strc_linenotes_range_sparse#1% order
- {\doifreferencefoundelse{lr:b:\currentlinenotereference}\settrue\setfalse\c_page_lines_current_from
+ {\doifelsereferencefound{lr:b:\currentlinenotereference}\settrue\setfalse\c_page_lines_current_from
\ifconditional\c_page_lines_current_from
\xdef\m_page_lines_current_from{\currentreferencelinenumber}%
- \doifreferencefoundelse{lr:e:\currentlinenotereference}\settrue\setfalse\c_page_lines_current_to
+ \doifelsereferencefound{lr:e:\currentlinenotereference}\settrue\setfalse\c_page_lines_current_to
\ifconditional\c_page_lines_current_to
\xdef\m_page_lines_current_to{\currentreferencelinenumber}%
\ifx\m_page_lines_previous_from\m_page_lines_current_from
diff --git a/Master/texmf-dist/tex/context/base/strc-lst.lua b/Master/texmf-dist/tex/context/base/strc-lst.lua
index 16160e2735f..4c9a7217e7e 100644
--- a/Master/texmf-dist/tex/context/base/strc-lst.lua
+++ b/Master/texmf-dist/tex/context/base/strc-lst.lua
@@ -15,12 +15,16 @@ if not modules then modules = { } end modules ['strc-lst'] = {
--
-- move more to commands
-local format, gmatch, gsub = string.format, string.gmatch, string.gsub
local tonumber, type = tonumber, type
-local concat, insert, remove = table.concat, table.insert, table.remove
+local concat, insert, remove, sort = table.concat, table.insert, table.remove, table.sort
local lpegmatch = lpeg.match
-local simple_hash_to_string, settings_to_hash = utilities.parsers.simple_hash_to_string, utilities.parsers.settings_to_hash
-local allocate, checked = utilities.storage.allocate, utilities.storage.checked
+
+local setmetatableindex = table.setmetatableindex
+local sortedkeys = table.sortedkeys
+
+local settings_to_set = utilities.parsers.settings_to_set
+local allocate = utilities.storage.allocate
+local checked = utilities.storage.checked
local trace_lists = false trackers.register("structures.lists", function(v) trace_lists = v end)
@@ -28,22 +32,23 @@ local report_lists = logs.reporter("structure","lists")
local context = context
local commands = commands
-
-local texgetcount = tex.getcount
+local implement = interfaces.implement
local structures = structures
local lists = structures.lists
local sections = structures.sections
local helpers = structures.helpers
local documents = structures.documents
-local pages = structures.pages
local tags = structures.tags
+local counters = structures.counters
local references = structures.references
local collected = allocate()
local tobesaved = allocate()
local cached = allocate()
local pushed = allocate()
+local kinds = allocate()
+local names = allocate()
lists.collected = collected
lists.tobesaved = tobesaved
@@ -53,19 +58,46 @@ lists.enhancers = lists.enhancers or { }
lists.ordered = allocate(lists.ordered or { }) -- to be checked
lists.cached = cached
lists.pushed = pushed
+lists.kinds = kinds
+lists.names = names
+
+local sorters = sorters
+local sortstripper = sorters.strip
+local sortsplitter = sorters.splitters.utf
+local sortcomparer = sorters.comparers.basic
local sectionblocks = allocate()
lists.sectionblocks = sectionblocks
references.specials = references.specials or { }
-local variables = interfaces.variables
local matchingtilldepth = sections.matchingtilldepth
local numberatdepth = sections.numberatdepth
+local getsectionlevel = sections.getlevel
+local typesetnumber = sections.typesetnumber
+local autosectiondepth = sections.autodepth
--- -- -- -- -- --
+local variables = interfaces.variables
-local function zerostrippedconcat(t,separator) -- for the moment not public
+local v_all = variables.all
+local v_reference = variables.reference
+local v_title = variables.title
+local v_number = variables.reference
+local v_command = variables.command
+local v_text = variables.text
+local v_current = variables.current
+local v_previous = variables.previous
+local v_next = variables.next
+local v_intro = variables.intro
+local v_here = variables.here
+local v_component = variables.component
+local v_reference = variables.reference
+local v_local = variables["local"]
+local v_default = variables.default
+
+-- for the moment not public --
+
+local function zerostrippedconcat(t,separator)
local f, l = 1, #t
for i=f,l do
if t[i] == 0 then
@@ -85,11 +117,11 @@ end
local function initializer()
-- create a cross reference between internal references
-- and list entries
- local collected = lists.collected
- local internals = checked(references.internals)
- local ordered = lists.ordered
+ local collected = lists.collected
+ local internals = checked(references.internals)
+ local ordered = lists.ordered
local usedinternals = references.usedinternals
- local blockdone = { }
+ local blockdone = { }
for i=1,#collected do
local c = collected[i]
local m = c.metadata
@@ -109,7 +141,8 @@ local function initializer()
end
end
-- access by order in list
- local kind, name = m.kind, m.name
+ local kind = m.kind
+ local name = m.name
if kind and name then
local ok = ordered[kind]
if ok then
@@ -122,6 +155,12 @@ local function initializer()
else
ordered[kind] = { [name] = { c } }
end
+ kinds[kind] = true
+ names[name] = true
+ elseif kind then
+ kinds[kind] = true
+ elseif name then
+ names[name] = true
end
end
if r then
@@ -147,7 +186,7 @@ end
job.register('structures.lists.collected', tobesaved, initializer, finalizer)
-local groupindices = table.setmetatableindex("table")
+local groupindices = setmetatableindex("table")
function lists.groupindex(name,group)
local groupindex = groupindices[name]
@@ -157,14 +196,23 @@ end
-- we could use t (as hash key) in order to check for dup entries
function lists.addto(t) -- maybe more more here (saves parsing at the tex end)
- local m = t.metadata
- local u = t.userdata
- if u and type(u) == "string" then
- t.userdata = helpers.touserdata(u)
- end
+ local metadata = t.metadata
+ local userdata = t.userdata
local numberdata = t.numberdata
+ if userdata and type(userdata) == "string" then
+ t.userdata = helpers.touserdata(userdata)
+ end
+ if not metadata.level then
+ metadata.level = structures.sections.currentlevel() -- this is not used so it will go away
+ end
+ if numberdata then
+ local numbers = numberdata.numbers
+ if type(numbers) == "string" then
+ numberdata.numbers = counters.compact(numbers,nil,true)
+ end
+ end
local group = numberdata and numberdata.group
- local name = m.name
+ local name = metadata.name
if not group then
-- forget about it
elseif group == "" then
@@ -180,6 +228,9 @@ function lists.addto(t) -- maybe more more here (saves parsing at the tex end)
setcomponent(t) -- can be inlined
end
local r = t.references
+ if r and not r.section then
+ r.section = structures.sections.currentid()
+ end
local i = r and r.internal or 0 -- brrr
local p = pushed[i]
if not p then
@@ -221,6 +272,11 @@ end
local enhanced = { }
+local synchronizepage = function(r) -- bah ... will move
+ synchronizepage = references.synchronizepage
+ return synchronizepage(r)
+end
+
function lists.enhance(n)
local l = cached[n]
if not l then
@@ -237,7 +293,7 @@ function lists.enhance(n)
-- save in the right order (happens at shipout)
lists.tobesaved[#lists.tobesaved+1] = l
-- default enhancer (cross referencing)
- references.realpage = texgetcount("realpageno")
+ synchronizepage(references)
-- tags
local kind = metadata.kind
local name = metadata.name
@@ -267,51 +323,88 @@ end
local nesting = { }
function lists.pushnesting(i)
- local parent = lists.result[i]
- local name = parent.metadata.name
+ local parent = lists.result[i]
+ local name = parent.metadata.name
local numberdata = parent and parent.numberdata
- local numbers = numberdata and numberdata.numbers
- local number = numbers and numbers[sections.getlevel(name)] or 0
- insert(nesting, { number = number, name = name, result = lists.result, parent = parent })
+ local numbers = numberdata and numberdata.numbers
+ local number = numbers and numbers[getsectionlevel(name)] or 0
+ insert(nesting, {
+ number = number,
+ name = name,
+ result = lists.result,
+ parent = parent
+ })
end
function lists.popnesting()
local old = remove(nesting)
- lists.result = old.result
+ if old then
+ lists.result = old.result
+ else
+ report_lists("nesting error")
+ end
end
--- will be split
-
-- Historically we had blocks but in the mkiv approach that could as well be a level
-- which would simplify things a bit.
-local splitter = lpeg.splitat(":")
+local splitter = lpeg.splitat(":") -- maybe also :: or have a block parameter
--- this will become filtercollected(specification) and then we'll also have sectionblock as key
-
-local sorters = {
- [variables.command] = function(a,b)
+local listsorters = {
+ [v_command] = function(a,b)
if a.metadata.kind == "command" or b.metadata.kind == "command" then
return a.references.internal < b.references.internal
else
return a.references.order < b.references.order
end
end,
- [variables.all] = function(a,b)
+ [v_all] = function(a,b)
return a.references.internal < b.references.internal
end,
+ [v_title] = function(a,b)
+ local da = a.titledata
+ local db = b.titledata
+ if da and db then
+ local ta = da.title
+ local tb = db.title
+ if ta and tb then
+ local sa = da.split
+ if not sa then
+ sa = sortsplitter(sortstripper(ta))
+ da.split = sa
+ end
+ local sb = db.split
+ if not sb then
+ sb = sortsplitter(sortstripper(tb))
+ db.split = sb
+ end
+ return sortcomparer(da,db) == -1
+ end
+ end
+ return a.references.internal < b.references.internal
+ end
}
--- some day soon we will pass a table .. also split the function
+-- was: names, criterium, number, collected, forced, nested, sortorder
-local function filtercollected(names, criterium, number, collected, forced, nested, sortorder) -- names is hash or string
- local numbers, depth = documents.data.numbers, documents.data.depth
- local result, nofresult, detail = { }, 0, nil
- local block = false -- all
- criterium = gsub(criterium or ""," ","") -- not needed
- -- new, will be applied stepwise
+local filters = setmetatableindex(function(t,k) return t[v_default] end)
+
+local function filtercollected(specification)
+ --
+ local names = specification.names or { }
+ local criterium = specification.criterium or v_default
+ local number = 0 -- specification.number
+ local reference = specification.reference or ""
+ local collected = specification.collected or lists.collected
+ local forced = specification.forced or { }
+ local nested = specification.nested or false
+ local sortorder = specification.sortorder or specification.order
+ --
+ local numbers = documents.data.numbers
+ local depth = documents.data.depth
+ local block = false -- all
local wantedblock, wantedcriterium = lpegmatch(splitter,criterium) -- block:criterium
- if wantedblock == "" or wantedblock == variables.all or wantedblock == variables.text then
+ if wantedblock == "" or wantedblock == v_all or wantedblock == v_text then
criterium = wantedcriterium ~= "" and wantedcriterium or criterium
elseif not wantedcriterium then
block = documents.data.block
@@ -321,236 +414,393 @@ local function filtercollected(names, criterium, number, collected, forced, nest
if block == "" then
block = false
end
--- print(">>",block,criterium)
- --
- forced = forced or { } -- todo: also on other branched, for the moment only needed for bookmarks
if type(names) == "string" then
- names = settings_to_hash(names)
+ names = settings_to_set(names)
end
- local all = not next(names) or names[variables.all] or false
+ local all = not next(names) or names[v_all] or false
+ --
+ specification.names = names
+ specification.criterium = criterium
+ specification.number = 0 -- obsolete
+ specification.reference = reference -- new
+ specification.collected = collected
+ specification.forced = forced -- todo: also on other branched, for the moment only needed for bookmarks
+ specification.nested = nested
+ specification.sortorder = sortorder
+ specification.numbers = numbers
+ specification.depth = depth
+ specification.block = block
+ specification.all = all
+ --
if trace_lists then
- report_lists("filtering names %a, criterium %a, block %a, number %a",names,criterium,block or "*",number)
+ report_lists("filtering names %,t, criterium %a, block %a",sortedkeys(names), criterium, block or "*")
end
- if criterium == variables.intro then
- -- special case, no structure yet
- for i=1,#collected do
- local v = collected[i]
+ local result = filters[criterium](specification)
+ if trace_lists then
+ report_lists("criterium %a, block %a, found %a",specification.criterium, specification.block or "*", #result)
+ end
+ --
+ if sortorder then -- experiment
+ local sorter = listsorters[sortorder]
+ if sorter then
+ if trace_lists then
+ report_lists("sorting list using method %a",sortorder)
+ end
+ for i=1,#result do
+ result[i].references.order = i
+ end
+ sort(result,sorter)
+ end
+ end
+ --
+ return result
+end
+
+filters[v_intro] = function(specification)
+ local collected = specification.collected
+ local result = { }
+ local nofresult = #result
+ local all = specification.all
+ local names = specification.names
+ for i=1,#collected do
+ local v = collected[i]
+ local metadata = v.metadata
+ if metadata and (all or names[metadata.name or false]) then
local r = v.references
if r and r.section == 0 then
nofresult = nofresult + 1
result[nofresult] = v
end
end
- elseif all or criterium == variables.all or criterium == variables.text then
- for i=1,#collected do
- local v = collected[i]
- local r = v.references
- if r and (not block or not r.block or block == r.block) then
- local metadata = v.metadata
- if metadata then
- local name = metadata.name or false
- local sectionnumber = (r.section == 0) or sections.collected[r.section]
- if forced[name] or (sectionnumber and not metadata.nolist and (all or names[name])) then -- and not sectionnumber.hidenumber then
- nofresult = nofresult + 1
- result[nofresult] = v
- end
- end
- end
- end
- elseif criterium == variables.current then
- if depth == 0 then
- return filtercollected(names,variables.intro,number,collected,forced,false,sortorder)
- else
+ end
+ return result
+end
+
+filters[v_reference] = function(specification)
+ local collected = specification.collected
+ local result = { }
+ local nofresult = #result
+ local names = specification.names
+ local sections = sections.collected
+ local reference = specification.reference
+ if reference ~= "" then
+ local prefix, rest = lpegmatch(references.prefixsplitter,reference) -- p::r
+ local r = prefix and rest and references.derived[prefix][rest] or references.derived[""][reference]
+ local s = r and r.numberdata -- table ref !
+ if s then
+ local depth = getsectionlevel(r.metadata.name)
+ local numbers = s.numbers
for i=1,#collected do
local v = collected[i]
local r = v.references
if r and (not block or not r.block or block == r.block) then
- local sectionnumber = sections.collected[r.section]
- if sectionnumber then -- and not sectionnumber.hidenumber then
- local cnumbers = sectionnumber.numbers
- local metadata = v.metadata
- if cnumbers then
- if metadata and not metadata.nolist and (all or names[metadata.name or false]) and #cnumbers > depth then
- local ok = true
- for d=1,depth do
- local cnd = cnumbers[d]
- if not (cnd == 0 or cnd == numbers[d]) then
- ok = false
- break
- end
- end
- if ok then
- nofresult = nofresult + 1
- result[nofresult] = v
- end
+ local metadata = v.metadata
+ if metadata and names[metadata.name or false] then
+ local sectionnumber = (r.section == 0) or sections[r.section]
+ if sectionnumber then
+ if matchingtilldepth(depth,numbers,sectionnumber.numbers) then
+ nofresult = nofresult + 1
+ result[nofresult] = v
end
end
end
end
end
- end
- elseif criterium == variables.here then
- -- this is quite dirty ... as cnumbers is not sparse we can misuse #cnumbers
- if depth == 0 then
- return filtercollected(names,variables.intro,number,collected,forced,false,sortorder)
else
- for i=1,#collected do
- local v = collected[i]
- local r = v.references
- if r then -- and (not block or not r.block or block == r.block) then
- local sectionnumber = sections.collected[r.section]
- if sectionnumber then -- and not sectionnumber.hidenumber then
- local cnumbers = sectionnumber.numbers
- local metadata = v.metadata
- if cnumbers then
- if metadata and not metadata.nolist and (all or names[metadata.name or false]) and #cnumbers >= depth then
- local ok = true
- for d=1,depth do
- local cnd = cnumbers[d]
- if not (cnd == 0 or cnd == numbers[d]) then
- ok = false
- break
- end
- end
- if ok then
- nofresult = nofresult + 1
- result[nofresult] = v
- end
- end
- end
- end
+ report_lists("unknown reference %a specified",reference)
+ end
+ else
+ report_lists("no reference specified")
+ end
+ return result
+end
+
+filters[v_all] = function(specification)
+ local collected = specification.collected
+ local result = { }
+ local nofresult = #result
+ local block = specification.block
+ local all = specification.all
+ local forced = specification.forced
+ local names = specification.names
+ local sections = sections.collected
+ for i=1,#collected do
+ local v = collected[i]
+ local r = v.references
+ if r and (not block or not r.block or block == r.block) then
+ local metadata = v.metadata
+ if metadata then
+ local name = metadata.name or false
+ local sectionnumber = (r.section == 0) or sections[r.section]
+ if forced[name] or (sectionnumber and not metadata.nolist and (all or names[name])) then -- and not sectionnumber.hidenumber then
+ nofresult = nofresult + 1
+ result[nofresult] = v
end
end
end
- elseif criterium == variables.previous then
- if depth == 0 then
- return filtercollected(names,variables.intro,number,collected,forced,false,sortorder)
- else
- for i=1,#collected do
- local v = collected[i]
- local r = v.references
- if r and (not block or not r.block or block == r.block) then
- local sectionnumber = sections.collected[r.section]
- if sectionnumber then -- and not sectionnumber.hidenumber then
- local cnumbers = sectionnumber.numbers
- local metadata = v.metadata
- if cnumbers then
- if metadata and not metadata.nolist and (all or names[metadata.name or false]) and #cnumbers >= depth then
- local ok = true
- for d=1,depth-1 do
- local cnd = cnumbers[d]
- if not (cnd == 0 or cnd == numbers[d]) then
- ok = false
- break
- end
- end
- if ok then
- nofresult = nofresult + 1
- result[nofresult] = v
- end
+ end
+ return result
+end
+
+filters[v_text] = filters[v_all]
+
+filters[v_current] = function(specification)
+ if specification.depth == 0 then
+ specification.nested = false
+ specification.criterium = v_intro
+ return filters[v_intro](specification)
+ end
+ local collected = specification.collected
+ local result = { }
+ local nofresult = #result
+ local depth = specification.depth
+ local block = specification.block
+ local all = specification.all
+ local names = specification.names
+ local numbers = specification.numbers
+ local sections = sections.collected
+ for i=1,#collected do
+ local v = collected[i]
+ local r = v.references
+ if r and (not block or not r.block or block == r.block) then
+ local sectionnumber = sections[r.section]
+ if sectionnumber then -- and not sectionnumber.hidenumber then
+ local cnumbers = sectionnumber.numbers
+ local metadata = v.metadata
+ if cnumbers then
+ if metadata and not metadata.nolist and (all or names[metadata.name or false]) and #cnumbers > depth then
+ local ok = true
+ for d=1,depth do
+ local cnd = cnumbers[d]
+ if not (cnd == 0 or cnd == numbers[d]) then
+ ok = false
+ break
end
end
+ if ok then
+ nofresult = nofresult + 1
+ result[nofresult] = v
+ end
end
end
end
end
- elseif criterium == variables["local"] then -- not yet ok
- local nested = nesting[#nesting]
- if nested then
- return filtercollected(names,nested.name,nested.number,collected,forced,nested,sortorder)
- elseif sections.autodepth(documents.data.numbers) == 0 then
- return filtercollected(names,variables.all,number,collected,forced,false,sortorder)
- else
- return filtercollected(names,variables.current,number,collected,forced,false,sortorder)
- end
- elseif criterium == variables.component then
- -- special case, no structure yet
- local component = resolvers.jobs.currentcomponent() or ""
- if component ~= "" then
- for i=1,#collected do
- local v = collected[i]
- local r = v.references
- local m = v.metadata
- if r and r.component == component and (m and names[m.name] or all) then
- nofresult = nofresult + 1
- result[nofresult] = v
+ end
+ return result
+end
+
+filters[v_here] = function(specification)
+ -- this is quite dirty ... as cnumbers is not sparse we can misuse #cnumbers
+ if specification.depth == 0 then
+ specification.nested = false
+ specification.criterium = v_intro
+ return filters[v_intro](specification)
+ end
+ local collected = specification.collected
+ local result = { }
+ local nofresult = #result
+ local depth = specification.depth
+ local block = specification.block
+ local all = specification.all
+ local names = specification.names
+ local numbers = specification.numbers
+ local sections = sections.collected
+ for i=1,#collected do
+ local v = collected[i]
+ local r = v.references
+ if r then -- and (not block or not r.block or block == r.block) then
+ local sectionnumber = sections[r.section]
+ if sectionnumber then -- and not sectionnumber.hidenumber then
+ local cnumbers = sectionnumber.numbers
+ local metadata = v.metadata
+ if cnumbers then
+ if metadata and not metadata.nolist and (all or names[metadata.name or false]) and #cnumbers >= depth then
+ local ok = true
+ for d=1,depth do
+ local cnd = cnumbers[d]
+ if not (cnd == 0 or cnd == numbers[d]) then
+ ok = false
+ break
+ end
+ end
+ if ok then
+ nofresult = nofresult + 1
+ result[nofresult] = v
+ end
+ end
end
end
end
- else -- sectionname, number
- -- not the same as register
- local depth = sections.getlevel(criterium)
- local number = tonumber(number) or numberatdepth(depth) or 0
- if trace_lists then
- local t = sections.numbers()
- detail = format("depth %s, number %s, numbers %s, startset %s",depth,number,(#t>0 and concat(t,".",1,depth)) or "?",#collected)
- end
- if number > 0 then
- local pnumbers = nil
- local pblock = block
- local parent = nested and nested.parent
- if parent then
- pnumbers = parent.numberdata.numbers or pnumbers -- so local as well as nested
- pblock = parent.references.block or pblock
- end
- for i=1,#collected do
- local v = collected[i]
- local r = v.references
- if r and (not block or not r.block or pblock == r.block) then
- local sectionnumber = sections.collected[r.section]
- if sectionnumber then
- local metadata = v.metadata
- local cnumbers = sectionnumber.numbers
- if cnumbers then
- if (all or names[metadata.name or false]) and #cnumbers >= depth and matchingtilldepth(depth,cnumbers,pnumbers) then
- nofresult = nofresult + 1
- result[nofresult] = v
+ end
+ return result
+end
+
+filters[v_previous] = function(specification)
+ if specification.depth == 0 then
+ specification.nested = false
+ specification.criterium = v_intro
+ return filters[v_intro](specification)
+ end
+ local collected = specification.collected
+ local result = { }
+ local nofresult = #result
+ local block = specification.block
+ local all = specification.all
+ local names = specification.names
+ local numbers = specification.numbers
+ local sections = sections.collected
+ local depth = specification.depth
+ for i=1,#collected do
+ local v = collected[i]
+ local r = v.references
+ if r and (not block or not r.block or block == r.block) then
+ local sectionnumber = sections[r.section]
+ if sectionnumber then -- and not sectionnumber.hidenumber then
+ local cnumbers = sectionnumber.numbers
+ local metadata = v.metadata
+ if cnumbers then
+ if metadata and not metadata.nolist and (all or names[metadata.name or false]) and #cnumbers >= depth then
+ local ok = true
+ for d=1,depth-1 do
+ local cnd = cnumbers[d]
+ if not (cnd == 0 or cnd == numbers[d]) then
+ ok = false
+ break
end
end
+ if ok then
+ nofresult = nofresult + 1
+ result[nofresult] = v
+ end
end
end
end
end
end
- if trace_lists then
- report_lists("criterium %a, block %a, found %a, detail %a",criterium,block or "*",#result,detail)
+ return result
+end
+
+filters[v_local] = function(specification)
+ local numbers = specification.numbers
+ local nested = nesting[#nesting]
+ if nested then
+ return filtercollected {
+ names = specification.names,
+ criterium = nested.name,
+ collected = specification.collected,
+ forced = specification.forced,
+ nested = nested,
+ sortorder = specification.sortorder,
+ }
+ else
+ specification.criterium = autosectiondepth(numbers) == 0 and v_all or v_current
+ specification.nested = false
+ return filtercollected(specification) -- rechecks, so better (for determining all)
end
+end
- if sortorder then -- experiment
- local sorter = sorters[sortorder]
- if sorter then
- if trace_lists then
- report_lists("sorting list using method %a",sortorder)
- end
- for i=1,#result do
- result[i].references.order = i
+
+filters[v_component] = function(specification)
+ -- special case, no structure yet
+ local collected = specification.collected
+ local result = { }
+ local nofresult = #result
+ local all = specification.all
+ local names = specification.names
+ local component = resolvers.jobs.currentcomponent() or ""
+ if component ~= "" then
+ for i=1,#collected do
+ local v = collected[i]
+ local r = v.references
+ local m = v.metadata
+ if r and r.component == component and (m and names[m.name] or all) then
+ nofresult = nofresult + 1
+ result[nofresult] = v
end
- table.sort(result,sorter)
end
end
-
return result
end
-lists.filtercollected = filtercollected
+-- local number = tonumber(number) or numberatdepth(depth) or 0
+-- if number > 0 then
+-- ...
+-- end
-function lists.filter(specification)
- return filtercollected(
- specification.names,
- specification.criterium,
- specification.number,
- lists.collected,
- specification.forced,
- false,
- specification.order
- )
+filters[v_default] = function(specification) -- is named
+ local collected = specification.collected
+ local result = { }
+ local nofresult = #result
+ ----- depth = specification.depth
+ local block = specification.block
+ local criterium = specification.criterium
+ local all = specification.all
+ local names = specification.names
+ local numbers = specification.numbers
+ local sections = sections.collected
+ local reference = specification.reference
+ local nested = specification.nested
+ --
+ if reference then
+ reference = tonumber(reference)
+ end
+ --
+ local depth = getsectionlevel(criterium)
+ local pnumbers = nil
+ local pblock = block
+ local parent = nested and nested.parent
+ --
+ if parent then
+ pnumbers = parent.numberdata.numbers or pnumbers -- so local as well as nested
+ pblock = parent.references.block or pblock
+ if trace_lists then
+ report_lists("filtering by block %a and section %a",pblock,criterium)
+ end
+ end
+ --
+ for i=1,#collected do
+ local v = collected[i]
+ local r = v.references
+ if r and (not block or not r.block or pblock == r.block) then
+ local sectionnumber = sections[r.section]
+ if sectionnumber then
+ local metadata = v.metadata
+ local cnumbers = sectionnumber.numbers
+ if cnumbers then
+ if all or names[metadata.name or false] then
+ if reference then
+ -- filter by number
+ if reference == cnumbers[depth] then
+ nofresult = nofresult + 1
+ result[nofresult] = v
+ end
+ else
+ if #cnumbers >= depth and matchingtilldepth(depth,cnumbers,pnumbers) then
+ nofresult = nofresult + 1
+ result[nofresult] = v
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ return result
end
+-- names, criterium, number, collected, forced, nested, sortorder) -- names is hash or string
+
+lists.filter = filtercollected
+
lists.result = { }
+function lists.getresult(r)
+ return lists.result[r]
+end
+
function lists.process(specification)
- lists.result = lists.filter(specification)
- local specials = utilities.parsers.settings_to_hash(specification.extras or "")
+ lists.result = filtercollected(specification)
+ local specials = settings_to_set(specification.extras or "")
specials = next(specials) and specials or nil
for i=1,#lists.result do
local r = lists.result[i]
@@ -561,7 +811,7 @@ function lists.process(specification)
end
function lists.analyze(specification)
- lists.result = lists.filter(specification)
+ lists.result = filtercollected(specification)
end
function lists.userdata(name,r,tag) -- to tex (todo: xml)
@@ -601,7 +851,7 @@ function lists.sectionnumber(name,n,spec)
local data = lists.result[n]
local sectiondata = sections.collected[data.references.section]
-- hm, prefixnumber?
- sections.typesetnumber(sectiondata,"prefix",spec,sectiondata) -- data happens to contain the spec too
+ typesetnumber(sectiondata,"prefix",spec,sectiondata) -- data happens to contain the spec too
end
-- some basics (todo: helpers for pages)
@@ -678,18 +928,18 @@ function lists.number(name,n,spec)
if data then
local numberdata = data.numberdata
if numberdata then
- sections.typesetnumber(numberdata,"number",spec or false,numberdata or false)
+ typesetnumber(numberdata,"number",spec or false,numberdata or false)
end
end
end
-function lists.prefixednumber(name,n,prefixspec,numberspec)
+function lists.prefixednumber(name,n,prefixspec,numberspec,forceddata)
local data = lists.result[n]
if data then
helpers.prefix(data,prefixspec)
- local numberdata = data.numberdata
+ local numberdata = data.numberdata or forceddata
if numberdata then
- sections.typesetnumber(numberdata,"number",numberspec or false,numberdata or false)
+ typesetnumber(numberdata,"number",numberspec or false,numberdata or false)
end
end
end
@@ -718,29 +968,175 @@ end
-- interface (maybe strclistpush etc)
-commands.pushlist = lists.pushnesting
-commands.poplist = lists.popnesting
-commands.enhancelist = lists.enhance
-commands.processlist = lists.process
-commands.analyzelist = lists.analyze
-commands.listtitle = lists.title
-commands.listprefixednumber = lists.prefixednumber
-commands.listprefixedpage = lists.prefixedpage
+if not lists.reordered then
+ function lists.reordered(data)
+ return data.numberdata
+ end
+end
+implement { name = "pushlist", actions = lists.pushnesting, arguments = "integer" }
+implement { name = "poplist", actions = lists.popnesting }
+
+implement {
+ name = "addtolist",
+ actions = { lists.addto, context },
+ arguments = {
+ {
+ { "references", {
+ { "internal", "integer" },
+ { "block" },
+ { "section", "integer" },
+ { "location" },
+ { "prefix" },
+ { "reference" },
+ { "order", "integer" },
+ }
+ },
+ { "metadata", {
+ { "kind" },
+ { "name" },
+ { "level", "integer" },
+ { "catcodes", "integer" },
+ { "coding" },
+ { "xmlroot" },
+ { "setup" },
+ }
+ },
+ { "userdata" },
+ { "titledata", {
+ { "label" },
+ { "title" },
+ { "bookmark" },
+ { "marking" },
+ { "list" },
+ }
+ },
+ { "prefixdata", {
+ { "prefix" },
+ { "separatorset" },
+ { "conversionset" },
+ { "conversion" },
+ { "set" },
+ { "segments" },
+ { "connector" },
+ }
+ },
+ { "numberdata", {
+ { "numbers" },
+ { "groupsuffix" },
+ { "group" },
+ { "counter" },
+ { "separatorset" },
+ { "conversionset" },
+ { "conversion" },
+ { "starter" },
+ { "stopper" },
+ { "segments" },
+ }
+ }
+ }
+ }
+}
-function commands.addtolist (...) context(lists.addto (...)) end
-function commands.listsize (...) context(lists.size (...)) end
-function commands.listlocation (...) context(lists.location (...)) end
-function commands.listlabel (...) context(lists.label (...)) end
-function commands.listrealpage (...) context(lists.realpage (...)) end
-function commands.listgroupindex (...) context(lists.groupindex(...)) end
+implement {
+ name = "enhancelist",
+ actions = lists.enhance,
+ arguments = "integer"
+}
-function commands.currentsectiontolist()
- context(lists.addto(sections.current()))
-end
+implement {
+ name = "processlist",
+ actions = lists.process,
+ arguments = {
+ {
+ { "names" },
+ { "criterium" },
+ { "reference" },
+ { "extras" },
+ { "order" },
+ }
+ }
+}
+
+implement {
+ name = "analyzelist",
+ actions = lists.analyze,
+ arguments = {
+ {
+ { "names" },
+ { "criterium" },
+ { "reference" },
+ }
+ }
+}
+
+implement {
+ name = "listtitle",
+ actions = lists.title,
+ arguments = { "string", "integer" }
+}
+
+implement {
+ name = "listprefixednumber",
+ actions = lists.prefixednumber,
+ arguments = {
+ "string",
+ "integer",
+ {
+ { "prefix" },
+ { "separatorset" },
+ { "conversionset" },
+ { "starter" },
+ { "stopper" },
+ { "set" },
+ { "segments" },
+ { "connector" },
+ },
+ {
+ { "separatorset" },
+ { "conversionset" },
+ { "starter" },
+ { "stopper" },
+ { "segments" },
+ }
+ }
+}
+
+implement {
+ name = "listprefixedpage",
+ actions = lists.prefixedpage,
+ arguments = {
+ "string",
+ "integer",
+ {
+ { "separatorset" },
+ { "conversionset" },
+ { "set" },
+ { "segments" },
+ { "connector" },
+ },
+ {
+ { "prefix" },
+ { "conversionset" },
+ { "starter" },
+ { "stopper" },
+ }
+ }
+}
+
+implement { name = "listsize", actions = { lists.size, context } }
+implement { name = "listlocation", actions = { lists.location, context }, arguments = "integer" }
+implement { name = "listlabel", actions = { lists.label, context }, arguments = { "integer", "string" } }
+implement { name = "listrealpage", actions = { lists.realpage, context }, arguments = { "string", "integer" } }
+implement { name = "listgroupindex", actions = { lists.groupindex, context }, arguments = { "string", "string" } }
-function commands.listuserdata(...)
- local str, metadata = lists.userdata(...)
+implement {
+ name = "currentsectiontolist",
+ actions = { sections.current, lists.addto, context }
+}
+
+local function userdata(name,r,tag)
+ local str, metadata = lists.userdata(name,r,tag)
if str then
-- local catcodes = metadata and metadata.catcodes
-- if catcodes then
@@ -752,25 +1148,21 @@ function commands.listuserdata(...)
end
end
+implement {
+ name = "listuserdata",
+ actions = userdata,
+ arguments = { "string", "integer", "string" }
+}
+
-- we could also set variables .. names will change (when this module is done)
-- maybe strc_lists_savedtitle etc
-function commands.doiflisthastitleelse (...) commands.doifelse(lists.hastitledata (...)) end
-function commands.doiflisthaspageelse (...) commands.doifelse(lists.haspagedata (...)) end
-function commands.doiflisthasnumberelse(...) commands.doifelse(lists.hasnumberdata(...)) end
-function commands.doiflisthasentry (n) commands.doifelse(lists.iscached (n )) end
-
-function commands.savedlistnumber(name,n)
- local data = cached[tonumber(n)]
- if data then
- local numberdata = data.numberdata
- if numberdata then
- sections.typesetnumber(numberdata,"number",numberdata or false)
- end
- end
-end
+implement { name = "doifelselisthastitle", actions = { lists.hastitledata, commands.doifelse }, arguments = { "string", "integer" } }
+implement { name = "doifelselisthaspage", actions = { lists.haspagedata, commands.doifelse }, arguments = { "string", "integer" } }
+implement { name = "doifelselisthasnumber", actions = { lists.hasnumberdata, commands.doifelse }, arguments = { "string", "integer" } }
+implement { name = "doifelselisthasentry", actions = { lists.iscached, commands.doifelse }, arguments = { "integer" } }
-function commands.savedlisttitle(name,n,tag)
+local function savedlisttitle(name,n,tag)
local data = cached[tonumber(n)]
if data then
local titledata = data.titledata
@@ -780,39 +1172,56 @@ function commands.savedlisttitle(name,n,tag)
end
end
--- function commands.savedlistprefixednumber(name,n)
--- local data = cached[tonumber(n)]
--- if data then
--- local numberdata = data.numberdata
--- if numberdata then
--- helpers.prefix(data,data.prefixdata)
--- sections.typesetnumber(numberdata,"number",numberdata or false)
--- end
--- end
--- end
-
-if not lists.reordered then
- function lists.reordered(data)
- return data.numberdata
+local function savedlistnumber(name,n)
+ local data = cached[tonumber(n)]
+ if data then
+ local numberdata = data.numberdata
+ if numberdata then
+ typesetnumber(numberdata,"number",numberdata or false)
+ end
end
end
-function commands.savedlistprefixednumber(name,n)
+local function savedlistprefixednumber(name,n)
local data = cached[tonumber(n)]
if data then
local numberdata = lists.reordered(data)
if numberdata then
helpers.prefix(data,data.prefixdata)
- sections.typesetnumber(numberdata,"number",numberdata or false)
+ typesetnumber(numberdata,"number",numberdata or false)
end
end
end
-commands.discardfromlist = lists.discard
+lists.savedlisttitle = savedlisttitle
+lists.savedlistnumber = savedlistnumber
+lists.savedlistprefixednumber = savedlistprefixednumber
--- new and experimental and therefore off by default
+implement {
+ name = "savedlistnumber",
+ actions = savedlistnumber,
+ arguments = { "string", "integer" }
+}
-local sort, setmetatableindex = table.sort, table.setmetatableindex
+implement {
+ name = "savedlisttitle",
+ actions = savedlisttitle,
+ arguments = { "string", "integer" }
+}
+
+implement {
+ name = "savedlistprefixednumber",
+ actions = savedlistprefixednumber,
+ arguments = { "string", "integer" }
+}
+
+implement {
+ name = "discardfromlist",
+ actions = lists.discard,
+ arguments = { "integer" }
+}
+
+-- new and experimental and therefore off by default
lists.autoreorder = false -- true
diff --git a/Master/texmf-dist/tex/context/base/strc-lst.mkvi b/Master/texmf-dist/tex/context/base/strc-lst.mkvi
index 0008f060231..556d2ab4895 100644
--- a/Master/texmf-dist/tex/context/base/strc-lst.mkvi
+++ b/Master/texmf-dist/tex/context/base/strc-lst.mkvi
@@ -47,7 +47,7 @@
\c!state=\v!start,
\c!coupling=\v!off,
\c!criterium=\v!local,
- \c!number=\zerocount,
+ \c!reference=,% was number which was sort of obsolete
\c!width=3\emwidth,
%\c!maxwidth=,
\c!distance=\zeropoint,
@@ -94,6 +94,8 @@
\expandafter\secondoftwoarguments
\fi}
+\let\doiflistelse\doifelselist
+
%D Regular list entries are bound to a specific location in order to
%D get the right pagenumber etc.\ associated. When pushing something
%D inbetween (in mkiv) it ends up directtly in the list. This is the
@@ -125,37 +127,48 @@
\def\strc_lists_inject_nop[#dummya][#dummyb]%
{\endgroup}
-\def\strc_lists_inject_yes[#settings][#userdata]%
+\unexpanded\def\strc_lists_inject_enhance#listindex#internal%
+ {\normalexpanded{\ctxlatecommand{enhancelist(#listindex)}}}
+
+\unexpanded\def\strc_lists_inject_yes[#settings][#userdata]% can be used directly
{\setupcurrentlist[\c!type=userdata,\c!location=\v!none,#settings]% grouped (use \let...
\edef\p_location{\listparameter\c!location}%
\setnextinternalreference
- \edef\currentlistnumber{\ctxcommand{addtolist{
- references = {
- internal = \nextinternalreference,
- block = "\currentsectionblock", % handy for lists, like bibl
- section = structures.sections.currentid(),
- % location = "\p_location",
- },
- metadata = {
- kind = "\listparameter\c!type",
- name = "\currentlist",
- level = structures.sections.currentlevel(),
- catcodes = \the\catcodetable,
- },
- userdata = \!!bs\detokenize{#userdata}\!!es % will be converted to table at the lua end
- }}}%
+ \scratchcounter\clf_addtolist
+ references {
+ internal \nextinternalreference
+ % block {\currentsectionblock}
+ % section structures.sections.currentid()
+ % location {\p_location}
+ }
+ metadata {
+ kind {\listparameter\c!type}
+ name {\currentlist}
+ % level structures.sections.currentlevel()
+ catcodes \catcodetable
+ }
+ userdata {\detokenize\expandafter{\normalexpanded{#userdata}}}
+ \relax
+ \edef\currentlistnumber{\the\scratchcounter}%
\ifx\p_location\v!here
% this branch injects nodes !
- \expanded{\ctxlatecommand{enhancelist(\currentlistnumber)}}%
- \ctxcommand{setinternalreference(nil,nil,\nextinternalreference)}% will change
+ \strc_lists_inject_enhance{\currentlistnumber}{\nextinternalreference}%
+ \clf_setinternalreference internal \nextinternalreference\relax % this will change
\xdef\currentstructurelistattribute{\the\lastdestinationattribute}%
\dontleavehmode\hbox attr \destinationattribute \lastdestinationattribute{}% todo
\else
% and this one doesn't
- \ctxcommand{enhancelist(\currentlistnumber)}%
+ \clf_enhancelist\currentlistnumber\relax
\fi
\endgroup}
+% todo: make like \strc_references_direct_full_user ... with {}{}{}
+
+\unexpanded\def\strc_lists_inject_direct[#tag]% [#settings][#userdata]
+ {\begingroup
+ \edef\currentlist{#tag}%
+ \strc_lists_inject_yes} % [#settings][#userdata]
+
\unexpanded\def\writebetweenlist{\dodoubleempty \strc_lists_write_between}
\unexpanded\def\writedatatolist {\dotripleargument\strc_lists_write_data_to}
\unexpanded\def\writetolist {\dodoubleempty \strc_lists_write_to}
@@ -244,7 +257,7 @@
\strc_lists_place_current % maybe inline
{#list}%
{\listparameter\c!criterium}%
- {\listparameter\c!number}%
+ {\listparameter\c!reference}%
{\listparameter\c!extras}%
{\listparameter\c!order}%
% \stoplistreferences
@@ -288,7 +301,7 @@
{\dotripleempty\strc_lists_combined_define}
\def\strc_lists_combined_define[#tag][#list][#settings]%
- {\definelist[#tag][\c!criterium=\v!local,\c!number=0,\c!alternative=,\c!list={#list},#settings]% inherits from root
+ {\definelist[#tag][\c!criterium=\v!local,\c!reference=,\c!alternative=,\c!list={#list},#settings]% inherits from root
\setvalue{\e!setup #tag\e!endsetup}{\dodoubleempty\strc_lists_combined_setup [#tag]}%
\setvalue{\e!place #tag}{\dodoubleempty\strc_lists_combined_place [#tag]}%
\setvalue{\e!complete #tag}{\dodoubleempty\strc_lists_combined_complete[#tag]}}
@@ -324,42 +337,42 @@
\def\currentstructurelistnumber{0} % injection
\def\currentlistmethod {entry} % typesetting
-\def\currentlistindex {0} % typesetting
+\def\currentlistindex {0} % typesetting (maybe also a real counter)
\def\structurelistlocation
- {\ctxcommand{listlocation(\currentlistindex)}}
+ {\clf_listlocation\numexpr\currentlistindex\relax}
\def\structurelistrealpagenumber
- {\ctxcommand{listrealpage("\currentlist",\currentlistindex)}}
+ {\clf_listrealpage{\currentlist}\numexpr\currentlistindex\relax}
\unexpanded\def\structurelistpagenumber
{\dostarttagged\t!listpage\empty
- \ctxcommand{listprefixedpage(
- "\currentlist",
- \currentlistindex,
- {
- separatorset = "\listparameter\c!pageprefixseparatorset",
- conversionset = "\listparameter\c!pageprefixconversionset",
- set = "\listparameter\c!pageprefixset",
- segments = "\listparameter\c!pageprefixsegments",
- connector = \!!bs\listparameter\c!pageprefixconnector\!!es,
- },
- {
- prefix = "\listparameter\c!pageprefix",
- conversionset = "\listparameter\c!pageconversionset",
- starter = \!!bs\listparameter\c!pagestarter\!!es,
- stopper = \!!bs\listparameter\c!pagestopper\!!es,
+ \clf_listprefixedpage
+ {\currentlist}
+ \currentlistindex
+ {
+ separatorset {\listparameter\c!pageprefixseparatorset}
+ conversionset {\listparameter\c!pageprefixconversionset}
+ set {\listparameter\c!pageprefixset}
+ segments {\listparameter\c!pageprefixsegments}
+ connector {\listparameter\c!pageprefixconnector}
}
- )}%
+ {
+ prefix {\listparameter\c!pageprefix}
+ conversionset {\listparameter\c!pageconversionset}
+ starter {\listparameter\c!pagestarter}
+ stopper {\listparameter\c!pagestopper}
+ }
+ \relax
\dostoptagged}
\unexpanded\def\structurelistuservariable#name%
{\dostarttagged\t!listdata{#name}%
- \ctxcommand{listuserdata("\currentlist",\currentlistindex,"#name")}%
+ \clf_listuserdata{\currentlist}\currentlistindex{#name}%
\dostoptagged}
\def\rawstructurelistuservariable#name%
- {\ctxcommand{listuserdata("\currentlist",\currentlistindex,"#name")}}
+ {\clf_listuserdata{\currentlist}\currentlistindex{#name}}
\unexpanded\def\structurelistfirst {\structurelistuservariable\s!first } % s!
\unexpanded\def\structurelistsecond{\structurelistuservariable\s!second} % s!
@@ -367,63 +380,70 @@
\def\rawstructurelistfirst {\rawstructurelistuservariable\s!first } % s! % was \unexpanded
\def\rawstructurelistsecond{\rawstructurelistuservariable\s!second} % s! % was \unexpanded
-\unexpanded\def\doifstructurelisthaspageelse
- {\ctxcommand{doiflisthaspageelse("\currentlist",\currentlistindex)}}
+\unexpanded\def\doifelsestructurelisthaspage
+ {\clf_doifelselisthaspage{\currentlist}\numexpr\currentlistindex\relax}
+
+\unexpanded\def\doifelsestructurelisthasnumber
+ {\clf_doifelselisthasnumber{\currentlist}\numexpr\currentlistindex\relax}
-\unexpanded\def\doifstructurelisthasnumberelse
- {\ctxcommand{doiflisthasnumberelse("\currentlist",\currentlistindex)}}
+\let\doifstructurelisthaspageelse \doifelsestructurelisthaspage
+\let\doifstructurelisthasnumberelse\doifelsestructurelisthasnumber
\unexpanded\def\structurelistgenerictitle
{\dostarttagged\t!listcontent\empty
- \ctxcommand{listtitle("\currentlist",\currentlistindex)}%
+ \clf_listtitle{\currentlist}\currentlistindex\relax
\dostoptagged}
\unexpanded\def\structurelistgenericnumber % tricky, we need to delay tagging as we have nested lua calls
{\dostarttagged\t!listtag\empty
- \ctxcommand{listprefixednumber("\currentlist",\currentlistindex, {
- prefix = "\listparameter\c!prefix",
- separatorset = "\listparameter\c!prefixseparatorset",
- conversionset = "\listparameter\c!prefixconversionset",
- starter = \!!bs\listparameter\c!prefixstarter\!!es,
- stopper = \!!bs\listparameter\c!prefixstopper\!!es,
- set = "\listparameter\c!prefixset",
- segments = "\listparameter\c!prefixsegments",
- connector = \!!bs\listparameter\c!prefixconnector\!!es,
- },
- {
- separatorset = "\listparameter\c!numberseparatorset",
- conversionset = "\listparameter\c!numberconversionset",
- starter = \!!bs\listparameter\c!numberstarter\!!es,
- stopper = \!!bs\listparameter\c!numberstopper\!!es,
- segments = "\listparameter\c!numbersegments",
- } )}%
+ \clf_listprefixednumber
+ {\currentlist}%
+ \currentlistindex
+ {%
+ prefix {\listparameter\c!prefix}%
+ separatorset {\listparameter\c!prefixseparatorset}%
+ conversionset {\listparameter\c!prefixconversionset}%
+ starter {\listparameter\c!prefixstarter}%
+ stopper {\listparameter\c!prefixstopper}%
+ set {\listparameter\c!prefixset}%
+ segments {\listparameter\c!prefixsegments}%
+ connector {\listparameter\c!prefixconnector}%
+ }%
+ {%
+ separatorset {\listparameter\c!numberseparatorset}%
+ conversionset {\listparameter\c!numberconversionset}%
+ starter {\listparameter\c!numberstarter}%
+ stopper {\listparameter\c!numberstopper}%
+ segments {\listparameter\c!numbersegments}%
+ }%
+ \relax
\dostoptagged}
% TODO: pass extra tag name (contents, figures, bibliography ...)
-\unexpanded\def\strc_lists_place_current#list#criterium#number#extras#order% beware, not a user command
- {\dostarttagged\t!list\empty
- \ctxcommand{processlist{
- names = "#list",
- criterium = "#criterium",
- number = "#number",
- extras = "#extras",
- order = "#order"
- }}%
+\unexpanded\def\strc_lists_place_current#list#criterium#reference#extras#order% beware, not a user command
+ {\dostarttaggedchained\t!list\empty\??list
+ \clf_processlist
+ names {#list}
+ criterium {#criterium}
+ reference {#reference}
+ extras {#extras}
+ order {#order}
+ \relax
\dostoptagged}
-\unexpanded\def\strc_lists_analyze#list#criterium#number%
- {\ctxcommand{analyzelist{
- names = "#list",
- criterium = "#criterium",
- number = "#number"
- }}}
+\unexpanded\def\strc_lists_analyze#list#criterium#reference%
+ {\clf_analyzelist
+ names {#list}
+ criterium {#criterium}
+ reference {#reference}
+ \relax}
-\def\firststructureelementinlist#list%
- {\ctxcommand{firstinset("#list")}}
+\def\firststructureelementinlist#list% expandable
+ {\clf_firstinset{#list}}
\def\structurelistsize
- {\ctxcommand{listsize()}}
+ {\clf_listsize}
%D Depending on what kind of list we have (e.g.\ a section related one)
%D processors can be defined.
@@ -451,14 +471,12 @@
\def\usestructurelistprocessor#tag%
{\csname\??structurelistprocessor#tag\endcsname}
-\unexpanded\def\strclistsentryprocess#tag#method#index#extra% This one is called at the lua end!
- {\ctxcommand{pushlist(#index)}%
- \edef\currentlist {#tag}%
- \edef\currentlistmethod{#method}%
- \edef\currentlistindex {#index}%
- \edef\currentlistextra {#extra}%
- \listextraparameter\c!before
+\let\dotaglistlocation\relax
+
+\def\strc_lists_entry_process % assume things to be set up
+ {\listextraparameter\c!before
\dostarttagged\t!listitem\currentlist
+ \dotaglistlocation
\csname\??structurelistprocessor
\ifcsname\??structurelistprocessor\currentlist:\currentlistmethod\endcsname\currentlist:\currentlistmethod\else
\ifcsname\??structurelistprocessor\currentlistmethod \endcsname\currentlistmethod \else
@@ -466,8 +484,16 @@
\s!default \fi\fi\fi
\endcsname
\dostoptagged
- \listextraparameter\c!after
- \ctxcommand{poplist()}}
+ \listextraparameter\c!after}
+
+\unexpanded\def\strclistsentryprocess#tag#method#index#extra% This one is called at the lua end!
+ {\clf_pushlist#index\relax
+ \edef\currentlist {#tag}%
+ \edef\currentlistmethod{#method}%
+ \edef\currentlistindex {#index}%
+ \edef\currentlistextra {#extra}%
+ \strc_lists_entry_process
+ \clf_poplist}
% lists that have a number/title are kind of generic and can share code
@@ -481,7 +507,7 @@
\strc_lists_apply_renderingsetup}
\installstructurelistprocessor\s!command
- {\ctxcommand{listuserdata("\currentlist",\currentlistindex,"\s!command")}}
+ {\clf_listuserdata{\currentlist}\currentlistindex{\s!command}}
\installstructurelistprocessor{section}
{\let\currentlistentrynumber \structurelistgenericnumber
@@ -498,7 +524,7 @@
% example of usage elsewhere:
%
% \installstructcurelistprocessor{pubs:userdata}
-% {\ctxcommand{listuserdata("\currentlist",\currentlistindex,"bibref")}}
+% {\clf_listuserdata{\currentlist}\currentlistindex{bibref}}
%D List symbols are used in interactive documents where no numbers
%D are used but nevertheless structure is present. Beware, the list
@@ -520,7 +546,7 @@
\def\strc_lists_assign_dimen#dimension#key#default%
{\edef\m_strc_list_dimen{\listparameter#key}%
- \doifinsetelse\m_strc_list_dimen{\v!fit,\v!broad}{#dimension#default}{#dimension\m_strc_list_dimen}\relax}
+ \doifelseinset\m_strc_list_dimen{\v!fit,\v!broad}{#dimension#default}{#dimension\m_strc_list_dimen}\relax}
\definesymbol[\v!list][\v!none ][\strc_lists_symbol_none]
\definesymbol[\v!list][\v!one ][\strc_lists_symbol_one]
@@ -531,7 +557,7 @@
\unexpanded\def\currentlistsymbol
{\edef\p_symbol{\listparameter\c!symbol}%
- \doifinsymbolsetelse\v!list\p_symbol
+ \doifelseinsymbolset\v!list\p_symbol
{\directsymbol\v!list\p_symbol}
{\directsymbol\v!list\s!default}}
@@ -589,7 +615,7 @@
{\currentlistentrynumber}
\setvalue{\??listsymbollabels\v!yes}% auto (use value stored in tuc file)
- {\edef\currentlistlabel{\ctxcommand{listlabel(\currentlistindex,"\currentlistlabel")}}%
+ {\edef\currentlistlabel{\clf_listlabel\currentlistindex{\currentlistlabel}}%
\leftlabeltext\currentlistlabel
\listparameter\c!starter
\currentlistentrynumber
@@ -700,7 +726,7 @@
\let\p_method\v!command
\fi
\normalexpanded{\definelistalternative[#tag][\p_method]}[\c!command=\strc_lists_placement_command]%
- \doifnextbgroupelse
+ \doifelsenextbgroup
{\strc_lists_define_placement_yes{#tag}}
{\strc_lists_define_placement_nop{#tag}}}
@@ -764,7 +790,7 @@
\settrue\c_lists_has_page
\settrue\c_lists_show_page
\else
- \doifstructurelisthaspageelse\settrue\setfalse\c_lists_has_page
+ \doifelsestructurelisthaspage\settrue\setfalse\c_lists_has_page
\ifx\p_pagenumber\v!yes
\settrue\c_lists_show_page
\else
@@ -777,7 +803,7 @@
\settrue\c_lists_has_number
\settrue\c_lists_show_number
\else
- \doifstructurelisthasnumberelse\settrue\setfalse\c_lists_has_number
+ \doifelsestructurelisthasnumber\settrue\setfalse\c_lists_has_number
\ifx\p_headnumber\v!yes
\settrue\c_lists_show_number
\else
@@ -818,6 +844,8 @@
% todo: provide packager via attributes
+\doinstallinjector\s!list
+
\installcorenamespace{listalternativemethods} % the general wrapper of a rendering
\startsetups[\??listrenderings:none]
@@ -845,12 +873,15 @@
% \stopsetups
\startsetups[\??listrenderings:generic]
+ \typo_injectors_check_list
\listparameter\c!before % can be \hskip
\edef\p_command{\listalternativeparameter\c!command}
\ifx\p_command\empty
\listalternativeparameter\c!before
\vbox {
\forgetall
+ \noindent % otherwise annotations are mirrored up
+ \typo_injectors_mark_list
\hbox \strc_lists_get_reference_attribute\v!all {
\ifconditional\c_lists_show_number
% \ifconditional\c_lists_has_page
@@ -878,6 +909,8 @@
}
\listalternativeparameter\c!after
\else
+ \noindent % otherwise annotations are mirrored up
+\typo_injectors_mark_list
\hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute {
\p_command\currentlistentrynumber\currentlistentrytitle\currentlistentrypagenumber
}
@@ -889,7 +922,8 @@
\startsetups[\??listrenderings:abc]
\endgraf % are we grouped?
-% \advance % yes or no ... \rightskip is also honored
+ \typo_injectors_check_list
+ % \advance % yes or no ... \rightskip is also honored
\leftskip\listparameter\c!margin % after \endgraf !
\listparameter\c!before
\endgraf
@@ -908,7 +942,8 @@
\scratchwidth\p_width
\fi
\fi\fi
- \noindent
+ \noindent % otherwise annotations are mirrored up
+ \typo_injectors_mark_list
\hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute {
\setlocalhsize
\hsize\localhsize
@@ -952,6 +987,8 @@
\hsize\scratchhsize
\usealignparameter\listparameter
\ifdim\scratchwidth<\hsize
+ % we have leftskip so we'd better just skip back instead of messing
+ % with hang*
\edef\p_hang{\listparameter\c!hang}
\hangindent\dimexpr\wd\b_strc_lists_number+\scratchdistance\relax
\hangafter\ifx\p_hang\v!no\zerocount\else\plusone\fi
@@ -964,7 +1001,7 @@
\scratchdistance\zeropoint
\fi
\parindent\zeropoint
- \dontleavehmode
+ \dontleavehmode % this nils hang: i need to figure out why
% % topaligned
%
% \scratchdimen\wd\b_strc_lists_number
@@ -1089,7 +1126,9 @@
\stopsetups
\startsetups[\??listrenderings:e]
- \noindent
+ \typo_injectors_check_list
+ \noindent % otherwise annotations are mirrored up
+ \typo_injectors_mark_list
\hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute {
\letlistparameter\c!depth\zeropoint
\letlistparameter\c!color\empty
@@ -1109,7 +1148,9 @@
\stopsetups
\startsetups[\??listrenderings:f]
- \noindent
+ \typo_injectors_check_list
+ \noindent % otherwise annotations are mirrored up
+ \typo_injectors_mark_list
\hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute {
\dosetraggedhbox{\listparameter\c!align}%
\raggedbox {
@@ -1127,7 +1168,9 @@
\stopsetups
\startsetups[\??listrenderings:g]
- \noindent
+ \typo_injectors_check_list
+ \noindent % otherwise annotations are mirrored up
+ \typo_injectors_mark_list
\hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute {
\midaligned {
\strc_lists_set_style_color\c!style\c!color\v!all
@@ -1148,19 +1191,119 @@
\definelistalternative
[\v!interactive]
- [\c!renderingsetup=\??listrenderings:interactive]
+ [\c!renderingsetup=\??listrenderings:interactive,
+ \c!before=\endgraf, % new per 2014-11-08
+ \c!after=\endgraf] % new per 2014-11-08
\startsetups[\??listrenderings:interactive]
- \edef\p_command{\listalternativeparameter\c!command}%
- \ifx\p_command\empty
- [\currentlist: \currentlistentrynumber\space -- \currentlistentrytitle\space -- \currentlistentrypagenumber]%
- \else
- \listparameter\c!before
- \hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute {
- \p_command\currentlistentrynumber\currentlistentrytitle\currentlistentrypagenumber
- }
- \listparameter\c!after
- \fi
+ \edef\p_command{\listalternativeparameter\c!command}%
+ \typo_injectors_check_list
+ \listparameter\c!before
+ \noindent % otherwise annotations are mirrored up
+ \typo_injectors_mark_list
+ \hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute {
+ \ifx\p_command\empty
+ [
+ \currentlist:\space
+ \currentlistentrynumber
+ \space\emdash\space
+ \currentlistentrytitle
+ \space\emdash\space
+ \currentlistentrypagenumber
+ ]
+ \else
+ \p_command\currentlistentrynumber\currentlistentrytitle\currentlistentrypagenumber
+ \fi
+ }
+ \listparameter\c!after
+\stopsetups
+
+%D One special for publications (as Alan loves to hangindent). No fonts and
+%D such (for now). No interaction either as that is dealt with elsewhere.
+%D
+%D \currentlistsymbol
+%D \currentlistentry
+%D \currentlistentrypagenumber % not really used
+
+\definelistalternative
+ [\v!paragraph]
+ [\c!filler=\hskip.25\emwidth,
+ \c!renderingsetup=\??listrenderings:\v!paragraph]
+
+\startsetups[\??listrenderings:\v!paragraph]
+ \endgraf % are we grouped?
+ \typo_injectors_check_list % ?
+ \listparameter\c!before
+ \endgraf
+ \begingroup
+ \forgetall
+ \noindent
+ \parindent\zeropoint
+ \edef\p_width{\listparameter\c!width}%
+ \edef\p_distance{\listparameter\c!distance}% we are nice for bib users
+ \edef\p_margin{\listparameter\c!margin}% we are nice for bib users
+ \ifx\p_distance\v!none
+ \scratchdistance\zeropoint
+ \else
+ \scratchdistance\p_distance
+ \fi
+ \ifx\p_margin\v!none
+ \scratchoffset\zeropoint
+ \else
+ \scratchoffset\p_margin
+ \fi
+ \ifx\p_width\v!fit
+ \scratchwidth\zeropoint
+ \leftskip\scratchoffset
+ \else
+ \scratchwidth\p_width
+ \ifdim\scratchoffset=\zeropoint
+ \leftskip\dimexpr\scratchwidth+\scratchdistance\relax
+ \else
+ \leftskip\scratchoffset
+ \fi
+ \fi
+ \usealignparameter\listparameter
+ \hskip-\leftskip
+ \ifconditional\c_lists_has_number
+ \ifconditional\c_lists_show_number
+ \setbox\scratchbox
+ \ifzeropt\scratchwidth
+ \hbox
+ \else
+ \simplealignedbox\scratchwidth{\listparameter\c!numberalign}
+ \fi
+ \bgroup
+ \useliststyleandcolor\c!numberstyle\c!numbercolor
+ \currentlistsymbol
+ \egroup
+ \ifdim\wd\scratchbox>\zeropoint
+ \box\scratchbox
+ \hskip\scratchdistance\relax
+ \fi
+ \fi
+ \fi
+ \begingroup
+ \useliststyleandcolor\c!textstyle\c!textcolor
+ \setstrut
+ \begstrut
+ \currentlistentrytitle
+ \endstrut
+ \endgroup
+ \ifconditional\c_lists_has_page
+ \ifconditional\c_lists_show_page
+ \nobreak
+ \listalternativeparameter\c!filler\relax
+ \begingroup
+ \useliststyleandcolor\c!pagestyle\c!pagecolor
+ \currentlistentrypagenumber
+ \endgroup
+ \fi
+ \fi
+ \endgraf
+ \endgroup
+ \allowbreak
+ \listparameter\c!after
\stopsetups
%D List elements are packaged in such a way that we can click on them
@@ -1303,7 +1446,7 @@
\let\listlength\!!zerocount
\else
\setupcurrentlist[#settings]%
- \strc_lists_analyze{#list}{\listparameter\c!criterium}{\listparameter\c!number}%
+ \strc_lists_analyze{#list}{\listparameter\c!criterium}{\listparameter\c!reference}%
\normalexpanded{\endgroup\noexpand\edef\noexpand\listlength{\structurelistsize}}%
\fi
\strc_lists_set_mode}
diff --git a/Master/texmf-dist/tex/context/base/strc-mar.lua b/Master/texmf-dist/tex/context/base/strc-mar.lua
index 9c6259de4c4..3af9113bf85 100644
--- a/Master/texmf-dist/tex/context/base/strc-mar.lua
+++ b/Master/texmf-dist/tex/context/base/strc-mar.lua
@@ -10,12 +10,14 @@ if not modules then modules = { } end modules ['strc-mar'] = {
-- todo: only commands.* print to tex, native marks return values
local insert, concat = table.insert, table.concat
-local tostring, next, rawget = tostring, next, rawget
+local tostring, next, rawget, type = tostring, next, rawget, type
local lpegmatch = lpeg.match
local context = context
local commands = commands
+local implement = interfaces.implement
+
local allocate = utilities.storage.allocate
local setmetatableindex = table.setmetatableindex
@@ -29,7 +31,6 @@ local getprev = nuts.getprev
local getid = nuts.getid
local getlist = nuts.getlist
local getattr = nuts.getattr
-local setattr = nuts.setattr
local getbox = nuts.getbox
local traversenodes = nuts.traverse
@@ -217,7 +218,11 @@ local function resolve(t,k)
end
function marks.define(name,settings)
- settings = settings or { }
+ if not settings then
+ settings = { }
+ elseif type(settings) == "string" then
+ settings = { parent = settings }
+ end
data[name] = settings
local parent = settings.parent
if parent == nil or parent == "" or parent == name then
@@ -712,20 +717,17 @@ end
-- interface
-commands.markingtitle = marks.title
-commands.markingnumber = marks.number
-
-commands.definemarking = marks.define
-commands.relatemarking = marks.relate
-commands.setmarking = marks.set
-commands.resetmarking = marks.reset
-commands.synchronizemarking = marks.synchronize
-commands.getmarking = marks.fetch
-commands.fetchonemark = marks.fetchonemark
-commands.fetchtwomarks = marks.fetchtwomarks
-commands.fetchallmarks = marks.fetchallmarks
-
-function commands.doifelsemarking(str) -- can be shortcut
- commands.doifelse(marks.exists(str))
-end
+implement { name = "markingtitle", actions = marks.title, arguments = { "string", "string" } }
+implement { name = "markingnumber", actions = marks.number, arguments = { "string", "string" } }
+
+implement { name = "definemarking", actions = marks.define, arguments = { "string", "string" } }
+implement { name = "relatemarking", actions = marks.relate, arguments = { "string", "string" } }
+implement { name = "setmarking", actions = marks.set, arguments = { "string", "string" } }
+implement { name = "resetmarking", actions = marks.reset, arguments = { "string" } }
+implement { name = "synchronizemarking", actions = marks.synchronize, arguments = { "string", "integer", "string" } }
+implement { name = "getmarking", actions = marks.fetch, arguments = { "string", "string", "string" } }
+implement { name = "fetchonemark", actions = marks.fetchonemark, arguments = { "string", "string", "string" } }
+implement { name = "fetchtwomarks", actions = marks.fetchtwomarks, arguments = { "string", "string" } }
+implement { name = "fetchallmarks", actions = marks.fetchallmarks, arguments = { "string", "string" } }
+implement { name = "doifelsemarking", actions = { marks.exists, commands.doifelse }, arguments = "string" }
diff --git a/Master/texmf-dist/tex/context/base/strc-mar.mkiv b/Master/texmf-dist/tex/context/base/strc-mar.mkiv
index 3685b66a702..8bd8c094e44 100644
--- a/Master/texmf-dist/tex/context/base/strc-mar.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-mar.mkiv
@@ -56,35 +56,31 @@
\unexpanded\def\synchronizemarking{\dotripleargument\strc_markings_synchronize}
\appendtoks
- \ctxcommand{definemarking("\currentmarking",{ parent = "\currentmarkingparent" })}%
+ \clf_definemarking{\currentmarking}{\currentmarkingparent}%
\to \everydefinemarking
\def\strc_markings_relate[#1][#2]%
- {\ctxcommand{relatemarking("#1","#2")}}
+ {\clf_relatemarking{#1}{#2}}
\def\strc_markings_set[#1]#2%
{\ifconditional\inhibitsetmarking
% nothing
\else
\doifelse{\namedmarkingparameter{#1}\c!expansion}\v!yes
- {\ctxcommand{setmarking("#1",\!!bs#2\!!es)}}
- {\ctxcommand{setmarking("#1",\!!bs\detokenize{#2}\!!es)}}%
+ {\clf_setmarking{#1}{#2}}
+ {\clf_setmarking{#1}{\detokenize{#2}}}%
\fi}
\def\strc_markings_reset[#1]%
- {\ctxcommand{resetmarking("#1")}}
+ {\clf_resetmarking{#1}}
\def\strc_markings_synchronize[#1][#2][#3]% #1=class #2=boxnumber (some day also name) #3=options, maybe second argument table
- {\ifvoid#2\else\ctxcommand{synchronizemarking("#1",\number#2,"#3")}\fi}
+ {\ifvoid#2\else\clf_synchronizemarking{#1}#2{#3}\fi}
-% \def\doifelsemarking#1% why no \unexpanded
-% {\ctxcommand{doifelsemarking("#1")}}
+\def\doifelsemarking#1% no \noexpanded
+ {\clf_doifelsemarking{#1}}
-% \def\doifelsemarking#1%
-% {\normalexpanded{\noexpand\ctxcommand{doifelsemarking("\noexpand\detokenize{#1}")}}}
-
-\def\doifelsemarking#1%
- {\ctxcommand{doifelsemarking(\!!bs#1\!!es)}}
+\let\doifmarkingelse \doifelsemarking
% \appendtoks
% \strc_markings_synchronize[\v!page][\normalpagebox][\v!keep]% keep if no marks
@@ -116,25 +112,25 @@
\setsystemmode\v!marking
\the\everymarking
\ifthirdargument
- \ctxcommand{getmarking("#1","#2","#3")}%
+ \clf_getmarking{#1}{#2}{#3}%
\else
- \ctxcommand{getmarking("#1","\v!page","#2")}%
+ \clf_getmarking{#1}{\v!page}{#2}%
\fi
\endgroup}}
% the fetchers are fully expandable: [name][method]
-\def\fetchonemark[#1]#2[#3]{\ifconditional\inhibitgetmarking\else\ctxcommand{fetchonemark ("#1","\v!page","#2")}\fi}
-\def\fetchtwomarks [#1]{\ifconditional\inhibitgetmarking\else\ctxcommand{fetchtwomarks("#1","\v!page")}\fi}
-\def\fetchallmarks [#1]{\ifconditional\inhibitgetmarking\else\ctxcommand{fetchallmarks("#1","\v!page")}\fi}
+\def\fetchonemark[#1]#2[#3]{\ifconditional\inhibitgetmarking\else\clf_fetchonemark {#1}{\v!page}{#2}\fi}
+\def\fetchtwomarks [#1]{\ifconditional\inhibitgetmarking\else\clf_fetchtwomarks{#1}{\v!page}\fi}
+\def\fetchallmarks [#1]{\ifconditional\inhibitgetmarking\else\clf_fetchallmarks{#1}{\v!page}\fi}
\let\fetchmark\fetchonemark
% also fully expandable but here we have: [name][range][method]
-\def\fetchonemarking[#1]#2[#3]#4[#5]{\ifconditional\inhibitgetmarking\else\ctxcommand{fetchonemark ("#1","#3","#5")}\fi}
-\def\fetchtwomarkings [#1]#2[#3]{\ifconditional\inhibitgetmarking\else\ctxcommand{fetchtwomarks("#1","#3")}\fi}
-\def\fetchallmarkings [#1]#2[#3]{\ifconditional\inhibitgetmarking\else\ctxcommand{fetchallmarks("#1","#3")}\fi}
+\def\fetchonemarking[#1]#2[#3]#4[#5]{\ifconditional\inhibitgetmarking\else\clf_fetchonemark {#1}{#3}{#5}\fi}
+\def\fetchtwomarkings [#1]#2[#3]{\ifconditional\inhibitgetmarking\else\clf_fetchtwomarks{#1}{#3}\fi}
+\def\fetchallmarkings [#1]#2[#3]{\ifconditional\inhibitgetmarking\else\clf_fetchallmarks{#1}{#3}\fi}
\let\fetchmarking\fetchonemarking
diff --git a/Master/texmf-dist/tex/context/base/strc-mat.lua b/Master/texmf-dist/tex/context/base/strc-mat.lua
index 98b1e996c3c..87f35ed1d3a 100644
--- a/Master/texmf-dist/tex/context/base/strc-mat.lua
+++ b/Master/texmf-dist/tex/context/base/strc-mat.lua
@@ -6,28 +6,35 @@ if not modules then modules = { } end modules ['strc-mat'] = {
license = "see context related readme files"
}
+----- copytable = table.copy
+
local structures = structures
-local lists = structures.lists
-local sections = structures.sections
-local floats = structures.floats
-local helpers = structures.helpers
-local formulas = structures.formulas
+local lists = structures.lists
+local sections = structures.sections
+local floats = structures.floats
+local helpers = structures.helpers
+local formulas = structures.formulas -- not used but reserved
-lists.enhancers = lists.enhancers or { }
+----- context = context
+----- simplify = helpers.simplify
-- maybe we want to do clever things with formulas, the store might go away
-local formuladata = { }
-
-function formulas.store(data)
- formuladata[#formuladata+1] = data
- context(#formuladata)
-end
-
-function formulas.current()
- return formuladata[#formuladata]
-end
+-- local formuladata = { }
+--
+-- function formulas.store(data)
+-- formuladata[#formuladata+1] = data
+-- context(#formuladata)
+-- end
+--
+-- function formulas.current()
+-- return formuladata[#formuladata]
+-- end
+
+-- function formulas.simplify(entry)
+-- return simplify(copytable(entry or formuladata[#formuladata]))
+-- end
function helpers.formulanumber(data,spec)
if data then
@@ -38,10 +45,9 @@ function helpers.formulanumber(data,spec)
end
end
-function formulas.simplify(entry)
- return helpers.simplify(table.copy(entry or formuladata[#formuladata]))
-end
-
function lists.formulanumber(name,n,spec)
- helpers.formulanumber(lists.result[n])
+ local result = lists.result
+ if result then
+ helpers.formulanumber(result[n])
+ end
end
diff --git a/Master/texmf-dist/tex/context/base/strc-mat.mkiv b/Master/texmf-dist/tex/context/base/strc-mat.mkiv
index 18cb005cbea..22fa5488910 100644
--- a/Master/texmf-dist/tex/context/base/strc-mat.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-mat.mkiv
@@ -360,7 +360,7 @@
\def\strc_formulas_handle_sub_numbering_indeed
{\let\strc_formulas_handle_sub_numbering\relax % else error: see math/numbering-001.tex
- \doiftextelse\currentsubformulasuffix
+ \doifelsetext\currentsubformulasuffix
{\strc_counters_setown_sub\v!formula\plustwo\currentsubformulasuffix}
{\strc_counters_increment_sub\v!formula\plustwo}%
\placecurrentformulanumber}
@@ -528,7 +528,7 @@
\unexpanded\def\strc_formulas_start_formula_indeed[#1][#2]% setting leftskip adaption is slow !
{\bgroup % HERE
\def\currentformula{#1}%
- \dostarttagged\t!formula\currentformula
+ \dostarttaggedchained\t!formula\currentformula\??formula
\the\everybeforedisplayformula
\d_strc_formulas_display_skip_par\parskip\relax
%\formulastrutdp\strutdepth
@@ -564,7 +564,7 @@
\unexpanded\def\strc_formulas_start_formula_nested#1%
{\bgroup
\let\strc_formulas_stop_formula\strc_formulas_stop_formula_nested
- \dostarttagged\t!subformula}
+ \dostarttagged\t!subformula\empty}
\unexpanded\def\strc_formulas_stop_formula_nested
{\dostoptagged
@@ -835,14 +835,14 @@
\def\strc_formulas_place[#1]%
{\def\currentplaceformulareference{#1}%
\let\currentplaceformulasuffix\empty
- \doifnextbgroupelse\strc_formulas_place_yes\strc_formulas_place_nop\strc_formulas_place_nop} % [ref]{}
+ \doifelsenextbgroup\strc_formulas_place_yes\strc_formulas_place_nop\strc_formulas_place_nop} % [ref]{}
\def\strc_formulas_place_yes#1%
{\def\currentplaceformulasuffix{#1}%
\strc_formulas_place_nop}
\def\strc_formulas_place_nop
- {\doifnextcharelse$\strc_formulas_place_pickup\strc_formulas_place_indeed} % [ref]$$ [ref]\start
+ {\doifelsenextchar$\strc_formulas_place_pickup\strc_formulas_place_indeed} % [ref]$$ [ref]\start
\def\strc_formulas_place_indeed
{\strc_formulas_place_numbering}
diff --git a/Master/texmf-dist/tex/context/base/strc-not.lua b/Master/texmf-dist/tex/context/base/strc-not.lua
index 40b78d59f8b..71eccf1cec2 100644
--- a/Master/texmf-dist/tex/context/base/strc-not.lua
+++ b/Master/texmf-dist/tex/context/base/strc-not.lua
@@ -38,6 +38,8 @@ local variables = interfaces.variables
local context = context
local commands = commands
+local implement = interfaces.implement
+
-- state: store, insert, postpone
local function store(tag,n)
@@ -69,9 +71,11 @@ end
notes.store = store
-function commands.storenote(tag,n)
- context(store(tag,n))
-end
+implement {
+ name = "storenote",
+ actions = { store, context },
+ arguments = { "string", "integer" }
+}
local function get(tag,n) -- tricky ... only works when defined
local nd = notedata[tag]
@@ -108,9 +112,11 @@ end
notes.listindex = listindex
-function commands.notelistindex(tag,n)
- context(listindex(tag,n))
-end
+implement {
+ name = "notelistindex",
+ actions = { listindex, context },
+ arguments = { "string", "integer" }
+}
local function setstate(tag,newkind)
local state = notestates[tag]
@@ -144,18 +150,28 @@ end
notes.setstate = setstate
notes.getstate = getstate
-commands.setnotestate = setstate
+implement {
+ name = "setnotestate",
+ actions = setstate,
+ arguments = { "string", "string" }
+}
-function commands.getnotestate(tag)
- context(getstate(tag))
-end
+implement {
+ name = "getnotestate",
+ actions = { getstate, context },
+ arguments = "string"
+}
function notes.define(tag,kind,number)
local state = setstate(tag,kind)
state.number = number
end
-commands.definenote = notes.define
+implement {
+ name = "definenote",
+ actions = notes.define,
+ arguments = { "string", "string", "integer" }
+}
function notes.save(tag,newkind)
local state = notestates[tag]
@@ -184,8 +200,8 @@ function notes.restore(tag,forcedstate)
end
end
-commands.savenote = notes.save
-commands.restorenote = notes.restore
+implement { name = "savenote", actions = notes.save, arguments = { "string", "string" } }
+implement { name = "restorenote", actions = notes.restore, arguments = { "string", "string" } }
local function hascontent(tag)
local ok = notestates[tag]
@@ -205,9 +221,11 @@ end
notes.hascontent = hascontent
-function commands.doifnotecontent(tag)
- commands.doif(hascontent(tag))
-end
+implement {
+ name = "doifnotecontent",
+ actions = { hascontent, commands.doif },
+ arguments = "string",
+}
local function internal(tag,n)
local nd = get(tag,n)
@@ -243,9 +261,11 @@ end
notes.doifonsamepageasprevious = onsamepageasprevious
-function commands.doifnoteonsamepageasprevious(tag)
- commands.doifelse(onsamepageasprevious(tag))
-end
+implement {
+ name = "doifnoteonsamepageasprevious",
+ actions = { onsamepageasprevious, commands.doifelse },
+ arguments = "string",
+}
function notes.checkpagechange(tag) -- called before increment !
local nd = notedata[tag] -- can be unset at first entry
@@ -277,7 +297,10 @@ function notes.postpone()
end
end
-commands.postponenotes = notes.postpone
+implement {
+ name = "postponenotes",
+ actions = notes.postpone
+}
function notes.setsymbolpage(tag,n,l)
local l = l or listindex(tag,n)
@@ -297,7 +320,11 @@ function notes.setsymbolpage(tag,n,l)
end
end
-commands.setnotesymbolpage = notes.setsymbolpage
+implement {
+ name = "setnotesymbolpage",
+ actions = notes.setsymbolpage,
+ arguments = { "string", "integer" }
+}
local function getsymbolpage(tag,n)
local li = internal(tag,n)
@@ -351,11 +378,11 @@ notes.getsymbolpage = getsymbolpage
notes.getnumberpage = getnumberpage
notes.getdeltapage = getdeltapage
-function commands.notesymbolpage(tag,n) context(getsymbolpage(tag,n)) end
-function commands.notenumberpage(tag,n) context(getnumberpage(tag,n)) end
-function commands.notedeltapage (tag,n) context(getdeltapage (tag,n)) end
+implement { name = "notesymbolpage", actions = { getsymbolpage, context }, arguments = { "string", "integer" } }
+implement { name = "notenumberpage", actions = { getnumberpage, context }, arguments = { "string", "integer" } }
+implement { name = "notedeltapage", actions = { getdeltapage, context }, arguments = { "string", "integer" } }
-function commands.flushnotes(tag,whatkind,how) -- store and postpone
+local function flushnotes(tag,whatkind,how) -- store and postpone
local state = notestates[tag]
local kind = state.kind
if kind == whatkind then
@@ -411,15 +438,26 @@ function commands.flushnotes(tag,whatkind,how) -- store and postpone
end
end
-function commands.flushpostponednotes()
+local function flushpostponednotes()
if trace_notes then
report_notes("flushing all postponed notes")
end
for tag, _ in next, notestates do
- commands.flushnotes(tag,"postpone")
+ flushnotes(tag,"postpone")
end
end
+implement {
+ name = "flushpostponednotes",
+ actions = flushpostponednotes
+}
+
+implement {
+ name = "flushnotes",
+ actions = flushnotes,
+ arguments = { "string", "string", "string" }
+}
+
function notes.resetpostponed()
if trace_notes then
report_notes("resetting all postponed notes")
@@ -432,13 +470,17 @@ function notes.resetpostponed()
end
end
-function commands.notetitle(tag,n)
- command.savedlisttitle(tag,notedata[tag][n])
-end
+implement {
+ name = "notetitle",
+ actions = function(tag,n) lists.savedlisttitle(tag,notedata[tag][n]) end,
+ arguments = { "string", "integer" }
+}
-function commands.noteprefixednumber(tag,n,spec)
- commands.savedlistprefixednumber(tag,notedata[tag][n])
-end
+implement {
+ name = "noteprefixednumber",
+ actions = function(tag,n) lists.savedlistprefixednumber(tag,notedata[tag][n]) end,
+ arguments = { "string", "integer" }
+}
function notes.internalid(tag,n)
local nd = get(tag,n)
diff --git a/Master/texmf-dist/tex/context/base/strc-not.mkvi b/Master/texmf-dist/tex/context/base/strc-not.mkvi
index 60ab66c980f..25a1072a3e7 100644
--- a/Master/texmf-dist/tex/context/base/strc-not.mkvi
+++ b/Master/texmf-dist/tex/context/base/strc-not.mkvi
@@ -170,7 +170,7 @@
\ifx\p_counter\empty %
\let\p_counter\currentnotation
\fi
- \doifcounterelse\p_counter\donothing{\strc_notes_define_counter\p_counter}%
+ \doifelsecounter\p_counter\donothing{\strc_notes_define_counter\p_counter}%
\letnotationparameter\s!counter\p_counter
%\strc_notes_setup_counter\currentnotation
\to \everydefinenotation
@@ -181,6 +181,7 @@
\unexpanded\setvalue{\??constructioninitializer\v!notation}%
{\let\currentnotation \currentconstruction
\let\constructionparameter \notationparameter
+ \let\constructionnamespace \??notation
\let\detokenizedconstructionparameter\detokenizednotationparameter
\let\letconstructionparameter \letnotationparameter
\let\useconstructionstyleandcolor \usenotationstyleandcolor
@@ -231,7 +232,7 @@
\ifnotesenabled
\strc_counters_increment_sub\currentconstructionnumber\currentconstructionlevel
\fi
- \doifnextoptionalcselse\strc_notations_command_yes\strc_notations_command_nop}
+ \doifelsenextoptionalcs\strc_notations_command_yes\strc_notations_command_nop}
\unexpanded\def\strc_notations_command_nop#title%
{\strc_constructions_register[\c!label={\descriptionparameter\c!text},\c!reference=,\c!title={#title},\c!bookmark=,\c!list=][]%
@@ -240,7 +241,7 @@
\normalexpanded{\endgroup\noteparameter\c!next}}
\unexpanded\def\strc_notations_command_yes[#optional]%
- {\doifassignmentelse{#optional}\strc_notations_command_assignment\strc_notations_command_argument[#optional]}
+ {\doifelseassignment{#optional}\strc_notations_command_assignment\strc_notations_command_argument[#optional]}
\unexpanded\def\strc_notations_command_assignment[#settings]%
{\strc_constructions_register[\c!label={\descriptionparameter\c!text},\c!reference=,\c!title=,\c!bookmark=,\c!list=,#settings][]%
@@ -278,7 +279,7 @@
\normalexpanded % not that efficient but also not that frequently used (\normaldef for parser)
{\def\noexpand\strc_pickup_yes[#one]#two\csname\e!stop#stoptag\endcsname{\strc_notations_command_yes[#one]{#two}}%
\def\noexpand\strc_pickup_nop #one\csname\e!stop#stoptag\endcsname{\strc_notations_command_nop {#one}}}%
- \doifnextoptionalcselse\strc_pickup_yes\strc_pickup_nop}
+ \doifelsenextoptionalcs\strc_pickup_yes\strc_pickup_nop}
\unexpanded\def\strc_notations_start_yes[#reference]#title%
{\strc_constructions_register[\c!label={\descriptionparameter\c!text},\c!reference={#reference},\c!title={#title},\c!bookmark=,\c!list=][]%
@@ -382,7 +383,7 @@
\appendtoks
\ifx\currentnoteparent\empty
- \doifinsertionelse\currentnote
+ \doifelseinsertion\currentnote
\donothing
{\defineinsertion[\currentnote]% could be an option
\normalexpanded{\t_strc_notes{\the\t_strc_notes\noexpand\strc_notes_process_list{\currentnote}}}}%
@@ -392,7 +393,7 @@
\setexpandednoteparameter\s!insert{\namednoteparameter\currentnoteparent\s!insert}%
\definenotation[\currentnote][\currentnoteparent][\c!type=\v!note]%
\fi
- \ctxcommand{definenote("\currentnote","insert",\number\currentnoteinsertionnumber)}%
+ \clf_definenote{\currentnote}{insert}\currentnoteinsertionnumber\relax
\to \everydefinenote
% maybe we will share this at some point:
@@ -437,7 +438,7 @@
\strc_notes_inject_dummy
\else
\begingroup
- \edef\currentnotenumber{\ctxcommand{storenote("\currentnote",\currentconstructionlistentry)}}%
+ \edef\currentnotenumber{\clf_storenote{\currentnote}\currentconstructionlistentry}%
\settrue\processingnote
\ifconditional\c_strc_notes_skip
\globallet\lastnotesymbol\strc_notes_inject_symbol_nop
@@ -519,7 +520,7 @@
\endcsname}
\setvalue{\??noteinteractioninline\v!yes}%
- {\strc_references_get_simple_page_reference{page(\ctxcommand{notenumberpage("\currentnote",\currentnotenumber)})}%
+ {\strc_references_get_simple_page_reference{page(\clf_notenumberpage{\currentnote}\currentnotenumber)}%
\edef\strc_notes_get_reference_attribute_symbol{attr\referenceattribute\currentreferenceattribute}%
\let \strc_notes_set_style_color_inline \strc_notes_set_style_color_inline_yes}
@@ -539,7 +540,7 @@
% page(...) : we could have a dedicated one
\setvalue{\??noteinteractiondisplay\v!yes}%
- {\strc_references_get_simple_page_reference{page(\ctxcommand{notesymbolpage("\currentnote",\currentnotenumber)})}%
+ {\strc_references_get_simple_page_reference{page(\clf_notesymbolpage{\currentnote}\currentnotenumber)}%
\edef\strc_notes_set_reference_attribute_number{\attribute\referenceattribute\currentreferenceattribute}%
\let \strc_notes_set_reference_attribute_text \donothing
\let \strc_notes_set_destination_attribute_text\donothing
@@ -552,7 +553,7 @@
\let\strc_notes_set_style_color_display \strc_notes_set_style_color_display_nop}
\setvalue{\??noteinteractiondisplay\v!all}%
- {\strc_references_get_simple_page_reference{page(\ctxcommand{notesymbolpage("\currentnote",\currentnotenumber)})}%
+ {\strc_references_get_simple_page_reference{page(\clf_notesymbolpage{\currentnote}\currentnotenumber)}%
\edef\strc_notes_set_reference_attribute_text {\attribute\referenceattribute\currentreferenceattribute}%
%\strc_references_set_simple_page_reference{note:\cldcontext{structures.notes.internalid("\currentnote",\currentnotenumber)}}%
\strc_references_set_simple_page_reference{note:\currentnote:\currentnotenumber}%
@@ -561,7 +562,7 @@
\let \strc_notes_set_style_color_display \strc_notes_set_style_color_display_yes}
\setvalue{\??noteinteractiondisplay\v!text}%
- {\strc_references_get_simple_page_reference{page(\ctxcommand{notesymbolpage("\currentnote",\currentnotenumber)})}%
+ {\strc_references_get_simple_page_reference{page(\clf_notesymbolpage{\currentnote}\currentnotenumber)}%
\edef\strc_notes_set_reference_attribute_text {\attribute\referenceattribute\currentreferenceattribute}%
%\strc_references_set_simple_page_reference{note:\cldcontext{structures.notes.internalid("\currentnote",\currentnotenumber)}}%
\strc_references_set_simple_page_reference{note:\currentnote:\currentnotenumber}%
@@ -586,7 +587,7 @@
{\iftrialtypesetting
% keep
\else\ifx\currentcolorparameter\empty
- \scratchcounter\ctxcommand{notedeltapage("\currentnote",\currentnotenumber)}\relax % todo calculate once
+ \scratchcounter\clf_notedeltapage{\currentnote}\currentnotenumber\relax % todo calculate once
\setlocationcolorspecified\scratchcounter
\fi\fi}
@@ -605,7 +606,7 @@
% in mkii the pointer only showed up in pagewise notes
\unexpanded\def\strc_notes_inject_pointer % todo calculate once
- {\ifcase\ctxcommand{notedeltapage("\currentnote",\currentnotenumber)}\relax
+ {\ifcase\clf_notedeltapage{\currentnote}\currentnotenumber\relax\relax
% unknown
\or
% same page
@@ -638,7 +639,7 @@
\unexpanded\def\strc_notes_inject_symbol_indeed#synchronize%
{\removeunwantedspaces
- \doifitalicelse\/\donothing % Charles IV \footnote{the fourth}
+ \doifelseitalic\/\donothing % Charles IV \footnote{the fourth}
\ifdim\lastkern=\notesignal
% \kern\noteparameter\c!distance % yes or no note font? or main text
\strc_notes_inject_separator
@@ -654,18 +655,18 @@
\hbox \strc_notes_get_reference_attribute_symbol \bgroup
\dostarttagged\t!descriptionsymbol\currentnote
\dotagsetnotesymbol
- \noteparameter\c!textcommand{\ctxcommand{noteprefixednumber("\currentnote",\currentnotenumber)}}%
+ \noteparameter\c!textcommand{\clf_noteprefixednumber{\currentnote}\currentnotenumber\relax}%
% the next one can cycle so we need to make sure it has no advance width
\doif{\noteparameter\c!indicator}\v!yes\strc_notes_inject_pointer
\dostoptagged
\egroup
\endgroup
- \dostoptagged % check
+% \dostoptagged % check
\globallet\lastnotesymbol\relax}
\unexpanded\def\strc_notes_inject_dummy % temp hack
{\removeunwantedspaces
- \doifitalicelse\/\donothing % Charles IV \footnote{the fourth}
+ \doifelseitalic\/\donothing % Charles IV \footnote{the fourth}
\ifdim\lastkern=\notesignal
% \kern\noteparameter\c!distance % yes or no note font? or main text
\strc_notes_inject_separator
@@ -1029,7 +1030,7 @@
\def\strc_notes_set_location_text % we don't use inserts anyway (e.g. endnotes)
{\settrue\c_strc_notes_delayed
- \ctxcommand{setnotestate("\currentnote","store")}%
+ \clf_setnotestate{\currentnote}{store}%
\page_inserts_set_location\currentnoteinsertion\v!text % \setupinsertion[\currentnote][\c!location=\v!text]%
\global\count\currentnoteinsertionnumber\zerocount
\global\dimen\currentnoteinsertionnumber\maxdimen
@@ -1181,6 +1182,7 @@
\insert\currentnoteinsertionnumber\bgroup
\the\everyinsidenoteinsert\relax
\usesetupsparameter\noteparameter % experimental
+ \useinterlinespaceparameter\noteparameter
\doifelse{\noteparameter\c!paragraph}\v!yes
{\nointerlineskip
\startvboxtohboxseparator
@@ -1203,7 +1205,7 @@
\edef\currentnote{#tag}%
\strc_constructions_initialize{#tag}%
\strc_notes_synchronize
- \edef\currentconstructionlistentry{\ctxcommand{notelistindex("\currentnote",#id)}}% index in list cache
+ \edef\currentconstructionlistentry{\clf_notelistindex{\currentnote}#id}% index in list cache
% as we can have collected notes (e.g. in tables) we need to recover
% \currentdescriptionattribute and \currentdescriptionsynchronize
%
@@ -1217,14 +1219,14 @@
\begstrut
\strc_references_flush_destination_nodes
\strc_notes_set_destination_attribute_text
- \strc_notes_inject_text
- \endstrut
+ \strc_notes_inject_text\relax
+ \ifvmode\obeydepth\else\endstrut\fi % \obeydepth is new per 2015-01-10
\strc_constructions_stored_stop
% \endgroup
}
\unexpanded\def\strc_notes_inject_text % hm main?
- {\ctxcommand{savedlisttitle("\currentconstructionmain",\currentconstructionlistentry)}}
+ {\clf_savedlisttitle{\currentconstructionmain}\currentconstructionlistentry\relax}
\let\startpushnote\relax
\let\stoppushnote \relax
@@ -1297,7 +1299,7 @@
\noteparameter\c!before
\fi
% \bgroup
- % \setupalign[\noteparameter\c!align]%
+ % \usealignparameter\noteparameter
\placenoterule % alleen in ..mode
% \par
% \egroup
@@ -1353,11 +1355,14 @@
% idea: tag with attr and then just flush them again
\def\strc_notes_flush_global
- {\doifelse{\noteparameter\c!paragraph}\v!yes
+ {\begingroup
+ \useinterlinespaceparameter\noteparameter
+ \doifelse{\noteparameter\c!paragraph}\v!yes
{\vbox\starthboxestohbox
\iftrialtypesetting\unvcopy\else\unvbox\fi\currentnoteinsertionnumber
\stophboxestohbox}
- {\iftrialtypesetting\unvcopied\else\unvboxed\fi\currentnoteinsertionnumber}}
+ {\iftrialtypesetting\unvcopied\else\unvboxed\fi\currentnoteinsertionnumber}%
+ \endgroup}
%D Supporting end notes is surprisingly easy. Even better, we
%D can combine this feature with solving the common \TEX\
@@ -1395,7 +1400,7 @@
{\ifconditional\postponingnotes\else
\global\settrue\postponingnotes
\global\let\flushnotes\doflushnotes
- \ctxcommand{postponenotes()}%
+ \clf_postponenotes
\fi}
\let\flushnotes\relax
@@ -1405,7 +1410,7 @@
\begingroup
\let\flushnotes \relax
\let\postponenotes\relax
- \ctxcommand{flushpostponednotes()}% this also resets the states !
+ \clf_flushpostponednotes% this also resets the states !
\global\setfalse\postponednote
\global\setfalse\postponingnotes
\global\let\flushnotes\relax
@@ -1452,20 +1457,20 @@
\strc_counters_save{#tag}%
\strc_counters_reset{#tag}%
\fi
- \ctxcommand{savenote("#tag","store")}}
+ \clf_savenote{#tag}{store}}
\def\strc_notes_local_stop_step#tag%
{\p_strc_notes_continue{\noteparameter\c!continue}%
\ifx\p_strc_notes_continue\v!yes \else
\strc_counters_restore{#tag}%
\fi
- \ctxcommand{restorenote("#tag")}}
+ \clf_restorenote{#tag}}
\unexpanded\def\placelocalnotes
{\dodoubleempty\strc_notes_local_place}
\def\strc_notes_local_place[#tag][#settings]%
- {\doif{\ctxcommand{getnotestate("#tag")}}{store}{\strc_notes_local_place_indeed{#settings}{#tag}}}
+ {\doif{\clf_getnotestate{#tag}}{store}{\strc_notes_local_place_indeed{#settings}{#tag}}}
\def\strc_notes_local_place_indeed#settings#tag%
{\begingroup
@@ -1525,7 +1530,7 @@
\def\strc_notes_place_indeed#settings#tag% settings note
{\edef\currentnote{#tag}% grouping ?
- \doifelse{\ctxcommand{getnotestate("#tag")}}{store}
+ \doifelse{\clf_getnotestate{#tag}}{store}
\strc_notes_local_place_indeed
\strc_notes_global_place_indeed
{#settings}{#tag}}
@@ -1545,7 +1550,7 @@
{\setvalue{\??notealternative#alternative}{#command}}
\unexpanded\def\doifnotescollected#tag%
- {\ctxcommand{doifnotecontent("#tag")}}
+ {\clf_doifnotecontent{#tag}}
\def\strc_notes_place_local_alternative % will be a setup (wrapper)
{\doifnotescollected\currentnote
@@ -1572,7 +1577,7 @@
% setups ?
-\def\flushlocalnotes#tag{\ctxcommand{flushnotes("#tag","store","\noteparameter\c!criterium")}}
+\def\flushlocalnotes#tag{\clf_flushnotes{#tag}{store}{\noteparameter\c!criterium}}
\installnotealternative \v!none
{\flushlocalnotes\currentnote}
@@ -1597,7 +1602,7 @@
\setupcurrentnote[\c!location=]%
\inheritednoteframed
{\edef\currentnotewidth{\noteparameter\c!width}%
- \doifdimensionelse\currentnotewidth\donothing
+ \doifelsedimension\currentnotewidth\donothing
{\edef\currentnotewidth{\the\hsize}}%
\startsimplecolumns[\c!distance=\noteparameter\c!columndistance,\c!n=\noteparameter\c!n,\c!width=\currentnotewidth]%
\flushlocalnotes\currentnote
@@ -1722,8 +1727,8 @@
\def\strc_notes_set_bodyfont
{\let\strc_notes_set_bodyfont\relax
\restoreglobalbodyfont
- \switchtobodyfont[\noteparameter\c!bodyfont]%
- \setupalign[\noteparameter\c!align]}
+ \usebodyfontparameter\noteparameter
+ \usealignparameter\noteparameter}
%D The footnote mechanism defaults to a traditional one
%D column way of showing them. By default we precede them by
@@ -1764,7 +1769,9 @@
%D }
%D \stoptyping
-\def\doifnoteonsamepageelse[#tag]{\ctxcommand{doifnoteonsamepageasprevious("#tag")}}
+\def\doifelsenoteonsamepage[#tag]{\clf_doifnoteonsamepageasprevious{#tag}}
+
+\let\doifnoteonsamepageelse\doifelsenoteonsamepage
%D New trickery:
@@ -1829,4 +1836,24 @@
% [ownnote]
% [\ownnotesymbol]
+% tricky:
+%
+% \enabletrackers[nodes.areas]
+% \enabletrackers[nodes.references]
+% \enabletrackers[nodes.destinations]
+%
+% \setupnotes[interaction=all,rule=no]
+% \setupinteraction[state=start,focus=standard]
+%
+% \starttext
+% \goto{\input tufte\relax}[page(2)] \par
+% \ruledhbox{\gotobox{\vtop{\input tufte\relax}}[page(2)]} \par
+% \ruledhbox{\gotobox{\vbox{\input tufte\relax}}[page(2)]} \par
+% % \completecontent
+% % \chapter{Chapter}
+% % \dorecurse{5}{\input knuth}
+% a\footnote{\input tufte\par\input ward\relax}
+% \stoptext
+
\protect \endinput
+
diff --git a/Master/texmf-dist/tex/context/base/strc-num.lua b/Master/texmf-dist/tex/context/base/strc-num.lua
index e1fc6003071..0203334fff6 100644
--- a/Master/texmf-dist/tex/context/base/strc-num.lua
+++ b/Master/texmf-dist/tex/context/base/strc-num.lua
@@ -20,6 +20,8 @@ local setmetatableindex = table.setmetatableindex
local trace_counters = false trackers.register("structures.counters", function(v) trace_counters = v end)
local report_counters = logs.reporter("structure","counters")
+local implement = interfaces.implement
+
local structures = structures
local helpers = structures.helpers
local sections = structures.sections
@@ -199,6 +201,24 @@ local function allocate(name,i) -- can be metatable
return ci
end
+local pattern = lpeg.P(variables.by)^-1 * lpeg.C(lpeg.P(1)^1)
+local lpegmatch = lpeg.match
+
+function counters.way(way)
+ if not way or way == "" then
+ return ""
+ else
+ return lpegmatch(pattern,way)
+ end
+end
+
+implement {
+ name = "way",
+ actions = { counters.way, context },
+ arguments = "string"
+}
+
+
function counters.record(name,i)
return allocate(name,i or 1)
end
@@ -376,10 +396,8 @@ local function check(name,data,start,stop)
end
end
-counters.reset = reset
-counters.set = set
-function counters.setown(name,n,value)
+local function setown(name,n,value)
local cd = counterdata[name]
if cd then
local d = allocate(name,n)
@@ -397,7 +415,7 @@ function counters.setown(name,n,value)
end
end
-function counters.restart(name,n,newstart,noreset)
+local function restart(name,n,newstart,noreset)
local cd = counterdata[name]
if cd then
newstart = tonumber(newstart)
@@ -425,7 +443,7 @@ function counters.restore(name)
end
end
-function counters.add(name,n,delta)
+local function add(name,n,delta)
local cd = counterdata[name]
if cd and (cd.state == v_start or cd.state == "") then
local data = cd.data
@@ -494,7 +512,12 @@ local function get(name,n,key)
end
end
-counters.get = get
+counters.reset = reset
+counters.set = set
+counters.add = add
+counters.get = get
+counters.setown = setown
+counters.restart = restart
function counters.value(name,n) -- what to do with own
return get(name,n or 1,'number') or 0
@@ -553,24 +576,7 @@ end
-- interfacing
-commands.definecounter = counters.define
-commands.setcounter = counters.set
-commands.setowncounter = counters.setown
-commands.resetcounter = counters.reset
-commands.restartcounter = counters.restart
-commands.savecounter = counters.save
-commands.restorecounter = counters.restore
-commands.addcounter = counters.add
-
-commands.rawcountervalue = function(...) context(counters.raw (...)) end
-commands.countervalue = function(...) context(counters.value (...)) end
-commands.lastcountervalue = function(...) context(counters.last (...)) end
-commands.firstcountervalue = function(...) context(counters.first (...)) end
-commands.nextcountervalue = function(...) context(counters.next (...)) end
-commands.prevcountervalue = function(...) context(counters.previous(...)) end
-commands.subcountervalues = function(...) context(counters.subs (...)) end
-
-function commands.showcounter(name)
+local function showcounter(name)
local cd = counterdata[name]
if cd then
context("[%s:",name)
@@ -583,17 +589,11 @@ function commands.showcounter(name)
end
end
-function commands.doifelsecounter(name) commands.doifelse(counterdata[name]) end
-function commands.doifcounter (name) commands.doif (counterdata[name]) end
-function commands.doifnotcounter (name) commands.doifnot (counterdata[name]) end
-
-function commands.incrementedcounter(...) context(counters.add(...)) end
-
-- the noreset is somewhat messy ... always false messes up e.g. itemize but true the pagenumbers
--
-- if this fails i'll clean up this still somewhat experimental mechanism (but i need use cases)
-function commands.checkcountersetup(name,level,start,state)
+local function checkcountersetup(name,level,start,state)
local noreset = true -- level > 0 -- was true
counters.restart(name,1,start,noreset) -- was true
counters.setstate(name,state)
@@ -601,6 +601,70 @@ function commands.checkcountersetup(name,level,start,state)
sections.setchecker(name,level,counters.reset)
end
+--
+
+implement { name = "addcounter", actions = add, arguments = { "string", "integer", "integer" } }
+implement { name = "setcounter", actions = set, arguments = { "string", 1, "integer" } }
+implement { name = "setowncounter", actions = setown, arguments = { "string", 1, "string" } }
+implement { name = "restartcounter", actions = restart, arguments = { "string", 1, "integer" } }
+implement { name = "resetcounter", actions = reset, arguments = { "string", 1 } }
+implement { name = "incrementcounter", actions = add, arguments = { "string", 1, 1 } }
+implement { name = "decrementcounter", actions = add, arguments = { "string", 1, -1 } }
+
+implement { name = "setsubcounter", actions = set, arguments = { "string", "integer", "integer" } }
+implement { name = "setownsubcounter", actions = setown, arguments = { "string", "integer", "string" } }
+implement { name = "restartsubcounter", actions = restart, arguments = { "string", "integer", "integer" } }
+implement { name = "resetsubcounter", actions = reset, arguments = { "string", "integer" } }
+implement { name = "incrementsubcounter", actions = add, arguments = { "string", "integer", 1 } }
+implement { name = "decrementsubcounter", actions = add, arguments = { "string", "integer", -1 } }
+
+implement { name = "rawcountervalue", actions = { counters.raw , context }, arguments = { "string", 1 } }
+implement { name = "countervalue", actions = { counters.value , context }, arguments = { "string", 1 } }
+implement { name = "lastcountervalue", actions = { counters.last , context }, arguments = { "string", 1 } }
+implement { name = "firstcountervalue", actions = { counters.first , context }, arguments = { "string", 1 } }
+implement { name = "nextcountervalue", actions = { counters.next , context }, arguments = { "string", 1 } }
+implement { name = "prevcountervalue", actions = { counters.previous, context }, arguments = { "string", 1 } }
+implement { name = "subcountervalues", actions = { counters.subs , context }, arguments = { "string", 1 } }
+
+implement { name = "rawsubcountervalue", actions = { counters.raw , context }, arguments = { "string", "integer" } }
+implement { name = "subcountervalue", actions = { counters.value , context }, arguments = { "string", "integer" } }
+implement { name = "lastsubcountervalue", actions = { counters.last , context }, arguments = { "string", "integer" } }
+implement { name = "firstsubcountervalue", actions = { counters.first , context }, arguments = { "string", "integer" } }
+implement { name = "nextsubcountervalue", actions = { counters.next , context }, arguments = { "string", "integer" } }
+implement { name = "previoussubcountervalue", actions = { counters.previous, context }, arguments = { "string", "integer" } }
+implement { name = "subsubcountervalues", actions = { counters.subs , context }, arguments = { "string", "integer" } }
+
+implement { name = "savecounter", actions = counters.save, arguments = "string" }
+implement { name = "restorecounter", actions = counters.restore, arguments = "string" }
+
+implement { name = "incrementedcounter", actions = { add, context }, arguments = { "string", 1, 1 } }
+implement { name = "decrementedcounter", actions = { add, context }, arguments = { "string", 1, -1 } }
+
+implement { name = "showcounter", actions = showcounter, arguments = "string" } -- todo
+implement { name = "checkcountersetup", actions = checkcountersetup, arguments = { "string", "integer", "integer", "string" } }
+
+table.setmetatablecall(counterdata,function(t,k) return t[k] end)
+
+implement { name = "doifelsecounter", actions = { counterdata, commands.doifelse }, arguments = "string" }
+implement { name = "doifcounter", actions = { counterdata, commands.doif }, arguments = "string" }
+implement { name = "doifnotcounter", actions = { counterdata, commands.doifnot }, arguments = "string" }
+
+implement {
+ name = "definecounter",
+ actions = counters.define,
+ arguments = {
+ {
+ { "name" } ,
+ { "start", "integer" },
+ { "counter" },
+ { "method" },
+ }
+ }
+}
+
+------------------------------------------------------------------
+------------------------------------------------------------------
+
-- -- move to strc-pag.lua
--
-- function counters.analyze(name,counterspecification)
diff --git a/Master/texmf-dist/tex/context/base/strc-num.mkiv b/Master/texmf-dist/tex/context/base/strc-num.mkiv
index 6802027e67b..58095b8e7d9 100644
--- a/Master/texmf-dist/tex/context/base/strc-num.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-num.mkiv
@@ -27,7 +27,9 @@
\installcommandhandler \??counter {counter} \??counter
-\let\setupstructurecounting\setupcounter
+\let\setupcounters\setupcounter
+
+\let\setupstructurecounting\setupcounter % will disappear
\setupcounter
[\c!way=\v!by\v!chapter,
@@ -41,7 +43,7 @@
\c!state=\v!start]
\def\autostructureprefixsegments#1% todo: \c!prefixsegments=\v!auto
- {2:\thenamedheadlevel{\ctxcommand{way("#1\c!way")}}}
+ {2:\thenamedheadlevel{\clf_way{#1\c!way}}}
\appendtoks
\resetcounterparameter\s!counter
@@ -50,15 +52,16 @@
\appendtoks
\ifx\currentcounterparent\empty
\edef\p_start{\counterparameter\c!start}%
- \ctxcommand{definecounter {
- name = "\currentcounter",
- start = \ifx\p_start\empty0\else\number\p_start\fi,
- counter = "\counterparameter\s!counter",
- method = "\counterparameter\c!method",
- }}%
+ \clf_definecounter
+ name {\currentcounter}%
+ start \ifx\p_start\empty\zerocount\else\numexpr\p_start\relax\fi
+ counter {\counterparameter\s!counter}%
+ method {\counterparameter\c!method}%
+ \relax
\letcounterparameter\s!name\currentcounter
\else
- \letcounterparameter\s!name\currentcounterparent
+ % \letcounterparameter\s!name\currentcounterparent % we need a chained clone
+ \setexpandedcounterparameter\s!name{\namedcounterparameter\currentcounterparent\s!name}%
\fi
\strc_counters_check_setup
\to \everydefinecounter
@@ -67,7 +70,7 @@
\ifx\currentcounter\empty \else
\edef\p_number{\counterparameter\c!number}%
\ifx\p_number\empty \else
- \ctxcommand{setcounter("\counterparameter\s!name",1,\number\p_number)}%
+ \clf_setcounter{\counterparameter\s!name}\numexpr\p_number\relax
\letcounterparameter\c!number\empty
\fi
\edef\p_start{\counterparameter\c!start}%
@@ -78,40 +81,28 @@
% % % %
-\def\strc_counters_way#1% slow, we need to store it at the tex end
- {\ctxcommand{way("\namedcounterparameter{#1}\c!way")}}
-
-% \def\thenamedcounterlevel#1%
-% {\thenamedheadlevel{\strc_counters_way{#1}}}
+\def\strc_counters_way#1{\clf_way{\namedcounterparameter{#1}\c!way}}
\def\thenamedcounterlevel#1%
- {\xthenamedheadlevel{\strc_counters_way{#1}}}
-
-% \def\strc_counters_check_setup#1% does it have to happen here?
-% {% this can be done at the lua end / a bit messy here ... todo ...
-% \ifcsname\??counter#1\c!number\endcsname
-% \doifelsevalue {\??counter#1\c!number}{#1} {\letbeundefined{\??counter#1\c!number}}%
-% {\doifvaluenothing{\??counter#1\c!number} {\letbeundefined{\??counter#1\c!number}}}%
-% \fi
-% \ifcsname\??counter#1\c!number\endcsname
-% % it's a clone
-% \else
-% \edef\currentcounterlevel{\thenamedcounterlevel{#1}}%
-% \edef\p_start{\counterparameter{#1}\c!start}%
-% \ctxcommand{checkcountersetup("#1",\currentcounterlevel,\ifx\p_start\empty0\else\number\p_start\fi,"\counterparameter{#1}\c!state")}%
-% \fi}
+ {\xthenamedheadlevel{\clf_way{\namedcounterparameter{#1}\c!way}}}
-\def\strc_counters_check_setup
+\unexpanded\def\strc_counters_check_setup
{\edef\p_name{\directcounterparameter\s!name}%
\ifx\currentcounter\p_name
\edef\currentcounterlevel{\thenamedcounterlevel\currentcounter}%
\edef\p_start{\counterparameter\c!start}%
- \ctxcommand{checkcountersetup("\currentcounter",\currentcounterlevel,\ifx\p_start\empty0\else\number\p_start\fi,"\counterparameter\c!state")}%
+ \clf_checkcountersetup
+ {\currentcounter}%
+ \numexpr\currentcounterlevel\relax
+ \numexpr\ifx\p_start\empty\zerocount\else\p_start\fi\relax % bug in scanner
+ {\counterparameter\c!state}%
\fi}
-\unexpanded\def\doifcounterelse #1{\ctxcommand{doifelsecounter("\namedcounterparameter{#1}\s!name")}}
-\unexpanded\def\doifcounter #1{\ctxcommand{doifcounter ("\namedcounterparameter{#1}\s!name")}}
-\unexpanded\def\doifnotcounter #1{\ctxcommand{doifnotcounter ("\namedcounterparameter{#1}\s!name")}}
+\unexpanded\def\doifelsecounter #1{\clf_doifelsecounter{\namedcounterparameter{#1}\s!name}}
+\unexpanded\def\doifcounter #1{\clf_doifcounter {\namedcounterparameter{#1}\s!name}}
+\unexpanded\def\doifnotcounter #1{\clf_doifnotcounter {\namedcounterparameter{#1}\s!name}}
+
+\let\doifcounterelse\doifelsecounter
\unexpanded\def\setcounter {\dotripleempty \strc_counters_set_interfaced}
\unexpanded\def\setcounterown {\dotripleempty \strc_counters_setown_interfaced}
@@ -252,90 +243,90 @@
\expandafter\gobbleoneoptional
\fi}
-\def\strc_counters_set_two [#1][#2][#3]{\strc_counters_set_sub {#1}{#2}{#3}}
-\def\strc_counters_setown_two [#1][#2][#3]{\strc_counters_setown_sub {#1}{#2}{#3}}
-\def\strc_counters_restart_two [#1][#2][#3]{\strc_counters_restart_sub {#1}{#2}{#3}}
-\def\strc_counters_reset_two [#1][#2]{\strc_counters_reset_sub {#1}{#2}}
-\def\strc_counters_increment_two [#1][#2]{\strc_counters_increment_sub{#1}{#2}}
-\def\strc_counters_decrement_two [#1][#2]{\strc_counters_decrement_sub{#1}{#2}}
-
-\def\strc_counters_raw_two [#1][#2]{\strc_counters_raw_sub {#1}{#2}}
-\def\strc_counters_last_two [#1][#2]{\strc_counters_last_sub {#1}{#2}}
-\def\strc_counters_first_two [#1][#2]{\strc_counters_first_sub {#1}{#2}}
-\def\strc_counters_next_two [#1][#2]{\strc_counters_next_sub {#1}{#2}}
-\def\strc_counters_prev_two [#1][#2]{\strc_counters_prev_sub {#1}{#2}}
-\def\strc_counters_subs_two [#1][#2]{\strc_counters_subs_sub {#1}{#2}}
-
-\def\strc_counters_set_one [#1][#2][#3]{\strc_counters_set_sub {#1}\plusone{#2}}
-\def\strc_counters_setown_one [#1][#2][#3]{\strc_counters_setown_sub {#1}\plusone{#2}}
-\def\strc_counters_restart_one [#1][#2][#3]{\strc_counters_restart_sub {#1}\plusone{#2}}
-\def\strc_counters_reset_one [#1][#2]{\strc_counters_reset_sub {#1}\plusone}
-\def\strc_counters_increment_one [#1][#2]{\strc_counters_increment_sub{#1}\plusone}
-\def\strc_counters_decrement_one [#1][#2]{\strc_counters_decrement_sub{#1}\plusone}
-
-\def\strc_counters_raw_one [#1][#2]{\strc_counters_raw_sub {#1}\plusone}
-\def\strc_counters_last_one [#1][#2]{\strc_counters_last_sub {#1}\plusone}
-\def\strc_counters_first_one [#1][#2]{\strc_counters_first_sub {#1}\plusone}
-\def\strc_counters_next_one [#1][#2]{\strc_counters_next_sub {#1}\plusone}
-\def\strc_counters_prev_one [#1][#2]{\strc_counters_prev_sub {#1}\plusone}
-\def\strc_counters_subs_one [#1][#2]{\strc_counters_subs_sub {#1}\plusone}
-
-\def\strc_counters_save_one [#1]{\strc_counters_save {#1}}
-\def\strc_counters_restore_one [#1]{\strc_counters_restore {#1}}
-
-\unexpanded\def\strc_counters_set #1#2{\strc_counters_set_sub {#1}\plusone{#2}}
-\unexpanded\def\strc_counters_setown #1#2{\strc_counters_setown_sub {#1}\plusone{#2}}
-\unexpanded\def\strc_counters_restart #1#2{\strc_counters_restart_sub {#1}\plusone{#2}}
-\unexpanded\def\strc_counters_reset #1{\strc_counters_reset_sub {#1}\plusone}
-\unexpanded\def\strc_counters_increment #1{\strc_counters_increment_sub{#1}\plusone}
-\unexpanded\def\strc_counters_decrement #1{\strc_counters_decrement_sub{#1}\plusone}
-
- \def\strc_counters_raw #1{\strc_counters_raw_sub {#1}\plusone}
- \def\strc_counters_last #1{\strc_counters_last_sub {#1}\plusone}
- \def\strc_counters_first #1{\strc_counters_first_sub {#1}\plusone}
- \def\strc_counters_next #1{\strc_counters_next_sub {#1}\plusone}
- \def\strc_counters_prev #1{\strc_counters_prev_sub {#1}\plusone}
- \def\strc_counters_subs #1{\strc_counters_subs_sub {#1}\plusone}
-
-\unexpanded\def\strc_counters_set_sub #1#2#3{\ctxcommand{setcounter ("\namedcounterparameter{#1}\s!name",\number#2,\number#3)}}
-\unexpanded\def\strc_counters_setown_sub #1#2#3{\ctxcommand{setowncounter ("\namedcounterparameter{#1}\s!name",\number#2,"#3")}}
-\unexpanded\def\strc_counters_restart_sub #1#2#3{\ctxcommand{restartcounter("\namedcounterparameter{#1}\s!name",\number#2,\number#3)}}
-\unexpanded\def\strc_counters_reset_sub #1#2{\ctxcommand{resetcounter ("\namedcounterparameter{#1}\s!name",\number#2)}}
-\unexpanded\def\strc_counters_increment_sub #1#2{\ctxcommand{addcounter ("\namedcounterparameter{#1}\s!name",\number#2,1)}}
-\unexpanded\def\strc_counters_decrement_sub #1#2{\ctxcommand{addcounter ("\namedcounterparameter{#1}\s!name",\number#2,-1)}}
-
- \def\strc_counters_raw_sub #1#2{\ctxcommand{countervalue ("\namedcounterparameter{#1}\s!name",\number#2)}} % maybe raw
- \def\strc_counters_last_sub #1#2{\ctxcommand{lastcountervalue ("\namedcounterparameter{#1}\s!name",\number#2)}}
- \def\strc_counters_first_sub #1#2{\ctxcommand{firstcountervalue ("\namedcounterparameter{#1}\s!name",\number#2)}}
- \def\strc_counters_next_sub #1#2{\ctxcommand{nextcountervalue ("\namedcounterparameter{#1}\s!name",\number#2)}}
- \def\strc_counters_prev_sub #1#2{\ctxcommand{previouscountervalue("\namedcounterparameter{#1}\s!name",\number#2)}}
- \def\strc_counters_subs_sub #1#2{\ctxcommand{subcountervalues ("\namedcounterparameter{#1}\s!name",\number#2)}}
-
-\unexpanded\def\strc_counters_save #1{\ctxcommand{savecounter ("\namedcounterparameter{#1}\s!name")}}
-\unexpanded\def\strc_counters_restore #1{\ctxcommand{restorecounter("\namedcounterparameter{#1}\s!name")}}
-
-\unexpanded\def\strc_counters_incremented #1{\ctxcommand{incrementedcounter("\namedcounterparameter{#1}\s!name",1, 1)}}
-\unexpanded\def\strc_counters_decremented #1{\ctxcommand{incrementedcounter("\namedcounterparameter{#1}\s!name",1,-1)}}
-
-\unexpanded\def\showcounter [#1]{\ctxcommand{tracecounter("\namedcounterparameter{#1}\s!name")}}
-
-\unexpanded\def\incrementedcounter [#1]{\strc_counters_incremented{#1}} % expandable, no \dosingleargument
-\unexpanded\def\decrementedcounter [#1]{\strc_counters_decremented{#1}} % expandable, no \dosingleargument
+\def\strc_counters_set_two [#1][#2][#3]{\clf_setsubcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax\numexpr#3\relax}
+\def\strc_counters_setown_two [#1][#2][#3]{\clf_setownsubcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax{#3}}
+\def\strc_counters_restart_two [#1][#2][#3]{\clf_restartsubcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax\numexpr#3\relax}
+\def\strc_counters_reset_two [#1][#2]{\clf_resetsubcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+\def\strc_counters_increment_two [#1][#2]{\clf_incrementsubcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+\def\strc_counters_decrement_two [#1][#2]{\clf_decrementsubcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+
+\def\strc_counters_raw_two [#1][#2]{\clf_subcountervalue {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+\def\strc_counters_last_two [#1][#2]{\clf_lastsubcountervalue {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+\def\strc_counters_first_two [#1][#2]{\clf_firstsubcountervalue {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+\def\strc_counters_next_two [#1][#2]{\clf_nextsubcountervalue {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+\def\strc_counters_prev_two [#1][#2]{\clf_previoussubcountervalue{\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+\def\strc_counters_subs_two [#1][#2]{\clf_subsubcountervalues {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+
+\def\strc_counters_set_one [#1][#2][#3]{\clf_setcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+\def\strc_counters_setown_one [#1][#2][#3]{\clf_setowncounter {\namedcounterparameter{#1}\s!name}{#2}}
+\def\strc_counters_restart_one [#1][#2][#3]{\clf_restartcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+\def\strc_counters_reset_one [#1][#2]{\clf_resetcounter {\namedcounterparameter{#1}\s!name}}
+\def\strc_counters_increment_one [#1][#2]{\clf_incrementcounter {\namedcounterparameter{#1}\s!name}}
+\def\strc_counters_decrement_one [#1][#2]{\clf_decrementcounter {\namedcounterparameter{#1}\s!name}}
+
+\def\strc_counters_raw_one [#1][#2]{\clf_countervalue {\namedcounterparameter{#1}\s!name}}
+\def\strc_counters_last_one [#1][#2]{\clf_lastcountervalue {\namedcounterparameter{#1}\s!name}}
+\def\strc_counters_first_one [#1][#2]{\clf_firstcountervalue {\namedcounterparameter{#1}\s!name}}
+\def\strc_counters_next_one [#1][#2]{\clf_nextcountervalue {\namedcounterparameter{#1}\s!name}}
+\def\strc_counters_prev_one [#1][#2]{\clf_previouscountervalue {\namedcounterparameter{#1}\s!name}}
+\def\strc_counters_subs_one [#1][#2]{\clf_subcountervalues {\namedcounterparameter{#1}\s!name}}
+
+\def\strc_counters_save_one [#1]{\clf_savecounter {\namedcounterparameter{#1}\s!name}}
+\def\strc_counters_restore_one [#1]{\clf_restorecounter {\namedcounterparameter{#1}\s!name}}
+
+\unexpanded\def\strc_counters_set #1#2{\clf_setcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+\unexpanded\def\strc_counters_setown #1#2{\clf_setowncounter {\namedcounterparameter{#1}\s!name}{#2}}
+\unexpanded\def\strc_counters_restart #1#2{\clf_restartcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+\unexpanded\def\strc_counters_reset #1{\clf_resetcounter {\namedcounterparameter{#1}\s!name}}
+\unexpanded\def\strc_counters_increment #1{\clf_incrementcounter {\namedcounterparameter{#1}\s!name}}
+\unexpanded\def\strc_counters_decrement #1{\clf_decrementcounter {\namedcounterparameter{#1}\s!name}}
+
+ \def\strc_counters_raw #1{\clf_countervalue {\namedcounterparameter{#1}\s!name}}
+ \def\strc_counters_last #1{\clf_lastcountervalue {\namedcounterparameter{#1}\s!name}}
+ \def\strc_counters_first #1{\clf_firstcountervalue {\namedcounterparameter{#1}\s!name}}
+ \def\strc_counters_next #1{\clf_nextcountervalue {\namedcounterparameter{#1}\s!name}}
+ \def\strc_counters_prev #1{\clf_previouscountervalue {\namedcounterparameter{#1}\s!name}}
+ \def\strc_counters_subs #1{\clf_subcountervalues {\namedcounterparameter{#1}\s!name}}
+
+\unexpanded\def\strc_counters_set_sub #1#2#3{\clf_setsubcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax\numexpr#3\relax}
+\unexpanded\def\strc_counters_setown_sub #1#2#3{\clf_setownsubcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax{#3}}
+\unexpanded\def\strc_counters_restart_sub #1#2#3{\clf_restartsubcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax\numexpr#3\relax}
+\unexpanded\def\strc_counters_reset_sub #1#2{\clf_resetsubcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+\unexpanded\def\strc_counters_increment_sub #1#2{\clf_incrementsubcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+\unexpanded\def\strc_counters_decrement_sub #1#2{\clf_decrementsubcounter {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+
+ \def\strc_counters_raw_sub #1#2{\clf_subcountervalue {\namedcounterparameter{#1}\s!name}\numexpr#2\relax} % maybe raw
+ \def\strc_counters_last_sub #1#2{\clf_lastsubcountervalue {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+ \def\strc_counters_first_sub #1#2{\clf_firstsubcountervalue {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+ \def\strc_counters_next_sub #1#2{\clf_nextsubcountervalue {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+ \def\strc_counters_prev_sub #1#2{\clf_previoussubcountervalue{\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+ \def\strc_counters_subs_sub #1#2{\clf_subsubcountervalues {\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
+
+\unexpanded\def\strc_counters_save #1{\clf_savecounter {\namedcounterparameter{#1}\s!name}}
+\unexpanded\def\strc_counters_restore #1{\clf_restorecounter {\namedcounterparameter{#1}\s!name}}
+
+\unexpanded\def\strc_counters_incremented #1{\clf_incrementedcounter {\namedcounterparameter{#1}\s!name}}
+\unexpanded\def\strc_counters_decremented #1{\clf_decrementedcounter {\namedcounterparameter{#1}\s!name}}
+
+\unexpanded\def\showcounter [#1]{\clf_showcounter {\namedcounterparameter{#1}\s!name}}
+
+\unexpanded\def\incrementedcounter [#1]{\clf_incrementedcounter {\namedcounterparameter{#1}\s!name}} % no \dosingleargument
+\unexpanded\def\decrementedcounter [#1]{\clf_decrementedcounter {\namedcounterparameter{#1}\s!name}} % no \dosingleargument
% public variants ... beware, for old cases, from now on the value variants are the
% ones that are expandable
-\def\rawcountervalue [#1]{\strc_counters_raw_sub {#1}\plusone}
-\def\lastcountervalue [#1]{\strc_counters_last_sub {#1}\plusone}
-\def\firstcountervalue[#1]{\strc_counters_first_sub{#1}\plusone}
-\def\nextcountervalue [#1]{\strc_counters_next_sub {#1}\plusone}
-\def\prevcountervalue [#1]{\strc_counters_prev_sub {#1}\plusone}
+\def\rawcountervalue [#1]{\clf_countervalue {\namedcounterparameter{#1}\s!name}}
+\def\lastcountervalue [#1]{\clf_lastcountervalue {\namedcounterparameter{#1}\s!name}}
+\def\firstcountervalue [#1]{\clf_firstcountervalue {\namedcounterparameter{#1}\s!name}}
+\def\nextcountervalue [#1]{\clf_nextcountervalue {\namedcounterparameter{#1}\s!name}}
+\def\prevcountervalue [#1]{\clf_previouscountervalue{\namedcounterparameter{#1}\s!name}}
-\let\rawsubcountervalue \strc_counters_raw_two
-\let\lastsubcountervalue \strc_counters_last_two
-\let\firstsubcountervalue\strc_counters_first_two
-\let\nextsubcountervalue \strc_counters_next_two
-\let\prevsubcountervalue \strc_counters_prev_two
+\let\rawsubcountervalue \strc_counters_raw_two
+\let\lastsubcountervalue \strc_counters_last_two
+\let\firstsubcountervalue \strc_counters_first_two
+\let\nextsubcountervalue \strc_counters_next_two
+\let\prevsubcountervalue \strc_counters_prev_two
% The bypage check needs a multipass reference and therefore we only check for it when we increment
% and know that some content will be placed. We could also check for spreads.
@@ -349,7 +340,7 @@
\strc_counters_reset{#1}%
\fi
\fi
- \ctxcommand{addcounter("\namedcounterparameter{#1}\s!name",\number#2,1)}}
+ \clf_incrementsubcounter{\namedcounterparameter{#1}\s!name}\numexpr#2\relax}
\unexpanded\def\convertedcounter
{\dodoubleempty\strc_counters_converted}
@@ -358,58 +349,58 @@
{\begingroup
\edef\currentcounter{#1}%
\ifsecondargument\setupcurrentcounter[#2]\fi
- \ctxcommand{prefixedconverted(
- "\counterparameter\s!name",
+ \clf_prefixedconverted
+ {\counterparameter\s!name}
{
- prefix = "\counterparameter\c!prefix",
- separatorset = "\counterparameter\c!prefixseparatorset",
- conversion = "\counterparameter\c!prefixconversion",
- conversionset = "\counterparameter\c!prefixconversionset",
- starter = \!!bs\counterparameter\c!prefixstarter\!!es,
- stopper = \!!bs\counterparameter\c!prefixstopper\!!es,
- set = "\counterparameter\c!prefixset",
- segments = "\counterparameter\c!prefixsegments",
- connector = \!!bs\counterparameter\c!prefixconnector\!!es,
- },
+ prefix {\counterparameter\c!prefix}
+ separatorset {\counterparameter\c!prefixseparatorset}
+ conversion {\counterparameter\c!prefixconversion}
+ conversionset {\counterparameter\c!prefixconversionset}
+ starter {\counterparameter\c!prefixstarter}
+ stopper {\counterparameter\c!prefixstopper}
+ set {\counterparameter\c!prefixset}
+ segments {\counterparameter\c!prefixsegments}
+ connector {\counterparameter\c!prefixconnector}
+ }
{
- order = "\counterparameter\c!numberorder",
- separatorset = "\counterparameter\c!numberseparatorset",
- conversion = \!!bs\counterparameter\c!numberconversion\!!es,
- conversionset = "\counterparameter\c!numberconversionset",
- starter = \!!bs\counterparameter\c!numberstarter\!!es,
- stopper = \!!bs\counterparameter\c!numberstopper\!!es,
- segments = "\counterparameter\c!numbersegments",
- type = "\counterparameter\c!type",
- criterium = "\counterparameter\c!criterium", % might change if we also want this with sectioning
+ order {\counterparameter\c!numberorder}
+ separatorset {\counterparameter\c!numberseparatorset}
+ conversion {\counterparameter\c!numberconversion}
+ conversionset {\counterparameter\c!numberconversionset}
+ starter {\counterparameter\c!numberstarter}
+ stopper {\counterparameter\c!numberstopper}
+ segments {\counterparameter\c!numbersegments}
+ type {\counterparameter\c!type}
+ criterium {\counterparameter\c!criterium}
}
- )}%
+ \relax
\endgroup}
\def\directconvertedcounter#1#2% name, type
- {\ctxcommand{prefixedconverted(
- "\namedcounterparameter{#1}\s!name",
+ {\clf_prefixedconverted
+ {\namedcounterparameter{#1}\s!name}
{
- prefix = "\namedcounterparameter{#1}\c!prefix",
- separatorset = "\namedcounterparameter{#1}\c!prefixseparatorset",
- conversion = "\namedcounterparameter{#1}\c!prefixconversion",
- conversionset = "\namedcounterparameter{#1}\c!prefixconversionset",
- % starter = \!!bs\namedcounterparameter{#1}\c!prefixstarter\!!es,
- % stopper = \!!bs\namedcounterparameter{#1}\c!prefixstopper\!!es,
- set = "\namedcounterparameter{#1}\c!prefixset",
- segments = "\namedcounterparameter{#1}\c!prefixsegments",
- connector = \!!bs\namedcounterparameter{#1}\c!prefixconnector\!!es,
- },
+ prefix {\namedcounterparameter{#1}\c!prefix}
+ separatorset {\namedcounterparameter{#1}\c!prefixseparatorset}
+ conversion {\namedcounterparameter{#1}\c!prefixconversion}
+ conversionset {\namedcounterparameter{#1}\c!prefixconversionset}
+ % starter {\namedcounterparameter{#1}\c!prefixstarter}
+ % stopper {\namedcounterparameter{#1}\c!prefixstopper}
+ set {\namedcounterparameter{#1}\c!prefixset}
+ segments {\namedcounterparameter{#1}\c!prefixsegments}
+ connector {\namedcounterparameter{#1}\c!prefixconnector}
+ }
{
- order = "\namedcounterparameter{#1}\c!numberorder",
- separatorset = "\namedcounterparameter{#1}\c!numberseparatorset",
- conversion = \!!bs\namedcounterparameter{#1}\c!numberconversion\!!es,
- conversionset = "\namedcounterparameter{#1}\c!numberconversionset",
- starter = \!!bs\namedcounterparameter{#1}\c!numberstarter\!!es,
- stopper = \!!bs\namedcounterparameter{#1}\c!numberstopper\!!es,
- segments = "\namedcounterparameter{#1}\c!numbersegments",
- type = "#2",
+ order {\namedcounterparameter{#1}\c!numberorder}
+ separatorset {\namedcounterparameter{#1}\c!numberseparatorset}
+ conversion {\namedcounterparameter{#1}\c!numberconversion}
+ conversionset {\namedcounterparameter{#1}\c!numberconversionset}
+ starter {\namedcounterparameter{#1}\c!numberstarter}
+ stopper {\namedcounterparameter{#1}\c!numberstopper}
+ segments {\namedcounterparameter{#1}\c!numbersegments}
+ type {#2}
}
- )}}
+ \relax}
\unexpanded\def\convertedsubcounter
{\dotripleempty\strc_counters_converted_sub}
@@ -444,7 +435,9 @@
\unexpanded\def\doifdefinedcounter {\doifcommandhandler \??counter}
\unexpanded\def\doifundefinedcounter {\doifnotcommandhandler \??counter}
-\unexpanded\def\doifdefinedcounterelse{\doifelsecommandhandler\??counter}
+\unexpanded\def\doifelsedefinedcounter{\doifelsecommandhandler\??counter}
+
+\let\doifdefinedcounterelse\doifelsedefinedcounter
%D What follows is a compatibility layer.
@@ -465,7 +458,8 @@
\let \doifdefinednumber \doifdefinedcounter % {number}{true}
\let \doifundefinednumber \doifnotdefinedcounter % {number}{true}
-\let \doifdefinednumberelse \doifdefinedcounterelse % {number}{true}{false}
+\let \doifelsedefinednumber \doifelsedefinedcounter % {number}{true}{false}
+\let \doifdefinednumberelse \doifelsedefinedcounter % {number}{true}{false}
\let \setupnumbering \setupcounter
@@ -487,7 +481,6 @@
% currentstructurecomponent => \strc_current_ or just \m_strc_
-
\unexpanded\def\strc_counters_register_component#1#2#3#4#5#6#7[#8][#9]% maybe also nolist
{\begingroup
%
@@ -525,27 +518,36 @@
\glet\m_strc_counters_last_registered_attribute \attributeunsetvalue
\glet\m_strc_counters_last_registered_synchronize\relax}
+\def\strc_counters_register_component_check_prefix
+ {\ifx\currentstructurecomponentreferenceprefix\empty
+ \let\currentstructurecomponentreferenceprefix\currentstructurereferenceprefix
+ \fi
+ \ifx\currentstructurecomponentreferenceprefix\empty
+ \let\currentstructurecomponentreferenceprefix\referenceprefix
+ \fi
+ \ifdefined\currentstructurecomponentreferenceprefix\else
+ \let\currentstructurecomponentreferenceprefix\empty
+ \fi}
+
\def\strc_counters_register_component_page#1%
{\xdef\currentstructurecomponentreference {#1\c!reference}%
\xdef\currentstructurecomponentreferenceprefix{#1\c!referenceprefix}%
- % maybe have a helper in strc-ref.mkvi
+ \strc_counters_register_component_check_prefix
\setnextinternalreference
- \ctxcommand{setreferenceattribute(% can be helper with less passed
- "\s!page",
- "\currentstructurecomponentreferenceprefix",
- "\currentstructurecomponentreference",
- {
- references = {
- internal = \nextinternalreference,
- block = "\currentsectionblock",
- section = structures.sections.currentid(),
- },
- metadata = {
- kind = "page",
- },
- },
- "\interactionparameter\c!focus")
- }%
+ \clf_setreferenceattribute
+ {%
+ references {%
+ internal \nextinternalreference
+ % block {\currentsectionblock}% move to lua
+ view {\interactionparameter\c!focus}%
+ prefix {\currentstructurecomponentreferenceprefix}%
+ reference {\currentstructurecomponentreference}%
+ }%
+ metadata {%
+ kind {\s!page}%
+ }%
+ }%
+ \relax
\xdef\m_strc_counters_last_registered_attribute {\the\lastdestinationattribute}%
\glet\m_strc_counters_last_registered_index \relax
\glet\m_strc_counters_last_registered_synchronize\relax}
@@ -559,6 +561,7 @@
\xdef\currentstructurecomponentlabel {#2\c!label}%
\xdef\currentstructurecomponentreference {#2\c!reference}%
\xdef\currentstructurecomponentreferenceprefix{#2\c!referenceprefix}%
+ \strc_counters_register_component_check_prefix
\ifx\currentstructurecomponentexpansion\s!xml
\xmlstartraw
\xdef\currentstructurecomponenttitle {#2\c!title}%
@@ -595,70 +598,71 @@
\fi
%
\setnextinternalreference
- \xdef\m_strc_counters_last_registered_index{\ctxcommand{addtolist{
- metadata = {
- kind = "#1",
- name = "\currentname",
- level = structures.sections.currentlevel(),
- catcodes = \the\ifx\currentstructurecomponentcatcodes\empty\catcodetable\else\csname\currentstructurecomponentcatcodes\endcsname\fi,
- coding = "\currentstructurecomponentcoding",
+ \scratchcounter\clf_addtolist %{
+ metadata {
+ kind {#1}
+ name {\currentname}
+ % level structures.sections.currentlevel()
+ catcodes \ifx\currentstructurecomponentcatcodes\empty\catcodetable\else\csname\currentstructurecomponentcatcodes\endcsname\fi
+ coding {\currentstructurecomponentcoding}
\ifx\currentstructurecomponentcoding\s!xml
- xmlroot = "\xmldocument",
+ xmlroot {\xmldocument}
\fi
\ifx\currentstructurecomponentxmlsetup\empty \else
- xmlsetup = "\currentstructurexmlsetup",
+ xmlsetup {\currentstructurexmlsetup}
\fi
- },
- references = {
- internal = \nextinternalreference,
- block = "\currentsectionblock",
- reference = "\currentstructurecomponentreference",
- referenceprefix = "\currentstructurecomponentreferenceprefix",
- section = structures.sections.currentid(),
- },
- titledata = {
- label = \!!bs\detokenize\expandafter{\currentstructurecomponentlabel }\!!es,
- title = \!!bs\detokenize\expandafter{\currentstructurecomponenttitle }\!!es,
+ }
+ references {
+ internal \nextinternalreference
+ % block {\currentsectionblock}
+ reference {\currentstructurecomponentreference}
+ prefix {\currentstructurecomponentreferenceprefix}
+ % section structures.sections.currentid()
+ }
+ titledata {
+ label {\detokenize\expandafter{\currentstructurecomponentlabel}}
+ title {\detokenize\expandafter{\currentstructurecomponenttitle}}
\ifx\currentstructurecomponentbookmark\currentstructurecomponenttitle \else
- bookmark = \!!bs\detokenize\expandafter{\currentstructurecomponentbookmark}\!!es,
+ bookmark {\detokenize\expandafter{\currentstructurecomponentbookmark}}
\fi
\ifx\currentstructurecomponentmarking\currentstructurecomponenttitle \else
- marking = \!!bs\detokenize\expandafter{\currentstructurecomponentmarking }\!!es,
+ marking {\detokenize\expandafter{\currentstructurecomponentmarking}}
\fi
\ifx\currentstructurecomponentlist\currentstructurecomponenttitle \else
- list = \!!bs\detokenize\expandafter{\currentstructurecomponentlist}\!!es,
+ list {\detokenize\expandafter{\currentstructurecomponentlist}}
\fi
- },
- \ifx\p_hasnumber\v!yes
- prefixdata = {
- prefix = "#2\c!prefix",
- separatorset = "#2\c!prefixseparatorset",
- conversion = \!!bs#2\c!prefixconversion\!!es,
- conversionset = "#2\c!prefixconversionset",
- set = "#2\c!prefixset",
- % segments = "#2\c!prefixsegments",
- segments = "\p_prefixsegments",
- connector = \!!bs#2\c!prefixconnector\!!es,
- },
- numberdata = { % more helpers here, like compact elsewhere
- numbers = structures.counters.compact("\currentcounter",nil,true),
- group = "#2\c!group",
- groupsuffix = \!!bs#2\c!groupsuffix\!!es,
- counter = "\currentcounter",
- separatorset = "#2\c!numberseparatorset",
- conversion = \!!bs#2\c!numberconversion\!!es,
- conversionset = "#2\c!numberconversionset",
- starter = \!!bs#2\c!numberstarter\!!es,
- stopper = \!!bs#2\c!numberstopper\!!es,
- segments = "#2\c!numbersegments",
- },
- \fi
- userdata = \!!bs\detokenize{#4}\!!es % will be converted to table at the lua end
- }
- }}%
- \ctxcommand{setinternalreference(nil,nil,\nextinternalreference)}%
+ }
+ \ifx\p_hasnumber\v!yes
+ prefixdata {
+ prefix {#2\c!prefix}
+ separatorset {#2\c!prefixseparatorset}
+ conversion {#2\c!prefixconversion}
+ conversionset {#2\c!prefixconversionset}
+ set {#2\c!prefixset}
+ % segments {#2\c!prefixsegments}
+ segments {\p_prefixsegments}
+ connector {#2\c!prefixconnector}
+ }
+ numberdata { % more helpers here, like compact elsewhere
+ numbers {\currentcounter}
+ group {#2\c!group}
+ groupsuffix {#2\c!groupsuffix}
+ counter {\currentcounter}
+ separatorset {#2\c!numberseparatorset}
+ conversion {#2\c!numberconversion}
+ conversionset {#2\c!numberconversionset}
+ starter {#2\c!numberstarter}
+ stopper {#2\c!numberstopper}
+ segments {#2\c!numbersegments}
+ }
+ \fi
+ userdata {\detokenize{#4}}
+ %}
+ \relax
+ \xdef\m_strc_counters_last_registered_index{\the\scratchcounter}%
+ \clf_setinternalreference internal \nextinternalreference\relax
\xdef\m_strc_counters_last_registered_attribute {\the\lastdestinationattribute}%
- \xdef\m_strc_counters_last_registered_synchronize{\ctxlatecommand{enhancelist(\m_strc_counters_last_registered_index)}}}
+ \xdef\m_strc_counters_last_registered_synchronize{\strc_lists_inject_enhance{\m_strc_counters_last_registered_index}{\nextinternalreference}}}
\let\m_strc_counters_last_registered_index \relax
\let\m_strc_counters_last_registered_attribute \relax
diff --git a/Master/texmf-dist/tex/context/base/strc-pag.lua b/Master/texmf-dist/tex/context/base/strc-pag.lua
index c294a464539..96d26e6f666 100644
--- a/Master/texmf-dist/tex/context/base/strc-pag.lua
+++ b/Master/texmf-dist/tex/context/base/strc-pag.lua
@@ -25,6 +25,7 @@ local counterdata = counters.data
local variables = interfaces.variables
local context = context
local commands = commands
+local implement = interfaces.implement
local processors = typesetters.processors
local applyprocessor = processors.apply
@@ -61,10 +62,12 @@ function pages.save(prefixdata,numberdata,extradata)
if trace_pages then
report_pages("saving page %s.%s",realpage,userpage)
end
+ local viewerprefix = extradata.viewerprefix
+ local state = extradata.state
local data = {
number = userpage,
- viewerprefix = extradata.viewerprefix,
- state = extradata.state,
+ viewerprefix = viewerprefix ~= "" and viewerprefix or nil,
+ state = state ~= "" and state or nil, -- maybe let "start" be default
block = sections.currentblock(),
prefixdata = prefixdata and helpers.simplify(prefixdata),
numberdata = numberdata and helpers.simplify(numberdata),
@@ -269,6 +272,24 @@ function pages.is_odd(n)
end
end
+function pages.on_right(n)
+ local pagemode = texgetcount("pageduplexmode")
+ if pagemode == 2 or pagemode == 1 then
+ n = n or texgetcount("realpageno")
+ if texgetcount("pagenoshift") % 2 == 0 then
+ return n % 2 == 0
+ else
+ return n % 2 ~= 0
+ end
+ else
+ return true
+ end
+end
+
+function pages.in_body(n)
+ return texgetcount("pagebodymode") > 0
+end
+
-- move to strc-pag.lua
function counters.analyze(name,counterspecification)
@@ -323,5 +344,58 @@ end
--
-commands.savepagedata = pages.save
-commands.prefixedconverted = sections.prefixedconverted -- weird place
+implement {
+ name = "savepagedata",
+ actions = pages.save,
+ arguments = {
+ {
+ { "prefix" },
+ { "separatorset" },
+ { "conversionset" },
+ { "conversion" },
+ { "set" },
+ { "segments" },
+ { "connector" },
+ },
+ {
+ { "conversionset" },
+ { "conversion" },
+ { "starter" },
+ { "stopper" },
+ },
+ {
+ { "viewerprefix" },
+ { "state" },
+ }
+ }
+}
+
+implement { -- weird place
+ name = "prefixedconverted",
+ actions = sections.prefixedconverted,
+ arguments = {
+ "string",
+ {
+ { "prefix" },
+ { "separatorset" },
+ { "conversionset" },
+ { "conversion" },
+ { "starter" },
+ { "stopper" },
+ { "set" },
+ { "segments" },
+ { "connector" },
+ },
+ {
+ { "order" },
+ { "separatorset" },
+ { "conversionset" },
+ { "conversion" },
+ { "starter" },
+ { "stopper" },
+ { "segments" },
+ { "type" },
+ { "criterium" },
+ }
+ }
+}
diff --git a/Master/texmf-dist/tex/context/base/strc-pag.mkiv b/Master/texmf-dist/tex/context/base/strc-pag.mkiv
index 6eddc0fba71..72f0cf32aa8 100644
--- a/Master/texmf-dist/tex/context/base/strc-pag.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-pag.mkiv
@@ -26,12 +26,14 @@
\countdef\subpageno \plustwo \subpageno \zerocount % !
\countdef\arrangeno \plusthree \arrangeno \zerocount % !
\countdef\pagenoshift\plusfour \pagenoshift\zerocount % !
+\countdef\lastpageno \plusfive \lastpageno \zerocount % !
\let\pageno\userpageno
\def\realfolio{\the\realpageno}
\def\userfolio{\the\userpageno}
\def\subfolio {\the\subpageno }
+\def\lastfolio{\the\lastpageno}
\newtoks\everyinitializepagecounters
@@ -103,6 +105,7 @@
\strc_counters_set\s!realpage\realpageno
\strc_counters_set\s!userpage\userpageno
\strc_counters_set\s!subpage \subpageno
+ \lastpageno\lastcountervalue[\s!realpage]\relax
\to \everyinitializepagecounters
\let\setuppagenumber\setupuserpagenumber
@@ -111,24 +114,25 @@
% invisible =
\def\strc_pagenumbers_page_state_save % \normalexpanded?
- {\ctxcommand{savepagedata({
- prefix = "\namedcounterparameter\s!userpage\c!prefix",
- separatorset = "\namedcounterparameter\s!userpage\c!prefixseparatorset",
- conversion = "\namedcounterparameter\s!userpage\c!prefixconversion",
- conversionset = "\namedcounterparameter\s!userpage\c!prefixconversionset",
- set = "\namedcounterparameter\s!userpage\c!prefixset",
- segments = "\namedcounterparameter\s!userpage\c!prefixsegments",
- connector = \!!bs\namedcounterparameter\s!userpage\c!prefixconnector\!!es,
- },{
- conversion = "\namedcounterparameter\s!userpage\c!numberconversion",
- conversionset = "\namedcounterparameter\s!userpage\c!numberconversionset",
- starter = \!!bs\namedcounterparameter\s!userpage\c!numberstarter\!!es,
- stopper = \!!bs\namedcounterparameter\s!userpage\c!numberstopper\!!es,
- },{
- viewerprefix = \!!bs\namedcounterparameter\s!userpage\c!viewerprefix\!!es,
- state = \!!bs\namedcounterparameter\s!userpage\c!state\!!es,
- }
- )}}
+ {\clf_savepagedata
+ {
+ prefix {\namedcounterparameter\s!userpage\c!prefix}
+ separatorset {\namedcounterparameter\s!userpage\c!prefixseparatorset}
+ conversion {\namedcounterparameter\s!userpage\c!prefixconversion}
+ conversionset {\namedcounterparameter\s!userpage\c!prefixconversionset}
+ set {\namedcounterparameter\s!userpage\c!prefixset}
+ segments {\namedcounterparameter\s!userpage\c!prefixsegments}
+ connector {\namedcounterparameter\s!userpage\c!prefixconnector}
+ }{
+ conversion {\namedcounterparameter\s!userpage\c!numberconversion}
+ conversionset {\namedcounterparameter\s!userpage\c!numberconversionset}
+ starter {\namedcounterparameter\s!userpage\c!numberstarter}
+ stopper {\namedcounterparameter\s!userpage\c!numberstopper}
+ }{
+ viewerprefix {\namedcounterparameter\s!userpage\c!viewerprefix}
+ state {\namedcounterparameter\s!userpage\c!state}
+ }%
+ \relax}
\prependtoks
\strc_pagenumbers_page_state_save
@@ -303,6 +307,12 @@
\trackingmarginnotesfalse
\fi
\fi
+ \pageduplexmode
+ \ifsinglesided
+ \ifdoublesided\plustwo\else\zerocount\fi
+ \else
+ \ifdoublesided\plusone\else\zerocount\fi
+ \fi
\page_backgrounds_recalculate
\strc_pagenumbers_set_location
\to \everysetuppagenumbering
diff --git a/Master/texmf-dist/tex/context/base/strc-ref.lua b/Master/texmf-dist/tex/context/base/strc-ref.lua
index 3f2c0608d2a..b6f2e9a3778 100644
--- a/Master/texmf-dist/tex/context/base/strc-ref.lua
+++ b/Master/texmf-dist/tex/context/base/strc-ref.lua
@@ -53,6 +53,7 @@ local v_auto = variables.auto
local context = context
local commands = commands
+local implement = interfaces.implement
local texgetcount = tex.getcount
local texsetcount = tex.setcount
@@ -76,6 +77,8 @@ local references = structures.references
local lists = structures.lists
local counters = structures.counters
+local jobpositions = job.positions
+
-- some might become local
references.defined = references.defined or allocate()
@@ -83,6 +86,7 @@ references.defined = references.defined or allocate()
local defined = references.defined
local derived = allocate()
local specials = allocate()
+local functions = allocate()
local runners = allocate()
local internals = allocate()
local filters = allocate()
@@ -98,6 +102,7 @@ local usedviews = allocate()
references.derived = derived
references.specials = specials
+references.functions = functions
references.runners = runners
references.internals = internals
references.filters = filters
@@ -123,7 +128,7 @@ local context_delayed = context.delayed
local ctx_pushcatcodes = context.pushcatcodes
local ctx_popcatcodes = context.popcatcodes
-local ctx_dofinishsomereference = context.dofinishsomereference
+local ctx_dofinishreference = context.dofinishreference
local ctx_dofromurldescription = context.dofromurldescription
local ctx_dofromurlliteral = context.dofromurlliteral
local ctx_dofromfiledescription = context.dofromfiledescription
@@ -339,8 +344,8 @@ local function setcomponent(data)
local references = data and data.references
if references then
references.component = component
- if references.referenceprefix == component then
- references.referenceprefix = nil
+ if references.prefix == component then
+ references.prefix = nil
end
end
return component
@@ -353,15 +358,32 @@ references.setnextinternal = setnextinternal
references.currentorder = currentorder
references.setcomponent = setcomponent
-commands.setnextreferenceorder = setnextorder
-commands.setnextinternalreference = setnextinternal
+implement {
+ name = "setnextreferenceorder",
+ actions = setnextorder,
+ arguments = { "string", "string" }
+}
-function commands.currentreferenceorder(kind,name)
- context(currentorder(kind,name))
-end
+implement {
+ name = "setnextinternalreference",
+ actions = setnextinternal,
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "currentreferenceorder",
+ actions = { currentorder, context },
+ arguments = { "string", "string" }
+}
-function references.set(kind,prefix,tag,data)
--- setcomponent(data)
+function references.set(data)
+ local references = data.references
+ local prefix = references.prefix or ""
+ local reference = references.reference
+ if not reference or reference == "" then
+ report_references("invalid reference")
+ return 0
+ end
local pd = tobesaved[prefix] -- nicer is a metatable
if not pd then
pd = { }
@@ -380,21 +402,44 @@ function references.set(kind,prefix,tag,data)
else
n = n + 1
pd[ref] = data
- ctx_dofinishsomereference(kind,prefix,ref)
+ local r = data.references
+ ctx_dofinishreference(prefix or "",ref or "",r and r.internal or 0)
end
end
- process_settings(tag,action)
+ process_settings(reference,action)
return n > 0
end
+-- function references.enhance(prefix,tag)
+-- local l = tobesaved[prefix][tag]
+-- if l then
+-- l.references.realpage = texgetcount("realpageno")
+-- end
+-- end
+
+local getpos = function() getpos = backends.codeinjections.getpos return getpos () end
+
+local function synchronizepage(reference) -- non public helper
+ reference.realpage = texgetcount("realpageno")
+ if jobpositions.used then
+ reference.x, reference.y = getpos()
+ end
+end
+
+references.synchronizepage = synchronizepage
+
function references.enhance(prefix,tag)
local l = tobesaved[prefix][tag]
if l then
- l.references.realpage = texgetcount("realpageno")
+ synchronizepage(l.references)
end
end
-commands.enhancereference = references.enhance
+implement {
+ name = "enhancereference",
+ actions = references.enhance,
+ arguments = { "string", "string" }
+}
-- -- -- related to strc-ini.lua -- -- --
@@ -402,15 +447,34 @@ commands.enhancereference = references.enhance
local function register_from_lists(collected,derived,pages,sections)
local derived_g = derived[""] -- global
+ local derived_p = nil
+ local derived_c = nil
+ local prefix = nil
+ local component = nil
+ local entry = nil
if not derived_g then
derived_g = { }
derived[""] = derived_g
end
+ local function action(s)
+ if trace_referencing then
+ report_references("list entry %a provides %a reference %a on realpage %a",i,kind,s,realpage)
+ end
+ if derived_p and not derived_p[s] then
+ derived_p[s] = entry
+ end
+ if derived_c and not derived_c[s] then
+ derived_c[s] = entry
+ end
+ if not derived_g[s] then
+ derived_g[s] = entry -- first wins
+ end
+ end
for i=1,#collected do
- local entry = collected[i]
+ entry = collected[i]
local metadata = entry.metadata
if metadata then
- local kind = metadata.kind
+ local kind = metadata.kind -- why this check
if kind then
local references = entry.references
if references then
@@ -418,10 +482,8 @@ local function register_from_lists(collected,derived,pages,sections)
if reference and reference ~= "" then
local realpage = references.realpage
if realpage then
- local prefix = references.referenceprefix
- local component = references.component
- local derived_p = nil
- local derived_c = nil
+ prefix = references.prefix
+ component = references.component
if prefix and prefix ~= "" then
derived_p = derived[prefix]
if not derived_p then
@@ -436,20 +498,6 @@ local function register_from_lists(collected,derived,pages,sections)
derived[component] = derived_c
end
end
- local function action(s)
- if trace_referencing then
- report_references("list entry %a provides %a reference %a on realpage %a",i,kind,s,realpage)
- end
- if derived_p and not derived_p[s] then
- derived_p[s] = entry
- end
- if derived_c and not derived_c[s] then
- derived_c[s] = entry
- end
- if not derived_g[s] then
- derived_g[s] = entry -- first wins
- end
- end
process_settings(reference,action)
end
end
@@ -462,6 +510,78 @@ end
references.registerinitializer(function() register_from_lists(lists.collected,derived) end)
+-- tracing
+
+local function collectbypage(tracedpages)
+ -- lists
+ do
+ local collected = structures.lists.collected
+ local data = nil
+ local function action(reference)
+ local prefix = data.prefix
+ local component = data.component
+ local realpage = data.realpage
+ if realpage then
+ local pagelist = rawget(tracedpages,realpage)
+ local internal = data.internal or 0
+ local prefix = (prefix ~= "" and prefix) or (component ~= "" and component) or ""
+ local pagedata = { prefix, reference, internal }
+ if pagelist then
+ pagelist[#pagelist+1] = pagedata
+ else
+ tracedpages[realpage] = { pagedata }
+ end
+ if internal > 0 then
+ data.usedprefix = prefix
+ end
+ end
+ end
+ for i=1,#collected do
+ local entry = collected[i]
+ local metadata = entry.metadata
+ if metadata and metadata.kind then
+ data = entry.references
+ if data then
+ local reference = data.reference
+ if reference and reference ~= "" then
+ process_settings(reference,action)
+ end
+ end
+ end
+ end
+ end
+ -- references
+ do
+ for prefix, list in next, collected do
+ for reference, entry in next, list do
+ local data = entry.references
+ if data then
+ local realpage = data.realpage
+ local internal = data.internal or 0
+ local pagelist = rawget(tracedpages,realpage)
+ local pagedata = { prefix, reference, internal }
+ if pagelist then
+ pagelist[#pagelist+1] = pagedata
+ else
+ tracedpages[realpage] = { pagedata }
+ end
+ if internal > 0 then
+ data.usedprefix = prefix
+ end
+ end
+ end
+ end
+ end
+end
+
+references.tracedpages = table.setmetatableindex(allocate(),function(t,k)
+ if collectbypage then
+ collectbypage(t)
+ collectbypage = nil
+ end
+ return rawget(t,k)
+end)
+
-- urls
local urls = references.urls or { }
@@ -487,7 +607,11 @@ function urls.get(name)
end
end
-function commands.geturl(name)
+function urls.found(name)
+ return urldata[name]
+end
+
+local function geturl(name)
local url = urls.get(name)
if url and url ~= "" then
ctx_pushcatcodes(txtcatcodes)
@@ -496,18 +620,23 @@ function commands.geturl(name)
end
end
--- function commands.gethyphenatedurl(name,...)
--- local url = urls.get(name)
--- if url and url ~= "" then
--- hyphenatedurl(url,...)
--- end
--- end
+implement {
+ name = "doifelseurldefined",
+ actions = { urls.found, commands.doifelse },
+ arguments = "string"
+}
-function commands.doifurldefinedelse(name)
- commands.doifelse(urldata[name])
-end
+implement {
+ name = "useurl",
+ actions = urls.define,
+ arguments = { "string", "string", "string", "string" }
+}
-commands.useurl= urls.define
+implement {
+ name = "geturl",
+ actions = geturl,
+ arguments = "string",
+}
-- files
@@ -529,11 +658,36 @@ function files.get(name,method,space) -- method: none, before, after, both, spac
end
end
-function commands.doiffiledefinedelse(name)
- commands.doifelse(filedata[name])
+function files.found(name)
+ return filedata[name]
+end
+
+local function getfile(name)
+ local fil = files.get(name)
+ if fil and fil ~= "" then
+ ctx_pushcatcodes(txtcatcodes)
+ context(fil)
+ ctx_popcatcodes()
+ end
end
-commands.usefile= files.define
+implement {
+ name = "doifelsefiledefined",
+ actions = { files.found, commands.doifelse },
+ arguments = "string"
+}
+
+implement {
+ name = "usefile",
+ actions = files.define,
+ arguments = { "string", "string", "string" }
+}
+
+implement {
+ name = "getfile",
+ actions = getfile,
+ arguments = "string"
+}
-- helpers
@@ -613,20 +767,30 @@ function references.checkedprogram(whatever) -- return whatever if not resolved
end
end
-commands.defineprogram = programs.define
+implement {
+ name = "defineprogram",
+ actions = programs.define,
+ arguments = { "string", "string", "string" }
+}
-function commands.getprogram(name)
- local f = programdata[name]
- if f then
- context(f[1])
+local function getprogram(name)
+ local p = programdata[name]
+ if p then
+ context(p[1])
end
end
+implement {
+ name = "getprogram",
+ actions = getprogram,
+ arguments = "string"
+}
+
-- shared by urls and files
-function references.whatfrom(name)
- context((urldata[name] and v_url) or (filedata[name] and v_file) or v_unknown)
-end
+-- function references.whatfrom(name)
+-- context((urldata[name] and v_url) or (filedata[name] and v_file) or v_unknown)
+-- end
function references.from(name)
local u = urldata[name]
@@ -653,7 +817,7 @@ function references.from(name)
end
end
-function commands.from(name)
+local function from(name)
local u = urldata[name]
if u then
local url, file, description = u[1], u[2], u[3]
@@ -678,6 +842,12 @@ function commands.from(name)
end
end
+implement {
+ name = "from",
+ actions = from,
+ arguments = "string"
+}
+
function references.define(prefix,reference,list)
local d = defined[prefix] if not d then d = { } defined[prefix] = d end
d[reference] = list
@@ -690,86 +860,17 @@ function references.reset(prefix,reference)
end
end
-commands.definereference = references.define
-commands.resetreference = references.reset
-
--- \primaryreferencefoundaction
--- \secondaryreferencefoundaction
--- \referenceunknownaction
-
--- t.special t.operation t.arguments t.outer t.inner
-
--- to what extend do we check the non prefixed variant
+implement {
+ name = "definereference",
+ actions = references.define,
+ arguments = { "string", "string", "string" }
+}
--- local strict = false
---
--- local function resolve(prefix,reference,args,set) -- we start with prefix,reference
--- if reference and reference ~= "" then
--- if not set then
--- set = { prefix = prefix, reference = reference }
--- else
--- if not set.reference then set.reference = reference end
--- if not set.prefix then set.prefix = prefix end
--- end
--- local r = settings_to_array(reference)
--- for i=1,#r do
--- local ri = r[i]
--- local d
--- if strict then
--- d = defined[prefix] or defined[""]
--- d = d and d[ri]
--- else
--- d = defined[prefix]
--- d = d and d[ri]
--- if not d then
--- d = defined[""]
--- d = d and d[ri]
--- end
--- end
--- if d then
--- resolve(prefix,d,nil,set)
--- else
--- local var = splitreference(ri)
--- if var then
--- var.reference = ri
--- local vo, vi = var.outer, var.inner
--- if not vo and vi then
--- -- to be checked
--- if strict then
--- d = defined[prefix] or defined[""]
--- d = d and d[vi]
--- else
--- d = defined[prefix]
--- d = d and d[vi]
--- if not d then
--- d = defined[""]
--- d = d and d[vi]
--- end
--- end
--- --
--- if d then
--- resolve(prefix,d,var.arguments,set) -- args can be nil
--- else
--- if args then var.arguments = args end
--- set[#set+1] = var
--- end
--- else
--- if args then var.arguments = args end
--- set[#set+1] = var
--- end
--- if var.has_tex then
--- set.has_tex = true
--- end
--- else
--- -- report_references("funny pattern %a",ri)
--- end
--- end
--- end
--- return set
--- else
--- return { }
--- end
--- end
+implement {
+ name = "resetreference",
+ actions = references.reset,
+ arguments = { "string", "string" }
+}
setmetatableindex(defined,"table")
@@ -824,11 +925,11 @@ end
references.currentset = nil
-function commands.setreferenceoperation(k,v)
+local function setreferenceoperation(k,v)
references.currentset[k].operation = v
end
-function commands.setreferencearguments(k,v)
+local function setreferencearguments(k,v)
references.currentset[k].arguments = v
end
@@ -849,7 +950,22 @@ function references.expandcurrent() -- todo: two booleans: o_has_tex& a_has_tex
end
end
-commands.expandcurrentreference = references.expandcurrent -- for the moment the same
+implement {
+ name = "expandcurrentreference",
+ actions = references.expandcurrent
+}
+
+implement {
+ name = "setreferenceoperation",
+ actions = setreferenceoperation,
+ arguments = { "integer", "string" }
+}
+
+implement {
+ name = "setreferencearguments",
+ actions = setreferencearguments,
+ arguments = { "integer", "string" }
+}
local externals = { }
@@ -893,7 +1009,7 @@ local function loadexternalreferences(name,utilitydata)
local realpage = references.realpage
if kind and realpage then
references.pagedata = pages[realpage]
- local prefix = references.referenceprefix or ""
+ local prefix = references.prefix or ""
local target = external[prefix]
if not target then
target = { }
@@ -995,7 +1111,7 @@ local function loadproductreferences(productname,componentname,utilitydata)
local realpage = references.realpage
if kind and realpage then
references.pagedata = pages[realpage]
- local prefix = references.referenceprefix or ""
+ local prefix = references.prefix or ""
local component = references.component
local ctarget, ptarget
if not component or component == componentname then
@@ -1141,7 +1257,7 @@ local useproduct = commands.useproduct
if useproduct then
- function commands.useproduct(product)
+ local function newuseproduct(product)
useproduct(product)
if texconditionals.autocrossfilereferences then
local component = justacomponent()
@@ -1154,6 +1270,13 @@ if useproduct then
end
end
+ implement {
+ name = "useproduct",
+ actions = newuseproduct,
+ arguments = "string",
+ overload = true,
+ }
+
end
-- productdata.firstsection.numberdata.numbers
@@ -1648,7 +1771,11 @@ local function identify(prefix,reference)
set.n = nofidentified
for i=1,#set do
local var = set[i]
- if var.special then
+ local spe = var.special
+ local fnc = functions[spe]
+ if fnc then
+ var = fnc(var) or { error = "invalid special function" }
+ elseif spe then
var = identify_special(set,var,i)
elseif var.outer then
var = identify_outer(set,var,i)
@@ -1675,7 +1802,7 @@ references.identify = identify
local unknowns, nofunknowns, f_valid = { }, 0, formatters["[%s][%s]"]
-function references.valid(prefix,reference,highlight,newwindow,layer)
+function references.valid(prefix,reference,specification)
local set, bug = identify(prefix,reference)
local unknown = bug or #set == 0
if unknown then
@@ -1690,16 +1817,28 @@ function references.valid(prefix,reference,highlight,newwindow,layer)
unknowns[str] = u + 1
end
else
- set.highlight, set.newwindow, set.layer = highlight, newwindow, layer
+ set.highlight = specification.highlight
+ set.newwindow = specification.newwindow
+ set.layer = specification.layer
currentreference = set[1]
end
-- we can do the expansion here which saves a call
return not unknown
end
-function commands.doifelsereference(prefix,reference,highlight,newwindow,layer)
- commands.doifelse(references.valid(prefix,reference,highlight,newwindow,layer))
-end
+implement {
+ name = "doifelsereference",
+ actions = { references.valid, commands.doifelse },
+ arguments = {
+ "string",
+ "string",
+ {
+ { "highlight", "boolean" },
+ { "newwindow", "boolean" },
+ { "layer" },
+ }
+ }
+}
function references.reportproblems() -- might become local
if nofunknowns > 0 then
@@ -1742,6 +1881,13 @@ function references.setinnermethod(m)
end
end
+implement {
+ name = "setinnerreferencemethod",
+ actions = references.setinnermethod,
+ arguments = "string",
+ onlyonce = true
+}
+
function references.getinnermethod()
return innermethod or defaultinnermethod
end
@@ -1754,24 +1900,27 @@ end)
local destinationattributes = { }
-local function setinternalreference(prefix,tag,internal,view) -- needs checking
+local function setinternalreference(specification)
+ local internal = specification.internal
local destination = unsetvalue
if innermethod == v_auto then
- local t, tn = { }, 0 -- maybe add to current
- if tag then
+ local t, tn = { }, 0 -- maybe add to current (now only used for tracing)
+ local reference = specification.reference
+ if reference then
+ local prefix = specification.prefix
if prefix and prefix ~= "" then
prefix = prefix .. ":" -- watch out, : here
local function action(ref)
tn = tn + 1
t[tn] = prefix .. ref
end
- process_settings(tag,action)
+ process_settings(reference,action)
else
local function action(ref)
tn = tn + 1
t[tn] = ref
end
- process_settings(tag,action)
+ process_settings(reference,action)
end
end
-- ugly .. later we decide to ignore it when we have a real one
@@ -1780,7 +1929,7 @@ local function setinternalreference(prefix,tag,internal,view) -- needs checking
tn = tn + 1
t[tn] = internal -- when number it's internal
end
- destination = references.mark(t,nil,nil,view) -- returns an attribute
+ destination = references.mark(t,nil,nil,specification.view) -- returns an attribute
end
if internal then -- new
destinationattributes[internal] = destination
@@ -1795,16 +1944,103 @@ end
references.setinternalreference = setinternalreference
references.getinternalreference = getinternalreference
-commands.setinternalreference = setinternalreference
-commands.getinternalreference = getinternalreference
-function references.setandgetattribute(kind,prefix,tag,data,view) -- maybe do internal automatically here
- local attr = references.set(kind,prefix,tag,data) and setinternalreference(prefix,tag,nil,view) or unsetvalue
+implement {
+ name = "setinternalreference",
+ actions = setinternalreference,
+ arguments = {
+ {
+ { "prefix" },
+ { "reference" },
+ { "internal", "integer" },
+ { "view" }
+ }
+ }
+}
+
+-- implement {
+-- name = "getinternalreference",
+-- actions = { getinternalreference, context },
+-- arguments = "integer",
+-- }
+
+function references.setandgetattribute(data) -- maybe do internal automatically here
+ local attr = unsetvalue
+ local mdat = data.metadata
+ local rdat = data.references
+ if mdat and rdat then
+ if not rdat.section then
+ rdat.section = structures.sections.currentid()
+ end
+ local ndat = data.numberdata
+ if ndat then
+ local numbers = ndat.numbers
+ if type(numbers) == "string" then
+ ndat.numbers = counters.compact(numbers,nil,true)
+ end
+ data.numberdata = helpers.simplify(ndat)
+ end
+ local pdat = data.prefixdata
+ if pdat then
+ data.prefixdata = helpers.simplify(pdat)
+ end
+ local udat = data.userdata
+ if type(udat) == "string" then
+ data.userdata = helpers.touserdata(udat)
+ end
+ if not rdat.block then
+ rdat.block = structures.sections.currentblock()
+ end
+ local done = references.set(data) -- we had kind i.e .item -> full
+ if done then
+ attr = setinternalreference {
+ prefix = prefix,
+ reference = tag,
+ internal = rdat.internal,
+ view = rdat.view
+ } or unsetvalue
+ end
+ end
texsetcount("lastdestinationattribute",attr)
return attr
end
-commands.setreferenceattribute = references.setandgetattribute
+implement {
+ name = "setreferenceattribute",
+ actions = references.setandgetattribute,
+ arguments = {
+ {
+ {
+ "references", {
+ { "internal", "integer" },
+ { "block" },
+ { "view" },
+ { "prefix" },
+ { "reference" },
+ },
+ },
+ {
+ "metadata", {
+ { "kind" },
+ { "xmlroot" },
+ { "catcodes", "integer" },
+ },
+ },
+ {
+ "prefixdata", { "*" }
+ },
+ {
+ "numberdata", { "*" }
+ },
+ {
+ "entries", { "*" }
+ },
+ {
+ "userdata"
+ }
+ }
+ }
+}
function references.getinternallistreference(n) -- n points into list (todo: registers)
local l = lists.collected[n]
@@ -1812,11 +2048,11 @@ function references.getinternallistreference(n) -- n points into list (todo: reg
return i and destinationattributes[i] or 0
end
-function commands.getinternallistreference(n) -- this will also be a texcount
- local l = lists.collected[n]
- local i = l and l.references.internal
- context(i and destinationattributes[i] or 0)
-end
+implement {
+ name = "getinternallistreference",
+ actions = { references.getinternallistreference, context },
+ arguments = "integer"
+}
--
@@ -1825,12 +2061,11 @@ function references.getcurrentmetadata(tag)
return data and data.metadata and data.metadata[tag]
end
-function commands.getcurrentreferencemetadata(tag)
- local data = references.getcurrentmetadata(tag)
- if data then
- context(data)
- end
-end
+implement {
+ name = "getcurrentreferencemetadata",
+ actions = { references.getcurrentmetadata, context },
+ arguments = "string",
+}
local function currentmetadata(tag)
local data = currentreference and currentreference.i
@@ -1840,15 +2075,29 @@ end
references.currentmetadata = currentmetadata
local function getcurrentprefixspec(default)
- -- todo: message
- return currentmetadata("kind") or "?", currentmetadata("name") or "?", default or "?"
+ local data = currentreference and currentreference.i
+ local metadata = data and data.metadata
+ return
+ metatadata and metadata.kind or "?",
+ metatadata and metadata.name or "?",
+ default or "?"
end
references.getcurrentprefixspec = getcurrentprefixspec
-function commands.getcurrentprefixspec(default)
- ctx_getreferencestructureprefix(getcurrentprefixspec(default))
-end
+-- implement {
+-- name = "getcurrentprefixspec",
+-- actions = { getcurrentprefixspec, context }, -- returns 3 arguments
+-- arguments = "string",
+-- }
+
+implement {
+ name = "getcurrentprefixspec",
+ actions = function(tag)
+ context("{%s}{%s}{%s}",getcurrentprefixspec(tag))
+ end,
+ arguments = "string",
+}
local genericfilters = { }
local userfilters = { }
@@ -1862,12 +2111,12 @@ filters.text = textfilters
filters.full = fullfilters
filters.section = sectionfilters
-local function filterreference(name,...) -- number page title ...
+local function filterreference(name,prefixspec,numberspec) -- number page title ...
local data = currentreference and currentreference.i -- maybe we should take realpage from here
if data then
if name == "realpage" then
local cs = references.analyze() -- normally already analyzed but also sets state
- context(tonumber(cs.realpage) or 0) -- todo, return and in command namespace
+ context(tonumber(cs.realpage) or 0)
else -- assumes data is table
local kind = type(data) == "table" and data.metadata and data.metadata.kind
if kind then
@@ -1877,7 +2126,7 @@ local function filterreference(name,...) -- number page title ...
if trace_referencing then
report_references("name %a, kind %a, using dedicated filter",name,kind)
end
- filter(data,name,...)
+ filter(data,name,prefixspec,numberspec)
elseif trace_referencing then
report_references("name %a, kind %a, using generic filter",name,kind)
end
@@ -1893,21 +2142,27 @@ local function filterreference(name,...) -- number page title ...
end
local function filterreferencedefault()
- return filterreference("default",getcurrentprefixspec(v_default))
+ return filterreference("default",getcurrentprefixspec("default"))
end
references.filter = filterreference
references.filterdefault = filterreferencedefault
-commands.filterreference = filterreference
-commands.filterdefaultreference = filterreferencedefault
+implement {
+ name = "filterreference",
+ actions = filterreference,
+ arguments = "string",
+}
-function commands.currentreferencedefault(tag)
- if not tag then
- tag = "default"
- end
- filterreference(tag,context_delayed(getcurrentprefixspec(tag)))
-end
+implement {
+ name = "filterdefaultreference",
+ actions = filterreference,
+ arguments = {
+ "string", -- 'default'
+ { { "*" } }, -- prefixspec
+ { { "*" } }, -- numberspec
+ }
+}
function genericfilters.title(data)
if data then
@@ -1927,12 +2182,12 @@ function genericfilters.text(data)
end
end
-function genericfilters.number(data,what,prefixspec) -- todo: spec and then no stopper
+function genericfilters.number(data,what,prefixspec,numberspec)
if data then
numberdata = lists.reordered(data) -- data.numberdata
if numberdata then
helpers.prefix(data,prefixspec)
- sections.typesetnumber(numberdata,"number",numberdata)
+ sections.typesetnumber(numberdata,"number",numberspec,numberdata)
else
local useddata = data.useddata
if useddata and useddata.number then
@@ -2056,12 +2311,71 @@ local specials = references.testspecials
-- pretty slow (progressively). In the pagebody one can best check the reference
-- real page to determine if we need contrastlocation as that is more lightweight.
-local function checkedpagestate(n,page)
- local r = referredpage(n)
+local function checkedpagestate(n,page,actions,position,spread)
local p = tonumber(page)
if not p then
return 0
- elseif p > r then
+ end
+ if position and #actions > 0 then
+ local i = actions[1].i -- brrr
+ if i then
+ local a = i.references
+ if a then
+ local x = a.x
+ local y = a.y
+ if x and y then
+ local jp = jobpositions.collected[position]
+ if jp then
+ local px = jp.x
+ local py = jp.y
+ local pp = jp.p
+ if p == pp then
+ -- same page
+ if py > y then
+ return 5 -- above
+ elseif py < y then
+ return 4 -- below
+ elseif px > x then
+ return 4 -- below
+ elseif px < x then
+ return 5 -- above
+ else
+ return 1 -- same
+ end
+ elseif spread then
+ if pp % 2 == 0 then
+ -- left page
+ if pp > p then
+ return 2 -- before
+ elseif pp + 1 == p then
+-- return 4 -- below (on right page)
+ return 5 -- above (on left page)
+ else
+ return 3 -- after
+ end
+ else
+ -- right page
+ if pp < p then
+ return 3 -- after
+ elseif pp - 1 == p then
+-- return 5 -- above (on left page)
+ return 4 -- below (on right page)
+ else
+ return 2 -- before
+ end
+ end
+ elseif pp > p then
+ return 2 -- before
+ else
+ return 3 -- after
+ end
+ end
+ end
+ end
+ end
+ end
+ local r = referredpage(n) -- sort of obsolete
+ if p > r then
return 3 -- after
elseif p < r then
return 2 -- before
@@ -2100,11 +2414,13 @@ local function setreferencerealpage(actions)
end
end
+references.setreferencerealpage = setreferencerealpage
+
-- we store some analysis data alongside the indexed array
-- at this moment only the real reference page is analyzed
-- normally such an analysis happens in the backend code
-function references.analyze(actions)
+function references.analyze(actions,position,spread)
if not actions then
actions = references.currentset
end
@@ -2119,32 +2435,56 @@ function references.analyze(actions)
elseif actions.external then
actions.pagestate = 0
else
- actions.pagestate = checkedpagestate(actions.n,realpage)
+ actions.pagestate = checkedpagestate(actions.n,realpage,actions,position,spread)
end
end
return actions
end
-function commands.referencepagestate(actions)
- if not actions then
- actions = references.currentset
- end
+local function referencepagestate(position,detail,spread)
+ local actions = references.currentset
if not actions then
- context(0)
+ return 0
else
if not actions.pagestate then
- references.analyze(actions) -- delayed unless explicitly asked for
--- print("NO STATE",actions.reference,actions.pagestate)
+ references.analyze(actions,position,spread) -- delayed unless explicitly asked for
+ end
+ local pagestate = actions.pagestate
+ if detail then
+ return pagestate
+ elseif pagestate == 4 then
+ return 2 -- compatible
+ elseif pagestate == 5 then
+ return 3 -- compatible
+ else
+ return pagestate
end
- context(actions.pagestate)
end
end
-function commands.referencerealpage(actions)
+implement {
+ name = "referencepagestate",
+ actions = { referencepagestate, context },
+ arguments = "string"
+}
+
+implement {
+ name = "referencepagedetail",
+ actions = { referencepagestate, context },
+ arguments = { "string", "boolean", "boolean" }
+}
+
+local function referencerealpage(actions)
actions = actions or references.currentset
- context(not actions and 0 or actions.realpage or setreferencerealpage(actions))
+ return not actions and 0 or actions.realpage or setreferencerealpage(actions)
end
+implement {
+ name = "referencerealpage",
+ actions = { referencerealpage, context },
+ arguments = "string"
+}
+
local plist, nofrealpages
local function realpageofpage(p) -- the last one counts !
@@ -2281,6 +2621,102 @@ function specials.section(var,actions)
end
end
+-- experimental:
+
+local p_splitter = lpeg.splitat(":")
+local p_lower = lpeg.patterns.utf8lower
+
+-- We can cache lowercased titles which saves a lot of time, but then
+-- we can better have a global cache with weak keys.
+
+-- local lowercache = table.setmetatableindex(function(t,k)
+-- local v = lpegmatch(p_lower,k)
+-- t[k] = v
+-- return v
+-- end)
+
+local lowercache = false
+
+local function locate(list,askedkind,askedname,pattern)
+ local kinds = lists.kinds
+ local names = lists.names
+ if askedkind and not kinds[askedkind] then
+ return false
+ end
+ if askedname and not names[askedname] then
+ return false
+ end
+ for i=1,#list do
+ local entry = list[i]
+ local metadata = entry.metadata
+ if metadata then
+ local found = false
+ if askedname then
+ local name = metadata.name
+ if name then
+ found = name == askedname
+ end
+ elseif askedkind then
+ local kind = metadata.kind
+ if kind then
+ found = kind == askedkind
+ end
+ end
+ if found then
+ local titledata = entry.titledata
+ if titledata then
+ local title = titledata.title
+ if title then
+ if lowercache then
+ found = lpegmatch(pattern,lowercache[title])
+ else
+ found = lpegmatch(pattern,lpegmatch(p_lower,title))
+ end
+ if found then
+ return {
+ inner = pattern,
+ kind = "inner",
+ reference = pattern,
+ i = entry,
+ p = "",
+ r = entry.references.realpage,
+ }
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+function functions.match(var,actions)
+ if not var.outer then
+ local operation = var.operation
+ if operation and operation ~= "" then
+ local operation = lpegmatch(p_lower,operation)
+ local list = lists.collected
+ local names = false
+ local kinds = false
+ local where, what = lpegmatch(p_splitter,operation)
+ if where and what then
+ local pattern = lpeg.finder(what)
+ return
+ locate(list,false,where,pattern)
+ or locate(list,where,false,pattern)
+ or { error = "no match" }
+ else
+ local pattern = lpeg.finder(operation)
+ -- todo: don't look at section and float in last pass
+ return
+ locate(list,"section",false,pattern)
+ or locate(list,"float",false,pattern)
+ or locate(list,false,false,pattern)
+ or { error = "no match" }
+ end
+ end
+ end
+end
+
-- needs a better split ^^^
-- done differently now:
@@ -2289,24 +2725,36 @@ function references.export(usedname) end
function references.import(usedname) end
function references.load (usedname) end
-commands.exportreferences = references.export
+implement { name = "exportreferences", actions =references.export }
-- better done here .... we don't insert/remove, just use a pointer
local prefixstack = { "" }
local prefixlevel = 1
-function commands.pushreferenceprefix(prefix)
+local function pushreferenceprefix(prefix)
prefixlevel = prefixlevel + 1
prefixstack[prefixlevel] = prefix
- context(prefix)
+ return prefix
end
-function commands.popreferenceprefix()
+local function popreferenceprefix()
prefixlevel = prefixlevel - 1
if prefixlevel > 0 then
- context(prefixstack[prefixlevel])
+ return prefixstack[prefixlevel]
else
report_references("unable to pop referenceprefix")
+ return ""
end
end
+
+implement {
+ name = "pushreferenceprefix",
+ actions = { pushreferenceprefix, context }, -- we can use setmacro
+ arguments = "string",
+}
+
+implement {
+ name = "popreferenceprefix",
+ actions = { popreferenceprefix, context }, -- we can use setmacro
+}
diff --git a/Master/texmf-dist/tex/context/base/strc-ref.mkvi b/Master/texmf-dist/tex/context/base/strc-ref.mkvi
index 91bcb619311..f5d0d1d7863 100644
--- a/Master/texmf-dist/tex/context/base/strc-ref.mkvi
+++ b/Master/texmf-dist/tex/context/base/strc-ref.mkvi
@@ -118,6 +118,11 @@
\unexpanded\def\reference {\dosingleargument\strc_references_full_reference} % never forgotten
\unexpanded\def\setreference {\dodoubleargument\strc_references_set_reference } %
+% maybe: \let\reference\textreference
+
+\unexpanded\def\showreferences
+ {\enabletrackers[nodes.references.show,nodes.destinations.show]}
+
%D These are implemented in a low level form as:
\unexpanded\def\strc_references_text_reference [#labels]{\strc_references_set_named_reference\s!text{#labels}{}}
@@ -140,13 +145,29 @@
\newcount\lastreferenceattribute
\newcount\lastdestinationattribute
-\def\dofinishfullreference#prefix#label{\normalexpanded{\ctxlatecommand{enhancereference("#prefix","#label")}}}
-\def\dofinishtextreference#prefix#label{\normalexpanded{\ctxlatecommand{enhancereference("#prefix","#label",{})}}}
+\def\strc_references_finish#prefix#reference#internal%
+ {\normalexpanded{\ctxlatecommand{enhancereference("#prefix","#reference")}}}
+
+\let\dofinishreference\strc_references_finish % used at lua end
+
+% This is somewhat tricky: we want to keep the reference with the following word but
+% that word should also hyphenate. We need to find a better way.
-\let\dofinishpagereference\dofinishfullreference
-\let\dofinishuserreference\dofinishfullreference
+% 0 = nothing
+% 1 = bind to following word
+
+\setnewconstant\c_strc_references_bind_state\plusone
+
+\def\strc_references_inject_before
+ {}
+
+\def\strc_references_inject_after
+ {\ifcase\c_strc_references_bind_state
+ % nothing
+ \or
+ \prewordbreak % to be tested: \removeunwantedspaces\permithyphenation
+ \fi}
-\def\dofinishsomereference#kind{\executeifdefined{dofinish#{kind}reference}\gobbletwoarguments}
\unexpanded\def\strc_references_set_named_reference
{\ifreferencing
@@ -195,30 +216,34 @@
% beware, the structures.references.set writes a
\setnextinternalreference
\strc_references_start_destination_nodes
- \ctxcommand{setreferenceattribute("\currentreferencekind", "\referenceprefix","\currentreferencelabels",
- {
- references = {
- internal = \nextinternalreference,
- block = "\currentsectionblock",
- section = structures.sections.currentid(),
- },
- metadata = { % we could assume page to have no metadata
- kind = "#kind", % \currentreferencekind
- \ifx\currentreferencekind\s!page\else
- catcodes = \the\catcodetable,
- xmlroot = \ifx\currentreferencecoding\s!xml "\xmldocument"\else nil\fi, % only useful when text
- \fi
- },
+ \clf_setreferenceattribute
+ {%
+ references {%
+ internal \nextinternalreference
+ % block {\currentsectionblock}%
+ view {\interactionparameter\c!focus}%
+ prefix {\referenceprefix}%
+ reference {\currentreferencelabels}%
+ }%
+ metadata {%
+ kind {\currentreferencekind}%
+ \ifx\currentreferencekind\s!page\else
+ \ifx\currentreferencecoding\s!xml
+ xmlroot {\xmldocument}%
+ \fi
+ catcodes \catcodetable
+ \fi
+ }%
\ifx\currentreferencedata\empty\else
- entries = {
- text = \!!bs\currentreferencedata\!!es
- },
+ entries {%
+ text {\currentreferencedata}%
+ }%
\fi
\ifx\currentreferenceuserdata\empty\else
- userdata = structures.helpers.touserdata(\!!bs\detokenize{#userdata}\!!es)
+ userdata {\detokenize{#userdata}}%
\fi
- },"\interactionparameter\c!focus")
- }%
+ }%
+ \relax
\strc_references_stop_destination_nodes
\fi
\else
@@ -229,10 +254,11 @@
\xdef\currentdestinationattribute{\number\lastdestinationattribute}%
% will become an option:
\ifnum\lastdestinationattribute>\zerocount
+ \strc_references_inject_before % new
\dontleavehmode\hbox attr \destinationattribute\lastdestinationattribute\bgroup
\strc_references_flush_destination_nodes
\egroup
- \prewordbreak % new
+ \strc_references_inject_after % new
\fi}
\def\strc_references_set_page_only_destination_attribute#labels% could in fact be fully expandable
@@ -243,19 +269,21 @@
\lastdestinationattribute\attributeunsetvalue
\else
\strc_references_start_destination_nodes
-\setnextinternalreference
- \ctxcommand{setreferenceattribute("\s!page", "\referenceprefix","\currentreferencelabels",
- {
- references = {
- internal = \nextinternalreference,
- block = "\currentsectionblock",
- section = structures.sections.currentid(),
- },
- metadata = {
- kind = "page",
- },
- },"\interactionparameter\c!focus")
- }%
+ \setnextinternalreference
+ \clf_setreferenceattribute
+ {%
+ references {%
+ internal \nextinternalreference
+ % block {\currentsectionblock}%
+ view {\interactionparameter\c!focus}%
+ prefix {\referenceprefix}%
+ reference {\currentreferencelabels}%
+ }%
+ metadata {%
+ kind {page}%
+ }%
+ }%
+ \relax
\strc_references_stop_destination_nodes
\fi
\else
@@ -269,28 +297,28 @@
\setnextinternalreference
\edef\m_strc_references_user{#user}%
\edef\m_strc_references_text{#text}%
- \ctxcommand{setreferenceattribute("\s!full", "\referenceprefix","#labels",
- {
- references = {
- internal = \nextinternalreference,
- block = "\currentsectionblock",
- section = structures.sections.currentid(),
- },
- metadata = {
- kind = "\s!full",
- },
- \ifx\m_strc_references_text\empty \else
- entries = {
- text = \!!bs\m_strc_references_text\!!es
- },
- \fi
- \ifx\m_strc_references_user\empty \else
- userdata = {
- \m_strc_references_user
- }
- \fi
- },"\interactionparameter\c!focus")
- }%
+ \clf_setreferenceattribute
+ {%
+ references {%
+ internal \nextinternalreference
+ % block {\currentsectionblock}%
+ view {\interactionparameter\c!focus}%
+ prefix {\referenceprefix}%
+ reference {#labels}%
+ }%
+ metadata {%
+ kind {\s!full}%
+ }%
+ \ifx\m_strc_references_text\empty \else
+ entries {%
+ text {\m_strc_references_text}%
+ }%
+ \fi
+ \ifx\m_strc_references_user\empty \else
+ userdata {\m_strc_references_user}% \detokenize\expandafter{\normalexpanded{...}}
+ \fi
+ }%
+ \relax
\strc_references_stop_destination_nodes
\else
\setbox\b_strc_destination_nodes\emptyhbox
@@ -300,10 +328,11 @@
\xdef\currentdestinationattribute{\number\lastdestinationattribute}%
% will become an option:
\ifnum\lastdestinationattribute>\zerocount
+ \strc_references_inject_before % new
\dontleavehmode\hbox attr \destinationattribute\lastdestinationattribute\bgroup
\strc_references_flush_destination_nodes
\egroup
- \prewordbreak % new
+ \strc_references_inject_after % new
\fi}
\unexpanded\def\strc_references_direct_full
@@ -345,17 +374,19 @@
\def\strc_references_set_simple_page_reference#label%
{\iflocation
\strc_references_start_destination_nodes
- \ctxcommand{setreferenceattribute("\s!page", "\referenceprefix","#label",
- {
- references = {
- % block = "\currentsectionblock",
- % section = structures.sections.currentid(),
- },
- metadata = { % we could assume page to have no metadata
- kind = "\s!page",
- },
- },"\interactionparameter\c!focus")
- }%
+ \clf_setreferenceattribute
+ {%
+ references {%
+ % block {\currentsectionblock}%
+ view {\interactionparameter\c!focus}%
+ prefix {\referenceprefix}%
+ reference {#label}%
+ }%
+ metadata {%
+ kind {\s!page}%
+ }%
+ }%
+ \relax
\strc_references_stop_destination_nodes
\xdef\currentdestinationattribute{\number\lastdestinationattribute}%
\else
@@ -365,7 +396,15 @@
\def\strc_references_get_simple_page_reference#label%
{\iflocation
- \ctxcommand{injectreference("\referenceprefix","#label",\number\ht\strutbox,\number\dp\strutbox,\extrareferencearguments)}%
+ \clf_injectreference
+ {\referenceprefix}%
+ {#label}%
+ {%
+ height \ht\strutbox
+ depth \dp\strutbox
+ \extrareferencearguments
+ }%
+ \relax
\xdef\currentreferenceattribute{\number\lastreferenceattribute}%
\else
\xdef\currentreferenceattribute{\number\attributeunsetvalue}%
@@ -505,9 +544,6 @@
\newcount\referencehastexstate % set in backend
-\def\referencepagestate{\ctxcommand{referencepagestate()}}
-\def\referencerealpage {\ctxcommand{referencerealpage ()}}
-
% referencepagestate:
%
% 0 = no page ref, 1=same page, 2=before, 3=after
@@ -595,13 +631,13 @@
{\dodoubleempty\strc_references_define_reference}
\def\strc_references_define_reference[#name][#specification]%
- {\ctxcommand{definereference("\referenceprefix","#name",\!!bs\detokenize{#specification}\!!es)}}
+ {\clf_definereference{\referenceprefix}{#name}{\detokenize{#specification}}}
\unexpanded\def\resetreference[#name]%
- {\ctxcommand{resetreference("\referenceprefix","#name")}}
+ {\clf_resetreference{\referenceprefix}{#name}}
\def\setpagereference#name#specification% hm,. low level ?
- {\ctxcommand{definereference("","#name",\!!bs\v!page(\luaescapestring{#specification})\!!es)}}
+ {\clf_definereference{}{#name}{\v!page(\detokenize{#specification}}} % is detokenize needed here?
%D Chained references are defined as:
%D
@@ -631,17 +667,19 @@
\newconditional\gotonewwindow \setfalse\gotonewwindow
\def\expandtexincurrentreference % will happen in lua some time
- {\ifcase\referencehastexstate\else\ctxcommand{expandcurrentreference()}\fi}
+ {\ifcase\referencehastexstate\else\clf_expandcurrentreference\fi}
-\def\expandreferenceoperation#tag#content{\ctxcommand{setreferenceoperation(#tag,\!!bs#content\!!es)}}
-\def\expandreferencearguments#tag#content{\ctxcommand{setreferencearguments(#tag,\!!bs#content\!!es)}}
+\def\expandreferenceoperation#tag#content{\clf_setreferenceoperation#tag{#content}}
+\def\expandreferencearguments#tag#content{\clf_setreferencearguments#tag{#content}}
-\def\doifreferencefoundelse#labels#yes#nop%
- {\ctxcommand{doifelsereference("\referenceprefix",\!!bs#labels\!!es,\luaconditional\highlighthyperlinks,\luaconditional\gotonewwindow)}%
+\def\doifelsereferencefound#label#yes#nop%
+ {\clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}%
{\expandtexincurrentreference
#yes}%
{#nop}}
+\let\doifreferencefoundelse \doifelsereferencefound
+
%D The tester only splits the reference in components but does
%D not look into them. The following macro does a preroll and
%D determines for instance the current real reference pagenumber.
@@ -747,14 +785,14 @@
{\global\advance\locationcount\plusone}
\def\setnextinternalreferences#kind#name% plural
- {\ctxcommand{setnextinternalreference("#kind","#name")}}
+ {\clf_setnextinternalreference{#kind}{#name}}
\def\getinternalorderreference#kind#name%
- {\ctxcommand{currentreferenceorder("#kind","#name")}}
+ {\clf_currentreferenceorder{#kind}{#name}}
\def\thisissomeinternal#kind#name% only for old time sake
{\begingroup
- \ctxcommand{setinternalreference("","#kind:#name")}%
+ \clf_setinternalreference reference {#kind:#name}\relax
\hbox attr \destinationattribute\lastdestinationattribute{}%
\endgroup}
@@ -817,7 +855,7 @@
\appendtoks
\edef\p_export{\referencingparameter\c!export}%
\ifx\p_export\v!yes
- \ctxcommand{exportreferences()}%
+ \clf_exportreferences
\fi
\to \everygoodbye
@@ -832,16 +870,16 @@
% {\popmacro\referenceprefix}
\unexpanded\def\globalpushreferenceprefix#prefix%
- {\xdef\referenceprefix{\ctxcommand{pushreferenceprefix("#prefix")}}}
+ {\xdef\referenceprefix{\clf_pushreferenceprefix{#prefix}}}
\unexpanded\def\globalpopreferenceprefix
- {\xdef\referenceprefix{\ctxcommand{popreferenceprefix()}}}
+ {\xdef\referenceprefix{\clf_popreferenceprefix}}
\unexpanded\def\pushreferenceprefix#prefix%
- {\edef\referenceprefix{\ctxcommand{pushreferenceprefix("#prefix")}}}
+ {\edef\referenceprefix{\clf_pushreferenceprefix{#prefix}}}
\unexpanded\def\popreferenceprefix
- {\edef\referenceprefix{\ctxcommand{popreferenceprefix()}}}
+ {\edef\referenceprefix{\clf_popreferenceprefix}}
\def\m_strc_references_prefix_yes{+}
\def\m_strc_references_prefix_nop{-}
@@ -931,15 +969,15 @@
\ifdefined\over \let\normalmathover \over \unexpanded\def\over {\mathortext\normalmathover \strc_references_about} \else \let\over \strc_references_about \fi
\to \everydump
- \def\filterreference #key{\ctxcommand{filterreference("#key")}} % no checking, expanded
-\unexpanded\def\getreferenceentry#key{\ctxcommand{filterreference("#key")}} % no checking, unexpanded
+ \def\filterreference #key{\clf_filterreference{#key}} % no checking, expanded
+\unexpanded\def\getreferenceentry#key{\clf_filterreference{#key}} % no checking, unexpanded
-\def\currentreferencenumber {\filterreference{number}}
-\def\currentreferencepage {\filterreference{page}}
-\def\currentreferencetitle {\filterreference{title}}
-\def\currentreferencetext {\filterreference{text}}
-\def\currentreferencedefault {\filterreference{default}}
-\def\currentreferencerealpage{\filterreference{realpage}}
+\def\currentreferencenumber {\clf_filterreference{number}}
+\def\currentreferencepage {\clf_filterreference{page}}
+\def\currentreferencetitle {\clf_filterreference{title}}
+\def\currentreferencetext {\clf_filterreference{text}}
+\def\currentreferencedefault {\clf_filterreference{default}}
+\def\currentreferencerealpage{\clf_filterreference{realpage}}
%D The most straightforward way of retrieving references is
%D using \type{\ref}.
@@ -949,7 +987,7 @@
\def\strc_references_get_reference[#key][#label]% #key = number page title text default realpage ...
{\ifsecondargument
- \doifreferencefoundelse{#label}{\ctxcommand{filterreference("#key")}}\dummyreference
+ \doifelsereferencefound{#label}{\clf_filterreference{#key}}\dummyreference
\else
\dummyreference
\fi}
@@ -965,7 +1003,7 @@
\let\\\space
\postponenotes % might go
\referencingparameter\c!left
- \doifreferencefoundelse{#label}
+ \doifelsereferencefound{#label}
{\goto{\limitatetext\currentreferencetitle{\referencingparameter\c!width}\unknown}[#label]}% not so efficient (dup lookup)
{}% todo
\flushnotes % might go
@@ -984,44 +1022,151 @@
%D ... \atpage[someref] ...
%D \stoptyping
-% 0 = unknown
-% 1 = same
-% 2 = before
-% 3 = after
+% standard detail
+%
+% 0 = unknown unknown
+% 1 = same on same page
+% 2 = before preceding page
+% 3 = after following page
+%
+% 4 = above above on same page
+% 5 = below below on same page
-\def\strc_references_by_reference_page_state#unknown#before#current#after%
- {\ifcase\referencepagestate\space#unknown\or#current\or#before\or#after\fi}
+% todo: optimize for use in pagebody
+% todo: maybe make it optional
-% \unexpanded\def\somewhere#backward#foreward#dummy[#label]% #dummy gobbles space around #foreward
-% {\doifreferencefoundelse{#label}% usage needs checking (useless)
-% {\goto{\strc_references_by_reference_page_state{#label}{#backward}{}{#foreward}}[#label]}
-% {[#label]}}
+% \setuppagenumbering[alternative=doublesided]
+% \setupreferencing [doublesided=no] % yes is default
%
-% better:
+% \somewhere{backward}{foreward}[label]
+% \someplace{preceding}{backward}{current}{foreward}{following}[label]
+% \atpage[#label]
+% \doifcheckedpagestate{label}{preceding}{backward}{current}{foreward}{following}{otherwise}
+%
+% \dorecurse {20} {
+% \placefigure[here][fig:#1]{}{\externalfigure[dummy]}
+% \dorecurse {20} {
+% ##1: \atpage[fig:##1] /
+% \doifcheckedpagestate
+% {fig:##1}
+% {preceding}{backward}{current}{foreward}{following}
+% {otherwise}
+% }
+% }
+
+\newcount \nofreferencestates
+\newconditional\pagestatespread
-\unexpanded\def\somewhere#backward#foreward#dummy[#label]% #dummy gobbles space around #foreward
- {\doifreferencefoundelse{#label}%
- {\strc_references_by_reference_page_state{#label}{\goto{#backward}[#label]}{}{\goto{#foreward}[#label]}}
- {[#label]}}
+\appendtoks
+ \doifelse{\referencingparameter\c!doublesided}\v!yes\settrue\setfalse\pagestatespread
+\to \everysetupreferencing
-\unexpanded\def\atpage[#label]% todo
- {\doifreferencefoundelse{#label}% kind of inefficient as \goto also analyzes
- {\goto
- {\strc_references_by_reference_page_state
- {\labeltexts\v!page\dummyreference}%
- {\labeltext\v!hencefore}%
- {\labeltexts\v!atpage\currentreferencepage}%
- {\labeltext\v!hereafter}}%
- [#label]}
- {[#label]}}
+\setupreferencing
+ [\c!doublesided=\v!yes]
+
+\def\referencepagestate
+ {\numexpr\clf_referencepagestate
+ {rst::\number\nofreferencestates}%
+ \relax}
+
+\def\referencepagedetail
+ {\numexpr\clf_referencepagestate
+ {rst::\number\nofreferencestates}%
+ true %
+ \ifconditional\pagestatespread false\ifdoublesided true\else false\fi\fi
+ \relax}
+
+\def\referencerealpage
+ {\clf_referencerealpage}
+
+\unexpanded\def\tracedpagestate
+ {{\blue\tttf(\ifcase\referencepagedetail unknown\or same\or previous\or next\or above\or below\else unknown\fi)}}
+
+\unexpanded\def\markreferencepage
+ {\dontleavehmode\begingroup
+ \iftrialtypesetting
+ % issue warning that not stable
+ \else
+ % needs checking ... but probably never in trialmode
+ \global\advance\nofreferencestates\plusone
+ \xypos{rst::\number\nofreferencestates}%
+ % \tracedpagestate
+ \fi
+ \endgroup}
+
+\unexpanded\def\doifcheckedpagestate#label% #preceding#backward#current#foreward#following#otherwise%
+ {\doifelsereferencefound{#label}\strc_references_handle_page_state_yes\strc_references_handle_page_state_nop}
+
+\let\strc_references_handle_page_state_nop\sixthofsixarguments
+
+\def\strc_references_handle_page_state_yes
+ {\markreferencepage
+ \ifcase\referencepagedetail
+ \expandafter\sixthofsixarguments \or
+ \expandafter\thirdofsixarguments \or
+ \expandafter\firstofsixarguments \or
+ \expandafter\fifthofsixarguments \or
+ \expandafter\secondofsixarguments\or
+ \expandafter\fourthofsixarguments\else
+ \expandafter\sixthofsixarguments \fi}
\unexpanded\def\referencesymbol
- {\hbox{\strut\high
- {\setupsymbolset[\interactionparameter\c!symbolset]%
- \symbol[\strc_references_by_reference_page_state\v!somewhere\v!nowhere\v!previous\v!next]}}}
+ {\hbox\bgroup
+ \strut
+ \markreferencepage
+ \high
+ {\setupsymbolset[\interactionparameter\c!symbolset]%
+ \symbol[\ifcase\referencepagedetail\v!somewhere\or\v!nowhere\or\v!previous\or\v!next\or\v!previous\or\v!next\else\v!somewhere\fi]}%
+ \egroup}
+
+%D Hereafter the \type {\ignorespaces} binds the state node to next character (more likely
+%D than a preceding one) and one can always add an explicit space.
+
+\unexpanded\def\somewhere#backward#foreward#dummy[#label]% #dummy gobbles space around #foreward
+ {\doifcheckedpagestate{#label}%
+ {\goto{#backward}[#label]}%
+ {\goto{#backward}[#label]}%
+ {\ignorespaces}%
+ {\goto{#foreward}[#label]}%
+ {\goto{#foreward}[#label]}%
+ {#label}}%
+
+\unexpanded\def\someplace#preceding#backward#current#foreward#following#dummy[#label]% #dummy gobbles space around #foreward
+ {\doifcheckedpagestate{#label}%
+ {\doifelsenothing{#preceding}{\goto{#preceding}[#label]}\ignorespaces}%
+ {\doifelsenothing {#backward}{\goto {#backward}[#label]}\ignorespaces}%
+ {\doifelsenothing {#current}{\goto {#current}[#label]}\ignorespaces}%
+ {\doifelsenothing {#foreward}{\goto {#foreward}[#label]}\ignorespaces}%
+ {\doifelsenothing{#following}{\goto{#following}[#label]}\ignorespaces}%
+ {#label}}
+
+\unexpanded\def\atpage[#label]% todo
+ {\doifcheckedpagestate{#label}%
+ {\goto{\labeltext \v!precedingpage }[#label]}%
+ {\goto{\labeltext \v!hencefore }[#label]}%
+ {\ignorespaces}%
+ {\goto{\labeltext \v!hereafter }[#label]}%
+ {\goto{\labeltext \v!followingpage }[#label]}%
+ {\goto{\labeltexts\v!page\dummyreference}[#label]}}
+
+% Someone requested this but in retrospect didn't need it so we keep it as example.
+% Beware: a node is injected which is why we add ignorespaces!
+%
+% \unexpanded\def\strc_references_conditional#action#text[#condition]#dummy[#label]%
+% {\doifcheckedpagestate{#label}%
+% {\doifelse{#condition}\v!precedingpage{#action{#text}[#label]}\ignorespaces}%
+% {\doifelse{#condition}\v!hencefore {#action{#text}[#label]}\ignorespaces}%
+% {\doifelse{#condition}\v!current {#action{#text}[#label]}\ignorespaces}%
+% {\doifelse{#condition}\v!hereafter {#action{#text}[#label]}\ignorespaces}%
+% {\doifelse{#condition}\v!followingpage{#action{#text}[#label]}\ignorespaces}%
+% {#label}}
+%
+% \unexpanded\def\conditionalat {\strc_references_conditional\at}
+% \unexpanded\def\conditionalin {\strc_references_conditional\in}
+% \unexpanded\def\conditionalabout{\strc_references_conditional\about}
-%D The other alternatives just conform their names: only the
-%D label, only the text, or the label and the text.
+%D The other alternatives just conform their names: only the label, only the text, or the
+%D label and the text.
% \dounknownreference -> \dummyreference
@@ -1044,11 +1189,11 @@
\setvalue{\??referencinginteraction\v!all}%
{\the\leftreferencetoks
- \doifsometokselse\leftreferencetoks \leftofreferencecontent \donothing
+ \doifelsesometoks\leftreferencetoks \leftofreferencecontent \donothing
\leftofreference
\currentreferencecontent
\rightofreference
- \doifsometokselse\rightreferencetoks\rightofreferencecontent\donothing
+ \doifelsesometoks\rightreferencetoks\rightofreferencecontent\donothing
\the\rightreferencetoks}
\setvalue{\??referencinginteraction\v!label}%
@@ -1108,14 +1253,21 @@
\let\rightofreferencecontent\empty
\fi
% inefficient: double resolve
- \doifreferencefoundelse{#label} % we need to resolve the text
+ \doifelsereferencefound{#label} % we need to resolve the text
{\goto{\referencesequence}[#label]}
{\let\currentreferencecontent\dummyreference
\goto{\referencesequence}[#label]}%
\strc_references_stop_goto}
-\unexpanded\def\strc_references_in{\strc_references_start_goto\let\currentreferencecontent\currentreferencedefault\strc_references_pickup_goto}
-\unexpanded\def\strc_references_at{\strc_references_start_goto\let\currentreferencecontent\currentreferencepage \strc_references_pickup_goto}
+\unexpanded\def\strc_references_in
+ {\strc_references_start_goto
+ \let\currentreferencecontent\currentreferencedefault
+ \strc_references_pickup_goto}
+
+\unexpanded\def\strc_references_at
+ {\strc_references_start_goto
+ \let\currentreferencecontent\currentreferencepage
+ \strc_references_pickup_goto}
%D \macros
%D {definereferenceformat}
@@ -1226,7 +1378,7 @@
\def\autoreferencelabeltextflag{*} % a proper key like 'auto' or 'name' can clash with a label key
\unexpanded\def\autoreferencelabeltext
- {\ctxcommand{getcurrentreferencemetadata("name")}}
+ {\clf_getcurrentreferencemetadata{name}}
% \starttext
% \definereferenceformat[inxx] [left=(,right=),text=txt]
@@ -1271,7 +1423,9 @@
\newconditional\uselocationstrut \settrue\uselocationstrut
\def\extrareferencearguments
- {\luaconditional\highlighthyperlinks,\luaconditional\gotonewwindow,"\currentviewerlayer"}
+ {highlight \luaconditional\highlighthyperlinks\space
+ newwindow \luaconditional\gotonewwindow\space
+ layer {\currentviewerlayer}}
\unexpanded\def\directgoto
{\ifconditional\uselocationstrut
@@ -1303,7 +1457,15 @@
\attribute\referenceattribute\attributeunsetvalue
\global\lastsavedreferenceattribute\attributeunsetvalue
\iflocation
- \ctxcommand{injectreference("\referenceprefix","#label",\number\ht\strutbox,\number\dp\strutbox,\extrareferencearguments)}%
+ \clf_injectreference
+ {\referenceprefix}%
+ {#label}%
+ {%
+ height \ht\strutbox
+ depth \dp\strutbox
+ \extrareferencearguments
+ }%
+ \relax
\setlocationattributes
\setstrut % can be option
\global\lastsavedreferenceattribute\lastreferenceattribute
@@ -1322,7 +1484,15 @@
\global\lastsavedreferenceattribute\attributeunsetvalue
\attribute\referenceattribute\attributeunsetvalue
\iflocation
- \ctxcommand{injectreference("\referenceprefix","#label",\number\dimexpr\interactionparameter\c!height\relax,\number\dimexpr\interactionparameter\c!depth\relax,\extrareferencearguments)}%
+ \clf_injectreference
+ {\referenceprefix}%
+ {#label}%
+ {%
+ height \dimexpr\interactionparameter\c!height\relax
+ depth \dimexpr\interactionparameter\c!depth \relax
+ \extrareferencearguments
+ }%
+ \relax
\setlocationattributes
\attribute\referenceattribute\lastreferenceattribute
\global\lastsavedreferenceattribute\lastreferenceattribute
@@ -1341,9 +1511,12 @@
\global\lastsavedreferenceattribute\attributeunsetvalue
\attribute\referenceattribute\attributeunsetvalue
\iflocation
- \ctxcommand{doifelsereference("\referenceprefix","#label",\extrareferencearguments)}%
+ \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}%
{\expandtexincurrentreference
- \ctxcommand{injectcurrentreference(\number\ht\strutbox,\number\dp\strutbox)}%
+ \clf_injectcurrentreferencehtdp
+ \ht\strutbox
+ \dp\strutbox
+ \relax
\setlocationattributes
\setstrut % can be option
\global\lastsavedreferenceattribute\lastreferenceattribute
@@ -1358,15 +1531,52 @@
%\egroup\unhbox\referencebox}
\endgroup}
+\unexpanded\def\startgoto[#label]%
+ {\dontleavehmode
+ \begingroup
+ \iflocation
+ \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}%
+ {\expandafter\startgoto_yes}%
+ {\expandafter\startgoto_nop}%
+ \else
+ \expandafter\startgoto_nop
+ \fi}
+
+\unexpanded\def\startgoto_nop
+ {\let\stopgoto\stopgoto_nop}
+
+\unexpanded\def\stopgoto_nop
+ {\endgroup}
+
+\unexpanded\def\startgoto_yes
+ {\expandtexincurrentreference
+ \clf_injectcurrentreferencehtdp
+ \ht\strutbox
+ \dp\strutbox
+ \relax
+ \setlocationattributes
+ \setstrut % can be option
+ \global\lastsavedreferenceattribute\lastreferenceattribute
+ \attribute\referenceattribute\lastreferenceattribute
+ \dostarttagged\t!link\empty
+ \let\stopgoto\stopgoto_yes}
+
+\unexpanded\def\stopgoto_yes
+ {\dostoptagged
+ \endgroup}
+
\def\dogotohtdp#content#dummy[#label]% dummy gobbles spaces
{\dontleavehmode
\begingroup
\global\lastsavedreferenceattribute\attributeunsetvalue
\attribute\referenceattribute\attributeunsetvalue
\iflocation
- \ctxcommand{doifelsereference("\referenceprefix","#label",\extrareferencearguments)}%
+ \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}%
{\expandtexincurrentreference
- \ctxcommand{injectcurrentreference(\number\dimexpr\interactionparameter\c!height\relax,\number\dimexpr\interactionparameter\c!depth\relax)}%
+ \clf_injectcurrentreferencehtdp
+ \dimexpr\interactionparameter\c!height\relax
+ \dimexpr\interactionparameter\c!depth \relax
+ \relax
\setlocationattributes
\global\lastsavedreferenceattribute\lastreferenceattribute
\attribute\referenceattribute\lastreferenceattribute
@@ -1385,7 +1595,11 @@
\global\lastsavedreferenceattribute\attributeunsetvalue
\attribute\referenceattribute\attributeunsetvalue
\iflocation
- \ctxcommand{injectreference("\referenceprefix","#label",nil,nil,\extrareferencearguments)}%
+ \clf_injectreference
+ {\referenceprefix}%
+ {#label}%
+ {\extrareferencearguments}%
+ \relax
\setlocationattributes
\global\lastsavedreferenceattribute\lastreferenceattribute
\dostarttagged\t!link\empty
@@ -1402,7 +1616,11 @@
\global\lastsavedreferenceattribute\attributeunsetvalue
\attribute\referenceattribute\attributeunsetvalue
\iflocation
- \ctxcommand{injectreference("\referenceprefix","#label",nil,nil,\extrareferencearguments)}%
+ \clf_injectreference
+ {\referenceprefix}%
+ {#label}%
+ {\extrareferencearguments}%
+ \relax
\setlocationcolorspec{#resolver}% no consequence for strut
\global\lastsavedreferenceattribute\lastreferenceattribute
\dostarttagged\t!link\empty
@@ -1419,7 +1637,11 @@
\global\lastsavedreferenceattribute\attributeunsetvalue
\attribute\referenceattribute\attributeunsetvalue
\iflocation
- \ctxcommand{injectreference("\referenceprefix","#label",nil,nil,\extrareferencearguments)}%
+ \clf_injectreference
+ {\referenceprefix}%
+ {#label}%
+ {\extrareferencearguments}%
+ \relax
\global\lastsavedreferenceattribute\lastreferenceattribute
\dostarttagged\t!link\empty
\hbox attr \referenceattribute \lastreferenceattribute {#content}%
@@ -1435,9 +1657,9 @@
\global\lastsavedreferenceattribute\attributeunsetvalue
\attribute\referenceattribute\attributeunsetvalue
\iflocation
- \ctxcommand{doifelsereference("\referenceprefix","#label",\extrareferencearguments)}%
+ \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}%
{\expandtexincurrentreference
- \ctxcommand{injectcurrentreference(nil,nil)}%
+ \clf_injectcurrentreference
\setlocationattributes
\global\lastsavedreferenceattribute\lastreferenceattribute
\dostarttagged\t!link\empty
@@ -1457,8 +1679,8 @@
\ht\scratchbox#height%
\global\lastsavedreferenceattribute\attributeunsetvalue
\attribute\referenceattribute\attributeunsetvalue
- \ctxcommand{doifelsereference("\referenceprefix","#label",\extrareferencearguments)}%
- {\ctxcommand{injectcurrentreference(nil,nil)}%
+ \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}%
+ {\clf_injectcurrentreference
\global\lastsavedreferenceattribute\lastreferenceattribute
\hbox attr \referenceattribute \lastreferenceattribute {\box\scratchbox}}
{\box\scratchbox}%
@@ -1520,13 +1742,16 @@
\let\useexternaldocument\usefile
\def\strc_references_use_url[#label][#url][#file][#description]%
- {\ctxcommand{useurl("#label",\!!bs\detokenize{#url}\!!es,\!!bs\detokenize{#file}\!!es,\!!bs\detokenize{#description}\!!es)}}
+ {\clf_useurl{#label}{\detokenize{#url}}{\detokenize{#file}}{\detokenize{#description}}}
\def\strc_references_use_file[#label][#file][#description]%
- {\ctxcommand{usefile("#label",\!!bs\detokenize{#file}\!!es,\!!bs\detokenize{#description}\!!es)}}
+ {\clf_usefile{#label}{\detokenize{#file}}{\detokenize{#description}}}
-\def\doifurldefinedelse #label{\ctxcommand{doifurldefinedelse ("#label")}}
-\def\doiffiledefinedelse#label{\ctxcommand{doiffiledefinedelse("#label")}}
+\def\doifelseurldefined #label{\clf_doifelseurldefined {#label}}
+\def\doifelsefiledefined#label{\clf_doifelsefiledefined{#label}}
+
+\let\doifurldefinedelse \doifelseurldefined
+\let\doiffiledefinedelse\doifelsefiledefined
%D \macros
%D {url,setupurl}
@@ -1557,7 +1782,7 @@
{\dontleavehmode
\begingroup
\useurlstyleandcolor\c!style\c!color
- \hyphenatedurl{\ctxcommand{geturl("#label")}}%
+ \hyphenatedurl{\clf_geturl{#label}}%
\endgroup}
%D This macro is hooked into a support macro, and thereby
@@ -1588,7 +1813,7 @@
\def\strc_references_do_special_from[#label]%
{\dontleavehmode
- \goto{\ctxcommand{from("#label")}}[fileorurl(#label)]}
+ \goto{\clf_from{#label}}[fileorurl(#label)]}
\def\dofromurldescription#content% called at the lua end
{#content}
@@ -1633,13 +1858,13 @@
{\dotripleargument\strc_references_define_program}
\def\strc_references_define_program[#name][#program][#description]%
- {\ctxcommand{defineprogram("#name",\!!bs#program\!!es,\!!bs#description\!!es)}}
+ {\clf_defineprogram{#name}{#program}{#description}}
\def\program[#name]% incompatible, more consistent, hardy used anyway
{\dontleavehmode
\begingroup
\useprogramsstyleandcolor\c!style\c!color
- \ctxcommand{getprogram("#name","\directprogramsparameter\c!alternative","\directprogramsparameter\c!space")}%
+ \clf_getprogram{#name}%
\endgroup}
%D As we can see, we directly use the special reference
@@ -1728,7 +1953,7 @@
%D
%D Only when \type {text} is not empty, a space is inserted.
-\def\dotextprefix#text%
+\unexpanded\def\dotextprefix#text%
{\begingroup
\setbox\scratchbox\hbox{#text}% to be solved some day
\ifdim\wd\scratchbox>\zeropoint
@@ -1864,14 +2089,24 @@
\installcorenamespace{referencingprefix}
\def\getreferencestructureprefix#kind#name#category% name will change
- {{
- prefix = "\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefix",
- separatorset = "\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixseparatorset",
- conversion = "\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixconversion",
- conversionset = "\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixconversionset",
- set = "\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixset",
- segments = "\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixsegments",
- connector = \!!bs\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixconnector\!!es,
+ {{%
+ prefix {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefix}%
+ separatorset {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixseparatorset}%
+ conversion {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixconversion}%
+ conversionset {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixconversionset}%
+ starter {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixstarter}%
+ stopper {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixstopper}%
+ set {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixset}%
+ segments {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixsegments}%
+ connector {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixconnector}%
+ }%
+ {%
+ separatorset {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberseparatorset}%
+ conversion {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberconversion}%
+ conversionset {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberconversionset}%
+ starter {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberstarter}%
+ stopper {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberstopper}%
+ segments {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numbersegments}%
}}
\unexpanded\def\setupreferencestructureprefix
@@ -1893,16 +2128,11 @@
\csname \??referencingprefix:#category#parameter\endcsname
\fi\fi\fi}
-% \def\currentreferencedefault
-% {\ctxcommand{filterdefaultreference()}}
-
-\def\currentreferencedefault
- {\ctxcommand{filterreference("\s!default",\ctxcommand{getcurrentprefixspec("\s!default")})}}
-
-% needs testing
-%
-% \def\currentreferencedefault
-% {\ctxcommand{currentreferencedefault()}}
+\def\currentreferencedefault % for some reason we need to explicitly expand
+ {\normalexpanded{\noexpand\clf_filterdefaultreference
+ {\s!default}%
+ \noexpand\getreferencestructureprefix\clf_getcurrentprefixspec{\s!default}% returns #kind#name#category
+ \relax}}
%D Not all support is visible by looking at the \TEX\ code; here is one of those:^
%D
@@ -1920,6 +2150,55 @@
%D \stopinteractionmenu
%D \stoptyping
+%D Relatively new:
+%D
+%D \starttyping
+%D \chapter{The never ending story}
+%D
+%D \section{An ending story}
+%D
+%D \in{chapter}[match(complex bibliographies)]
+%D \in{chapter}[match(never ending)]
+%D \in{chapter}[match(ending)]
+%D \in{chapter}[match(chapter:never ending)]
+%D \in{chapter}[match(chapter:ending)]
+%D \in{section}[match(section:ending)]
+%D \in{figure}[match(float:mess)]
+%D \in{figure}[match(figure:mess)]
+%D \in{figure (not found)}[match(section:mess)]
+%D \in{figure (not found)}[match(section:xxxx)]
+%D \in{figure}[match(mess)]
+%D
+%D \placefigure{What a mess}{}
+%D
+%D \chapter{About complex bibliographies}
+%D
+%D \in{chapter}[match(complex bibliographies)]
+%D \in{chapter}[match(never ending)]
+%D \in{figure}[match(mess)]
+%D \stoptyping
+
+%D Tracing:
+
+\unexpanded\def\strc_references_tracer#1#2% \csleft csright
+ {\hbox to \zeropoint \bgroup
+ \hss
+ \infofont
+ \darkblue
+ \ifx#1\empty\else
+ \raise\strutht \hbox \s!to \zeropoint \bgroup
+ \hss#1\hskip.2\emwidth
+ \egroup
+ \fi
+ \vrule \s!height 1.5\strutht \s!depth \strutdp \s!width .1\emwidth
+ \ifx#2\empty\else
+ \raise\strutht \hbox \s!to \zeropoint \bgroup
+ \hskip.2\emwidth#2\hss
+ \egroup
+ \fi
+ \hss
+ \egroup}%
+
\protect \endinput
% tricky:
diff --git a/Master/texmf-dist/tex/context/base/strc-reg.lua b/Master/texmf-dist/tex/context/base/strc-reg.lua
index bdb2e0d6713..ed329219595 100644
--- a/Master/texmf-dist/tex/context/base/strc-reg.lua
+++ b/Master/texmf-dist/tex/context/base/strc-reg.lua
@@ -47,6 +47,8 @@ local v_text = variables.text
local context = context
local commands = commands
+local implement = interfaces.implement
+
local matchingtilldepth = sections.matchingtilldepth
local numberatdepth = sections.numberatdepth
local currentlevel = sections.currentlevel
@@ -64,6 +66,10 @@ local a_destination = attributes.private('destination')
local absmaxlevel = 5 -- \c_strc_registers_maxlevel
+local h_prefixpage = helpers.prefixpage
+local h_prefixlastpage = helpers.prefixlastpage
+local h_title = helpers.title
+
local ctx_startregisteroutput = context.startregisteroutput
local ctx_stopregisteroutput = context.stopregisteroutput
local ctx_startregistersection = context.startregistersection
@@ -74,13 +80,115 @@ local ctx_startregisterentry = context.startregisterentry
local ctx_stopregisterentry = context.stopregisterentry
local ctx_startregisterpages = context.startregisterpages
local ctx_stopregisterpages = context.stopregisterpages
-local ctx_stopregisterseewords = context.stopregisterseewords
local ctx_startregisterseewords = context.startregisterseewords
+local ctx_stopregisterseewords = context.stopregisterseewords
local ctx_registerentry = context.registerentry
local ctx_registerseeword = context.registerseeword
local ctx_registerpagerange = context.registerpagerange
local ctx_registeronepage = context.registeronepage
+-- possible export, but ugly code (overloads)
+--
+-- local output, section, entries, nofentries, pages, words, rawtext
+--
+-- h_title = function(a,b) rawtext = a end
+--
+-- local function ctx_startregisteroutput()
+-- output = { }
+-- section = nil
+-- entries = nil
+-- nofentries = nil
+-- pages = nil
+-- words = nil
+-- rawtext = nil
+-- end
+-- local function ctx_stopregisteroutput()
+-- inspect(output)
+-- output = nil
+-- section = nil
+-- entries = nil
+-- nofentries = nil
+-- pages = nil
+-- words = nil
+-- rawtext = nil
+-- end
+-- local function ctx_startregistersection(tag)
+-- section = { }
+-- output[#output+1] = {
+-- section = section,
+-- tag = tag,
+-- }
+-- end
+-- local function ctx_stopregistersection()
+-- end
+-- local function ctx_startregisterentries(n)
+-- entries = { }
+-- nofentries = 0
+-- section[#section+1] = entries
+-- end
+-- local function ctx_stopregisterentries()
+-- end
+-- local function ctx_startregisterentry(n) -- or subentries (nested?)
+-- nofentries = nofentries + 1
+-- entry = { }
+-- entries[nofentries] = entry
+-- end
+-- local function ctx_stopregisterentry()
+-- nofentries = nofentries - 1
+-- entry = entries[nofentries]
+-- end
+-- local function ctx_startregisterpages()
+-- pages = { }
+-- entry.pages = pages
+-- end
+-- local function ctx_stopregisterpages()
+-- end
+-- local function ctx_startregisterseewords()
+-- words = { }
+-- entry.words = words
+-- end
+-- local function ctx_stopregisterseewords()
+-- end
+-- local function ctx_registerentry(processor,internal,seeparent,text)
+-- text()
+-- entry.text = {
+-- processor = processor,
+-- internal = internal,
+-- seeparent = seeparent,
+-- text = rawtext,
+-- }
+-- end
+-- local function ctx_registerseeword(i,n,processor,internal,seeindex,seetext)
+-- seetext()
+-- entry.words[i] = {
+-- processor = processor,
+-- internal = internal,
+-- seeparent = seeparent,
+-- seetext = rawtext,
+-- }
+-- end
+-- local function ctx_registerpagerange(fprocessor,finternal,frealpage,lprocessor,linternal,lrealpage)
+-- pages[#pages+1] = {
+-- first = {
+-- processor = fprocessor,
+-- internal = finternal,
+-- realpage = frealpage,
+-- },
+-- last = {
+-- processor = lprocessor,
+-- internal = linternal,
+-- realpage = lrealpage,
+-- },
+-- }
+-- end
+-- local function ctx_registeronepage(processor,internal,realpage)
+-- pages[#pages+1] = {
+-- processor = processor,
+-- internal = internal,
+-- realpage = realpage,
+-- }
+-- end
+
-- some day we will share registers and lists (although there are some conceptual
-- differences in the application of keywords)
@@ -194,6 +302,7 @@ local function filtercollected(names,criterium,number,collected,prevmode)
end
else -- sectionname, number
-- beware, this works ok for registers
+ -- to be redone with reference instead
local depth = sections.getlevel(criterium)
local number = tonumber(number) or numberatdepth(depth) or 0
if trace_registers then
@@ -309,30 +418,71 @@ end
registers.define = defineregister -- 4 times is somewhat over the top but we want consistency
registers.setmethod = defineregister -- and we might have a difference some day
-commands.defineregister = defineregister
-commands.setregistermethod = defineregister
+
+implement {
+ name = "defineregister",
+ actions = defineregister,
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "setregistermethod",
+ actions = defineregister, -- duplicate use
+ arguments = { "string", "string" }
+}
local entrysplitter = lpeg.tsplitat('+') -- & obsolete in mkiv
local tagged = { }
+-- this whole splitting is an inheritance of mkii
+
local function preprocessentries(rawdata)
local entries = rawdata.entries
if entries then
- local e, k = entries[1] or "", entries[2] or ""
- local et, kt, entryproc, pageproc
- if type(e) == "table" then
- et = e
- else
- entryproc, e = splitprocessor(e)
+ --
+ -- local e = entries[1] or ""
+ -- local k = entries[2] or ""
+ -- local et, kt, entryproc, pageproc
+ -- if type(e) == "table" then
+ -- et = e
+ -- else
+ -- entryproc, e = splitprocessor(e)
+ -- et = lpegmatch(entrysplitter,e)
+ -- end
+ -- if type(k) == "table" then
+ -- kt = k
+ -- else
+ -- pageproc, k = splitprocessor(k)
+ -- kt = lpegmatch(entrysplitter,k)
+ -- end
+ --
+ local processors = rawdata.processors
+ local et = entries.entries
+ local kt = entries.keys
+ local entryproc = processors and processors.entry
+ local pageproc = processors and processors.page
+ if entryproc == "" then
+ entryproc = nil
+ end
+ if pageproc == "" then
+ pageproc = nil
+ end
+ if not et then
+ local p, e = splitprocessor(entries.entry or "")
+ if p then
+ entryproc = p
+ end
et = lpegmatch(entrysplitter,e)
end
- if type(k) == "table" then
- kt = k
- else
- pageproc, k = splitprocessor(k)
+ if not kt then
+ local p, k = splitprocessor(entries.key or "")
+ if p then
+ pageproc = p
+ end
kt = lpegmatch(entrysplitter,k)
end
+ --
entries = { }
local ok = false
for k=#et,1,-1 do
@@ -347,7 +497,7 @@ local function preprocessentries(rawdata)
end
rawdata.list = entries
if pageproc or entryproc then
- rawdata.processors = { entryproc, pageproc }
+ rawdata.processors = { entryproc, pageproc } -- old way: indexed .. will be keys
end
rawdata.entries = nil
end
@@ -361,6 +511,11 @@ local function storeregister(rawdata) -- metadata, references, entries
local references = rawdata.references
local metadata = rawdata.metadata
-- checking
+ if not metadata then
+ metadata = { }
+ rawdata.metadata = metadata
+ end
+ --
if not metadata.kind then
metadata.kind = "entry"
end
@@ -372,6 +527,11 @@ local function storeregister(rawdata) -- metadata, references, entries
local name = metadata.name
local notsaved = tobesaved[name].metadata.notsaved
--
+ if not references then
+ references = { }
+ rawdata.references = references
+ end
+ --
local internal = references.internal
if not internal then
internal = texgetcount("locationcount") -- we assume that it has been set
@@ -408,7 +568,9 @@ local function storeregister(rawdata) -- metadata, references, entries
return #entries
end
-local function enhanceregister(name,n)
+registers.store = storeregister
+
+function registers.enhance(name,n)
local data = tobesaved[name].metadata.notsaved and collected[name] or tobesaved[name]
local entry = data.entries[n]
if entry then
@@ -416,7 +578,7 @@ local function enhanceregister(name,n)
end
end
-local function extendregister(name,tag,rawdata) -- maybe do lastsection internally
+function registers.extend(name,tag,rawdata) -- maybe do lastsection internally
if type(tag) == "string" then
tag = tagged[tag]
end
@@ -460,18 +622,70 @@ local function extendregister(name,tag,rawdata) -- maybe do lastsection internal
end
end
-registers.store = storeregister
-registers.enhance = enhanceregister
-registers.extend = extendregister
-
-function commands.storeregister(rawdata)
- local nofentries = storeregister(rawdata)
- setinternalreference(nil,nil,rawdata.references.internal)
- context(nofentries)
+function registers.get(tag,n)
+ local list = tobesaved[tag]
+ return list and list.entries[n]
end
-commands.enhanceregister = enhanceregister
-commands.extendregister = extendregister
+implement {
+ name = "enhanceregister",
+ actions = registers.enhance,
+ arguments = { "string", "integer" }
+}
+
+implement {
+ name = "extendregister",
+ actions = registers.extend,
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "storeregister",
+ actions = function(rawdata)
+ local nofentries = storeregister(rawdata)
+ setinternalreference { internal = rawdata.references.internal }
+ context(nofentries)
+ end,
+ arguments = {
+ {
+ { "metadata", {
+ { "kind" },
+ { "name" },
+ { "coding" },
+ { "level", "integer" },
+ { "catcodes", "integer" },
+ { "own" },
+ { "xmlroot" },
+ { "xmlsetup" }
+ }
+ },
+ { "entries", {
+ { "entries", "list" },
+ { "keys", "list" },
+ { "entry" },
+ { "key" }
+ }
+ },
+ { "references", {
+ { "internal", "integer" },
+ { "section", "integer" },
+ { "label" }
+ }
+ },
+ { "seeword", {
+ { "text" }
+ }
+ },
+ { "processors", {
+ { "entry" },
+ { "key" },
+ { "page" }
+ }
+ },
+ { "userdata" },
+ }
+ }
+}
-- sorting and rendering
@@ -508,7 +722,7 @@ end
local seeindex = 0
--- meerdere loops, seewords, dan words, an seewords
+-- meerdere loops, seewords, dan words, anders seewords
local function crosslinkseewords(result) -- all words
-- collect all seewords
@@ -712,10 +926,21 @@ end
registers.analyze = analyzeregister
-function registers.analyze(class,options)
- context(analyzeregister(class,options))
-end
-
+implement {
+ name = "analyzeregister",
+ actions = { analyzeregister, context },
+ arguments = {
+ "string",
+ {
+ { "language" },
+ { "method" },
+ { "numberorder" },
+ { "compress" },
+ { "criterium" },
+ { "pagenumber", "boolean" },
+ }
+ }
+}
-- todo take conversion from index
@@ -724,20 +949,14 @@ function registers.userdata(index,name)
return data and data.userdata and data.userdata[name] or nil
end
-function commands.registeruserdata(index,name)
- local data = references.internals[tonumber(index)]
- data = data and data.userdata and data.userdata[name]
- if data then
- context(data)
- end
-end
+implement {
+ name = "registeruserdata",
+ actions = { registers.userdata, context },
+ arguments = { "integer", "string" }
+}
-- todo: ownnumber
-local h_prefixpage = helpers.prefixpage
-local h_prefixlastpage = helpers.prefixlastpage
-local h_title = helpers.title
-
local function pagerange(f_entry,t_entry,is_last,prefixspec,pagespec)
local fer, ter = f_entry.references, t_entry.references
ctx_registerpagerange(
@@ -873,8 +1092,8 @@ function registers.flush(data,options,prefixspec,pagespec)
if #list > 1 then
list[#list] = nil
else
- -- we have an \seeindex{Foo}{Bar} without Foo being defined anywhere
- report_registers("invalid see entry in register %a, reference %a",entry.metadata.name,list[1][1])
+ -- we have an \seeindex{Foo}{Bar} without Foo being defined anywhere .. somehow this message is wrong
+ -- report_registers("invalid see entry in register %a, reference %a",entry.metadata.name,list[1][1])
end
end
end
@@ -882,60 +1101,68 @@ function registers.flush(data,options,prefixspec,pagespec)
-- but we don't want to allocate too many entries so there we go
while d < #data do
d = d + 1
- local entry = data[d]
+ local entry = data[d]
+ local metadata = entry.metadata
+ local kind = metadata.kind
+ local list = entry.list
local e = { false, false, false }
for i=3,maxlevel do
e[i] = false
end
- local metadata = entry.metadata
- local kind = metadata.kind
- local list = entry.list
for i=1,maxlevel do
if list[i] then
e[i] = list[i][1]
end
- if e[i] ~= done[i] then
- if e[i] and e[i] ~= "" then
- done[i] = e[i]
- for j=i+1,maxlevel do
- done[j] = false
- end
- if started then
- ctx_stopregisterentry()
- started = false
- end
- if n == i then
+ if e[i] == done[i] then
+ -- skip
+ elseif not e[i] then
+ -- see ends up here
+ -- can't happen any more
+ done[i] = false
+ for j=i+1,maxlevel do
+ done[j] = false
+ end
+ elseif e[i] == "" then
+ done[i] = false
+ for j=i+1,maxlevel do
+ done[j] = false
+ end
+ else
+ done[i] = e[i]
+ for j=i+1,maxlevel do
+ done[j] = false
+ end
+ if started then
+ ctx_stopregisterentry()
+ started = false
+ end
+ if n == i then
-- ctx_stopregisterentries()
-- ctx_startregisterentries(n)
- else
- while n > i do
- n = n - 1
- ctx_stopregisterentries()
- end
- while n < i do
- n = n + 1
- ctx_startregisterentries(n)
- end
+ else
+ while n > i do
+ n = n - 1
+ ctx_stopregisterentries()
end
- local references = entry.references
- local processors = entry.processors
- local internal = references.internal or 0
- local seeparent = references.seeparent or ""
- local processor = processors and processors[1] or ""
- -- so, we need to keep e as is (local), or we need local title = e[i] ... which might be
- -- more of a problem
- ctx_startregisterentry(0) -- will become a counter
- started = true
- if metadata then
- ctx_registerentry(processor,internal,seeparent,function() h_title(e[i],metadata) end)
- else -- ?
- ctx_registerentry(processor,internal,seeindex,e[i])
+ while n < i do
+ n = n + 1
+ ctx_startregisterentries(n)
end
+ end
+ local references = entry.references
+ local processors = entry.processors
+ local internal = references.internal or 0
+ local seeparent = references.seeparent or ""
+ local processor = processors and processors[1] or ""
+ -- so, we need to keep e as is (local), or we need local title = e[i] ... which might be
+ -- more of a problem
+ ctx_startregisterentry(0) -- will become a counter
+ started = true
+ if metadata then
+ ctx_registerentry(processor,internal,seeparent,function() h_title(e[i],metadata) end)
else
- done[i] = false
- for j=i+1,maxlevel do
- done[j] = false
- end
+ -- can this happen?
+ ctx_registerentry(processor,internal,seeindex,e[i])
end
end
end
@@ -1051,7 +1278,8 @@ function registers.flush(data,options,prefixspec,pagespec)
local seetext = seeword.text or ""
local processor = seeword.processor or (entry.processors and entry.processors[1]) or ""
local seeindex = entry.references.seeindex or ""
- ctx_registerseeword(i,n,processor,0,seeindex,seetext)
+ -- ctx_registerseeword(i,nt,processor,0,seeindex,seetext)
+ ctx_registerseeword(i,nt,processor,0,seeindex,function() h_title(seetext,metadata) end)
end
ctx_stopregisterseewords()
end
@@ -1078,12 +1306,42 @@ function registers.flush(data,options,prefixspec,pagespec)
-- collectgarbage("collect")
end
-local function processregister(class,...)
+function registers.process(class,...)
if analyzeregister(class,...) > 0 then
local data = collected[class]
registers.flush(data,...)
end
end
-registers.process = processregister
-commands.processregister = processregister
+implement {
+ name = "processregister",
+ actions = registers.process,
+ arguments = {
+ "string",
+ {
+ { "language" },
+ { "method" },
+ { "numberorder" },
+ { "compress" },
+ { "criterium" },
+ { "pagenumber", "boolean" },
+ },
+ {
+ { "separatorset" },
+ { "conversionset" },
+ { "starter" },
+ { "stopper" },
+ { "set" },
+ { "segments" },
+ { "connector" },
+ },
+ {
+ { "prefix" },
+ { "separatorset" },
+ { "conversionset" },
+ { "starter" },
+ { "stopper" },
+ { "segments" },
+ }
+ }
+}
diff --git a/Master/texmf-dist/tex/context/base/strc-reg.mkiv b/Master/texmf-dist/tex/context/base/strc-reg.mkiv
index d072aca69b1..138a1486f3e 100644
--- a/Master/texmf-dist/tex/context/base/strc-reg.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-reg.mkiv
@@ -134,7 +134,7 @@
\ifconditional\c_strc_registers_defining \else % todo: dosingle ...
\settrue\c_strc_registers_defining
\definemixedcolumns[\currentregister][\v!register]% first as otherwise it overloads start/stop
- \ctxcommand{defineregister("\currentregister","\registerparameter\c!referencemethod")}%
+ \clf_defineregister{\currentregister}{\registerparameter\c!referencemethod}%
\normalexpanded{\presetheadtext[\currentregister=\Word{\currentregister}]}%
\setuevalue{\currentregister}{\dodoubleempty\strc_registers_insert_entry[\currentregister]}%
\setuevalue{\e!see\currentregister}{\dodoubleempty\strc_registers_insert_see[\currentregister]}%
@@ -155,7 +155,7 @@
\to \everydefineregister
\appendtoks
- \ctxcommand{setregistermethod("\currentregister","\registerparameter\c!referencemethod")}%
+ \clf_setregistermethod{\currentregister}{\registerparameter\c!referencemethod}%
\to \everysetupregister
%D Registering:
@@ -251,49 +251,49 @@
\setnextinternalreference
% we could consider storing register entries in a list which we
% could then sort
- \xdef\currentregisternumber{\ctxcommand{storeregister{ % 'own' should not be in metadata
- metadata = {
- % kind = "entry",
- name = "\currentregister",
- % level = structures.sections.currentlevel(),
- coding = "\currentregistercoding",
- % catcodes = \the\catcodetable,
+ \xdef\currentregisternumber{\clf_storeregister % 'own' should not be in metadata
+ metadata {%
+ name {\currentregister}%
+ coding {\currentregistercoding}%
\ifx\currentregisterownnumber\v!yes
- own = "\registerparameter\c!alternative", % can be used instead of pagenumber
+ own {\registerparameter\c!alternative}% can be used instead of pagenumber
\fi
\ifx\currentreferencecoding\s!xml
- xmlroot = "\xmldocument", % only useful when text
+ xmlroot {\xmldocument} % only useful when text
\fi
\ifx\currentregisterxmlsetup\empty \else
- xmlsetup = "\currentregisterxmlsetup",
+ xmlsetup {\currentregisterxmlsetup}%
\fi
- },
- references = {
- % internal = \nextinternalreference,
- % section = structures.sections.currentid(), % hm, why then not also lastsection the same way
+ }%
+ references {%
\ifx\currentregisterlabel\empty \else
- label = "\currentregisterlabel",
+ label {\currentregisterlabel}%
\fi
- },
- % \ifx\currentregisterentries\empty \else
- entries = {
+ }%
+ entries {%
% we need a special one for xml, this is just a single one
\ifx\currentregisterentries\empty
- { \!!bs\currentregisterentriesa\!!es, \!!bs\currentregisterentriesb\!!es, \!!bs\currentregisterentriesc\!!es },
+ entries {
+ {\currentregisterentriesa}%
+ {\currentregisterentriesb}%
+ {\currentregisterentriesc}%
+ }
\else
- \!!bs\currentregisterentries\!!es,
+ entry {\currentregisterentries}%
\fi
\ifx\currentregisterkeys\empty
- { \!!bs\currentregisterkeysa\!!es, \!!bs\currentregisterkeysb\!!es, \!!bs\currentregisterkeysc\!!es },
+ keys {
+ {\currentregisterkeysa}%
+ {\currentregisterkeysb}%
+ {\currentregisterkeysc}%
+ }
\else
- \!!bs\currentregisterkeys\!!es,
+ key {\currentregisterkeys}%
\fi
- },
- % \fi
- userdata = structures.helpers.touserdata(\!!bs\detokenize{#3}\!!es)
- }
- }}%
- % \ctxcommand{setinternalreference(nil,nil,\nextinternalreference)}% in previous
+ }%
+ userdata {\detokenize\expandafter{\normalexpanded{#3}}}
+ }%
+ % \clf_setinternalreference internal \nextinternalreference\relax % in previous
\ifx\currentregisterownnumber\v!yes
\glet\currentregistersynchronize\relax
\else
@@ -302,9 +302,42 @@
\currentregistersynchronize % here?
% needs thinking ... bla\index{bla}. will break before the . but adding a
% penalty is also no solution
+ \dostarttagged\t!registerlocation\currentregister
+ \attribute\destinationattribute\lastdestinationattribute \signalcharacter % no \strut as it will be removed during cleanup
+ \dotagregisterlocation
+ \dostoptagged
+ \endgroup}
+
+\unexpanded\def\dosetfastregisterentry#1#2#3#4#5% register entry key processor processor
+ {\begingroup
+ \edef\currentregister{#1}%
+ \setnextinternalreference
+ \xdef\currentregisternumber{\clf_storeregister
+ {%
+ metadata {%
+ name {\currentregister}%
+ }
+ entries {%
+ entry {#2}%
+ key {#3}%
+ }%
+ processors {%
+ entry {#4}%
+ page {#5}%
+ }%
+ }%
+ }%
+ % overlap with the above
+ \xdef\currentregistersynchronize{\ctxlatecommand{enhanceregister("\currentregister",\currentregisternumber)}}%
+ \currentregistersynchronize % here?
+ \dostarttagged\t!registerlocation\currentregister
\attribute\destinationattribute\lastdestinationattribute \signalcharacter % no \strut as it will be removed during cleanup
+ \dotagregisterlocation
+ \dostoptagged
\endgroup}
+\let\dotagregisterlocation\relax % experiment
+
\unexpanded\def\strc_registers_insert_entry[#1][#2]%
{\def\currentregister{#1}%
\doifelse{\registerparameter\c!ownnumber}\v!yes
@@ -349,7 +382,7 @@
\def\strc_registers_finish_entry_indeed#1#2#3% register data userdata
{\begingroup
\edef\currentregister{#1}%
- \setupcurrentregister[\c!entries=,\c!label=,\c!keys=,\c!alternative=,#2]%
+ \setupcurrentregister[\c!entries=,\c!label=,\c!keys=,\c!alternative=,#2]% todo: fast setter
\edef\currentregisterlabel {\registerparameter\c!label}%
\edef\currentregisterexpansion{\registerparameter\c!expansion}%
\edef\currentregisterownnumber{\registerparameter\c!ownnumber}%
@@ -461,27 +494,28 @@
\fi
\setnextinternalreference
% we could consider storing register entries in list
- \edef\temp{\ctxcommand{storeregister{
- metadata = {
- kind = "see",
- name = "\currentregister",
- % level = structures.sections.currentlevel(),
- % catcodes = \the\catcodetable,
- },
- references = {
- % internal = \nextinternalreference,
- % section = structures.sections.currentid(),
- },
- entries = {
- % we need a special one for xml, this is just a single one
- \!!bs\currentregisterentries\!!es,
- \!!bs#2\!!es
- },
- seeword = {
- text = \!!bs\currentregisterseeword\!!es
- },
- }
+ \edef\temp{\clf_storeregister{
+ metadata {%
+ kind {see}%
+ name {\currentregister}%
+ }%
+ references {%
+ % internal = \nextinternalreference,
+ % section = structures.sections.currentid(),
+ }%
+ entries {%
+ % we need a special one for xml, this is just a single one
+ entry {\currentregisterentries}%
+ key {#2}%
+ }%
+ seeword {%
+ text {\currentregisterseeword}%
+ }%
}}%
+ \dostarttagged\t!registerlocation\currentregister
+ \attribute\destinationattribute\lastdestinationattribute \signalcharacter % no \strut as it will be removed during cleanup
+ \dotagregisterlocation
+ \dostoptagged
\endgroup}
%D Rendering:
@@ -497,14 +531,17 @@
{\begingroup
\edef\currentregister{#1}%
\setupregister[\currentregister][#2]%
- \normalexpanded{\endgroup\noexpand\xdef\noexpand\utilityregisterlength{\ctxcommand{analyzeregister('\currentregister',{
- language = "\registerparameter\s!language",
- method = "\registerparameter\c!method",
- numberorder = "\registerparameter\c!numberorder",
- compress = "\registerparameter\c!compress",
- criterium = "\registerparameter\c!criterium",
- pagenumber = \ifx\registerpageseparatorsymbol\empty false\else true\fi,
- })}}}% brrr
+ \normalexpanded{\endgroup\noexpand\xdef\noexpand\utilityregisterlength{\clf_analyzeregister
+ {\currentregister}%
+ {%
+ language {\registerparameter\s!language}%
+ method {\registerparameter\c!method}%
+ numberorder {\registerparameter\c!numberorder}%
+ compress {\registerparameter\c!compress}%
+ criterium {\registerparameter\c!criterium}%
+ pagenumber \ifx\registerpageseparatorsymbol\empty false\else true\fi
+ }%
+ }}%
\ifcase\utilityregisterlength\relax
\resetsystemmode\v!register
\else
@@ -520,27 +557,6 @@
\unexpanded\def\placeregister
{\dodoubleempty\strc_registers_place}
-% \def\strc_registers_place[#1][#2]%
-% {\iffirstargument
-% \begingroup
-% %\forgetall
-% \edef\currentregister{#1}%
-% \setupregister[\currentregister][#2]%
-% \the\everyplaceregister
-% \ifnum\registerparameter\c!n>\plusone
-% \startcolumns
-% [\c!n=\registerparameter\c!n,
-% \c!balance=\registerparameter\c!balance,
-% \c!align=\registerparameter\c!align,
-% \c!tolerance=\registerparameter\c!tolerance]%
-% \strc_registers_place_indeed
-% \stopcolumns
-% \else
-% \strc_registers_place_indeed
-% \fi
-% \endgroup
-% \fi}
-
\def\strc_registers_place[#1][#2]%
{\iffirstargument
\begingroup
@@ -558,42 +574,33 @@
\endgroup
\fi}
-% \def\strc_registers_place_columns
-% {\startmixedcolumns[\currentregister]
-% \startpacked[\v!blank]%
-% \strc_registers_place_indeed
-% \stoppacked
-% \stopmixedcolumns}
-%
-% \def\strc_registers_place_normal
-% {\startpacked[\v!blank]%
-% \strc_registers_place_indeed
-% \stoppacked}
-
\def\strc_registers_place_indeed
- {\ctxcommand{processregister('\currentregister',{
- language = "\registerparameter\s!language",
- method = "\registerparameter\c!method",
- numberorder = "\registerparameter\c!numberorder",
- compress = "\registerparameter\c!compress",
- criterium = "\registerparameter\c!criterium",
- pagenumber = \ifx\registerpageseparatorsymbol\empty false\else true\fi,
- },{
- separatorset = "\registerparameter\c!pageprefixseparatorset",
- conversionset = "\registerparameter\c!pageprefixconversionset",
- starter = \!!bs\registerparameter\c!pageprefixstarter\!!es,
- stopper = \!!bs\registerparameter\c!pageprefixstopper\!!es,
- set = "\registerparameter\c!pageprefixset",
- segments = "\registerparameter\c!pageprefixsegments",
- connector = \!!bs\registerparameter\c!pageprefixconnector\!!es,
- },{
- prefix = "\registerparameter\c!pageprefix",
- separatorset = "\registerparameter\c!pageseparatorset",
- conversionset = "\registerparameter\c!pageconversionset",
- starter = \!!bs\registerparameter\c!pagestarter\!!es,
- stopper = \!!bs\registerparameter\c!pagestopper\!!es,
- segments = "\registerparameter\c!pagesegments",
- })}}
+ {\clf_processregister
+ {\currentregister}%
+ {%
+ language {\registerparameter\s!language}%
+ method {\registerparameter\c!method}%
+ numberorder {\registerparameter\c!numberorder}%
+ compress {\registerparameter\c!compress}%
+ criterium {\registerparameter\c!criterium}%
+ pagenumber \ifx\registerpageseparatorsymbol\empty false\else true\fi
+ }{%
+ separatorset {\registerparameter\c!pageprefixseparatorset}%
+ conversionset {\registerparameter\c!pageprefixconversionset}%
+ starter {\registerparameter\c!pageprefixstarter}%
+ stopper {\registerparameter\c!pageprefixstopper}%
+ set {\registerparameter\c!pageprefixset}%
+ segments {\registerparameter\c!pageprefixsegments}%
+ connector {\registerparameter\c!pageprefixconnector}%
+ }{%
+ prefix {\registerparameter\c!pageprefix}%
+ separatorset {\registerparameter\c!pageseparatorset}%
+ conversionset {\registerparameter\c!pageconversionset}%
+ starter {\registerparameter\c!pagestarter}%
+ stopper {\registerparameter\c!pagestopper}%
+ segments {\registerparameter\c!pagesegments}%
+ }%
+ \relax}
\def\strc_registers_limited_entry#1%
{\limitatetext{#1}\currentregistermaxwidth\unknown}%
@@ -668,17 +675,19 @@
% a =
-\setvalue{\??registerindicator a}#1%
+\def\strc_registers_indicator_a#1#2%
{\registerparameter\c!before
% bugged, why does leftskip gets set: \vskip\lineheight\goodbreak\vskip-\lineheight
+ \typo_injectors_check_register
\begingroup
\useregisterstyleandcolor\c!style\c!color
\dontleavehmode
+ \typo_injectors_mark_register
\strut
\iflocation
\dosetdirectpagereference{\currentregister:\v!section:#1}%
\fi
- \registerparameter\c!command{#1}%
+ \registerparameter\c!command{#2}%
\endgroup
\blank[\v!samepage]%
\registerparameter\c!after
@@ -687,38 +696,55 @@
% b =
-\setvalue{\??registerindicator b}#1% will be shared with a
+\def\strc_registers_indicator_b#1#2%
{\registerparameter\c!before
+ \typo_injectors_check_register
\begingroup
\useregisterstyleandcolor\c!style\c!color
\dontleavehmode
+ \typo_injectors_mark_register
\strut
\iflocation
\dosetdirectpagereference{\currentregister:\v!section:#1}%
\fi
- \registerparameter\c!command{#1}%
+ \registerparameter\c!command{#2}%
\endgroup
\registerparameter\c!after
\nobreak}
-\setvalue{\??registerindicator A}#1{\getvalue{\??registerindicator a}{\WORD{#1}}}
-\setvalue{\??registerindicator B}#1{\getvalue{\??registerindicator b}{\WORD{#1}}}
+\setvalue{\??registerindicator a}#1{\strc_registers_indicator_a{#1}{#1}}
+\setvalue{\??registerindicator A}#1{\strc_registers_indicator_a{#1}{\WORD{#1}}}
+\setvalue{\??registerindicator b}#1{\strc_registers_indicator_b{#1}{#1}}
+\setvalue{\??registerindicator B}#1{\strc_registers_indicator_b{#1}{\WORD{#1}}}
%D The following macros are the interface to the rendering. These are
%D generated by \LUA. This might change.
+% \showinjector
+% \setinjector[register][2][\column]
+%
+% \starttext
+% first \index{first}
+% second \index{second}
+% third \index{third}
+% fourth \index{fourth}
+% \placeregister[index]
+% \stoptext
+
+\doinstallinjector\s!register
+
%D Beware, we get funny side effects when a dangling \index precedes an
%D placeindex as then flushing takes place inside the index. Took me hours
%D to notice that.
-\newconditional\c_strc_registers_page_done
+\newconstant \c_strc_registers_page_state % 0=nothing 1=page 2=see
\newdimen \d_strc_registers_distance
\unexpanded\def\startregisteroutput
{\endgraf
\begingroup
\d_strc_registers_distance\registerparameter\c!distance\relax
- \dostarttagged\t!register\currentregister
+ \dostarttaggedchained\t!register\currentregister\??register
\forgeteverypar
\forgetparindent
\forgetparskip}
@@ -728,18 +754,6 @@
\dostoptagged
\endgroup}
-% \unexpanded\def\startregisterentries#1% depth
-% {\endgraf
-% \begingroup
-% \dostarttagged\t!registerentries\empty
-% \let\savedcurrentregister\currentregister
-% \edef\currentregister{\currentregister:#1}%
-% \useregisterstyleandcolor\c!textstyle\c!textcolor
-% \advance\leftskip\numexpr#1-\plusone\relax\dimexpr\d_strc_registers_distance\relax
-% \hangindent\registerparameter\c!distance\relax
-% \hangafter\plusone
-% \let\currentregister\savedcurrentregister}
-
\newdimen\d_strc_registers_hangindent
\newcount\c_strc_registers_hangafter
@@ -756,7 +770,7 @@
\fi
\d_strc_registers_hangindent\registerparameter\c!distance\relax
\c_strc_registers_hangafter \plusone
-\blank[\v!samepage]%
+ \blank[\v!samepage]%
\let\currentregister\savedcurrentregister}
\unexpanded\def\stopregisterentries
@@ -765,12 +779,18 @@
\endgroup}
\unexpanded\def\startregisterentry#1% todo: level
- {\begingroup
+ {\typo_injectors_check_register
+ \begingroup
+ \dostarttagged\t!registerentry\empty
+ \global\setconstant\c_strc_registers_page_state\zerocount
\hangindent\d_strc_registers_hangindent
- \hangafter \c_strc_registers_hangafter}
+ \hangafter \c_strc_registers_hangafter
+ \typo_injectors_mark_register}
\unexpanded\def\stopregisterentry
{\endgraf
+ \global\setconstant\c_strc_registers_page_state\zerocount
+ \dostoptagged
\endgroup}
\unexpanded\def\startregistersection#1% title
@@ -786,7 +806,6 @@
\unexpanded\def\startregisterpages
{\begingroup
\dostarttagged\t!registerpages\empty
- \setfalse\c_strc_registers_page_done
\useregisterstyleandcolor\c!pagestyle\c!pagecolor}
\unexpanded\def\stopregisterpages
@@ -794,9 +813,8 @@
\endgroup}
\unexpanded\def\startregisterseewords
- {\ifhmode\crlf\fi
+ {%\par % \ifhmode\crlf\fi % otherwise wrong level
\begingroup
- \setfalse\c_strc_registers_page_done
\dostarttagged\t!registerpage\empty
\useregisterstyleandcolor\c!pagestyle\c!pagecolor}
@@ -804,12 +822,17 @@
{\dostoptagged
\endgroup}
-\unexpanded\def\registerpageseparator% todo: , configurable
- {\ifconditional\c_strc_registers_page_done
- \registerpageseparatorsymbol
- \else
+\unexpanded\def\registerpageseparator % todo: , configurable
+ {\ifcase\c_strc_registers_page_state
\hskip\d_strc_registers_distance\relax
- \settrue\c_strc_registers_page_done
+ \or
+ \dostarttagged\t!registerseparator\empty
+ \registerpageseparatorsymbol % page
+ \dostoptagged
+ \or
+ \dostarttagged\t!registerseparator\empty
+ \registerpageseparatorsymbol % see
+ \dostoptagged
\fi}
\unexpanded\def\registeronepagerangeseparator
@@ -825,12 +848,14 @@
\unexpanded\def\registeronepage#1#2#3#4% #1:processor content
{\registerpageseparator
+ \global\setconstant\c_strc_registers_page_state\plusone
\dostarttagged\t!registerpage\empty
\withregisterpagecommand{#1}{#2}{#3}{#4}%
\dostoptagged}
\unexpanded\def\registerpagerange#1#2#3#4#5#6#7% #1:processor content, content todo: -- configurable
{\registerpageseparator
+ \global\setconstant\c_strc_registers_page_state\plusone
\dostarttagged\t!registerpagerange\empty
\dostarttagged\t!registerfrompage\empty
\withregisterpagecommand{#1}{#2}{#3}{#4}%
@@ -841,12 +866,8 @@
\dostoptagged
\dostoptagged}
-\let\strc_register_injector_process\relax
-\let\strc_register_injector_show \relax
-
\unexpanded\def\defaultregisterentry#1#2#3#4% #1:processor #2:internal #3:seeindex #4:word
{\def\currentregisterpageindex{#2}%
- \strc_register_injector_process
\iflocation
\def\currentregisterseeindex{#3}%
\doifelse{\registerparameter\c!interaction}\v!text
@@ -858,10 +879,9 @@
\fi}
\unexpanded\def\doapplyregisterentrycommand#1#2% processor text
- {\dostarttagged\t!registerentry\empty
+ {\dostarttagged\t!registercontent\empty
\ifx\currentregisterseeindex\empty \else
\dontleavehmode
- \strc_register_injector_show
\dosetdirectpagereference{seeindex:\currentregisterseeindex}% maybe some day we will support an area
\fi
\applyprocessor{#1}{\registerparameter\c!textcommand{\limitedregisterentry{\registerparameter\c!deeptextcommand{#2}}}}%
@@ -876,7 +896,8 @@
\fi}
\unexpanded\def\defaultregisterseeword#1#2#3#4#5#6% i n #3:processor #4:internal #5:seeindex #6:word
- {%\registerpageseparator
+ {\registerpageseparator
+ \global\setconstant\c_strc_registers_page_state\plustwo
\def\currentregisterpageindex{#4}%
\dostarttagged\t!registersee\empty
\settrue\c_strc_registers_page_done
@@ -914,7 +935,7 @@
% \placeregister[index][n=1,pagecommand=\MyRegisterPageCommand]
% \stoptext
-\def\registerpageuserdata #1#2{\ctxcommand{registeruserdata(#1,"#2")}}
+\def\registerpageuserdata #1#2{\clf_registeruserdata#1{#2}}
\def\currentregisterpageuserdata {\registerpageuserdata\currentregisterpageindex} % {#1}
% not yet ok : new internal handler names
@@ -945,7 +966,7 @@
\def\registeronepage {\registerpagebuttonsymbol\gobblefourarguments}%
\def\registerpagerange{\registerpagebuttonsymbol\gobblesevenarguments}}
-\def\setregisterpagerendering
+\unexpanded\def\setregisterpagerendering
{\doifelse{\registerparameter\c!pagenumber}\v!no
{\let \currentregisterpagesymbol\v!none}
{\edef\currentregisterpagesymbol{\registerparameter\c!symbol}}%
diff --git a/Master/texmf-dist/tex/context/base/strc-ren.mkiv b/Master/texmf-dist/tex/context/base/strc-ren.mkiv
index fdf8fb7f4a4..34903dfa02a 100644
--- a/Master/texmf-dist/tex/context/base/strc-ren.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-ren.mkiv
@@ -135,7 +135,7 @@
\unexpanded\def\strc_rendering_place_head_number_and_text
{\strc_rendering_start_placement
\setheadmarking
- \doiftextelse\getheadnumber
+ \doifelsetext\getheadnumber
\dosettructureheadnumbercontent
\doresettructureheadnumbercontent
\ifconditional\c_strc_sectioning_empty
@@ -422,7 +422,7 @@
{\dodoubleargument\strc_rendering_define_placement}
\def\strc_rendering_define_placement[#1][#2]%
- {\doifnextbgroupelse
+ {\doifelsenextbgroup
{\strc_rendering_define_placement_yes[#1][#2]}%
{\strc_rendering_define_placement_nop[#1][#2]}}
@@ -516,6 +516,11 @@
\fi
\endgroup}
+\def\fakedheadnumber{\vphantom{0}} % needed for mathplus
+
+\unexpanded\def\fakeheadnumbercontent
+ {\hbox to \zeropoint{\let\getheadnumber\fakedheadnumber\headnumbercontent}}
+
\unexpanded\def\strc_rendering_inject_number_and_text
{\edef\p_command{\headparameter\c!command}% assumes \unexpanded definition
\ifx\p_command\empty
@@ -608,6 +613,7 @@
\hsize\headtextwidth
\fi
\noindent
+ \fakeheadnumbercontent % will also be done in the other ones (force consistency with numbered)
\fi
\headtextcontent
}
@@ -629,7 +635,7 @@
\hbox {
\hfill
\headnumbercontent
- \doifrightpageelse{
+ \doifelserightpage{
\scratchdistance\leftmargindistance
} {
\scratchdistance\rightmargindistance
@@ -637,6 +643,8 @@
\hskip\dimexpr\d_strc_rendering_local_leftoffset+\scratchdistance\relax
}
}
+ \else
+ \fakeheadnumbercontent % will also be done in the other ones (force consistency with numbered)
\fi
\headtextcontent
}
@@ -650,6 +658,30 @@
% \directsetup{\??headrenderings:\v!vertical:\v!inmargin}
% \stopsetups
+%D This one is for head based numbering usage: foo 1.2 and so:
+
+\defineheadalternative
+ [\v!reverse]
+ [\c!alternative=\v!vertical,
+ \c!renderingsetup=\??headrenderings:\v!reverse]
+
+\startsetups[\??headrenderings:\v!reverse]
+ \vbox {
+ \headsetupspacing
+ \noindent
+ \begstrut
+ \setfalse\headisdisplay % so a kind of mix
+ \headtextcontent
+ \ifconditional\headshownumber
+ \kern\headnumberdistance
+ \headnumbercontent
+ \else
+ \fakeheadnumbercontent
+ \fi
+ \endstrut
+ }
+\stopsetups
+
\defineheadalternative
[\v!middle]
[\c!alternative=\v!vertical,
@@ -665,6 +697,8 @@
\strut
\headnumbercontent
\par
+ \else
+ \fakeheadnumbercontent % will also be done in the other ones (force consistency with numbered)
\fi
\begstrut
\headtextcontent
diff --git a/Master/texmf-dist/tex/context/base/strc-rsc.lua b/Master/texmf-dist/tex/context/base/strc-rsc.lua
index e2105a4efc1..627e443b2ce 100644
--- a/Master/texmf-dist/tex/context/base/strc-rsc.lua
+++ b/Master/texmf-dist/tex/context/base/strc-rsc.lua
@@ -12,7 +12,8 @@ if not modules then modules = { } end modules ['strc-rsc'] = {
-- The scanner accepts nested outer, but we don't care too much, maybe
-- some day we will have both but currently the innermost wins.
-local lpegmatch, lpegP, lpegS, lpegCs, lpegCt, lpegCf, lpegCc, lpegC, lpegCg = lpeg.match, lpeg.P, lpeg.S, lpeg.Cs, lpeg.Ct, lpeg.Cf, lpeg.Cc, lpeg.C, lpeg.Cg
+local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
+local lpegP, lpegS, lpegCs, lpegCt, lpegCf, lpegCc, lpegC, lpegCg = lpeg.P, lpeg.S, lpeg.Cs, lpeg.Ct, lpeg.Cf, lpeg.Cc, lpeg.C, lpeg.Cg
local find = string.find
local spaces = lpegP(" ")^0
@@ -34,18 +35,28 @@ local backslash = lpegP("\\")
local endofall = spaces * lpegP(-1)
-local o_token = 1 - rparent - rbrace - lparent - lbrace -- can be made more efficient
-local a_token = 1 - rbrace
+----- o_token = 1 - rparent - rbrace - lparent - lbrace -- can be made more efficient
+----- a_token = 1 - rbrace
local s_token = 1 - lparent - lbrace
local i_token = 1 - lparent - lbrace - endofall
local f_token = 1 - lparent - lbrace - dcolon
local c_token = 1 - lparent - lbrace - tcolon
+-- experimental
+
+local o_token = lpegpatterns.nestedparents
+ + (1 - rparent - lbrace)
+local a_token = lpegpatterns.nestedbraces
+ + (1 - rbrace)
+local q_token = lpegpatterns.unsingle
+ + lpegpatterns.undouble
+
local hastexcode = lpegCg(lpegCc("has_tex") * lpegCc(true)) -- cannot be made to work
local component = lpegCg(lpegCc("component") * lpegCs(c_token^1))
local outer = lpegCg(lpegCc("outer") * lpegCs(f_token^1))
-local operation = lpegCg(lpegCc("operation") * lpegCs(o_token^1))
-local arguments = lpegCg(lpegCc("arguments") * lpegCs(a_token^0))
+----- operation = lpegCg(lpegCc("operation") * lpegCs(o_token^1))
+local operation = lpegCg(lpegCc("operation") * lpegCs(q_token + o_token^1))
+local arguments = lpegCg(lpegCc("arguments") * lpegCs(q_token + a_token^0))
local special = lpegCg(lpegCc("special") * lpegCs(s_token^1))
local inner = lpegCg(lpegCc("inner") * lpegCs(i_token^1))
@@ -56,9 +67,16 @@ local inner = lpegCg(lpegCc("inner") * lpegCs(i_token^1))
inner = inner * arguments
special = special * lparent * (operation * arguments)^-1 * rparent
-local referencesplitter = spaces * lpegCf (lpegCt("") * (component + outer)^-1 * (special + inner)^-1 * endofall, rawset)
-local prefixsplitter = lpegCs(lpegP((1-scolon)^1 * scolon)) * #-scolon * lpegCs(lpegP(1)^1)
-local componentsplitter = lpegCs(lpegP((1-scolon)^1)) * scolon * #-scolon * lpegCs(lpegP(1)^1)
+local referencesplitter = spaces
+ * lpegCf (lpegCt("") * (component + outer)^-1 * (special + inner)^-1 * endofall, rawset)
+
+local prefixsplitter = lpegCs(lpegP((1-scolon)^1 * scolon))
+ * #-scolon
+ * lpegCs(lpegP(1)^1)
+
+local componentsplitter = lpegCs(lpegP((1-scolon)^1))
+ * scolon * #-scolon
+ * lpegCs(lpegP(1)^1)
prefixsplitter = componentsplitter
@@ -135,6 +153,8 @@ references.splitcomponent = splitcomponent
-- inspect(splitreference([[ outer :: inner { argument } ]]))
-- inspect(splitreference([[ special ( outer :: operation ) ]]))
+-- inspect(splitreference([[inner(foo,bar)]]))
+
-- inspect(splitreference([[]]))
-- inspect(splitreference([[inner]]))
-- inspect(splitreference([[special(operation{argument,argument})]]))
@@ -152,3 +172,14 @@ references.splitcomponent = splitcomponent
-- inspect(splitreference([[outer::special()]]))
-- inspect(splitreference([[outer::inner{argument}]]))
-- inspect(splitreference([[special(outer::operation)]]))
+
+-- inspect(splitreference([[special(operation)]]))
+-- inspect(splitreference([[special(operation(whatever))]]))
+-- inspect(splitreference([[special(operation{argument,argument{whatever}})]]))
+-- inspect(splitreference([[special(operation{argument{whatever}})]]))
+
+-- inspect(splitreference([[special("operation(")]]))
+-- inspect(splitreference([[special("operation(whatever")]]))
+-- inspect(splitreference([[special(operation{"argument,argument{whatever"})]]))
+-- inspect(splitreference([[special(operation{"argument{whatever"})]]))
+
diff --git a/Master/texmf-dist/tex/context/base/strc-sbe.mkiv b/Master/texmf-dist/tex/context/base/strc-sbe.mkiv
index fc48307ec06..9f1d214cfda 100644
--- a/Master/texmf-dist/tex/context/base/strc-sbe.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-sbe.mkiv
@@ -65,7 +65,7 @@
\resetallstructuremarks
\strc_sectionblock_get_environment\currentsectionblock
\sectionblockparameter\c!before % don't move
- \dostarttagged\t!division\currentsectionblock
+ \dostarttagged\t!division\currentsectionblock % no parents
\to \everybeforesectionblock
\appendtoks
@@ -81,7 +81,9 @@
\def\strc_sectionblock_set[#1][#2]% used to set the default
{\edef\currentsectionblock{#1}% from now on we assume a value
\setupcurrentsectionblock[#2]%
- \ctxcommand{setsectionblock("#1", { bookmark = "\sectionblockparameter\c!bookmark" })}}
+ \clf_setsectionblock{#1}
+ bookmark {\sectionblockparameter\c!bookmark}%
+ \relax}
\let\currentsectionblock\empty % was \s!unknown
@@ -93,7 +95,9 @@
\begingroup
\edef\currentsectionblock{#1}% from now on we assume a value
\setupcurrentsectionblock[#2]%
- \ctxcommand{pushsectionblock("#1", { bookmark = "\sectionblockparameter\c!bookmark" })}%
+ \clf_pushsectionblock{#1}
+ bookmark {\sectionblockparameter\c!bookmark}%
+ \relax
\csname #1true\endcsname % obsolete
\setsystemmode\currentsectionblock
\the\everybeforesectionblock\relax
@@ -102,7 +106,7 @@
\unexpanded\def\stopsectionblock
{\showmessage\m!structures2\currentsectionblock
\the\everyaftersectionblock\relax
- \ctxcommand{popsectionblock()}%
+ \clf_popsectionblock
\endgroup}
%D \starttyping
diff --git a/Master/texmf-dist/tex/context/base/strc-sec.mkiv b/Master/texmf-dist/tex/context/base/strc-sec.mkiv
index 5adfeba1edb..f2a183601cb 100644
--- a/Master/texmf-dist/tex/context/base/strc-sec.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-sec.mkiv
@@ -175,71 +175,68 @@
\setnextinternalreference
\storeinternalreference\currentstructurename\nextinternalreference %
\strc_sectioning_set_reference_prefix
- \ctxcommand{% todo: combine with next call, adapt marks accordingly
- setsectionentry{
- references = {
- internal = \nextinternalreference,
- block = "\currentsectionblock",
- reference = "\currentstructurereference",
- referenceprefix = "\currentstructurereferenceprefix",
- backreference = "\currentstructurebackreference",
- },
- directives = {
- resetset = "\structureparameter\c!sectionresetset",
- },
- metadata = {
- kind = "section",
- name = "\currentstructurename",
- catcodes = \the\ifx\currentstructurecatcodes\empty\catcodetable\else\csname\currentstructurecatcodes\endcsname\fi,
- coding = "\currentstructurecoding",
- \ifx\currentstructurecoding\s!xml
- xmlroot = "\xmldocument",
- \fi
- \ifx\currentstructurexmlsetup\empty \else
- xmlsetup = "\currentstructurexmlsetup",
- \fi
- \ifx\currentstructuresaveinlist\v!no
- nolist = true,
- \fi
- \ifx\currentstructureincrementnumber\v!yes
- increment = "\currentstructureincrementnumber",
- \fi
- },
- titledata = { % we can add mark and reference
- label = \!!bs\detokenize\expandafter{\currentstructurelabel }\!!es,
- title = \!!bs\detokenize\expandafter{\currentstructuretitle }\!!es,
- \ifx\currentstructurebookmark\currentstructuretitle \else
- bookmark = \!!bs\detokenize\expandafter{\currentstructurebookmark }\!!es,
- \fi
- \ifx\currentstructuremarking\currentstructuretitle \else
- marking = \!!bs\detokenize\expandafter{\currentstructuremarking }\!!es,
- \fi
- \ifx\currentstructuresaveinlist\v!no \else
- \ifx\currentstructurelist\currentstructuretitle \else
- list = \!!bs\detokenize\expandafter{\currentstructurelist}\!!es,
- \fi
- \fi
- },
- numberdata = {
- % needed ?
- block = "\currentsectionblock",
- \ifx\currentstructureshownumber\v!no
- hidenumber = true, % titles
- \fi
- % so far
- separatorset = "\structureparameter\c!sectionseparatorset",
- conversion = "\structureparameter\c!sectionconversion", % for good old times sake
- conversionset = "\structureparameter\c!sectionconversionset",
- starter = \!!bs\structureparameter\c!sectionstarter\!!es,
- stopper = \!!bs\structureparameter\c!sectionstopper\!!es,
- set = "\structureparameter\c!sectionset",
- segments = "\structureparameter\c!sectionsegments",
- ownnumber = "\currentstructureownnumber",
- },
- userdata = \!!bs\detokenize{#3}\!!es % will be converted to table at the lua end
+ \clf_setsectionentry
+ references {
+ internal \nextinternalreference\space
+ % block {\currentsectionblock}
+ prefix {\currentstructurereferenceprefix}
+ reference {\currentstructurereference}
+ backreference {\currentstructurebackreference}
}
- }%
- \xdef\currentstructurelistnumber{\ctxcommand{currentsectiontolist()}}%
+ directives {
+ resetset {\structureparameter\c!sectionresetset}
+ }
+ metadata {
+ kind {section}
+ name {\currentstructurename}
+ catcodes \ifx\currentstructurecatcodes\empty\catcodetable\else\csname\currentstructurecatcodes\endcsname\fi\space
+ coding {\currentstructurecoding}
+ \ifx\currentstructurecoding\s!xml
+ xmlroot {\xmldocument}
+ \fi
+ \ifx\currentstructurexmlsetup\empty \else
+ xmlsetup {\currentstructurexmlsetup}
+ \fi
+ \ifx\currentstructuresaveinlist\v!no
+ nolist \space true\space
+ \fi
+ \ifx\currentstructureincrementnumber\v!yes
+ increment {\currentstructureincrementnumber}
+ \fi
+ }
+ titledata {
+ label {\detokenize\expandafter{\currentstructurelabel}}
+ title {\detokenize\expandafter{\currentstructuretitle}}
+ \ifx\currentstructurebookmark\currentstructuretitle \else
+ bookmark {\detokenize\expandafter{\currentstructurebookmark}}
+ \fi
+ \ifx\currentstructuremarking\currentstructuretitle \else
+ marking {\detokenize\expandafter{\currentstructuremarking}}
+ \fi
+ \ifx\currentstructuresaveinlist\v!no \else
+ \ifx\currentstructurelist\currentstructuretitle \else
+ list {\detokenize\expandafter{\currentstructurelist}}
+ \fi
+ \fi
+ }
+ numberdata {
+ % block {\currentsectionblock}
+ \ifx\currentstructureshownumber\v!no
+ hidenumber \space true\space
+ \fi
+ separatorset {\structureparameter\c!sectionseparatorset}
+ conversionset {\structureparameter\c!sectionconversionset}
+ conversion {\structureparameter\c!sectionconversion}
+ starter {\structureparameter\c!sectionstarter}
+ stopper {\structureparameter\c!sectionstopper}
+ set {\structureparameter\c!sectionset}
+ segments {\structureparameter\c!sectionsegments}
+ ownnumber {\currentstructureownnumber}
+ language {\currentlanguage}% for the moment, needed for bookmarks conversion
+ }
+ userdata {\detokenize{#3}}% will be converted to table at the lua end
+ \relax
+ \xdef\currentstructurelistnumber{\clf_currentsectiontolist}%
% \currentstructuresynchronize has to be called someplace, since it introduces a node
\setstructuresynchronization\currentstructurelistnumber
\endgroup}
@@ -266,16 +263,15 @@
% todo: #1 => "#1" ... adapt lua code for name and number
-\def\structurenumber {\ctxcommand{structurenumber()}}
-\def\structuretitle {\ctxcommand{structuretitle()}}
-\def\structurevariable #1{\ctxcommand{structurevariable("#1")}}
-\def\structureuservariable #1{\ctxcommand{structureuservariable("#1")}}
-\def\structurecatcodedget #1{\ctxcommand{structurecatcodedget("#1")}} % bad name
-\def\structuregivencatcodedget #1#2{\ctxcommand{structuregivencatcodedget("#1",\number#2)}} % bad name
-\def\structureautocatcodedget #1#2{\ctxcommand{structureautocatcodedget ("#1","#2")}}
-
-\def\namedstructurevariable #1#2{\ctxcommand{namedstructurevariable ("#1","#2")}}
-\def\namedstructureuservariable#1#2{\ctxcommand{namedstructureuservariable("#1","#2")}}
+\def\structurenumber {\clf_structurenumber}
+\def\structuretitle {\clf_structuretitle}
+\def\structurevariable #1{\clf_structurevariable {#1}}
+\def\structureuservariable #1{\clf_structureuservariable {#1}}
+\def\structurecatcodedget #1{\clf_structurecatcodedget {#1}} % bad name
+\def\structuregivencatcodedget #1#2{\clf_structuregivencatcodedget {#1}#2 } % bad name
+\def\structureautocatcodedget #1#2{\clf_structureautocatcodedget {#1}{#2}}
+\def\namedstructurevariable #1#2{\clf_namedstructurevariable {#1}{#2}}
+\def\namedstructureuservariable#1#2{\clf_namedstructureuservariable{#1}{#2}}
% compatibility issue:
%
@@ -305,18 +301,14 @@
\newconditional\c_strc_rendering_continuous % not used (mkii ?)
-\def\setstructurelevel #1#2{\ctxcommand{setsectionlevel("#1","#2")}} % name, level|parent
-\def\getstructurelevel #1{\ctxcommand{getcurrentsectionlevel("#1")}}% name
-\def\setstructurenumber #1#2{\ctxcommand{setsectionnumber(#1,"#2")}} % level, number (+/-)
-\def\getstructurenumber #1{\ctxcommand{getsectionnumber(#1)}} % level
-\def\getsomestructurenumber #1#2{\ctxcommand{getsectionnumber(#1,"#2")}} % level, what
-\def\getfullstructurenumber #1{\ctxcommand{getfullsectionnumber(#1)}} % level
-\def\getsomefullstructurenumber#1#2{\ctxcommand{getfullsectionnumber(#1,"#2")}}
-\def\getspecificstructuretitle #1{\ctxcommand{getstructuredata("#1","titledata.title",nil,"\headparameter\s!catcodes")}}%
-
-% will be:
-%
-% \def\getfullstructurenumber #1{\ctxcommand{structurenumber(\thenamedheadlevel{#1})}}
+\def\setstructurelevel #1#2{\clf_setstructurelevel {#1}{#2}} % name, level|parent
+\def\getstructurelevel #1{\clf_getstructurelevel {#1}} % name
+\def\setstructurenumber #1#2{\clf_setstructurenumber #1{#2}} % level, number (+/-)
+\def\getstructurenumber #1{\clf_getstructurenumber #1 } % level
+\def\getsomestructurenumber #1#2{\clf_getsomestructurenumber #1{#2}} % level, what
+\def\getfullstructurenumber #1{\clf_getfullstructurenumber #1 } % level
+\def\getsomefullstructurenumber#1#2{\clf_getsomefullstructurenumber #1{#2}} % level, what
+\def\getspecificstructuretitle #1{\clf_getspecificstructuretitle {#1}{\headparameter\s!catcodes}}
% structure heads (like \startchapter)
@@ -412,7 +404,7 @@
\definemarking[\currenthead] [\currentheadsection]%
\definemarking[\currenthead\v!number][\currentheadsection]%
\setupmarking [\currenthead] [\c!filtercommand=\noexpand\sectionheadmarkingtitle {\currenthead}]%
- \setupmarking [\currenthead\c!number][\c!filtercommand=\noexpand\sectionheadmarkingnumber{\currenthead}]%
+ \setupmarking [\currenthead\v!number][\c!filtercommand=\noexpand\sectionheadmarkingnumber{\currenthead}]%
}%
\doifelselist\currenthead\donothing
{\definelist[\currenthead][\c!prefix=\v!no]}%
@@ -430,23 +422,30 @@
\the\everysetuphead
\to \everydefinehead
+\newtoks\everyredefinehead
+
\appendtoks
- \setstructurelevel\currenthead{\thenamedheadlevel\currenthead}%
+ \the\everyredefinehead
\to \everydefinehead
+\appendtoks
+ \setstructurelevel\currenthead{\thenamedheadlevel\currenthead}%
+\to \everyredefinehead
+
\appendtoks
% beware, this is a global register
\begingroup
\edef\currentsectionheadcoupling{\sectionheadcoupling\currenthead}%
\edef\currentsectionheadsection {\sectionheadsection \currentsectionheadcoupling}%
\edef\currentsectionlevel {\sectionlevel \currentsectionheadsection}%
- \ctxcommand{registersection("\currenthead",{
- coupling = "\currentsectionheadcoupling",
- section = "\currentsectionheadsection",
- level = \currentsectionlevel,
- })}%
+ \clf_registersection {\currenthead} {
+ coupling {\currentsectionheadcoupling}
+ section {\currentsectionheadsection}
+ level \currentsectionlevel
+ parent {\currentheadparent}
+ }%
\endgroup
-\to \everydefinehead
+\to \everyredefinehead
\appendtoks
% \setevalue{\e!next \currenthead}{\donexthead [\currenthead]}%
@@ -460,6 +459,15 @@
{\setuevalue\currenthead{\strc_sectioning_handle_nop[\currenthead]}}%
\to \everysetuphead
+\unexpanded\def\doredefinehead#1#2% called at lua end
+ {\pushmacro\currenthead
+ \pushmacro\currentheadparent
+ \edef\currenthead{#1}%
+ \edef\currentheadparent{#2}%
+ \the\everyredefinehead\relax
+ \popmacro\currentheadparent
+ \popmacro\currenthead}
+
\let\currentnamedsection\empty
\unexpanded\def\startnamedsection
@@ -583,8 +591,8 @@
% head -> head
-\def\sectionheadmarkingtitle #1#2{\ctxcommand{markingtitle("#1","#2")}}
-\def\sectionheadmarkingnumber#1#2{\ctxcommand{markingnumber("#1","#2")}}
+\def\sectionheadmarkingtitle #1#2{\clf_markingtitle {#1}{#2}}
+\def\sectionheadmarkingnumber#1#2{\clf_markingnumber{#1}{#2}}
\def\sectionheadcoupling#1{\namedheadparameter{#1}\c!coupling}
\def\sectionheadsection #1{\namedheadparameter{#1}\c!section}
@@ -608,7 +616,7 @@
\unexpanded\def\strc_sectioning_handle_nop_indeed[#1][#2]% for taco: [key=value] variant
{\setfalse\currentstructureown
\triggerautostructurelevel
- \doifassignmentelse{#2}\strc_sectioning_handle_nop_indeed_yes\strc_sectioning_handle_nop_indeed_nop{#1}{#2}}
+ \doifelseassignment{#2}\strc_sectioning_handle_nop_indeed_yes\strc_sectioning_handle_nop_indeed_nop{#1}{#2}}
\unexpanded\def\strc_sectioning_handle_nop_indeed_yes#1#2%
{\strc_sectioning_handle{#1}{#2}{}}
@@ -768,7 +776,7 @@
\unexpanded\def\placeheadtext {\dosingleempty\strc_sectioning_place_head_text } % use with care
\unexpanded\def\placeheadnumber{\dosingleempty\strc_sectioning_place_head_number} % use with care
-\unexpanded\def\strc_sectioning_report{\ctxcommand{reportstructure()}}
+\unexpanded\def\strc_sectioning_report{\clf_reportstructure}
\ifdefined\strc_rendering_initialize_style_and_color \else
@@ -990,15 +998,19 @@
\hskip\s_strc_sectioniong_continuous_signal\relax
\fi}
+% \let\dotagsectionlevel\relax
+
\def\strc_sectioning_before_yes
{\strc_sectioning_check_before\strc_sectioning_handle_page_yes
\headparameter\c!inbetween
- \dostarttagged\t!section\currenthead}
+ \dostarttaggedchained\t!section\currenthead\??head
+% \dotagsectionlevel
+ }
\def\strc_sectioning_before_nop
{\strc_sectioning_check_before\strc_sectioning_handle_page_nop
\headparameter\c!inbetween
- \dostarttagged\currenthead\empty}
+ \dostarttagged\currenthead\empty} % this is a weird one .. needs checking
\def\strc_sectioning_empty_correction
{\ifconditional\c_strc_sectioning_empty
@@ -1045,8 +1057,8 @@
#1%
\fi}
-\def\currentsectioncountervalue {\ctxcommand{depthnumber(\thenamedheadlevel\currenthead)}}
-\def\previoussectioncountervalue{\ctxcommand{depthnumber(\thenamedheadlevel\currenthead-1)}}
+\def\currentsectioncountervalue {\clf_depthnumber\numexpr\thenamedheadlevel\currenthead\relax}
+\def\previoussectioncountervalue{\clf_depthnumber\numexpr\thenamedheadlevel\currenthead+\minusone\relax}
\def\strc_sectioning_handle_page_nop
{\edef\p_continue{\headparameter\c!continue}%
@@ -1101,7 +1113,7 @@
{\dodoubleargument\strc_sectioning_setup_number}
\def\strc_sectioning_setup_number[#1][#2]% todo: reset if at other level
- {\setstructurenumber{\thenamedheadlevel{#1}}{#2}}
+ {\setstructurenumber{\thenamedheadlevel{#1}}{\number#2}}
\def\currentheadnumber{0} % ==> \currentheadnumber
@@ -1148,7 +1160,7 @@
\unexpanded\def\strc_sectioning_initialize_autolevel
{\ifconditional\c_strc_sectioning_auto_levels
- \ctxcommand{autonextstructurelevel(\number\currentheadlevel)}%
+ \clf_autonextstructurelevel\currentheadlevel\relax
\global\setfalse\c_strc_sectioning_auto_levels
\fi}
@@ -1156,7 +1168,7 @@
{\global\settrue\c_strc_sectioning_auto_levels}
\unexpanded\def\finalizeautostructurelevels
- {\ctxcommand{autofinishstructurelevels()}}
+ {\clf_autofinishstructurelevels}
\unexpanded\def\finalizeautostructurelevel
{\dostoptagged
diff --git a/Master/texmf-dist/tex/context/base/strc-syn.lua b/Master/texmf-dist/tex/context/base/strc-syn.lua
index 604365b2d0c..5f3557a6958 100644
--- a/Master/texmf-dist/tex/context/base/strc-syn.lua
+++ b/Master/texmf-dist/tex/context/base/strc-syn.lua
@@ -7,12 +7,12 @@ if not modules then modules = { } end modules ['strc-syn'] = {
}
local next, type = next, type
-local format = string.format
-local allocate = utilities.storage.allocate
-
--- interface to tex end
local context = context
+local implement = interfaces.implement
+
+local allocate = utilities.storage.allocate
+
local sorters = sorters
local structures = structures
@@ -44,77 +44,129 @@ job.register('structures.synonyms.collected', tobesaved, initializer, finalizer)
-- todo: allocate becomes metatable
-local function allocate(class)
- local d = tobesaved[class]
- if not d then
- d = {
- metadata = {
- language = 'en',
- sorted = false,
- class = class
- },
- entries = {
- },
- hash = {
- }
+table.setmetatableindex(tobesaved,function(t,k)
+ local v = {
+ metadata = {
+ language = 'en',
+ sorted = false,
+ class = v
+ },
+ entries = {
+ },
+ hash = {
}
- tobesaved[class] = d
- end
- return d
-end
+ }
+ t[k] = v
+ return v
+end)
function synonyms.define(class,kind)
- local data = allocate(class)
+ local data = tobesaved[class]
data.metadata.kind = kind
end
function synonyms.register(class,kind,spec)
- local data = allocate(class)
+ local data = tobesaved[class]
+ local hash = data.hash
+ local definition = spec.definition
+ local tag = definition.tag or ""
data.metadata.kind = kind -- runtime, not saved in format (yet)
- if not data.hash[spec.definition.tag or ""] then
- data.entries[#data.entries+1] = spec
- data.hash[spec.definition.tag or ""] = spec
+ if not hash[tag] then
+ if definition.used == nil then
+ definition.used = false
+ end
+ if definition.shown == nil then
+ definition.shown = false
+ end
+ local entries = data.entries
+ entries[#entries+1] = spec
+ hash[tag] = spec
end
end
function synonyms.registerused(class,tag)
- local data = allocate(class)
- local dht = data.hash[tag]
- if dht then
- dht.definition.used = true
+ local data = tobesaved[class]
+ local okay = data.hash[tag]
+ if okay then
+ local definition = okay.definition
+ definition.used = true
+ definition.list = true
+ end
+end
+
+function synonyms.registershown(class,tag)
+ local data = tobesaved[class]
+ local okay = data.hash[tag]
+ if okay then
+ local definition = okay.definition
+ definition.shown = true
+ definition.list = true
+ end
+end
+
+function synonyms.isused(class,tag)
+ local data = tobesaved[class]
+ local okay = data.hash[tag]
+ return okay and okay.definition.used
+end
+
+function synonyms.isshown(class,tag)
+ local data = tobesaved[class]
+ local okay = data.hash[tag]
+ return okay and okay.definition.shown
+end
+
+function synonyms.resetused(class)
+ for tag, data in next, tobesaved[class].hash do
+ data.definition.used = false
+ end
+end
+
+function synonyms.resetshown(class)
+ for tag, data in next, tobesaved[class].hash do
+ data.definition.shown = false
end
end
function synonyms.synonym(class,tag)
- local data = allocate(class).hash
- local d = data[tag]
- if d then
- local de = d.definition
- de.used = true
- context(de.synonym)
+ local data = tobesaved[class]
+ local okay = data.hash[tag]
+ if okay then
+ local definition = okay.definition
+ definition.used = true
+ definition.list = true
+ context(definition.synonym)
end
end
function synonyms.meaning(class,tag)
- local data = allocate(class).hash
- local d = data[tag]
- if d then
- local de = d.definition
- de.used = true
- context(de.meaning)
+ local data = tobesaved[class]
+ local okay = data.hash[tag]
+ if okay then
+ local definition = okay.definition
+ definition.shown = true
+ definition.list = true
+ context(definition.meaning)
end
end
synonyms.compare = sorters.comparers.basic -- (a,b)
function synonyms.filter(data,options)
- local result = { }
+ local result = { }
local entries = data.entries
- local all = options and options.criterium == interfaces.variables.all
- for i=1,#entries do
- local entry = entries[i]
- if all or entry.definition.used then
- result[#result+1] = entry
+ local all = options and options.criterium == interfaces.variables.all
+ if all then
+ for i=1,#entries do
+ result[i] = entries[i]
+ end
+ else
+ for i=1,#entries do
+ local entry = entries[i]
+ local definition = entry.definition
+ if definition.list then
+ result[#result+1] = entry
+ end
end
end
data.result = result
@@ -124,12 +176,12 @@ function synonyms.prepare(data)
local result = data.result
if result then
for i=1, #result do
- local r = result[i]
- local rd = r.definition
- if rd then
- local rt = rd.tag
- local sortkey = rt and rt ~= "" and rt or rd.synonym
- r.split = splitter(strip(sortkey))
+ local entry = result[i]
+ local definition = entry.definition
+ if definition then
+ local tag = definition.tag
+ local key = tag ~= "" and tag or definition.synonym
+ entry.split = splitter(strip(key))
end
end
end
@@ -137,25 +189,31 @@ end
function synonyms.sort(data,options)
sorters.sort(data.result,synonyms.compare)
+ data.metadata.sorted = true
end
-function synonyms.finalize(data,options)
- local result = data.result
- data.metadata.nofsorted = #result
- local split = { }
+function synonyms.finalize(data,options) -- mostly the same as registers so we will generalize it: sorters.split
+ local result = data.result
+ local split = { }
+ local nofsplit = 0
+ local lasttag = nil
+ local lasttag = nil
+ local nofdone = 0
for k=1,#result do
- local v = result[k]
- local entry, tag = firstofsplit(v)
- local s = split[entry] -- keeps track of change
- local d
- if not s then
- d = { }
- s = { tag = tag, data = d }
- split[entry] = s
- else
- d = s.data
+ local entry = result[k]
+ local first, tag = firstofsplit(entry)
+ if tag ~= lasttag then
+ -- if trace_registers then
+ -- report_registers("splitting at %a",tag)
+ -- end
+ done = { }
+ nofdone = 0
+ nofsplit = nofsplit + 1
+ lasttag = tag
+ split[nofsplit] = { tag = tag, data = done }
end
- d[#d+1] = v
+ nofdone = nofdone + 1
+ done[nofdone] = entry
end
data.result = split
end
@@ -166,27 +224,25 @@ end
local ctx_synonymentry = context.synonymentry
function synonyms.flush(data,options)
- local kind = data.metadata.kind -- hack, will be done better
local result = data.result
- local sorted = table.sortedkeys(result)
- for k=1,#sorted do
- local letter = sorted[k]
- local sublist = result[letter]
- local data = sublist.data
+ for i=1,#result do
+ local sublist = result[i]
+ local letter = sublist.tag
+ local data = sublist.data
for d=1,#data do
local entry = data[d].definition
ctx_synonymentry(d,entry.tag,entry.synonym,entry.meaning or "")
end
end
- data.result = nil
+ data.result = nil
data.metadata.sorted = false
end
function synonyms.analyzed(class,options)
- local data = synonyms.collected[class]
+ local data = collected[class]
if data and data.entries then
options = options or { }
- sorters.setlanguage(options.language)
+ sorters.setlanguage(options.language,options.method)
synonyms.filter(data,options) -- filters entries to result
synonyms.prepare(data,options) -- adds split table parallel to list table
synonyms.sort(data,options) -- sorts entries in result
@@ -198,12 +254,65 @@ end
function synonyms.process(class,options)
if synonyms.analyzed(class,options) then
- synonyms.flush(synonyms.collected[class],options)
+ synonyms.flush(collected[class],options)
end
end
-commands.registersynonym = synonyms.register
-commands.registerusedsynonym = synonyms.registerused
-commands.synonymmeaning = synonyms.meaning
-commands.synonymname = synonyms.synonym
-commands.processsynonyms = synonyms.process
+-- todo: local higher up
+
+implement { name = "registerusedsynonym", actions = synonyms.registerused, arguments = { "string", "string" } }
+implement { name = "registershownsynonym", actions = synonyms.registershown, arguments = { "string", "string" } }
+implement { name = "synonymmeaning", actions = synonyms.meaning, arguments = { "string", "string" } }
+implement { name = "synonymname", actions = synonyms.synonym, arguments = { "string", "string" } }
+implement { name = "resetusedsynonyms", actions = synonyms.resetused, arguments = "string" }
+implement { name = "resetshownsynonyms", actions = synonyms.resetshown, arguments = "string" }
+
+implement {
+ name = "doifelsesynonymused",
+ actions = { synonyms.isused, commands.doifelse },
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "doifelsesynonymshown",
+ actions = { synonyms.isshown, commands.doifelse },
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "registersynonym",
+ actions = synonyms.register,
+ arguments = {
+ "string",
+ "string",
+ {
+ { "metadata", {
+ { "catcodes", "integer" },
+ { "coding" },
+ { "xmlroot" }
+ }
+ },
+ {
+ "definition", {
+ { "tag" },
+ { "synonym" },
+ { "meaning" },
+ { "used", "boolean" }
+ }
+ }
+ }
+ }
+}
+
+implement {
+ name = "processsynonyms",
+ actions = synonyms.process,
+ arguments = {
+ "string",
+ {
+ { "criterium" },
+ { "language" },
+ { "method" }
+ }
+ }
+}
diff --git a/Master/texmf-dist/tex/context/base/strc-syn.mkiv b/Master/texmf-dist/tex/context/base/strc-syn.mkiv
index 73aca18e601..0c132a602f0 100644
--- a/Master/texmf-dist/tex/context/base/strc-syn.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-syn.mkiv
@@ -15,6 +15,93 @@
\registerctxluafile{strc-syn}{1.001}
+%D Although we could nowadays build this on top of regular lists we keep this
+%D more efficient variant around. Eventually we can add some options to lists
+%D that also provide such functionality but at the cost of much more overhead.
+%D
+%D We show a usage of both synonyms and sorts, which are deep down variants of
+%D so called simple lists. A definition looks like this:
+%D
+%D \startbuffer
+%D \definesynonyms
+%D [myabbreviation]
+%D
+%D \setupsynonyms
+%D [myabbreviation]
+%D [headstyle=bold,
+%D headcolor=darkred,
+%D synonymstyle=boldslanted,
+%D synonymcolor=darkblue,
+%D textstyle=slanted,
+%D textcolor=darkgreen,
+%D style=normal,
+%D color=darkyellow]
+%D
+%D \definesorting
+%D [mylogo]
+%D
+%D \setupsorting
+%D [mylogo]
+%D [style=bold,
+%D color=darkmagenta]
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D More complex definitions involves commands to call up meanings and such. The
+%D use of the defined commands is as follows: \
+%D
+%D \startbuffer
+%D \myabbreviation [FIRST] {TheFirst} {The First Words}
+%D \myabbreviation [SECOND] {TheSecond} {The Second Words}
+%D \myabbreviation [THIRD] {TheThird} {The Third Words}
+%D
+%D \mylogo [FOURTH] {TheFourth}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D By default a synonym is just typeset and flagges as being used, so that in
+%D a list it wil be shows with its meaning. You can however also expand the
+%D meaning automatically at first use:
+%D
+%D \startbuffer
+%D \setupsynonyms[myabbreviation][alternative=first]
+%D
+%D We have \FIRST, \SECOND\ and also \THIRD\ but no \FOURTH.
+%D
+%D We have \FIRST, \SECOND\ and also \THIRD\ but no \FOURTH.
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D We can change the order, as demonstrated in:
+%D
+%D \startbuffer
+%D \resetshownsynonyms[myabbreviation]
+%D
+%D \setupsynonyms[myabbreviation][alternative=last]
+%D
+%D We have \FIRST\ and \THIRD\ or \FOURTH.
+%D
+%D We have \FIRST\ and \THIRD\ or \FOURTH.
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D A list is called up with:
+%D
+%D \startbuffer
+%D \placelistofsynonyms[myabbreviation]
+%D
+%D \placelistofsorts[mylogo]
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D The lists are constructions (like descriptions are) and can be set up
+%D likewise.
+
% todo: add 'define only' option to descriptions, then add sorting (also based on key)
% and call to definition -> replaces this module
@@ -22,7 +109,7 @@
% split but common in lua
-\def\preprocessexpansion#1#2#3#4%
+\def\preprocessexpansion#1#2#3#4% do this at the lua end if still needed
{\ifx#1\s!xml
\xmlstartraw
\xdef#2{#4}%
@@ -100,6 +187,7 @@
\setuvalue{\??constructioninitializer\v!simplelist}%
{\let\currentsimplelist \currentconstruction
\let\constructionparameter \simplelistparameter
+ \let\constructionnamespace \??simplelist
\let\detokenizedconstructionparameter\detokenizedsimplelistparameter
\let\letconstructionparameter \letsimplelistparameter
\let\useconstructionstyleandcolor \usesimpleliststyleandcolor
@@ -175,7 +263,7 @@
%
\presetheadtext[#2=\Word{#2}]% changes the \if...argument
%
- \setvalue{\e!setup #2\e!endsetup}{\setupsynonym[#1]}% obsolete definition
+ \setvalue{\e!setup #2\e!endsetup}{\setupsynonyms[#1]}% obsolete definition
\setvalue{\e!place \e!listof#2}{\placelistofsynonyms[#1]}% accepts extra argument
\setvalue{\e!complete\e!listof#2}{\completelistofsynonyms[#1]}}
@@ -194,21 +282,27 @@
% todo: error message
\else
\edef\currentsynonymexpansion{\simplelistparameter\c!expansion}%
- \preprocessexpansion\currentsynonymexpansion\currentsynonymtext \currentsynonymcoding{#4}%
- \preprocessexpansion\currentsynonymexpansion\currentsynonymmeaning\currentsynonymcoding{#5}%
- \ctxcommand{registersynonym("\currentsynonym", "synonym", {
- metadata = {
- catcodes = \the\catcodetable,
- coding = "\currentsynonymcoding",
- xmlroot = \ifx\currentsynonymcoding\s!xml "\xmldocument" \else nil \fi,
- },
- definition = {
- tag = "\currentsynonymtag",
- synonym = \!!bs\currentsynonymtext\!!es,
- meaning = \!!bs\currentsynonymmeaning\!!es,
- used = false,
- }
- })}%
+ \preprocessexpansion\currentsynonymexpansion\m_synonyms_text \currentsynonymcoding{#4}%
+ \preprocessexpansion\currentsynonymexpansion\m_synonyms_meaning\currentsynonymcoding{#5}%
+ \clf_registersynonym
+ {\currentsynonym}%
+ {synonym}%
+ {%
+ metadata {%
+ catcodes \catcodetable
+ coding {\currentsynonymcoding}%
+ \ifx\currentsynonymcoding\s!xml
+ xmlroot {\xmldocument}%
+ \fi
+ }%
+ definition {%
+ tag {\currentsynonymtag}%
+ synonym {\m_synonyms_text}%
+ meaning {\m_synonyms_meaning}%
+ % used false
+ }%
+ }%
+ \relax
\doif{#1}\v!yes{\setuxvalue\currentsynonymtag{\strc_synonyms_insert{\currentsynonym}{\currentsynonymtag}}}%
\fi
\endgroup}
@@ -217,43 +311,120 @@
{\dodoubleargument\strc_synonyms_register}
\def\strc_synonyms_register[#1][#2]%
- {\ctxcommand{registerusedsynonym("#1","#2")}}
+ {\clf_registerusedsynonym{#1}{#2}}
+
+\unexpanded\def\currentsynonymname {\clf_synonymname {\currentsimplelist}{\currentsynonymtag}}
+\unexpanded\def\currentsynonymmeaning {\clf_synonymmeaning {\currentsimplelist}{\currentsynonymtag}}
+\unexpanded\def\doifelsecurrentsynonymused {\clf_doifelsesynonymused {\currentsimplelist}{\currentsynonymtag}}
+\unexpanded\def\doifelsecurrentsynonymshown{\clf_doifelsesynonymshown{\currentsimplelist}{\currentsynonymtag}}
+\unexpanded\def\resetusedsynonyms [#1]{\clf_resetusedsynonyms {#1}}
+\unexpanded\def\resetshownsynonyms [#1]{\clf_resetshownsynonyms {#1}}
+
+\installcorenamespace{simplelistalternative} % specific ways of rendering a list
+\installcorenamespace{simplelistrenderings} % a namespace for setups (rather local)
+
+\installcommandhandler \??simplelistalternative {simplelistalternative} \??simplelistalternative
+
+\setupsimplelist
+ [\v!synonym]
+ [\c!alternative=\v!normal]
\unexpanded\def\strc_synonyms_insert_meaning#1#2% name tag
{\begingroup
\def\currentsimplelist{#1}%
- \usesimpleliststyleandcolor\c!textstyle\c!textcolor
- \simplelistparameter\c!textcommand{\ctxcommand{synonymmeaning("#1","#2")}}%
+ \fastsetup{\??simplelistrenderings:\v!text}%
\endgroup}
\unexpanded\def\strc_synonyms_insert#1#2% name tag
{\begingroup
\edef\currentsimplelist{#1}%
- \let\currentsynonym\currentsimplelist % for a while
- \def\currentsynonymtag{#2}%
- \dostarttagged\t!synonym\currentsynonym
- \dotagsynonym
- \usesimpleliststyleandcolor\c!synonymstyle\c!synonymcolor
- \simplelistparameter\c!synonymcommand{\ctxcommand{synonymname("#1","#2")}}%
- \dostoptagged
+ \let \currentsynonym\currentsimplelist % for a while
+ \def \currentsynonymtag{#2}%
+ \edef\currentsimplelistalternative{\simplelistparameter\c!alternative}%
+ \fastsetup{\??simplelistrenderings:\v!synonym:\currentsimplelistalternative}%
\normalexpanded{\endgroup\simplelistparameter\c!next}}
+% \setupsimplelistalternative
+% [\c!command=\strictsimplelistparameter\c!command]
+
+\definesimplelistalternative
+ [\v!normal]
+ [\c!inbetween=\space,
+ \c!left=(,
+ \c!right=)]
+
+\definesimplelistalternative
+ [\v!first]
+ [\v!normal]
+
+\definesimplelistalternative
+ [\v!last]
+ [\v!normal]
+
+\startsetups[\??simplelistrenderings::\v!synonym]
+ \begingroup
+ \dostarttaggedchained\t!synonym\currentsynonym\??simplelist
+ \dotagsynonym
+ \usesimpleliststyleandcolor\c!synonymstyle\c!synonymcolor
+ \simplelistparameter\c!synonymcommand{\currentsynonymname}%
+ \dostoptagged
+ \endgroup
+\stopsetups
+
+\startsetups[\??simplelistrenderings::\v!text]
+ \begingroup
+ \usesimpleliststyleandcolor\c!textstyle\c!textcolor
+ \simplelistparameter\c!textcommand{\currentsynonymmeaning}%
+ \endgroup
+\stopsetups
+
+\startsetups[\??simplelistrenderings:\v!synonym:\v!normal]
+ \fastsetup{\??simplelistrenderings::\v!synonym}
+\stopsetups
+
+\startsetups[\??simplelistrenderings:\v!synonym:\v!first]
+ \fastsetup{\??simplelistrenderings::\v!synonym}
+ \doifelsecurrentsynonymshown \donothing {
+ \simplelistalternativeparameter\c!inbetween
+ \simplelistalternativeparameter\c!left
+ \fastsetup{\??simplelistrenderings::\v!text}
+ \simplelistalternativeparameter\c!right
+ }
+\stopsetups
+
+\startsetups[\??simplelistrenderings:\v!synonym:\v!last]
+ \doifelsecurrentsynonymshown {
+ \fastsetup{\??simplelistrenderings::\v!synonym}
+ } {
+ \fastsetup{\??simplelistrenderings::\v!text}
+ \simplelistalternativeparameter\c!inbetween
+ \simplelistalternativeparameter\c!left
+ \fastsetup{\??simplelistrenderings::\v!synonym}
+ \simplelistalternativeparameter\c!right
+ }
+\stopsetups
+
\unexpanded\def\placelistofsynonyms
{\dodoubleempty\strc_synonyms_place_list}
\def\strc_synonyms_place_list[#1][#2]%
{\begingroup
\edef\currentsimplelist{#1}%
- \strc_constructions_initialize{#1}%
- \setupcurrentsimplelist[#2]%
- \let\synonymentry\strc_synonym_normal
- \startpacked
- \ctxcommand{processsynonyms('#1',{
- criterium = "\simplelistparameter\c!criterium",
- language = "\simplelistparameter\s!language",
- method = "\simplelistparameter\c!method",
- })}%
- \stoppacked
+ \doifelsecommandhandler\??simplelist\currentsimplelist
+ {\strc_constructions_initialize{#1}%
+ \setupcurrentsimplelist[#2]%
+ \let\synonymentry\strc_synonym_normal
+ \startpacked
+ \clf_processsynonyms
+ {#1}%
+ {%
+ criterium {\simplelistparameter\c!criterium}%
+ language {\simplelistparameter\s!language}%
+ method {\simplelistparameter\c!method}%
+ }%
+ \relax
+ \stoppacked}%
+ {}% todo: message that invalid
\endgroup}
\def\completelistofsynonyms
@@ -262,10 +433,12 @@
\def\strc_synonyms_complete_list[#1][#2]%
{\begingroup
\edef\currentsimplelist{#1}%
- \normalexpanded{\startnamedsection[\v!chapter][\c!title={\headtext{\simplelistparameter\s!multi}},\c!reference=#1]}%
- \strc_synonyms_place_list[#1][#2]%
- \page
- \stopnamedsection
+ \doifelsecommandhandler\??simplelist\currentsimplelist
+ {\normalexpanded{\startnamedsection[\v!chapter][\c!title={\headtext{\simplelistparameter\s!multi}},\c!reference=#1]}%
+ \strc_synonyms_place_list[#1][#2]%
+ \page
+ \stopnamedsection}%
+ {}% todo: message that invalid
\endgroup}
\unexpanded\def\strc_synonym_normal#1#2#3#4%
@@ -337,40 +510,65 @@
\else
\edef\currentsortingexpansion{\simplelistparameter\c!expansion}%
\preprocessexpansion\currentsortingexpansion\currentsortingtext\currentsortingcoding{#4}%
- \ctxcommand{registersynonym("\currentsorting", "sorting", {
- metadata = {
- catcodes = \the\catcodetable,
- coding = "\currentsortingcoding",
- xmlroot = \ifx\currentsortingcoding\s!xml "\xmldocument" \else nil \fi,
- },
- definition = {
- tag = "\currentsortingtag",
- synonym = \!!bs\currentsortingtext\!!es,
- % used = false,
- }
- })}%
+ \clf_registersynonym
+ {\currentsorting}%
+ {sorting}%
+ {%
+ metadata {%
+ catcodes \catcodetable
+ coding {\currentsortingcoding}%
+ \ifx\currentsortingcoding\s!xml
+ xmlroot {\xmldocument}%
+ \fi
+ }%
+ definition {%
+ tag {\currentsortingtag}%
+ synonym {\currentsortingtext}%
+ % used false
+ }%
+ }%
+ \relax
\doif{#1}\v!yes{\setuxvalue\currentsortingtag{\strc_sorting_insert{\currentsorting}{\currentsortingtag}}}%
\fi
\endgroup}
+\unexpanded\def\currentsortingname {\clf_synonymname {\currentsimplelist}{\currentsortingtag}}
+\unexpanded\def\doifelsecurrentsortingused {\clf_doifelsesynonymused {\currentsimplelist}{\currentsortingtag}}
+\unexpanded\def\resetusedsortings [#1]{\clf_resetusedsynonyms {#1}}
+
+\setupsimplelist
+ [\v!sorting]
+ [\c!alternative=\v!normal]
+
\unexpanded\def\strc_sorting_insert#1#2% name tag
{\begingroup
% no kap currently, of .. we need to map cap onto WORD
\edef\currentsorting{#1}%
- \def\currentsortingtag{#2}%
- \let\currentsimplelist\currentsorting
- \dostarttagged\t!sorting\currentsorting
- \dotagsorting
- \usesimpleliststyleandcolor\c!style\c!color
- \ctxcommand{synonymname("#1","#2")}%
- \dostoptagged
+ \def \currentsortingtag{#2}%
+ \let \currentsimplelist\currentsorting
+ \edef\currentsimplelistalternative{\simplelistparameter\c!alternative}%
+ \fastsetup{\??simplelistrenderings:\v!sorting:\currentsimplelistalternative}%
\normalexpanded{\endgroup\simplelistparameter\c!next}}
+\startsetups [\??simplelistrenderings:\v!sorting:\v!normal]
+ \fastsetup{\??simplelistrenderings::\v!sorting}%
+\stopsetups
+
+\startsetups [\??simplelistrenderings::\v!sorting]
+ \begingroup
+ \dostarttaggedchained\t!sorting\currentsorting\??simplelist
+ \dotagsorting
+ \usesimpleliststyleandcolor\c!style\c!color
+ \currentsortingname
+ \dostoptagged
+ \endgroup
+\stopsetups
+
\unexpanded\def\registersort
{\dodoubleargument\strc_sorting_register}
\def\strc_sorting_register[#1][#2]%
- {\ctxcommand{registerusedsynonym("#1","#2")}}
+ {\clf_registerusedsynonym{#1}{#2}}
% before after
%
@@ -391,11 +589,14 @@
\let\synonymentry\strc_sorting_command
\fi
\startpacked
- \ctxcommand{processsynonyms('#1',{
- criterium = "\simplelistparameter\c!criterium",
- language = "\simplelistparameter\s!language",
- method = "\simplelistparameter\c!method",
- })}%
+ \clf_processsynonyms
+ {#1}%
+ {%
+ criterium {\simplelistparameter\c!criterium}%
+ language {\simplelistparameter\s!language}%
+ method {\simplelistparameter\c!method}%
+ }%
+ \relax
\stoppacked
\endgroup}
@@ -423,6 +624,15 @@
%D Presets.
+% To be considered:
+%
+% \setupsimplelist
+% [\v!sorting]
+% [\c!headstyle=\simplelistparameter\c!synonymstyle,
+% \c!headcolor=\simplelistparameter\c!synonymcolor,
+% \c!style=\simplelistparameter\c!textstyle,
+% \c!color=\simplelistparameter\c!textcolor]
+
\definesynonyms
[\v!abbreviation]
[\v!abbreviations]
diff --git a/Master/texmf-dist/tex/context/base/strc-tag.lua b/Master/texmf-dist/tex/context/base/strc-tag.lua
index 7e5c6f99377..637d74e8c08 100644
--- a/Master/texmf-dist/tex/context/base/strc-tag.lua
+++ b/Master/texmf-dist/tex/context/base/strc-tag.lua
@@ -6,189 +6,219 @@ if not modules then modules = { } end modules ['strc-tag'] = {
license = "see context related readme files"
}
--- This is rather experimental code.
+-- This is rather experimental code. Tagging happens on the fly and there are two analysers
+-- involved: the pdf backend tagger and the exporter. They share data but there are subtle
+-- differences. Each tag carries a specification and these can be accessed by attribute (the
+-- end of the chain tag) or by so called fullname which is a tagname combined with a number.
+local type, next = type, next
local insert, remove, unpack, concat = table.insert, table.remove, table.unpack, table.concat
-local gsub, find, topattern, format = string.gsub, string.find, string.topattern, string.format
-local lpegmatch = lpeg.match
+local find, topattern, format = string.find, string.topattern, string.format
+local lpegmatch, P, S, C, Cc = lpeg.match, lpeg.P, lpeg.S, lpeg.C, lpeg.Cc
local texattribute = tex.attribute
local allocate = utilities.storage.allocate
local settings_to_hash = utilities.parsers.settings_to_hash
+local setmetatableindex = table.setmetatableindex
local trace_tags = false trackers.register("structures.tags", function(v) trace_tags = v end)
local report_tags = logs.reporter("structure","tags")
-local attributes, structures = attributes, structures
+local attributes = attributes
+local structures = structures
+local implement = interfaces.implement
local a_tagged = attributes.private('tagged')
local unsetvalue = attributes.unsetvalue
local codeinjections = backends.codeinjections
-local taglist = allocate()
-local properties = allocate()
-local labels = allocate()
-local stack = { }
-local chain = { }
-local ids = { }
-local enabled = false
-local tagdata = { } -- used in export
-local tagmetadata = { } -- used in export
-
-local tags = structures.tags
-tags.taglist = taglist -- can best be hidden
-tags.labels = labels
-tags.data = tagdata
-tags.metadata = tagmetadata
-
-local properties = allocate {
-
- document = { pdf = "Div", nature = "display" },
-
- division = { pdf = "Div", nature = "display" },
- paragraph = { pdf = "P", nature = "mixed" },
- p = { pdf = "P", nature = "mixed" },
- construct = { pdf = "Span", nature = "inline" },
- highlight = { pdf = "Span", nature = "inline" },
-
- section = { pdf = "Sect", nature = "display" },
- sectiontitle = { pdf = "H", nature = "mixed" },
- sectionnumber = { pdf = "H", nature = "mixed" },
- sectioncontent = { pdf = "Div", nature = "display" },
-
- itemgroup = { pdf = "L", nature = "display" },
- item = { pdf = "Li", nature = "display" },
- itemtag = { pdf = "Lbl", nature = "mixed" },
- itemcontent = { pdf = "LBody", nature = "mixed" },
-
- description = { pdf = "Div", nature = "display" },
- descriptiontag = { pdf = "Div", nature = "mixed" },
- descriptioncontent = { pdf = "Div", nature = "mixed" },
- descriptionsymbol = { pdf = "Span", nature = "inline" }, -- note reference
-
- verbatimblock = { pdf = "Code", nature = "display" },
- verbatimlines = { pdf = "Code", nature = "display" },
- verbatimline = { pdf = "Code", nature = "mixed" },
- verbatim = { pdf = "Code", nature = "inline" },
-
- lines = { pdf = "Code", nature = "display" },
- line = { pdf = "Code", nature = "mixed" },
-
- synonym = { pdf = "Span", nature = "inline" },
- sorting = { pdf = "Span", nature = "inline" },
-
- register = { pdf = "Div", nature = "display" },
- registersection = { pdf = "Div", nature = "display" },
- registertag = { pdf = "Span", nature = "mixed" },
- registerentries = { pdf = "Div", nature = "display" },
- registerentry = { pdf = "Span", nature = "mixed" },
- registersee = { pdf = "Span", nature = "mixed" },
- registerpages = { pdf = "Span", nature = "mixed" },
- registerpage = { pdf = "Span", nature = "inline" },
- registerpagerange = { pdf = "Span", nature = "mixed" },
-
- table = { pdf = "Table", nature = "display" },
- tablerow = { pdf = "TR", nature = "display" },
- tablecell = { pdf = "TD", nature = "mixed" },
-
- tabulate = { pdf = "Table", nature = "display" },
- tabulaterow = { pdf = "TR", nature = "display" },
- tabulatecell = { pdf = "TD", nature = "mixed" },
-
- list = { pdf = "TOC", nature = "display" },
- listitem = { pdf = "TOCI", nature = "display" },
- listtag = { pdf = "Lbl", nature = "mixed" },
- listcontent = { pdf = "P", nature = "mixed" },
- listdata = { pdf = "P", nature = "mixed" },
- listpage = { pdf = "Reference", nature = "mixed" },
-
- delimitedblock = { pdf = "BlockQuote", nature = "display" },
- delimited = { pdf = "Quote", nature = "inline" },
- subsentence = { pdf = "Span", nature = "inline" },
-
- label = { pdf = "Span", nature = "mixed" },
- number = { pdf = "Span", nature = "mixed" },
-
- float = { pdf = "Div", nature = "display" }, -- Figure
- floatcaption = { pdf = "Caption", nature = "mixed" },
- floatlabel = { pdf = "Span", nature = "inline" },
- floatnumber = { pdf = "Span", nature = "inline" },
- floattext = { pdf = "Span", nature = "mixed" },
- floatcontent = { pdf = "P", nature = "mixed" },
-
- image = { pdf = "P", nature = "mixed" },
- mpgraphic = { pdf = "P", nature = "mixed" },
-
- formulaset = { pdf = "Div", nature = "display" },
- formula = { pdf = "Div", nature = "display" }, -- Formula
- formulacaption = { pdf = "Span", nature = "mixed" },
- formulalabel = { pdf = "Span", nature = "mixed" },
- formulanumber = { pdf = "Span", nature = "mixed" },
- formulacontent = { pdf = "P", nature = "display" },
- subformula = { pdf = "Div", nature = "display" },
-
- link = { pdf = "Link", nature = "inline" },
-
- margintextblock = { pdf = "Span", nature = "inline" },
- margintext = { pdf = "Span", nature = "inline" },
-
- math = { pdf = "Div", nature = "inline" }, -- no display
- mn = { pdf = "Span", nature = "mixed" },
- mi = { pdf = "Span", nature = "mixed" },
- mo = { pdf = "Span", nature = "mixed" },
- ms = { pdf = "Span", nature = "mixed" },
- mrow = { pdf = "Span", nature = "display" },
- msubsup = { pdf = "Span", nature = "display" },
- msub = { pdf = "Span", nature = "display" },
- msup = { pdf = "Span", nature = "display" },
- merror = { pdf = "Span", nature = "mixed" },
- munderover = { pdf = "Span", nature = "display" },
- munder = { pdf = "Span", nature = "display" },
- mover = { pdf = "Span", nature = "display" },
- mtext = { pdf = "Span", nature = "mixed" },
- mfrac = { pdf = "Span", nature = "display" },
- mroot = { pdf = "Span", nature = "display" },
- msqrt = { pdf = "Span", nature = "display" },
- mfenced = { pdf = "Span", nature = "display" },
- maction = { pdf = "Span", nature = "display" },
-
- mtable = { pdf = "Table", nature = "display" }, -- might change
- mtr = { pdf = "TR", nature = "display" }, -- might change
- mtd = { pdf = "TD", nature = "display" }, -- might change
-
- ignore = { pdf = "Span", nature = "mixed" },
- metadata = { pdf = "Div", nature = "display" },
- metavariable = { pdf = "Span", nature = "mixed" },
-
- mid = { pdf = "Span", nature = "inline" },
- sub = { pdf = "Span", nature = "inline" },
- sup = { pdf = "Span", nature = "inline" },
- subsup = { pdf = "Span", nature = "inline" },
-
- combination = { pdf = "Span", nature = "display" },
- combinationpair = { pdf = "Span", nature = "display" },
- combinationcontent = { pdf = "Span", nature = "mixed" },
- combinationcaption = { pdf = "Span", nature = "mixed" },
+local taglist = allocate() -- access by attribute
+local specifications = allocate() -- access by fulltag
+local labels = allocate()
+local stack = { }
+local chain = { }
+local ids = { }
+local enabled = false
+local tagcontext = { }
+local tagpatterns = { }
+local lasttags = { }
+local stacksize = 0
+local metadata = nil -- applied to the next element
+
+local tags = structures.tags
+tags.taglist = taglist -- can best be hidden
+tags.labels = labels
+tags.patterns = tagpatterns
+tags.specifications = specifications
+
+-- Tags are internally stored as:
+--
+-- tag>number tag>number tag>number
+
+local p_splitter = C((1-S(">"))^1) * P(">") * C(P(1)^1)
+tagpatterns.splitter = p_splitter
+
+local properties = allocate {
+
+ document = { pdf = "Div", nature = "display" },
+
+ division = { pdf = "Div", nature = "display" },
+ paragraph = { pdf = "P", nature = "mixed" },
+ p = { pdf = "P", nature = "mixed" },
+ construct = { pdf = "Span", nature = "inline" },
+ highlight = { pdf = "Span", nature = "inline" },
+
+ section = { pdf = "Sect", nature = "display" },
+ sectiontitle = { pdf = "H", nature = "mixed" },
+ sectionnumber = { pdf = "H", nature = "mixed" },
+ sectioncontent = { pdf = "Div", nature = "display" },
+
+ itemgroup = { pdf = "L", nature = "display" },
+ item = { pdf = "LI", nature = "display" },
+ itemtag = { pdf = "Lbl", nature = "mixed" },
+ itemcontent = { pdf = "LBody", nature = "mixed" },
+ itemhead = { pdf = "Div", nature = "display" },
+ itembody = { pdf = "Div", nature = "display" },
+
+ description = { pdf = "Div", nature = "display" },
+ descriptiontag = { pdf = "Div", nature = "mixed" },
+ descriptioncontent = { pdf = "Div", nature = "mixed" },
+ descriptionsymbol = { pdf = "Span", nature = "inline" }, -- note reference
+
+ verbatimblock = { pdf = "Code", nature = "display" },
+ verbatimlines = { pdf = "Code", nature = "display" },
+ verbatimline = { pdf = "Code", nature = "mixed" },
+ verbatim = { pdf = "Code", nature = "inline" },
+
+ lines = { pdf = "Code", nature = "display" },
+ line = { pdf = "Code", nature = "mixed" },
+
+ synonym = { pdf = "Span", nature = "inline" },
+ sorting = { pdf = "Span", nature = "inline" },
+
+ register = { pdf = "Div", nature = "display" },
+ registerlocation = { pdf = "Span", nature = "inline" },
+ registersection = { pdf = "Div", nature = "display" },
+ registertag = { pdf = "Span", nature = "mixed" },
+ registerentries = { pdf = "Div", nature = "display" },
+ registerentry = { pdf = "Div", nature = "display" },
+ registercontent = { pdf = "Span", nature = "mixed" },
+ registersee = { pdf = "Span", nature = "mixed" },
+ registerpages = { pdf = "Span", nature = "mixed" },
+ registerpage = { pdf = "Span", nature = "mixed" },
+ registerseparator = { pdf = "Span", nature = "inline" },
+ registerpagerange = { pdf = "Span", nature = "mixed" },
+
+ table = { pdf = "Table", nature = "display" },
+ tablerow = { pdf = "TR", nature = "display" },
+ tablecell = { pdf = "TD", nature = "mixed" },
+
+ tabulate = { pdf = "Table", nature = "display" },
+ tabulaterow = { pdf = "TR", nature = "display" },
+ tabulatecell = { pdf = "TD", nature = "mixed" },
+
+ list = { pdf = "TOC", nature = "display" },
+ listitem = { pdf = "TOCI", nature = "display" },
+ listtag = { pdf = "Lbl", nature = "mixed" },
+ listcontent = { pdf = "P", nature = "mixed" },
+ listdata = { pdf = "P", nature = "mixed" },
+ listpage = { pdf = "Reference", nature = "mixed" },
+
+ delimitedblock = { pdf = "BlockQuote", nature = "display" },
+ delimited = { pdf = "Quote", nature = "inline" },
+ subsentence = { pdf = "Span", nature = "inline" },
+
+ label = { pdf = "Span", nature = "mixed" },
+ number = { pdf = "Span", nature = "mixed" },
+
+ float = { pdf = "Div", nature = "display" }, -- Figure
+ floatcaption = { pdf = "Caption", nature = "mixed" },
+ floatlabel = { pdf = "Span", nature = "inline" },
+ floatnumber = { pdf = "Span", nature = "inline" },
+ floattext = { pdf = "Span", nature = "mixed" },
+ floatcontent = { pdf = "P", nature = "mixed" },
+
+ image = { pdf = "P", nature = "mixed" },
+ mpgraphic = { pdf = "P", nature = "mixed" },
+
+ formulaset = { pdf = "Div", nature = "display" },
+ formula = { pdf = "Div", nature = "display" }, -- Formula
+ formulacaption = { pdf = "Span", nature = "mixed" },
+ formulalabel = { pdf = "Span", nature = "mixed" },
+ formulanumber = { pdf = "Span", nature = "mixed" },
+ formulacontent = { pdf = "P", nature = "display" },
+ subformula = { pdf = "Div", nature = "display" },
+
+ link = { pdf = "Link", nature = "inline" },
+
+ margintextblock = { pdf = "Span", nature = "inline" },
+ margintext = { pdf = "Span", nature = "inline" },
+
+ math = { pdf = "Div", nature = "inline" }, -- no display
+ mn = { pdf = "Span", nature = "mixed" },
+ mi = { pdf = "Span", nature = "mixed" },
+ mo = { pdf = "Span", nature = "mixed" },
+ ms = { pdf = "Span", nature = "mixed" },
+ mrow = { pdf = "Span", nature = "display" },
+ msubsup = { pdf = "Span", nature = "display" },
+ msub = { pdf = "Span", nature = "display" },
+ msup = { pdf = "Span", nature = "display" },
+ merror = { pdf = "Span", nature = "mixed" },
+ munderover = { pdf = "Span", nature = "display" },
+ munder = { pdf = "Span", nature = "display" },
+ mover = { pdf = "Span", nature = "display" },
+ mtext = { pdf = "Span", nature = "mixed" },
+ mfrac = { pdf = "Span", nature = "display" },
+ mroot = { pdf = "Span", nature = "display" },
+ msqrt = { pdf = "Span", nature = "display" },
+ mfenced = { pdf = "Span", nature = "display" },
+ maction = { pdf = "Span", nature = "display" },
+
+ mstacker = { pdf = "Span", nature = "display" }, -- these are only internally used
+ mstackertop = { pdf = "Span", nature = "display" }, -- these are only internally used
+ mstackerbot = { pdf = "Span", nature = "display" }, -- these are only internally used
+ mstackermid = { pdf = "Span", nature = "display" }, -- these are only internally used
+
+ mtable = { pdf = "Table", nature = "display" }, -- might change
+ mtr = { pdf = "TR", nature = "display" }, -- might change
+ mtd = { pdf = "TD", nature = "display" }, -- might change
+
+ ignore = { pdf = "Span", nature = "mixed" }, -- used internally
+ private = { pdf = "Span", nature = "mixed" }, -- for users (like LS) when they need it
+ metadata = { pdf = "Div", nature = "display" },
+ metavariable = { pdf = "Span", nature = "mixed" },
+
+ mid = { pdf = "Span", nature = "inline" },
+ sub = { pdf = "Span", nature = "inline" },
+ sup = { pdf = "Span", nature = "inline" },
+ subsup = { pdf = "Span", nature = "inline" },
+
+ combination = { pdf = "Span", nature = "display" },
+ combinationpair = { pdf = "Span", nature = "display" },
+ combinationcontent = { pdf = "Span", nature = "mixed" },
+ combinationcaption = { pdf = "Span", nature = "mixed" },
}
-function tags.detailedtag(tag,detail,attribute)
- if not attribute then
- attribute = texattribute[a_tagged]
- end
+tags.properties = properties
+
+local patterns = setmetatableindex(function(t,tag)
+ local v = topattern("^" .. tag .. ">")
+ t[tag] = v
+ return v
+end)
+
+function tags.locatedtag(tag)
+ local attribute = texattribute[a_tagged]
if attribute >= 0 then
- local tl = taglist[attribute]
- if tl then
- local pattern
- if detail and detail ~= "" then
- pattern = "^" .. tag .. ":".. detail .. "%-"
- else
- pattern = "^" .. tag .. "%-"
- end
- for i=#tl,1,-1 do
- local tli = tl[i]
- if find(tli,pattern) then
- return tli
+ local specification = taglist[attribute]
+ if specification then
+ local taglist = specification.taglist
+ local pattern = patterns[tag]
+ for i=#taglist,1,-1 do
+ local t = taglist[i]
+ if find(t,pattern) then
+ return t
end
end
end
@@ -198,12 +228,20 @@ function tags.detailedtag(tag,detail,attribute)
return false -- handy as bogus index
end
-tags.properties = properties
-
-local lasttags = { }
-local userdata = { }
-
-tags.userdata = userdata
+function structures.atlocation(str)
+ local specification = taglist[texattribute[a_tagged]]
+ if specification then
+ if list then
+ local taglist = specification.taglist
+ local pattern = patterns[str]
+ for i=#list,1,-1 do
+ if find(list[i],pattern) then
+ return true
+ end
+ end
+ end
+ end
+end
function tags.setproperty(tag,key,value)
local p = properties[tag]
@@ -214,15 +252,18 @@ function tags.setproperty(tag,key,value)
end
end
-function tags.registerdata(data)
- local fulltag = chain[nstack]
- if fulltag then
- tagdata[fulltag] = data
+function tags.setaspect(key,value)
+ local tag = chain[stacksize]
+ if tag then
+ local p = properties[tag]
+ if p then
+ p[key] = value
+ else
+ properties[tag] = { [key] = value }
+ end
end
end
-local metadata
-
function tags.registermetadata(data)
local d = settings_to_hash(data)
if metadata then
@@ -232,75 +273,92 @@ function tags.registermetadata(data)
end
end
-local nstack = 0
-
function tags.start(tag,specification)
- local label, detail, user
- if specification then
- label, detail, user = specification.label, specification.detail, specification.userdata
- end
if not enabled then
codeinjections.enabletags()
enabled = true
end
--
---~ labels[tag] = label ~= "" and label or tag
---~ local fulltag
---~ if detail and detail ~= "" then
---~ fulltag = tag .. ":" .. detail
---~ else
---~ fulltag = tag
---~ end
+ labels[tag] = tag -- can go away
--
- local fulltag = label ~= "" and label or tag
- labels[tag] = fulltag
- if detail and detail ~= "" then
- fulltag = fulltag .. ":" .. detail
- end
+ local attribute = #taglist + 1
+ local tagindex = (ids[tag] or 0) + 1
--
- local t = #taglist + 1
- local n = (ids[fulltag] or 0) + 1
- ids[fulltag] = n
- lasttags[tag] = n
- local completetag = fulltag .. "-" .. n
- nstack = nstack + 1
- chain[nstack] = completetag
- stack[nstack] = t
- -- a copy as we can add key values for alt and actualtext if needed:
- taglist[t] = { unpack(chain,1,nstack) }
+ local completetag = tag .. ">" .. tagindex
--
- if user and user ~= "" then
- -- maybe we should merge this into taglist or whatever ... anyway there is room to optimize
- -- taglist.userdata = settings_to_hash(user)
- userdata[completetag] = settings_to_hash(user)
- end
- if metadata then
- tagmetadata[completetag] = metadata
+ ids[tag] = tagindex
+ lasttags[tag] = tagindex
+ stacksize = stacksize + 1
+ --
+ chain[stacksize] = completetag
+ stack[stacksize] = attribute
+ tagcontext[tag] = completetag
+ --
+ local tagnesting = { unpack(chain,1,stacksize) } -- a copy so we can add actualtext
+ --
+ if specification then
+ specification.attribute = attribute
+ specification.tagindex = tagindex
+ specification.taglist = tagnesting
+ specification.tagname = tag
+ if metadata then
+ specification.metadata = metadata
+ metadata = nil
+ end
+ local userdata = specification.userdata
+ if user ~= "" and type(userdata) == "string" then
+ specification.userdata = settings_to_hash(userdata)
+ end
+ local detail = specification.detail
+ if detail == "" then
+ specification.detail = nil
+ end
+ local parents = specification.parents
+ if parents == "" then
+ specification.parents = nil
+ end
+ else
+ specification = {
+ attribute = attribute,
+ tagindex = tagindex,
+ taglist = tagnesting,
+ tagname = tag,
+ metadata = metadata,
+ }
metadata = nil
end
- texattribute[a_tagged] = t
- return t
+ --
+ taglist[attribute] = specification
+ specifications[completetag] = specification
+ --
+ texattribute[a_tagged] = attribute
+ return attribute
end
-function tags.restart(completetag)
- local t = #taglist + 1
- nstack = nstack + 1
- chain[nstack] = completetag
- stack[nstack] = t
- taglist[t] = { unpack(chain,1,nstack) }
- texattribute[a_tagged] = t
- return t
+function tags.restart(attribute)
+ stacksize = stacksize + 1
+ if type(attribute) == "number" then
+ local taglist = taglist[attribute].taglist
+ chain[stacksize] = taglist[#taglist]
+ else
+ chain[stacksize] = attribute -- a string
+ attribute = #taglist + 1
+ taglist[attribute] = { taglist = { unpack(chain,1,stacksize) } }
+ end
+ stack[stacksize] = attribute
+ texattribute[a_tagged] = attribute
+ return attribute
end
function tags.stop()
- if nstack > 0 then
- nstack = nstack -1
+ if stacksize > 0 then
+ stacksize = stacksize - 1
end
- local t = stack[nstack]
+ local t = stack[stacksize]
if not t then
- if trace_tags then
- report_tags("ignoring end tag, previous chain: %s",nstack > 0 and concat(chain[nstack],"",1,nstack) or "none")
- end
+ -- if trace_tags then
+ report_tags("ignoring end tag, previous chain: %s",stacksize > 0 and concat(chain," ",1,stacksize) or "none")
+ -- end
t = unsetvalue
end
texattribute[a_tagged] = t
@@ -308,24 +366,56 @@ function tags.stop()
end
function tags.getid(tag,detail)
- if detail and detail ~= "" then
- return ids[tag .. ":" .. detail] or "?"
- else
- return ids[tag] or "?"
- end
+ return ids[tag] or "?"
end
function tags.last(tag)
return lasttags[tag] -- or false
end
-function tags.lastinchain()
- return chain[nstack]
+function tags.lastinchain(tag)
+ if tag and tag ~= "" then
+ return tagcontext[tag]
+ else
+ return chain[stacksize]
+ end
end
-function structures.atlocation(str)
- local location = gsub(concat(taglist[texattribute[a_tagged]],"-"),"%-%d+","")
- return find(location,topattern(str)) ~= nil
+local strip = C((1-S(">"))^1)
+
+function tags.elementtag()
+ local fulltag = chain[stacksize]
+ if fulltag then
+ return lpegmatch(strip,fulltag)
+ end
+end
+
+function tags.strip(fulltag)
+ return lpegmatch(strip,fulltag)
+end
+
+function tags.setuserproperties(tag,list)
+ if not list or list == "" then
+ tag, list = chain[stacksize], tag
+ else
+ tag = tagcontext[tag]
+ end
+ if tag then -- an attribute now
+ local l = settings_to_hash(list)
+ local s = specifications[tag]
+ if s then
+ local u = s.userdata
+ if u then
+ for k, v in next, l do
+ u[k] = v
+ end
+ else
+ s.userdata = l
+ end
+ else
+ -- error
+ end
+ end
end
function tags.handler(head) -- we need a dummy
@@ -334,8 +424,8 @@ end
statistics.register("structure elements", function()
if enabled then
- if nstack > 0 then
- return format("%s element chains identified, open chain: %s ",#taglist,concat(chain," => ",1,nstack))
+ if stacksize > 0 then
+ return format("%s element chains identified, open chain: %s ",#taglist,concat(chain," => ",1,stacksize))
else
return format("%s element chains identified",#taglist)
end
@@ -349,6 +439,65 @@ directives.register("backend.addtags", function(v)
end
end)
-commands.starttag = tags.start
-commands.stoptag = tags.stop
-commands.settagproperty = tags.setproperty
+-- interface
+
+local starttag = tags.start
+
+implement {
+ name = "starttag",
+ actions = starttag,
+ arguments = { "string" }
+}
+
+implement {
+ name = "stoptag",
+ actions = tags.stop,
+}
+
+implement {
+ name = "starttag_u",
+ scope = "private",
+ actions = function(tag,userdata) starttag(tag,{ userdata = userdata }) end,
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "starttag_d",
+ scope = "private",
+ actions = function(tag,detail) starttag(tag,{ detail = detail }) end,
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "starttag_c",
+ scope = "private",
+ actions = function(tag,detail,parents) starttag(tag,{ detail = detail, parents = parents }) end,
+ arguments = { "string", "string", "string" }
+}
+
+implement { name = "settagaspect", actions = tags.setaspect, arguments = { "string", "string" } }
+
+implement { name = "settagproperty", actions = tags.setproperty, arguments = { "string", "string", "string" } }
+implement { name = "settagproperty_b", actions = tags.setproperty, arguments = { "string", "'backend'", "string" }, scope = "private" }
+implement { name = "settagproperty_n", actions = tags.setproperty, arguments = { "string", "'nature'", "string" }, scope = "private" }
+
+implement { name = "getelementtag", actions = { tags.elementtag, context } }
+
+implement {
+ name = "setelementuserproperties",
+ scope = "private",
+ actions = tags.setuserproperties,
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "doifelseinelement",
+ actions = { structures.atlocation, commands.testcase },
+ arguments = "string",
+}
+
+implement {
+ name = "settaggedmetadata",
+ actions = structures.tags.registermetadata,
+ arguments = "string"
+}
diff --git a/Master/texmf-dist/tex/context/base/strc-tag.mkiv b/Master/texmf-dist/tex/context/base/strc-tag.mkiv
index 6e792fd3f97..f2b59c29c2d 100644
--- a/Master/texmf-dist/tex/context/base/strc-tag.mkiv
+++ b/Master/texmf-dist/tex/context/base/strc-tag.mkiv
@@ -11,6 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+% labels: no language needed
% key/values and other names might change (and probably will)
\writestatus{loading}{ConTeXt Structure Macros / Tags}
@@ -22,123 +23,139 @@
%D Eventually these labels will either move to the modules
%D where they're used, or they will en dup in mult-tag.
-\def\t!document {document} % Div
-
-\def\t!division {division} % Div
-\def\t!paragraph {paragraph} % P
-\def\t!p {p} % P
-\def\t!construct {construct} % Span
-\def\t!highlight {highlight} % Span
-
-\def\t!section {section} % Sect
-\def\t!sectiontitle {sectiontitle} % H
-\def\t!sectionnumber {sectionnumber} % H
-\def\t!sectioncontent {sectioncontent} % Div
-
-\def\t!itemgroup {itemgroup} % L
-\def\t!item {item} % Li
-\def\t!itemtag {itemtag} % Lbl
-\def\t!itemcontent {itemcontent} % LBody
-
-\def\t!description {description} % Li
-\def\t!descriptiontag {descriptiontag} % Lbl
-\def\t!descriptioncontent {descriptioncontent} % LBody
-\def\t!descriptionsymbol {descriptionsymbol} % Span
-
-\let\t!construction \t!description
-\let\t!constructiontag \t!descriptiontag
-\let\t!constructioncontent\t!descriptioncontent
-\let\t!constructionsymbol \t!descriptionsymbol
-
-\def\t!verbatimblock {verbatimblock} % Code
-\def\t!verbatimlines {verbatimlines} % Code
-\def\t!verbatimline {verbatimline} % Code
-\def\t!verbatim {verbatim} % Code
-
-\def\t!lines {lines} % Code
-\def\t!line {line} % Code
-
-\def\t!sorting {sorting} % Span
-\def\t!synonym {synonym} % Span
-
-\def\t!register {register} % Div
-\def\t!registersection {registersection} % Div
-\def\t!registertag {registertag} % Span
-\def\t!registerentries {registerentries} % Div
-\def\t!registerentry {registerentry} % Span
-\def\t!registersee {registersee} % Span
-\def\t!registerpages {registerpages} % Span
-\def\t!registerpage {registerpage} % Span
-\def\t!registerpagerange {registerpagerange} % Span
-
-\def\t!table {table} % Table
-\def\t!tablerow {tablerow} % TR
-\def\t!tablecell {tablecell} % TD
-\def\t!tabulate {tabulate} % Table
-\def\t!tabulaterow {tabulaterow} % TR
-\def\t!tabulatecell {tabulatecell} % TD
-
-\def\t!math {math} % math
-\def\t!mathtable {mtable} % Table
-\def\t!mathtablerow {mtr} % TR
-\def\t!mathtablecell {mtd} % TD
-\def\t!mathaction {maction} %
-
-\def\t!list {list} % TOC
-\def\t!listitem {listitem} % TOCI
-\def\t!listtag {listtag} % Lbl
-\def\t!listcontent {listcontent} % P
-\def\t!listdata {listdata} % P
-\def\t!listpage {listpage} % Reference
-
-\def\t!delimitedblock {delimited} % BlockQuote
-\def\t!delimited {delimited} % Quote
-\def\t!subsentence {subsentence} % Span
-
-\def\t!float {float} % Div
-\def\t!floatcaption {floatcaption} % Caption
-\def\t!floatlabel {floatlabel} % Span
-\def\t!floattext {floattext} % Span
-\def\t!floatnumber {floatnumber} % Span
-\def\t!floatcontent {floatcontent} % P
-
-\def\t!image {image} % P
-
-\def\t!mpgraphic {mpgraphic} % P
-
-\def\t!formulaset {formulaset} % Div
-\def\t!formula {formula} % Div
-\def\t!formulacaption {formulacaption} % Span
-\def\t!formulalabel {formulalabel} % Span
-\def\t!formulanumber {formulanumber} % P
-\def\t!formulacontent {formulacontent} % P
-\def\t!subformula {subformula} % Div
-
-\def\t!link {link} % Link
-
-\def\t!margintext {margintext} % Span
-\def\t!margintextblock {margintextblock} % Div
+\def\t!document {document} % Div
+
+\def\t!division {division} % Div
+\def\t!paragraph {paragraph} % P
+\def\t!p {p} % P
+\def\t!construct {construct} % Span
+\def\t!highlight {highlight} % Span
+
+\def\t!section {section} % Sect
+\def\t!sectiontitle {sectiontitle} % H
+\def\t!sectionnumber {sectionnumber} % H
+\def\t!sectioncontent {sectioncontent} % Div
+
+\def\t!itemgroup {itemgroup} % L
+\def\t!item {item} % Li
+\def\t!itemtag {itemtag} % Lbl
+\def\t!itemcontent {itemcontent} % LBody
+\def\t!itemhead {itemhead} % Div
+\def\t!itembody {itembody} % Div
+
+\def\t!description {description} % Li
+\def\t!descriptiontag {descriptiontag} % Lbl
+\def\t!descriptioncontent {descriptioncontent} % LBody
+\def\t!descriptionsymbol {descriptionsymbol} % Span
+
+\let\t!construction \t!description
+\let\t!constructiontag \t!descriptiontag
+\let\t!constructioncontent \t!descriptioncontent
+\let\t!constructionsymbol \t!descriptionsymbol
+
+\def\t!verbatimblock {verbatimblock} % Code
+\def\t!verbatimlines {verbatimlines} % Code
+\def\t!verbatimline {verbatimline} % Code
+\def\t!verbatim {verbatim} % Code
+
+\def\t!lines {lines} % Code
+\def\t!line {line} % Code
+
+\def\t!sorting {sorting} % Span
+\def\t!synonym {synonym} % Span
+
+\def\t!register {register} % Div
+\def\t!registerlocation {registerlocation} % Span
+\def\t!registersection {registersection} % Div
+\def\t!registertag {registertag} % Span
+\def\t!registerentries {registerentries} % Div
+\def\t!registerentry {registerentry} % Span
+\def\t!registercontent {registercontent} % Span
+\def\t!registersee {registersee} % Span
+\def\t!registerpages {registerpages} % Span
+\def\t!registerpage {registerpage} % Span
+\def\t!registerpagerange {registerpagerange} % Span
+\def\t!registerfrompage {registerfrompage} % Span
+\def\t!registertopage {registertopage} % Span
+\def\t!registerseparator {registerseparator} % Span
+
+\def\t!table {table} % Table
+\def\t!tablerow {tablerow} % TR
+\def\t!tablecell {tablecell} % TD
+\def\t!tabulate {tabulate} % Table
+\def\t!tabulaterow {tabulaterow} % TR
+\def\t!tabulatecell {tabulatecell} % TD
+
+\def\t!math {math} % math
+\def\t!mathtable {mtable} % Table
+\def\t!mathtablerow {mtr} % TR
+\def\t!mathtablecell {mtd} % TD
+\def\t!mathaction {maction} %
+\def\t!mathstacker {mstacker}
+\def\t!mathstackertop {mstackertop}
+\def\t!mathstackermid {mstackermid}
+\def\t!mathstackerbot {mstackerbot}
+
+\def\t!munderover {munderover} % special cases
+\def\t!munder {munder} % special cases
+\def\t!mover {mover} % special cases
+
+\def\t!list {list} % TOC
+\def\t!listitem {listitem} % TOCI
+\def\t!listtag {listtag} % Lbl
+\def\t!listcontent {listcontent} % P
+\def\t!listdata {listdata} % P
+\def\t!listpage {listpage} % Reference
+
+\def\t!delimitedblock {delimited} % BlockQuote
+\def\t!delimited {delimited} % Quote
+\def\t!subsentence {subsentence} % Span
+
+\def\t!float {float} % Div
+\def\t!floatcaption {floatcaption} % Caption
+\def\t!floatlabel {floatlabel} % Span
+\def\t!floattext {floattext} % Span
+\def\t!floatnumber {floatnumber} % Span
+\def\t!floatcontent {floatcontent} % P
+
+\def\t!image {image} % P
+
+\def\t!mpgraphic {mpgraphic} % P
+
+\def\t!formulaset {formulaset} % Div
+\def\t!formula {formula} % Div
+\def\t!formulacaption {formulacaption} % Span
+\def\t!formulalabel {formulalabel} % Span
+\def\t!formulanumber {formulanumber} % P
+\def\t!formulacontent {formulacontent} % P
+\def\t!subformula {subformula} % Div
+
+\def\t!link {link} % Link
+
+\def\t!margintext {margintext} % Span
+\def\t!margintextblock {margintextblock} % Div
% we might opt for verbose variants so this is experimental:
-\def\t!label {label} % Span
-\def\t!number {number} % Span
+\def\t!label {label} % Span
+\def\t!number {number} % Span
-\def\t!ignore {ignore} % Span
+\def\t!ignore {ignore} % Span
+\def\t!private {private} % Span
-\def\t!mid {mid} % Span
-\def\t!sub {sub} % Span
-\def\t!sup {sup} % Span
-\def\t!subsup {subsup} % Span
+\def\t!mid {mid} % Span
+\def\t!sub {sub} % Span
+\def\t!sup {sup} % Span
+\def\t!subsup {subsup} % Span
-\def\t!unit {unit} % Span
-\def\t!quantity {quantity} % Span
-\def\t!number {number} % Span
+\def\t!unit {unit} % Span
+\def\t!quantity {quantity} % Span
+\def\t!number {number} % Span
-\def\t!combination {combination} % Span
-\def\t!combinationpair {combinationpair} % Span
-\def\t!combinationcontent {combinationcontent} % Span
-\def\t!combinationcaption {combinationcaption} % Span
+\def\t!combination {combination} % Span
+\def\t!combinationpair {combinationpair} % Span
+\def\t!combinationcontent {combinationcontent} % Span
+\def\t!combinationcaption {combinationcaption} % Span
% \setuptaglabeltext
% [en]
@@ -152,8 +169,11 @@
\unexpanded\def\setelementbackendtag{\dodoubleargument\strc_tags_set_backend}
\unexpanded\def\setelementnature {\dodoubleargument\strc_tags_set_nature}
-\def\strc_tags_set_backend[#1][#2]{\ctxcommand{settagproperty("#1","backend","#2")}}
-\def\strc_tags_set_nature [#1][#2]{\ctxcommand{settagproperty("#1","nature", "#2")}}
+\def\strc_tags_set_backend[#1][#2]{\clf_settagproperty_b{#1}{#2}} % todo: ignore when no export
+\def\strc_tags_set_nature [#1][#2]{\clf_settagproperty_n{#1}{#2}} % todo: ignore when no export
+
+\unexpanded\def\strc_tags_set_aspect_nop#1#2{}
+\unexpanded\def\strc_tags_set_aspect_yes#1#2{\clf_settagaspect{#1}{#2}} % todo: ignore when no export / also \let
\installcorenamespace{tagging}
@@ -176,11 +196,14 @@
\expandafter\strc_tags_element_stop_yes
\fi}
+% it makes no sense to have labels ... maybe some day as a last 'replace' in the export
+% which might be more efficient then ... okay, we now cannot overload but who cares
+
\unexpanded\def\strc_tags_element_start_yes_indeed_yes[#1][#2]%
- {\ctxcommand{starttag("#1",{label="\dogetupsometaglabeltext{#1}",userdata=\!!bs#2\!!es})}}
+ {\clf_starttag_u{#1}{#2}}
\unexpanded\def\strc_tags_element_stop_yes
- {\ctxcommand{stoptag()}}
+ {\clf_stoptag}
\unexpanded\def\strc_tags_element_start_nop_indeed[#1][#2]%
{}
@@ -191,19 +214,35 @@
\unexpanded\def\strc_tags_enable_elements
{\setuplanguage[\s!default][\s!righthyphenchar="AD]% for the moment here
\let\startelement\strc_tags_element_start_yes
- \let\stopelement \strc_tags_element_stop_yes}
+ \let\stopelement \strc_tags_element_stop_yes
+ \let\dosettagproperty\strc_tags_set_aspect_yes}
\unexpanded\def\strc_tags_disable_elements
{\let\startelement\strc_tags_element_start_nop
- \let\stopelement \strc_tags_element_stop_nop}
+ \let\stopelement \strc_tags_element_stop_nop
+ \let\dosettagproperty\strc_tags_set_aspect_nop}
% beware: making these unexpanded spoils tables (noalign problem)
-\def\strc_tags_enabled_start
+\def\strc_tags_enabled_start_no_detail
+ {\iftrialtypesetting
+ \expandafter\strc_tags_start_nop_no_detail
+ \else
+ \expandafter\strc_tags_start_yes_no_detail
+ \fi}
+
+\def\strc_tags_enabled_start_detail
+ {\iftrialtypesetting
+ \expandafter\strc_tags_start_nop_detail
+ \else
+ \expandafter\strc_tags_start_yes_detail
+ \fi}
+
+\def\strc_tags_enabled_start_chained
{\iftrialtypesetting
- \expandafter\strc_tags_start_nop
+ \expandafter\strc_tags_start_nop_chained
\else
- \expandafter\strc_tags_start_yes
+ \expandafter\strc_tags_start_yes_chained
\fi}
\def\strc_tags_enabled_stop
@@ -213,25 +252,66 @@
\expandafter\strc_tags_stop_yes
\fi}
-\def\strc_tags_start_yes#1#2% we could have a fast labeltext resolver
- {\ctxcommand{starttag("#1",{label="\dogetupsometaglabeltext{#1}",detail="#2"})}}
+\def\strc_tags_start_yes_no_detail #1{\clf_starttag{#1}}
+\def\strc_tags_start_yes_detail #1#2{\clf_starttag_d{#1}{#2}}
+\def\strc_tags_start_yes_chained #1#2#3{\clf_starttag_c{#1}{#2}{\getcurrentparentchain#3{#2}}}
+\def\strc_tags_stop_yes {\clf_stoptag}
-\def\strc_tags_stop_yes
- {\ctxcommand{stoptag()}}
+\let\strc_tags_start_nop_no_detail\gobbleoneargument
+\let\strc_tags_start_nop_detail \gobbletwoarguments
+\let\strc_tags_start_nop_chained \gobblethreearguments
+\let\strc_tags_stop_nop \donothing
-\def\strc_tags_start_nop#1#2%
- {}
+% more efficient:
-\def\strc_tags_stop_nop
- {}
+% \dostarttagged % {tag} {detail}
+% \dostarttaggedchained % {tag} {detail} \??hash
+% \dostarttaggednodetail % {tag}
+
+% \unexpanded\def\strc_tags_enable
+% {\let\dostarttagged\strc_tags_start_yes
+% \let\dostoptagged \strc_tags_stop_yes}
\unexpanded\def\strc_tags_enable
- {\let\dostarttagged\strc_tags_start_yes
- \let\dostoptagged \strc_tags_stop_yes}
+ {\let\dostarttagged \strc_tags_enabled_start_detail
+ \let\dostarttaggednodetail\strc_tags_enabled_start_no_detail
+ \let\dostarttaggedchained \strc_tags_enabled_start_chained
+ \let\dostoptagged \strc_tags_enabled_stop}
\unexpanded\def\strc_tags_disable
- {\let\dostarttagged\strc_tags_start_nop
- \let\dostoptagged \strc_tags_stop_nop}
+ {\let\dostarttagged \strc_tags_start_nop_detail
+ \let\dostarttaggednodetail\strc_tags_start_nop_no_detail
+ \let\dostarttaggedchained \strc_tags_start_nop_chained
+ \let\dostoptagged \strc_tags_stop_nop}
+
+% for luigi (beware: fully expandable):
+
+\def\strc_tags_get_element_tag_yes{\clf_getelementtag}
+\let\strc_tags_get_element_tag_nop\donothing
+
+\unexpanded\def\strc_tags_setup_element_user_properties_yes
+ {\dodoubleempty\strc_tags_setup_element_user_properties_indeed}
+
+\unexpanded\def\strc_tags_setup_element_user_properties_nop
+ {\dodoubleempty\strc_tags_setup_element_user_properties_indeed_nop}
+
+\def\strc_tags_setup_element_user_properties_indeed
+ {\iftrialtypesetting
+ \expandafter\strc_tags_setup_element_user_properties_indeed_nop
+ \else
+ \expandafter\strc_tags_setup_element_user_properties_indeed_yes
+ \fi}
+
+\def\strc_tags_setup_element_user_properties_indeed_nop[#1][#2]{}
+\def\strc_tags_setup_element_user_properties_indeed_yes[#1][#2]{\clf_setelementuserproperties{#1}{#2}}
+
+\unexpanded\def\strc_tags_enable_properties
+ {\let\getelementtag \strc_tags_get_element_tag_yes
+ \let\setupelementuserproperties\strc_tags_setup_element_user_properties_yes}
+
+\unexpanded\def\strc_tags_disable_properties
+ {\let\getelementtag \strc_tags_get_element_tag_nop
+ \let\setupelementuserproperties\strc_tags_setup_element_user_properties_nop}
%D The triggers:
@@ -240,11 +320,13 @@
\appendtoks
\strc_tags_enable_elements
+ \strc_tags_enable_properties
\doifelse{\taggingparameter\c!method}\v!auto\strc_tags_enable\strc_tags_disable
\to \everyenableelements
\appendtoks
\strc_tags_disable_elements
+ \strc_tags_disable_properties
\strc_tags_disable
\to \everydisableelements
@@ -277,41 +359,41 @@
\installcorenamespace {paragraph}
\installcommandhandler \??paragraph {paragraph} \??paragraph
-\setupparagraph % someday maybe also strut (beg/end)
+\setupparagraph % someday maybe also strut (beg/end) and align
[\c!color=,
\c!style=]
\unexpanded\def\startparagraph
- {\dodoubleempty\paragraph_start}
+ {\dodoubleempty\paragraph_start}
\def\paragraph_start
- {\iffirstargument
- \ifsecondargument
- \doubleexpandafter\paragraph_start_two
- \else
- \doubleexpandafter\paragraph_start_one
- \fi
- \else
- \expandafter\paragraph_start_zero
- \fi}
+ {\endgraf % we end before the group
+ \begingroup
+ \iffirstargument
+ \ifsecondargument
+ \doubleexpandafter\paragraph_start_two
+ \else
+ \doubleexpandafter\paragraph_start_one
+ \fi
+ \else
+ \expandafter\paragraph_start_zero
+ \fi}
\def\paragraph_start_two[#1][#2]%
- {\endgraf % we end before the group
- \begingroup
- \let\stopparagraph\paragraph_stop_indeed
- \edef\currentparagraph{#1}%
- \setupcurrentparagraph[#2]%
- \paragraph_start_indeed}
+ {\edef\currentparagraph{#1}%
+ \setupcurrentparagraph[#2]%
+ \paragraph_start_indeed}
\def\paragraph_start_one[#1][#2]%
- {\endgraf % we end before the group
- \begingroup
- \let\stopparagraph\paragraph_stop_indeed
- \doifassignmentelse{#1}
- {\let\currentparagraph\empty
- \setupcurrentparagraph[#1]}
- {\edef\currentparagraph{#1}}%
- \paragraph_start_indeed}
+ {\doifelseassignment{#1}
+ {\let\currentparagraph\empty
+ \setupcurrentparagraph[#1]}
+ {\edef\currentparagraph{#1}}%
+ \paragraph_start_indeed}
+
+\def\paragraph_start_zero[#1][#2]%
+ {\let\currentparagraph\empty
+ \paragraph_start_indeed}
\def\paragraph_start_indeed
{\useparagraphstyleandcolor\c!style\c!color
@@ -319,27 +401,32 @@
\usesetupsparameter\paragraphparameter
\dostarttagged\t!paragraph\currentparagraph}
-\def\paragraph_start_zero[#1][#2]%
- {\let\currentparagraph\empty
- \paragraph_start_indeed}
-
-\unexpanded\def\paragraph_stop_indeed
- {\dostoptagged
- \endgraf % we end inside the group
- \endgroup}
-
\unexpanded\def\stopparagraph
- {\dostoptagged}
+ {\dostoptagged
+ \endgraf % we end inside the group
+ \endgroup}
\let\startpar\startparagraph
\let\stoppar \stopparagraph
+\def\strc_tags_document_start_indeed
+ {\glet\strc_tags_document_start_indeed\relax
+ \dostarttagged\t!document\empty}
+
+\def\strc_tags_document_stop_indeed
+ {\glet\strc_tags_document_stop_indeed\relax
+ \dostoptagged}
+
\appendtoks
- \dostarttagged\t!document\empty
-\to \everystarttext
+ \strc_tags_document_start_indeed % here because otherwise products don't get a root (starttext before env)
+\to \everyenableelements
+
+% \appendtoks
+% \strc_tags_document_start_indeed
+% \to \everystarttext
\appendtoks
- \dostoptagged
+ \strc_tags_document_stop_indeed
\to \everystoptext
\appendtoks
@@ -347,12 +434,14 @@
\strc_tags_disable
\to \everybeforepagebody
-% \doifinelementelse{structure:section} {yes} {no}
-% \doifinelementelse{structure:chapter} {yes} {no}
-% \doifinelementelse{division:*-structure:chapter} {yes} {no}
+% \doifelseinelement{structure:section} {yes} {no}
+% \doifelseinelement{structure:chapter} {yes} {no}
+% \doifelseinelement{division:*-structure:chapter} {yes} {no}
+
+\unexpanded\def\doifelseinelement#1%
+ {\clf_doifelseinelement{#1}}
-\unexpanded\def\doifinelementelse#1%
- {\ctxcommand{testcase(structures.atlocation("#1"))}}
+\let\doifinelementelse\doifelseinelement
\unexpanded\def\taggedlabeltexts#1#2#3% experimental: label, numberdetail, numbercontent
{\begingroup
@@ -398,7 +487,7 @@
%D \stoptyping
\unexpanded\def\settaggedmetadata[#1]%
- {\ctxlua{structures.tags.registermetadata(\!!bs#1\!!es)}}
+ {\clf_settaggedmetadata{#1}}
%D An overload:
diff --git a/Master/texmf-dist/tex/context/base/supp-box.lua b/Master/texmf-dist/tex/context/base/supp-box.lua
index 3c5a3383d01..7cc71a891dd 100644
--- a/Master/texmf-dist/tex/context/base/supp-box.lua
+++ b/Master/texmf-dist/tex/context/base/supp-box.lua
@@ -8,13 +8,16 @@ if not modules then modules = { } end modules ['supp-box'] = {
-- this is preliminary code, use insert_before etc
+local lpegmatch = lpeg.match
+
local report_hyphenation = logs.reporter("languages","hyphenation")
local tex = tex
local context = context
-local commands = commands
local nodes = nodes
+local implement = interfaces.implement
+
local splitstring = string.split
local nodecodes = nodes.nodecodes
@@ -42,9 +45,12 @@ local setfield = nuts.setfield
local setbox = nuts.setbox
local free_node = nuts.free
-local copy_list = nuts.copy_list
+local flush_list = nuts.flush_list
local copy_node = nuts.copy
+local copy_list = nuts.copy_list
local find_tail = nuts.tail
+local traverse_id = nuts.traverse_id
+local link_nodes = nuts.linked
local listtoutf = nodes.listtoutf
@@ -52,29 +58,64 @@ local nodepool = nuts.pool
local new_penalty = nodepool.penalty
local new_hlist = nodepool.hlist
local new_glue = nodepool.glue
+local new_rule = nodepool.rule
+local new_kern = nodepool.kern
+
+local setlistcolor = nodes.tracers.colors.setlist
local texget = tex.get
+local texgetbox = tex.getbox
-local function hyphenatedlist(head)
+local function hyphenatedlist(head,usecolor)
local current = head and tonut(head)
while current do
local id = getid(current)
local next = getnext(current)
local prev = getprev(current)
if id == disc_code then
- local hyphen = getfield(current,"pre")
- if hyphen then
- local penalty = new_penalty(-500)
- -- insert_after etc
- setfield(hyphen,"next",penalty)
- setfield(penalty,"prev",hyphen)
- setfield(prev,"next",hyphen)
- setfield(next,"prev", penalty)
- setfield(penalty,"next",next)
- setfield(hyphen,"prev",prev)
+ local pre = getfield(current,"pre")
+ local post = getfield(current,"post")
+ local replace = getfield(current,"replace")
+ if pre then
setfield(current,"pre",nil)
- free_node(current)
end
+ if post then
+ setfield(current,"post",nil)
+ end
+ if not usecolor then
+ -- nothing fancy done
+ elseif pre and post then
+ setlistcolor(pre,"darkmagenta")
+ setlistcolor(post,"darkcyan")
+ elseif pre then
+ setlistcolor(pre,"darkyellow")
+ elseif post then
+ setlistcolor(post,"darkyellow")
+ end
+ if replace then
+ flush_list(replace)
+ setfield(current,"replace",nil)
+ end
+ -- setfield(current,"replace",new_rule(65536)) -- new_kern(65536*2))
+ setfield(current,"next",nil)
+ setfield(current,"prev",nil)
+ local list = link_nodes (
+ pre and new_penalty(10000),
+ pre,
+ current,
+ post,
+ post and new_penalty(10000)
+ )
+ local tail = find_tail(list)
+ if prev then
+ setfield(prev,"next",list)
+ setfield(list,"prev",prev)
+ end
+ if next then
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
+ end
+ -- free_node(current)
elseif id == vlist_code or id == hlist_code then
hyphenatedlist(getlist(current))
end
@@ -82,11 +123,29 @@ local function hyphenatedlist(head)
end
end
-commands.hyphenatedlist = hyphenatedlist
+implement {
+ name = "hyphenatedlist",
+ arguments = { "integer", "boolean" },
+ actions = function(n,color)
+ local b = texgetbox(n)
+ if b then
+ hyphenatedlist(b.list,color)
+ end
+ end
+}
-function commands.showhyphenatedinlist(list)
- report_hyphenation("show: %s",listtoutf(tonut(list),false,true))
-end
+-- local function hyphenatedhack(head,pre)
+-- pre = tonut(pre)
+-- for n in traverse_id(disc_code,tonut(head)) do
+-- local hyphen = getfield(n,"pre")
+-- if hyphen then
+-- flush_list(hyphen)
+-- end
+-- setfield(n,"pre",copy_list(pre))
+-- end
+-- end
+--
+-- commands.hyphenatedhack = hyphenatedhack
local function checkedlist(list)
if type(list) == "number" then
@@ -96,12 +155,20 @@ local function checkedlist(list)
end
end
+implement {
+ name = "showhyphenatedinlist",
+ arguments = "integer",
+ actions = function(box)
+ report_hyphenation("show: %s",listtoutf(checkedlist(n),false,true))
+ end
+}
+
local function applytochars(current,doaction,noaction,nested)
while current do
local id = getid(current)
if nested and (id == hlist_code or id == vlist_code) then
context.beginhbox()
- applytochars(getlist(current),what,nested)
+ applytochars(getlist(current),doaction,noaction,nested)
context.endhbox()
elseif id ~= glyph_code then
noaction(tonode(copy_node(current)))
@@ -124,7 +191,7 @@ local function applytowords(current,doaction,noaction,nested)
noaction(tonode(copy_node(current)))
elseif nested and (id == hlist_code or id == vlist_code) then
context.beginhbox()
- applytowords(getlist(current),what,nested)
+ applytowords(getlist(current),doaction,noaction,nested)
context.egroup()
elseif not start then
start = current
@@ -136,17 +203,43 @@ local function applytowords(current,doaction,noaction,nested)
end
end
-commands.applytochars = function(list,what,nested) applytochars(checkedlist(list),context[what or "ruledhbox"],context,nested) end
-commands.applytowords = function(list,what,nested) applytowords(checkedlist(list),context[what or "ruledhbox"],context,nested) end
+local methods = {
+ char = applytochars,
+ characters = applytochars,
+ word = applytowords,
+ words = applytowords,
+}
+
+implement {
+ name = "applytobox",
+ arguments = {
+ {
+ { "box", "integer" },
+ { "command" },
+ { "method" },
+ { "nested", "boolean" },
+ }
+ },
+ actions = function(specification)
+ local list = checkedlist(specification.box)
+ local action = methods[specification.method or "char"]
+ if list and action then
+ action(list,context[specification.command or "ruledhbox"],context,specification.nested)
+ end
+ end
+}
local split_char = lpeg.Ct(lpeg.C(1)^0)
local split_word = lpeg.tsplitat(lpeg.patterns.space)
local split_line = lpeg.tsplitat(lpeg.patterns.eol)
-function commands.processsplit(str,command,how,spaced)
- how = how or "word"
- if how == "char" then
- local words = lpeg.match(split_char,str)
+local function processsplit(specification)
+ local str = specification.data or ""
+ local command = specification.command or "ruledhbox"
+ local method = specification.method or "word"
+ local spaced = specification.spaced
+ if method == "char" or method == "character" then
+ local words = lpegmatch(split_char,str)
for i=1,#words do
local word = words[i]
if word == " " then
@@ -159,8 +252,8 @@ function commands.processsplit(str,command,how,spaced)
context(word)
end
end
- elseif how == "word" then
- local words = lpeg.match(split_word,str)
+ elseif method == "word" then
+ local words = lpegmatch(split_word,str)
for i=1,#words do
local word = words[i]
if spaced and i > 1 then
@@ -172,8 +265,8 @@ function commands.processsplit(str,command,how,spaced)
context(word)
end
end
- elseif how == "line" then
- local words = lpeg.match(split_line,str)
+ elseif method == "line" then
+ local words = lpegmatch(split_line,str)
for i=1,#words do
local word = words[i]
if spaced and i > 1 then
@@ -190,63 +283,88 @@ function commands.processsplit(str,command,how,spaced)
end
end
+implement {
+ name = "processsplit",
+ actions = processsplit,
+ arguments = {
+ {
+ { "data" },
+ { "command" },
+ { "method" },
+ { "spaced", "boolean" },
+ }
+ }
+}
+
local a_vboxtohboxseparator = attributes.private("vboxtohboxseparator")
-function commands.vboxlisttohbox(original,target,inbetween)
- local current = getlist(getbox(original))
- local head = nil
- local tail = nil
- while current do
- local id = getid(current)
- local next = getnext(current)
- if id == hlist_code then
- local list = getlist(current)
- if head then
- if inbetween > 0 then
- local n = new_glue(0,0,inbetween)
- setfield(tail,"next",n)
- setfield(n,"prev",tail)
- tail = n
- end
- setfield(tail,"next",list)
- setfield(list,"prev",tail)
- else
- head = list
- end
- tail = find_tail(list)
- -- remove last separator
- if getid(tail) == hlist_code and getattribute(tail,a_vboxtohboxseparator) == 1 then
- local temp = tail
- local prev = getprev(tail)
- if next then
- local list = getlist(tail)
- setfield(prev,"next",list)
- setfield(list,"prev",prev)
- setfield(tail,"list",nil)
- tail = find_tail(list)
+implement {
+ name = "vboxlisttohbox",
+ arguments = { "integer", "integer", "dimen" },
+ actions = function(original,target,inbetween)
+ local current = getlist(getbox(original))
+ local head = nil
+ local tail = nil
+ while current do
+ local id = getid(current)
+ local next = getnext(current)
+ if id == hlist_code then
+ local list = getlist(current)
+ if head then
+ if inbetween > 0 then
+ local n = new_glue(0,0,inbetween)
+ setfield(tail,"next",n)
+ setfield(n,"prev",tail)
+ tail = n
+ end
+ setfield(tail,"next",list)
+ setfield(list,"prev",tail)
else
- tail = prev
+ head = list
+ end
+ tail = find_tail(list)
+ -- remove last separator
+ if getid(tail) == hlist_code and getattribute(tail,a_vboxtohboxseparator) == 1 then
+ local temp = tail
+ local prev = getprev(tail)
+ if next then
+ local list = getlist(tail)
+ setfield(prev,"next",list)
+ setfield(list,"prev",prev)
+ setfield(tail,"list",nil)
+ tail = find_tail(list)
+ else
+ tail = prev
+ end
+ free_node(temp)
end
- free_node(temp)
+ -- done
+ setfield(tail,"next",nil)
+ setfield(current,"list",nil)
end
- -- done
- setfield(tail,"next",nil)
- setfield(current,"list",nil)
+ current = next
end
- current = next
+ local result = new_hlist()
+ setfield(result,"list",head)
+ setbox(target,result)
end
- local result = new_hlist()
- setfield(result,"list",head)
- setbox(target,result)
-end
+}
-function commands.hboxtovbox(original)
- local b = getbox(original)
- local factor = texget("baselineskip").width / texget("hsize")
- setfield(b,"depth",0)
- setfield(b,"height",getfield(b,"width") * factor)
-end
+implement {
+ name = "hboxtovbox",
+ arguments = "integer",
+ actions = function(n)
+ local b = getbox(n)
+ local factor = texget("baselineskip").width / texget("hsize")
+ setfield(b,"depth",0)
+ setfield(b,"height",getfield(b,"width") * factor)
+ end
+}
-function commands.boxtostring(n)
- context.puretext(nodes.toutf(tex.box[n].list)) -- helper is defined later
-end
+implement {
+ name = "boxtostring",
+ arguments = "integer",
+ actions = function(n)
+ context.puretext(nodes.toutf(texgetbox(n).list)) -- helper is defined later
+ end
+}
diff --git a/Master/texmf-dist/tex/context/base/supp-box.mkiv b/Master/texmf-dist/tex/context/base/supp-box.mkiv
index 66f373b72a7..54b0e2860a3 100644
--- a/Master/texmf-dist/tex/context/base/supp-box.mkiv
+++ b/Master/texmf-dist/tex/context/base/supp-box.mkiv
@@ -570,7 +570,7 @@
%D \doiftext {data} {then branch}
%D \stoptyping
-\unexpanded\def\doiftextelse#1%
+\unexpanded\def\doifelsetext#1%
{\begingroup
\setbox\scratchbox\hbox
{\settrialtypesetting
@@ -581,6 +581,8 @@
\endgroup\expandafter\firstoftwoarguments
\fi}
+\let\doiftextelse\doifelsetext
+
\unexpanded\def\doiftext#1%
{\begingroup
\setbox\scratchbox\hbox
@@ -658,8 +660,8 @@
%D A slower but more versatile implementation is:
%D
%D \starttyping
-%D \long\def\dowithnextbox#1#2%
-%D {\long\def\syst_boxes_with_next_box{#1}%
+%D \unexpanded\def\dowithnextbox#1#2%
+%D {\def\syst_boxes_with_next_box{#1}%
%D \ifx#2\hbox
%D \afterassignment\syst_boxes_with_next_box_indeed
%D \else\ifx#2\vbox
@@ -1063,10 +1065,11 @@
%D \showhyphens{dohyphenatedword}
%D \stoptyping
-\def\doshowhyphenatednextbox
- {\ctxcommand{showhyphenatedinlist(tex.box[\number\nextbox].list)}}
+\unexpanded\def\doshowhyphenatednextbox
+ {\clf_showhyphenatedinlist\nextbox}
-\unexpanded\def\showhyphens{\dowithnextboxcs\doshowhyphenatednextbox\hbox}
+\unexpanded\def\showhyphens
+ {\dowithnextboxcs\doshowhyphenatednextbox\hbox}
%D The following macros are seldom used but handy for tracing.
%D
@@ -1076,14 +1079,20 @@
%D \hyphenatedfile{tufte}
%D \stoptyping
-\def\dohyphenatednextbox
- {\ctxcommand{hyphenatedlist(tex.box[\number\nextbox].list)}%
+\unexpanded\def\dohyphenatednextbox
+ {\clf_hyphenatedlist\nextbox false\relax
\unhbox\nextbox}
\unexpanded\def\hyphenatedword {\dowithnextboxcs\dohyphenatednextbox\hbox}
\unexpanded\def\hyphenatedpar {\dowithnextboxcs\dohyphenatednextbox\hbox}
\unexpanded\def\hyphenatedfile#1{\dowithnextboxcs\dohyphenatednextbox\hbox{\readfile{#1}\donothing\donothing}}
+\unexpanded\def\dohyphenatednextboxcolor
+ {\clf_hyphenatedlist\nextbox true\relax
+ \unhbox\nextbox}
+
+\unexpanded\def\hyphenatedcoloredword{\dowithnextboxcs\dohyphenatednextboxcolor\hbox}
+
%D \macros
%D {processtokens}
%D
@@ -1363,7 +1372,12 @@
\begingroup
\setbox\scratchbox\hbox{\settrialtypesetting#2{\savecurrentattributes{pic}}}%
\setbox\scratchbox\hbox{\restorecurrentattributes{pic}#1}%
- \ctxcommand{applytochars(\number\scratchbox,"\strippedcsname#2",true)}%
+ \clf_applytobox
+ method {char}%
+ box \scratchbox
+ command {\checkedstrippedcsname#2}%
+ nested true%
+ \relax
\endgroup}
\unexpanded\def\processisolatedwords#1#2%
@@ -1371,34 +1385,88 @@
\begingroup
\setbox\scratchbox\hbox{\settrialtypesetting#2{\savecurrentattributes{pic}}}%
\setbox\scratchbox\hbox{\restorecurrentattributes{pic}#1}%
- \ctxcommand{applytowords(\number\scratchbox,"\strippedcsname#2",true)}%
+ \clf_applytobox
+ method {word}%
+ box \scratchbox
+ command {\checkedstrippedcsname#2}%
+ nested true%
+ \relax
\endgroup}
-\unexpanded\def\processwords#1%
- {\processisolatedwords{#1}\processword}
-
-\let\processword\relax
-
-\unexpanded\def\applytosplitstringchar#1#2{\dontleavehmode\ctxcommand{processsplit(\!!bs#2\!!es,"\strippedcsname#1","char")}}
-\unexpanded\def\applytosplitstringword#1#2{\dontleavehmode\ctxcommand{processsplit(\!!bs#2\!!es,"\strippedcsname#1","word")}}
-\unexpanded\def\applytosplitstringline#1#2{\dontleavehmode\ctxcommand{processsplit(\!!bs#2\!!es,"\strippedcsname#1","line")}}
-
-\unexpanded\def\applytosplitstringcharspaced#1#2{\dontleavehmode\ctxcommand{processsplit(\!!bs#2\!!es,"\strippedcsname#1","char",true)}}
-\unexpanded\def\applytosplitstringwordspaced#1#2{\dontleavehmode\ctxcommand{processsplit(\!!bs#2\!!es,"\strippedcsname#1","word",true)}}
-\unexpanded\def\applytosplitstringlinespaced#1#2{\dontleavehmode\ctxcommand{processsplit(\!!bs#2\!!es,"\strippedcsname#1","line",true)}}
-
%D A variant:
\unexpanded\def\applytocharacters#1%
{\dontleavehmode
- \dowithnextbox{\ctxcommand{applytochars(\number\nextbox,"\strippedcsname#1",true)}}%
+ \dowithnextbox{\clf_applytobox
+ method {char}%
+ box \nextbox
+ command {\checkedstrippedcsname#1}%
+ nested true%
+ \relax}%
\hbox}
\unexpanded\def\applytowords#1%
{\dontleavehmode
- \dowithnextbox{\ctxcommand{applytowords(\number\nextbox,"\strippedcsname#1",true)}}%
+ \dowithnextbox{\clf_applytobox
+ method {word}%
+ box \nextbox
+ command {\checkedstrippedcsname#1}%
+ nested true%
+ \relax}%
\hbox}
+%D The old call:
+
+\unexpanded\def\processwords#1%
+ {\processisolatedwords{#1}\processword}
+
+\let\processword\relax
+
+\unexpanded\def\applytosplitstringchar#1#2%
+ {\dontleavehmode\clf_processsplit
+ data {#2}%
+ command {\checkedstrippedcsname#1}%
+ method {char}%
+ \relax}
+
+\unexpanded\def\applytosplitstringword#1#2%
+ {\dontleavehmode\clf_processsplit
+ data {#2}%
+ command {\checkedstrippedcsname#1}%
+ method {word}%
+ \relax}
+
+\unexpanded\def\applytosplitstringline#1#2%
+ {\dontleavehmode\clf_processsplit
+ data {#2}%
+ command {\checkedstrippedcsname#1}%
+ method {line}%
+ \relax}
+
+\unexpanded\def\applytosplitstringcharspaced#1#2%
+ {\dontleavehmode\clf_processsplit
+ data {#2}%
+ command {\checkedstrippedcsname#1}%
+ method {char}%
+ spaced true%
+ \relax}
+
+\unexpanded\def\applytosplitstringwordspaced#1#2%
+ {\dontleavehmode\clf_processsplit
+ data {#2}%
+ command {\checkedstrippedcsname#1}%
+ method {word}%
+ spaced true%
+ \relax}
+
+\unexpanded\def\applytosplitstringlinespaced#1#2%
+ {\dontleavehmode\clf_processsplit
+ data {#2}%
+ command {\checkedstrippedcsname#1}%
+ method {line}%
+ spaced true%
+ \relax}
+
%D \macros
%D {sbox}
%D
@@ -1795,7 +1863,7 @@
\box\d_syst_boxes_separator
\fi
\egroup
- \ctxcommand{hboxtovbox(\number\scratchbox)}%
+ \clf_hboxtovbox\scratchbox
\box\scratchbox
\endgroup}
@@ -1849,7 +1917,7 @@
\unexpanded\def\stophboxestohbox
{\egroup
- \ctxcommand{vboxlisttohbox(\number\scratchbox,\number\nextbox,\number\dimexpr\hboxestohboxslack)}%
+ \clf_vboxlisttohbox\scratchbox\nextbox\dimexpr\hboxestohboxslack\relax
\dontleavehmode
\unhbox\nextbox
\removeunwantedspaces
@@ -2024,7 +2092,7 @@
{\bgroup
\def\syst_boxes_process_indeed{#1}% #1 can be redefined halfway
\setbox\processbox\emptybox
- \doifnextbgroupelse\syst_boxes_process_yes\syst_boxes_process_nop}
+ \doifelsenextbgroup\syst_boxes_process_yes\syst_boxes_process_nop}
\def\syst_boxes_process_yes
{\dowithnextboxcs\syst_boxes_process_content\hbox}
@@ -2032,7 +2100,7 @@
\def\syst_boxes_process_content
{\removeunwantedspaces
\syst_boxes_process_indeed % takes \nextbox makes \processbox
- \doifnextbgroupelse\syst_boxes_process_yes\syst_boxes_process_nop}
+ \doifelsenextbgroup\syst_boxes_process_yes\syst_boxes_process_nop}
\unexpanded\def\syst_boxes_process_nop
{\removeunwantedspaces
@@ -2489,13 +2557,15 @@
\copy\csname\??stackbox#1:#2\endcsname
\fi}}
-\unexpanded\def\doifboxelse#1#2#3#4%
+\unexpanded\def\doifelsebox#1#2#3#4%
{\ifcsname\??stackbox#1:#2\endcsname
\ifvoid\csname\??stackbox#1:#2\endcsname#4\else#3\fi
\else
#4%
\fi}
+\let\doifboxelse\doifelsebox
+
%D This one is cheaper (the above is no longer used that much):
\installcorenamespace {boxstack}
@@ -2525,9 +2595,6 @@
\unexpanded\def\globalpushbox{\syst_boxes_push\global}
\unexpanded\def\globalpopbox {\syst_boxes_pop \global}
-% \unexpanded\def\pushbox#1{\ctxcommand{pushbox(\number#1)}}
-% \unexpanded\def\popbox #1{\ctxcommand{popbox(\number#1)}}
-
%D \macros
%D {removedepth, obeydepth}
%D
@@ -2776,12 +2843,16 @@
% {\dowithnextbox{\edef#1{\syst_boxes_nodestostring}}\hbox}
%
% \def\syst_boxes_nodestostring
-% {\ctxcommand{boxtostring(\number\nextbox)}}
+% {\clf_boxtostring\nextbox}
\unexpanded\def\nodestostring#1#2% more tolerant for #2=\cs
{\begingroup
\setbox\nextbox\hbox{#2}%
- \normalexpanded{\endgroup\edef\noexpand#1{\ctxcommand{boxtostring(\number\nextbox)}}}}
+ \normalexpanded{\endgroup\edef\noexpand#1{\clf_boxtostring\nextbox}}}
+
+%D Even more dirty:
+
+\let\hyphenatedhbox\hbox
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/supp-ran.lua b/Master/texmf-dist/tex/context/base/supp-ran.lua
index 7997db8f648..1d34393fa64 100644
--- a/Master/texmf-dist/tex/context/base/supp-ran.lua
+++ b/Master/texmf-dist/tex/context/base/supp-ran.lua
@@ -10,12 +10,16 @@ if not modules then modules = { } end modules ['supp-ran'] = {
local report_system = logs.reporter("system","randomizer")
-local math = math
-local context, commands = context, commands
+local math = math
+local context = context
+local implement = interfaces.implement
-local random, randomseed, round, seed, last = math.random, math.randomseed, math.round, false, 1
-
-local maxcount = 2^30-1 -- 1073741823
+local random = math.random
+local randomseed = math.randomseed
+local round = math.round
+local seed = false
+local last = 1
+local maxcount = 2^30-1 -- 1073741823
local function setrandomseedi(n,comment)
if not n then
@@ -34,28 +38,23 @@ end
math.setrandomseedi = setrandomseedi
-function commands.getrandomcounta(min,max)
+local function getrandomnumber(min,max)
last = random(min,max)
- context(last)
-end
-
-function commands.getrandomcountb(min,max)
- last = random(min,max)/65536
- context(last)
+ return last
end
-function commands.setrandomseed(n)
+local function setrandomseed(n)
last = n
setrandomseedi(n)
end
-function commands.getrandomseed(n)
- context(last)
+local function getrandomseed()
+ return last
end
-- maybe stack
-function commands.freezerandomseed(n)
+local function freezerandomseed(n)
if seed == false or seed == nil then
seed = last
setrandomseedi(seed,"freeze",seed)
@@ -65,9 +64,18 @@ function commands.freezerandomseed(n)
end
end
-function commands.defrostrandomseed()
+local function defrostrandomseed()
if seed ~= false then
setrandomseedi(seed,"defrost",seed) -- was last (bug)
seed = false
end
end
+
+implement { name = "getrandomnumber", actions = { getrandomnumber, context }, arguments = { "integer", "integer" } }
+implement { name = "getrandomdimen", actions = { getrandomnumber, context }, arguments = { "dimen", "dimen" } }
+implement { name = "getrandomfloat", actions = { getrandomnumber, context }, arguments = { "number", "number" } }
+implement { name = "setrandomseed", actions = { setrandomseed }, arguments = { "integer" } }
+implement { name = "getrandomseed", actions = { getrandomseed, context } }
+implement { name = "freezerandomseed", actions = { freezerandomseed } }
+implement { name = "defrostrandomseed", actions = { defrostrandomseed } }
+
diff --git a/Master/texmf-dist/tex/context/base/supp-ran.mkiv b/Master/texmf-dist/tex/context/base/supp-ran.mkiv
index f5466a0e1fd..e491737170c 100644
--- a/Master/texmf-dist/tex/context/base/supp-ran.mkiv
+++ b/Master/texmf-dist/tex/context/base/supp-ran.mkiv
@@ -18,13 +18,15 @@
\registerctxluafile{supp-ran}{1.001}
-\unexpanded\def\getrandomcount #1#2#3{#1=\ctxcommand{getrandomcounta(\number#2,\number#3)}\relax}
-\unexpanded\def\getrandomdimen #1#2#3{#1=\ctxcommand{getrandomcounta(\number\dimexpr#2,\number\dimexpr#3)}\scaledpoint\relax}
-\unexpanded\def\getrandomnumber#1#2#3{\edef#1{\ctxcommand{getrandomcounta(\number#2,\number#3)}}}
-\unexpanded\def\getrandomfloat #1#2#3{\edef#1{\ctxcommand{getrandomcountb(\number\dimexpr#2\points,\number\dimexpr#3\points)}}}
-\unexpanded\def\setrandomseed #1{\ctxcommand{setrandomseed(\number#1)}}
-\unexpanded\def\getrandomseed #1{\edef#1{\ctxcommand{getrandomseed()}}}
-\unexpanded\def\freezerandomseed {\ctxcommand{freezerandomseed()}}
-\unexpanded\def\defrostrandomseed {\ctxcommand{defrostrandomseed()}}
+\unprotect
-\endinput
+\unexpanded\def\getrandomcount #1#2#3{#1=\clf_getrandomnumber#2 #3\relax}
+\unexpanded\def\getrandomdimen #1#2#3{#1=\clf_getrandomdimen#2 #3 \scaledpoint\relax}
+\unexpanded\def\getrandomnumber#1#2#3{\edef#1{\clf_getrandomnumber#2 #3}}
+\unexpanded\def\getrandomfloat #1#2#3{\edef#1{\clf_getrandomfloat#2 #3}}
+\unexpanded\def\setrandomseed #1{\clf_setrandomseed#1\relax}
+\unexpanded\def\getrandomseed #1{\edef#1{\clf_getrandomseed}}
+\unexpanded\def\freezerandomseed {\clf_freezerandomseed}
+\unexpanded\def\defrostrandomseed {\clf_defrostrandomseed}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/symb-imp-cc.mkiv b/Master/texmf-dist/tex/context/base/symb-imp-cc.mkiv
index 45ea977328e..e753d695f8c 100644
--- a/Master/texmf-dist/tex/context/base/symb-imp-cc.mkiv
+++ b/Master/texmf-dist/tex/context/base/symb-imp-cc.mkiv
@@ -11,8 +11,10 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+%D LS/HH: This font has changed over time so there might be diffences
+%D in rendering. The otf, ttf and type1 version can differ too.
-\doiffontpresentelse{ccicons.otf} { % redone ctan version
+\doifelsefontpresent{ccicons.otf} { % redone ctan version
\definefontfeature
[creativecommons]
[mode=base,
diff --git a/Master/texmf-dist/tex/context/base/symb-ini.lua b/Master/texmf-dist/tex/context/base/symb-ini.lua
index 9586338be12..6a4a1882529 100644
--- a/Master/texmf-dist/tex/context/base/symb-ini.lua
+++ b/Master/texmf-dist/tex/context/base/symb-ini.lua
@@ -6,20 +6,27 @@ if not modules then modules = { } end modules ['symb-ini'] = {
license = "see context related readme files"
}
-local context, commands = context, commands
+local context = context
+local variables = interfaces.variables
-local variables = interfaces.variables
+fonts = fonts or { } -- brrrr
-fonts = fonts or { } -- brrrr
+local symbols = fonts.symbols or { }
+fonts.symbols = symbols
-local symbols = fonts.symbols or { }
-fonts.symbols = symbols
+local listitem = utilities.parsers.listitem
+local uselibrary = resolvers.uselibrary
local report_symbols = logs.reporter ("fonts","symbols")
local status_symbols = logs.messenger("fonts","symbols")
-local patterns = { "symb-imp-%s.mkiv", "symb-imp-%s.tex", "symb-%s.mkiv", "symb-%s.tex" }
-local listitem = utilities.parsers.listitem
+local patterns = {
+ "symb-imp-%s.mkiv",
+ "symb-imp-%s.tex",
+ -- obsolete:
+ "symb-%s.mkiv",
+ "symb-%s.tex"
+}
local function action(name,foundname)
-- context.startnointerference()
@@ -37,7 +44,7 @@ end
function symbols.uselibrary(name)
if name ~= variables.reset then
for name in listitem(name) do
- commands.uselibrary {
+ uselibrary {
name = name,
patterns = patterns,
action = action,
@@ -48,4 +55,8 @@ function symbols.uselibrary(name)
end
end
-commands.usesymbols = symbols.uselibrary
+interfaces.implement {
+ name = "usesymbols",
+ actions = symbols.uselibrary,
+ arguments = "string",
+}
diff --git a/Master/texmf-dist/tex/context/base/symb-ini.mkiv b/Master/texmf-dist/tex/context/base/symb-ini.mkiv
index e957e68c1f5..40a0af6d690 100644
--- a/Master/texmf-dist/tex/context/base/symb-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/symb-ini.mkiv
@@ -74,9 +74,12 @@
\letvalue{\??symbolset}\empty
-\unexpanded\def\doifinsymbolsetelse#1#2{\ifcsname\??symbol#1:#2\endcsname\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
+\unexpanded\def\doifelseinsymbolset#1#2{\ifcsname\??symbol#1:#2\endcsname\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
\unexpanded\def\doifinsymbolset #1#2{\ifcsname\??symbol#1:#2\endcsname\expandafter\firstofoneargument \else\expandafter\gobbleoneargument \fi}
-\unexpanded\def\doifsymbolsetelse #1{\ifcsname\??symbolset#1\endcsname\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
+\unexpanded\def\doifelsesymbolset #1{\ifcsname\??symbolset#1\endcsname\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
+
+\let\doifinsymbolsetelse\doifelseinsymbolset
+\let\doifsymbolsetelse \doifelsesymbolset
\def\symbolset#1{\csname\??symbolset\ifcsname\??symbolset#1\endcsname#1\fi\endcsname} % no [#1], to be used in commalists etc
@@ -216,7 +219,7 @@
\def\symb_fetch_second#1%
{\doifinsymbolset\empty\currentsymbol{\settrue\c_symb_found}}
-\def\doifsymboldefinedelse#1%
+\unexpanded\def\doifelsesymboldefined#1%
{\begingroup
\edef\currentsymbol{#1}%
\let\symb_fetch\symb_fetch_first
@@ -233,6 +236,8 @@
\fi
\fi}
+\let\doifsymboldefinedelse\doifelsesymboldefined
+
%D \macros
%D {setupsymbolset,startsymbolset}
%D
@@ -300,7 +305,7 @@
%D
%D \showsetup{usesymbols}
-\unexpanded\def\usesymbols[#1]{\ctxcommand{usesymbols("#1")}}
+\unexpanded\def\usesymbols[#1]{\clf_usesymbols{#1}}
%D As longs as symbols are linked to levels or numbers, we can
%D also use the conversion mechanism, but in for instance the
diff --git a/Master/texmf-dist/tex/context/base/syst-aux.lua b/Master/texmf-dist/tex/context/base/syst-aux.lua
index de15428f966..a880bace3b0 100644
--- a/Master/texmf-dist/tex/context/base/syst-aux.lua
+++ b/Master/texmf-dist/tex/context/base/syst-aux.lua
@@ -11,42 +11,66 @@ if not modules then modules = { } end modules ['syst-aux'] = {
-- utfmatch(str,"(.?)(.*)$")
-- utf.sub(str,1,1)
-local commands, context = commands, context
-
-local settings_to_array = utilities.parsers.settings_to_array
-local format = string.format
+local tonumber = tonumber
local utfsub = utf.sub
-local P, S, C, Cc, Cs, Carg, lpegmatch, utf8char = lpeg.P, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Carg, lpeg.match, lpeg.patterns.utf8char
-
+local P, S, R, C, Cc, Cs, Carg, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Carg, lpeg.match
-local setvalue = context.setvalue
-
-local pattern = C(utf8char^-1) * C(P(1)^0)
+local context = context
+local implement = interfaces.implement
+local formatters = string.formatters
+local setcatcode = tex.setcatcode
+local utf8character = lpeg.patterns.utf8character
+local settings_to_array = utilities.parsers.settings_to_array
+local setmacro = interfaces.setmacro
+
+local pattern = C(utf8character^-1) * C(P(1)^0)
+
+implement {
+ name = "getfirstcharacter",
+ arguments = "string",
+ actions = function(str)
+ local first, rest = lpegmatch(pattern,str)
+ setmacro("firstcharacter",first)
+ setmacro("remainingcharacters",rest)
+ end
+}
-function commands.getfirstcharacter(str)
- local first, rest = lpegmatch(pattern,str)
- setvalue("firstcharacter",first)
- setvalue("remainingcharacters",rest)
-end
+implement {
+ name = "thefirstcharacter",
+ arguments = "string",
+ actions = function(str)
+ local first, rest = lpegmatch(pattern,str)
+ context(first)
+ end
+}
-function commands.thefirstcharacter(str)
- local first, rest = lpegmatch(pattern,str)
- context(first)
-end
-function commands.theremainingcharacters(str)
- local first, rest = lpegmatch(pattern,str)
- context(rest)
-end
+implement {
+ name = "theremainingcharacters",
+ arguments = "string",
+ actions = function(str)
+ local first, rest = lpegmatch(pattern,str)
+ context(rest)
+ end
+}
-local pattern = C(utf8char^-1)
+local pattern = C(utf8character^-1)
+local ctx_doifelse = commands.doifelse
-function commands.doiffirstcharelse(chr,str)
- commands.doifelse(lpegmatch(pattern,str) == chr)
-end
+implement {
+ name = "doifelsefirstchar",
+ arguments = { "string", "string" },
+ actions = function(str,chr)
+ ctx_doifelse(lpegmatch(pattern,str) == chr)
+ end
+}
-function commands.getsubstring(str,first,last)
- context(utfsub(str,tonumber(first),tonumber(last)))
-end
+implement {
+ name = "getsubstring",
+ arguments = { "string", "string", "string" },
+ actions = function(str,first,last)
+ context(utfsub(str,tonumber(first),tonumber(last)))
+ end
+}
-- function commands.addtocommalist(list,item)
-- if list == "" then
@@ -78,21 +102,40 @@ end
-- end
-- end
-local pattern = (C((1-P("%"))^1) * Carg(1)) /function(n,d) return format("%.0fsp",d * tonumber(n)/100) end * P("%") * P(-1) -- .0 ?
+local pattern = (C((1-P("%"))^1) * Carg(1)) / function(n,d)
+ return formatters["%.0fsp"](d * tonumber(n)/100) end * P("%") * P(-1) -- .0 ?
--- commands.percentageof("10%",65536*10)
+-- percentageof("10%",65536*10)
-function commands.percentageof(str,dim)
- context(lpegmatch(pattern,str,1,dim) or str)
-end
+implement {
+ name = "percentageof",
+ arguments = { "string", "dimen" },
+ actions = function(str,dim)
+ context(lpegmatch(pattern,str,1,dim) or str)
+ end
+}
-- \gdef\setpercentdimen#1#2%
-- {#1=\ctxcommand{percentageof("#2",\number#1)}\relax}
-local spaces = P(" ")^0/""
+local spaces = P(" ")^0 / ""
+local nohash = 1 - P("#")
+local digit = R("09")
+local double = P("##") / "#"
+local single = P("#")
+local sentinel = spaces * (nohash^1 / "\\%0")
+local sargument = (single * digit)^1
+local dargument = (double * digit)^1
-local pattern = Cs(
- ( P("global") / "\\global" )^0
+local usespaces = nil
+local texpreamble = nil
+
+local pattern = Cs( -- ^-1
+ ( P("spaces") / function() usespaces = true return "" end )^0
+ * spaces
+ * ( P("nospaces") / function() usespaces = false return "" end )^0
+ * spaces
+ * ( P("global") / "\\global" )^0
* spaces
* ( P("unexpanded") / "\\unexpanded" )^0
* spaces
@@ -102,15 +145,85 @@ local pattern = Cs(
* spaces
* ( P((1-S(" #"))^1) / "def\\csname %0\\endcsname" )
* spaces
- * Cs( (P("##")/"#" + P(1))^0 )
+ * (
+ -- (double * digit)^1 * sentinel^-1 * double^-1
+ -- + (single * digit)^1 * sentinel^-1 * single^-1
+ ( P("[") * dargument * P("]") + dargument)^1 * sentinel^-1 * double^-1
+ + ( P("[") * sargument * P("]") + sargument)^1 * sentinel^-1 * single^-1
+ + sentinel^-1 * (double+single)^-1
+ )
)
-function commands.thetexdefinition(str)
- context(lpegmatch(pattern,str))
+local ctx_dostarttexdefinition = context.dostarttexdefinition
+
+local function texdefinition_one(str)
+ usespaces = nil
+ texpreamble = lpegmatch(pattern,str)
+ if usespaces == true then
+ setcatcode(32,10) -- space
+ setcatcode(13, 5) -- endofline
+ elseif usespaces == false then
+ setcatcode(32, 9) -- ignore
+ setcatcode(13, 9) -- ignore
+ else
+ -- this is default
+ -- setcatcode(32,10) -- space
+ -- setcatcode(13, 9) -- ignore
+ end
+ ctx_dostarttexdefinition()
+end
+
+local function texdefinition_two()
+ context(texpreamble)
end
-local upper, lower, strip = utf.upper, utf.lower, string.strip
+implement { name = "texdefinition_one", actions = texdefinition_one, scope = "private", arguments = "string" }
+implement { name = "texdefinition_two", actions = texdefinition_two, scope = "private" }
+
+implement { name = "upper", arguments = "string", actions = { utf.upper, context } }
+implement { name = "lower", arguments = "string", actions = { utf.lower, context } }
+implement { name = "strip", arguments = "string", actions = { string.strip, context } } -- or utf.strip
+
+-- implement {
+-- name = "converteddimen",
+-- arguments = { "dimen", "string" },
+-- actions = function(dimen,unit)
+-- context(todimen(dimen,unit or "pt","%0.5f")) -- no unit appended (%F)
+-- end
+-- }
+
+-- where, not really the best spot for this:
-function commands.upper(s) context(upper(s)) end
-function commands.lower(s) context(lower(s)) end
-function commands.strip(s) context(strip(s)) end
+implement {
+ name = "immediatemessage",
+ arguments = { "'message'", "string" },
+ actions = logs.status
+}
+
+implement {
+ name = "resettimer",
+ actions = function()
+ statistics.resettiming("whatever")
+ statistics.starttiming("whatever")
+ end
+}
+
+implement {
+ name = "elapsedtime",
+ actions = function()
+ statistics.stoptiming("whatever")
+ context(statistics.elapsedtime("whatever"))
+ end
+}
+
+local accuracy = table.setmetatableindex(function(t,k)
+ local v = formatters["%0." ..k .. "f"]
+ t[k] = v
+ return v
+end)
+
+implement {
+ name = "rounded",
+ arguments = "integer",
+ actions = function(n,m) context(accuracy[n](m)) end
+}
diff --git a/Master/texmf-dist/tex/context/base/syst-aux.mkiv b/Master/texmf-dist/tex/context/base/syst-aux.mkiv
index 308e4b6fca5..308ed5a3ba4 100644
--- a/Master/texmf-dist/tex/context/base/syst-aux.mkiv
+++ b/Master/texmf-dist/tex/context/base/syst-aux.mkiv
@@ -11,13 +11,17 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D There are some references to \LUA\ variants here but these concern
-%D (often old) experiments, moved from local test modules to here,
-%D cleaned up, but not really used. After all it's not that urgent
-%D and replacing helpers is a delicate process. Don't depend on it.
+%D There are some references to \LUA\ variants here but these concern (often old)
+%D experiments, moved from local test modules to here, cleaned up, but not really
+%D used. After all it's not that urgent and replacing helpers is a delicate process.
+%D Don't depend on it.
\registerctxluafile{syst-aux}{1.001}
+% A dedicated primitive \ifvoidmacro\cs == \ifx\cs\empty is some 10% faster but
+% probably not that noticeable in practice. An \ifvoidtoks might make sense but we
+% don't test that often for it (and it's more work to implement in the engine).
+
%D This is a stripped down combination of:
%D
%D \startitemize
@@ -26,20 +30,18 @@
%D \item \type {syst-new.tex}
%D \stopitemize
%D
-%D We keep them around (for \MKII) so you can find comments,
-%D experiences, intermediate versions and cleaner variants
-%D there (and also non-\ETEX\ variants).
+%D We keep them around (for \MKII) so you can find comments, experiences,
+%D intermediate versions and cleaner variants there (and also non-\ETEX\ variants).
%D
-%D Contrary to the older files, we now assume that this one
-%D is used in \CONTEXT\ and therefore we might also assume that
-%D some basic functionality is available.
+%D Contrary to the older files, we now assume that this one is used in \CONTEXT\ and
+%D therefore we might also assume that some basic functionality is available.
%D
-%D The original files contain previous implementations and notes about
-%D performance. This file will be stripped down in due time.
-
-%D Some of the macros here were only used in the bibliography module. They
-%D have been be moved to a separate syst module since the bib module is no
-%D longer using them. Some more will go away.
+%D The original files contain previous implementations and notes about performance.
+%D This file will be stripped down in due time.
+%D
+%D Some of the macros here were only used in the bibliography module. They have been
+%D be moved to a separate syst module since the bib module is no longer using them.
+%D Some more will go away.
\unprotect
@@ -72,13 +74,20 @@
% %def\expunded#1{\normalexpanded\expandafter{#1}}
% \def\expunded#1{\expandafter\empty#1} % used within an edef anyway
-
%D As we don't have namespace definers yet, we use a special one:
-\newcount\c_syst_helpers_n_of_namespaces \c_syst_helpers_n_of_namespaces\pluseight % 1-8 reserved for catcodes
+\ifdefined\c_syst_helpers_n_of_namespaces
+
+ % lets plug in a better error message
+
+\else
+
+ \newcount\c_syst_helpers_n_of_namespaces \c_syst_helpers_n_of_namespaces\pluseight % 1-8 reserved for catcodes
-\def\v_interfaces_prefix_template_system{\number \c_syst_helpers_n_of_namespaces>>}
-%def\v_interfaces_prefix_template_system{\characters\c_syst_helpers_n_of_namespaces>>} % no \characters yet
+ \def\v_interfaces_prefix_template_system{\number \c_syst_helpers_n_of_namespaces>>}
+ %def\v_interfaces_prefix_template_system{\characters\c_syst_helpers_n_of_namespaces>>} % no \characters yet
+
+\fi
\unexpanded\def\installsystemnamespace#1% maybe move this to syst-ini
{\ifcsname ??#1\endcsname
@@ -278,12 +287,14 @@
%D {\localnext} because we don't want clashes with \type
%D {\next}.
-\unexpanded\def\doifnextcharelse#1#2#3% #1 should not be {} !
+\unexpanded\def\doifelsenextchar#1#2#3% #1 should not be {} !
{\let\charactertoken=#1% = needed here
\def\m_syst_action_yes{#2}%
\def\m_syst_action_nop{#3}%
\futurelet\nexttoken\syst_helpers_inspect_next_character}
+\let\doifnextcharelse\doifelsenextchar
+
\def\syst_helpers_inspect_next_character
{\ifx\nexttoken\blankspace
\expandafter\syst_helpers_reinspect_next_character
@@ -318,18 +329,21 @@
\let\syst_helpers_next_optional_character_token=[
-\unexpanded\def\doifnextoptionalelse#1#2%
+\unexpanded\def\doifelsenextoptional#1#2%
{\def\m_syst_action_yes{#1}%
\def\m_syst_action_nop{#2}%
\let\if_next_blank_space_token\iffalse
\futurelet\nexttoken\syst_helpers_inspect_next_optional_character}
-\unexpanded\def\doifnextoptionalcselse#1#2% \cs \cs (upto 10% faster)
+\unexpanded\def\doifelsenextoptionalcs#1#2% \cs \cs (upto 10% faster)
{\let\m_syst_action_yes#1%
\let\m_syst_action_nop#2%
\let\if_next_blank_space_token\iffalse
\futurelet\nexttoken\syst_helpers_inspect_next_optional_character}
+\let\doifnextoptionalelse \doifelsenextoptional
+\let\doifnextoptionalcselse\doifelsenextoptionalcs
+
\def\syst_helpers_inspect_next_optional_character
{\ifx\nexttoken\blankspace
\expandafter\syst_helpers_reinspect_next_optional_character
@@ -346,18 +360,21 @@
\let\syst_helpers_next_bgroup_character_token\bgroup
-\unexpanded\def\doifnextbgroupelse#1#2%
+\unexpanded\def\doifelsenextbgroup#1#2%
{\def\m_syst_action_yes{#1}%
\def\m_syst_action_nop{#2}%
\let\if_next_blank_space_token\iffalse
\futurelet\nexttoken\syst_helpers_inspect_next_bgroup_character}
-\unexpanded\def\doifnextbgroupcselse#1#2%
+\unexpanded\def\doifelsenextbgroupcs#1#2%
{\let\m_syst_action_yes#1%
\let\m_syst_action_nop#2%
\let\if_next_blank_space_token\iffalse
\futurelet\nexttoken\syst_helpers_inspect_next_bgroup_character}
+\let\doifnextbgroupelse \doifelsenextbgroup
+\let\doifnextbgroupcselse\doifelsenextbgroupcs
+
\def\syst_helpers_inspect_next_bgroup_character
{\ifx\nexttoken\blankspace
\expandafter\syst_helpers_reinspect_next_bgroup_character
@@ -374,12 +391,14 @@
\let\syst_helpers_next_parenthesis_character_token(
-\unexpanded\def\doifnextparenthesiselse#1#2%
+\unexpanded\def\doifelsenextparenthesis#1#2%
{\def\m_syst_action_yes{#1}%
\def\m_syst_action_nop{#2}%
\let\if_next_blank_space_token\iffalse
\futurelet\nexttoken\syst_helpers_inspect_next_parenthesis_character}
+\let\doifnextparenthesiselse\doifelsenextparenthesis
+
\def\syst_helpers_inspect_next_parenthesis_character
{\ifx\nexttoken\blankspace
\expandafter\syst_helpers_reinspect_next_parenthesis_character
@@ -396,16 +415,19 @@
%D The next one is handy in predictable situations:
-\unexpanded\def\doiffastoptionalcheckelse#1#2%
+\unexpanded\def\doifelsefastoptionalcheck#1#2%
{\def\m_syst_action_yes{#1}%
\def\m_syst_action_nop{#2}%
\futurelet\nexttoken\syst_helpers_do_if_fast_optional_check_else}
-\unexpanded\def\doiffastoptionalcheckcselse#1#2% \cs \cs
+\unexpanded\def\doifelsefastoptionalcheckcs#1#2% \cs \cs
{\let\m_syst_action_yes#1%
\let\m_syst_action_nop#2%
\futurelet\nexttoken\syst_helpers_do_if_fast_optional_check_else}
+\let\doiffastoptionalcheckelse \doifelsefastoptionalcheck
+\let\doiffastoptionalcheckcselse\doifelsefastoptionalcheckcs
+
\def\syst_helpers_do_if_fast_optional_check_else
{\ifx\nexttoken\syst_helpers_next_optional_character_token
\expandafter\m_syst_action_yes
@@ -574,12 +596,12 @@
\suppressifcsnameerror\plusone
-\def\doifundefinedelse#1%
+\def\doifelseundefined#1%
{\ifcsname#1\endcsname
\expandafter\secondoftwoarguments\else\expandafter\firstoftwoarguments
\fi}
-\def\doifdefinedelse#1%
+\def\doifelsedefined#1%
{\ifcsname#1\endcsname
\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments
\fi}
@@ -594,6 +616,9 @@
\expandafter\firstofoneargument\else\expandafter\gobbleoneargument
\fi}
+\let\doifundefinedelse\doifelseundefined
+\let\doifdefinedelse \doifelsedefined
+
%D \macros
%D {letbeundefined}
%D
@@ -617,7 +642,7 @@
%D behavior in text and math mode, which was due to this grouping subtilities. We
%D therefore decided to use \type{\begingroup} instead of \type{\bgroup}.
-\unexpanded\def\doifalldefinedelse#1%
+\unexpanded\def\doifelsealldefined#1%
{\begingroup
\donetrue % we could use a reserved one and avoid the group
\processcommalist[#1]\syst_helpers_do_if_all_defined_else
@@ -627,6 +652,8 @@
\endgroup\expandafter\secondoftwoarguments
\fi}
+\let\doifalldefinedelse\doifelsealldefined
+
\def\syst_helpers_do_if_all_defined_else#1%
{\ifcsname#1\endcsname\else
\donefalse
@@ -690,7 +717,7 @@
%D
%D This time, the string is not expanded.
-\unexpanded\def\doifemptyelse#1%
+\unexpanded\def\doifelseempty#1%
{\def\m_syst_string_one{#1}%
\ifx\m_syst_string_one\empty
\expandafter\firstoftwoarguments
@@ -698,6 +725,8 @@
\expandafter\secondoftwoarguments
\fi}
+\let\doifemptyelse\doifelseempty
+
\unexpanded\def\doifempty#1%
{\def\m_syst_string_one{#1}%
\ifx\m_syst_string_one\empty
@@ -763,7 +792,7 @@
\def\syst_helpers_re_do_if_in_set {\expandafter\syst_helpers_do_check_if_item_in_set \m_syst_string_two,],\relax}
\def\syst_helpers_re_do_if_not_in_set {\expandafter\syst_helpers_do_check_if_item_not_in_set \m_syst_string_two,],\relax}
-\unexpanded\def\doifinsetelse#1% make this two step too
+\unexpanded\def\doifelseinset#1% make this two step too
{\edef\m_syst_string_one{#1}%
\ifx\m_syst_string_one\empty
\expandafter\thirdofthreearguments
@@ -771,6 +800,8 @@
\expandafter\syst_helpers_do_if_in_set_else
\fi}
+\let\doifinsetelse\doifelseinset
+
\def\syst_helpers_do_if_in_set_else#1%
{\edef\m_syst_string_two{#1}%
\ifx\m_syst_string_two\empty
@@ -961,10 +992,12 @@
\fi\fi
#1#2}
-\unexpanded\def\doifcommonelse{\syst_helpers_do_do_if_common_else\firstoftwoarguments\secondoftwoarguments}
+\unexpanded\def\doifelsecommon{\syst_helpers_do_do_if_common_else\firstoftwoarguments\secondoftwoarguments}
\unexpanded\def\doifcommon {\syst_helpers_do_do_if_common_else\firstofoneargument \gobbleoneargument }
\unexpanded\def\doifnotcommon {\syst_helpers_do_do_if_common_else\gobbleoneargument \firstofoneargument }
+\let\doifcommonelse\doifelsecommon
+
%D \macros
%D {processcommalist,processcommacommand,quitcommalist,
%D processcommalistwithparameters}
@@ -1306,10 +1339,12 @@
\let\firstcharacter \empty
\let\remainingcharacters\empty
-\unexpanded\def\getfirstcharacter #1{\ctxcommand{getfirstcharacter(\!!bs#1\!!es)}}
-\unexpanded\def\doiffirstcharelse #1#2{\ctxcommand{doiffirstcharelse(\!!bs#1\!!es,\!!bs#2\!!es)}} % chr str
-\unexpanded\def\thefirstcharacter #1{\ctxcommand{thefirstcharacter(\!!bs#1\!!es)}}
-\unexpanded\def\theremainingcharacters#1{\ctxcommand{theremainingcharacters(\!!bs#1\!!es)}}
+\unexpanded\def\getfirstcharacter #1{\clf_getfirstcharacter{#1}}
+\unexpanded\def\doifelsefirstchar #1#2{\clf_doifelsefirstchar{#1}{#2}}
+\unexpanded\def\thefirstcharacter #1{\clf_thefirstcharacter{#1}}
+\unexpanded\def\theremainingcharacters#1{\clf_theremainingcharacters{#1}}
+
+\let\doiffirstcharelse\doifelsefirstchar
%D \macros
%D {doifinstringelse, doifincsnameelse}
@@ -1323,7 +1358,7 @@
\let\m_syst_sub_string\empty
-\unexpanded\def\doifinstringelse#1%
+\unexpanded\def\doifelseinstring#1%
{\edef\m_syst_sub_string{#1}% expand #1 here
\ifx\m_syst_sub_string\empty
\expandafter\thirdofthreearguments
@@ -1331,6 +1366,8 @@
\expandafter\syst_helpers_do_if_in_string_else_indeed
\fi}
+\let\doifinstringelse\doifelseinstring
+
\unexpanded\def\syst_helpers_do_if_in_string_else_indeed#1%
{\syst_helpers_do_if_in_string_else\m_syst_sub_string{#1}%
\expandafter\firstoftwoarguments
@@ -1393,13 +1430,15 @@
{\unless\if##2@}%
\expandafter\syst_helpers_do_do_if_in_csname_else#2#1@@\_e_o_s_}
-\unexpanded\def\doifincsnameelse#1#2%
+\unexpanded\def\doifelseincsname#1#2%
{\normalexpanded{\syst_helpers_do_if_in_csname_else{#1}}{#2}%
\expandafter\firstoftwoarguments
\else
\expandafter\secondoftwoarguments
\fi}
+\let\doifincsnameelse\doifelseincsname
+
%D \macros
%D {doifnumberelse,doifnumber,doifnotnumber}
%D
@@ -1415,13 +1454,15 @@
%D The macro accepts \type {123}, \type {abc}, \type {{}}, \type {\getal} and
%D \type {\the\count...}. This macro is a rather dirty one.
-\def\doifnumberelse#1% does not accept counters (fully expandable)
+\def\doifelsenumber#1% does not accept counters (fully expandable)
{\ifcase0\ifcase1#1\or\or\or\or\or\or\or\or\or\else1\fi\space
\expandafter\secondoftwoarguments
\else
\expandafter\firstoftwoarguments
\fi}
+\let\doifnumberelse\doifelsenumber
+
\def\doifnumber#1%
{\ifcase0\ifcase1#1\or\or\or\or\or\or\or\or\or\else1\fi\space
\expandafter\firstofoneargument
@@ -1446,10 +1487,10 @@
%D \stoptyping
\def\percentdimen#1#2% dimen percentage (with %)
- {\dimexpr\ctxcommand{percentageof("#2",\number#1)}\relax}
+ {\dimexpr\clf_percentageof{#2}\dimexpr#1\relax}
\unexpanded\def\setpercentdimen#1#2% dimen percentage (with %)
- {#1=\ctxcommand{percentageof("#2",\number#1)}\relax}
+ {#1=\clf_percentageof{#2}\dimexpr#1\relax}
%D \macros
%D {makerawcommalist,
@@ -1469,7 +1510,7 @@
%D
%D \starttyping
%D \makerawcommalist[string,string,...]\stringlist
-%D \rawdoifinsetelse{string}{string,...}{...}{...}
+%D \rawdoifelseinset{string}{string,...}{...}{...}
%D \rawprocesscommalist[string,string,...]\commando
%D \rawprocessaction[x][a=>\a,b=>\b,c=>\c]
%D \stoptyping
@@ -1504,12 +1545,12 @@
\unexpanded\def\rawprocesscommacommand[#1]% not really needed
{\normalexpanded{\rawprocesscommalist[#1]}}
-% \def\rawdoifinsetelse#1#2{\doifinstringelse{,#1,}{,#2,}}
+% \def\rawdoifelseinset#1#2{\doifinstringelse{,#1,}{,#2,}}
% \def\rawdoifinset #1#2{\doifinstring {,#1,}{,#2,}}
\def\m_syst_two_commas{,,}
-\unexpanded\def\rawdoifinsetelse#1%
+\unexpanded\def\rawdoifelseinset#1%
{\edef\m_syst_sub_string{,#1,}% expand #1 here
\ifx\m_syst_sub_string\m_syst_two_commas
\expandafter\thirdofthreearguments
@@ -1517,6 +1558,8 @@
\expandafter\syst_helpers_raw_do_if_in_set_else
\fi}
+\let\rawdoifinsetelse\rawdoifinsetelse
+
\unexpanded\def\syst_helpers_raw_do_if_in_set_else#1%
{\syst_helpers_do_if_in_string_else\m_syst_sub_string{,#1,}%
\expandafter\firstoftwoarguments
@@ -2182,7 +2225,7 @@
\unexpanded\def\dosingleempty#1%
{\syst_helpers_argument_reset
- \doifnextoptionalelse
+ \doifelsenextoptional
{\firstargumenttrue#1}%
{\syst_helpers_single_empty_one_nop#1}}
@@ -2194,13 +2237,13 @@
\unexpanded\def\dodoubleempty#1%
{\syst_helpers_argument_reset
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_double_empty_one_yes#1}%
{\syst_helpers_double_empty_one_nop#1}}
\def\syst_helpers_double_empty_one_yes#1[#2]%
{\firstargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\secondargumenttrue#1[{#2}]}%
{\syst_helpers_double_empty_two_nop#1{#2}}}
@@ -2224,19 +2267,19 @@
\unexpanded\def\dotripleempty#1%
{\syst_helpers_argument_reset
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_triple_empty_one_yes#1}%
{\syst_helpers_triple_empty_one_nop#1}}
\def\syst_helpers_triple_empty_one_yes#1[#2]%
{\firstargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_triple_empty_two_yes#1{#2}}%
{\syst_helpers_triple_empty_two_nop#1{#2}}}
\def\syst_helpers_triple_empty_two_yes#1#2[#3]%
{\secondargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\thirdargumenttrue#1[{#2}][{#3}]}%
{\syst_helpers_triple_empty_three_nop#1{#2}{#3}}}
@@ -2272,25 +2315,25 @@
\unexpanded\def\doquadrupleempty#1%
{\syst_helpers_argument_reset
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_quadruple_empty_one_yes#1}%
{\syst_helpers_quadruple_empty_one_nop#1}}
\def\syst_helpers_quadruple_empty_one_yes#1[#2]%
{\firstargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_quadruple_empty_two_yes#1{#2}}%
{\syst_helpers_quadruple_empty_two_nop#1{#2}}}
\def\syst_helpers_quadruple_empty_two_yes#1#2[#3]%
{\secondargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_quadruple_empty_three_yes#1{#2}{#3}}%
{\syst_helpers_quadruple_empty_three_nop#1{#2}{#3}}}
\def\syst_helpers_quadruple_empty_three_yes#1#2#3[#4]%
{\thirdargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\fourthargumenttrue#1[{#2}][{#3}][{#4}]}%
{\syst_helpers_quadruple_empty_four_nop#1{#2}{#3}{#4}}}
@@ -2339,31 +2382,31 @@
\unexpanded\def\doquintupleempty#1%
{\syst_helpers_argument_reset
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_quintuple_empty_one_yes#1}%
{\syst_helpers_quintuple_empty_one_nop#1}}
\def\syst_helpers_quintuple_empty_one_yes#1[#2]%
{\firstargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_quintuple_empty_two_yes#1{#2}}%
{\syst_helpers_quintuple_empty_two_nop#1{#2}}}
\def\syst_helpers_quintuple_empty_two_yes#1#2[#3]%
{\secondargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_quintuple_empty_three_yes#1{#2}{#3}}%
{\syst_helpers_quintuple_empty_three_nop#1{#2}{#3}}}
\def\syst_helpers_quintuple_empty_three_yes#1#2#3[#4]%
{\thirdargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_quintuple_empty_four_yes#1{#2}{#3}{#4}}%
{\syst_helpers_quintuple_empty_four_nop#1{#2}{#3}{#4}}}
\def\syst_helpers_quintuple_empty_four_yes#1#2#3#4[#5]%
{\fourthargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\fifthargumenttrue#1[{#2}][{#3}][{#4}][{#5}]}%
{\syst_helpers_quintuple_empty_five_nop#1{#2}{#3}{#4}{#5}}}
@@ -2426,37 +2469,37 @@
\unexpanded\def\dosixtupleempty#1%
{\syst_helpers_argument_reset
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_sixtuple_empty_one_yes#1}
{\syst_helpers_sixtuple_empty_one_nop#1}}
\def\syst_helpers_sixtuple_empty_one_yes#1[#2]%
{\firstargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_sixtuple_empty_two_yes#1{#2}}%
{\syst_helpers_sixtuple_empty_two_nop#1{#2}}}
\def\syst_helpers_sixtuple_empty_two_yes#1#2[#3]%
{\secondargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_sixtuple_empty_three_yes#1{#2}{#3}}%
{\syst_helpers_sixtuple_empty_three_nop#1{#2}{#3}}}
\def\syst_helpers_sixtuple_empty_three_yes#1#2#3[#4]%
{\thirdargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_sixtuple_empty_four_yes#1{#2}{#3}{#4}}%
{\syst_helpers_sixtuple_empty_four_nop#1{#2}{#3}{#4}}}
\def\syst_helpers_sixtuple_empty_four_yes#1#2#3#4[#5]%
{\fourthargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_sixtuple_empty_five_yes#1{#2}{#3}{#4}{#5}}%
{\syst_helpers_sixtuple_empty_five_nop#1{#2}{#3}{#4}{#5}}}
\def\syst_helpers_sixtuple_empty_five_yes#1#2#3#4#5[#6]%
{\fifthargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\sixthargumenttrue#1[{#2}][{#3}][{#4}][{#5}][{#6}]}%
{\syst_helpers_sixtuple_empty_six_nop#1{#2}{#3}{#4}{#5}{#6}}}
@@ -2534,43 +2577,43 @@
\unexpanded\def\doseventupleempty#1%
{\syst_helpers_argument_reset
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_seventuple_empty_one_yes#1}%
{\syst_helpers_seventuple_empty_one_nop#1}}
\def\syst_helpers_seventuple_empty_one_yes#1[#2]%
{\firstargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_seventuple_empty_two_yes#1{#2}}%
{\syst_helpers_seventuple_empty_two_nop#1{#2}}}
\def\syst_helpers_seventuple_empty_two_yes#1#2[#3]%
{\secondargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_seventuple_empty_three_yes#1{#2}{#3}}%
{\syst_helpers_seventuple_empty_three_nop#1{#2}{#3}}}
\def\syst_helpers_seventuple_empty_three_yes#1#2#3[#4]%
{\thirdargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_seventuple_empty_four_yes#1{#2}{#3}{#4}}%
{\syst_helpers_seventuple_empty_four_nop#1{#2}{#3}{#4}}}
\def\syst_helpers_seventuple_empty_four_yes#1#2#3#4[#5]%
{\fourthargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_seventuple_empty_five_yes#1{#2}{#3}{#4}{#5}}%
{\syst_helpers_seventuple_empty_five_nop#1{#2}{#3}{#4}{#5}}}
\def\syst_helpers_seventuple_empty_five_yes#1#2#3#4#5[#6]%
{\fifthargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\syst_helpers_seventuple_empty_six_yes#1{#2}{#3}{#4}{#5}{#6}}%
{\syst_helpers_seventuple_empty_six_nop#1{#2}{#3}{#4}{#5}{#6}}}
\def\syst_helpers_seventuple_empty_six_yes#1#2#3#4#5#6[#7]%
{\sixthargumenttrue
- \doifnextoptionalelse
+ \doifelsenextoptional
{\seventhargumenttrue#1[{#2}][{#3}][{#4}][{#5}][{#6}][{#7}]}%
{\syst_helpers_seventuple_empty_seven_nop#1{#2}{#3}{#4}{#5}{#6}{#7}}}
@@ -2726,13 +2769,13 @@
\unexpanded\def\complexorsimple#1%
{% \relax % prevents lookahead, brrr
- \doifnextoptionalelse
+ \doifelsenextoptional
{\firstargumenttrue \csname\s!complex\strippedcsname#1\endcsname}
{\firstargumentfalse\csname\s!simple \strippedcsname#1\endcsname}}
\unexpanded\def\complexorsimpleempty#1%
{% \relax % prevents lookahead, brrr
- \doifnextoptionalelse
+ \doifelsenextoptional
{\firstargumenttrue \csname\s!complex\strippedcsname#1\endcsname}
{\firstargumentfalse\csname\s!complex\strippedcsname#1\endcsname[]}}
@@ -2744,10 +2787,10 @@
%D in protection.
\unexpanded\def\syst_helpers_complex_or_simple#1#2%
- {\doifnextoptionalelse{\firstargumenttrue#1}{\firstargumentfalse#2}}
+ {\doifelsenextoptional{\firstargumenttrue#1}{\firstargumentfalse#2}}
\unexpanded\def\syst_helpers_complex_or_simple_empty#1%
- {\doifnextoptionalelse{\firstargumenttrue#1}{\firstargumentfalse#1[]}}
+ {\doifelsenextoptional{\firstargumenttrue#1}{\firstargumentfalse#1[]}}
\unexpanded\def\definecomplexorsimple#1%
{\unexpanded\edef#1{\syst_helpers_complex_or_simple
@@ -2948,7 +2991,14 @@
\def\fifthofsixarguments #1#2#3#4#5#6{#5}
\def\sixthofsixarguments #1#2#3#4#5#6{#6}
-\unexpanded\def\firstofoneunexpanded#1{#1}
+\unexpanded\def\firstofoneunexpanded #1{#1}
+
+\unexpanded\def\firstoftwounexpanded #1#2{#1}
+\unexpanded\def\secondoftwounexpanded #1#2{#2}
+
+\unexpanded\def\firstofthreeunexpanded #1#2#3{#1}
+\unexpanded\def\secondofthreeunexpanded#1#2#3{#2}
+\unexpanded\def\thirdofthreeunexpanded #1#2#3{#3}
%D \macros
%D {globalletempty,letempty,
@@ -3033,7 +3083,7 @@
%D
%D A fully expandable message:
-\def\immediatemessage#1{\ctxlua{logs.status("message","#1")}}
+\let\immediatemessage\clf_immediatemessage % {} mandate
%D \macros
%D {debuggerinfo}
@@ -3249,6 +3299,25 @@
% [here #oeps: \the\scratchcounter]
% \stoptexdefinition
+% \bgroup \obeylines
+%
+% \global\let\stoptexdefinition\relax
+%
+% \unexpanded\gdef\starttexdefinition%
+% {\bgroup%
+% \obeylines%
+% \syst_helpers_start_tex_definition_one}
+%
+% \gdef\syst_helpers_start_tex_definition_one#1
+% {\catcode\endoflineasciicode\ignorecatcode%
+% \syst_helpers_start_tex_definition_two{#1}}
+%
+% \gdef\syst_helpers_start_tex_definition_two#1#2\stoptexdefinition%
+% {\egroup%
+% \ctxcommand{thetexdefinition("#1")}{#2}}
+%
+% \egroup
+
\bgroup \obeylines
\global\let\stoptexdefinition\relax
@@ -3256,19 +3325,19 @@
\unexpanded\gdef\starttexdefinition%
{\bgroup%
\obeylines%
- \syst_helpers_start_tex_definition_one}
+ \syst_helpers_start_tex_definition}
-\gdef\syst_helpers_start_tex_definition_one#1
+\gdef\syst_helpers_start_tex_definition#1
{\catcode\endoflineasciicode\ignorecatcode%
- \syst_helpers_start_tex_definition_two{#1}}
+ \clf_texdefinition_one{#1}}
-\gdef\syst_helpers_start_tex_definition_two#1#2\stoptexdefinition%
+\gdef\dostarttexdefinition#1\stoptexdefinition%
{\egroup%
- \ctxcommand{thetexdefinition("#1")}{#2}}
+ \clf_texdefinition_two{#1}}
\egroup
-\unexpanded\def\texdefinition#1{\csname\ifcsname#1\endcsname#1\else donothing\fi\endcsname}
+\unexpanded\def\texdefinition#1{\csname\ifcsname#1\endcsname#1\else donothing\fi\endcsname} % todo: a nop cs: char 0 or some corenamespace
% This is a first variant, more might be added:
@@ -3345,14 +3414,14 @@
\def\syst_helpers_do_do_do_increment#1,#2){\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+#2\relax}}
\def\syst_helpers_do_do_do_decrement#1,#2){\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi-#2\relax}}
-\def\syst_helpers_do_do_increment(#1{\doifnextcharelse,{\syst_helpers_do_do_do_increment#1}{\syst_helpers_do_do_do_increment#1,\plusone}}
-\def\syst_helpers_do_do_decrement(#1{\doifnextcharelse,{\syst_helpers_do_do_do_decrement#1}{\syst_helpers_do_do_do_decrement#1,\plusone}}
+\def\syst_helpers_do_do_increment(#1{\doifelsenextchar,{\syst_helpers_do_do_do_increment#1}{\syst_helpers_do_do_do_increment#1,\plusone}}
+\def\syst_helpers_do_do_decrement(#1{\doifelsenextchar,{\syst_helpers_do_do_do_decrement#1}{\syst_helpers_do_do_do_decrement#1,\plusone}}
\unexpanded\def\fastincrement#1{\dodoglobal\edef#1{\the\numexpr#1+\plusone \relax}}
\unexpanded\def\fastdecrement#1{\dodoglobal\edef#1{\the\numexpr#1+\minusone\relax}}
-\unexpanded\def\increment{\doifnextcharelse(\syst_helpers_do_do_increment\syst_helpers_do_increment}
-\unexpanded\def\decrement{\doifnextcharelse(\syst_helpers_do_do_decrement\syst_helpers_do_decrement}
+\unexpanded\def\increment{\doifelsenextchar(\syst_helpers_do_do_increment\syst_helpers_do_increment}
+\unexpanded\def\decrement{\doifelsenextchar(\syst_helpers_do_do_decrement\syst_helpers_do_decrement}
\unexpanded\def\incrementvalue#1{\expandafter\increment\csname#1\endcsname}
\unexpanded\def\decrementvalue#1{\expandafter\decrement\csname#1\endcsname}
@@ -3396,6 +3465,7 @@
{\expandafter\syst_helpers_checked_stripped_csname\string#1}
\def\syst_helpers_checked_stripped_csname#1%
+ %{\ifx#1\letterbackslash\else#1\fi}
{\if\noexpand#1\letterbackslash\else#1\fi}
%D \macros
@@ -4028,13 +4098,15 @@
\def\syst_helpers_check_if_assignment_else#1=#2#3\_e_o_p_{\if#2@}%
-\unexpanded\def\doifassignmentelse#1% expandable
+\unexpanded\def\doifelseassignment#1% expandable
{\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=@@\_e_o_p_
\expandafter\secondoftwoarguments
\else
\expandafter\firstoftwoarguments
\fi}
+\let\doifassignmentelse\doifelseassignment
+
\newif\ifassignment
\unexpanded\def\docheckassignment#1%
@@ -4107,7 +4179,7 @@
%D
%D Watch the one level expansion of the second argument.
-\unexpanded\def\doifmeaningelse#1#2%
+\unexpanded\def\doifelsemeaning#1#2%
{\edef\m_syst_string_one{\meaning#1}%
\def \m_syst_string_two{#2}%
\edef\m_syst_string_two{\meaning\m_syst_string_two}%
@@ -4117,6 +4189,8 @@
\expandafter\secondoftwoarguments
\fi}
+\let\doifmeaningelse\doifelsemeaning
+
%D \macros
%D {doifsamestringselse,doifsamestring,doifnotsamestring}
%D
@@ -4134,10 +4208,12 @@
\edef\m_syst_string_two{\detokenize\expandafter{\normalexpanded{#4}}}%
\ifx\m_syst_string_one\m_syst_string_two\expandafter#1\else\expandafter#2\fi}
-\unexpanded\def\doifsamestringelse{\syst_helpers_if_samestring_else\firstoftwoarguments\secondoftwoarguments}
+\unexpanded\def\doifelsesamestring{\syst_helpers_if_samestring_else\firstoftwoarguments\secondoftwoarguments}
\unexpanded\def\doifsamestring {\syst_helpers_if_samestring_else\firstofoneargument \gobbleoneargument }
\unexpanded\def\doifnotsamestring {\syst_helpers_if_samestring_else\gobbleoneargument \firstofoneargument }
+\let\doifsamestringelse\doifelsesamestring
+
%D \macros
%D {ConvertToConstant,ConvertConstantAfter}
%D
@@ -4199,7 +4275,7 @@
\unexpanded\def\CheckConstantAfter#1#2%
{\expandafter\convertargument\v!prefix!\to\ascii
\convertargument#1\to#2\relax
- \doifinstringelse\ascii{#2}
+ \doifelseinstring\ascii{#2}
{\expandafter\convertargument#1\to#2}
{}}
@@ -4438,6 +4514,18 @@
{\m_syst_helpers_handle_group_after
\egroup}%
+\unexpanded\def\syst_helpers_handle_group_pickup#1#2#3% no inner group (so no kerning interference)
+ {\bgroup
+ \def\m_syst_helpers_handle_group_before{#1}%
+ \def\m_syst_helpers_handle_group_after {#2\egroup#3}%
+ \afterassignment\m_syst_helpers_handle_group_pickup_before
+ \let\next=}
+
+\def\m_syst_helpers_handle_group_pickup_before
+ {\bgroup
+ \aftergroup\m_syst_helpers_handle_group_after
+ \m_syst_helpers_handle_group_before}
+
\unexpanded\def\syst_helpers_handle_group_nop
{\ifnum\currentgrouptype=\semisimplegroupcode
\expandafter\syst_helpers_handle_group_nop_a
@@ -4470,10 +4558,13 @@
%D implementation became:
\unexpanded\def\groupedcommand#1#2%
- {\doifnextbgroupelse{\syst_helpers_handle_group_normal{#1}{#2}}{\syst_helpers_handle_group_nop{#1}{#2}}}
+ {\doifelsenextbgroup{\syst_helpers_handle_group_normal{#1}{#2}}{\syst_helpers_handle_group_nop{#1}{#2}}}
\unexpanded\def\simplegroupedcommand#1#2%
- {\doifnextbgroupelse{\syst_helpers_handle_group_simple{#1}{#2}}{\syst_helpers_handle_group_nop{#1}{#2}}}
+ {\doifelsenextbgroup{\syst_helpers_handle_group_simple{#1}{#2}}{\syst_helpers_handle_group_nop{#1}{#2}}}
+
+\unexpanded\def\pickupgroupedcommand#1#2#3%
+ {\doifelsenextbgroup{\syst_helpers_handle_group_pickup{#1}{#2}{#3}}{\syst_helpers_handle_group_nop{#1}{#2}}}
%D Users should be aware of the fact that grouping can
%D interfere with ones paragraph settings that are executed
@@ -4567,14 +4658,14 @@
\newtoks\AfterPar
\def\redowithpar\par
- {\doifnextcharelse\par\redowithpar\dodowithpar}%
+ {\doifelsenextchar\par\redowithpar\dodowithpar}%
\def\dowithpar#1#2%
{\def\dodowithpar##1\par{#1##1#2}%
\redowithpar\par}
\def\redogotopar\par
- {\doifnextcharelse\par\redogotopar\dodogotopar}%
+ {\doifelsenextchar\par\redogotopar\dodogotopar}%
\def\dogotopar#1%
{\def\dodogotopar{#1}%
@@ -4638,7 +4729,7 @@
\unexpanded\def\dowithpargument#1%
{\def\syst_helpers_next_par##1 \par{#1{##1}}%
\def\syst_helpers_next_arg##1{#1{##1}}%
- \doifnextbgroupelse\syst_helpers_next_arg{\doifnextcharelse\par{#1{}}\syst_helpers_next_par}}
+ \doifelsenextbgroup\syst_helpers_next_arg{\doifelsenextchar\par{#1{}}\syst_helpers_next_par}}
%D The \type{p} in the previous command stands for paragraph.
%D When we want to act upon words we can use the \type{w}
@@ -4668,7 +4759,7 @@
\unexpanded\def\dowithwargument#1%
{\def\syst_helpers_next_war##1 {#1{##1}}%
\def\syst_helpers_next_arg##1{#1{##1}}%
- \doifnextbgroupelse\syst_helpers_next_arg\syst_helpers_next_war}
+ \doifelsenextbgroup\syst_helpers_next_arg\syst_helpers_next_war}
%D \macros
%D {dorepeat,dorepeatwithcommand}
@@ -4763,11 +4854,13 @@
\expandafter\firstoftwoarguments
\fi}
-\def\doifstringinstringelse#1#2%
+\def\doifelsestringinstring#1#2%
{\expandafter\def\expandafter\syst_helpers_if_instring_else\expandafter##\expandafter1#1##2##3\_e_o_s_
{\syst_helpers_if_instring_else_indeed##2}%
\expandafter\expandafter\expandafter\syst_helpers_if_instring_else\expandafter#2#1@@\_e_o_s_}
+\let\doifstringinstringelse\doifelsestringinstring
+
%D \macros
%D {appendtoks,prependtoks,appendtoksonce,prependtoksonce,
%D doifintokselse,flushtoks,dotoks}
@@ -4813,19 +4906,21 @@
\def\syst_helpers_append_toks_once#1\to#2%
{\let\m_syst_helpers_scratch#2%
\t_syst_helpers_scratch\expandafter{\gobbleoneargument#1}%
- \doifintokselse\t_syst_helpers_scratch\m_syst_helpers_scratch\donothing\syst_helpers_append_toks_indeed}
+ \doifelseintoks\t_syst_helpers_scratch\m_syst_helpers_scratch\donothing\syst_helpers_append_toks_indeed}
\def\syst_helpers_prepend_toks_once#1\to#2%
{\let\m_syst_helpers_scratch#2%
\t_syst_helpers_scratch\expandafter{\gobbleoneargument#1}%
- \doifintokselse\t_syst_helpers_scratch\m_syst_helpers_scratch\donothing\syst_helpers_prepend_toks_indeed}
+ \doifelseintoks\t_syst_helpers_scratch\m_syst_helpers_scratch\donothing\syst_helpers_prepend_toks_indeed}
%D The test macro:
-\unexpanded\def\doifintokselse#1#2% #1 en #2 zijn toks
+\unexpanded\def\doifelseintoks#1#2% #1 en #2 zijn toks
{\edef\asciia{\detokenize\expandafter{\the#1}}%
\edef\asciib{\detokenize\expandafter{\the#2}}%
- \doifstringinstringelse\asciia\asciib}
+ \doifelsestringinstring\asciia\asciib}
+
+\let\doifintokselse\doifelseintoks
%D A nice one too:
@@ -5019,24 +5114,26 @@
{\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}
\unexpanded\def\addtocommalist#1#2% {item} \cs
- {\rawdoifinsetelse{#1}#2\resetglobal
+ {\rawdoifelseinset{#1}#2\resetglobal
{\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}}
\unexpanded\def\pretocommalist#1#2% {item} \cs
- {\rawdoifinsetelse{#1}#2\resetglobal
+ {\rawdoifelseinset{#1}#2\resetglobal
{\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}}
-\unexpanded\def\robustdoifinsetelse#1#2%
+\unexpanded\def\robustdoifelseinset#1#2%
{\edef\m_syst_string_one{\detokenize\expandafter{\normalexpanded{#1}}}%
\edef\m_syst_string_two{\detokenize\expandafter{\normalexpanded{#2}}}%
- \rawdoifinsetelse\m_syst_string_one\m_syst_string_two}
+ \rawdoifelseinset\m_syst_string_one\m_syst_string_two}
+
+\let\robustdoifinsetelse\robustdoifelseinset
\unexpanded\def\robustaddtocommalist#1#2% {item} \cs
- {\robustdoifinsetelse{#1}#2\resetglobal
+ {\robustdoifelseinset{#1}#2\resetglobal
{\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}}
\unexpanded\def\robustpretocommalist#1#2% {item} \cs
- {\robustdoifinsetelse{#1}#2\resetglobal
+ {\robustdoifelseinset{#1}#2\resetglobal
{\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}}
\unexpanded\def\xsplitstring#1#2% \cs {str}
@@ -5050,7 +5147,7 @@
\def\acleanedupcommalist#1,,#2\relax{#1}
\unexpanded\def\removefromcommalist#1#2% to be sped up
- {\rawdoifinsetelse{#1}#2%
+ {\rawdoifelseinset{#1}#2%
{\normalexpanded{\xsplitstring\noexpand#2{#1}}%
\dodoglobal\edef#2%
{\ifx\m_syst_string_one\empty
@@ -5288,7 +5385,7 @@
\let\popmacro \localpopmacro
%D \macros
-%D {setlocalhsize}
+%D {setlocalhsize,distributedhsize}
%D
%D Sometimes we need to work with the \type{\hsize} that is
%D corrected for indentation and left and right skips. The
@@ -5307,7 +5404,7 @@
\newdimen\localhsize
\unexpanded\def\setlocalhsize % don't change !
- {\doifnextoptionalelse
+ {\doifelsenextoptional
\syst_helpers_set_local_hsize_yes
\syst_helpers_set_local_hsize_nop}
@@ -5326,6 +5423,12 @@
\fi
\relax}
+\def\distributedhsize#1#2#3%
+ {\dimexpr(#1-\numexpr#3-1\relax\dimexpr#2\relax)/#3\relax}
+
+\def\hsizefraction#1#2%
+ {\dimexpr#1/#2\relax}
+
%D \macros
%D {doifvalue,doifnotvalue,doifelsevalue,
%D doifnothing,doifsomething,doifelsenothing,
@@ -5388,7 +5491,7 @@
\expandafter\secondoftwoarguments
\fi}
-\unexpanded\def\doifsomethingelse#1%
+\unexpanded\def\doifelsesomething#1%
{\edef\m_syst_string_one{#1}%
\ifx\m_syst_string_one\empty
\expandafter\secondoftwoarguments
@@ -5420,18 +5523,25 @@
\expandafter\secondoftwoarguments
\fi}
+\let\doifvalueelse \doifelsevalue
+\let\doifnothingelse \doifelsenothing
+\let\doifsomethingelse \doifelsesomething
+\let\doifvaluenothingelse\doifelsevaluenothing
+
%D \macros
%D {doifemptyelsevalue, doifemptyvalue, doifnotemptyvalue}
%D
%D Also handy:
-\def\doifemptyelsevalue#1%
+\def\doifelseemptyvalue#1%
{\expandafter\ifx\csname#1\endcsname\empty
\expandafter\firstoftwoarguments
\else
\expandafter\secondoftwoarguments
\fi}
+\let\doifemptyvalueelse\doifelseemptyvalue
+
\def\doifemptyvalue#1%
{\expandafter\ifx\csname#1\endcsname\empty
\expandafter\firstofoneargument
@@ -5461,10 +5571,12 @@
\processcommalist[#3]\syst_helpers_do_common_check_all
\ifdone\expandafter#1\else\expandafter#2\fi}
-\unexpanded\def\doifallcommonelse{\syst_helpers_do_if_all_common_else\firstoftwoarguments\secondoftwoarguments}
+\unexpanded\def\doifelseallcommon{\syst_helpers_do_if_all_common_else\firstoftwoarguments\secondoftwoarguments}
\unexpanded\def\doifallcommon {\syst_helpers_do_if_all_common_else\firstofonearguments\gobbleoneargument }
\unexpanded\def\doifnotallcommon {\syst_helpers_do_if_all_common_else\gobbleoneargument \firstofonearguments }
+\let\doifallcommonelse\doifelseallcommon
+
%D \macros
%D {DOIF,DOIFELSE,DOIFNOT}
%D
@@ -5668,13 +5780,15 @@
\def\syst_helpers_if_some_space_else#1 #2#3\_e_o_s_{\if\noexpand#2@}
-\def\doifsomespaceelse#1% % #2#3%
+\def\doifelsesomespace#1% % #2#3%
{\syst_helpers_if_some_space_else#1 @ @\_e_o_s_ % #3\else#2\fi}
\expandafter\secondoftwoarguments
\else
\expandafter\firstoftwoarguments
\fi}
+\let\doifsomespaceelse\doifelsesomespace
+
%D \macros
%D {processseparatedlist}
%D
@@ -5924,11 +6038,11 @@
%D These macros are sort of obsolete as we never use uppercase this
%D way. But nevertheless we provide them:
-\def\utfupper#1{\ctxcommand{upper(\!!bs#1\!!es)}} % expandable
-\def\utflower#1{\ctxcommand{lower(\!!bs#1\!!es)}} % expandable
+\def\utfupper#1{\clf_upper{#1}} % expandable
+\def\utflower#1{\clf_lower{#1}} % expandable
-\unexpanded\def\uppercasestring#1\to#2{\dodoglobal\edef#2{\ctxcommand{upper(\!!bs#1\!!es)}}}
-\unexpanded\def\lowercasestring#1\to#2{\dodoglobal\edef#2{\ctxcommand{lower(\!!bs#1\!!es)}}}
+\unexpanded\def\uppercasestring#1\to#2{\dodoglobal\edef#2{\clf_upper{#1}}}
+\unexpanded\def\lowercasestring#1\to#2{\dodoglobal\edef#2{\clf_lower{#1}}}
%D \macros
%D {handletokens}
@@ -6124,24 +6238,20 @@
% \def\threedigitrounding#1%
% {\expandafter\expandafter\expandafter\dothreedigitrounding\expandafter\WITHOUTPT\the\dimexpr#1\points+.0005\points\relax0000.*00\relax}
-\def\integerrounding #1{\cldcontext{"\letterpercent 0.0f",#1}}
-\def\onedigitrounding #1{\cldcontext{"\letterpercent 0.1f",#1}}
-\def\twodigitrounding #1{\cldcontext{"\letterpercent 0.2f",#1}}
-\def\threedigitrounding#1{\cldcontext{"\letterpercent 0.3f",#1}}
+\def\integerrounding #1{\clf_rounded\zerocount\numexpr#1\relax}
+\def\onedigitrounding #1{\clf_rounded\plusone \numexpr#1\relax}
+\def\twodigitrounding #1{\clf_rounded\plustwo \numexpr#1\relax}
+\def\threedigitrounding#1{\clf_rounded\plusthree\numexpr#1\relax}
%D \macros
%D {processcontent}
%D
-%D This is the first occasion where \TEX\ and \ETEX\ are no
-%D longer compatible, although in many cases things go ok.
-%D Beware of verbatim, i.e. catcode changes.
+%D This macro is first used in the tabulation macros.
%D
%D \starttyping
%D \unexpanded\def\starthans%
%D {\processcontent{stophans}\test{\message{\test}\wait}}
%D \stoptyping
-%D
-%D This macro is first used in the tabulation macros.
\unexpanded\def\processcontent#1%
{\begingroup\expandafter\syst_helpers_process_content\csname#1\endcsname}
@@ -6207,7 +6317,7 @@
%D Not that fast I guess, but here's a way to test for token
%D registers being empty.
-\unexpanded\def\doifsometokselse#1%
+\unexpanded\def\doifelsesometoks#1%
{\edef\m_syst_string_one{\the#1}% one level expansion so quite ok
\ifx\m_syst_string_one\empty
\expandafter\secondoftwoarguments
@@ -6215,6 +6325,8 @@
\expandafter\firstoftwoarguments
\fi}
+\let\doifsometokselse\doifelsesometoks
+
\unexpanded\def\doifsometoks#1%
{\edef\m_syst_string_one{\the#1}% one level expansion so quite ok
\ifx\m_syst_string_one\empty
@@ -6253,9 +6365,11 @@
\unexpanded\def\stopstrictinspectnextcharacter
{\let\syst_helpers_inspect_next_character\syst_helpers_normal_inspect_next_character}
-\def\strictdoifnextoptionalelse#1#2%
+\unexpanded\def\strictdoifelsenextoptional#1#2%
{\startstrictinspectnextcharacter
- \doifnextcharelse[{\stopstrictinspectnextcharacter#1}{\stopstrictinspectnextcharacter#2}}
+ \doifelsenextchar[{\stopstrictinspectnextcharacter#1}{\stopstrictinspectnextcharacter#2}}
+
+\let\strictdoifnextoptionalelse\strictdoifelsenextoptional
%D \macros
%D {gobblespacetokens}
@@ -6448,9 +6562,11 @@
%D
%D This is a dirty one: we simply append a unit and discard it when needed.
-\def\doifdimensionelse#1%
+\def\doifelsedimension#1%
{\afterassignment\syst_helpers_if_dimension_else\scratchdimen#1pt\relax}
+\let\doifdimensionelse\doifelsedimension
+
\def\syst_helpers_if_dimension_else#1%
{\ifx#1\relax
\expandafter\secondoftwoarguments
@@ -6479,7 +6595,9 @@
\installsystemnamespace{dimencheckb}
\installsystemnamespace{dimencheckc}
-\def\doifdimenstringelse#1{\normalexpanded{\noexpand\dodimenteststageone#1}\empty\empty]}
+\def\doifelsedimenstring#1{\normalexpanded{\noexpand\dodimenteststageone#1}\empty\empty]}
+
+\let\doifdimenstringelse\doifelsedimenstring
\def\dodimenteststageone #1#2{\csname \??dimenchecka\ifcsname \??dimenchecka#2\endcsname#2\else x\fi\endcsname#2}
\def\dodimenteststagetwo #1#2{\csname \??dimencheckb\ifcsname \??dimencheckb#2\endcsname#2\else x\fi\endcsname#2}
@@ -6602,10 +6720,12 @@
% sometimes handy:
-\unexpanded\def\doifhasspaceelse#1%
+\unexpanded\def\doifelsehasspace#1%
{\edef\m_syst_string_one{#1}%
\normalexpanded{\syst_helpers_if_has_space_else#1\space}\empty\relax}
+\let\doifhasspaceelse\doifelsehasspace
+
\unexpanded\def\syst_helpers_if_has_space_else#1 #2#3\relax % \space\empty\relax
{\ifx\m_syst_string_one\space
\expandafter\firstoftwoarguments
@@ -6614,7 +6734,7 @@
\else
\doubleexpandafter\firstoftwoarguments
\fi\fi}
-
+
% this will replace loadfile once and alike !!! todo
\installsystemnamespace{flag}
@@ -6633,6 +6753,8 @@
\doubleexpandafter\secondoftwoarguments
\fi\fi}
+\let\doifflaggedelse\doifelseflagged
+
\def\doifnotflagged#1%
{\expandafter\ifx\csname\??flag#1\endcsname\relax
\expandafter\firstofoneargument
@@ -6641,10 +6763,10 @@
\else
\doubleexpandafter\firstofoneargument
\fi\fi}
-
+
\unexpanded\def\inheritparameter[#1]#2[#3]#4[#5]% tag tokey fromkey
{\expandafter\def\csname#1#3\expandafter\endcsname\expandafter{\csname#1#5\endcsname}}
-
+
\def\syst_helpers_if_non_zero_positive_else#1#2\end % #3#4%
{\ifx#1\relax
\ifcase\scratchcounter
@@ -6659,9 +6781,11 @@
\expandafter\secondoftwoarguments
\fi}
-\def\doifnonzeropositiveelse#1%
+\def\doifelsenonzeropositive#1%
{\begingroup\afterassignment\syst_helpers_if_non_zero_positive_else\scratchcounter=0#1\relax\empty\end}
-
+
+\let\doifnonzeropositiveelse\doifelsenonzeropositive
+
% here ?
\unexpanded\def\dosetrawvalue #1#2#3{\expandafter \def\csname#1#2\endcsname{#3}}
@@ -6705,8 +6829,8 @@
% \fi
% \def\elapsedseconds{\expandafter\withoutpt\the\dimexpr\elapsedtime sp\relax}
-\def\resettimer {\ctxcommand{resettimer()}}
-\def\elapsedtime {\ctxcommand{elapsedtime()}}
+\let\resettimer \clf_resettimer
+\let\elapsedtime \clf_elapsedtime
\let\elapsedseconds \elapsedtime
\newcount\c_syst_helpers_test_feature_n
@@ -6820,7 +6944,7 @@
%D \typebuffer \getbuffer
\unexpanded\def\ignoreimplicitspaces
- {\doifnextcharelse\relax\relax\relax}
+ {\doifelsenextchar\relax\relax\relax}
%D \macros
%D {processwords}
@@ -6883,7 +7007,7 @@
\def\syst_helpers_direct_double_empty_one_nop#1{#1[][]}
\def\syst_helpers_direct_double_empty_two_nop#1[#2]{#1[#2][]}
-%D Used in math definitions (in an type {\edef}):
+%D Used in math definitions (in an \type {\edef}):
%D \startbuffer
%D [\docheckedpair{}]
@@ -6997,8 +7121,80 @@
% expandable:
-%def\getsubstring#1#2#3{\cldcontext{utf.sub([[#3]],tonumber("#1"),tonumber("#2"))}}
-\def\getsubstring#1#2#3{\ctxcommand{getsubstring(\!!bs#3\!!es,"#1","#2")}}
+\def\getsubstring#1#2#3{\clf_getsubstring{#3}{#1}{#2}}
+
+%D Other dimensions than pt:
+
+% \def\converteddimen#1#2{\clf_converteddimen\dimexpr#1\relax{#2}}
+
+%D Maybe (looks ugly):
+%D
+%D \starttyping
+%D \doifcase {foo}
+%D {bar} {BAR}
+%D {foo} {FOO}
+%D {default} {DEFAULT}
+%D
+%D \doifcase {foo}
+%D {bar} {BAR}
+%D {foo} {\doifcase {bar}
+%D {bar} {BAR}
+%D {foo} {FOO}
+%D {default} {DEFAULT}
+%D }
+%D {default} {DEFAULT}
+%D \stoptyping
+
+% \doifcase {\btxfoundname{author}}
+% {author} {\btxflush{author}}
+% {editor} {\texdefinition{btx:apa:editor-or-editors}}
+% {title} {\texdefinition{btx:apa:title-subtitle-type}}
+% {default} {\btxflush{author}}
+
+% \unexpanded\def\doifcase#1%
+% {\edef\m_case_asked{#1}%
+% \syst_aux_case}
+%
+% \def\syst_aux_case#1%
+% {\edef\m_case_temp{#1}%
+% \ifx\m_case_temp\m_case_asked
+% \expandafter\syst_aux_case_yes
+% \else\ifx\m_case_temp\s!default
+% \doubleexpandafter\firstofoneargument
+% \else
+% \doubleexpandafter\syst_aux_case_nop
+% \fi\fi}
+%
+% \def\syst_aux_skip#1#2%
+% {\edef\m_case_temp{#1}%
+% \ifx\m_case_temp\s!default
+% \expandafter\syst_aux_done
+% \else
+% \expandafter\syst_aux_skip
+% \fi}
+%
+% \def\syst_aux_case_yes#1%
+% {\def\syst_aux_done{#1}%
+% \syst_aux_skip}
+%
+% \def\syst_aux_case_nop#1%
+% {\syst_aux_case}
+
+%D \macros
+%D {ntimes}
+%D
+%D some repetition:
+%D
+%D \startbuffer
+%D \ntimes{*}{20}
+%D \stopbuffer
+%D
+%D \typebuffer \blank gives: \getbuffer \blank
+%D
+%D This is not real fast but quite okay:
+
+%def\ntimes#1#2{\ifnum#2>\zerocount#1\ntimes{#1}{\numexpr#2-\plusone\relax}\fi} % 1.72
+\def\ntimes#1#2{\clf_ntimes{#1}\numexpr#2\relax} % 0.33
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/syst-con.lua b/Master/texmf-dist/tex/context/base/syst-con.lua
index dfbd490518e..0fa685b2dab 100644
--- a/Master/texmf-dist/tex/context/base/syst-con.lua
+++ b/Master/texmf-dist/tex/context/base/syst-con.lua
@@ -7,16 +7,18 @@ if not modules then modules = { } end modules ['syst-con'] = {
}
local tonumber = tonumber
+local math = math
local utfchar = utf.char
-local gsub, format = string.gsub, string.format
+local gsub = string.gsub
converters = converters or { }
local converters = converters
local context = context
-local comands = commands
+local commands = commands
+local implement = interfaces.implement
-local formatters = string,formatters
+local formatters = string.formatters
--[[ldx--
For raw 8 bit characters, the offset is 0x110000 (bottom of plane 18) at
@@ -28,45 +30,39 @@ function converters.octstringtonumber(n) tonumber(n, 8) end
function converters.rawcharacter (n) utfchar(0x110000+n) end
-converters.lchexnumber = formatters["%x" ]
-converters.uchexnumber = formatters["%X" ]
-converters.lchexnumbers = formatters["%02x"]
-converters.uchexnumbers = formatters["%02X"]
-converters.octnumber = formatters["%03o"]
-
-function commands.hexstringtonumber(n) context(tonumber(n,16)) end
-function commands.octstringtonumber(n) context(tonumber(n, 8)) end
-
-function commands.rawcharacter (n) context(utfchar(0x110000+n)) end
-
-function commands.lchexnumber (n) context("%x" ,n) end
-function commands.uchexnumber (n) context("%X" ,n) end
-function commands.lchexnumbers (n) context("%02x",n) end
-function commands.uchexnumbers (n) context("%02X",n) end
-function commands.octnumber (n) context("%03o",n) end
-
-function commands.format(fmt,...) -- used ?
- fmt = gsub(fmt,"@","%%")
- context(fmt,...)
-end
-
-local cosd, sind, tand = math.cosd, math.sind, math.tand
-local cos, sin, tan = math.cos, math.sin, math.tan
-
--- unfortunately %s spits out: 6.1230317691119e-017
---
--- function commands.sind(n) context(sind(n)) end
--- function commands.cosd(n) context(cosd(n)) end
--- function commands.tand(n) context(tand(n)) end
---
--- function commands.sin (n) context(sin (n)) end
--- function commands.cos (n) context(cos (n)) end
--- function commands.tan (n) context(tan (n)) end
-
-function commands.sind(n) context("%0.6F",sind(n)) end
-function commands.cosd(n) context("%0.6F",cosd(n)) end
-function commands.tand(n) context("%0.6F",tand(n)) end
-
-function commands.sin (n) context("%0.6F",sin (n)) end
-function commands.cos (n) context("%0.6F",cos (n)) end
-function commands.tan (n) context("%0.6F",tan (n)) end
+local lchexnumber = formatters["%x"]
+local uchexnumber = formatters["%X"]
+local lchexnumbers = formatters["%02x"]
+local uchexnumbers = formatters["%02X"]
+local octnumber = formatters["%03o"]
+local nicenumber = formatters["%0.6F"]
+
+converters.lchexnumber = lchexnumber
+converters.uchexnumber = uchexnumber
+converters.lchexnumbers = lchexnumbers
+converters.uchexnumbers = uchexnumbers
+converters.octnumber = octnumber
+converters.nicenumber = nicenumber
+
+implement { name = "hexstringtonumber", actions = { tonumber, context }, arguments = { "integer", 16 } }
+implement { name = "octstringtonumber", actions = { tonumber, context }, arguments = { "integer", 8 } }
+
+implement { name = "rawcharacter", actions = function(n) context(utfchar(0x110000+n)) end, arguments = "integer" }
+
+implement { name = "lchexnumber", actions = { lchexnumber, context }, arguments = "integer" }
+implement { name = "uchexnumber", actions = { uchexnumber, context }, arguments = "integer" }
+implement { name = "lchexnumbers", actions = { lchexnumbers, context }, arguments = "integer" }
+implement { name = "uchexnumbers", actions = { uchexnumbers, context }, arguments = "integer" }
+implement { name = "octnumber", actions = { octnumber, context }, arguments = "integer" }
+
+implement { name = "sin", actions = { math.sin, nicenumber, context }, arguments = "number" }
+implement { name = "cos", actions = { math.cos, nicenumber, context }, arguments = "number" }
+implement { name = "tan", actions = { math.tan, nicenumber, context }, arguments = "number" }
+
+implement { name = "sind", actions = { math.sind, nicenumber, context }, arguments = "number" }
+implement { name = "cosd", actions = { math.cosd, nicenumber, context }, arguments = "number" }
+implement { name = "tand", actions = { math.tand, nicenumber, context }, arguments = "number" }
+
+-- only as commands
+
+function commands.format(fmt,...) context((gsub(fmt,"@","%%")),...) end
diff --git a/Master/texmf-dist/tex/context/base/syst-con.mkiv b/Master/texmf-dist/tex/context/base/syst-con.mkiv
index de8ed597e1a..17c40781977 100644
--- a/Master/texmf-dist/tex/context/base/syst-con.mkiv
+++ b/Master/texmf-dist/tex/context/base/syst-con.mkiv
@@ -46,10 +46,10 @@
%D [\expandafter\uchexnumber\expandafter{\the\zerocount}]
%D \stoptyping
-\def\lchexnumber #1{\ctxcommand{lchexnumber(\number#1)}}
-\def\uchexnumber #1{\ctxcommand{uchexnumber(\number#1)}}
-\def\lchexnumbers#1{\ctxcommand{lchexnumbers(\number#1)}}
-\def\uchexnumbers#1{\ctxcommand{uchexnumbers(\number#1)}}
+\def\lchexnumber #1{\clf_lchexnumber \numexpr#1\relax}
+\def\uchexnumber #1{\clf_uchexnumber \numexpr#1\relax}
+\def\lchexnumbers#1{\clf_lchexnumbers\numexpr#1\relax}
+\def\uchexnumbers#1{\clf_uchexnumbers\numexpr#1\relax}
\let\hexnumber\uchexnumber
@@ -58,7 +58,7 @@
%D
%D For unicode remapping purposes, we need octal numbers.
-\def\octnumber#1{\ctxcommand{octnumber(\number#1)}}
+\def\octnumber#1{\clf_octnumber\numexpr#1\relax}
%D \macros
%D {hexstringtonumber,octstringtonumber}
@@ -67,8 +67,8 @@
%D a decimal number, thereby taking care of lowercase characters
%D as well.
-\def\hexstringtonumber#1{\ctxcommand{hexstringtonumber("#1")}}
-\def\octstringtonumber#1{\ctxcommand{octstringtonumber("#1")}}
+\def\hexstringtonumber#1{\clf_hexstringtonumber\numexpr#1\relax}
+\def\octstringtonumber#1{\clf_octstringtonumber\numexpr#1\relax}
%D \macros
%D {rawcharacter}
@@ -76,7 +76,7 @@
%D This macro can be used to produce proper 8 bit characters
%D that we sometimes need in backends and round||trips.
-\def\rawcharacter#1{\ctxcommand{rawcharacter(\number#1)}}
+\def\rawcharacter#1{\clf_rawcharacter\numexpr#1\relax}
%D \macros
%D {twodigits, threedigits}
@@ -126,23 +126,12 @@
%D \macros
%D {setcalculatedsin,setcalculatedcos,setcalculatedtan}
-%D
-%D This saves some 2K in the format. At some point we will redo the
-%D code that calls this. Beware: in \MKII\ this is a separate module.
-
-% \let\calculatesin\gobbleoneargument
-% \let\calculatecos\gobbleoneargument
-% \let\calculatetan\gobbleoneargument
-
-% \def\setcalculatedsin#1#2{\edef#1{\cldcontext{math.sind(#2)}}} % jit-unsafe
-% \def\setcalculatedcos#1#2{\edef#1{\cldcontext{math.cosd(#2)}}} % jit-unsafe
-% \def\setcalculatedtan#1#2{\edef#1{\cldcontext{math.tand(#2)}}} % jit-unsafe
-\def\setcalculatedsin#1#2{\edef#1{\ctxcommand{sind(#2)}}}
-\def\setcalculatedcos#1#2{\edef#1{\ctxcommand{cosd(#2)}}}
-\def\setcalculatedtan#1#2{\edef#1{\ctxcommand{tand(#2)}}}
+\def\setcalculatedsin#1#2{\edef#1{\clf_sind#2}}
+\def\setcalculatedcos#1#2{\edef#1{\clf_cosd#2}}
+\def\setcalculatedtan#1#2{\edef#1{\clf_tand#2}}
- \def\formatted#1{\ctxcommand{format(#1)}}
-\unexpanded\def\format #1{\ctxcommand{format(#1)}}
+ \def\formatted#1{\ctxcommand{format(#1)}} % not clf
+\unexpanded\def\format #1{\ctxcommand{format(#1)}} % not clf
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/syst-ini.mkiv b/Master/texmf-dist/tex/context/base/syst-ini.mkiv
index a533f8a6a6a..8631aed9075 100644
--- a/Master/texmf-dist/tex/context/base/syst-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/syst-ini.mkiv
@@ -114,11 +114,6 @@
end
}
-%D Handy.
-
-\suppresslongerror = 1
-\suppressoutererror = 1
-
%D \ETEX\ has a not so handy way of telling you the version number, i.e. the revision
%D number has a period in it:
@@ -198,7 +193,7 @@
\countdef \c_syst_last_allocated_language = 41 \c_syst_last_allocated_language = \c_syst_min_allocated_language % not used in context
\countdef \c_syst_last_allocated_insertion = 42 \c_syst_last_allocated_insertion = \c_syst_min_allocated_insert
\countdef \c_syst_last_allocated_family = 43 \c_syst_last_allocated_family = \c_syst_min_allocated_family % not used in context
-\countdef \c_syst_last_allocated_attribute = 44 \c_syst_last_allocated_attribute = \c_syst_min_allocated_attribute
+\countdef \c_syst_last_allocated_attribute = 44 \c_syst_last_allocated_attribute = \c_syst_min_allocated_attribute % not used in context
\countdef \c_syst_min_counter_value = 125 \c_syst_min_counter_value = -"7FFFFFFF % beware, we use index 125 at the lua end
\countdef \c_syst_max_counter_value = 126 \c_syst_max_counter_value = "7FFFFFFF % beware, we use index 126 at the lua end
@@ -328,7 +323,7 @@
\newcount\scratchcounterone \newcount\scratchcountertwo \newcount\scratchcounterthree
\newdimen \scratchdimenone \newdimen \scratchdimentwo \newdimen \scratchdimenthree
\newskip \scratchskipone \newskip \scratchskiptwo \newskip \scratchskipthree
-\newbox \scratchmuskipone \newbox \scratchmuskiptwo \newbox \scratchmuskipthree
+\newmuskip\scratchmuskipone \newmuskip\scratchmuskiptwo \newmuskip\scratchmuskipthree
\newtoks \scratchtoksone \newtoks \scratchtokstwo \newtoks \scratchtoksthree
\newbox \scratchboxone \newbox \scratchboxtwo \newbox \scratchboxthree
@@ -386,6 +381,8 @@
\newmuskip\zeromuskip \zeromuskip = 0mu
\newmuskip\onemuskip \onemuskip = 1mu
+\newmuskip\muquad \muquad = 18mu
+
\let\points \onepoint
\let\halfpoint\halfapoint
@@ -417,6 +414,7 @@
\chardef \plustwentythousand = 20000
\chardef \medcard = 32768
\chardef \maxcard = 65536 % pdftex has less mathchars
+\chardef \maxcardminusone = 65535
%D \macros
%D {doubleexpandafter,tripleexpandafter,expanded,startexpanded}
@@ -631,6 +629,8 @@
%D
%D In \LUATEX\ we have ways around this.
+% no longer \errorstopmode cf. plain tex 3.141592653
+
\normalprotected\def\tracingall
{\tracingonline \plusone
\tracingcommands \plusthree
@@ -647,8 +647,7 @@
\tracingifs \plusone
\tracingscantokens\plusone
\tracingnesting \plusone
- \tracingassigns \plustwo
- \errorstopmode}
+ \tracingassigns \plustwo}
\normalprotected\def\loggingall
{\tracingall
@@ -766,8 +765,8 @@
\normalprotected\def\newfraction#1{\let#1\!!plusone}
-%D It would be handy to have a primitive \unless\ifcase because then we could
-%D use nicer values. Anyhow, this conditional code used to be in the \type
+%D It would be handy to have a primitive \type {\unless\ifcase} because then we
+%D could use nicer values. Anyhow, this conditional code used to be in the \type
%D {syst-aux} module but is now promoted to here.
%D \macros
@@ -1016,12 +1015,18 @@
% \bindprimitive ifabsnum ifpdfabsnum
%D We need to make sure that we start up in \DVI\ mode, so, after testing for running
-%D \PDFTEX, we default to \DVI.
-
-\pdfoutput \zerocount
-\pdfminorversion \plusfive
-\pdfgentounicode \plusone
-\pdfinclusioncopyfonts\plusone
+%D \PDFTEX, we default to \DVI. Why?
+
+\pdfoutput \zerocount
+\pdfminorversion \plusseven
+\pdfgentounicode \plusone
+\pdfinclusioncopyfonts \plusone
+\pdfinclusionerrorlevel \zerocount
+\pdfdecimaldigits \plusten
+\pdfhorigin 1 true in
+\pdfvorigin \pdfhorigin
+\pdfimageresolution 300
+\pdfpkresolution 600
\normalprotected\def\nopdfcompression {\pdfobjcompresslevel\zerocount \pdfcompresslevel\zerocount}
\normalprotected\def\maximumpdfcompression{\pdfobjcompresslevel\plusnine \pdfcompresslevel\plusnine }
@@ -1084,6 +1089,12 @@
\voffset\zeropoint \let\voffset\relax \newdimen\voffset % prevent messing up
\hoffset\zeropoint \let\hoffset\relax \newdimen\hoffset % prevent messing up
+%D Handy.
+
+\suppresslongerror \plusone
+\suppressoutererror \plusone
+\suppressmathparerror \plusone
+
%D While cleaning this code up a bit I was listening to Heather Nova's \CD\ Redbird.
%D The first song on that \CD\ ends with a few lines suitable for ending this
%D initialization module:
@@ -1101,4 +1112,21 @@
%D
%D So let's see what \TEX\ can do now that we've opened up the basic machinery.
+%D Now we define a few helpers that we need in a very early stage. We hav eno message system
+%D yet but redundant definitions are fatal anyway.
+
+\newcount\c_syst_helpers_n_of_namespaces \c_syst_helpers_n_of_namespaces\pluseight % 1-8 reserved for catcodes
+
+\def\v_interfaces_prefix_template_system{\number \c_syst_helpers_n_of_namespaces>>}
+%def\v_interfaces_prefix_template_system{\characters\c_syst_helpers_n_of_namespaces>>} % no \characters yet
+
+\normalprotected\def\installsystemnamespace#1%
+ {\ifcsname ??#1\endcsname
+ \immediate\write16{fatal error: duplicate system namespace '#1'}%
+ \expandafter\normalend
+ \else
+ \global\advance\c_syst_helpers_n_of_namespaces\plusone
+ \expandafter\edef\csname ??#1\endcsname{\v_interfaces_prefix_template_system}%
+ \fi}
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/syst-lua.lua b/Master/texmf-dist/tex/context/base/syst-lua.lua
index cd7dcc062c5..a6665f4104a 100644
--- a/Master/texmf-dist/tex/context/base/syst-lua.lua
+++ b/Master/texmf-dist/tex/context/base/syst-lua.lua
@@ -6,16 +6,28 @@ if not modules then modules = { } end modules ['syst-lua'] = {
license = "see context related readme files"
}
-local format, find, match, rep = string.format, string.find, string.match, string.rep
+local find, match = string.find, string.match
local tonumber = tonumber
-local S, lpegmatch, lpegtsplitat = lpeg.S, lpeg.match, lpeg.tsplitat
+local S, C, P, lpegmatch, lpegtsplitat = lpeg.S, lpeg.C, lpeg.P, lpeg.match, lpeg.tsplitat
-commands = commands or { }
-local commands = commands
-local context = context
+commands = commands or { }
+local commands = commands
-function commands.writestatus(...) logs.status(...) end -- overloaded later
+local implement = interfaces.implement
+
+local two_strings = interfaces.strings[2]
+
+local context = context
+local csprint = context.sprint
+
+local prtcatcodes = tex.prtcatcodes
+
+implement { -- will b eoverloaded later
+ name = "writestatus",
+ arguments = two_strings,
+ actions = logs.status,
+}
local ctx_firstoftwoarguments = context.firstoftwoarguments -- context.constructcsonly("firstoftwoarguments" )
local ctx_secondoftwoarguments = context.secondoftwoarguments -- context.constructcsonly("secondoftwoarguments")
@@ -30,24 +42,60 @@ local ctx_gobbleoneargument = context.gobbleoneargument -- context.constru
function commands.doifelse(b)
if b then
ctx_firstoftwoarguments()
+-- csprint(prtcatcodes,[[\ui_ft]]) -- ctx_firstoftwoarguments
+ else
+ ctx_secondoftwoarguments()
+-- csprint(prtcatcodes,[[\ui_st]]) -- ctx_secondoftwoarguments
+ end
+end
+
+function commands.doifelsesomething(b)
+ if b and b ~= "" then
+ ctx_firstoftwoarguments()
+-- csprint(prtcatcodes,[[\ui_ft]]) -- ctx_firstoftwoarguments
else
ctx_secondoftwoarguments()
+-- csprint(prtcatcodes,[[\ui_st]]) -- ctx_secondoftwoarguments
end
end
function commands.doif(b)
if b then
ctx_firstofoneargument()
+-- context.__flushdirect(prtcatcodes,[[\ui_fo]]) -- ctx_firstofonearguments
+ else
+ ctx_gobbleoneargument()
+-- context.__flushdirect(prtcatcodes,[[\ui_go]]) -- ctx_gobbleonearguments
+ end
+end
+
+function commands.doifsomething(b)
+ if b and b ~= "" then
+ ctx_firstofoneargument()
+-- context.__flushdirect(prtcatcodes,[[\ui_fo]]) -- ctx_firstofonearguments
else
ctx_gobbleoneargument()
+-- context.__flushdirect(prtcatcodes,[[\ui_go]]) -- ctx_gobbleonearguments
end
end
function commands.doifnot(b)
if b then
ctx_gobbleoneargument()
+-- csprint(prtcatcodes,[[\ui_go]]) -- ctx_gobbleonearguments
+ else
+ ctx_firstofoneargument()
+-- csprint(prtcatcodes,[[\ui_fo]]) -- ctx_firstofonearguments
+ end
+end
+
+function commands.doifnotthing(b)
+ if b and b ~= "" then
+ ctx_gobbleoneargument()
+-- csprint(prtcatcodes,[[\ui_go]]) -- ctx_gobbleonearguments
else
ctx_firstofoneargument()
+-- csprint(prtcatcodes,[[\ui_fo]]) -- ctx_firstofonearguments
end
end
@@ -68,7 +116,7 @@ end
local s = lpegtsplitat(",")
local h = { }
-function commands.doifcommonelse(a,b) -- often the same test
+local function doifelsecommon(a,b) -- often the same test
local ha = h[a]
local hb = h[b]
if not ha then
@@ -92,7 +140,7 @@ function commands.doifcommonelse(a,b) -- often the same test
ctx_secondoftwoarguments()
end
-function commands.doifinsetelse(a,b)
+local function doifelseinset(a,b)
local hb = h[b]
if not hb then hb = lpegmatch(s,b) h[b] = hb end
for i=1,#hb do
@@ -104,9 +152,21 @@ function commands.doifinsetelse(a,b)
ctx_secondoftwoarguments()
end
+implement {
+ name = "doifelsecommon",
+ arguments = two_strings,
+ actions = doifelsecommon
+}
+
+implement {
+ name = "doifelseinset",
+ arguments = two_strings,
+ actions = doifelseinset
+}
+
local pattern = lpeg.patterns.validdimen
-function commands.doifdimenstringelse(str)
+function commands.doifelsedimenstring(str)
if lpegmatch(pattern,str) then
ctx_firstoftwoarguments()
else
@@ -114,11 +174,70 @@ function commands.doifdimenstringelse(str)
end
end
-function commands.firstinset(str)
- local first = match(str,"^([^,]+),")
- context(first or str)
-end
+local p_first = C((1-P(",")-P(-1))^0)
-function commands.ntimes(str,n)
- context(rep(str,n or 1))
-end
+implement {
+ name = "firstinset",
+ arguments = "string",
+ actions = function(str) context(lpegmatch(p_first,str or "")) end
+}
+
+implement {
+ name = "ntimes",
+ arguments = { "string", "integer" },
+ actions = { string.rep, context }
+}
+
+implement {
+ name = "execute",
+ arguments = "string",
+ actions = os.execute -- wrapped in sandbox
+}
+
+-- function commands.write(n,str)
+-- if n == 18 then
+-- os.execute(str)
+-- elseif n == 16 then
+-- -- immediate
+-- logs.report(str)
+-- else
+-- -- at the tex end we can still drop the write / also delayed vs immediate
+-- context.writeviatex(n,str)
+-- end
+-- end
+
+implement {
+ name = "doifelsesame",
+ arguments = two_strings,
+ actions = function(a,b)
+ if a == b then
+ ctx_firstoftwoarguments()
+ else
+ ctx_secondoftwoarguments()
+ end
+ end
+}
+
+implement {
+ name = "doifsame",
+ arguments = two_strings,
+ actions = function(a,b)
+ if a == b then
+ ctx_firstofoneargument()
+ else
+ ctx_gobbleoneargument()
+ end
+ end
+}
+
+implement {
+ name = "doifnotsame",
+ arguments = two_strings,
+ actions = function(a,b)
+ if a == b then
+ ctx_gobbleoneargument()
+ else
+ ctx_firstofoneargument()
+ end
+ end
+}
diff --git a/Master/texmf-dist/tex/context/base/syst-lua.mkiv b/Master/texmf-dist/tex/context/base/syst-lua.mkiv
index 88a8c246e26..5e82a9ea9e7 100644
--- a/Master/texmf-dist/tex/context/base/syst-lua.mkiv
+++ b/Master/texmf-dist/tex/context/base/syst-lua.mkiv
@@ -15,15 +15,18 @@
\unprotect
-\def\expdoifelse#1#2{\ctxcommand{doifelse(\!!bs#1\!!es==\!!bs#2\!!es)}}
-\def\expdoif #1#2{\ctxcommand{doif (\!!bs#1\!!es==\!!bs#2\!!es)}}
-\def\expdoifnot #1#2{\ctxcommand{doifnot (\!!bs#1\!!es==\!!bs#2\!!es)}}
+\def\expdoifelse#1#2{\clf_doifelsesame{#1}{#2}}
+\def\expdoif #1#2{\clf_doifsame {#1}{#2}}
+\def\expdoifnot #1#2{\clf_doifnotsame {#1}{#2}}
% \testfeatureonce{100000}{\doifelse{hello world}{here i am}{}} % 0.3
% \testfeatureonce{100000}{\expandabledoifelse{hello world}{here i am}{}} % 1.5
-\def\expdoifcommonelse#1#2{\ctxcommand{doifcommonelse("#1","#2")}}
-\def\expdoifinsetelse #1#2{\ctxcommand{doifinsetelse("#1","#2")}}
+\def\expdoifelsecommon#1#2{\clf_doifelsecommon{#1}{#2}}
+\def\expdoifelseinset #1#2{\clf_doifelseinset {#1}{#2}}
+
+\def\expdoifcommonelse\expdoifelsecommon
+\def\expdoifinsetelse \expdoifelseinset
% we define these here, just in case ...
@@ -32,7 +35,7 @@
\edef\!!bs{[\luastringsep[}
\edef\!!es{]\luastringsep]}
-\unexpanded\def\writestatus#1#2{\ctxcommand{writestatus(\!!bs#1\!!es,\!!bs#2\!!es)}}
+\unexpanded\def\writestatus#1#2{\clf_writestatus{#1}{#2}}
% A handy helper:
@@ -41,7 +44,7 @@
% We can omit the tex.ctxcatcodes here as nowadays we seldom
% change the regime at the \TEX\ end:
-\def\luaexpr#1{\directlua{tex.print(tostring(#1))}}
+\def\luaexpr#1{\ctxlua{tex.print(tostring(#1))}} % no use is shortcutting has to be compiled
% helpers:
@@ -50,4 +53,49 @@
\def\ui_ft#1#2{#1}
\def\ui_st#1#2{#2}
+%D Let's bring this under \LUA\ (and therefore \MKIV\ sandbox) control:
+
+% \setnewconstant\c_syst_write 18
+%
+% \unexpanded\def\write#1#% so we can handle \immediate
+% {\ifnum#1=\c_syst_write
+% \expandafter\syst_execute
+% \else
+% \normalwrite#1%
+% \fi}
+%
+% \unexpanded\def\syst_execute#1%
+% {\ctxlua{os.execute(\!!bs#1\!!es)}}
+
+%D But as we only use write 16 we could as well do all in \LUA\
+%D and ignore the rest. Okay, we still can do writes here but only
+%D when not blocked.
+
+% Nicer would be if we could just disable write 18 and keep os.execute
+% which in fact we can do by defining write18 as macro instead of
+% primitive ... todo.
+
+% \unexpanded\def\write#1#%
+% {\syst_write{#1}}
+%
+% \def\syst_write#1#2%
+% {\ctxcommand{write(\number#1,\!!bs\normalunexpanded{#2}\!!es)}}
+%
+% \unexpanded\def\writeviatex#1#2%
+% {\ifx\normalwrite\relax\else
+% \normalwrite#1{#2}%
+% \fi}
+
+% we have no way yet to pickup \immediate unless we redefine it
+% we assume immediate execution
+
+\let\syst_write_execute\clf_execute % always {...}
+
+\unexpanded\def\write#1#%
+ {\ifnum#1=18
+ \expandafter\syst_write_execute
+ \else
+ \normalwrite#1%
+ \fi}
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/syst-rtp.mkiv b/Master/texmf-dist/tex/context/base/syst-rtp.mkiv
index f65e599eca5..82c0778b43f 100644
--- a/Master/texmf-dist/tex/context/base/syst-rtp.mkiv
+++ b/Master/texmf-dist/tex/context/base/syst-rtp.mkiv
@@ -13,6 +13,6 @@
\unprotect
-\def\executesystemcommand#1{\ctxlua{os.execute([[#1]])}}
+\let\executesystemcommand\clf_execute
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/tabl-ltb.mkiv b/Master/texmf-dist/tex/context/base/tabl-ltb.mkiv
index f7fbc0390df..4c892138e82 100644
--- a/Master/texmf-dist/tex/context/base/tabl-ltb.mkiv
+++ b/Master/texmf-dist/tex/context/base/tabl-ltb.mkiv
@@ -138,6 +138,8 @@
\expandafter\secondoftwoarguments
\fi}
+\let\doiflinetablecparameterelse\doifelselinetablecparameter
+
\def\linetablecparameter#1%
{\csname
\ifcsname\??lec\number\linetablecolumn#1\endcsname
@@ -614,7 +616,7 @@
{\global\linetablepage\zerocount
\ifcase\linetablerepeat \else \ifcase\linetablepage
\doif{\linetableparameter\c!repeat}\v!no
- {\global\linetablepage\doifoddpageelse\plusone\plustwo}%
+ {\global\linetablepage\doifelseoddpage\plusone\plustwo}%
\fi \fi}
\def\flushlinetablehead
diff --git a/Master/texmf-dist/tex/context/base/tabl-ntb.mkii b/Master/texmf-dist/tex/context/base/tabl-ntb.mkii
index 465ed44b21f..fbf43eb1edc 100644
--- a/Master/texmf-dist/tex/context/base/tabl-ntb.mkii
+++ b/Master/texmf-dist/tex/context/base/tabl-ntb.mkii
@@ -423,7 +423,9 @@
\ifcsname\@@tblprefix\c!x\positivecol\c!y\positiverow\endcsname\csname\@@tblprefix\c!x\positivecol\c!y\positiverow\endcsname\fi
\ifcsname\@@tblprefix\c!x\negativecol\c!y\negativerow\endcsname\csname\@@tblprefix\c!x\negativecol\c!y\negativerow\endcsname\fi
% done
- \global\letcscsname\@@tblsplitafter\csname\@@tbl\@@tbl\c!after\endcsname
+ \global\letcscsname\@@tblsplitafter \csname\@@tbl\@@tbl\c!after \endcsname
+ \global\letcscsname\@@tblsplitbefore \csname\@@tbl\@@tbl\c!before \endcsname
+ \global\letcscsname\@@tblsplitsamepage\csname\@@tbl\@@tbl\c!samepage\endcsname
\relax}
% we cannot use +n (checking on number/last/first would slow down too much)
@@ -439,7 +441,9 @@
% \dorecurse{10}{\bTR \dorecurse{6}{\bTD xxx \eTD} \eTR}
% \eTABLE
-\globallet\@@tblsplitafter\relax
+\globallet\@@tblsplitafter \relax
+\globallet\@@tblsplitbefore \relax
+\globallet\@@tblsplitsamepage\relax
% split + page:
%
@@ -851,7 +855,17 @@
{\noalign
{\global\advance\tblrow\plusone
\global\tblcol\zerocount
- \global\tblspn\zerocount}%
+ \global\tblspn\zerocount
+ \bgroup % protect local vars
+ \@@tblsplitbefore
+ \egroup
+ \ifx\@@tblsplitsamepage\v!before
+ \unpenalty
+ \nobreak
+ \else\ifx\@@tblsplitsamepage\v!both
+ \unpenalty
+ \nobreak
+ \fi\fi}%
\nexttblcol
\kern\dimexpr\tbltblleftmargindistance-\tbltblcolumndistance\relax}
@@ -862,7 +876,14 @@
{\nointerlineskip
\ifnum\tblrow>\noftblheadlines
\ifnum\gettblnob\tblrow=\zerocount
- \allowbreak
+ \unpenalty
+ \ifx\@@tblsplitsamepage\v!after
+ \nobreak
+ \else\ifx\@@tblsplitsamepage\v!both
+ \nobreak
+ \else
+ \allowbreak
+ \fi\fi
\fi
\else
\allowbreak % else no proper head split off
diff --git a/Master/texmf-dist/tex/context/base/tabl-ntb.mkiv b/Master/texmf-dist/tex/context/base/tabl-ntb.mkiv
index a7a7ae50bc7..2b6f3a3ecf6 100644
--- a/Master/texmf-dist/tex/context/base/tabl-ntb.mkiv
+++ b/Master/texmf-dist/tex/context/base/tabl-ntb.mkiv
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D This module as a more modern variant in xtables but as we follow a bit
+%D This module has a more modern variant in xtables but as we follow a bit
%D different approach with settings there, this mechanism will stay. In fact
%D each of them has its advantages. This module could be sped up a bit and made
%D more efficient by delegating some housekeeping to \LUA\ but it's not worth
@@ -19,8 +19,14 @@
%D real purpose in it. If needed I can squeeze out a few more percentages
%D runtime.
+% columndistance 'optimized' ... needs checking
+%
+% we don't need the alignment mechanism .. we can just pack the row in a box
+
\writestatus{loading}{ConTeXt Table Macros / Natural Tables}
+% sometimes this helps (with nc going wild): \setupTABLE[maxwidth=100cm]
+%
% bug: width 3cm is not honored and column becomes too wide
% as given width is added to distributed width
%
@@ -98,7 +104,7 @@
\to \t_tabl_ntb_cell_start
\unexpanded\def\tabl_ntb_cell_start
- {\inhibitblank
+ {% \inhibitblank
\dotagTABLEcell
%\tabl_ntb_next_level
\usenaturaltablelocalstyleandcolor\c!style\c!color
@@ -145,6 +151,9 @@
\newcount\c_tabl_ntb_maximum_row_span
\newcount\c_tabl_ntb_maximum_col_span
+\newcount\c_tabl_ntb_encountered_col
+\newcount\c_tabl_ntb_encountered_max
+
\newtoks\t_tabl_ntb
\newtoks\t_tabl_ntb_row
@@ -162,6 +171,11 @@
\newdimen\d_tabl_ntb_height
\newdimen\d_tabl_ntb_width
+\newdimen\d_tabl_ntb_leftmargindistance
+\newdimen\d_tabl_ntb_rightmargindistance
+\newdimen\d_tabl_ntb_columndistance
+\newdimen\d_tabl_ntb_maxwidth
+
\newtoks\everyTABLEpass % public
\newcount\tablecellrows % public (needs checking)
@@ -208,6 +222,8 @@
\installdirectcommandhandler \??naturaltable {naturaltable} % \??naturaltable
\installsimpleframedcommandhandler \??naturaltablelocal {naturaltablelocal} \??naturaltablelocal
+\installcorenamespace{naturaltabletal}
+\installcorenamespace{naturaltablegal}
\installcorenamespace{naturaltablenob}
\installcorenamespace{naturaltabletag}
\installcorenamespace{naturaltablecol}
@@ -219,11 +235,26 @@
\installcorenamespace{naturaltablehei}
\installcorenamespace{naturaltabledis}
\installcorenamespace{naturaltableaut}
+\installcorenamespace{naturaltablefwd} % forcedwidth
\installcorenamespace{naturaltabletxt}
\installcorenamespace{naturaltablespn}
\installcorenamespace{naturaltableref}
\installcorenamespace{naturaltableset}
\installcorenamespace{naturaltablecell}
+\installcorenamespace{naturaltablesqueeze}
+\installcorenamespace{naturaltabletok}
+
+\letvalue{\??naturaltablesqueeze }\donefalse
+\letvalue{\??naturaltablesqueeze\v!fit }\donetrue
+\letvalue{\??naturaltablesqueeze\v!fixed}\donetrue
+\letvalue{\??naturaltablesqueeze\v!broad}\donetrue
+\letvalue{\??naturaltablesqueeze\v!local}\donetrue
+
+\def\tabl_ntb_let_gal{\global\expandafter\let\csname\??naturaltablegal\m_tabl_tbl_level\endcsname}
+\def\tabl_ntb_get_gal{\csname\??naturaltablegal\m_tabl_tbl_level\endcsname}
+
+\def\tabl_ntb_let_tal#1{\global\expandafter\let\csname\??naturaltabletal\m_tabl_tbl_level:\number#1\endcsname}
+\def\tabl_ntb_get_tal#1{\csname\??naturaltabletal\m_tabl_tbl_level:\number#1\endcsname}
\def\tabl_ntb_set_nob#1{\expandafter\let\csname\??naturaltablenob\m_tabl_tbl_level:\number#1\endcsname\plusone}
\def\tabl_ntb_get_nob#1{\ifcsname\??naturaltablenob\m_tabl_tbl_level:\number#1\endcsname\plusone\else\zerocount\fi}
@@ -281,15 +312,22 @@
% \def\tabl_ntb_row_state#1#2{\ifcsname\??naturaltablerow\m_tabl_tbl_level:\number#1:\number#2\endcsname\zerocount\else\plusone\fi}
% \def\tabl_ntb_col_state#1#2{\ifcsname\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2\endcsname\zerocount\else\plusone\fi}
-\def\tabl_ntb_set_spn #1{\expandafter\let\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname \!!plusone}
-\def\tabl_ntb_spn_doifelse#1{\doifelse {\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname}\!!plusone}
+%def\tabl_ntb_set_spn #1{\expandafter\let\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname \!!plusone}
+%def\tabl_ntb_spn_doifelse#1{\doifelse {\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname}\!!plusone}
+
+%def\tabl_ntb_set_spn #1{\setvalue {\??naturaltablespn\m_tabl_tbl_level:\number#1}{1}}
+%def\tabl_ntb_spn_doifelse#1{\doifelsevalue{\??naturaltablespn\m_tabl_tbl_level:\number#1}{1}}
-\def\tabl_ntb_set_spn #1{\setvalue {\??naturaltablespn\m_tabl_tbl_level:\number#1}{1}}
-\def\tabl_ntb_spn_doifelse#1{\doifelsevalue{\??naturaltablespn\m_tabl_tbl_level:\number#1}{1}}
+\def\tabl_ntb_let_ref #1#2{\expandafter\glet\csname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+\def\tabl_ntb_set_ref #1#2{\expandafter\xdef\csname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+\def\tabl_ntb_get_ref #1#2{\ifcsname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname\csname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname\fi}
-\def\tabl_ntb_let_ref#1#2{\expandafter\glet\csname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname}
-\def\tabl_ntb_set_ref#1#2{\expandafter\xdef\csname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname}
-\def\tabl_ntb_get_ref#1#2{\ifcsname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname\csname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname\fi}
+\def\tabl_ntb_set_spn #1{\expandafter\let\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname \!!plusone}
+\def\tabl_ntb_spn_doifelse#1{\ifcase0\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname\relax % could be inlined
+ \expandafter\secondoftwoarguments % unset
+ \else
+ \expandafter\firstoftwoarguments % a span
+ \fi}
% keep for a while:
%
@@ -317,6 +355,7 @@
\newif\ifenableTBLbreak \enableTBLbreakfalse
\newif\ifmultipleTBLheads \multipleTBLheadsfalse
\newif\iftightTBLrowspan \tightTBLrowspantrue
+\newif\iftightTBLcolspan \tightTBLcolspanfalse
\newif\iftraceTABLE \traceTABLEfalse
@@ -549,7 +588,6 @@
% local
\ifcsname\m_tabl_ntb_prefix\c!y++\m_tabl_ntb_positive_row\endcsname\csname\m_tabl_ntb_prefix\c!y++\m_tabl_ntb_positive_row\endcsname\fi
% done
- \xdef\m_tabl_ntb_after_split{\naturaltablelocalparameter\c!after}% to be checked
\relax}
% we cannot use +n (checking on number/last/first would slow down too much)
@@ -565,7 +603,9 @@
% \dorecurse{10}{\bTR \dorecurse{6}{\bTD xxx \eTD} \eTR}
% \eTABLE
-\let\m_tabl_ntb_after_split\relax
+\let\m_tabl_ntb_before_split\empty
+\let\m_tabl_ntb_after_split \empty
+\let\m_tabl_ntb_same_page \empty
% split + page:
%
@@ -577,6 +617,7 @@
\unexpanded\def\tabl_ntb_tr
{\c_tabl_ntb_running_col\zerocount
+ \c_tabl_ntb_encountered_col\zerocount
\advance\c_tabl_ntb_maximum_row\plusone
\iffirstargument
\expandafter\tabl_ntb_tr_yes
@@ -591,7 +632,8 @@
\def\m_tabl_ntb_default_nc{\naturaltableparameter\c!nc}
\unexpanded\def\tabl_ntb_td
- {\iffirstargument
+ {\advance\c_tabl_ntb_encountered_col\plusone
+ \iffirstargument
\expandafter\tabl_ntb_td_yes
\else
\expandafter\tabl_ntb_td_nop
@@ -651,7 +693,10 @@
% save text
\normalexpanded
{\tabl_ntb_set_txt_process\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_maximum_row}{\the\c_tabl_ntb_running_col}}%
- {#1}{#2}}
+ {#1}{#2}%
+ \ifnum\c_tabl_ntb_encountered_col>\c_tabl_ntb_encountered_max
+ \c_tabl_ntb_encountered_max\c_tabl_ntb_encountered_col
+ \fi}
\def\tabl_ntb_td_nop[#1]#2\eTD
{\global\advance\c_tabl_ntb_spn\plusone\relax
@@ -671,7 +716,10 @@
\tabl_ntb_let_ref\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col\empty
\normalexpanded
{\tabl_ntb_set_txt_process\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_maximum_row}{\the\c_tabl_ntb_running_col}}%
- {#1}{#2}}
+ {#1}{#2}%
+ \ifnum\c_tabl_ntb_encountered_col>\c_tabl_ntb_encountered_max
+ \c_tabl_ntb_encountered_max\c_tabl_ntb_encountered_col
+ \fi}
\def\tabl_ntb_td_pass_n#1%
{\scratchcounter\numexpr\m_tabl_ntb_n-\c_tabl_ntb_running_col+\minusone-\c_tabl_ntb_spn\relax
@@ -850,10 +898,20 @@
\ifhmode\kern\zeropoint\fi % blocks \removeunwantedspaces: check this on icare handelingsschema
\resetcharacteralign % new
\setupcurrentnaturaltablelocal[\c!align={\v!right,\v!broad,\v!high},#1]%
+ %
+ \d_tabl_ntb_leftmargindistance \naturaltablelocalparameter\c!leftmargindistance\relax
+ \d_tabl_ntb_rightmargindistance\naturaltablelocalparameter\c!rightmargindistance\relax
+ \d_tabl_ntb_columndistance \naturaltablelocalparameter\c!columndistance\relax
+ \d_tabl_ntb_maxwidth \naturaltablelocalparameter\c!maxwidth\relax
+ %
\usesetupsparameter\naturaltablelocalparameter
\doifelse{\naturaltablelocalparameter\c!textwidth}\v!local
{\hsize\availablehsize}
{\hsize\naturaltablelocalparameter\c!textwidth}%
+ \enableTBLbreakfalse
+ \multipleTBLheadsfalse
+ \autoTBLspreadfalse
+ \tightTBLcolspanfalse
\processaction
[\naturaltablelocalparameter\c!split]
[ \v!yes=>\enableTBLbreaktrue,
@@ -865,7 +923,8 @@
\tabl_ntb_preset_parameters
\processallactionsinset
[\naturaltablelocalparameter\c!option]
- [\v!stretch=>\autoTBLspreadtrue]%
+ [\v!stretch=>\autoTBLspreadtrue,%
+ \v!tight=>\tightTBLcolspantrue]%
\linewidth\naturaltablelocalparameter\c!rulethickness % needs to be frozen
\dontcomplain
\c_tabl_ntb_running_col \zerocount
@@ -905,10 +964,10 @@
\unexpanded\def\eTABLE % beware, we need to get rid of spurious spaces when in hmode
{% tricky and dirty order -)
- \doifsometokselse\t_tabl_ntb_head % slow, better a flag
+ \doifelsesometoks\t_tabl_ntb_head % slow, better a flag
{\the\t_tabl_ntb_head
\c_tabl_ntb_n_of_head_lines\c_tabl_ntb_maximum_row\relax
- \doifsometokselse\t_tabl_ntb_next
+ \doifelsesometoks\t_tabl_ntb_next
{\the\t_tabl_ntb_next
\c_tabl_ntb_n_of_next_lines\numexpr\c_tabl_ntb_maximum_row-\c_tabl_ntb_n_of_head_lines\relax}%
{\c_tabl_ntb_n_of_next_lines\zerocount}% was 1
@@ -1013,7 +1072,7 @@
\ifautoTBLemptycell
\normalexpanded
{\tabl_ntb_set_txt_process\c_tabl_ntb_current_row\c_tabl_ntb_current_col{\the\c_tabl_ntb_current_row}{\the\c_tabl_ntb_current_col}}%
- {}{\strut}%
+ {\c!option=\v!tight}{\strut\kern\scaledpoint}% the kern forces the tight
\fi}
\def\tabl_ntb_loop_two
@@ -1045,79 +1104,179 @@
\newcount\c_tabl_prelocated_rows % \prelocateTBLrows{1000} may speed up large tables
-\def\tabl_ntb_row_start{\t_tabl_ntb_row\emptytoks}
-\def\tabl_ntb_row_stop {\normalexpanded{\t_tabl_ntb{\the\t_tabl_ntb\noexpand\tabl_ntb_row_align_start\the\t_tabl_ntb_row\tabl_ntb_row_align_stop}}}
+% \def\tabl_ntb_row_start{\t_tabl_ntb_row\emptytoks}
+% \def\tabl_ntb_row_stop {\normalexpanded{\t_tabl_ntb{\the\t_tabl_ntb\noexpand\tabl_ntb_row_align_start\the\t_tabl_ntb_row\tabl_ntb_row_align_stop}}}
+
+\def\tabl_ntb_row_start
+ {\t_tabl_ntb_row\emptytoks}
+
+\def\tabl_ntb_row_stop
+ {\ifenableTBLbreak
+ \tabl_ntb_row_stop_split
+ \else
+ \tabl_ntb_row_stop_boxed
+ \fi}
+
+\def\tabl_ntb_row_stop_boxed
+ {% \noindent % no, else double leftskip in narrower
+ \normalexpanded
+ {\t_tabl_ntb
+ {\the\t_tabl_ntb
+ % no need for init
+ \tabl_ntb_row_align_start
+ \the\t_tabl_ntb_row
+ \tabl_ntb_row_align_stop}}}
+
+\def\tabl_ntb_row_stop_split
+ {\ifcsname\??naturaltableset\m_tabl_tbl_level:\c!y++\the\c_tabl_ntb_current_row\endcsname
+ \tabl_ntb_row_stop_split_yes
+ \else
+ \tabl_ntb_row_stop_split_nop
+ \fi}
+
+\def\tabl_ntb_row_stop_split_nop
+ {\normalexpanded
+ {\t_tabl_ntb
+ {\the\t_tabl_ntb
+ \tabl_ntb_row_align_reset
+ \tabl_ntb_row_align_start
+ \the\t_tabl_ntb_row
+ \tabl_ntb_row_align_stop}}}
+
+\def\tabl_ntb_row_stop_split_yes
+ {\begingroup
+ \csname\??naturaltableset\m_tabl_tbl_level:\c!y++\the\c_tabl_ntb_current_row\endcsname
+ \xdef\m_tabl_ntb_before_split{\naturaltablelocalparameter\c!before}% to be checked
+ \xdef\m_tabl_ntb_after_split {\naturaltablelocalparameter\c!after}% to be checked
+ \xdef\m_tabl_ntb_same_page {\naturaltablelocalparameter\c!samepage}%
+ \endgroup
+ \normalexpanded
+ {\t_tabl_ntb
+ {\the\t_tabl_ntb
+ \tabl_ntb_row_align_set{\m_tabl_ntb_before_split}{\m_tabl_ntb_after_split}{\m_tabl_ntb_same_page}%
+ \tabl_ntb_row_align_start
+ \the\t_tabl_ntb_row
+ \tabl_ntb_row_align_stop}}}
+
+\unexpanded\def\tabl_ntb_row_align_set#1#2#3%
+ {\xdef\m_tabl_ntb_before_split{#1}%
+ \xdef\m_tabl_ntb_after_split {#2}%
+ \xdef\m_tabl_ntb_same_page {#3}}
+
+\unexpanded\def\tabl_ntb_row_align_reset
+ {\global\let\m_tabl_ntb_before_split\empty
+ \global\let\m_tabl_ntb_after_split \empty
+ \global\let\m_tabl_ntb_same_page \empty}
\def\tabl_ntb_prelocate_error
{\writestatus\m!system{fatal error: use \string\prelocateTBLrows\space to increase table memory (now: \the\c_tabl_prelocated_rows)}}
% \prelocateTBLrows{1000} % may speed up large tables
-\installcorenamespace{naturaltabletok}
-
\def\prelocateTBLrows#1% we start at zero so we have one to much, better play safe anyway
- {\dostepwiserecurse\c_tabl_prelocated_rows{#1}\plusone{\expandafter\newtoks\csname\??naturaltabletok\recurselevel\endcsname}%
+ {\dostepwiserecurse\c_tabl_prelocated_rows{#1}\plusone
+ {\expandafter\newtoks\csname\??naturaltabletok\recurselevel\endcsname}%
\def\tabl_ntb_row_start
{\ifnum\c_tabl_ntb_row<\c_tabl_prelocated_rows\relax
- \expandafter\let\expandafter\t_tabl_ntb_row\csname\??naturaltabletok\the\c_tabl_ntb_row\endcsname\t_tabl_ntb_row\emptytoks
+ \tabl_ntb_prelocate_okay
\else
\tabl_ntb_prelocate_error
\fi}%
\def\tabl_ntb_row_stop
- {\normalexpanded{\t_tabl_ntb{\the\t_tabl_ntb\noexpand\tabl_ntb_row_align_start\the\csname\??naturaltabletok\the\c_tabl_ntb_row\endcsname\tabl_ntb_row_align_stop}}}%
+ {\normalexpanded
+ {\t_tabl_ntb
+ {\the\t_tabl_ntb
+ \tabl_ntb_row_align_start
+ \the\csname\??naturaltabletok\the\c_tabl_ntb_row\endcsname
+ \tabl_ntb_row_align_stop}}}%
\global\c_tabl_prelocated_rows#1\relax}
+\def\tabl_ntb_prelocate_okay
+ {\expandafter\let\expandafter\t_tabl_ntb_row\csname\??naturaltabletok\the\c_tabl_ntb_row\endcsname\t_tabl_ntb_row\emptytoks}
+
% We use aligments to handle the empty (skipped) columns, so
% that we don't have to (re|)|calculate these.
-\def\tabl_ntb_column_skip
- {\global\advance\c_tabl_ntb_col\plusone}
-
-\def\tabl_ntb_column_next
- {\global\advance\c_tabl_ntb_col\plusone
- \kern\naturaltablelocalparameter\c!columndistance
- \aligntab}
-
-\def\tabl_ntb_column_span
- {\span}
-
\let\m_tabl_ntb_saved_row\!!zerocount
\let\m_tabl_ntb_saved_col\!!zerocount
-\def\tabl_ntb_row_align_start
- {\noalign{\tabl_ntb_row_align_reset}%
- \tabl_ntb_column_next
- \kern\dimexpr\naturaltablelocalparameter\c!leftmargindistance-\naturaltablelocalparameter\c!columndistance\relax}
-
-\unexpanded\def\tabl_ntb_row_align_reset
+\unexpanded\def\tabl_ntb_row_align_start
{\global\advance\c_tabl_ntb_row\plusone
- \global\c_tabl_ntb_col\zerocount
- \global\c_tabl_ntb_spn\zerocount}
+ \global\c_tabl_ntb_col\plusone
+ \global\c_tabl_ntb_spn\zerocount
+ \tabl_ntb_row_align_start_inject
+ \dostarttagged\t!tablerow\empty
+ \hbox\bgroup
+ \kern\dimexpr\d_tabl_ntb_leftmargindistance\relax}
\unexpanded\def\tabl_ntb_row_align_stop
- {\kern\dimexpr\naturaltablelocalparameter\c!rightmargindistance-\naturaltablelocalparameter\c!columndistance\relax
- \crcr
- \noalign
- {\nointerlineskip
- \ifnum\c_tabl_ntb_row>\c_tabl_ntb_n_of_head_lines
- \ifnum\tabl_ntb_get_nob\c_tabl_ntb_row=\zerocount
- \allowbreak
- \fi
- \else
- \allowbreak % else no proper head split off
- \fi
- \bgroup % protect local vars
- \m_tabl_ntb_after_split
- \egroup
- \bgroup % protect local vars
- \scratchcounter\numexpr\c_tabl_ntb_row+\plusone\relax
- \ifnum\scratchcounter>\c_tabl_ntb_n_of_hdnx_lines\relax
- \ifnum\scratchcounter<\c_tabl_ntb_maximum_row\relax
- \doifsomething{\naturaltablelocalparameter\c!spaceinbetween}
- {\blank[\naturaltablelocalparameter\c!spaceinbetween]}%
- \fi
- \fi
- \egroup}}
+ {\kern\dimexpr\d_tabl_ntb_rightmargindistance-\d_tabl_ntb_columndistance\relax
+ \egroup
+ \dostoptagged
+ \tabl_ntb_row_align_stop_inject}
+
+\unexpanded\def\tabl_ntb_before_page
+ {\ifx\m_tabl_ntb_same_page\v!before
+ % \blank[\v!samepage,\v!strong]%
+ \unpenalty
+ \nobreak
+ \else\ifx\m_tabl_ntb_same_page\v!both
+ % \blank[\v!samepage,\v!strong]%
+ \unpenalty
+ \nobreak
+ \fi\fi}
+
+\unexpanded\def\tabl_ntb_after_page
+ {\ifnum\c_tabl_ntb_row>\c_tabl_ntb_n_of_head_lines
+ \ifnum\tabl_ntb_get_nob\c_tabl_ntb_row=\zerocount
+ \unpenalty
+ \ifx\m_tabl_ntb_same_page\v!after
+ % \blank[\v!samepage,\v!strong]%
+ \nobreak
+ \else\ifx\m_tabl_ntb_same_page\v!both
+ % \blank[\v!samepage,\v!strong]%
+ \nobreak
+ \else
+ % \blank[\v!preference,\v!weak]%
+ \allowbreak
+ \fi\fi
+ \fi
+ \else
+ % \blank[\v!preference,\v!weak]%
+ \allowbreak % else no proper head split off
+ \fi}
+
+\unexpanded\def\tabl_ntb_inbetween
+ {\scratchcounter\numexpr\c_tabl_ntb_row+\plusone\relax
+ \ifnum\scratchcounter>\c_tabl_ntb_n_of_hdnx_lines\relax
+ \ifnum\scratchcounter<\c_tabl_ntb_maximum_row\relax
+ \edef\p_spaceinbetween{\naturaltablelocalparameter\c!spaceinbetween}%
+ \ifx\p_spaceinbetween\empty\else
+ \blank[\p_spaceinbetween]%
+ \fi
+ \fi
+ \fi}
+
+\unexpanded\def\tabl_ntb_row_align_start_inject
+ {\bgroup % protect local vars
+ \m_tabl_ntb_before_split
+ \egroup
+ \ifenableTBLbreak
+ \tabl_ntb_before_page
+ \fi}
+
+\unexpanded\def\tabl_ntb_row_align_stop_inject
+ {\par
+ \nointerlineskip
+ \ifenableTBLbreak
+ \tabl_ntb_after_page
+ \fi
+ \bgroup % protect local vars
+ \m_tabl_ntb_after_split
+ \egroup
+ \bgroup % protect local vars
+ \tabl_ntb_inbetween
+ \egroup}
\def\tabl_ntb_flush_content
{\the\everyTABLEpass
@@ -1125,47 +1284,56 @@
\global\c_tabl_ntb_col\zerocount
\global\c_tabl_ntb_row\zerocount
\global\advance\c_tabl_ntb_row\minusone
- \tabskip\zeropoint
- \dostarttagged\t!table\empty
- \dostarttagged\t!tablerow\empty
- \appendtoks\dostoptagged\dostarttagged\t!tablerow\empty\to\everycr
- \halign\bgroup
- \registerparoptions
- % watch out: tagging the cell happens at the outer level (faster)
- \ignorespaces\alignmark\alignmark\unskip
- \aligntab\aligntab
- \ignorespaces\alignmark\alignmark\unskip
- \cr % one too many
- \the\t_tabl_ntb
- \dostoptagged
- \egroup
+ \dostarttaggedchained\t!table\empty\??naturaltable
+ %\registerparoptions % (*) triggers max hsize
+ \the\t_tabl_ntb
\dostoptagged}
+\unexpanded\def\tabl_ntb_span#1%
+ {\dorecurse{#1}
+ {\hskip\tabl_ntb_get_wid\c_tabl_ntb_col\relax
+ \global\advance\c_tabl_ntb_col\plusone}}
+
+\unexpanded\def\tabl_ntb_skip#1%
+ {\global\advance\c_tabl_ntb_col#1\relax}
+
+\unexpanded\def\tabl_ntb_plus
+ {\global\advance\c_tabl_ntb_col\plusone
+ \kern\d_tabl_ntb_columndistance}
+
+% \setvalue{\??naturaltablecell\the\c_tabl_ntb_none}#1#2%
+% {\scratchcounter\tabl_ntb_get_col{#1}{#2}\relax
+% \ifnum\scratchcounter>\zerocount
+% \normalexpanded
+% {\t_tabl_ntb_row
+% {\the\t_tabl_ntb_row
+% \tabl_ntb_span{\the\scratchcounter}%
+% \tabl_ntb_plus}}%
+% \fi}
+
\setvalue{\??naturaltablecell\the\c_tabl_ntb_none}#1#2%
{\scratchcounter\tabl_ntb_get_col{#1}{#2}\relax
\ifnum\scratchcounter>\zerocount
- \advance\scratchcounter\minusone
- \ifnum\scratchcounter>\zerocount
- \tabl_ntb_span
- \fi
- \t_tabl_ntb_row\expandafter{\the\t_tabl_ntb_row\tabl_ntb_column_next}
+ \normalexpanded
+ {\t_tabl_ntb_row
+ {\the\t_tabl_ntb_row
+ \tabl_ntb_span{\the\scratchcounter}}}%
\fi}
\setvalue{\??naturaltablecell\the\c_tabl_ntb_cell}#1#2%
{\t_tabl_ntb_row\expandafter{\the\t_tabl_ntb_row\tabl_ntb_pass #1 #2 }% space delimited -> less tokens
\scratchcounter\tabl_ntb_get_col{#1}{#2}\relax
\ifnum\scratchcounter>\zerocount
- \advance\scratchcounter\minusone
- \ifnum\scratchcounter>\zerocount
- \tabl_ntb_span
- \fi
- \t_tabl_ntb_row\expandafter{\the\t_tabl_ntb_row\tabl_ntb_column_next}
+ \normalexpanded
+ {\t_tabl_ntb_row
+ {\the\t_tabl_ntb_row
+ \ifnum\scratchcounter=\plusone
+ \tabl_ntb_plus
+ \else
+ \tabl_ntb_skip{\the\scratchcounter}%
+ \fi}}%
\fi}
-\def\tabl_ntb_span
- {\dorecurse\scratchcounter{\t_tabl_ntb_row\expandafter{\the\t_tabl_ntb_row\tabl_ntb_column_span}}%
- \dorecurse\scratchcounter{\t_tabl_ntb_row\expandafter{\the\t_tabl_ntb_row\tabl_ntb_column_skip}}}
-
\unexpanded\def\tabl_ntb_cell#1#2%
{\csname\??naturaltablecell\the\tabl_ntb_get_tag{#1}{#2}\endcsname{#1}{#2}}
@@ -1183,16 +1351,22 @@
{\d_tabl_ntb_width\zeropoint
\scratchcounter\c_tabl_ntb_col
\!!counta\tabl_ntb_get_col{#1}{#2}\relax
- \dorecurse\!!counta
- {\advance\d_tabl_ntb_width\dimexpr
- \tabl_ntb_get_wid\scratchcounter
- +\naturaltablelocalparameter\c!columndistance
- \ifnum\recurselevel<\!!counta
- +\tabl_ntb_get_dis\scratchcounter
- \fi
- \relax
- \advance\scratchcounter\plusone}%
- \advance\d_tabl_ntb_width-\naturaltablelocalparameter\c!columndistance\relax
+ \ifcase\!!counta\or
+ \advance\d_tabl_ntb_width\dimexpr
+ \tabl_ntb_get_wid\scratchcounter
+ \relax
+ \advance\scratchcounter\plusone
+ \else
+ \dorecurse\!!counta
+ {\advance\d_tabl_ntb_width\dimexpr
+ \tabl_ntb_get_wid\scratchcounter
+ \ifnum\recurselevel<\!!counta
+ +\d_tabl_ntb_columndistance
+ +\tabl_ntb_get_dis\scratchcounter
+ \fi
+ \relax
+ \advance\scratchcounter\plusone}%
+ \fi
\setbox\scratchbox\hbox{\tabl_ntb_get_txt{#1}{#2}}%
\tabl_ntb_set_ht{#1}{#2}{\the\ht\scratchbox}%
\tabl_ntb_set_wd{#1}{#2}{\the\wd\scratchbox}%
@@ -1223,16 +1397,22 @@
% width
\d_tabl_ntb_width\zeropoint
\scratchcounter\c_tabl_ntb_col
- \dorecurse\!!counta
- {\advance\d_tabl_ntb_width\dimexpr
- \tabl_ntb_get_wid\scratchcounter
- +\naturaltablelocalparameter\c!columndistance
- \ifnum\recurselevel<\!!counta
- +\tabl_ntb_get_dis\scratchcounter
- \fi
- \relax
- \advance\scratchcounter\plusone}%
- \advance\d_tabl_ntb_width-\naturaltablelocalparameter\c!columndistance\relax
+ \ifcase\!!counta\or
+ \advance\d_tabl_ntb_width\dimexpr
+ \tabl_ntb_get_wid\scratchcounter
+ \relax
+ \advance\scratchcounter\plusone
+ \else
+ \dorecurse\!!counta
+ {\advance\d_tabl_ntb_width\dimexpr
+ \tabl_ntb_get_wid\scratchcounter
+ \ifnum\recurselevel<\!!counta
+ +\d_tabl_ntb_columndistance
+ +\tabl_ntb_get_dis\scratchcounter
+ \fi
+ \relax
+ \advance\scratchcounter\plusone}%
+ \fi
% cell
\setbox\scratchbox\hbox attr \taggedattribute \attribute\taggedattribute \bgroup
\dotagTABLEsignal % maybe we need to add some packaging in this case
@@ -1280,10 +1460,13 @@
\fi}
\def\tabl_ntb_table_stop
- {\setbox\scratchbox\hbox
- {\setupcurrentnaturaltablelocal[\c!frame=\v!off,\c!background=,\c!align=\v!no]%
- \inheritednaturaltablelocalframed{\strut}}%
- \edef\minimalcellheight{\the\ht\scratchbox}% not used
+ {\forgetall % new, here see narrower-004.tex
+ %\setbox\scratchbox\hbox
+ % {\letnaturaltablelocalparameter\c!frame\v!off
+ % \letnaturaltablelocalparameter\c!background\empty
+ % \letnaturaltablelocalparameter\c!align\v!no
+ % \inheritednaturaltablelocalframed{\strut}}%
+ %\edef\minimalcellheight{\the\ht\scratchbox}% not used
\dorecurse\c_tabl_ntb_maximum_col
{\tabl_ntb_let_aut\recurselevel\zeropoint
% new
@@ -1292,14 +1475,22 @@
{\tabl_ntb_let_wd\recurselevel\c_tabl_ntb_current_col_one\zeropoint
\tabl_ntb_let_ht\recurselevel\c_tabl_ntb_current_col_one\zeropoint}%
% till here
+ \tabl_ntb_let_tal\recurselevel\zerocount
\tabl_ntb_let_wid\recurselevel\zeropoint
\tabl_ntb_let_dis\recurselevel\zeropoint}%
\dorecurse\c_tabl_ntb_maximum_row
{\tabl_ntb_let_hei\recurselevel\maxdimen}%
+ \tabl_ntb_let_gal\zerocount
\c_tabl_tbl_pass\plusone
\let\tabl_ntb_pass\tabl_ntb_pass_one
\let\tabl_ntb_cell_process\tabl_ntb_cell_process_a
- \setbox0\vbox{\settrialtypesetting \tabl_ntb_flush_content}%
+ \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}%
+ \ifcase\tabl_ntb_get_gal\or
+ % \c_tabl_tbl_pass\plusone
+ % \let\tabl_ntb_pass\tabl_ntb_pass_one
+ \let\tabl_ntb_cell_process\tabl_ntb_cell_process_a_extra
+ \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}%
+ \fi
\tabl_ntb_let_dis\c_tabl_ntb_maximum_col\zeropoint
\ifautoTBLspread
% experimental, stretch non fixed cells to \hsize
@@ -1308,21 +1499,24 @@
\tabl_ntb_stretch_widths
\let\tabl_ntb_cell_process\tabl_ntb_cell_process_b
\setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}%
- \else\ifdim\wd0>\hsize
+ \else\ifdim\wd\scratchbox>\hsize
\ifautoTBLhsize
\tabl_ntb_check_widths_one % trial run
\tabl_ntb_check_widths_two % real run
\let\tabl_ntb_cell_process\tabl_ntb_cell_process_b
\setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}%
\fi
- \else\ifautoTBLrowspan\ifnum\c_tabl_ntb_maximum_row_span>1 % max ?
+ \else\ifautoTBLrowspan\ifnum\c_tabl_ntb_maximum_row_span>\plusone % max ?
% added jan 2002 because nx=* did no longer work
+ \ifnum\c_tabl_ntb_encountered_max<\c_tabl_ntb_maximum_col
+ % added jun 2014 because someone had less columns than nx .. sigh / see *nx*
+ \writestatus\m!TABLE{missing\space\number\numexpr\c_tabl_ntb_maximum_col-\c_tabl_ntb_encountered_max\relax\space column(s), guessing widths}%
+ \fi
\edef\savedhsize{\the\hsize}%
- \hsize\wd0\relax % new per 17/04/2006
+ \hsize\wd\scratchbox\relax % new per 17/04/2006
\tabl_ntb_check_widths_one % trial run
\tabl_ntb_check_widths_two % real run
\hsize\savedhsize
- %
\let\tabl_ntb_cell_process\tabl_ntb_cell_process_c
\setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}%
\fi\fi\fi\fi
@@ -1336,39 +1530,56 @@
\c_tabl_tbl_pass\plusthree
\let\tabl_ntb_pass\tabl_ntb_pass_three
\ifnum\m_tabl_tbl_level>\plusone
- \expandafter\tabl_tbl_split_nop
+ \tabl_tbl_split_nop
\else\ifenableTBLbreak
- \doubleexpandafter\tabl_tbl_split_yes
+ \tabl_tbl_split_yes
\else
- \doubleexpandafter\tabl_tbl_split_nop
- \fi\fi{\tabl_ntb_flush_content}}
+ \tabl_tbl_split_nop
+ \fi\fi}
\def\tabl_ntb_stretch_widths % more variants, e.g. a max to \dimend
{\ifcase\c_tabl_ntb_maximum_col\else % else division by zero
\!!dimend\zeropoint
- \!!dimene\hsize
+ \!!dimene\dimexpr
+ \hsize
+ -\d_tabl_ntb_leftmargindistance
+ -\d_tabl_ntb_rightmargindistance
+ +\d_tabl_ntb_columndistance
+ \relax
\dorecurse\c_tabl_ntb_maximum_col
- {\advance\!!dimend\dimexpr\tabl_ntb_get_wid\recurselevel+\naturaltablelocalparameter\c!columndistance\relax
- \advance\!!dimene-\tabl_ntb_get_dis\recurselevel}%
- \advance\!!dimend\dimexpr-\naturaltablelocalparameter\c!columndistance+\naturaltablelocalparameter\c!leftmargindistance+\naturaltablelocalparameter\c!rightmargindistance\relax
+ {\advance\!!dimend\dimexpr
+ \tabl_ntb_get_wid\recurselevel
+ \relax
+ \advance\!!dimene\dimexpr
+ -\tabl_ntb_get_dis\recurselevel
+ -\d_tabl_ntb_columndistance
+ \relax}%
+ \relax
% distribute width (stretch)
\ifdim\!!dimend<\!!dimene
\advance\!!dimend-\!!dimene
- \!!dimend-\!!dimend
\divide\!!dimend\c_tabl_ntb_maximum_col
\dorecurse\c_tabl_ntb_maximum_col
- {\tabl_ntb_set_wid\recurselevel{\the\dimexpr\tabl_ntb_get_wid\recurselevel+\!!dimend\relax}}%
+ {\tabl_ntb_set_wid\recurselevel{\the\dimexpr\tabl_ntb_get_wid\recurselevel-\!!dimend\relax}}%
\fi
\fi}
-\def\tabl_tbl_split_nop#1%
- {\setbox\b_tabl_ntb_final\vbox{#1}%
+\def\tabl_tbl_split_nop
+ {\setbox\b_tabl_ntb_final\vbox{\tabl_ntb_flush_content}%
\postprocessTABLEbox\b_tabl_ntb_final
\beforeTABLEbox
+ % packaging prevents max hsized box
+ % \hbox{\registerparoptions\box\b_tabl_ntb_final}% (*) better here
+ % better :
+ \ifinsidefloat
+ % nothing, else we get a \hsized box
+ \else
+ \registerparoptions % (*) better here
+ \fi
\box\b_tabl_ntb_final
\afterTABLEbox}
-\def\tabl_tbl_split_yes % #1
+\def\tabl_tbl_split_yes
{\ifinsidesplitfloat
\donetrue
\else\ifinsidefloat
@@ -1386,14 +1597,15 @@
\let\extratblsplitheight\zeropoint % additional space taken by before/afterTABLEsplitbox
-\def\tabl_ntb_split_box#1%
+\def\tabl_ntb_split_box
{\resettsplit
\def\tsplitminimumfreelines{2}%
\def\tsplitminimumfreespace{\dimexpr\extratblsplitheight+\naturaltablelocalparameter\c!splitoffset\relax}%
\def\tsplitbeforeresult {\beforeTABLEsplitbox}%
\def\tsplitafterresult {\afterTABLEsplitbox}%
\def\tsplitafter {\m_tabl_ntb_after_split}%
- \setbox\tsplitcontent\vbox{#1}%
+ \def\tsplitbefore {\m_tabl_ntb_before_split}% supported ?
+ \setbox\tsplitcontent\vbox{\tabl_ntb_flush_content}%
\ifmultipleTBLheads
\dorecurse\c_tabl_ntb_n_of_head_lines
{\setbox\scratchbox\vsplit\tsplitcontent to \lineheight
@@ -1402,8 +1614,10 @@
{\setbox\scratchbox\vsplit\tsplitcontent to \lineheight
\setbox\tsplitnext\vbox{\unvcopy\tsplitnext\unvcopy\scratchbox}}%
\fi
- \doifsomething{\naturaltablelocalparameter\c!spaceinbetween}
- {\def\tsplitinbetween{\blank[\naturaltablelocalparameter\c!spaceinbetween]}}%
+ \edef\p_spaceinbetween{\naturaltablelocalparameter\c!spaceinbetween}%
+ \ifx\p_spaceinbetween\empty\else
+ \blank[\p_spaceinbetween]%
+ \fi
\def\postprocesstsplit{\postprocessTABLEsplitbox{\box\tsplitresult}}%
\handletsplit}
@@ -1423,15 +1637,23 @@
\def\tabl_ntb_check_widths_indeed#1%
{\iftraceTABLE\tabl_ntb_show_widths{B#1}\fi
\!!counta\zerocount
- \!!dimena\dimexpr\hsize-\naturaltablelocalparameter\c!leftmargindistance-\naturaltablelocalparameter\c!rightmargindistance-\naturaltablelocalparameter\c!columndistance\relax
+ \!!dimena\dimexpr
+ \hsize
+ -\d_tabl_ntb_leftmargindistance
+ -\d_tabl_ntb_rightmargindistance
+ -\d_tabl_ntb_columndistance
+ \relax
\dorecurse\c_tabl_ntb_maximum_col
{\scratchdimen\tabl_ntb_get_aut\recurselevel\relax
- \advance\!!dimena-\tabl_ntb_get_dis\recurselevel\relax
+ \advance\!!dimena\dimexpr
+ -\tabl_ntb_get_dis\recurselevel
+ -\d_tabl_ntb_columndistance
+ \relax
\ifdim\scratchdimen>\zeropoint\relax
\advance\!!dimena -\scratchdimen
\else
\scratchdimen\tabl_ntb_get_wid\recurselevel\relax
- \ifdim\scratchdimen>\naturaltablelocalparameter\c!maxwidth\relax
+ \ifdim\scratchdimen>\d_tabl_ntb_maxwidth\relax
\ifcase#1\else\tabl_ntb_let_wid\recurselevel\zeropoint\fi
\advance\!!counta \plusone
\else
@@ -1440,7 +1662,9 @@
\else
% eigenlijk moet dit alleen als de kolom wordt overspannen door een
% vorige, maw extra dubbele loop en status var
- \advance\!!counta \plusone
+ \ifnum\c_tabl_ntb_encountered_max=\c_tabl_ntb_maximum_col % *nx* bah
+ \advance\!!counta \plusone % setting maxwidth to a large value also works
+ \fi
\fi
\fi
\fi}%
@@ -1531,7 +1755,9 @@
\def\tabl_ntb_show_widths#1%
{\vbox
- {\forgetall\tttf[#1]\dorecurse\c_tabl_ntb_maximum_col
+ {\forgetall
+ \tttf[#1]%
+ \dorecurse\c_tabl_ntb_maximum_col
{\scratchdimen\tabl_ntb_get_wid\recurselevel\relax
[\recurselevel:\the\scratchdimen]}}}
@@ -1548,46 +1774,115 @@
% \setsecondpasscharacteralign \checkalignment{#3}% {\strut#2\unskip}%
% \ignorespaces}
-\def\tabl_ntb_char_align
- {\doifelse{\naturaltablelocalparameter\c!aligncharacter}\v!yes
- \tabl_ntb_char_align_indeed
- \gobbletwoarguments}
+\def\tabl_ntb_char_align % called often
+ {\edef\p_characteralign{\naturaltablelocalparameter\c!aligncharacter}%
+ \ifx\p_characteralign\v!yes
+ \ifcase\c_tabl_tbl_pass\or
+ \tabl_ntb_let_tal\currentTABLEcolumn\plusone
+ \tabl_ntb_let_gal\plusone
+ \fi
+ \expandafter\tabl_ntb_char_align_indeed
+ \else
+ \expandafter\gobbletwoarguments
+ \fi}
\def\tabl_ntb_char_align_indeed#1#2% row column
{\ifcase\c_tabl_tbl_pass \or
- \setcharacteralign{#2}{\naturaltablelocalparameter\c!alignmentcharacter}%
+ \setcharacteralign{#2}{\naturaltablelocalparameter\c!alignmentcharacter}% we could store the character in tal
\fi
\typo_charalign_adapt_font
\signalcharacteralign{#2}{#1}}
+\unexpanded\def\tabl_ntb_cell_process_a_extra#1#2%
+ {\ifcase\tabl_ntb_get_tal{#2}\relax
+ \expandafter\tabl_ntb_cell_process_x
+ \else
+ \expandafter\tabl_ntb_cell_process_a
+ \fi{#1}{#2}}
+
+\unexpanded\def\tabl_ntb_cell_process_x#1#2[#3]#4%
+ {}
+
+% problem: when span doesn't break we can have a span that is the sum of
+% cells but still to small .. chicken egg problem ... for that we should
+% also have a smallest width run
+%
+% nilling the background makes a run upto 25% faster
+
+\def\tabl_ntb_cell_process_a_check_span_one
+ {\ifautosqueezeTBLspan
+ \edef\p_width{\naturaltablelocalparameter\c!width}%
+ \csname\??naturaltablesqueeze\ifcsname\??naturaltablesqueeze\p_width\endcsname\p_width\fi\endcsname
+ \else
+ \donetrue
+ \fi
+ \ifdone % brr, 0
+ \ifnum\scratchcounter>\plusone
+ \tabl_ntb_set_spn\c_tabl_ntb_col
+ \fi
+ \fi}
+
+\def\tabl_ntb_cell_process_a_check_span_two_yes
+ {\iftightTBLcolspan
+ \donefalse
+ \else
+ \ifnum\scratchcounter>\plusone
+ \begingroup
+ \edef\p_width{\naturaltablelocalparameter\c!width}%
+ \csname\??naturaltablesqueeze\ifcsname\??naturaltablesqueeze\p_width\endcsname\p_width\fi\endcsname
+ \ifdone
+ \endgroup
+ \edef\p_option{\naturaltablelocalparameter\c!option}%
+ \ifx\p_option\v!tight\donefalse\else\donetrue\fi
+ \else
+ % a dimension
+ \endgroup
+ \donefalse
+ \fi
+ \else
+ \edef\p_option{\naturaltablelocalparameter\c!option}%
+ \ifx\p_option\v!tight\donefalse\else\donetrue\fi
+ \fi
+ \fi}
+
+
+% \let\tabl_ntb_cell_process_a_check_span_two_nop\donetrue
+
+\def\tabl_ntb_cell_process_a_check_span_two_nop
+ {\ifnum\scratchcounter>\plusone
+ \edef\p_width{\naturaltablelocalparameter\c!width}%
+ \csname\??naturaltablesqueeze\ifcsname\??naturaltablesqueeze\p_width\endcsname\p_width\fi\endcsname
+ \else
+ \donetrue
+ \fi}
+
\unexpanded\def\tabl_ntb_cell_process_a#1#2[#3]#4% grouping added ! ! !
{\bgroup
+ \letnaturaltablelocalparameter\c!option\empty
\tabl_ntb_setup_cell{#1}{#2}%
+ \setupcurrentnaturaltablelocal[#3]%
+ \letnaturaltablelocalparameter\c!background\empty
+ \letnaturaltablelocalparameter\c!frame\v!off
+ \scratchcounter\tabl_ntb_get_col{#1}{#2}\relax
\setbox\scratchbox\hbox
{\scratchdimen\naturaltablelocalparameter\c!distance\relax
\ifdim\scratchdimen>\tabl_ntb_get_dis{#2}\relax
\tabl_ntb_set_dis{#2}{\the\scratchdimen}%
\fi
- \setupcurrentnaturaltablelocal[#3,\c!background=,\c!frame=\v!off]% 25% faster
\inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop\tabl_ntb_cell_finalize}}%
\scratchdimen\tabl_ntb_get_wid\c_tabl_ntb_col\relax
\ifdim\wd\scratchbox>\scratchdimen
\ifsqueezeTBLspan
- \ifautosqueezeTBLspan
- \doifinsetelse{\naturaltablelocalparameter\c!width}{\v!fit,\v!fixed,\v!broad,\v!local}
- \donetrue \donefalse
- \else
- \donetrue
- \fi
- \ifdone % brr, 0
- \ifnum\tabl_ntb_get_col{#1}{#2}>\plusone \tabl_ntb_set_spn\c_tabl_ntb_col\fi
- \fi
+ \tabl_ntb_cell_process_a_check_span_one
\fi
\tabl_ntb_spn_doifelse\c_tabl_ntb_col
- \donothing
- {\ifdim\tabl_ntb_get_wid\c_tabl_ntb_col<\wd\scratchbox
+ \tabl_ntb_cell_process_a_check_span_two_yes
+ \tabl_ntb_cell_process_a_check_span_two_nop
+ \ifdone
+ \ifdim\tabl_ntb_get_wid\c_tabl_ntb_col<\wd\scratchbox
\tabl_ntb_set_wid\c_tabl_ntb_col{\the\wd\scratchbox}%
- \fi}% auto set
+ \fi
+ \fi
\fi
\scratchcounter\numexpr\c_tabl_ntb_row+\plusone\relax
\scratchdimen\tabl_ntb_get_hei\scratchcounter\relax
@@ -1608,8 +1903,7 @@
% unless span
\tabl_ntb_set_aut\c_tabl_ntb_col{\the\wd\scratchbox}%
% to be translated
- \writestatus\m!TABLE
- {no auto width in (\number#1,\number#2)\space\the\wd\scratchbox/\the\hsize}%
+ \writestatus\m!TABLE{no auto width in (\number#1,\number#2)\space\the\wd\scratchbox/\the\hsize}%
\fi\fi
\fi
\fi
@@ -1624,7 +1918,9 @@
\unexpanded\def\tabl_ntb_cell_process_b_c#1#2#3[#4]#5%
{\setbox\scratchbox\hbox
{\tabl_ntb_setup_cell{#2}{#3}%
- \setupcurrentnaturaltablelocal[#4,#1,\c!frame=\v!off,\c!background=]%
+ \setupcurrentnaturaltablelocal[#4,#1]%
+ \letnaturaltablelocalparameter\c!background\empty
+ \letnaturaltablelocalparameter\c!frame\v!off
\inheritednaturaltablelocalframed{\tabl_ntb_cell_start#5\tabl_ntb_cell_stop}}%
\setbox2\emptyhbox
\wd2\wd\scratchbox
@@ -1663,7 +1959,10 @@
\unexpanded\def\tabl_ntb_cell_process_d#1#2[#3]#4%
{\tabl_ntb_setup_cell{#1}{#2}%
\bgroup
- \setupcurrentnaturaltablelocal[#3,\c!width=\d_tabl_ntb_width,\c!background=,\c!frame=\v!off]% 25% faster
+ \setupcurrentnaturaltablelocal[#3]%
+ \letnaturaltablelocalparameter\c!background\empty
+ \letnaturaltablelocalparameter\c!frame\v!off
+ \setnaturaltablelocalparameter\c!width{\d_tabl_ntb_width}%
\inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop}%
\egroup}
@@ -1672,10 +1971,11 @@
\setupcurrentnaturaltablelocal[#3]% to get the color right, the way we
\color % handle color here prevents interference due to whatsit nodes
[\naturaltablelocalparameter\c!color] % as well as permits local colors to take precedence
- {\ifdim\d_tabl_ntb_height=\zeropoint\relax % case: nc=maxcolumns
- \setupcurrentnaturaltablelocal[\c!color=,\c!width=\d_tabl_ntb_width]%
+ {\letnaturaltablelocalparameter\c!color\empty
+ \setnaturaltablelocalparameter\c!width{\d_tabl_ntb_width}%
+ \ifdim\d_tabl_ntb_height=\zeropoint\relax % case: nc=maxcolumns
\else
- \setupcurrentnaturaltablelocal[\c!color=,\c!width=\d_tabl_ntb_width,\c!height=\d_tabl_ntb_height]%
+ \setnaturaltablelocalparameter\c!height{\d_tabl_ntb_height}%
\fi
\inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop}}%
\hskip\tabl_ntb_get_dis{#2}}
@@ -1728,7 +2028,7 @@
\newconditional\resetTABLEmode \settrue\resetTABLEmode
-\def\tabl_ntb_parameters_reset
+\def\tabl_ntb_parameters_reset % we can use setters instead
{\ifnum\m_tabl_tbl_level>\plusone % in ieder geval
\ifconditional\resetTABLEmode
% not ok yet
diff --git a/Master/texmf-dist/tex/context/base/tabl-tab.mkiv b/Master/texmf-dist/tex/context/base/tabl-tab.mkiv
index f9ac27e7011..5add1c684a0 100644
--- a/Master/texmf-dist/tex/context/base/tabl-tab.mkiv
+++ b/Master/texmf-dist/tex/context/base/tabl-tab.mkiv
@@ -1503,9 +1503,9 @@
\global\setfalse\tableactionstatepermitted
\global\setfalse\hassometablehead
\global\setfalse\hassometabletail
- \expanded{\doifinstringelse{|}{#1}}
+ \expanded{\doifelseinstring{|}{#1}}
{\xdef\restarttable{\noexpand\dorestarttable{\noexpand\thirdstagestarttable{#1}}}}
- {\doifdefinedelse{\??tabletemplate#1}
+ {\doifelsedefined{\??tabletemplate#1}
{\gdef\restarttable{\getvalue{\??tabletemplate#1}}}
{\gdef\restarttable{\dorestarttable{\getvalue{#1}}}}}%
\egroup
@@ -1921,7 +1921,7 @@
{\global\currenttablecolumn\zerocount}
\def\dotablevrulecommand#1% global assignments
- {\doifnumberelse{#1}
+ {\doifelsenumber{#1}
{\global\tablevrulethicknessfactor#1\relax
\global\multiply\tablevrulethicknessfactor\m_tabl_table_VLwidth\relax}
{\xdef\tablecurrentvrulecolor{#1}}}
@@ -1955,7 +1955,7 @@
\unexpanded\def\dotableVN#1{\global\noftablevrules#1\relax\VL}
\def\dotablehrulecommand#1% global assignments
- {\doifnumberelse{#1}
+ {\doifelsenumber{#1}
{\global\tablehrulethicknessfactor#1\relax
\global\multiply\tablehrulethicknessfactor\m_tabl_table_HLheight\relax}
{\xdef\tablecurrenthrulecolor{#1}}}
@@ -2075,7 +2075,7 @@
\fi}
\def\dotabledrulecommand#1% global assignments
- {\doifnumberelse{#1}
+ {\doifelsenumber{#1}
{\ifcase\tabledrulespan
\global\tabledrulespan#1\relax
\else
@@ -2203,7 +2203,7 @@
\def\dolocaltablesetup
{\directtablesparameter\c!commands\relax
- \doifsomething{\directtablesparameter\c!bodyfont}{\switchtobodyfont[\directtablesparameter\c!bodyfont]}%
+ \usebodyfontparameter\directtablesparameter
\tablelinethicknessunit\dimexpr\directtablesparameter\c!rulethickness/\tablelinethicknessfactor\relax
\edef\p_tabl_table_height{\directtablesparameter\c!height}%
\edef\p_tabl_table_depth{\directtablesparameter\c!depth}%
@@ -2288,8 +2288,7 @@
\c!distance=\v!medium,
\c!bodyfont=,
\c!commands=,
- \c!background=\v!screen, % huh?
- \c!backgroundscreen=\defaultbackgroundscreen,
+ \c!background=,
\c!backgroundcolor=,
\c!split=\v!auto]
diff --git a/Master/texmf-dist/tex/context/base/tabl-tbl.lua b/Master/texmf-dist/tex/context/base/tabl-tbl.lua
index b088a10086e..13d899de647 100644
--- a/Master/texmf-dist/tex/context/base/tabl-tbl.lua
+++ b/Master/texmf-dist/tex/context/base/tabl-tbl.lua
@@ -25,7 +25,7 @@ local pattern = Ct((separator * (C(nested) + Cc("")) * C((1-separator)^0))^0
local ctx_settabulatelastentry = context.settabulatelastentry
local ctx_settabulateentry = context.settabulateentry
-function commands.presettabulate(preamble)
+local function presettabulate(preamble)
preamble = gsub(preamble,"~","d") -- let's get rid of ~ mess here
if find(preamble,"*",1,true) then
-- todo: lpeg but not now
@@ -43,3 +43,10 @@ function commands.presettabulate(preamble)
end
ctx_settabulatelastentry(t[m+1])
end
+
+interfaces.implement {
+ name = "presettabulate",
+ actions = presettabulate,
+ arguments = "string",
+ scope = "private",
+}
diff --git a/Master/texmf-dist/tex/context/base/tabl-tbl.mkiv b/Master/texmf-dist/tex/context/base/tabl-tbl.mkiv
index c25d61741f4..ae4f03825a7 100644
--- a/Master/texmf-dist/tex/context/base/tabl-tbl.mkiv
+++ b/Master/texmf-dist/tex/context/base/tabl-tbl.mkiv
@@ -331,7 +331,7 @@
{\dowithnextboxcs\tabl_tabulate_shaped_par_finish\vbox\bgroup}
\def\tabl_tabulate_shaped_par_finish
- {\ctxcommand{doreshapeframedbox(\number\nextbox)}%
+ {\clf_doreshapeframedbox\nextbox\relax
\ifvmode\unvbox\else\box\fi\nextbox}
\let\tabl_tabulate_shaped_par_end\egroup
@@ -599,17 +599,17 @@
\tabl_tabulate_set_preamble}
\def\tabl_tabulate_set_preskip#1%
- {\doifnumberelse{#1}
+ {\doifelsenumber{#1}
{\s_tabl_tabulate_pre#1\d_tabl_tabulate_unit\tabl_tabulate_set_preamble }
{\s_tabl_tabulate_pre.5\d_tabl_tabulate_unit\tabl_tabulate_set_preamble#1}}
\def\tabl_tabulate_set_posskip#1%
- {\doifnumberelse{#1}
+ {\doifelsenumber{#1}
{\s_tabl_tabulate_post#1\d_tabl_tabulate_unit\tabl_tabulate_set_preamble }
{\s_tabl_tabulate_post.5\d_tabl_tabulate_unit\tabl_tabulate_set_preamble#1}}
\def\tabl_tabulate_set_preposskip#1%
- {\doifnumberelse{#1}
+ {\doifelsenumber{#1}
{\s_tabl_tabulate_pre#1\d_tabl_tabulate_unit\s_tabl_tabulate_post\s_tabl_tabulate_pre\tabl_tabulate_set_preamble }
{\s_tabl_tabulate_pre.5\d_tabl_tabulate_unit\s_tabl_tabulate_post\s_tabl_tabulate_pre\tabl_tabulate_set_preamble#1}}
@@ -651,7 +651,7 @@
\tabl_tabulate_set_preamble}
\def\tabl_tabulate_pickup_width
- {\doifnextparenthesiselse\tabl_tabulate_set_width_indeed\tabl_tabulate_set_preamble}
+ {\doifelsenextparenthesis\tabl_tabulate_set_width_indeed\tabl_tabulate_set_preamble}
\def\tabl_tabulate_set_width
{\setfalse\c_tabl_tabulate_pwidth_set
@@ -664,7 +664,7 @@
\tabl_tabulate_set_preamble}
\def\tabl_tabulate_set_paragraph
- {\doifnextparenthesiselse
+ {\doifelsenextparenthesis
{\c_tabl_tabulate_modus\plusone
\settrue\c_tabl_tabulate_pwidth_set
\tabl_tabulate_pickup_width}
@@ -749,7 +749,7 @@
\tabl_tabulate_set_preamble}
\def\tabl_tabulate_set_vrule_command#1%
- {\doifnumberelse{#1}
+ {\doifelsenumber{#1}
{\global\d_tabl_tabulate_vrulethickness#1\d_tabl_tabulate_vrulethickness_default}
{\xdef\m_tabl_tabulate_vrule_color{#1}}}
@@ -1049,17 +1049,25 @@
\def\tabl_tabulate_insert_foot_content
{\tabulatenoalign{\global\settrue\c_tabl_tabulate_someamble}%
- \csname\??tabulatehead\currenttabulation\endcsname
+ \csname\??tabulatefoot\currenttabulation\endcsname
\tabulatenoalign{\global\setfalse\c_tabl_tabulate_someamble}}%
\def\tabl_tabulate_check_full_content % - needed, else confusion with \c!header
{\ifcsname\??tabulatehead\currenttabulation\endcsname
- \let\tabl_tabulate_insert_head\tabl_tabulate_insert_head_content
+ \expandafter\ifx\csname\??tabulatehead\currenttabulation\endcsname\empty
+ \let\tabl_tabulate_insert_head\empty
+ \else
+ \let\tabl_tabulate_insert_head\tabl_tabulate_insert_head_content
+ \fi
\else
\let\tabl_tabulate_insert_head\empty
\fi
\ifcsname\??tabulatefoot\currenttabulation\endcsname
- \let\tabl_tabulate_insert_foot\tabl_tabulate_insert_foot_content
+ \expandafter\ifx\csname\??tabulatefoot\currenttabulation\endcsname\empty
+ \let\tabl_tabulate_insert_foot\empty
+ \else
+ \let\tabl_tabulate_insert_foot\tabl_tabulate_insert_head_content
+ \fi
\else
\let\tabl_tabulate_insert_foot\empty
\fi}
@@ -1079,8 +1087,10 @@
\tabulatenoalign{\kern-\lineheight}%
\fi}
-\setuvalue{\e!start\v!tabulatehead}{\doifnextoptionalcselse\tabl_tabulate_start_head_yes\tabl_tabulate_start_head_nop}
-\setuvalue{\e!start\v!tabulatetail}{\doifnextoptionalcselse\tabl_tabulate_start_foot_yes\tabl_tabulate_start_foot_nop}
+% todo: make footer synonym to tail
+
+\setuvalue{\e!start\v!tabulatehead}{\doifelsenextoptionalcs\tabl_tabulate_start_head_yes\tabl_tabulate_start_head_nop}
+\setuvalue{\e!start\v!tabulatetail}{\doifelsenextoptionalcs\tabl_tabulate_start_foot_yes\tabl_tabulate_start_foot_nop}
\let\m_tabl_tabulate_data\empty
@@ -1090,30 +1100,30 @@
\def\tabl_tabulate_start_foot_yes[#1]%
{\processcontent{\e!stop\v!tabulatetail}\m_tabl_tabulate_data{\letvalue{\??tabulatefoot#1}\m_tabl_tabulate_data}}
-% \def\tabl_tabulate_start_head_nop{\tabl_tabulate_start_head_yes[\v!tabulate]}
-% \def\tabl_tabulate_start_foot_nop{\tabl_tabulate_start_foot_yes[\v!tabulate]}
+\def\tabl_tabulate_start_head_nop{\tabl_tabulate_start_head_yes[\v!tabulate]}
+\def\tabl_tabulate_start_foot_nop{\tabl_tabulate_start_foot_yes[\v!tabulate]}
-\def\tabl_tabulate_start_head_nop{\tabl_tabulate_start_head_yes[]}
-\def\tabl_tabulate_start_foot_nop{\tabl_tabulate_start_foot_yes[]}
+% \def\tabl_tabulate_start_head_nop{\tabl_tabulate_start_head_yes[]}
+% \def\tabl_tabulate_start_foot_nop{\tabl_tabulate_start_foot_yes[]}
% \unexpanded\def\tabl_start_defined[#1]%
% {\bgroup
% \edef\currenttabulationparent{#1}%
% \let\currenttabulation\currenttabulationparent
-% \doifnextoptionalcselse\tabl_start_defined_yes\tabl_start_defined_nop}
-%
-% \def\tabl_start_defined_yes[#1]%
-% {\edef\currenttabulation{\currenttabulation:#1}%
-% \tabl_tabulate_start_building}
-%
-% \def\tabl_start_defined_nop
-% {\tabl_tabulate_start_building}
+% \dodoubleargument\tabl_start_defined_indeed}
\unexpanded\def\tabl_start_defined[#1]%
{\bgroup
\edef\currenttabulationparent{#1}%
\let\currenttabulation\currenttabulationparent
- \dodoubleargument\tabl_start_defined_indeed}
+ \edef\p_format{\tabulationparameter\c!format}%
+ \ifx\p_format\v!none
+ % this is special case: we need to define the generic english
+ % \starttabulate in other interfaces as well
+ \expandafter\dodoubleempty \expandafter\tabl_start_regular
+ \else
+ \expandafter\dodoubleargument\expandafter\tabl_start_defined_indeed
+ \fi}
\def\tabl_start_defined_indeed
{\iffirstargument
@@ -1127,7 +1137,7 @@
\fi}
\def\tabl_start_defined_one[#1][#2]%
- {\doifassignmentelse{#1}
+ {\doifelseassignment{#1}
{\setuptabulation[\currenttabulation][#1]}%
{\edef\currenttabulation{\currenttabulation:#1}}%
\tabl_tabulate_start_building}
@@ -1144,26 +1154,11 @@
\unexpanded\setuvalue{\e!start\v!tabulate}%
{\bgroup % whole thing
+ \let\currenttabulationparent\empty
\dodoubleempty\tabl_start_regular}
-% \def\tabl_start_regular[#1][#2]%
-% {%\let\currenttabulationparent\v!tabulate
-% \let\currenttabulationparent\empty
-% \let\currenttabulation\currenttabulationparent
-% \def\p_format{#1}%
-% \ifx\p_format\empty
-% \def\p_format{|l|p|}%
-% \fi
-% \lettabulationparameter\c!format\p_format
-% \ifsecondargument
-% \setupcurrenttabulation[#2]%
-% \fi
-% \tabl_tabulate_start_building}
-
\def\tabl_start_regular
- {%\let\currenttabulationparent\v!tabulate
- \let\currenttabulationparent\empty
- \let\currenttabulation\currenttabulationparent
+ {\let\currenttabulation\currenttabulationparent
\ifsecondargument
\expandafter\tabl_start_regular_two
\else
@@ -1171,7 +1166,7 @@
\fi}
\def\tabl_start_regular_one[#1][#2]%
- {\doifassignmentelse{#1}
+ {\doifelseassignment{#1}
{\setupcurrenttabulation[\c!format={|l|p|},#1]}
{\def\p_format{#1}%
\ifx\p_format\empty
@@ -1321,7 +1316,7 @@
\def\tabl_tabulate_set_color_column#1% overloaded
{\unskip
- \doiffastoptionalcheckelse{\tabl_tabulate_set_color_column_yes#1}{\tabl_tabulate_set_color_column_nop#1}}
+ \doifelsefastoptionalcheck{\tabl_tabulate_set_color_column_yes#1}{\tabl_tabulate_set_color_column_nop#1}}
\def\tabl_tabulate_set_color_column_nop
{\tabl_tabulate_column_normal}
@@ -1360,13 +1355,13 @@
% \fi\fi
\global\let\m_tabl_tabulate_vrule_color_local\m_tabl_tabulate_vrule_color_default
\global\d_tabl_tabulate_vrulethickness_local\d_tabl_tabulate_vrulethickness_default
- \doiffastoptionalcheckelse{\tabl_tabulate_column_vruled_yes#1}{\tabl_tabulate_column_vruled_nop#1}}
+ \doifelsefastoptionalcheck{\tabl_tabulate_column_vruled_yes#1}{\tabl_tabulate_column_vruled_nop#1}}
\def\tabl_tabulate_column_vruled_nop
{\tabl_tabulate_column_normal}
\def\tabl_tabulate_column_vruled_step#1%
- {\doifnumberelse{#1}
+ {\doifelsenumber{#1}
{\global\d_tabl_tabulate_vrulethickness_local#1\d_tabl_tabulate_vrulethickness_default}
{\xdef\m_tabl_tabulate_vrule_color_local{#1}}}
@@ -1454,15 +1449,15 @@
\def\tabl_tabulate_hrule_spec_ignore#1%
{%\global\let\currenttabulationlocalhrulecolor\empty
%\global\d_tabl_tabulate_hrulethickness_local\d_tabl_tabulate_hrulethickness_default
- \doiffastoptionalcheckelse#1#1}
+ \doifelsefastoptionalcheck#1#1}
\def\tabl_tabulate_hrule_spec_pickup#1%
{\global\let\currenttabulationlocalhrulecolor\m_tabl_tabulate_hrule_color_default
\global\d_tabl_tabulate_hrulethickness_local\d_tabl_tabulate_hrulethickness_default
- \doiffastoptionalcheckelse{\tabl_tabulate_hrule_preset#1}#1}
+ \doifelsefastoptionalcheck{\tabl_tabulate_hrule_preset#1}#1}
\def\tabl_tabulate_hrule_preset_step#1%
- {\doifnumberelse{#1}
+ {\doifelsenumber{#1}
{\global\d_tabl_tabulate_hrulethickness_local#1\d_tabl_tabulate_hrulethickness_default}
{\xdef\currenttabulationlocalhrulecolor{#1}}}
@@ -1531,7 +1526,7 @@
\unexpanded\def\tabl_tabulate_color_set#1% we could store the attributes at the cost of a lua call
{\begingroup
- \node_backgrounds_align_initialize % name might change
+ \clf_enablebackgroundalign % was \node_backgrounds_align_initialize
\global\let\tabl_tabulate_color_repeat\tabl_tabulate_color_repeat_second
\global\settrue\c_tabl_tabulate_has_colors
\ifnum\c_tabl_tabulate_column>\c_tabl_tabulate_max_colorcolumn
@@ -2106,7 +2101,7 @@
\c_tabl_tabulate_nofcolumns \zerocount
\c_tabl_tabulate_has_rule_spec_first\zerocount
\c_tabl_tabulate_has_rule_spec_last \zerocount
- \ctxcommand{presettabulate(\!!bs\detokenizedtabulationparameter\c!format\!!es)}%
+ \clf_presettabulate{\detokenizedtabulationparameter\c!format}%
%
% \edef\totaltabulatecolumns{\the\numexpr3*\c_tabl_tabulate_columns+\plusfour}%
\d_tabl_tabulate_width\zeropoint
@@ -2172,7 +2167,7 @@
\global\setbox\b_tabl_tabulate\vbox \bgroup
\fi
%
- \dostarttagged\t!tabulate\empty
+ \dostarttaggedchained\t!tabulate\empty\??tabulation
\dostarttagged\t!tabulaterow\empty
\setfalse\inhibitmargindata % new per 2012.06.13 ... really needed
\everycr\expandafter{\the\everycr\dostoptagged\dostarttagged\t!tabulaterow\empty}%
@@ -2452,4 +2447,10 @@
%D \stopwhatever
%D \stoptyping
+%D This is needed because we soemtimes use the english command in
+%D tracing macros. In fact, most detailed tracing macros that
+%D are done with \LUA\ only work in the english interface anyway.
+
+\definetabulate[tabulate] \setuptabulate[tabulate][\c!format=\v!none] % so no \v! here
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/tabl-tsp.mkiv b/Master/texmf-dist/tex/context/base/tabl-tsp.mkiv
index 0138697af8e..64ab94a67da 100644
--- a/Master/texmf-dist/tex/context/base/tabl-tsp.mkiv
+++ b/Master/texmf-dist/tex/context/base/tabl-tsp.mkiv
@@ -195,7 +195,7 @@
\normalexpanded{\egroup\noexpand\edef\noexpand\extrasplitfloatlines{\the\noflines}}%
\global\settrue\usesamefloatnumber
\else
- \doifnumberelse\extrasplitfloatlines\donothing{\def\extrasplitfloatlines{1}}%
+ \doifelsenumber\extrasplitfloatlines\donothing{\def\extrasplitfloatlines{1}}%
\fi}
\unexpanded\def\doifnotinsidesplitfloat
diff --git a/Master/texmf-dist/tex/context/base/tabl-xtb.lua b/Master/texmf-dist/tex/context/base/tabl-xtb.lua
index 5728b80e95f..bddd627adce 100644
--- a/Master/texmf-dist/tex/context/base/tabl-xtb.lua
+++ b/Master/texmf-dist/tex/context/base/tabl-xtb.lua
@@ -24,13 +24,16 @@ this mechamism will be improved so that it can replace its older cousin.
]]--
-- todo: use linked list instead of r/c array
+-- todo: we can use the sum of previously forced widths for column spans
-local tonumber = tonumber
+local tonumber, next = tonumber, next
local commands = commands
local context = context
local tex = tex
+local implement = interfaces.implement
+
local texgetcount = tex.getcount
local texsetcount = tex.setcount
local texgetdimen = tex.getdimen
@@ -41,10 +44,13 @@ local format = string.format
local concat = table.concat
local points = number.points
+local todimen = string.todimen
+
local context_beginvbox = context.beginvbox
local context_endvbox = context.endvbox
local context_blank = context.blank
local context_nointerlineskip = context.nointerlineskip
+local context_dummyxcell = context.dummyxcell
local variables = interfaces.variables
@@ -83,6 +89,11 @@ local v_repeat = variables["repeat"]
local v_max = variables.max
local v_fixed = variables.fixed
local v_auto = variables.auto
+local v_before = variables.before
+local v_after = variables.after
+local v_both = variables.both
+local v_samepage = variables.samepage
+local v_tight = variables.tight
local xtables = { }
typesetters.xtables = xtables
@@ -110,36 +121,40 @@ local stack, data = { }, nil
function xtables.create(settings)
table.insert(stack,data)
- local rows = { }
- local widths = { }
- local heights = { }
- local depths = { }
- local spans = { }
- local distances = { }
- local autowidths = { }
- local modes = { }
- local fixedrows = { }
- local fixedcolumns = { }
- local frozencolumns = { }
- local options = { }
+ local rows = { }
+ local widths = { }
+ local heights = { }
+ local depths = { }
+ local spans = { }
+ local distances = { }
+ local autowidths = { }
+ local modes = { }
+ local fixedrows = { }
+ local fixedcolumns = { }
+ -- local fixedcspans = { }
+ local frozencolumns = { }
+ local options = { }
+ local rowproperties = { }
data = {
- rows = rows,
- widths = widths,
- heights = heights,
- depths = depths,
- spans = spans,
- distances = distances,
- modes = modes,
- autowidths = autowidths,
- fixedrows = fixedrows,
- fixedcolumns = fixedcolumns,
- frozencolumns = frozencolumns,
- options = options,
- nofrows = 0,
- nofcolumns = 0,
- currentrow = 0,
- currentcolumn = 0,
- settings = settings or { },
+ rows = rows,
+ widths = widths,
+ heights = heights,
+ depths = depths,
+ spans = spans,
+ distances = distances,
+ modes = modes,
+ autowidths = autowidths,
+ fixedrows = fixedrows,
+ fixedcolumns = fixedcolumns,
+ -- fixedcspans = fixedcspans,
+ frozencolumns = frozencolumns,
+ options = options,
+ nofrows = 0,
+ nofcolumns = 0,
+ currentrow = 0,
+ currentcolumn = 0,
+ settings = settings or { },
+ rowproperties = rowproperties,
}
local function add_zero(t,k)
t[k] = 0
@@ -155,6 +170,9 @@ function xtables.create(settings)
nx = 0,
ny = 0,
list = false,
+ wd = 0,
+ ht = 0,
+ dp = 0,
}
row[c] = cell
if c > data.nofcolumns then
@@ -180,24 +198,28 @@ function xtables.create(settings)
setmetatableindex(fixedrows,add_zero)
setmetatableindex(fixedcolumns,add_zero)
setmetatableindex(options,add_table)
+ -- setmetatableindex(fixedcspans,add_table)
+ --
+ local globaloptions = settings_to_hash(settings.option)
--
- settings.columndistance = tonumber(settings.columndistance) or 0
- settings.rowdistance = tonumber(settings.rowdistance) or 0
- settings.leftmargindistance = tonumber(settings.leftmargindistance) or 0
+ settings.columndistance = tonumber(settings.columndistance) or 0
+ settings.rowdistance = tonumber(settings.rowdistance) or 0
+ settings.leftmargindistance = tonumber(settings.leftmargindistance) or 0
settings.rightmargindistance = tonumber(settings.rightmargindistance) or 0
- settings.options = settings_to_hash(settings.option)
- settings.textwidth = tonumber(settings.textwidth) or texget("hsize")
- settings.lineheight = tonumber(settings.lineheight) or texgetdimen("lineheight")
- settings.maxwidth = tonumber(settings.maxwidth) or settings.textwidth/8
+ settings.options = globaloptions
+ settings.textwidth = tonumber(settings.textwidth) or texget("hsize")
+ settings.lineheight = tonumber(settings.lineheight) or texgetdimen("lineheight")
+ settings.maxwidth = tonumber(settings.maxwidth) or settings.textwidth/8
-- if #stack > 0 then
-- settings.textwidth = texget("hsize")
-- end
data.criterium_v = 2 * data.settings.lineheight
data.criterium_h = .75 * data.settings.textwidth
-
+ --
+ data.tight = globaloptions[v_tight] and true or false
end
-function xtables.initialize_reflow_width(option)
+function xtables.initialize_reflow_width(option,width)
local r = data.currentrow
local c = data.currentcolumn + 1
local drc = data.rows[r][c]
@@ -218,8 +240,7 @@ function xtables.initialize_reflow_width(option)
data.currentcolumn = c
end
--- local function rather_fixed(n)
--- for n in node.
+-- todo: we can better set the cell values in one go
function xtables.set_reflow_width()
local r = data.currentrow
@@ -234,50 +255,105 @@ function xtables.set_reflow_width()
--
drc.list = true -- we don't need to keep the content around as we're in trial mode (no: copy_node_list(tb))
--
- local widths, width = data.widths, getfield(tb,"width")
- if width > widths[c] then
- widths[c] = width
- end
- local heights, height = data.heights, getfield(tb,"height")
- if height > heights[r] then
- heights[r] = height
+ local width = getfield(tb,"width")
+ local height = getfield(tb,"height")
+ local depth = getfield(tb,"depth")
+ --
+ local widths = data.widths
+ local heights = data.heights
+ local depths = data.depths
+ local cspan = drc.nx
+ if cspan < 2 then
+ if width > widths[c] then
+ widths[c] = width
+ end
+ else
+ local options = data.options[r][c]
+ if data.tight then
+ -- no check
+ elseif not options then
+ if width > widths[c] then
+ widths[c] = width
+ end
+ elseif not options[v_tight] then
+ if width > widths[c] then
+ widths[c] = width
+ end
+ end
end
- local depths, depth = data.depths, getfield(tb,"depth")
- if depth > depths[r] then
- depths[r] = depth
+ -- if cspan > 1 then
+ -- local f = data.fixedcspans[c]
+ -- local w = f[cspan] or 0
+ -- if width > w then
+ -- f[cspan] = width -- maybe some day a solution for autospanmax and so
+ -- end
+ -- end
+ if drc.ny < 2 then
+ if height > heights[r] then
+ heights[r] = height
+ end
+ if depth > depths[r] then
+ depths[r] = depth
+ end
end
--
+ drc.wd = width
+ drc.ht = height
+ drc.dp = depth
+ --
local dimensionstate = texgetcount("frameddimensionstate")
local fixedcolumns = data.fixedcolumns
local fixedrows = data.fixedrows
if dimensionstate == 1 then
- if width > fixedcolumns[c] then -- how about a span here?
- fixedcolumns[c] = width
- end
+ if cspan > 1 then
+ -- ignore width
+ elseif width > fixedcolumns[c] then -- how about a span here?
+ fixedcolumns[c] = width
+ end
elseif dimensionstate == 2 then
fixedrows[r] = height
elseif dimensionstate == 3 then
fixedrows[r] = height -- width
fixedcolumns[c] = width -- height
- elseif data.options[v_auto] then -- new per 5/5/2014
- data.autowidths[c] = true
- else
- -- no dimensions are set in the cell
- if width <= data.criterium_h and height >= data.criterium_v then
- -- somewhat tricky branch
- if width > fixedcolumns[c] then -- how about a span here?
- -- maybe an image, so let's fix
- fixedcolumns[c] = width
- end
- else
- -- safeguard as it could be text that can be recalculated
- -- and the previous branch could have happened in a previous
- -- row and then forces a wrong one-liner in a multiliner
- if width > fixedcolumns[c] then
- data.autowidths[c] = true -- new per 5/5/2014
- end
+ elseif width <= data.criterium_h and height >= data.criterium_v then
+ -- somewhat tricky branch
+ if width > fixedcolumns[c] then -- how about a span here?
+ -- maybe an image, so let's fix
+ fixedcolumns[c] = width
end
end
+--
+-- -- this fails so not good enough predictor
+--
+-- -- \startxtable
+-- -- \startxrow
+-- -- \startxcell knuth \stopxcell
+-- -- \startxcell \input knuth \stopxcell
+-- -- \stopxrow
+--
+-- else
+-- local o = data.options[r][c]
+-- if o and o[v_auto] then -- new per 5/5/2014 - removed per 15/07/2014
+-- data.autowidths[c] = true
+-- else
+-- -- no dimensions are set in the cell
+-- if width <= data.criterium_h and height >= data.criterium_v then
+-- -- somewhat tricky branch
+-- if width > fixedcolumns[c] then -- how about a span here?
+-- -- maybe an image, so let's fix
+-- fixedcolumns[c] = width
+-- end
+-- else
+-- -- safeguard as it could be text that can be recalculated
+-- -- and the previous branch could have happened in a previous
+-- -- row and then forces a wrong one-liner in a multiliner
+-- if width > fixedcolumns[c] then
+-- data.autowidths[c] = true -- new per 5/5/2014 - removed per 15/07/2014
+-- end
+-- end
+-- end
+-- end
+--
--
drc.dimensionstate = dimensionstate
--
@@ -324,7 +400,6 @@ function xtables.initialize_reflow_height()
end
texsetdimen("d_tabl_x_width",w)
local dimensionstate = drc.dimensionstate or 0
--- print(r,c,w,data.autowidths[c])
if dimensionstate == 1 or dimensionstate == 3 then
-- width was fixed so height is known
texsetcount("c_tabl_x_skip_mode",1)
@@ -334,6 +409,8 @@ function xtables.initialize_reflow_height()
elseif data.autowidths[c] then
-- width has changed so we need to recalculate the height
texsetcount("c_tabl_x_skip_mode",0)
+ elseif data.fixedcolumns[c] then
+ texsetcount("c_tabl_x_skip_mode",0) -- new
else
texsetcount("c_tabl_x_skip_mode",1)
end
@@ -347,18 +424,30 @@ function xtables.set_reflow_height()
-- while row[c].span do -- we could adapt drc.nx instead
-- c = c + 1
-- end
- local tb = getbox("b_tabl_x")
+ local tb = getbox("b_tabl_x")
local drc = row[c]
- if data.fixedrows[r] == 0 then -- and drc.dimensionstate < 2
- local heights, height = data.heights, getfield(tb,"height")
- if height > heights[r] then
- heights[r] = height
- end
- local depths, depth = data.depths, getfield(tb,"depth")
- if depth > depths[r] then
- depths[r] = depth
+ --
+ local width = getfield(tb,"width")
+ local height = getfield(tb,"height")
+ local depth = getfield(tb,"depth")
+ --
+ if drc.ny < 2 then
+ if data.fixedrows[r] == 0 then -- and drc.dimensionstate < 2
+ local heights = data.heights
+ local depths = data.depths
+ if height > heights[r] then
+ heights[r] = height
+ end
+ if depth > depths[r] then
+ depths[r] = depth
+ end
end
end
+ --
+ drc.wd = width
+ drc.ht = height
+ drc.dp = depth
+ --
-- c = c + drc.nx - 1
-- data.currentcolumn = c
end
@@ -372,23 +461,35 @@ function xtables.initialize_construct()
c = c + 1
end
data.currentcolumn = c
- local widths = data.widths
+ local widths = data.widths
local heights = data.heights
- local depths = data.depths
- local w = widths[c]
- local h = heights[r]
- local d = depths[r]
+ local depths = data.depths
+ --
local drc = row[c]
+ local wd = drc.wd
+ local ht = drc.ht
+ local dp = drc.dp
+ --
+ local width = widths[c]
+ local height = heights[r]
+ local depth = depths[r]
+ --
for x=1,drc.nx-1 do
- w = w + widths[c+x]
+ width = width + widths[c+x]
end
- for y=1,drc.ny-1 do
- h = h + heights[r+y]
- d = d + depths[r+y]
+ --
+ local total = height + depth
+ local ny = drc.ny
+ if ny > 1 then
+ for y=1,ny-1 do
+ local nxt = r + y
+ total = total + heights[nxt] + depths[nxt]
+ end
end
- texsetdimen("d_tabl_x_width",w)
- texsetdimen("d_tabl_x_height",h + d)
- texsetdimen("d_tabl_x_depth",0)
+ --
+ texsetdimen("d_tabl_x_width",width)
+ texsetdimen("d_tabl_x_height",total)
+ texsetdimen("d_tabl_x_depth",0) -- for now
end
function xtables.set_construct()
@@ -401,8 +502,7 @@ function xtables.set_construct()
-- end
local drc = row[c]
-- this will change as soon as in luatex we can reset a box list without freeing
--- drc.list = copy_node_list(getbox("b_tabl_x"))
-drc.list = takebox("b_tabl_x")
+ drc.list = takebox("b_tabl_x")
-- c = c + drc.nx - 1
-- data.currentcolumn = c
end
@@ -435,6 +535,8 @@ function xtables.reflow_width()
local maxwidth = settings.maxwidth
-- calculate width
local widths = data.widths
+ local heights = data.heights
+ local depths = data.depths
local distances = data.distances
local autowidths = data.autowidths
local fixedcolumns = data.fixedcolumns
@@ -448,6 +550,7 @@ function xtables.reflow_width()
showwidths("stage 1",widths,autowidths)
end
local noffrozen = 0
+ -- inspect(data.fixedcspans)
if options[v_max] then
for c=1,nofcolumns do
width = width + widths[c]
@@ -570,16 +673,50 @@ function xtables.reflow_width()
--
data.currentrow = 0
data.currentcolumn = 0
+ --
+-- inspect(data)
end
function xtables.reflow_height()
data.currentrow = 0
data.currentcolumn = 0
local settings = data.settings
+ --
+ -- analyze ny
+ --
+ local nofrows = data.nofrows
+ local nofcolumns = data.nofcolumns
+ local widths = data.widths
+ local heights = data.heights
+ local depths = data.depths
+ --
+ for r=1,nofrows do
+ for c=1,nofcolumns do
+ local drc = data.rows[r][c]
+ if drc then
+ local ny = drc.ny
+ if ny > 1 then
+ local height = heights[r]
+ local depth = depths[r]
+ local total = height + depth
+ local htdp = drc.ht + drc.dp
+ for y=1,ny-1 do
+ local nxt = r + y
+ total = total + heights[nxt] + depths[nxt]
+ end
+ local delta = htdp - total
+ if delta > 0 then
+ delta = delta / ny
+ for y=1,ny do
+ heights[y] = heights[y] + delta
+ end
+ end
+ end
+ end
+ end
+ end
+ --
if settings.options[v_height] then
- local heights = data.heights
- local depths = data.depths
- local nofrows = data.nofrows
local totalheight = 0
local totaldepth = 0
for i=1,nofrows do
@@ -597,6 +734,8 @@ function xtables.reflow_height()
end
end
end
+ --
+-- inspect(data)
end
local function showspans(data)
@@ -636,6 +775,7 @@ function xtables.construct()
local rowdistance = settings.rowdistance
local leftmargindistance = settings.leftmargindistance
local rightmargindistance = settings.rightmargindistance
+ local rowproperties = data.rowproperties
-- ranges can be mixes so we collect
if trace_xtable then
@@ -728,14 +868,33 @@ function xtables.construct()
result[nofr][4] = true
end
nofr = nofr + 1
+ local rp = rowproperties[r]
+ -- we have a direction issue here but hpack_node_list(list,0,"exactly","TLT") cannot be used
+ -- due to the fact that we need the width
+ local hbox = hpack_node_list(list)
+ setfield(hbox,"dir","TLT")
result[nofr] = {
- hpack_node_list(list),
+ hbox,
size,
i < nofrange and rowdistance > 0 and rowdistance or false, -- might move
- false
+ false,
+ rp and rp.samepage or false,
}
end
end
+ if nofr > 0 then
+ -- the [5] slot gets the after break
+ result[1] [5] = false
+ result[nofr][5] = false
+ for i=2,nofr-1 do
+ local r = result[i]
+ if r == v_both or r == v_before then
+ result[i-1][5] = true
+ elseif r == v_after then
+ result[i][5] = true
+ end
+ end
+ end
return result
end
local body = collect_range(ranges[body_mode])
@@ -769,8 +928,14 @@ local function inject(row,copy,package)
context_nointerlineskip() -- figure out a better way
if row[4] then
-- nothing as we have a span
+ elseif row[5] then
+ if row[3] then
+ context_blank { v_samepage, row[3] .. "sp" }
+ else
+ context_blank { v_samepage }
+ end
elseif row[3] then
- context_blank(row[3] .. "sp") -- why blank ?
+ context_blank { row[3] .. "sp" } -- why blank ?
else
context(tonode(new_glue(0)))
end
@@ -823,23 +988,23 @@ local function spanheight(body,i)
end
function xtables.flush(directives) -- todo split by size / no inbetween then .. glue list kern blank
- local vsize = directives.vsize
- local method = directives.method or v_normal
- local settings = data.settings
- local results = data.results
- local rowdistance = settings.rowdistance
- local head = results[head_mode]
- local foot = results[foot_mode]
- local more = results[more_mode]
- local body = results[body_mode]
+ local height = directives.height
+ local method = directives.method or v_normal
+ local settings = data.settings
+ local results = data.results
+ local rowdistance = settings.rowdistance
+ local head = results[head_mode]
+ local foot = results[foot_mode]
+ local more = results[more_mode]
+ local body = results[body_mode]
local repeatheader = settings.header == v_repeat
local repeatfooter = settings.footer == v_repeat
- if vsize and vsize > 0 then
+ if height and height > 0 then
context_beginvbox()
local bodystart = data.bodystart or 1
local bodystop = data.bodystop or #body
if bodystart > 0 and bodystart <= bodystop then
- local bodysize = vsize
+ local bodysize = height
local footsize = total(foot,rowdistance)
local headsize = total(head,rowdistance)
local moresize = total(more,rowdistance)
@@ -926,7 +1091,7 @@ function xtables.flush(directives) -- todo split by size / no inbetween then ..
texsetcount("global","c_tabl_x_state",2)
end
else
- if firstsize > vsize then
+ if firstsize > height then
-- get rid of the too large cell
for s=1,firstspans do
inject(body[bodystart])
@@ -950,13 +1115,13 @@ function xtables.flush(directives) -- todo split by size / no inbetween then ..
inject(head[i],false,true)
end
if #head > 0 and rowdistance > 0 then
- context_blank(rowdistance .. "sp")
+ context_blank { rowdistance .. "sp" }
end
for i=1,#body do
inject(body[i],false,true)
end
if #foot > 0 and rowdistance > 0 then
- context_blank(rowdistance .. "sp")
+ context_blank { rowdistance .. "sp" }
end
for i=1,#foot do
inject(foot[i],false,true)
@@ -1014,28 +1179,71 @@ function xtables.cleanup()
data = table.remove(stack)
end
-function xtables.next_row()
+function xtables.next_row(specification)
local r = data.currentrow + 1
data.modes[r] = texgetcount("c_tabl_x_mode")
data.currentrow = r
data.currentcolumn = 0
+ data.rowproperties[r] = specification
+end
+
+function xtables.finish_row()
+ local n = data.nofcolumns - data.currentcolumn
+ if n > 0 then
+ -- message
+ for i=1,n do
+ context_dummyxcell()
+ end
+ end
end
-- eventually we might only have commands
-commands.x_table_create = xtables.create
-commands.x_table_reflow_width = xtables.reflow_width
-commands.x_table_reflow_height = xtables.reflow_height
-commands.x_table_construct = xtables.construct
-commands.x_table_flush = xtables.flush
-commands.x_table_cleanup = xtables.cleanup
-commands.x_table_next_row = xtables.next_row
-commands.x_table_init_reflow_width = xtables.initialize_reflow_width
-commands.x_table_init_reflow_height = xtables.initialize_reflow_height
-commands.x_table_init_construct = xtables.initialize_construct
-commands.x_table_set_reflow_width = xtables.set_reflow_width
-commands.x_table_set_reflow_height = xtables.set_reflow_height
-commands.x_table_set_construct = xtables.set_construct
+implement {
+ name = "x_table_create",
+ actions = xtables.create,
+ arguments = {
+ {
+ { "option" },
+ { "textwidth", "dimen" },
+ { "textheight", "dimen" },
+ { "maxwidth", "dimen" },
+ { "lineheight", "dimen" },
+ { "columndistance", "dimen" },
+ { "leftmargindistance", "dimen" },
+ { "rightmargindistance", "dimen" },
+ { "rowdistance", "dimen" },
+ { "header" },
+ { "footer" },
+ }
+ }
+}
+
+implement {
+ name = "x_table_flush",
+ actions = xtables.flush,
+ arguments = {
+ {
+ { "method" },
+ { "height", "dimen" }
+ }
+ }
+}
-commands.x_table_r = function() context(data.currentrow or 0) end
-commands.x_table_c = function() context(data.currentcolumn or 0) end
+implement { name = "x_table_reflow_width", actions = xtables.reflow_width }
+implement { name = "x_table_reflow_height", actions = xtables.reflow_height }
+implement { name = "x_table_construct", actions = xtables.construct }
+implement { name = "x_table_cleanup", actions = xtables.cleanup }
+implement { name = "x_table_next_row", actions = xtables.next_row }
+implement { name = "x_table_next_row_option", actions = xtables.next_row, arguments = "string" }
+implement { name = "x_table_finish_row", actions = xtables.finish_row }
+implement { name = "x_table_init_reflow_width", actions = xtables.initialize_reflow_width }
+implement { name = "x_table_init_reflow_height", actions = xtables.initialize_reflow_height }
+implement { name = "x_table_init_reflow_width_option", actions = xtables.initialize_reflow_width, arguments = "string" }
+implement { name = "x_table_init_reflow_height_option", actions = xtables.initialize_reflow_height, arguments = "string" }
+implement { name = "x_table_init_construct", actions = xtables.initialize_construct }
+implement { name = "x_table_set_reflow_width", actions = xtables.set_reflow_width }
+implement { name = "x_table_set_reflow_height", actions = xtables.set_reflow_height }
+implement { name = "x_table_set_construct", actions = xtables.set_construct }
+implement { name = "x_table_r", actions = function() context(data.currentrow or 0) end }
+implement { name = "x_table_c", actions = function() context(data.currentcolumn or 0) end }
diff --git a/Master/texmf-dist/tex/context/base/tabl-xtb.mkvi b/Master/texmf-dist/tex/context/base/tabl-xtb.mkvi
index 06fb472cdfd..876abef8c8f 100644
--- a/Master/texmf-dist/tex/context/base/tabl-xtb.mkvi
+++ b/Master/texmf-dist/tex/context/base/tabl-xtb.mkvi
@@ -29,6 +29,8 @@
% - maybe only tag the box
% - scale to fit
%
+% - buffers permit verbatim but are not always handy
+
%D This module started as an afternoon experiment and surprisingly could be
%D mostly finished the same evening. Of course it builds upon existing
%D functionality. The main reason for writing it is that we occasionally
@@ -78,8 +80,13 @@
\let\dotagxtablesignal\relax % names will change
\appendtoks
- \def\dotagxtablecell {\taggedctxcommand{settagtablecell(\number\tablecellrows,\number\tablecellcolumns,\number\raggedstatus)}}%
- \def\dotagxtablesignal{\char\zerocount}% not used
+ \def\dotagxtablecell
+ {\clf_settagtablecell
+ \numexpr\tablecellrows\relax
+ \numexpr\tablecellcolumns\relax
+ \numexpr\raggedstatus\relax}%
+ \def\dotagxtablesignal
+ {\char\zerocount}% not used
\to \everyenableelements
\newdimen\d_tabl_x_width
@@ -96,8 +103,8 @@
\newcount\c_tabl_x_skip_mode % 1 = skip
\newdimen\d_tabl_x_textwidth
-\def\currentxtablerow {\ctxcommand{x_table_r()}}
-\def\currentxtablecolumn{\ctxcommand{x_table_c()}}
+\let\currentxtablerow \clf_x_table_r
+\let\currentxtablecolumn\clf_x_table_c
% \setupxtable[one][parent][a=b,c=d]
% \setupxtable[one] [a=b,c=d]
@@ -194,7 +201,7 @@
\unexpanded\def\tabl_x_embedded_start[#settings]#content\stopembeddedxtable
{\tabl_x_prepare{#settings}%
- \ctxcommand{assignbuffer("embedded_x_table",\!!bs\detokenize{#content}\!!es)}%
+ \clf_assignbuffer{embedded_x_table}{\detokenize{#content}}\catcodetable\relax
\bgroup
\let\tabl_x_start_table\tabl_x_process_buffer
\edef\tabl_x_current_buffer{embedded_x_table}%
@@ -216,12 +223,12 @@
\unexpanded\def\tabl_x_start_named_indeed[#settings]%
{\advance\c_tabl_x_nesting\plusone
- \dostarttagged\t!table\empty
+ \dostarttaggedchained\t!table\empty\??xtable
\iffirstargument
\setupcurrentxtable[#settings]%
\fi
\tabl_x_check_textwidth
- \forgetall
+ %\forgetall % else whitespace mess
\edef\tabl_x_current_buffer{\tabl_x_default_buffer}%
\normalexpanded{\buff_pickup{\tabl_x_current_buffer}{\e!start\currentxtable}{\e!stop\currentxtable}\relax\tabl_x_process\zerocount}}
@@ -240,15 +247,15 @@
\unexpanded\def\tabl_x_prepare#settings% assumes \iffirstargument to be set
{\advance\c_tabl_x_nesting\plusone
- \dostarttagged\t!table\empty
+ \dostarttaggedchained\t!table\empty\??xtable
\iffirstargument
\tabl_x_set_checked{#settings}%
\fi
\tabl_x_check_textwidth
- \forgetall}
+ }% else whitespace mess
\def\tabl_x_get_buffer
- {\ctxcommand{gettexbuffer("\tabl_x_current_buffer")}}
+ {\clf_gettexbuffer{\tabl_x_current_buffer}}
\let\tabl_x_start_row_yes \relax
\let\tabl_x_start_row_nop \relax
@@ -259,23 +266,24 @@
\unexpanded\def\tabl_x_process
{\begingroup % *
- \doifsomething{\xtableparameter\c!bodyfont}
- {\setupbodyfont[\xtableparameter\c!bodyfont]}%
+ \forgetall % moved here
+ \dontcomplain % for the moment here till we figure out where we get the overflow
+ \usebodyfontparameter\xtableparameter
\setbox\scratchbox\vbox
- {\xtableparameter\c!spaceinbetween}%
- \ctxcommand{x_table_create {
- option = "\xtableparameter\c!option",
- textwidth = \number\d_tabl_x_textwidth,
- textheight = \number\dimexpr\xtableparameter\c!textheight,
- maxwidth = \number\dimexpr\xtableparameter\c!maxwidth,
- lineheight = \number\openlineheight,
- columndistance = \number\dimexpr\xtableparameter\c!columndistance,
- leftmargindistance = \number\dimexpr\xtableparameter\c!leftmargindistance,
- rightmargindistance = \number\dimexpr\xtableparameter\c!rightmargindistance,
- rowdistance = \number\ht\scratchbox,
- header = "\xtableparameter\c!header",
- footer = "\xtableparameter\c!footer",
- } }%
+ {\doifsomething{\xtableparameter\c!spaceinbetween}{\blank[\xtableparameter\c!spaceinbetween]}}%
+ \clf_x_table_create
+ option {\xtableparameter\c!option}%
+ textwidth \d_tabl_x_textwidth
+ textheight \dimexpr\xtableparameter\c!textheight\relax
+ maxwidth \dimexpr\xtableparameter\c!maxwidth\relax
+ lineheight \openlineheight
+ columndistance \dimexpr\xtableparameter\c!columndistance\relax
+ leftmargindistance \dimexpr\xtableparameter\c!leftmargindistance\relax
+ rightmargindistance \dimexpr\xtableparameter\c!rightmargindistance\relax
+ rowdistance \ht\scratchbox
+ header {\xtableparameter\c!header}%
+ footer {\xtableparameter\c!footer}%
+ \relax
%
\letxtableparameter\c!option\empty
% not so nice but needed as we use this in the setup
@@ -290,7 +298,7 @@
\let\tabl_x_stop_cell \tabl_x_stop_cell_reflow_width
\settrialtypesetting
\tabl_x_get_buffer
- \ctxcommand{x_table_reflow_width()}\relax
+ \clf_x_table_reflow_width
\endgroup
\begingroup
\let\tabl_x_start_row_yes \tabl_x_start_row_reflow_height_yes
@@ -301,7 +309,7 @@
\let\tabl_x_stop_cell \tabl_x_stop_cell_reflow_height
\settrialtypesetting
\tabl_x_get_buffer
- \ctxcommand{x_table_reflow_height()}\relax
+ \clf_x_table_reflow_height
\endgroup
\begingroup
\let\tabl_x_start_row_yes \tabl_x_start_row_construct_yes
@@ -311,7 +319,7 @@
\let\tabl_x_start_cell_nop\tabl_x_start_cell_construct_nop
\let\tabl_x_stop_cell \tabl_x_stop_cell_construct
\tabl_x_get_buffer
- \ctxcommand{x_table_construct()}\relax
+ \clf_x_table_construct
\endgroup
\endgroup % *
\ifinsidesplitfloat
@@ -321,7 +329,7 @@
\else
\tabl_x_flush_text_checked
\fi\fi
- \ctxcommand{x_table_cleanup()}%
+ \clf_x_table_cleanup
\dostoptagged
\resetbuffer[\tabl_x_current_buffer]%
\egroup}
@@ -336,19 +344,27 @@
% in text flow: headers and footers only once
\setvalue{\??xtableflushsplit\v!yes}%
- {\ctxcommand{x_table_flush{ method = "\v!split" }}}
+ {\clf_x_table_flush
+ method {\v!split}%
+ \relax}
% in text flow: headers and footers only once
\setvalue{\??xtableflushsplit\v!no}%
- {\dontleavehmode % else no leftskip etc
- \ctxcommand{x_table_flush{ method = "\v!normal" }}}
+ {\noindent % \dontleavehmode % else no leftskip etc
+ \clf_x_table_flush
+ method {\v!normal}%
+ \relax
+ \removeunwantedspaces}
% in text flow: headers and footers get repeated
\setvalue{\??xtableflushsplit\v!repeat}%
{\doloop
- {\ctxcommand{x_table_flush{ method = "\v!split", vsize = \number\ifdim\pagegoal=\maxdimen\textheight\else\pagegoal\fi }}%
+ {\clf_x_table_flush
+ method {\v!split}%
+ height \ifdim\pagegoal=\maxdimen\textheight\else\pagegoal\fi
+ \relax
\ifcase\c_tabl_x_state
\exitloop
\else
@@ -370,7 +386,10 @@
% \stopsetups
%
% \unexpanded\def\xtablesplitflush
-% {\ctxcommand{x_table_flush{ method = "\v!split", vsize = \number\dimexpr\xtablesplitvsize\relax}}\relax}
+% {\clf_x_table_flush
+% method {\v!split}%
+% height \dimexpr\xtablesplitvsize\relax
+% \relax}
%
% \def\xtablesplitvsize
% {\ifdim\pagegoal=\maxdimen\textheight\else\pagegoal\fi}
@@ -380,7 +399,9 @@
\let\extratxtablesplitheight\zeropoint % might disappear so don't depend on it
\unexpanded\def\tabl_x_flush_float_normal
- {\ctxcommand{x_table_flush{ method = "\v!normal" }}}
+ {\clf_x_table_flush
+ method {\v!normal}%
+ \relax}
\unexpanded\def\tabl_x_flush_float_split
{\resetdirecttsplit
@@ -391,9 +412,12 @@
\let\tsplitdirectwidth \d_tabl_x_final_width
\handledirecttsplit}
-\unexpanded\def\tabl_x_split_splitter#vsize%
+\unexpanded\def\tabl_x_split_splitter#height%
{\setbox\tsplitresult\vbox
- {\ctxcommand{x_table_flush{ method = "\v!split", vsize = \number\dimexpr#vsize }}}%
+ {\clf_x_table_flush
+ method {\v!split}%
+ height \dimexpr#height\relax
+ \relax}%
\ifcase\c_tabl_x_state
\global\setfalse\somenextsplitofffloat
\else
@@ -402,14 +426,14 @@
\unexpanded\def\startxrow
{\begingroup
- \doifnextoptionalcselse\tabl_x_start_row_yes\tabl_x_start_row_nop}
+ \doifelsenextoptionalcs\tabl_x_start_row_yes\tabl_x_start_row_nop}
\unexpanded\def\tabl_x_start_row_reflow_width_yes[#settings]%
{\setupcurrentxtable[#settings]%
- \ctxcommand{x_table_next_row()}}
+ \clf_x_table_next_row}
\unexpanded\def\tabl_x_start_row_reflow_width_nop
- {\ctxcommand{x_table_next_row()}}
+ {\clf_x_table_next_row}
\unexpanded\def\tabl_x_stop_row_reflow_width
{}
@@ -421,27 +445,36 @@
\unexpanded\def\tabl_x_start_row_construct_yes[#settings]%
{\setupcurrentxtable[#settings]%
\dostarttagged\t!tablerow\empty
- \ctxcommand{x_table_next_row()}}
+ \clf_x_table_next_row_option{\xtableparameter\c!samepage}}
\unexpanded\def\tabl_x_start_row_construct_nop
{\dostarttagged\t!tablerow\empty
- \ctxcommand{x_table_next_row()}}
+ \clf_x_table_next_row}
\unexpanded\def\tabl_x_stop_row_construct
- {\dostoptagged}
+ {\clf_x_table_finish_row
+ \dostoptagged}
\unexpanded\def\stopxrow
{\tabl_x_stop_row
\endgroup}
\unexpanded\def\startxcell
- {\doifnextoptionalcselse\tabl_x_start_cell_yes\tabl_x_start_cell_nop}
+ {\doifelsenextoptionalcs\tabl_x_start_cell_yes\tabl_x_start_cell_nop}
\unexpanded\def\stopxcell
{\tabl_x_stop_cell}
+\unexpanded\def\dummyxcell#1%
+ {\tabl_x_start_cell_nop
+ \tabl_x_stop_cell}
+
+\unexpanded\def\dummyxcell
+ {\tabl_x_start_cell_nop
+ \tabl_x_stop_cell}
+
\unexpanded\def\tabl_x_begin_of_cell
- {\inhibitblank
+ {%\inhibitblank % already in framed
\everypar{\delayedbegstrut}}
\unexpanded\def\tabl_x_end_of_cell
@@ -467,8 +500,16 @@
% Although this becomes kind of messy. It saves already time that we only check
% for it when we have settings.
-\def\tabl_x_set_hsize
- {\hsize.25\maxdimen} % let's be reasonable
+% \def\tabl_x_set_hsize
+% {\hsize.25\maxdimen} % let's be reasonable
+
+% \def\tabl_x_set_hsize
+% {\edef\p_width{\xtableparameter\c!width}%
+% \ifx\p_width\empty
+% \hsize.25\maxdimen % is this really needed
+% \fi}
+
+\let\tabl_x_set_hsize\relax
\unexpanded\def\tabl_x_start_cell_reflow_width_yes[#settings]%
{\setbox\b_tabl_x\hbox\bgroup
@@ -494,7 +535,7 @@
\fi
%
\d_tabl_x_distance\xtableparameter\c!distance\relax
- \ctxcommand{x_table_init_reflow_width("\xtableparameter\c!option")}%
+ \clf_x_table_init_reflow_width_option{\xtableparameter\c!option}%
\inheritedxtableframed\bgroup
\tabl_x_begin_of_cell
\tabl_x_set_hsize}
@@ -508,7 +549,7 @@
\c_tabl_x_nx\plusone
\c_tabl_x_ny\plusone
\d_tabl_x_distance\xtableparameter\c!distance\relax
- \ctxcommand{x_table_init_reflow_width()}%
+ \clf_x_table_init_reflow_width
\inheritedxtableframed\bgroup
\tabl_x_begin_of_cell
\tabl_x_set_hsize}
@@ -517,11 +558,11 @@
{\tabl_x_end_of_cell
\egroup
\egroup
- \ctxcommand{x_table_set_reflow_width()}}
+ \clf_x_table_set_reflow_width}
\unexpanded\def\tabl_x_start_cell_reflow_height_yes[#settings]%
{\setbox\b_tabl_x\hbox\bgroup
- \ctxcommand{x_table_init_reflow_height()}%
+ \clf_x_table_init_reflow_height
\ifcase\c_tabl_x_skip_mode % can be sped up
\ifnum\c_tabl_x_nesting>\plusone
\letxtableparameter\c!height\v!fit % overloads given height
@@ -535,7 +576,7 @@
\unexpanded\def\tabl_x_start_cell_reflow_height_nop
{\setbox\b_tabl_x\hbox\bgroup
- \ctxcommand{x_table_init_reflow_height()}%
+ \clf_x_table_init_reflow_height
\ifcase\c_tabl_x_skip_mode % can be sped up
\ifnum\c_tabl_x_nesting>\plusone
\letxtableparameter\c!height\v!fit % overloads given height
@@ -552,7 +593,7 @@
\egroup
\fi
\egroup
- \ctxcommand{x_table_set_reflow_height()}}
+ \clf_x_table_set_reflow_height}
\unexpanded\def\tabl_x_start_cell_construct_yes[#settings]%
{\dostarttagged\t!tablecell\empty % can't we just tag the box
@@ -560,7 +601,7 @@
\setupcurrentxtable[#settings]%
\letxtableparameter\c!width \d_tabl_x_width % overloads given width
\letxtableparameter\c!height\d_tabl_x_height % overloads given height
- \ctxcommand{x_table_init_construct()}%
+ \clf_x_table_init_construct
\inheritedxtableframed\bgroup
\tabl_x_begin_of_cell
\dotagxtablecell}
@@ -570,7 +611,7 @@
\setbox\b_tabl_x\hbox\bgroup
\letxtableparameter\c!width \d_tabl_x_width % overloads given width
\letxtableparameter\c!height\d_tabl_x_height % overloads given height (commenting it ... nice option)
- \ctxcommand{x_table_init_construct()}%
+ \clf_x_table_init_construct
\inheritedxtableframed\bgroup
\tabl_x_begin_of_cell
\dotagxtablecell}
@@ -580,7 +621,7 @@
\egroup
\dotagxtablesignal % harmless spot
\egroup
- \ctxcommand{x_table_set_construct()}%
+ \clf_x_table_set_construct
\dostoptagged}
\unexpanded\def\startxcellgroup
@@ -677,7 +718,7 @@
\unexpanded\def\startxgroup
{\begingroup
- \doifnextoptionalcselse\tabl_x_start_group_delayed_one\relax}
+ \doifelsenextoptionalcs\tabl_x_start_group_delayed_one\relax}
\unexpanded\def\stopxgroup
{\endgroup}
@@ -695,7 +736,7 @@
\chaintocurrentxtable{#tag}%
\fi
\edef\currentxtable{#tag}%
- \doifnextoptionalcselse\setupcurrentxtable\relax}
+ \doifelsenextoptionalcs\setupcurrentxtable\relax}
\let\startxrowgroup \startxgroup
\let\stopxrowgroup \stopxgroup
@@ -706,7 +747,7 @@
\unexpanded\def\startxcell
{\begingroup
- \doifnextoptionalcselse\tabl_x_start_cell_delayed_one\tabl_x_start_cell_nop}
+ \doifelsenextoptionalcs\tabl_x_start_cell_delayed_one\tabl_x_start_cell_nop}
\unexpanded\def\tabl_x_start_cell_delayed_one[#tag]%
% {\ifcsname\namedxtablehash{#tag}\s!parent\endcsname
@@ -721,7 +762,7 @@
\chaintocurrentxtable{#tag}%
\fi
\edef\currentxtable{#tag}%
- \doifnextoptionalcselse\tabl_x_start_cell_yes\tabl_x_start_cell_nop}
+ \doifelsenextoptionalcs\tabl_x_start_cell_yes\tabl_x_start_cell_nop}
\unexpanded\def\stopxcell
{\tabl_x_stop_cell
@@ -731,7 +772,7 @@
\unexpanded\def\startxrow
{\begingroup
- \doifnextoptionalcselse\tabl_x_start_row_delayed_one\tabl_x_start_row_nop}
+ \doifelsenextoptionalcs\tabl_x_start_row_delayed_one\tabl_x_start_row_nop}
\unexpanded\def\tabl_x_start_row_delayed_one[#tag]%
% {\ifcsname\namedxtablehash{#tag}\s!parent\endcsname
@@ -746,7 +787,7 @@
\chaintocurrentxtable{#tag}%
\fi
\edef\currentxtable{#tag}%
- \doifnextoptionalcselse\tabl_x_start_row_yes\tabl_x_start_row_nop}
+ \doifelsenextoptionalcs\tabl_x_start_row_yes\tabl_x_start_row_nop}
\unexpanded\def\stopxrow
{\tabl_x_stop_row
diff --git a/Master/texmf-dist/tex/context/base/task-ini.lua b/Master/texmf-dist/tex/context/base/task-ini.lua
index 3dc5e71b4c8..ed9989a81cc 100644
--- a/Master/texmf-dist/tex/context/base/task-ini.lua
+++ b/Master/texmf-dist/tex/context/base/task-ini.lua
@@ -21,9 +21,11 @@ local tasks = nodes.tasks
local prependaction = tasks.prependaction
local appendaction = tasks.appendaction
local disableaction = tasks.disableaction
+local enableaction = tasks.enableaction
local freezegroup = tasks.freezegroup
local freezecallbacks = callbacks.freeze
+appendaction("processors", "normalizers", "typesetters.wrappers.handler") -- disabled
appendaction("processors", "normalizers", "typesetters.characters.handler") -- always on
appendaction("processors", "normalizers", "fonts.collections.process") -- disabled
appendaction("processors", "normalizers", "fonts.checkers.missing") -- disabled
@@ -37,11 +39,13 @@ appendaction("processors", "characters", "typesetters.breakpoints.handler")
appendaction("processors", "characters", "scripts.injectors.handler") -- disabled
appendaction("processors", "words", "languages.replacements.handler") -- disabled
-appendaction("processors", "words", "builders.kernel.hyphenation") -- always on
+
+appendaction("processors", "words", "languages.hyphenators.handler") -- always on
+
appendaction("processors", "words", "languages.words.check") -- disabled -- might move up, no disc check needed then
appendaction("processors", "words", "typesetters.initials.handler") -- disabled -- might move up
-appendaction("processors", "words", "typesetters.firstlines.handler") -- disabled -- might move up
+appendaction("processors", "words", "typesetters.firstlines.handler") -- disabled -- might move down
appendaction("processors", "fonts", "builders.paragraphs.solutions.splitters.split") -- experimental
appendaction("processors", "fonts", "nodes.handlers.characters") -- maybe todo
@@ -57,10 +61,12 @@ appendaction("processors", "lists", "typesetters.spacings.handler")
appendaction("processors", "lists", "typesetters.kerns.handler") -- disabled
appendaction("processors", "lists", "typesetters.digits.handler") -- disabled (after otf handling)
appendaction("processors", "lists", "typesetters.italics.handler") -- disabled (after otf/kern handling)
-------------("processors", "lists", "typesetters.initials.handler") -- disabled
+appendaction("processors", "lists", "languages.visualizediscretionaries") -- disabled
+
+-- appendaction("processors", "lists", "typesetters.initials.handler") -- disabled
-appendaction("shipouts", "normalizers", "builders.paragraphs.expansion.trace") -- disabled
appendaction("shipouts", "normalizers", "nodes.handlers.cleanuppage") -- disabled
+appendaction("shipouts", "normalizers", "builders.paragraphs.expansion.trace") -- disabled
appendaction("shipouts", "normalizers", "typesetters.alignments.handler")
appendaction("shipouts", "normalizers", "nodes.references.handler") -- disabled
appendaction("shipouts", "normalizers", "nodes.destinations.handler") -- disabled
@@ -102,10 +108,8 @@ appendaction("math", "builders", "builders.kernel.mlist_to_hlist")
------------("math", "builders", "noads.handlers.italics", nil, "nohead") -- disabled
appendaction("math", "builders", "typesetters.directions.processmath") -- disabled (has to happen pretty late)
--- quite experimental (nodes.handlers.graphicvadjust might go away)
-
appendaction("finalizers", "lists", "builders.paragraphs.keeptogether")
-appendaction("finalizers", "lists", "nodes.handlers.graphicvadjust") -- todo
+------------("finalizers", "lists", "nodes.handlers.graphicvadjust") -- todo
appendaction("finalizers", "fonts", "builders.paragraphs.solutions.splitters.optimize") -- experimental
appendaction("finalizers", "lists", "builders.paragraphs.tag")
@@ -128,6 +132,7 @@ appendaction ("shipouts", "normalizers", "nodes.properties.delayed") -- enabl
-- speedup: only kick in when used
+disableaction("processors", "typesetters.wrappers.handler")
disableaction("processors", "languages.replacements.handler")
disableaction("processors", "typesetters.characteralign.handler")
disableaction("processors", "scripts.autofontfeature.handler")
@@ -147,6 +152,7 @@ disableaction("processors", "typesetters.firstlines.handler")
disableaction("processors", "typesetters.spacings.handler")
disableaction("processors", "typesetters.kerns.handler")
disableaction("processors", "typesetters.italics.handler")
+disableaction("processors", "languages.visualizediscretionaries")
disableaction("processors", "nodes.handlers.stripping")
disableaction("shipouts", "builders.paragraphs.expansion.trace")
@@ -164,7 +170,6 @@ disableaction("shipouts", "nodes.visualizers.handler")
disableaction("shipouts", "nodes.handlers.accessibility")
disableaction("shipouts", "nodes.handlers.backgrounds")
disableaction("shipouts", "nodes.handlers.alignbackgrounds")
-disableaction("shipouts", "nodes.handlers.cleanuppage")
disableaction("shipouts", "nodes.references.handler")
disableaction("shipouts", "nodes.destinations.handler")
@@ -177,7 +182,7 @@ disableaction("processors", "builders.paragraphs.solutions.splitters.split")
disableaction("finalizers", "builders.paragraphs.keeptogether")
disableaction("finalizers", "builders.paragraphs.solutions.splitters.optimize")
-disableaction("finalizers", "nodes.handlers.graphicvadjust") -- sort of obsolete
+-------------("finalizers", "nodes.handlers.graphicvadjust") -- sort of obsolete
disableaction("finalizers", "builders.paragraphs.tag")
disableaction("math", "noads.handlers.showtree")
@@ -216,3 +221,18 @@ freezegroup("vboxbuilders", "normalizers")
freezegroup("math", "normalizers")
freezegroup("math", "builders")
+
+-- new: disabled here
+
+disableaction("processors", "builders.kernel.ligaturing")
+disableaction("processors", "builders.kernel.kerning")
+
+directives.register("nodes.basepass", function(v)
+ if v then
+ disableaction("processors", "builders.kernel.ligaturing")
+ disableaction("processors", "builders.kernel.kerning")
+ else
+ enableaction("processors", "builders.kernel.ligaturing")
+ enableaction("processors", "builders.kernel.kerning")
+ end
+end)
diff --git a/Master/texmf-dist/tex/context/base/toks-ini.lua b/Master/texmf-dist/tex/context/base/toks-ini.lua
index 0f0c016f8e9..f8b94589040 100644
--- a/Master/texmf-dist/tex/context/base/toks-ini.lua
+++ b/Master/texmf-dist/tex/context/base/toks-ini.lua
@@ -5,338 +5,252 @@ if not modules then modules = { } end modules ['toks-ini'] = {
license = "see context related readme files"
}
-local context, commands = context, commands
-local utfbyte, utfchar, utfvalues = utf.byte, utf.char, utf.values
-local format, gsub = string.format, string.gsub
-
---[[ldx--
-
This code is experimental and needs a cleanup. The visualizers will move to
-a module.
---ldx]]--
-
--- 1 = command, 2 = modifier (char), 3 = controlsequence id
---
--- callback.register('token_filter', token.get_next)
---
--- token.get_next()
--- token.expand()
--- token.create()
--- token.csname_id()
--- token.csname_name(v)
--- token.command_id()
--- token.command_name(v)
--- token.is_expandable()
--- token.is_activechar()
--- token.lookup(v)
-
--- actually, we can use token registers to store tokens
-
-local token, tex = token, tex
-
-local createtoken = token.create
-local csname_id = token.csname_id
-local command_id = token.command_id
-local command_name = token.command_name
-local get_next = token.get_next
-local expand = token.expand
-local is_activechar = token.is_activechar
-local csname_name = token.csname_name
-
-tokens = tokens or { }
-local tokens = tokens
-
-tokens.vbox = createtoken("vbox")
-tokens.hbox = createtoken("hbox")
-tokens.vtop = createtoken("vtop")
-tokens.bgroup = createtoken(utfbyte("{"), 1)
-tokens.egroup = createtoken(utfbyte("}"), 2)
-
-tokens.letter = function(chr) return createtoken(utfbyte(chr), 11) end
-tokens.other = function(chr) return createtoken(utfbyte(chr), 12) end
-
-tokens.letters = function(str)
- local t, n = { }, 0
- for chr in utfvalues(str) do
- n = n + 1
- t[n] = createtoken(chr, 11)
- end
- return t
-end
-
-tokens.collectors = tokens.collectors or { }
-local collectors = tokens.collectors
-
-collectors.data = collectors.data or { }
-local collectordata = collectors.data
+tokens = tokens or { }
+
+local tokens = tokens
+local tostring = tostring
+local utfchar = utf.char
+local char = string.char
+local printtable = table.print
+local concat = table.concat
+
+if newtoken then
+
+ if setinspector then
+
+ local istoken = newtoken.is_token
+ local simple = { letter = "letter", other_char = "other" }
+
+ local function astable(t)
+ if t and istoken(t) then
+ local cmdname = t.cmdname
+ local simple = simple[cmdname]
+ if simple then
+ return {
+ category = simple,
+ character = utfchar(t.mode) or nil,
+ }
+ else
+ return {
+ command = t.command,
+ id = t.id,
+ tok = t.tok,
+ csname = t.csname,
+ active = t.active,
+ expandable = t.expandable,
+ protected = t.protected,
+ mode = t.mode,
+ cmdname = cmdname,
+ }
+ end
+ end
+ end
-collectors.registered = collectors.registered or { }
-local registered = collectors.registered
+ tokens.istoken = istoken
+ tokens.astable = astable
-local function printlist(data)
- callbacks.push('token_filter', function ()
- callbacks.pop('token_filter') -- tricky but the nil assignment helps
- return data
- end)
-end
+ setinspector(function(v) if istoken(v) then printtable(astable(v),tostring(v)) return true end end)
-tex.printlist = printlist -- will change to another namespace
+ end
-function collectors.flush(tag)
- printlist(collectordata[tag])
-end
+ local scan_toks = newtoken.scan_toks
+ local scan_string = newtoken.scan_string
+ local scan_int = newtoken.scan_int
+ local scan_code = newtoken.scan_code
+ local scan_dimen = newtoken.scan_dimen
+ local scan_glue = newtoken.scan_glue
+ local scan_keyword = newtoken.scan_keyword
+ local scan_token = newtoken.scan_token
+ local scan_word = newtoken.scan_word
+ local scan_number = newtoken.scan_number
-function collectors.test(tag)
- printlist(collectordata[tag])
-end
+ local get_next = newtoken.get_next
-function collectors.register(name)
- registered[csname_id(name)] = name
-end
+ local set_macro = newtoken.set_macro
-local call = command_id("call")
-local letter = command_id("letter")
-local other = command_id("other_char")
-
-function collectors.install(tag,end_cs)
- local data, d = { }, 0
- collectordata[tag] = data
- local endcs = csname_id(end_cs)
- while true do
- local t = get_next()
- local a, b = t[1], t[3]
- if b == endcs then
- context["end_cs"]()
- return
- elseif a == call and registered[b] then
- expand()
+ set_macro = function(k,v,g)
+ if g == "global" then
+ context.setgvalue(k,v or '')
else
- d = d + 1
- data[d] = t
+ context.setvalue(k,v or '')
end
end
-end
-
-function collectors.handle(tag,handle,flush)
- collectordata[tag] = handle(collectordata[tag])
- if flush then
- collectors.flush(tag)
- end
-end
-local show_methods = { }
-collectors.show_methods = show_methods
+ local bits = {
+ escape = 2^ 0,
+ begingroup = 2^ 1,
+ endgroup = 2^ 2,
+ mathshift = 2^ 3,
+ alignment = 2^ 4,
+ endofline = 2^ 5,
+ parameter = 2^ 6,
+ superscript = 2^ 7,
+ subscript = 2^ 8,
+ ignore = 2^ 9,
+ space = 2^10, -- 1024
+ letter = 2^11,
+ other = 2^12,
+ active = 2^13,
+ comment = 2^14,
+ invalid = 2^15,
+ --
+ character = 2^11 + 2^12,
+ whitespace = 2^13 + 2^10, -- / needs more checking
+ --
+ open = 2^10 + 2^1, -- space + begingroup
+ close = 2^10 + 2^2, -- space + endgroup
+ }
+
+ -- for k, v in next, bits do bits[v] = k end
+
+ tokens.bits = bits
+
+ local space_bits = bits.space
+
+ -- words are space or \relax terminated and the trailing space is gobbled; a word
+ -- can contain any non-space letter/other
+
+ local t = { } -- small optimization, a shared variable that is not reset
+
+ if scan_word then
+
+ scan_number = function(base)
+ local s = scan_word()
+ if not s then
+ return nil
+ elseif base then
+ return tonumber(s,base)
+ else
+ return tonumber(s)
+ end
+ end
-function collectors.show(tag, method)
- if type(tag) == "table" then
- show_methods[method or 'a'](tag)
else
- show_methods[method or 'a'](collectordata[tag])
- end
-end
-
-function collectors.defaultwords(t,str)
- local n = #t
- n = n + 1
- t[n] = tokens.bgroup
- n = n + 1
- t[n] = createtoken("red")
- for i=1,#str do
- n = n + 1
- t[n] = tokens.other('*')
- end
- n = n + 1
- t[n] = tokens.egroup
-end
-function collectors.dowithwords(tag,handle)
- local t, w, tn, wn = { }, { }, 0, 0
- handle = handle or collectors.defaultwords
- local tagdata = collectordata[tag]
- for k=1,#tagdata do
- local v = tagdata[k]
- if v[1] == letter then
- wn = wn + 1
- w[wn] = v[2]
- else
- if wn > 0 then
- handle(t,w)
- wn = 0
+ scan_word = function()
+ local n = 0
+ while true do
+ local c = scan_code()
+ if c then
+ n = n + 1
+ t[n] = utfchar(c)
+ elseif scan_code(space_bits) then
+ if n > 0 then
+ break
+ end
+ elseif n > 0 then
+ break
+ else
+ return
+ end
end
- tn = tn + 1
- t[tn] = v
+ return concat(t,"",1,n)
end
- end
- if wn > 0 then
- handle(t,w)
- end
- collectordata[tag] = t
-end
-local function showtoken(t)
- if t then
- local cmd, chr, id, cs, name = t[1], t[2], t[3], nil, command_name(t) or ""
- if cmd == letter or cmd == other then
- return format("%s-> %s -> %s", name, chr, utfchar(chr))
- elseif id > 0 then
- cs = csname_name(t) or nil
- if cs then
- return format("%s-> %s", name, cs)
- elseif tonumber(chr) < 0 then
- return format("%s-> %s", name, id)
+ -- so we gobble the space (like scan_int) (number has to be space or non-char terminated
+ -- as we accept 0xabcd and such so there is no clear separator for a keyword
+
+ scan_number = function(base)
+ local n = 0
+ while true do
+ local c = scan_code()
+ if c then
+ n = n + 1
+ t[n] = char(c)
+ elseif scan_code(space_bits) then
+ if n > 0 then
+ break
+ end
+ elseif n > 0 then
+ break
+ else
+ return
+ end
+ end
+ local s = concat(t,"",1,n)
+ if base then
+ return tonumber(s,base)
else
- return format("%s-> (%s,%s)", name, chr, id)
+ return tonumber(s)
end
- else
- return format("%s", name)
end
- else
- return "no node"
- end
-end
-
-collectors.showtoken = showtoken
-
-function collectors.trace()
- local t = get_next()
- logs.report("tokenlist",showtoken(t))
- return t
-end
-
--- these might move to a runtime module
-show_methods.a = function(data) -- no need to store the table, just pass directly
- local function row(one,two,three,four,five)
- context.NC() context(one)
- context.NC() context(two)
- context.NC() context(three)
- context.NC() context(four)
- context.NC() context(five)
- context.NC() context.NR()
end
- context.starttabulate { "|T|Tr|cT|Tr|T|" }
- row("cmd","chr","","id","name")
- context.HL()
- for _,v in next, data do
- local cmd, chr, id, cs, sym = v[1], v[2], v[3], "", ""
- local name = gsub(command_name(v) or "","_","\\_")
- if id > 0 then
- cs = csname_name(v) or ""
- if cs ~= "" then cs = "\\string " .. cs end
- else
- id = ""
- end
- if cmd == letter or cmd == other then
- sym = "\\char " .. chr
- end
- if tonumber(chr) < 0 then
- row(name,"",sym,id,cs)
- else
- row(name,chr,sym,id,cs)
- end
- end
- context.stoptabulate()
-end
-local function show_b_c(data,swap) -- no need to store the table, just pass directly
- local function row(one,two,three)
- context.NC() context(one)
- context.NC() context(two)
- context.NC() context(three)
- context.NC() context.NR()
- end
- if swap then
- context.starttabulate { "|Tl|Tl|Tr|" }
- else
- context.starttabulate { "|Tl|Tr|Tl|" }
- end
- row("cmd","chr","name")
- context.HL()
- for _,v in next, data do
- local cmd, chr, id, cs, sym = v[1], v[2], v[3], "", ""
- local name = gsub(command_name(v) or "","_","\\_")
- if id > 0 then
- cs = csname_name(v) or ""
- end
- if cmd == letter or cmd == other then
- sym = "\\char " .. chr
- elseif cs == "" then
- -- okay
- elseif is_activechar(v) then
- sym = "\\string " .. cs
+ -- -- the next one cannot handle \iftrue true\else false\fi
+ --
+ -- local function scan_boolean()
+ -- if scan_keyword("true") then
+ -- return true
+ -- elseif scan_keyword("false") then
+ -- return false
+ -- else
+ -- return nil
+ -- end
+ -- end
+
+ local function scan_boolean()
+ local kw = scan_word()
+ if kw == "true" then
+ return true
+ elseif kw == "false" then
+ return false
else
- sym = "\\string\\" .. cs
- end
- if swap then
- row(name,sym,chr)
- elseif tonumber(chr) < 0 then
- row(name,"",sym)
- else
- row(name,chr,sym)
+ return nil
end
end
- context.stoptabulate()
-end
--- Even more experimental ...
+ tokens.scanners = { -- these expand
+ token = scan_token or get_next,
+ toks = scan_toks,
+ tokens = scan_toks,
+ dimen = scan_dimen,
+ dimension = scan_dimen,
+ glue = scan_glue,
+ skip = scan_glue,
+ integer = scan_int,
+ count = scan_int,
+ string = scan_string,
+ code = scan_code,
+ word = scan_word,
+ number = scan_number,
+ boolean = scan_boolean,
+ keyword = scan_keyword,
+ }
+
+ tokens.getters = { -- these don't expand
+ token = get_next,
+ count = tex.getcount,
+ dimen = tex.getdimen,
+ box = tex.getbox,
+ }
+
+ tokens.setters = {
+ macro = set_macro,
+ count = tex.setcount,
+ dimen = tex.setdimen,
+ box = tex.setbox,
+ }
-show_methods.b = function(data) show_b_c(data,false) end
-show_methods.c = function(data) show_b_c(data,true ) end
-
-local remapper = { } -- namespace
-collectors.remapper = remapper
-
-local remapperdata = { } -- user mappings
-remapper.data = remapperdata
-
-function remapper.store(tag,class,key)
- local s = remapperdata[class]
- if not s then
- s = { }
- remapperdata[class] = s
- end
- s[key] = collectordata[tag]
- collectordata[tag] = nil
end
-function remapper.convert(tag,toks)
- local data = remapperdata[tag]
- local leftbracket, rightbracket = utfbyte('['), utfbyte(']')
- local skipping = 0
- -- todo: math
- if data then
- local t, n = { }, 0
- for s=1,#toks do
- local tok = toks[s]
- local one, two = tok[1], tok[2]
- if one == 11 or one == 12 then
- if two == leftbracket then
- skipping = skipping + 1
- n = n + 1 ; t[n] = tok
- elseif two == rightbracket then
- skipping = skipping - 1
- n = n + 1 ; t[n] = tok
- elseif skipping == 0 then
- local new = data[two]
- if new then
- if #new > 1 then
- for n=1,#new do
- n = n + 1 ; t[n] = new[n]
- end
- else
- n = n + 1 ; t[n] = new[1]
- end
- else
- n = n + 1 ; t[n] = tok
- end
- else
- n = n + 1 ; t[n] = tok
- end
- else
- n = n + 1 ; t[n] = tok
- end
- end
- return t
- else
- return toks
- end
-end
+-- static int run_scan_token(lua_State * L)
+-- {
+-- saved_tex_scanner texstate;
+-- save_tex_scanner(texstate);
+-- get_x_token();
+-- make_new_token(L, cur_cmd, cur_chr, cur_cs);
+-- unsave_tex_scanner(texstate);
+-- return 1;
+-- }
+--
+-- static int run_get_future(lua_State * L)
+-- {
+-- /* saved_tex_scanner texstate; */
+-- /* save_tex_scanner(texstate); */
+-- get_token();
+-- make_new_token(L, cur_cmd, cur_chr, cur_cs);
+-- back_input();
+-- /* unsave_tex_scanner(texstate); */
+-- return 1;
+-- }
diff --git a/Master/texmf-dist/tex/context/base/toks-ini.mkiv b/Master/texmf-dist/tex/context/base/toks-ini.mkiv
index 4eb756b7537..49625a93990 100644
--- a/Master/texmf-dist/tex/context/base/toks-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/toks-ini.mkiv
@@ -14,57 +14,11 @@
\writestatus{loading}{ConTeXt Token Support / Initialization}
\registerctxluafile{toks-ini}{1.001}
+\registerctxluafile{toks-scn}{1.001}
+\registerctxluafile{cldf-scn}{1.001}
\unprotect
-%D Handy for manuals \unknown
-
-\unexpanded\def\starttokens [#1]{\ctxlua{tokens.collectors.install("#1","stoptokens")}}
- \let\stoptokens \relax
- \def\flushtokens [#1]{\ctxlua{tokens.collectors.flush("#1")}}
- \def\showtokens [#1]{\ctxlua{tokens.collectors.show("#1")}}
- \def\testtokens [#1]{\ctxlua{tokens.collectors.with_words("#1")}}
- \def\registertoken #1{\ctxlua{tokens.collectors.register("#1")}}
-
-%D Inspired by a prototype by Taco for Thomas cum suis.
-
-% \defineremapper[babelgreek]
-%
-% \remapcharacter[babelgreek][`a]{\alpha}
-% \remapcharacter[babelgreek][`b]{\beta}
-% \remapcharacter[babelgreek][`c]{\gamma}
-% \remapcharacter[babelgreek][`d]{OEPS}
-%
-% \starttext
-%
-% [\startbabelgreek
-% a b c some stuff here \blank[big] oeps b d
-% \stopbabelgreek]
-%
-% [\babelgreek{some stuff here}]
-%
-% \stoptext
-
-\unexpanded\def\defineremapper[#1]%
- {\setuevalue{\e!start#1}{\toks_start_remapper{#1}}%
- \setuevalue{\e!stop #1}{\toks_stop_remapper {#1}}%
- \letvalue{#1}\relax
- \normalexpanded{\expandafter\def\csname#1\endcsname##1{\csname\e!start#1\endcsname##1\csname\e!stop#1\endcsname}}}
-
-\unexpanded\def\toks_start_remapper#1%
- {\ctxlua{tokens.collectors.install("#1", "\e!stop#1")}}
-
-\unexpanded\def\toks_stop_remapper#1%
- {\ctxlua{tokens.collectors.handle("#1",function(str) return tokens.collectors.remapper.convert("#1",str) end, true)}}
-
-\unexpanded\def\remaptokens#1%
- {\ctxlua{tokens.collectors.handle("#1",function(str) return tokens.collectors.remapper.convert("#1",str) end)}}
-
-\unexpanded\def\remapcharacter
- {\dodoubleempty\toks_remap_character}
-
-\def\toks_remap_character[#1][#2]#3%
- {\ctxlua{tokens.collectors.install("store", "ctxlua")}#3%
- \ctxlua{tokens.collectors.remapper.store("store","#1",\number#2)}}
+% nothing yet
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/toks-map.lua b/Master/texmf-dist/tex/context/base/toks-map.lua
new file mode 100644
index 00000000000..9120c2084e6
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/toks-map.lua
@@ -0,0 +1,70 @@
+if not modules then modules = { } end modules ['toks-map'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Even more experimental ... this used to be part of toks-ini but as
+-- this kind of remapping has not much use it is not loaded in the
+-- core. We just keep it here for old times sake.
+
+-- local remapper = { } -- namespace
+-- collectors.remapper = remapper
+--
+-- local remapperdata = { } -- user mappings
+-- remapper.data = remapperdata
+--
+-- function remapper.store(tag,class,key)
+-- local s = remapperdata[class]
+-- if not s then
+-- s = { }
+-- remapperdata[class] = s
+-- end
+-- s[key] = collectordata[tag]
+-- collectordata[tag] = nil
+-- end
+--
+-- function remapper.convert(tag,toks)
+-- local data = remapperdata[tag]
+-- local leftbracket = utfbyte('[')
+-- local rightbracket = utfbyte(']')
+-- local skipping = 0
+-- -- todo: math
+-- if data then
+-- local t, n = { }, 0
+-- for s=1,#toks do
+-- local tok = toks[s]
+-- local one, two = tok[1], tok[2]
+-- if one == 11 or one == 12 then
+-- if two == leftbracket then
+-- skipping = skipping + 1
+-- n = n + 1 ; t[n] = tok
+-- elseif two == rightbracket then
+-- skipping = skipping - 1
+-- n = n + 1 ; t[n] = tok
+-- elseif skipping == 0 then
+-- local new = data[two]
+-- if new then
+-- if #new > 1 then
+-- for n=1,#new do
+-- n = n + 1 ; t[n] = new[n]
+-- end
+-- else
+-- n = n + 1 ; t[n] = new[1]
+-- end
+-- else
+-- n = n + 1 ; t[n] = tok
+-- end
+-- else
+-- n = n + 1 ; t[n] = tok
+-- end
+-- else
+-- n = n + 1 ; t[n] = tok
+-- end
+-- end
+-- return t
+-- else
+-- return toks
+-- end
+-- end
diff --git a/Master/texmf-dist/tex/context/base/toks-map.mkiv b/Master/texmf-dist/tex/context/base/toks-map.mkiv
new file mode 100644
index 00000000000..f1b63a68b0a
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/toks-map.mkiv
@@ -0,0 +1,63 @@
+%D \module
+%D [ file=toks-map, % experimental moved from toks-ini
+%D version=2007.03.03,
+%D title=\CONTEXT\ Token Support,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% \writestatus{loading}{ConTeXt Token Support / Remapping}
+%
+% \registerctxluafile{toks-map}{1.001}
+%
+% \unprotect
+%
+% %D Inspired by a prototype by Taco for Thomas cum suis.
+% %D
+% %D \starttyping
+% %D \defineremapper[babelgreek]
+% %D
+% %D \remapcharacter[babelgreek][`a]{\alpha}
+% %D \remapcharacter[babelgreek][`b]{\beta}
+% %D \remapcharacter[babelgreek][`c]{\gamma}
+% %D \remapcharacter[babelgreek][`d]{OEPS}
+% %D
+% %D \starttext
+% %D
+% %D [\startbabelgreek
+% %D a b c some stuff here \blank[big] oeps b d
+% %D \stopbabelgreek]
+% %D
+% %D [\babelgreek{some stuff here}]
+% %D
+% %D \stoptext
+% %D \stoptyping
+%
+% \unexpanded\def\defineremapper[#1]%
+% {\setuevalue{\e!start#1}{\toks_start_remapper{#1}}%
+% \setuevalue{\e!stop #1}{\toks_stop_remapper {#1}}%
+% \letvalue{#1}\relax
+% \normalexpanded{\expandafter\def\csname#1\endcsname##1{\csname\e!start#1\endcsname##1\csname\e!stop#1\endcsname}}}
+%
+% \unexpanded\def\toks_start_remapper#1%
+% {\ctxlua{tokens.collectors.install("#1", "\e!stop#1")}}
+%
+% \unexpanded\def\toks_stop_remapper#1%
+% {\ctxlua{tokens.collectors.handle("#1",function(str) return tokens.collectors.remapper.convert("#1",str) end, true)}}
+%
+% \unexpanded\def\remaptokens#1%
+% {\ctxlua{tokens.collectors.handle("#1",function(str) return tokens.collectors.remapper.convert("#1",str) end)}}
+%
+% \unexpanded\def\remapcharacter
+% {\dodoubleempty\toks_remap_character}
+%
+% \def\toks_remap_character[#1][#2]#3%
+% {\ctxlua{tokens.collectors.install("store", "ctxlua")}#3%
+% \ctxlua{tokens.collectors.remapper.store("store","#1",\number#2)}}
+%
+% \protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/toks-scn.lua b/Master/texmf-dist/tex/context/base/toks-scn.lua
new file mode 100644
index 00000000000..84924c69419
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/toks-scn.lua
@@ -0,0 +1,437 @@
+if not modules then modules = { } end modules ['toks-scn'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Writing this kind of code (and completing the newtoken code base) is fun. I did
+-- so with the brilliant film music from The Girl with the Dragon Tattoo running in a
+-- loop in the background (three cd's by Trent Reznor and Atticus Ross). An alien
+-- feeling helps with alien code.
+
+-- todo: more \let's at the tex end
+
+local type, next, tostring, tonumber = type, next, tostring, tonumber
+
+local formatters = string.formatters
+local concat = table.concat
+
+local scanners = tokens.scanners
+local tokenbits = tokens.bits
+
+local scanstring = scanners.string
+local scaninteger = scanners.integer
+local scannumber = scanners.number
+local scankeyword = scanners.keyword
+local scanword = scanners.word
+local scancode = scanners.code
+local scanboolean = scanners.boolean
+local scandimen = scanners.dimen
+
+local todimen = number.todimen
+local toboolean = toboolean
+
+local lpegmatch = lpeg.match
+local p_unquoted = lpeg.Cs(lpeg.patterns.unquoted)
+
+local trace_compile = false trackers.register("tokens.compile", function(v) trace_compile = v end)
+local report_compile = logs.reporter("tokens","compile")
+local report_scan = logs.reporter("tokens","scan")
+
+local open = tokenbits.open
+local close = tokenbits.close
+
+local function scanopen()
+ while true do
+ local c = scancode(open)
+ if c == 123 then
+ return true
+ -- elseif c ~= 32 then
+ elseif not c then
+ return
+ end
+ end
+end
+
+local function scanclose()
+ while true do
+ local c = scancode(close)
+ if c == 125 then
+ return true
+ -- elseif c ~= 32 then
+ elseif not c then
+ return
+ end
+ end
+end
+
+scanners.scanopen = scanopen
+scanners.scanclose = scanclose
+
+local function scanlist()
+ local wrapped = scanopen()
+ local list = { }
+ local size = 0
+ while true do
+ local entry = scanstring()
+ if entry then
+ size = size + 1
+ list[size] = entry
+ else
+ break
+ end
+ end
+ if wrapped then
+ scanclose()
+ end
+ return list
+end
+
+local function scanconditional()
+ local kw = scanword()
+ if kw == "true" then
+ return true
+ end
+ if kw == "false" then
+ return false
+ end
+ local c = scaninteger()
+ if c then
+ return c == 0 -- with a conditional 0=true
+ end
+ return nil
+end
+
+scanners.list = scanlist
+scanners.conditional = scanconditional
+
+local shortcuts = {
+ tokens = tokens,
+ bits = tokenbits,
+ open = open,
+ close = close,
+ scanners = scanners,
+ scanstring = scanstring,
+ scaninteger = scaninteger,
+ scannumber = scannumber,
+ scankeyword = scankeyword,
+ scanword = scanword,
+ scancode = scancode,
+ scanboolean = scanboolean,
+ scandimen = scandimen,
+ scandimension = scandimen,
+ scanconditional = scanconditional,
+ scanopen = scanopen,
+ scanclose = scanclose,
+ scanlist = scanlist,
+ todimen = todimen,
+ tonumber = tonumber,
+ tostring = tostring,
+ toboolean = toboolean,
+ inspect = inspect,
+ report = report_scan,
+}
+
+tokens.shortcuts = shortcuts
+
+local load = load
+local dump = string.dump
+
+local function loadstripped(code)
+ return load(code,nil,nil,shortcuts)
+ -- return load(dump(load(code),true),nil,nil,shortcuts)
+end
+
+tokens.converters = {
+ tonumber = "tonumber",
+ tostring = "tostring",
+ toboolean = "toboolean",
+ todimen = "todimen",
+ toglue = "todimen",
+}
+
+local f_if = formatters[ " if scankeyword('%s') then data['%s'] = scan%s()"]
+local f_elseif = formatters[" elseif scankeyword('%s') then data['%s'] = scan%s()"]
+local f_local = formatters["local scan%s = scanners.%s"]
+local f_scan = formatters["scan%s()"]
+local f_shortcut = formatters["local %s = scanners.converters.%s"]
+
+local f_if_c = formatters[ " if scankeyword('%s') then data['%s'] = %s(scan%s())"]
+local f_elseif_c = formatters[" elseif scankeyword('%s') then data['%s'] = %s(scan%s())"]
+local f_scan_c = formatters["%s(scan%s())"]
+
+local f_any = formatters[" else local key = scanword() if key then data[key] = scan%s() else break end end"]
+local f_any_c = formatters[" else local key = scanword() if key then data[key] = %s(scan%s()) else break end end"]
+local s_done = " else break end"
+
+local f_any_all = formatters[" local key = scanword() if key then data[key] = scan%s() else break end"]
+local f_any_all_c= formatters[" local key = scanword() if key then data[key] = %s(scan%s()) else break end"]
+
+local f_table = formatters["%\nt\nreturn function()\n local data = { }\n%s\n return %s\nend\n"]
+local f_sequence = formatters["%\nt\n%\nt\n%\nt\nreturn function()\n return %s\nend\n"]
+local f_simple = formatters["%\nt\nreturn function()\n return %s\nend\n"]
+local f_string = formatters["%q"]
+local f_action_f = formatters["action%s(%s)"]
+local f_action_s = formatters["local action%s = tokens._action[%s]"]
+local f_nested = formatters["local function scan%s()\n local data = { }\n%s\n return data\nend\n"]
+
+-- local f_check = formatters[ [[
+-- local wrapped = false
+-- while true do
+-- local c = scancode(open)
+-- if c == 123 then
+-- wrapped = true
+-- break
+-- elseif c ~= 32 then
+-- break
+-- end
+-- end
+-- while true do
+-- ]] .. "%\nt\n" .. [[
+-- %s
+-- end
+-- if wrapped then
+-- while true do
+-- local c = scancode(close)
+-- if c == 125 then
+-- break
+-- elseif c ~= 32 then
+-- break
+-- end
+-- end
+-- end
+-- ]] ]
+
+local f_check = formatters[ [[
+ local wrapped = scanopen()
+ while true do
+ ]] .. "%\nt\n" .. [[
+ %s
+ end
+ if wrapped then
+ scanclose()
+ end
+]] ]
+
+function tokens.compile(specification)
+ local f = { }
+ local n = 0
+ local c = { }
+ local t = specification.arguments or specification
+ local a = specification.actions or nil
+ if type(a) == "function" then
+ a = { a }
+ end
+ local code
+ local function compile(t,nested)
+ local done = s_done
+ local r = { }
+ local m = 0
+ for i=1,#t do
+ local ti = t[i]
+ if ti == "*" and i == 1 then
+ done = f_any_all("string")
+ else
+ local t1 = ti[1]
+ local t2 = ti[2] or "string"
+ if type(t2) == "table" then
+ n = n + 1
+ f[n] = compile(t2,n)
+ t2 = n
+ end
+ local t3 = ti[3]
+ if type(t3) == "function" then
+ -- todo: also create shortcut
+ elseif t3 then
+ c[t3] = f_shortcut(t3,t3)
+ if t1 == "*" then
+ if i == 1 then
+ done = f_any_all_c(t3,t2)
+ break
+ else
+ done = f_any_c(t3,t2)
+ end
+ else
+ m = m + 1
+ r[m] = (m > 1 and f_elseif_c or f_if_c)(t1,t1,t3,t2)
+ end
+ else
+ if t1 == "*" then
+ if i == 1 then
+ done = f_any_all(t2)
+ break
+ else
+ done = f_any(t2)
+ end
+ else
+ m = m + 1
+ r[m] = (m > 1 and f_elseif or f_if )(t1,t1,t2)
+ end
+ end
+ end
+ end
+ local c = f_check(r,done)
+ if nested then
+ return f_nested(nested,c)
+ else
+ return c
+ end
+ end
+ local tt = type(t)
+ if tt == "string" then
+ if a then
+ local s = lpegmatch(p_unquoted,t)
+ if s and t ~= s then
+ code = t
+ else
+ code = f_scan(t)
+ end
+ tokens._action = a
+ for i=1,#a do
+ code = f_action_f(i,code)
+ f[#f+1] = f_action_s(i,i)
+ end
+ code = f_simple(f,code)
+ else
+ return scanners[t]
+ end
+ elseif tt ~= "table" then
+ return
+ elseif #t == 1 then
+ local ti = t[1]
+ if type(ti) == "table" then
+ ti = compile(ti)
+ code = "data"
+ if a then
+ tokens._action = a
+ for i=1,#a do
+ code = f_action_f(i,code)
+ f[#f+1] = f_action_s(i,i)
+ end
+ end
+ code = f_table(f,ti,code)
+ elseif a then
+ code = f_scan(ti)
+ tokens._action = a
+ for i=1,#a do
+ code = f_action_f(i,code)
+ f[#f+1] = f_action_s(i,i)
+ end
+ code = f_simple(f,code)
+ else
+ return scanners[ti]
+ end
+ else
+ local r = { }
+ local p = { }
+ local m = 0
+ for i=1,#t do
+ local ti = t[i]
+ local tt = type(ti)
+ if tt == "table" then
+ if ti[1] == "_constant_" then
+ local v = ti[2]
+ if type(v) == "string" then
+ r[i] = f_string(v)
+ else
+ r[i] = tostring(v)
+ end
+ else
+ m = m + 1
+ p[m] = compile(ti,100+m)
+ r[i] = f_scan(100+m)
+ end
+ elseif tt == "number" then
+ r[i] = tostring(ti)
+ elseif tt == "boolean" then
+ r[i] = tostring(ti)
+ else
+ local s = lpegmatch(p_unquoted,ti)
+ if s and ti ~= s then
+ r[i] = ti -- a string, given as "'foo'" or '"foo"'
+ elseif scanners[ti] then
+ r[i] = f_scan(ti)
+ else
+ report_compile("unknown scanner %a",ti)
+ r[i] = ti
+ end
+ end
+ end
+ code = concat(r,",")
+ if a then
+ tokens._action = a
+ for i=1,#a do
+ code = f_action_f(i,code)
+ f[#f+1] = f_action_s(i,i)
+ end
+ end
+ code = f_sequence(c,f,p,code)
+ end
+ if not code then
+ return
+ end
+ if trace_compile then
+ report_compile("code: %s",code)
+ end
+ local code, message = loadstripped(code)
+ if code then
+ code = code() -- sets action
+ else
+ report_compile("error in code: %s",code)
+ report_compile("error message: %s",message)
+ end
+ if a then
+ tokens._action = nil
+ end
+ if code then
+ return code
+ end
+end
+
+-- local fetch = tokens.compile {
+-- "string",
+-- "string",
+-- {
+-- { "data", "string" },
+-- { "tab", "string" },
+-- { "method", "string" },
+-- { "foo", {
+-- { "method", "integer" },
+-- { "compact", "number" },
+-- { "nature" },
+-- { "*" }, -- any key
+-- } },
+-- { "compact", "string", "tonumber" },
+-- { "nature", "boolean" },
+-- { "escape", "string" },
+-- { "escape" },
+-- }
+-- "boolean",
+-- }
+--
+-- os.exit()
+
+function tokens.scantable(t,data)
+ if not data then
+ data = { }
+ end
+ local wrapped = scanopen()
+ while true do
+ local key = scanword()
+ if key then
+ local get = t[key]
+ if get then
+ data[key] = get()
+ else
+ -- catch all we can get
+ end
+ else
+ break
+ end
+ end
+ if wrapped then
+ scanclose()
+ end
+ return data
+end
diff --git a/Master/texmf-dist/tex/context/base/toks-tra.lua b/Master/texmf-dist/tex/context/base/toks-tra.lua
new file mode 100644
index 00000000000..bf2b91d38a3
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/toks-tra.lua
@@ -0,0 +1,298 @@
+if not modules then modules = { } end modules ['toks-ini'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+
+local utfbyte, utfchar, utfvalues = utf.byte, utf.char, utf.values
+local format, gsub = string.format, string.gsub
+local tostring = tostring
+
+local tokens = tokens
+local newtoken = newtoken
+local tex = tex
+local context = context
+local commands = commands
+
+tokens.collectors = tokens.collectors or { }
+local collectors = tokens.collectors
+
+collectors.data = collectors.data or { }
+local collectordata = collectors.data
+
+collectors.registered = collectors.registered or { }
+local registered = collectors.registered
+
+local report = logs.reporter("tokens","collectors")
+
+if newtoken then
+
+ -- todo:
+ --
+ -- register : macros that will be expanded (only for demo-ing)
+ -- flush : print back to tex
+ -- test : fancy stuff
+
+ local get_next = newtoken.get_next
+ local create = newtoken.create
+
+ function collectors.install(tag,end_cs)
+ local data, d = { }, 0
+ collectordata[tag] = data
+ end_cs = gsub(end_cs,"^\\","")
+ while true do
+ local t = get_next()
+ if t.csname == end_cs then
+ context[end_cs]()
+ return
+ else
+ d = d + 1
+ data[d] = t
+ end
+ end
+ end
+
+ local simple = { letter = "letter", other_char = "other" }
+
+ function collectors.show(data)
+ -- We no longer have methods as we only used (in demos) method a
+ -- so there is no need to burden the core with this. We have a
+ -- different table anyway.
+ if type(data) == "string" then
+ data = collectordata[data]
+ end
+ if not data then
+ return
+ end
+ local ctx_NC = context.NC
+ local ctx_NR = context.NR
+ local ctx_bold = context.bold
+ local ctx_verbatim = context.verbatim
+ context.starttabulate { "|Tl|Tc|Tl|" }
+ ctx_NC() ctx_bold("cmd")
+ ctx_NC() ctx_bold("meaning")
+ ctx_NC() ctx_bold("properties")
+ ctx_NC() ctx_NR()
+ context.HL()
+ for i=1,#data do
+ local token = data[i]
+ local cmdname = token.cmdname
+ local simple = simple[cmdname]
+ ctx_NC()
+ ctx_verbatim(simple or cmdname)
+ ctx_NC()
+ ctx_verbatim(simple and utfchar(token.mode) or token.csname)
+ ctx_NC()
+ if token.active then context("active ") end
+ if token.expandable then context("expandable ") end
+ if token.protected then context("protected ") end
+ ctx_NC()
+ ctx_NR()
+ end
+ context.stoptabulate()
+ end
+
+ local function printlist(data)
+ if data and #data > 0 then
+ report("not supported (yet): printing back to tex")
+ end
+ end
+
+ tokens.printlist = printlist -- will change to another namespace
+
+ function collectors.flush(tag)
+ printlist(collectordata[tag])
+ end
+
+ function collectors.test(tag,handle)
+ report("not supported (yet): testing")
+ end
+
+ function collectors.register(name)
+ report("not supported (yet): registering")
+ end
+
+else
+
+ -- 1 = command, 2 = modifier (char), 3 = controlsequence id
+
+ local create = token.create
+ local csname_id = token.csname_id
+ local command_id = token.command_id
+ local command_name = token.command_name
+ local get_next = token.get_next
+ local expand = token.expand
+ local csname_name = token.csname_name
+
+ local function printlist(data)
+ if data and #data > 0 then
+ callbacks.push('token_filter', function ()
+ callbacks.pop('token_filter') -- tricky but the nil assignment helps
+ return data
+ end)
+ end
+ end
+
+ tokens.printlist = printlist -- will change to another namespace
+
+ function collectors.flush(tag)
+ printlist(collectordata[tag])
+ end
+
+ function collectors.register(name)
+ registered[csname_id(name)] = name
+ end
+
+ local call = command_id("call")
+ local letter = command_id("letter")
+ local other = command_id("other_char")
+
+ function collectors.install(tag,end_cs)
+ local data, d = { }, 0
+ collectordata[tag] = data
+ end_cs = gsub(end_cs,"^\\","")
+ local endcs = csname_id(end_cs)
+ while true do
+ local t = get_next()
+ local a, b = t[1], t[3]
+ if b == endcs then
+ context[end_cs]()
+ return
+ elseif a == call and registered[b] then
+ expand()
+ else
+ d = d + 1
+ data[d] = t
+ end
+ end
+ end
+
+ function collectors.show(data)
+ -- We no longer have methods as we only used (in demos) method a
+ -- so there is no need to burden the core with this.
+ if type(data) == "string" then
+ data = collectordata[data]
+ end
+ if not data then
+ return
+ end
+ local ctx_NC = context.NC
+ local ctx_NR = context.NR
+ local ctx_bold = context.bold
+ local ctx_verbatim = context.verbatim
+ context.starttabulate { "|T|Tr|cT|Tr|T|" }
+ ctx_NC() ctx_bold("cmd")
+ ctx_NC() ctx_bold("chr")
+ ctx_NC()
+ ctx_NC() ctx_bold("id")
+ ctx_NC() ctx_bold("name")
+ ctx_NC() ctx_NR()
+ context.HL()
+ for i=1,#data do
+ local token = data[i]
+ local cmd = token[1]
+ local chr = token[2]
+ local id = token[3]
+ local name = command_name(token)
+ ctx_NC()
+ ctx_verbatim(name)
+ ctx_NC()
+ if tonumber(chr) >= 0 then
+ ctx_verbatim(chr)
+ end
+ ctx_NC()
+ if cmd == letter or cmd == other then
+ ctx_verbatim(utfchar(chr))
+ end
+ ctx_NC()
+ if id > 0 then
+ ctx_verbatim(id)
+ end
+ ctx_NC()
+ if id > 0 then
+ ctx_verbatim(csname_name(token) or "")
+ end
+ ctx_NC() ctx_NR()
+ end
+ context.stoptabulate()
+ end
+
+ function collectors.test(tag,handle)
+ local t, w, tn, wn = { }, { }, 0, 0
+ handle = handle or collectors.defaultwords
+ local tagdata = collectordata[tag]
+ for k=1,#tagdata do
+ local v = tagdata[k]
+ if v[1] == letter then
+ wn = wn + 1
+ w[wn] = v[2]
+ else
+ if wn > 0 then
+ handle(t,w)
+ wn = 0
+ end
+ tn = tn + 1
+ t[tn] = v
+ end
+ end
+ if wn > 0 then
+ handle(t,w)
+ end
+ collectordata[tag] = t
+ end
+
+end
+
+-- Interfacing:
+
+commands.collecttokens = collectors.install
+commands.showtokens = collectors.show
+commands.flushtokens = collectors.flush
+commands.testtokens = collectors.test
+commands.registertoken = collectors.register
+
+-- Redundant:
+
+-- function collectors.test(tag)
+-- printlist(collectordata[tag])
+-- end
+
+-- For old times sake:
+
+collectors.dowithwords = collectors.test
+
+-- This is only used in old articles ... will move to a module:
+
+local create = newtoken and newtoken.create or token.create
+
+tokens.vbox = create("vbox")
+tokens.hbox = create("hbox")
+tokens.vtop = create("vtop")
+tokens.bgroup = create(utfbyte("{"),1)
+tokens.egroup = create(utfbyte("}"),2)
+
+tokens.letter = function(chr) return create(utfbyte(chr),11) end
+tokens.other = function(chr) return create(utfbyte(chr),12) end
+
+tokens.letters = function(str)
+ local t, n = { }, 0
+ for chr in utfvalues(str) do
+ n = n + 1
+ t[n] = create(chr, 11)
+ end
+ return t
+end
+
+function collectors.defaultwords(t,str)
+ if t then
+ local n = #t
+ n = n + 1 ; t[n] = tokens.bgroup
+ n = n + 1 ; t[n] = create("red")
+ for i=1,#str do
+ n = n + 1 ; t[n] = tokens.other('*')
+ end
+ n = n + 1 ; t[n] = tokens.egroup
+ end
+end
diff --git a/Master/texmf-dist/tex/context/base/toks-tra.mkiv b/Master/texmf-dist/tex/context/base/toks-tra.mkiv
new file mode 100644
index 00000000000..a3e27eaf89f
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/toks-tra.mkiv
@@ -0,0 +1,31 @@
+%D \module
+%D [ file=toks-tra, % was toks-ini
+%D version=2007.03.03,
+%D title=\CONTEXT\ Token Support,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Token Support / Tracing}
+
+\registerctxluafile{toks-tra}{1.001}
+
+\unprotect
+
+%D Handy for manuals \unknown\ but not really used in practice, so it might
+%D become a runtime loaded module instead.
+
+\unexpanded\def\starttokens [#1]{\ctxcommand{collecttokens("#1","stoptokens")}}
+ \let\stoptokens \relax
+ \def\flushtokens [#1]{\ctxcommand{flushtokens("#1")}}
+ \def\showtokens [#1]{\ctxcommand{showtokens("#1")}}
+ \def\testtokens [#1]{\ctxcommand{testtokens("#1")}}
+ \def\registertoken #1{\ctxcommand{registertoken("#1")}}
+
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/trac-ctx.lua b/Master/texmf-dist/tex/context/base/trac-ctx.lua
index 706e7a2447a..493ce793686 100644
--- a/Master/texmf-dist/tex/context/base/trac-ctx.lua
+++ b/Master/texmf-dist/tex/context/base/trac-ctx.lua
@@ -6,15 +6,15 @@ if not modules then modules = { } end modules ['trac-ctx'] = {
license = "see context related readme files"
}
-local commands = commands
-local context = context
-local register = trackers.register
+local context = context
+local implement = interfaces.implement
+local register = trackers.register
local textrackers = tex.trackers or { }
local texdirectives = tex.directives or { }
-tex.trackers = textrackers
-tex.directives = texdirectives
+tex.trackers = textrackers
+tex.directives = texdirectives
storage.register("tex/trackers", textrackers, "tex.trackers")
storage.register("tex/directives",texdirectives,"tex.directives")
@@ -39,10 +39,32 @@ local function install(category,register,tag,enable,disable)
register(tag, function(v) doit(category,tag,v) end) -- todo: v,tag in caller
end
-function commands.initializetextrackers () initialize(textrackers ,trackers .register ) end
-function commands.initializetexdirectives() initialize(texdirectives,directives.register) end
+implement {
+ name = "initializetextrackers",
+ actions = function()
+ initialize(textrackers,trackers.register)
+ end
+}
--- commands.install(tag,enable,disable):
+implement {
+ name = "initializetexdirectives",
+ actions = function()
+ initialize(texdirectives,directives.register)
+ end
+}
-function commands.installtextracker (...) install(textrackers ,trackers .register,...) end
-function commands.installtexdirective(...) install(texdirectives,directives.register,...) end
+implement {
+ name = "installtextracker",
+ actions = function(tag,enable,disable)
+ install(textrackers,trackers.register,tag,enable,disable)
+ end,
+ arguments = { "string", "string", "string" }
+}
+
+implement {
+ name = "installtexdirective",
+ actions = function(tag,enable,disable)
+ install(texdirectives,directives.register,tag,enable,disable)
+ end,
+ arguments = { "string", "string", "string" }
+}
diff --git a/Master/texmf-dist/tex/context/base/trac-ctx.mkiv b/Master/texmf-dist/tex/context/base/trac-ctx.mkiv
index 3eb53713cb3..4240281a6fb 100644
--- a/Master/texmf-dist/tex/context/base/trac-ctx.mkiv
+++ b/Master/texmf-dist/tex/context/base/trac-ctx.mkiv
@@ -18,14 +18,14 @@
\unprotect
\unexpanded\def\installtextracker#1#2#3%
- {\ctxcommand{installtextracker("#1",\!!bs\detokenize{#2}\!!es,\!!bs\detokenize{#3}\!!es)}}
+ {\clf_installtextracker{#1}{\detokenize{#2}}{\detokenize{#3}}}
\unexpanded\def\installtexdirective#1#2#3%
- {\ctxcommand{installtexdirective("#1",\!!bs\detokenize{#2}\!!es,\!!bs\detokenize{#3}\!!es)}}
+ {\clf_installtexdirective{#1}{\detokenize{#2}}{\detokenize{#3}}}
\appendtoks
- \ctxcommand{initializetextrackers ()}%
- \ctxcommand{initializetexdirectives()}%
+ \clf_initializetextrackers
+ \clf_initializetexdirectives
\to \everyjob
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/trac-deb.lua b/Master/texmf-dist/tex/context/base/trac-deb.lua
index d52399bcf1f..d998295c13c 100644
--- a/Master/texmf-dist/tex/context/base/trac-deb.lua
+++ b/Master/texmf-dist/tex/context/base/trac-deb.lua
@@ -32,6 +32,8 @@ local texgetdimen = tex.getdimen
local texgettoks = tex.gettoks
local texgetcount = tex.getcount
+local implement = interfaces.implement
+
strings.undefined = "undefined"
lists.scratch = {
@@ -304,3 +306,20 @@ local function trace_calls(n)
end
directives.register("system.tracecalls", function(n) trace_calls(n) end) -- indirect is needed for nilling
+
+implement { name = "showtrackers", actions = trackers.show }
+implement { name = "enabletrackers", actions = trackers.enable, arguments = "string" }
+implement { name = "disabletrackers", actions = trackers.disable, arguments = "string" }
+implement { name = "resettrackers", actions = trackers.reset }
+
+implement { name = "showdirectives", actions = directives.show }
+implement { name = "enabledirectives", actions = directives.enable, arguments = "string" }
+implement { name = "disabledirectives", actions = directives.disable, arguments = "string" }
+
+implement { name = "showexperiments", actions = experiments.show }
+implement { name = "enableexperiments", actions = experiments.enable, arguments = "string" }
+implement { name = "disableexperiments", actions = experiments.disable, arguments = "string" }
+
+implement { name = "showdebuginfo", actions = lmx.showdebuginfo }
+implement { name = "overloaderror", actions = lmx.overloaderror }
+implement { name = "showlogcategories", actions = logs.show }
diff --git a/Master/texmf-dist/tex/context/base/trac-deb.mkiv b/Master/texmf-dist/tex/context/base/trac-deb.mkiv
index fe5dd02dc4a..1e61a351261 100644
--- a/Master/texmf-dist/tex/context/base/trac-deb.mkiv
+++ b/Master/texmf-dist/tex/context/base/trac-deb.mkiv
@@ -13,25 +13,31 @@
\writestatus{loading}{ConTeXt Tracing Macros / Debugger}
+\unprotect
+
%registerctxluafile{trac-lmx}{1.001}
\registerctxluafile{trac-deb}{1.001}
-\unexpanded\def\breakpoint{\showdebuginfo\wait}
+\unexpanded\def\breakpoint {\showdebuginfo\wait}
+
+\unexpanded\def\showtrackers {\clf_showtrackers}
+\unexpanded\def\enabletrackers [#1]{\clf_enabletrackers{#1}}
+\unexpanded\def\disabletrackers [#1]{\clf_disabletrackers{#1}}
+\unexpanded\def\resettrackers {\clf_resettrackers}
+
+\unexpanded\def\showdirectives {\clf_showdirectives}
+\unexpanded\def\enabledirectives [#1]{\clf_enabledirectives{#1}}
+\unexpanded\def\disabledirectives [#1]{\clf_disabledirectives{#1}}
-\unexpanded\def\showtrackers {\ctxlua{trackers.show()}}
-\unexpanded\def\enabletrackers [#1]{\ctxlua{trackers.enable("#1")}}
-\unexpanded\def\disabletrackers [#1]{\ctxlua{trackers.disable("#1")}}
-\unexpanded\def\resettrackers {\ctxlua{trackers.reset()}}
+\unexpanded\def\showexperiments {\clf_showexperiments}
+\unexpanded\def\enableexperiments [#1]{\clf_enableexperiments{#1}}
+\unexpanded\def\disableexperiments[#1]{\clf_disableexperiments{#1}}
-\unexpanded\def\showdirectives {\ctxlua{directives.show()}}
-\unexpanded\def\enabledirectives [#1]{\ctxlua{directives.enable("#1")}}
-\unexpanded\def\disabledirectives [#1]{\ctxlua{directives.disable("#1")}}
+\unexpanded\def\showdebuginfo {\clf_showdebuginfo}
+\unexpanded\def\overloaderror {\clf_overloaderror}
-\unexpanded\def\showexperiments {\ctxlua{experiments.show()}}
-\unexpanded\def\enableexperiments [#1]{\ctxlua{experiments.enable("#1")}}
-\unexpanded\def\disableexperiments[#1]{\ctxlua{experiments.disable("#1")}}
+\unexpanded\def\showlogcategories {\clf_showlogcategories}
-\unexpanded\def\showdebuginfo {\ctxlua{lmx.showdebuginfo()}}
-\unexpanded\def\overloaderror {\ctxlua{lmx.overloaderror()}} % \enabledirectives[system.showerror]
+% \enabledirectives[system.showerror]
-\unexpanded\def\showlogcategories {\ctxlua{logs.show()}}
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/trac-inf.lua b/Master/texmf-dist/tex/context/base/trac-inf.lua
index 034726ffcdd..5497e54eb70 100644
--- a/Master/texmf-dist/tex/context/base/trac-inf.lua
+++ b/Master/texmf-dist/tex/context/base/trac-inf.lua
@@ -207,17 +207,3 @@ function statistics.tracefunction(base,tag,...)
statistics.register(formatters["%s.%s"](tag,name),function() return serialize(stat,"calls") end)
end
end
-
--- where, not really the best spot for this:
-
-commands = commands or { }
-
-function commands.resettimer(name)
- resettiming(name or "whatever")
- starttiming(name or "whatever")
-end
-
-function commands.elapsedtime(name)
- stoptiming(name or "whatever")
- context(elapsedtime(name or "whatever"))
-end
diff --git a/Master/texmf-dist/tex/context/base/trac-jus.lua b/Master/texmf-dist/tex/context/base/trac-jus.lua
index 00c871159ad..0c92848dcec 100644
--- a/Master/texmf-dist/tex/context/base/trac-jus.lua
+++ b/Master/texmf-dist/tex/context/base/trac-jus.lua
@@ -62,9 +62,10 @@ end
checkers.set = set
checkers.reset = reset
-function commands.showjustification(n)
- set(n)
-end
+interfaces.implement {
+ name = "showjustification",
+ actions = set
+}
trackers.register("visualizers.justification", function(v)
if v then
@@ -77,7 +78,7 @@ end)
function checkers.handler(head)
for current in traverse_id(hlist_code,tonut(head)) do
if getattr(current,a_justification) == 1 then
- setattr(current,a_justification,0)
+ setattr(current,a_justification,0) -- kind of reset
local width = getfield(current,"width")
if width > 0 then
local list = getlist(current)
diff --git a/Master/texmf-dist/tex/context/base/trac-jus.mkiv b/Master/texmf-dist/tex/context/base/trac-jus.mkiv
index 7a5347da844..d0823d31196 100644
--- a/Master/texmf-dist/tex/context/base/trac-jus.mkiv
+++ b/Master/texmf-dist/tex/context/base/trac-jus.mkiv
@@ -20,6 +20,6 @@
\definesystemattribute[justification] [public]
\unexpanded\def\showjustification
- {\ctxcommand{showjustification()}}
+ {\clf_showjustification} % currently no argument (default 1)
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/trac-lmx.lua b/Master/texmf-dist/tex/context/base/trac-lmx.lua
index 41d9305361a..4f4ea62c489 100644
--- a/Master/texmf-dist/tex/context/base/trac-lmx.lua
+++ b/Master/texmf-dist/tex/context/base/trac-lmx.lua
@@ -530,7 +530,7 @@ do_nested_include = function(data) -- also used in include
return lpegmatch(pattern_1,data)
end
-function lmxnew(data,defaults,nocache,path) -- todo: use defaults in calling routines
+local function lmxnew(data,defaults,nocache,path) -- todo: use defaults in calling routines
data = data or ""
local known = cache[data]
if not known then
@@ -608,7 +608,7 @@ function lmx.convertfile(templatefile,variables,nocache)
return lmxresult(converter,variables)
end
-function lmxconvert(templatefile,resultfile,variables,nocache) -- or (templatefile,variables)
+local function lmxconvert(templatefile,resultfile,variables,nocache) -- or (templatefile,variables)
if trace_variables then -- will become templates
report_lmx("converting file %a",templatefile)
end
@@ -665,14 +665,13 @@ function lmx.color(r,g,b,a)
end
end
-
-- these can be overloaded
lmx.lmxfile = string.itself
lmx.htmfile = string.itself
lmx.popupfile = os.launch
-function lmxmake(name,variables)
+local function lmxmake(name,variables)
local lmxfile = lmx.lmxfile(name)
local htmfile = lmx.htmfile(name)
if lmxfile == htmfile then
@@ -682,7 +681,7 @@ function lmxmake(name,variables)
return htmfile
end
-lmxmake = lmx.make
+lmx.make = lmxmake
function lmx.show(name,variables)
local htmfile = lmxmake(name,variables)
diff --git a/Master/texmf-dist/tex/context/base/trac-log.lua b/Master/texmf-dist/tex/context/base/trac-log.lua
index 72f271d9c3c..ce620e6cf0c 100644
--- a/Master/texmf-dist/tex/context/base/trac-log.lua
+++ b/Master/texmf-dist/tex/context/base/trac-log.lua
@@ -9,76 +9,28 @@ if not modules then modules = { } end modules ['trac-log'] = {
-- In fact all writes could go through lua and we could write the console and
-- terminal handler in lua then. Ok, maybe it's slower then, so a no-go.
--- if tex and (tex.jobname or tex.formatname) then
---
--- -- quick hack, awaiting speedup in engine (8 -> 6.4 sec for --make with console2)
--- -- still needed for luajittex
---
--- local texio_write_nl = texio.write_nl
--- local texio_write = texio.write
--- local io_write = io.write
---
--- local write_nl = function(target,...)
--- if not io_write then
--- io_write = io.write
--- end
--- if target == "term and log" then
--- texio_write_nl("log",...)
--- texio_write_nl("term","")
--- io_write(...)
--- elseif target == "log" then
--- texio_write_nl("log",...)
--- elseif target == "term" then
--- texio_write_nl("term","")
--- io_write(...)
--- else
--- texio_write_nl("log",target,...)
--- texio_write_nl("term","")
--- io_write(target,...)
--- end
--- end
---
--- local write = function(target,...)
--- if not io_write then
--- io_write = io.write
--- end
--- if target == "term and log" then
--- texio_write("log",...)
--- io_write(...)
--- elseif target == "log" then
--- texio_write("log",...)
--- elseif target == "term" then
--- io_write(...)
--- else
--- texio_write("log",target,...)
--- io_write(target,...)
--- end
--- end
---
--- texio.write = write
--- texio.write_nl = write_nl
---
--- else
---
--- -- texlua or just lua
---
--- end
-
--- todo: less categories, more subcategories (e.g. nodes)
--- todo: split into basics and ctx specific
-
+local next, type, select, print = next, type, select, print
local write_nl, write = texio and texio.write_nl or print, texio and texio.write or io.write
local format, gmatch, find = string.format, string.gmatch, string.find
local concat, insert, remove = table.concat, table.insert, table.remove
local topattern = string.topattern
-local next, type, select = next, type, select
local utfchar = utf.char
+local datetime = os.date
+local openfile = io.open
local setmetatableindex = table.setmetatableindex
local formatters = string.formatters
local texgetcount = tex and tex.getcount
+-- variant is set now
+
+local variant = "default"
+-- local variant = "ansi"
+
+-- todo: less categories, more subcategories (e.g. nodes)
+-- todo: split into basics and ctx specific
+
--[[ldx--
This is a prelude to a more extensive logging module. We no longer
provide based logging as parsing is relatively easy anyway.
@@ -112,12 +64,12 @@ wiki : http://contextgarden.net
-- [[local chruni = utilities.strings.chruni]]
-- )
-utilities.strings.formatters.add (
+formatters.add (
formatters, "unichr",
[["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]]
)
-utilities.strings.formatters.add (
+formatters.add (
formatters, "chruni",
[[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]]
)
@@ -150,20 +102,127 @@ setmetatableindex(logs, function(t,k) t[k] = ignore ; return ignore end)
local report, subreport, status, settarget, setformats, settranslations
-local direct, subdirect, writer, pushtarget, poptarget, setlogfile, settimedlog, setprocessor, setformatters
+local direct, subdirect, writer, pushtarget, poptarget, setlogfile, settimedlog, setprocessor, setformatters, newline
+
+-- we use formatters but best check for % then because for simple messages but
+-- we don't want this overhead for single messages (not that there are that
+-- many; we could have a special weak table)
if tex and (tex.jobname or tex.formatname) then
- -- local format = string.formatter
+ local function useluawrites()
- local valueiskey = { __index = function(t,k) t[k] = k return k end } -- will be helper
+ -- quick hack, awaiting speedup in engine (8 -> 6.4 sec for --make with console2)
+ -- still needed for luajittex .. luatex should not have that ^^ mess
- local target = "term and log"
+ local texio_write_nl = texio.write_nl
+ local texio_write = texio.write
+ local io_write = io.write
- logs.flush = io.flush
+ write_nl = function(target,...)
+ if not io_write then
+ io_write = io.write
+ end
+ if target == "term and log" then
+ texio_write_nl("log",...)
+ texio_write_nl("term","")
+ io_write(...)
+ elseif target == "log" then
+ texio_write_nl("log",...)
+ elseif target == "term" then
+ texio_write_nl("term","")
+ io_write(...)
+ elseif target ~= "none" then
+ texio_write_nl("log",target,...)
+ texio_write_nl("term","")
+ io_write(target,...)
+ end
+ end
+
+ write = function(target,...)
+ if not io_write then
+ io_write = io.write
+ end
+ if target == "term and log" then
+ texio_write("log",...)
+ io_write(...)
+ elseif target == "log" then
+ texio_write("log",...)
+ elseif target == "term" then
+ io_write(...)
+ elseif target ~= "none" then
+ texio_write("log",target,...)
+ io_write(target,...)
+ end
+ end
- local formats = { } setmetatable(formats, valueiskey)
- local translations = { } setmetatable(translations,valueiskey)
+ texio.write = write
+ texio.write_nl = write_nl
+
+ useluawrites = ignore
+
+ end
+
+ -- local format = string.formatter
+
+ local whereto = "both"
+ local target = nil
+ local targets = nil
+
+ local formats = table.setmetatableindex("self")
+ local translations = table.setmetatableindex("self")
+
+ local report_yes, subreport_yes, direct_yes, subdirect_yes, status_yes
+ local report_nop, subreport_nop, direct_nop, subdirect_nop, status_nop
+
+ local variants = {
+ default = {
+ formats = {
+ report_yes = formatters["%-15s > %s\n"],
+ report_nop = formatters["%-15s >\n"],
+ direct_yes = formatters["%-15s > %s"],
+ direct_nop = formatters["%-15s >"],
+ subreport_yes = formatters["%-15s > %s > %s\n"],
+ subreport_nop = formatters["%-15s > %s >\n"],
+ subdirect_yes = formatters["%-15s > %s > %s"],
+ subdirect_nop = formatters["%-15s > %s >"],
+ status_yes = formatters["%-15s : %s\n"],
+ status_nop = formatters["%-15s :\n"],
+ },
+ targets = {
+ logfile = "log",
+ log = "log",
+ file = "log",
+ console = "term",
+ terminal = "term",
+ both = "term and log",
+ },
+ },
+ ansi = {
+ formats = {
+ report_yes = formatters["[0;33m%-15s [0;1m>[0m %s\n"],
+ report_nop = formatters["[0;33m%-15s [0;1m>[0m\n"],
+ direct_yes = formatters["[0;33m%-15s [0;1m>[0m %s"],
+ direct_nop = formatters["[0;33m%-15s [0;1m>[0m"],
+ subreport_yes = formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s\n"],
+ subreport_nop = formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m\n"],
+ subdirect_yes = formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s"],
+ subdirect_nop = formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m"],
+ status_yes = formatters["[0;33m%-15s [0;1m:[0m %s\n"],
+ status_nop = formatters["[0;33m%-15s [0;1m:[0m\n"],
+ },
+ targets = {
+ logfile = "none",
+ log = "none",
+ file = "none",
+ console = "term",
+ terminal = "term",
+ both = "term",
+ },
+ }
+ }
+
+ logs.flush = io.flush
writer = function(...)
write_nl(target,...)
@@ -173,13 +232,6 @@ if tex and (tex.jobname or tex.formatname) then
write_nl(target,"\n")
end
- local report_yes = formatters["%-15s > %s\n"]
- local report_nop = formatters["%-15s >\n"]
-
- -- we can use formatters but best check for % then because for simple messages
- -- we con't want this overhead for single messages (not that there are that
- -- many; we could have a special weak table)
-
report = function(a,b,c,...)
if c then
write_nl(target,report_yes(translations[a],formatters[formats[b]](c,...)))
@@ -192,9 +244,6 @@ if tex and (tex.jobname or tex.formatname) then
end
end
- local direct_yes = formatters["%-15s > %s"]
- local direct_nop = formatters["%-15s >"]
-
direct = function(a,b,c,...)
if c then
return direct_yes(translations[a],formatters[formats[b]](c,...))
@@ -207,9 +256,6 @@ if tex and (tex.jobname or tex.formatname) then
end
end
- local subreport_yes = formatters["%-15s > %s > %s\n"]
- local subreport_nop = formatters["%-15s > %s >\n"]
-
subreport = function(a,s,b,c,...)
if c then
write_nl(target,subreport_yes(translations[a],translations[s],formatters[formats[b]](c,...)))
@@ -222,9 +268,6 @@ if tex and (tex.jobname or tex.formatname) then
end
end
- local subdirect_yes = formatters["%-15s > %s > %s"]
- local subdirect_nop = formatters["%-15s > %s >"]
-
subdirect = function(a,s,b,c,...)
if c then
return subdirect_yes(translations[a],translations[s],formatters[formats[b]](c,...))
@@ -237,9 +280,6 @@ if tex and (tex.jobname or tex.formatname) then
end
end
- local status_yes = formatters["%-15s : %s\n"]
- local status_nop = formatters["%-15s :\n"]
-
status = function(a,b,c,...)
if c then
write_nl(target,status_yes(translations[a],formatters[formats[b]](c,...)))
@@ -252,17 +292,13 @@ if tex and (tex.jobname or tex.formatname) then
end
end
- local targets = {
- logfile = "log",
- log = "log",
- file = "log",
- console = "term",
- terminal = "term",
- both = "term and log",
- }
-
- settarget = function(whereto)
- target = targets[whereto or "both"] or targets.both
+ settarget = function(askedwhereto)
+ whereto = askedwhereto or whereto or "both"
+ target = targets[whereto]
+ if not target then
+ whereto = "both"
+ target = targets[whereto]
+ end
if target == "term" or target == "term and log" then
logs.flush = io.flush
else
@@ -298,24 +334,81 @@ if tex and (tex.jobname or tex.formatname) then
end
end
- setformatters = function(f)
- report_yes = f.report_yes or report_yes
- report_nop = f.report_nop or report_nop
- subreport_yes = f.subreport_yes or subreport_yes
- subreport_nop = f.subreport_nop or subreport_nop
- direct_yes = f.direct_yes or direct_yes
- direct_nop = f.direct_nop or direct_nop
- subdirect_yes = f.subdirect_yes or subdirect_yes
- subdirect_nop = f.subdirect_nop or subdirect_nop
- status_yes = f.status_yes or status_yes
- status_nop = f.status_nop or status_nop
+ setformatters = function(specification)
+ local t = nil
+ local f = nil
+ local d = variants.default
+ if not specification then
+ --
+ elseif type(specification) == "table" then
+ t = specification.targets
+ f = specification.formats or specification
+ else
+ local v = variants[specification]
+ if v then
+ t = v.targets
+ f = v.formats
+ variant = specification
+ end
+ end
+ targets = t or d.targets
+ target = targets[whereto] or target
+ if f then
+ d = d.formats
+ else
+ f = d.formats
+ d = f
+ end
+ setmetatableindex(f,d)
+ report_yes = f.report_yes
+ report_nop = f.report_nop
+ subreport_yes = f.subreport_yes
+ subreport_nop = f.subreport_nop
+ direct_yes = f.direct_yes
+ direct_nop = f.direct_nop
+ subdirect_yes = f.subdirect_yes
+ subdirect_nop = f.subdirect_nop
+ status_yes = f.status_yes
+ status_nop = f.status_nop
+ if variant == "ansi" then
+ useluawrites() -- because tex escapes ^^
+ end
+ settarget(whereto)
end
+ setformatters(variant)
+
setlogfile = ignore
settimedlog = ignore
else
+ local report_yes, subreport_yes, status_yes
+ local report_nop, subreport_nop, status_nop
+
+ local variants = {
+ default = {
+ formats = {
+ report_yes = formatters["%-15s | %s"],
+ report_nop = formatters["%-15s |"],
+ subreport_yes = formatters["%-15s | %s | %s"],
+ subreport_nop = formatters["%-15s | %s |"],
+ status_yes = formatters["%-15s : %s\n"],
+ status_nop = formatters["%-15s :\n"],
+ },
+ },
+ ansi = {
+ formats = {
+ report_yes = formatters["[0;32m%-15s [0;1m|[0m %s"],
+ report_nop = formatters["[0;32m%-15s [0;1m|[0m"],
+ subreport_yes = formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m %s"],
+ subreport_nop = formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m"],
+ status_yes = formatters["[0;32m%-15s [0;1m:[0m %s\n"],
+ status_nop = formatters["[0;32m%-15s [0;1m:[0m\n"],
+ },
+ },
+ }
+
logs.flush = ignore
writer = function(s)
@@ -326,9 +419,6 @@ else
write_nl("\n")
end
- local report_yes = formatters["%-15s | %s"]
- local report_nop = formatters["%-15s |"]
-
report = function(a,b,c,...)
if c then
write_nl(report_yes(a,formatters[b](c,...)))
@@ -341,9 +431,6 @@ else
end
end
- local subreport_yes = formatters["%-15s | %s | %s"]
- local subreport_nop = formatters["%-15s | %s |"]
-
subreport = function(a,sub,b,c,...)
if c then
write_nl(subreport_yes(a,sub,formatters[b](c,...)))
@@ -356,9 +443,6 @@ else
end
end
- local status_yes = formatters["%-15s : %s\n"]
- local status_nop = formatters["%-15s :\n"]
-
status = function(a,b,c,...) -- not to be used in lua anyway
if c then
write_nl(status_yes(a,formatters[b](c,...)))
@@ -387,15 +471,36 @@ else
end
end
- setformatters = function(f)
- report_yes = f.report_yes or report_yes
- report_nop = f.report_nop or report_nop
- subreport_yes = f.subreport_yes or subreport_yes
- subreport_nop = f.subreport_nop or subreport_nop
- status_yes = f.status_yes or status_yes
- status_nop = f.status_nop or status_nop
+ setformatters = function(specification)
+ local f = nil
+ local d = variants.default
+ if specification then
+ if type(specification) == "table" then
+ f = specification.formats or specification
+ else
+ local v = variants[specification]
+ if v then
+ f = v.formats
+ end
+ end
+ end
+ if f then
+ d = d.formats
+ else
+ f = d.formats
+ d = f
+ end
+ setmetatableindex(f,d)
+ report_yes = f.report_yes
+ report_nop = f.report_nop
+ subreport_yes = f.subreport_yes
+ subreport_nop = f.subreport_nop
+ status_yes = f.status_yes
+ status_nop = f.status_nop
end
+ setformatters(variant)
+
setlogfile = function(name,keepopen)
if name and name ~= "" then
local localtime = os.localtime
@@ -726,13 +831,13 @@ logs.simpleline = simple
-- obsolete
-function logs.setprogram () end -- obsolete
-function logs.extendbanner() end -- obsolete
-function logs.reportlines () end -- obsolete
-function logs.reportbanner() end -- obsolete
-function logs.reportline () end -- obsolete
-function logs.simplelines () end -- obsolete
-function logs.help () end -- obsolete
+logs.setprogram = ignore -- obsolete
+logs.extendbanner = ignore -- obsolete
+logs.reportlines = ignore -- obsolete
+logs.reportbanner = ignore -- obsolete
+logs.reportline = ignore -- obsolete
+logs.simplelines = ignore -- obsolete
+logs.help = ignore -- obsolete
-- applications
@@ -845,10 +950,12 @@ end
-- logs.system(syslogname,"context","test","fonts","font %s recached due to newer version (%s)","blabla","123")
-- end
-function logs.system(whereto,process,jobname,category,...)
- local message = formatters["%s %s => %s => %s => %s\r"](os.date("%d/%m/%y %H:%m:%S"),process,jobname,category,format(...))
+local f_syslog = formatters["%s %s => %s => %s => %s\r"]
+
+function logs.system(whereto,process,jobname,category,fmt,arg,...)
+ local message = f_syslog(datetime("%d/%m/%y %H:%m:%S"),process,jobname,category,arg == nil and fmt or format(fmt,arg,...))
for i=1,10 do
- local f = io.open(whereto,"a") -- we can consider keeping the file open
+ local f = openfile(whereto,"a") -- we can consider keeping the file open
if f then
f:write(message)
f:close()
diff --git a/Master/texmf-dist/tex/context/base/trac-set.lua b/Master/texmf-dist/tex/context/base/trac-set.lua
index 95fdc43b30f..9e2bf87589a 100644
--- a/Master/texmf-dist/tex/context/base/trac-set.lua
+++ b/Master/texmf-dist/tex/context/base/trac-set.lua
@@ -37,7 +37,7 @@ function setters.initialize(filename,name,values) -- filename only for diagnosti
local data = setter.data
if data then
for key, newvalue in next, values do
- local newvalue = is_boolean(newvalue,newvalue)
+ local newvalue = is_boolean(newvalue,newvalue,true) -- strict
local functions = data[key]
if functions then
local oldvalue = functions.value
@@ -97,7 +97,7 @@ local function set(t,what,newvalue)
elseif not value then
value = false -- catch nil
else
- value = is_boolean(value,value)
+ value = is_boolean(value,value,true) -- strict
end
w = topattern(w,true,true)
for name, functions in next, data do
@@ -258,6 +258,7 @@ function setters.new(name) -- we could use foo:bar syntax (but not used that oft
report = function(...) setters.report (setter,...) end,
enable = function(...) enable (setter,...) end,
disable = function(...) disable (setter,...) end,
+ reset = function(...) reset (setter,...) end, -- can be dangerous
register = function(...) register(setter,...) end,
list = function(...) list (setter,...) end,
show = function(...) show (setter,...) end,
diff --git a/Master/texmf-dist/tex/context/base/trac-tex.lua b/Master/texmf-dist/tex/context/base/trac-tex.lua
index 7e340607313..5fe4754cbde 100644
--- a/Master/texmf-dist/tex/context/base/trac-tex.lua
+++ b/Master/texmf-dist/tex/context/base/trac-tex.lua
@@ -8,7 +8,7 @@ if not modules then modules = { } end modules ['trac-tex'] = {
-- moved from trac-deb.lua
-local format = string.format
+local next = next
local texhashtokens = tex.hashtokens
@@ -20,23 +20,70 @@ function trackers.savehash()
saved = texhashtokens()
end
-function trackers.dumphashtofile(filename,delta)
- local list, hash, command_name = { }, texhashtokens(), token.command_name
- for name, token in next, hash do
- if not delta or not saved[name] then
- -- token: cmd, chr, csid -- combination cmd,chr determines name
- local category = command_name(token)
- local dk = list[category]
- if not dk then
- -- a bit funny names but this sorts better (easier to study)
- dk = { names = { }, found = 0, code = token[1] }
- list[category] = dk
+if newtoken then
+
+ function trackers.dumphashtofile(filename,delta)
+ local list = { }
+ local hash = tex.hashtokens()
+ local create = newtoken.create
+ for name, token in next, hash do
+ if not delta or not saved[name] then
+ if token[2] ~= 0 then -- still old interface
+ local token = create(name)
+ -- inspect(token)
+ local category = token.cmdname
+ local dk = list[category]
+ if not dk then
+ dk = {
+ names = { },
+ found = 0,
+ -- code = token[1],
+ }
+ list[category] = dk
+ end
+ if token.protected then
+ if token.expandable then
+ dk.names[name] = "ep"
+ else
+ dk.names[name] = "-p"
+ end
+ else
+ if token.expandable then
+ dk.names[name] = "ep"
+ else
+ dk.names[name] = "--"
+ end
+ end
+ dk.found = dk.found + 1
+ end
end
- dk.names[name] = { token[2], token[3] }
- dk.found = dk.found + 1
end
+ table.save(filename or tex.jobname .. "-hash.log",list)
end
- io.savedata(filename or tex.jobname .. "-hash.log",table.serialize(list,true))
+
+else
+
+ function trackers.dumphashtofile(filename,delta)
+ local list = { }
+ local hash = texhashtokens()
+ local getname = token.command_name
+ for name, token in next, hash do
+ if not delta or not saved[name] then
+ -- token: cmd, chr, csid -- combination cmd,chr determines name
+ local category = getname(token)
+ local dk = list[category]
+ if not dk then
+ -- a bit funny names but this sorts better (easier to study)
+ dk = { names = { }, found = 0, code = token[1] }
+ list[category] = dk
+ end
+ dk.names[name] = { token[2], token[3] }
+ dk.found = dk.found + 1
+ end
+ end
+ table.save(filename or tex.jobname .. "-hash.log",list)
+ end
+
end
local delta = nil
diff --git a/Master/texmf-dist/tex/context/base/trac-vis.lua b/Master/texmf-dist/tex/context/base/trac-vis.lua
index eb5373ee350..86af6da0bdc 100644
--- a/Master/texmf-dist/tex/context/base/trac-vis.lua
+++ b/Master/texmf-dist/tex/context/base/trac-vis.lua
@@ -190,7 +190,7 @@ end
local function enable()
if not usedfont then
- -- we use a narrow monospaced font
+ -- we use a narrow monospaced font -- infofont ?
visualizers.setfont(fonts.definers.define { name = "lmmonoltcond10regular", size = tex.sp("4pt") })
end
for mode, value in next, modes do
@@ -280,13 +280,6 @@ function visualizers.setlayer(n)
texsetattribute(a_layer,layers[n] or unsetvalue)
end
-commands.setvisual = visualizers.setvisual
-commands.setlayer = visualizers.setlayer
-
-function commands.visual(n)
- context(setvisual(n))
-end
-
local function set(mode,v)
texsetattribute(a_visual,setvisual(mode,texgetattribute(a_visual),v))
end
@@ -322,7 +315,7 @@ local c_glyph_d = "trace:do"
local c_white_d = "trace:dw"
local c_math_d = "trace:dr"
-local function sometext(str,layer,color,textcolor) -- we can just paste verbatim together .. no typesteting needed
+local function sometext(str,layer,color,textcolor,lap) -- we can just paste verbatim together .. no typesteting needed
local text = fast_hpack_string(str,usedfont)
local size = getfield(text,"width")
local rule = new_rule(size,2*exheight,exheight/2)
@@ -336,10 +329,13 @@ local function sometext(str,layer,color,textcolor) -- we can just paste verbatim
local info = linked_nodes(rule,kern,text)
setlisttransparency(info,c_zero)
info = fast_hpack(info)
+ local width = getfield(info,"width")
+ if lap then
+ info = fast_hpack(linked_nodes(new_kern(-width),info))
+ end
if layer then
setattr(info,a_layer,layer)
end
- local width = getfield(info,"width")
setfield(info,"width",0)
setfield(info,"height",0)
setfield(info,"depth",0)
@@ -580,7 +576,8 @@ local function ruledglyph(head,current,previous)
setfield(current,"prev",nil)
local linewidth = emwidth/20
local baseline
- if dp ~= 0 and ht ~= 0 then
+ -- if dp ~= 0 and ht ~= 0 then
+ if (dp >= 0 and ht >= 0) or (dp <= 0 and ht <= 0) then
baseline = new_rule(wd-2*linewidth,linewidth,0)
end
local doublelinewidth = 2*linewidth
@@ -740,7 +737,7 @@ local function ruledpenalty(head,current,vertical)
return head, getnext(current)
end
-local function visualize(head,vertical)
+local function visualize(head,vertical,forced)
local trace_hbox = false
local trace_vbox = false
local trace_vtop = false
@@ -760,7 +757,7 @@ local function visualize(head,vertical)
local prev_trace_fontkern = nil
while current do
local id = getid(current)
- local a = getattr(current,a_visual) or unsetvalue
+ local a = forced or getattr(current,a_visual) or unsetvalue
if a ~= attr then
prev_trace_fontkern = trace_fontkern
if a == unsetvalue then
@@ -801,19 +798,17 @@ local function visualize(head,vertical)
head, current = ruledglyph(head,current,previous)
end
elseif id == disc_code then
- if trace_glyph then
- local pre = getfield(current,"pre")
- if pre then
- setfield(current,"pre",ruledglyph(pre,pre))
- end
- local post = getfield(current,"post")
- if post then
- setfield(current,"post",ruledglyph(post,post))
- end
- local replace = getfield(current,"replace")
- if replace then
- setfield(current,"replace",ruledglyph(replace,replace))
- end
+ local pre = getfield(current,"pre")
+ if pre then
+ setfield(current,"pre",visualize(pre,false,a))
+ end
+ local post = getfield(current,"post")
+ if post then
+ setfield(current,"post",visualize(post,false,a))
+ end
+ local replace = getfield(current,"replace")
+ if replace then
+ setfield(current,"replace",visualize(replace,false,a))
end
elseif id == kern_code then
local subtype = getsubtype(current)
@@ -822,7 +817,7 @@ local function visualize(head,vertical)
if trace_fontkern or prev_trace_fontkern then
head, current = fontkern(head,current)
end
- elseif subtype == user_kern_code then
+ else -- if subtype == user_kern_code then
if trace_kern then
head, current = ruledkern(head,current,vertical)
end
@@ -838,10 +833,6 @@ local function visualize(head,vertical)
if trace_penalty then
head, current = ruledpenalty(head,current,vertical)
end
- elseif id == disc_code then
- setfield(current,"pre",visualize(getfield(current,"pre")))
- setfield(current,"post",isualize(getfield(current,"post")))
- setfield(current,"replace",visualize(getfield(current,"replace")))
elseif id == hlist_code then
local content = getlist(current)
if content then
@@ -967,10 +958,6 @@ function visualizers.markfonts(list)
markfonts(type(n) == "number" and getlist(getbox(n)) or n)
end
-function commands.markfonts(n)
- visualizers.markfonts(n)
-end
-
luatex.registerstopactions(cleanup)
statistics.register("visualization time",function()
@@ -979,3 +966,14 @@ statistics.register("visualization time",function()
return format("%s seconds",statistics.elapsedtime(visualizers))
end
end)
+
+-- interface
+
+local implement = interfaces.implement
+
+implement { name = "setvisual", arguments = "string", actions = visualizers.setvisual }
+implement { name = "getvisual", arguments = "string", actions = { setvisual, context } }
+implement { name = "setvisuallayer", arguments = "string", actions = visualizers.setlayer }
+implement { name = "markvisualfonts", arguments = "integer", actions = visualizers.markfonts }
+implement { name = "setvisualfont", arguments = "integer", actions = visualizers.setfont }
+
diff --git a/Master/texmf-dist/tex/context/base/trac-vis.mkiv b/Master/texmf-dist/tex/context/base/trac-vis.mkiv
index 7517037ea46..a227e83544e 100644
--- a/Master/texmf-dist/tex/context/base/trac-vis.mkiv
+++ b/Master/texmf-dist/tex/context/base/trac-vis.mkiv
@@ -54,10 +54,10 @@
\let\syst_visualizers_vbox\vbox
\let\syst_visualizers_vtop\vtop
-\unexpanded\def\ruledhbox{\syst_visualizers_hbox attr \visualattribute \ctxcommand{visual("simplehbox")} }
-\unexpanded\def\ruledvbox{\syst_visualizers_vbox attr \visualattribute \ctxcommand{visual("simplevbox")} }
-\unexpanded\def\ruledvtop{\syst_visualizers_vtop attr \visualattribute \ctxcommand{visual("simplevtop")} } % special case
-\unexpanded\def\ruledtopv{\syst_visualizers_vtop attr \visualattribute \ctxcommand{visual("vtop")} }
+\unexpanded\def\ruledhbox{\syst_visualizers_hbox attr \visualattribute \clf_getvisual{simplehbox} }
+\unexpanded\def\ruledvbox{\syst_visualizers_vbox attr \visualattribute \clf_getvisual{simplevbox} }
+\unexpanded\def\ruledvtop{\syst_visualizers_vtop attr \visualattribute \clf_getvisual{simplevtop} } % special case
+\unexpanded\def\ruledtopv{\syst_visualizers_vtop attr \visualattribute \clf_getvisual{vtop} }
\unexpanded\def\ruledmbox#1{\ruledhbox{\startimath#1\stopimath}}
@@ -87,29 +87,29 @@
\unexpanded\def\syst_visualizers_makeup[#1]%
{\iffirstargument
- \ctxcommand{setvisual("#1")}%
+ \clf_setvisual{#1}%
\else
- \ctxcommand{setvisual("makeup")}%
+ \clf_setvisual{makeup}%
\let\normalvtop\ruledtopv
\let\vtop \ruledtopv
\fi}
\unexpanded\def\showallmakeup
- {\ctxcommand{setvisual("all")}%
+ {\clf_setvisual{all}%
\let\normalvtop\ruledtopv
\let\vtop \ruledtopv
\showstruts}
\unexpanded\def\showboxes
- {\ctxcommand{setvisual("boxes")}%
+ {\clf_setvisual{boxes}%
\let\normalvtop\ruledtopv
\let\vtop \ruledtopv}
\unexpanded\def\showglyphs
- {\ctxcommand{setvisual("glyph")}}
+ {\clf_setvisual{glyph}}
\unexpanded\def\showfontkerns
- {\ctxcommand{setvisual("fontkern")}}
+ {\clf_setvisual{fontkern}}
\unexpanded\def\setvisualizerfont
{\dosingleempty\syst_visualizers_setfont}
@@ -117,7 +117,7 @@
\def\syst_visualizers_setfont[#1]% somename at 4pt
{\begingroup
\doifelsenothing{#1}{\definedfont[Mono at 4pt]}{\definedfont[#1]}%
- \ctxlua{nodes.visualizers.setfont()}%
+ \clf_setvisualfont\fontid\font
\endgroup}
%D New (these might also be a visualizers):
@@ -148,14 +148,14 @@
%D Overload:
% \def\spac_struts_vide_hbox
-% {\hbox attr \visualattribute \ctxcommand{visual("strut")} }
+% {\hbox attr \visualattribute \clf_getvisual{strut} }
%
% \def\spac_struts_vide_hbox
-% {\xdef\spac_struts_vide_hbox{\hbox attr \visualattribute \ctxcommand{visual("strut")} }%
+% {\xdef\spac_struts_vide_hbox{\hbox attr \visualattribute \clf_getvisual{strut} }%
% \spac_struts_vide_hbox}
\unexpanded\def\spac_struts_vide_hbox
- {\hbox attr \visualattribute \ctxcommand{visual("strut")} }
+ {\hbox attr \visualattribute \clf_getvisual{strut} }
\appendtoks
\normalexpanded{\unexpanded\xdef\spac_struts_vide_hbox\expandafter{\spac_struts_vide_hbox}}%
@@ -167,7 +167,7 @@
{\dontleavehmode
\begingroup
\setbox\scratchbox\hbox{\getbuffer}%
- \ctxcommand{markfonts(\number\scratchbox)}%
+ \clf_markvisualfonts\scratchbox
\unhbox\scratchbox
\endgroup}
diff --git a/Master/texmf-dist/tex/context/base/type-imp-dejavu.mkiv b/Master/texmf-dist/tex/context/base/type-imp-dejavu.mkiv
index de1f7752cc9..41cf1f701e3 100644
--- a/Master/texmf-dist/tex/context/base/type-imp-dejavu.mkiv
+++ b/Master/texmf-dist/tex/context/base/type-imp-dejavu.mkiv
@@ -15,33 +15,6 @@
\starttypescriptcollection[dejavu]
- \starttypescript [\s!mono] [dejavu-condensed] [\s!name]
- \setups[\s!font:\s!fallback:\s!mono]
- % \definefontsynonym [\s!Mono] [\s!name:dejavusansmonocondensed] [\s!features=\s!none]
- % \definefontsynonym [\s!MonoBold] [\s!name:dejavusansmonoboldcondensed] [\s!features=\s!none]
- % \definefontsynonym [\s!MonoItalic] [\s!name:dejavusansmonoobliquecondensed] [\s!features=\s!none]
- % \definefontsynonym [\s!MonoBoldItalic] [\s!name:dejavusansmonoboldobliquecondensed] [\s!features=\s!none]
- \definefontsynonym [\s!Mono] [\s!name:dejavusansmono] [\s!features=dejavu-condensed-mono]
- \definefontsynonym [\s!MonoBold] [\s!name:dejavusansmonobold] [\s!features=dejavu-condensed-mono]
- \definefontsynonym [\s!MonoItalic] [\s!name:dejavusansmonooblique] [\s!features=dejavu-condensed-mono]
- \definefontsynonym [\s!MonoBoldItalic] [\s!name:dejavusansmonoboldoblique] [\s!features=dejavu-condensed-mono]
- \stoptypescript
-
- % \starttypescript [\s!mono] [dejavu-condensed] [\s!name]
- % \setups[\s!font:\s!fallback:\s!mono]
- % \definefontsynonym [\s!Mono] [\s!name:dejavusansmono] [\s!features=\s!none]
- % \definefontsynonym [\s!MonoBold] [\s!name:dejavusansmonobold] [\s!features=\s!none]
- % \definefontsynonym [\s!MonoItalic] [\s!name:dejavusansmonooblique] [\s!features=\s!none]
- % \definefontsynonym [\s!MonoBoldItalic] [\s!name:dejavusansmonoboldoblique] [\s!features=\s!none]
- % \stoptypescript
-
- \starttypescript[dejavu-condensed]
- \definetypeface [dejavu-condensed] [\s!rm] [\s!serif] [dejavu-condensed] [\s!default]
- \definetypeface [dejavu-condensed] [\s!ss] [\s!sans] [dejavu-condensed] [\s!default]
- \definetypeface [dejavu-condensed] [\s!tt] [\s!mono] [dejavu-condensed] [\s!default]
- \definetypeface [dejavu-condensed] [\s!mm] [\s!math] [xits] [\s!default] [\s!rscale=1.2]
- \stoptypescript
-
\starttypescript [\s!serif] [dejavu] [\s!name]
\setups[\s!font:\s!fallback:\s!serif]
\definefontsynonym [\s!Serif] [\s!name:dejavuserif] [\s!features=\s!default]
@@ -66,11 +39,17 @@
\definefontsynonym [\s!MonoBoldItalic] [\s!name:dejavusansmonoboldoblique] [\s!features=\s!none]
\stoptypescript
+ \starttypescript [\s!math][dejavu][\s!name]
+ %\loadfontgoodies[dejavu]
+ \definefontsynonym[\s!MathRoman][file:dejavu-math.otf][\s!features=\s!math\mathsizesuffix]
+ \stoptypescript
+
\starttypescript[dejavu]
\definetypeface [dejavu] [\s!rm] [\s!serif] [dejavu] [\s!default]
\definetypeface [dejavu] [\s!ss] [\s!sans] [dejavu] [\s!default]
\definetypeface [dejavu] [\s!tt] [\s!mono] [dejavu] [\s!default]
- \definetypeface [dejavu] [\s!mm] [\s!math] [xits] [\s!default] [\s!rscale=1.2]
+% \definetypeface [dejavu] [\s!mm] [\s!math] [xits] [\s!default] [\s!rscale=1.2]
+ \definetypeface [dejavu] [\s!mm] [\s!math] [dejavu] [\s!default]
\stoptypescript
\starttypescript[dejavubidi]
@@ -96,4 +75,32 @@
\definefontsynonym [\s!SansBoldItalic] [\s!name:dejavusanscondensedboldoblique] [\s!features=\s!default]
\stoptypescript
+ \starttypescript [\s!mono] [dejavu-condensed] [\s!name]
+ \setups[\s!font:\s!fallback:\s!mono]
+ % \definefontsynonym [\s!Mono] [\s!name:dejavusansmonocondensed] [\s!features=\s!none]
+ % \definefontsynonym [\s!MonoBold] [\s!name:dejavusansmonoboldcondensed] [\s!features=\s!none]
+ % \definefontsynonym [\s!MonoItalic] [\s!name:dejavusansmonoobliquecondensed] [\s!features=\s!none]
+ % \definefontsynonym [\s!MonoBoldItalic] [\s!name:dejavusansmonoboldobliquecondensed] [\s!features=\s!none]
+ \definefontsynonym [\s!Mono] [\s!name:dejavusansmono] [\s!features=dejavu-condensed-mono]
+ \definefontsynonym [\s!MonoBold] [\s!name:dejavusansmonobold] [\s!features=dejavu-condensed-mono]
+ \definefontsynonym [\s!MonoItalic] [\s!name:dejavusansmonooblique] [\s!features=dejavu-condensed-mono]
+ \definefontsynonym [\s!MonoBoldItalic] [\s!name:dejavusansmonoboldoblique] [\s!features=dejavu-condensed-mono]
+ \stoptypescript
+
+ % \starttypescript [\s!mono] [dejavu-condensed] [\s!name]
+ % \setups[\s!font:\s!fallback:\s!mono]
+ % \definefontsynonym [\s!Mono] [\s!name:dejavusansmono] [\s!features=\s!none]
+ % \definefontsynonym [\s!MonoBold] [\s!name:dejavusansmonobold] [\s!features=\s!none]
+ % \definefontsynonym [\s!MonoItalic] [\s!name:dejavusansmonooblique] [\s!features=\s!none]
+ % \definefontsynonym [\s!MonoBoldItalic] [\s!name:dejavusansmonoboldoblique] [\s!features=\s!none]
+ % \stoptypescript
+
+ \starttypescript[dejavu-condensed]
+ \definetypeface [dejavu-condensed] [\s!rm] [\s!serif] [dejavu-condensed] [\s!default]
+ \definetypeface [dejavu-condensed] [\s!ss] [\s!sans] [dejavu-condensed] [\s!default]
+ \definetypeface [dejavu-condensed] [\s!tt] [\s!mono] [dejavu-condensed] [\s!default]
+% \definetypeface [dejavu-condensed] [\s!mm] [\s!math] [xits] [\s!default] [\s!rscale=1.2]
+ \definetypeface [dejavu-condensed] [\s!mm] [\s!math] [dejavu] [\s!default]
+ \stoptypescript
+
\stoptypescriptcollection
diff --git a/Master/texmf-dist/tex/context/base/type-ini.lua b/Master/texmf-dist/tex/context/base/type-ini.lua
index 4f53fbf4011..cd5b32d3e6c 100644
--- a/Master/texmf-dist/tex/context/base/type-ini.lua
+++ b/Master/texmf-dist/tex/context/base/type-ini.lua
@@ -6,15 +6,23 @@ if not modules then modules = { } end modules ['type-ini'] = {
license = "see context related readme files"
}
+local gsub = string.gsub
+local lpegmatch, P, Cs = lpeg.match, lpeg.P, lpeg.Cs
+
-- more code will move here
-local commands, context = commands, context
+local commands = commands
+local context = context
+local implement = interfaces.implement
-local gsub = string.gsub
+local uselibrary = resolvers.uselibrary
+
+local name_one = nil
+local name_two = nil
-local report_typescripts = logs.reporter("fonts","typescripts")
+local p_strip = Cs((P("type-") * (P("imp-")^0))^0/"" * P(1)^0)
-local patterns = { "type-imp-%s.mkiv", "type-imp-%s.tex", "type-%s.mkiv", "type-%s.tex" } -- this will be imp only
+local report = logs.reporter("fonts","typescripts")
local function action(name,foundname)
-- context.startreadingfile()
@@ -27,52 +35,83 @@ local function action(name,foundname)
context.loadfoundtypescriptfile(foundname)
end
-local name_one, name_two
-
-local function failure_two(name)
- report_typescripts("unknown library %a or %a",name_one,name_two)
-end
+local patterns = {
+ "type-imp-%s.mkiv",
+ "type-imp-%s.tex"
+}
-local function failure_one(name)
- name_two = gsub(name,"%-.*$","")
+local function failure(name)
if name == "loc" then
-- ignore
- elseif name_two == name then
- report_typescripts("unknown library %a",name_one)
else
- commands.uselibrary {
- name = name_two,
+ report("unknown library %a",name)
+ end
+end
+
+implement {
+ name = "loadtypescriptfile",
+ arguments = "string",
+ actions = function(name) -- a more specific name
+ uselibrary {
+ name = lpegmatch(p_strip,name) or name,
patterns = patterns,
action = action,
- failure = failure_two,
+ failure = failure,
onlyonce = false, -- will become true
}
end
-end
-
-function commands.doprocesstypescriptfile(name)
- name_one = gsub(name,"^type%-","")
- commands.uselibrary {
- name = name_one,
- patterns = patterns,
- action = action,
- failure = failure_one,
- onlyonce = false, -- will become true
- }
-end
+}
-local patterns = { "type-imp-%s.mkiv", "type-imp-%s.tex" }
+local patterns = {
+ "type-imp-%s.mkiv",
+ "type-imp-%s.tex",
+ -- obsolete
+ "type-%s.mkiv",
+ "type-%s.tex"
+}
-local function failure(name)
- report_typescripts("unknown library %a",name)
-end
+-- local function failure_two(name)
+-- report("unknown library %a or %a",name_one,name_two)
+-- end
+--
+-- local function failure_one(name)
+-- name_two = gsub(name,"%-.*$","")
+-- if name == "loc" then
+-- -- ignore
+-- elseif name_two == name then
+-- report("unknown library %a",name_one)
+-- else
+-- commands.uselibrary {
+-- name = name_two,
+-- patterns = patterns,
+-- action = action,
+-- failure = failure_two,
+-- onlyonce = false, -- will become true
+-- }
+-- end
+-- end
+--
+-- function commands.doprocesstypescriptfile(name)
+-- name_one = lpegmatch(p_strip,name) or name
+-- uselibrary {
+-- name = name_one,
+-- patterns = patterns,
+-- action = action,
+-- failure = failure_one,
+-- onlyonce = false, -- will become true
+-- }
+-- end
-function commands.loadtypescriptfile(name) -- a more specific name
- commands.uselibrary {
- name = gsub(name,"^type%-",""),
- patterns = patterns,
- action = action,
- failure = failure,
- onlyonce = false, -- will become true
- }
-end
+implement {
+ name = "doprocesstypescriptfile",
+ arguments = "string",
+ actions = function(name)
+ uselibrary {
+ name = lpegmatch(p_strip,name) or name,
+ patterns = patterns,
+ action = action,
+ failure = failure,
+ onlyonce = false, -- will become true
+ }
+ end
+}
diff --git a/Master/texmf-dist/tex/context/base/type-ini.mkvi b/Master/texmf-dist/tex/context/base/type-ini.mkvi
index faa9c667c34..f56c5573d5d 100644
--- a/Master/texmf-dist/tex/context/base/type-ini.mkvi
+++ b/Master/texmf-dist/tex/context/base/type-ini.mkvi
@@ -172,7 +172,7 @@
\unexpanded\def\loadtypescriptfile[#1]%
{\pushmacro\typescriptstate
\let\typescriptstate\plustwo % assumes 2 at the outer level
- \ctxcommand{loadtypescriptfile("#1")}%
+ \clf_loadtypescriptfile{#1}%
\popmacro\typescriptstate}
\unexpanded\def\loadfoundtypescriptfile#1%
@@ -237,7 +237,7 @@
\expandafter\let\csname\??typescriptfiles\currenttypefile\endcsname\t_font_typescripts}
\def\font_typescript_process_typescript_file
- {\ctxcommand{doprocesstypescriptfile("\currenttypefile")}}
+ {\clf_doprocesstypescriptfile{\currenttypefile}}
\unexpanded\def\usetypescriptonce
{\dotripleempty\font_typescripts_use_once}
@@ -294,12 +294,12 @@
%{\appendtoks\starttypescript#definitions\stoptypescript\to\c_font_typescripts_document}
{\c_font_typescripts_document\expandafter{\the\c_font_typescripts_document\starttypescript#definitions\stoptypescript}}
-\def\font_typescripts_start_process % could be a faster \doifnextoptionalelse if needed
+\def\font_typescripts_start_process % could be a faster \doifelsenextoptionalif needed
{\let\typescriptone \m_font_typescripts_one
\let\typescripttwo \m_font_typescripts_two
\let\typescriptthree\m_font_typescripts_three
\let\m_font_typescripts_match\empty
- \doifnextoptionalcselse\font_typescripts_start_process_one\font_typescripts_start_process_all}
+ \doifelsenextoptionalcs\font_typescripts_start_process_one\font_typescripts_start_process_all}
\def\font_typescripts_start_process_all % could be a \let
{\ifconditional\c_font_typescripts_first_pass
@@ -333,10 +333,10 @@
{\font_typescripts_check\m_font_typescripts_three\typescriptthree\font_typescripts_start_process_again_three}
\def\font_typescripts_start_process_again_one
- {\doifnextoptionalcselse\font_typescripts_start_process_two\font_typescripts_start_process_yes}
+ {\doifelsenextoptionalcs\font_typescripts_start_process_two\font_typescripts_start_process_yes}
\def\font_typescripts_start_process_again_two
- {\doifnextoptionalcselse\font_typescripts_start_process_three\font_typescripts_start_process_yes}
+ {\doifelsenextoptionalcs\font_typescripts_start_process_three\font_typescripts_start_process_yes}
\let\font_typescripts_start_process_again_three\font_typescripts_start_process_yes
@@ -359,7 +359,7 @@
\donetrue
\let#target\m_font_typescripts_check
\else
- \doifcommonelse\m_font_typescripts_check#asked\donetrue\donefalse
+ \doifelsecommon\m_font_typescripts_check#asked\donetrue\donefalse
\ifdone
\let#target\commalistelement
\fi
@@ -381,13 +381,13 @@
\unexpanded\def\loadmapline{\dodoubleempty\font_map_load_line}
\def\font_map_load_file[#filename]%
- {\ctxlua{fonts.mappings.loadfile("#filename")}}
+ {\clf_loadmapfile{#filename}}
\def\font_map_load_line[#kind][#data]%
- {\ctxlua{fonts.mappings.loadline("#kind","#data")}}
+ {\clf_loadmapline{#kind}{#data}}
\unexpanded\def\forgetmapfiles
- {\ctxlua{fonts.mappings.reset()}}
+ {\clf_resetmapfiles}
% \prependtoks
% \loadmapfile[mkiv-base.map]% can't we preload this one?
@@ -497,7 +497,7 @@
{\font_typefaces_define_indeed[#name][#style]}
\def\font_typefaces_define_d[#name][#specification][#dummya][#dummyb][#dummyc][#dummyd]% use definitions in lfg file
- {\ctxlua{fonts.definetypeface("#name",\!!bs#specification\!!es)}}
+ {\clf_definetypeface{#name}{#specification}}
\def\font_typefaces_define_indeed[#name][#style]% saveguard against redefinition
{\doifsomething{#name}
@@ -575,12 +575,6 @@
\fi \fi \fi
\ifmmode\mr\else\tf\fi} % needed ?
-% obsolete
-%
-% \unexpanded\def\usetypefile[#type]% recurses on path ! % no storage
-% {\edef\currenttypefile{#type}%
-% \ctxcommand{doprocesstypescriptfile("\currenttypefile")}}
-
%D For Taco:
%D
%D \starttyping
diff --git a/Master/texmf-dist/tex/context/base/type-run.mkiv b/Master/texmf-dist/tex/context/base/type-run.mkiv
index 4da633371d9..0455d896636 100644
--- a/Master/texmf-dist/tex/context/base/type-run.mkiv
+++ b/Master/texmf-dist/tex/context/base/type-run.mkiv
@@ -21,7 +21,7 @@
\def\dochecktypescript##1##2% script use
{\doifelsenothing{##1##2}
{\donetrue}
- {\doifcommonelse{##1}{##2}\donetrue\donefalse}}
+ {\doifelsecommon{##1}{##2}\donetrue\donefalse}}
\edef\typescriptone {\truetypescript{#1}}%
\edef\typescripttwo {\truetypescript{#2}}%
\edef\typescriptthree{\truetypescript{#3}}%
@@ -30,7 +30,7 @@
\obeylines % else we loose the first line due to lookahead
\dotripleempty\dostarttypescript}
\def\dostarttypescript[##1][##2][##3]%
- {\long\def\next####1\stoptypescript{\egroup}
+ {\def\next####1\stoptypescript{\egroup}
\dochecktypescript{##1}\typescriptone \ifdone
\dochecktypescript{##2}\typescripttwo \ifdone
\dochecktypescript{##3}\typescriptthree\ifdone
diff --git a/Master/texmf-dist/tex/context/base/typo-bld.lua b/Master/texmf-dist/tex/context/base/typo-bld.lua
index ad37c36f41a..4d0f28d9ab1 100644
--- a/Master/texmf-dist/tex/context/base/typo-bld.lua
+++ b/Master/texmf-dist/tex/context/base/typo-bld.lua
@@ -165,13 +165,8 @@ local function processor(head,followed_by_display)
end
end
-function constructors.enable()
- enabled = true
-end
-
-function constructors.disable()
- enabled = false
-end
+function constructors.enable () enabled = true end
+function constructors.disable() enabled = false end
callbacks.register('linebreak_filter', processor, "breaking paragraps into lines")
@@ -179,15 +174,6 @@ statistics.register("linebreak processing time", function()
return statistics.elapsedseconds(parbuilders)
end)
--- interface
-
-commands.defineparbuilder = constructors.define
-commands.startparbuilder = constructors.start
-commands.stopparbuilder = constructors.stop
-commands.setparbuilder = constructors.set
-commands.enableparbuilder = constructors.enable
-commands.disableparbuilder = constructors.disable
-
-- todo: move from nodes.builders to builders
nodes.builders = nodes.builder or { }
@@ -267,3 +253,12 @@ callbacks.register('buildpage_filter', builders.buildpage_filter, "vertical spac
statistics.register("v-node processing time", function()
return statistics.elapsedseconds(builders)
end)
+
+local implement = interfaces.implement
+
+implement { name = "defineparbuilder", actions = constructors.define, arguments = "string" }
+implement { name = "setparbuilder", actions = constructors.set, arguments = "string" }
+implement { name = "startparbuilder", actions = constructors.start, arguments = "string" }
+implement { name = "stopparbuilder", actions = constructors.stop }
+implement { name = "enableparbuilder", actions = constructors.enable }
+implement { name = "disableparbuilder", actions = constructors.disable }
diff --git a/Master/texmf-dist/tex/context/base/typo-bld.mkiv b/Master/texmf-dist/tex/context/base/typo-bld.mkiv
index 10502005b9a..69047c98b15 100644
--- a/Master/texmf-dist/tex/context/base/typo-bld.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-bld.mkiv
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{ConTeXt Node Macros / Paragraph Building}
+\writestatus{loading}{ConTeXt Typesetting Macros / Paragraph Building}
%D This is very experimental, undocumented, subjected to changes, etc. just as
%D the underlying interfaces. But at least it's cleaned as part of the status-mkiv
@@ -38,18 +38,18 @@
\installcorenamespace {parbuilder}
\unexpanded\def\defineparbuilder[#1]%
- {\ctxcommand{defineparbuilder("#1")}}
+ {\clf_defineparbuilder{#1}}
\unexpanded\def\startparbuilder[#1]%
{\ifhmode\par\fi
- \ctxcommand{startparbuilder("#1")}}
+ \clf_startparbuilder{#1}}
\unexpanded\def\stopparbuilder
{\ifhmode\par\fi
- \ctxcommand{stopparbuilder()}}
+ \clf_stopparbuilder}
\unexpanded\def\setmainparbuilder[#1]%
- {\ctxcommand{setparbuilder("#1")}}
+ {\clf_setparbuilder{#1}}
% no high level interface, after all implementing a linebreaker is not something that
% the average user will do
@@ -58,7 +58,7 @@
\defineparbuilder[oneline] % just for testing
\defineparbuilder[basic] % just for testing
-\def\enableparbuilders {\ctxcommand{enableparbuilder()}} % hooks in otr so we need to pickup
-\def\disableparbuilders{\ctxcommand{disableparbuilder()}} % hooks in otr so we need to pickup
+\unexpanded\def\enableparbuilders {\clf_enableparbuilder } % hooks in otr so we need to pickup
+\unexpanded\def\disableparbuilders{\clf_disableparbuilder} % hooks in otr so we need to pickup
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/typo-brk.lua b/Master/texmf-dist/tex/context/base/typo-brk.lua
index f9a65c6ba4c..a9d775856b4 100644
--- a/Master/texmf-dist/tex/context/base/typo-brk.lua
+++ b/Master/texmf-dist/tex/context/base/typo-brk.lua
@@ -53,6 +53,8 @@ local tasks = nodes.tasks
local v_reset = interfaces.variables.reset
+local implement = interfaces.implement
+
local new_penalty = nodepool.penalty
local new_glue = nodepool.glue
local new_disc = nodepool.disc
@@ -107,7 +109,8 @@ methods[2] = function(head,start) -- ( => (-
local tmp
head, start, tmp = remove_node(head,start)
head, start = insert_node_before(head,start,new_disc())
- setfield(start,"attr",copy_nodelist(getfield(tmp,"attr"))) -- just a copy will do
+ -- setfield(start,"attr",copy_nodelist(getfield(tmp,"attr"))) -- just a copy will do
+ setfield(start,"attr",getfield(tmp,"attr"))
setfield(start,"replace",tmp)
local tmp = copy_node(tmp)
local hyphen = copy_node(tmp)
@@ -125,7 +128,8 @@ methods[3] = function(head,start) -- ) => -)
local tmp
head, start, tmp = remove_node(head,start)
head, start = insert_node_before(head,start,new_disc())
- setfield(start,"attr",copy_nodelist(getfield(tmp,"attr"))) -- just a copy will do
+ -- setfield(start,"attr",copy_nodelist(getfield(tmp,"attr"))) -- just a copy will do
+ setfield(start,"attr",getfield(tmp,"attr"))
setfield(start,"replace",tmp)
local tmp = copy_node(tmp)
local hyphen = copy_node(tmp)
@@ -143,7 +147,8 @@ methods[4] = function(head,start) -- - => - - -
local tmp
head, start, tmp = remove_node(head,start)
head, start = insert_node_before(head,start,new_disc())
- setfield(start,"attr",copy_nodelist(getfield(tmp,"attr"))) -- just a copy will do
+ -- setfield(start,"attr",copy_nodelist(getfield(tmp,"attr"))) -- just a copy will do
+ setfield(start,"attr",getfield(tmp,"attr"))
setfield(start,"pre",copy_node(tmp))
setfield(start,"post",copy_node(tmp))
setfield(start,"replace",tmp)
@@ -171,7 +176,8 @@ methods[5] = function(head,start,settings) -- x => p q r
if middle then
setfield(start,"replace",(tonodes(tostring(middle),font,attr)))
end
- setfield(start,"attr",copy_nodelist(attr)) -- todo: critical only -- just a copy will do
+ -- setfield(start,"attr",copy_nodelist(attr)) -- todo: critical only -- just a copy will do
+ setfield(start,"attr",attr) -- todo: critical only -- just a copy will do
free_node(tmp)
insert_break(head,start,10000,10000)
end
@@ -315,6 +321,32 @@ end
-- interface
-commands.definebreakpoints = breakpoints.define
-commands.definebreakpoint = breakpoints.setreplacement
-commands.setbreakpoints = breakpoints.set
+implement {
+ name = "definebreakpoints",
+ actions = breakpoints.define,
+ arguments = "string"
+}
+
+implement {
+ name = "definebreakpoint",
+ actions = breakpoints.setreplacement,
+ arguments = {
+ "string",
+ "string",
+ "string",
+ {
+ { "type", "integer" },
+ { "nleft" },
+ { "nright" },
+ { "right" },
+ { "left" },
+ { "middle" },
+ }
+ }
+}
+
+implement {
+ name = "setbreakpoints",
+ actions = breakpoints.set,
+ arguments = "string"
+}
diff --git a/Master/texmf-dist/tex/context/base/typo-brk.mkiv b/Master/texmf-dist/tex/context/base/typo-brk.mkiv
index af498bfecb5..3b463c06f92 100644
--- a/Master/texmf-dist/tex/context/base/typo-brk.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-brk.mkiv
@@ -25,13 +25,13 @@
\definesystemattribute[breakpoint][public,global]
-\exhyphenchar\minusone % we use a different order then base tex, so we really need this
+% see below: \exhyphenchar \minusone % we use a different order tha n base tex, so we really need this
\unexpanded\def\definebreakpoints
{\dosingleargument\typo_breakpoints_define}
\def\typo_breakpoints_define[#1]%
- {\ctxcommand{definebreakpoints("#1")}}
+ {\clf_definebreakpoints{#1}}
\def\definebreakpoint
{\dotripleempty\typo_breakpoints_define_character}
@@ -39,18 +39,24 @@
\def\typo_breakpoints_define_character[#1][#2][#3]% name char settings
{\begingroup
\getdummyparameters[\c!type=1,\c!nleft=3,\c!nright=3,\s!language=,\c!left=,\c!right=,\c!middle=,#3]%
- \ctxcommand{definebreakpoint("#1", "#2", "\reallanguagetag{\directdummyparameter\s!language}", { % maybe deal with #3 at the lua end
- type = \directdummyparameter\c!type,
- nleft = "\directdummyparameter\c!nleft",
- nright = "\directdummyparameter\c!nright",
- right = "\directdummyparameter\c!right",
- left = "\directdummyparameter\c!left",
- middle = "\directdummyparameter\c!middle"
- } )}%
+ \clf_definebreakpoint
+ {#1}%
+ {#2}%
+ {\reallanguagetag{\directdummyparameter\s!language}}%
+ {% maybe deal with #3 at the lua end
+ type \directdummyparameter\c!type
+ nleft {\directdummyparameter\c!nleft}%
+ nright {\directdummyparameter\c!nright}%
+ right {\directdummyparameter\c!right}%
+ left {\directdummyparameter\c!left}%
+ middle {\directdummyparameter\c!middle}%
+ }%
+ \relax
\endgroup}
\unexpanded\def\setbreakpoints[#1]%
- {\ctxcommand{setbreakpoints("#1")}}
+ {\exhyphenchar\minusone % we use a different order tha n base tex, so we really need this
+ \clf_setbreakpoints{#1}}
\unexpanded\def\resetbreakpoints
{\attribute\breakpointattribute\attributeunsetvalue}
diff --git a/Master/texmf-dist/tex/context/base/typo-cap.lua b/Master/texmf-dist/tex/context/base/typo-cap.lua
index 78ed8700a31..80a74bac916 100644
--- a/Master/texmf-dist/tex/context/base/typo-cap.lua
+++ b/Master/texmf-dist/tex/context/base/typo-cap.lua
@@ -33,6 +33,9 @@ local getchar = nuts.getchar
local copy_node = nuts.copy
local end_of_math = nuts.end_of_math
+local traverse_nodes = nuts.traverse
+local traverse_id = nuts.traverse_id
+local insert_after = nuts.insert_after
local nodecodes = nodes.nodecodes
local skipcodes = nodes.skipcodes
@@ -72,6 +75,8 @@ local a_cases = attributes.private("case")
local extract = bit32.extract
local run = 0 -- a trick to make neighbouring ranges work
+local blocked = { }
+
local function set(tag,font)
if run == 2^6 then
run = 1
@@ -104,88 +109,40 @@ end
--
-- \WORD {far too \Word{many \WORD{more \word{pushed} in between} useless} words}
-local uccodes = characters.uccodes
-local lccodes = characters.lccodes
+local uccodes = characters.uccodes
+local lccodes = characters.lccodes
+local categories = characters.categories
-- true false true == mixed
-local function helper(start,attr,lastfont,n,codes,special,once,keepother)
+local function replacer(start,codes)
local char = getchar(start)
local dc = codes[char]
if dc then
local fnt = getfont(start)
- if keepother and dc == char then
- local lfa = lastfont[n]
- if lfa then
- setfield(start,"font",lfa)
- return start, true
- else
- return start, false
- end
- else
- if special then
- local lfa = lastfont[n]
- if lfa then
- local previd = getid(getprev(start))
- if previd ~= glyph_code and previd ~= disc_code then
- fnt = lfa
- setfield(start,"font",lfa)
- end
+ local ifc = fontchar[fnt]
+ if type(dc) == "table" then
+ for i=1,#dc do
+ if not ifc[dc[i]] then
+ return start, false
end
end
- local ifc = fontchar[fnt]
- if type(dc) == "table" then
- local ok = true
- for i=1,#dc do
- -- could be cached in font
- if not ifc[dc[i]] then
- ok = false
- break
- end
- end
- if ok then
- -- todo: use generic injector
- local prev = start
- local original = start
- for i=1,#dc do
- local chr = dc[i]
- prev = start
- if i == 1 then
- setfield(start,"char",chr)
- else
- local g = copy_node(original)
- setfield(g,"char",chr)
- local next = getnext(start)
- setfield(g,"prev",start)
- if next then
- setfield(g,"next",next)
- setfield(start,"next",g)
- setfield(next,"prev",g)
- end
- start = g
- end
- end
- if once then
- lastfont[n] = false
- end
- return prev, true
- end
- if once then
- lastfont[n] = false
- end
- return start, false
- elseif ifc[dc] then
- setfield(start,"char",dc)
- if once then
- lastfont[n] = false
+ for i=#dc,1,-1 do
+ local chr = dc[i]
+ if i == 1 then
+ setfield(start,"char",chr)
+ else
+ local g = copy_node(start)
+ setfield(g,"char",chr)
+ insert_after(start,start,g)
end
- return start, true
end
+ return start, true
+ elseif ifc[dc] then
+ setfield(start,"char",dc)
+ return start, true
end
end
- if once then
- lastfont[n] = false
- end
return start, false
end
@@ -206,140 +163,147 @@ end
cases.register = register
-local function WORD(start,attr,lastfont,n)
+local function WORD(start,attr,lastfont,n,count,where,first)
lastfont[n] = false
- return helper(start,attr,lastfont,n,uccodes)
+ return replacer(first or start,uccodes)
end
-local function word(start,attr,lastfont,n)
+local function word(start,attr,lastfont,n,count,where,first)
lastfont[n] = false
- return helper(start,attr,lastfont,n,lccodes)
-end
-
-local function blockrest(start)
- local n = getnext(start)
- while n do
- local id = getid(n)
- if id == glyph_code or id == disc_node and getattr(n,a_cases) == attr then
- setattr(n,a_cases,unsetvalue)
- else
- -- break -- we can have nested mess
- end
- n = getnext(n)
- end
+ return replacer(first or start,lccodes)
end
-local function Word(start,attr,lastfont,n) -- looks quite complex
- lastfont[n] = false
- local prev = getprev(start)
- if prev and getid(prev) == kern_code and getsubtype(prev) == kerning_code then
- prev = getprev(prev)
+local function Words(start,attr,lastfont,n,count,where,first) -- looks quite complex
+ if where == "post" then
+ return
end
- if not prev then
- blockrest(start)
- return helper(start,attr,lastfont,n,uccodes)
- end
- local previd = getid(prev)
- if previd ~= glyph_code and previd ~= disc_code then
- -- only the first character is treated
- blockrest(start)
- -- we could return the last in the range and save some scanning
- -- but why bother
- return helper(start,attr,lastfont,n,uccodes)
+ if count == 1 and where ~= "post" then
+ replacer(first or start,uccodes)
+ return start, true, true
else
- return start, false
+ return start, false, true
end
end
-local function Words(start,attr,lastfont,n)
- lastfont[n] = false
- local prev = getprev(start)
- if prev and getid(prev) == kern_code and getsubtype(prev) == kerning_code then
- prev = getprev(prev)
- end
- if not prev then
- return helper(start,attr,lastfont,n,uccodes)
+local function Word(start,attr,lastfont,n,count,where,first)
+ blocked[attr] = true
+ return Words(start,attr,lastfont,n,count,where,first)
+end
+
+local function camel(start,attr,lastfont,n,count,where,first)
+ local _, done_1 = word(start,attr,lastfont,n,count,where,first)
+ local _, done_2 = Words(start,attr,lastfont,n,count,where,first)
+ return start, done_1 or done_2, true
+end
+
+local function mixed(start,attr,lastfont,n,count,where,first)
+ if where == "post" then
+ return
end
- local previd = getid(prev)
- if previd ~= glyph_code and previd ~= disc_code then
- return helper(start,attr,lastfont,n,uccodes)
+ local used = first or start
+ local char = getchar(first)
+ local dc = uccodes[char]
+ if not dc then
+ return start, false, true
+ elseif dc == char then
+ local lfa = lastfont[n]
+ if lfa then
+ setfield(first,"font",lfa)
+ return start, true, true
+ else
+ return start, false, true
+ end
else
- return start, false
+ replacer(first or start,uccodes)
+ return start, true, true
end
end
-local function capital(start,attr,lastfont,n) -- 3
- return helper(start,attr,lastfont,n,uccodes,true,true)
-end
-
-local function Capital(start,attr,lastfont,n) -- 4
- return helper(start,attr,lastfont,n,uccodes,true,false)
+local function Capital(start,attr,lastfont,n,count,where,first,once) -- 3
+ local used = first or start
+ if count == 1 and where ~= "post" then
+ local lfa = lastfont[n]
+ if lfa then
+ local dc = uccodes[getchar(used)]
+ if dc then
+ setfield(used,"font",lfa)
+ end
+ end
+ end
+ local s, d, c = replacer(first or start,uccodes)
+ if once then
+ lastfont[n] = false -- here
+ end
+ return start, d, c
end
-local function mixed(start,attr,lastfont,n)
- return helper(start,attr,lastfont,n,uccodes,false,false,true)
+local function capital(start,attr,lastfont,n,where,count,first,count) -- 4
+ return Capital(start,attr,lastfont,n,where,count,first,true)
end
-local function none(start,attr,lastfont,n)
- return start, false
+local function none(start,attr,lastfont,n,count,where,first)
+ return start, false, true
end
-local function random(start,attr,lastfont,n)
+local function random(start,attr,lastfont,n,count,where,first)
+ local used = first or start
+ local char = getchar(used)
+ local font = getfont(used)
+ local tfm = fontchar[font]
lastfont[n] = false
- local ch = getchar(start)
- local tfm = fontchar[getfont(start)]
- if lccodes[ch] then
+ local kind = categories[char]
+ if kind == "lu" then
while true do
- local d = chardata[randomnumber(1,0xFFFF)]
- if d then
- local uc = uccodes[d]
- if uc and tfm[uc] then -- this also intercepts tables
- setfield(start,"char",uc)
- return start, true
- end
+ local n = randomnumber(0x41,0x5A)
+ if tfm[n] then -- this also intercepts tables
+ setfield(used,"char",n)
+ return start, true
end
end
- elseif uccodes[ch] then
+ elseif kind == "ll" then
while true do
- local d = chardata[randomnumber(1,0xFFFF)]
- if d then
- local lc = lccodes[d]
- if lc and tfm[lc] then -- this also intercepts tables
- setfield(start,"char",lc)
- return start, true
- end
+ local n = randomnumber(0x61,0x7A)
+ if tfm[n] then -- this also intercepts tables
+ setfield(used,"char",n)
+ return start, true
end
end
end
return start, false
end
-register(variables.WORD, WORD) -- 1
-register(variables.word, word) -- 2
-register(variables.Word, Word) -- 3
-register(variables.Words, Words) -- 4
-register(variables.capital, capital) -- 5
-register(variables.Capital, Capital) -- 6
-register(variables.none, none) -- 7 (dummy)
-register(variables.random, random) -- 8
-register(variables.mixed, mixed) -- 9
+register(variables.WORD, WORD) -- 1
+register(variables.word, word) -- 2
+register(variables.Word, Word) -- 3
+register(variables.Words, Words) -- 4
+register(variables.capital,capital) -- 5
+register(variables.Capital,Capital) -- 6
+register(variables.none, none) -- 7 (dummy)
+register(variables.random, random) -- 8
+register(variables.mixed, mixed) -- 9
+register(variables.camel, camel) -- 10
-register(variables.cap, variables.capital) -- clone
-register(variables.Cap, variables.Capital) -- clone
+register(variables.cap, variables.capital) -- clone
+register(variables.Cap, variables.Capital) -- clone
function cases.handler(head) -- not real fast but also not used on much data
- head = tonut(head)
local lastfont = { }
local lastattr = nil
local done = false
- local start = head
+ local start = tonut(head)
+ local count = 0
+ local previd = nil
+ local prev = nil
while start do -- while because start can jump ahead
local id = getid(start)
if id == glyph_code then
local attr = getattr(start,a_cases)
- if attr and attr > 0 then
+ if attr and attr > 0 and not blocked[attr] then
if attr ~= lastattr then
lastattr = attr
+ count = 1
+ else
+ count = count + 1
end
setattr(start,a_cases,unsetvalue)
local n, id, m = get(attr)
@@ -348,7 +312,7 @@ function cases.handler(head) -- not real fast but also not used on much data
end
local action = actions[n] -- map back to low number
if action then
- start, ok = action(start,attr,lastfont,n)
+ start, ok = action(start,attr,lastfont,n,count)
if ok then
done = true
end
@@ -361,9 +325,10 @@ function cases.handler(head) -- not real fast but also not used on much data
end
elseif id == disc_code then
local attr = getattr(start,a_cases)
- if attr and attr > 0 then
+ if attr and attr > 0 and not blocked[attr] then
if attr ~= lastattr then
lastattr = attr
+ count = 0
end
setattr(start,a_cases,unsetvalue)
local n, id, m = get(attr)
@@ -374,28 +339,73 @@ function cases.handler(head) -- not real fast but also not used on much data
if action then
local replace = getfield(start,"replace")
if replace then
- action(replace,attr,lastfont,n)
+ local cnt = count
+ for g in traverse_id(glyph_code,replace) do
+ cnt = cnt + 1
+ -- setattr(g,a_cases,unsetvalue)
+ local _, _, quit = action(start,attr,lastfont,n,cnt,"replace",g)
+ if quit then break end
+ end
end
local pre = getfield(start,"pre")
if pre then
- action(pre,attr,lastfont,n)
+ local cnt = count
+ for g in traverse_id(glyph_code,pre) do
+ cnt = cnt + 1
+ -- setattr(g,a_cases,unsetvalue)
+ local _, _, quit = action(start,attr,lastfont,n,cnt,"pre",g)
+ if quit then break end
+ end
end
local post = getfield(start,"post")
if post then
- action(post,attr,lastfont,n)
+ local cnt = count
+ for g in traverse_id(glyph_code,post) do
+ cnt = cnt + 1
+ -- setattr(g,a_cases,unsetvalue)
+ local _, _, quit = action(start,attr,lastfont,n,cnt,"post",g)
+ if quit then break end
+ end
end
end
+ count = count + 1
end
elseif id == math_code then
start = end_of_math(start)
+ count = 0
+ elseif prev_id == kern_code and getsubtype(prev) == kerning_code then
+ -- still inside a word ...nomally kerns are added later
+ else
+ count = 0
end
- if start then -- why test
- start = getnext(start)
+ if start then
+ prev = start
+ previd = id
+ start = getnext(start)
end
end
- return tonode(head), done
+ return head, done
end
+-- function cases.handler(head) -- let's assume head doesn't change ... no reason
+-- local done = false
+-- local lastfont = { }
+-- for first, last, size, attr in nuts.words(tonut(head),a_cases) do
+-- local n, id, m = get(attr)
+-- if lastfont[n] == nil then
+-- lastfont[n] = id
+-- end
+-- local action = actions[n]
+-- if action then
+-- local _, ok = action(first,attr,lastfont,n)
+-- if ok then
+-- done = true
+-- end
+-- end
+-- end
+-- return head, done
+-- end
+
local enabled = false
function cases.set(n,id)
@@ -422,4 +432,8 @@ end
-- interface
-commands.setcharactercasing = cases.set
+interfaces.implement {
+ name = "setcharactercasing",
+ actions = cases.set,
+ arguments = { "string", "integer" }
+}
diff --git a/Master/texmf-dist/tex/context/base/typo-cap.mkiv b/Master/texmf-dist/tex/context/base/typo-cap.mkiv
index c4458129f51..2859ba104e1 100644
--- a/Master/texmf-dist/tex/context/base/typo-cap.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-cap.mkiv
@@ -43,6 +43,7 @@
\definecapitals[\v!WORD] % all lower
\definecapitals[\v!Word] % one upper + font
\definecapitals[\v!Words] % some upper
+\definecapitals[\v!camel] % lowers first
\definecapitals[\v!word][\c!style=] % nothing
%D \macros
@@ -76,7 +77,7 @@
% test \Word{test TEST \TeX} test
\unexpanded\def\setcharactercasing[#1]%
- {\ctxcommand{setcharactercasing("#1",\number\fontid\font)}}
+ {\clf_setcharactercasing{#1}\fontid\font}
% todo: names casings
@@ -84,6 +85,7 @@
\unexpanded\def\word {\groupedcommand{\setcharactercasing[\v!word ]}{}}
\unexpanded\def\Word {\groupedcommand{\setcharactercasing[\v!Word ]}{}}
\unexpanded\def\Words{\groupedcommand{\setcharactercasing[\v!Words]}{}}
+\unexpanded\def\camel{\groupedcommand{\setcharactercasing[\v!camel]}{}}
% This might become:
%
@@ -166,16 +168,13 @@
\def\typo_capitals_set_fake#1%
{\edef\currentcapitals{#1}%
- %\setcharactercasing[\currentcapitals]%
- \ctxcommand{setcharactercasing("\currentcapitals",\number\fontid\font)}%
- \signalcharacter % retain current style
+ \clf_setcharactercasing{\currentcapitals}\fontid\font
\usecapitalsstyleparameter\c!style}
\def\typo_capitals_set_real#1%
{\edef\currentcapitals{#1}%
\sc
- %\setcharactercasing[\currentcapitals]}
- \ctxcommand{setcharactercasing("\currentcapitals",\number\fontid\font)}}
+ \clf_setcharactercasing{\currentcapitals}\fontid\font}
\unexpanded\def\pseudosmallcapped{\groupedcommand{\typo_capitals_set_fake\v!WORD }\donothing} % all upper
\unexpanded\def\pseudoSmallcapped{\groupedcommand{\typo_capitals_set_fake\v!capital}\donothing} % one upper + font
diff --git a/Master/texmf-dist/tex/context/base/typo-chr.lua b/Master/texmf-dist/tex/context/base/typo-chr.lua
new file mode 100644
index 00000000000..94095828ddc
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/typo-chr.lua
@@ -0,0 +1,155 @@
+if not modules then modules = { } end modules ['typo-chr'] = {
+ version = 1.001,
+ comment = "companion to typo-bld.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- local nodecodes = nodes.nodecodes
+-- local whatsitcodes = nodes.whatsitcodes
+-- local glyph_code = nodecodes.glyph
+-- local whatsit_code = nodecodes.whatsit
+-- local user_code = whatsitcodes.userdefined
+--
+-- local stringusernode = nodes.pool.userstring
+--
+-- local nuts = nodes.nuts
+-- local pool = nuts.pool
+--
+-- local tonut = nuts.tonut
+-- local tonode = nuts.tonode
+-- local getid = nuts.getid
+-- local getprev = nuts.getprev
+-- local getsubtype = nuts.getsubtype
+-- local getchar = nuts.getchar
+-- local getfield = nuts.getfield
+--
+-- local remove_node = nuts.remove
+-- local traverse_by_id = nuts.traverse_id
+--
+-- local signal = pool.userids.signal
+--
+-- local is_punctuation = characters.is_punctuation
+--
+-- local actions = {
+-- removepunctuation = function(head,n)
+-- local prev = getprev(n)
+-- if prev then
+-- if getid(prev) == glyph_code then
+-- if is_punctuation[getchar(prev)] then
+-- head = remove_node(head,prev,true)
+-- end
+-- end
+-- end
+-- return head
+-- end
+-- }
+--
+-- -- we can also use properties .. todo (saves pass)
+--
+-- typesetters.signals = { }
+--
+-- function typesetters.signals.handler(head)
+-- local h = tonut(head)
+-- local done = false
+-- for n in traverse_by_id(whatsit_code,h) do
+-- if getsubtype(n) == user_code and getfield(n,"user_id") == signal and getfield(n,"type") == 115 then
+-- local action = actions[getfield(n,"value")]
+-- if action then
+-- h = action(h,n)
+-- end
+-- h = remove_node(h,n,true)
+-- done = true
+-- end
+-- end
+-- if done then
+-- return tonode(h), true
+-- else
+-- return head
+-- end
+-- end
+--
+-- local enabled = false
+--
+-- local function signal(what)
+-- if not enabled then
+-- nodes.tasks.prependaction("processors","normalizers", "typesetters.signals.handler")
+-- enabled = true
+-- end
+-- context(stringusernode(signal,what))
+-- end
+--
+-- interfaces.implement {
+-- name = "signal",
+-- actions = signal,
+-- arguments = "string",
+-- }
+
+local insert, remove = table.insert, table.remove
+
+local nodecodes = nodes.nodecodes
+local glyph_code = nodecodes.glyph
+
+local texnest = tex.nest
+local free_node = node.free
+
+local punctuation = characters.is_punctuation
+
+local stack = { }
+
+local function pickup()
+ local list = texnest[texnest.ptr]
+ if list then
+ local tail = list.tail
+ if tail and tail.id == glyph_code and punctuation[tail.char] then
+ local prev = tail.prev
+ list.tail = prev
+ if prev then
+ prev.next = nil
+ end
+ list.tail = prev
+ tail.prev = nil
+ return tail
+ end
+ end
+end
+
+local actions = {
+ remove = function(specification)
+ local n = pickup()
+ if n then
+ free_node(n)
+ end
+ end,
+ push = function(specification)
+ local n = pickup()
+ if n then
+ insert(stack,n or false)
+ end
+ end,
+ pop = function(specification)
+ local n = remove(stack)
+ if n then
+ context(n)
+ end
+ end,
+}
+
+local function pickuppunctuation(specification)
+ local action = actions[specification.action or "remove"]
+ if action then
+ action(specification)
+ end
+end
+
+interfaces.implement {
+ name = "pickuppunctuation",
+ actions = pickuppunctuation,
+ arguments = {
+ {
+ { "action" }
+ }
+ }
+}
+
diff --git a/Master/texmf-dist/tex/context/base/typo-chr.mkiv b/Master/texmf-dist/tex/context/base/typo-chr.mkiv
new file mode 100644
index 00000000000..9d8dd7c20c8
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/typo-chr.mkiv
@@ -0,0 +1,28 @@
+
+%D \module
+%D [ file=typo-cap,
+%D version=2009.03.27, % code moved from core-spa.mkiv
+%D title=\CONTEXT\ Typesetting Macros,
+%D subtitle=Capping,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Typesetting Macros / Characters}
+
+\unprotect
+
+%D Maybe we need a more clever system: either command or style mode etc. so
+%D that we can avoid the grouped mess in a simple style switch.
+
+\registerctxluafile{typo-chr}{1.001}
+
+\unexpanded\def\removepunctuation{\clf_pickuppunctuation action {remove}\relax}
+\unexpanded\def\pushpunctuation {\clf_pickuppunctuation action {push}\relax}
+\unexpanded\def\poppunctuation {\clf_pickuppunctuation action {pop}\relax}
+
+\protect
diff --git a/Master/texmf-dist/tex/context/base/typo-cln.lua b/Master/texmf-dist/tex/context/base/typo-cln.lua
index 8b1ac78768d..7228e02c543 100644
--- a/Master/texmf-dist/tex/context/base/typo-cln.lua
+++ b/Master/texmf-dist/tex/context/base/typo-cln.lua
@@ -101,4 +101,8 @@ end
-- interface
-commands.setcharactercleaning = cleaners.set
+interfaces.implement {
+ name = "setcharactercleaning",
+ actions = cleaners.set,
+ arguments = "string"
+}
diff --git a/Master/texmf-dist/tex/context/base/typo-cln.mkiv b/Master/texmf-dist/tex/context/base/typo-cln.mkiv
index 5306f614f27..193198dc556 100644
--- a/Master/texmf-dist/tex/context/base/typo-cln.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-cln.mkiv
@@ -24,7 +24,7 @@
%D 1: Autocap first character of a line
\unexpanded\def\setcharactercleaning[#1]% This name might change!
- {\ctxcommand{setcharactercleaning("#1")}} % also accepts "reset"
+ {\clf_setcharactercleaning{#1}} % also accepts "reset"
% \appendtoks
% \attribute\cleanerattribute\attributeunsetvalue
diff --git a/Master/texmf-dist/tex/context/base/typo-del.mkiv b/Master/texmf-dist/tex/context/base/typo-del.mkiv
index 603471f752c..4c3c5ab3da0 100644
--- a/Master/texmf-dist/tex/context/base/typo-del.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-del.mkiv
@@ -70,23 +70,23 @@
{\ifcase\boundarycharactermode
\or
%\nobreak
- \hskip\hspaceamount\currentlanguage{#2}%
- \languageparameter#1%
+ \hskip\hspaceamount\currentusedlanguage{#2}%
+ \usedlanguageparameter#1%
%\nobreak
- \hskip\hspaceamount\currentlanguage{#2}%
+ \hskip\hspaceamount\currentusedlanguage{#2}%
\or
- \languageparameter#1%
+ \usedlanguageparameter#1%
\fi
\boundarycharactermode\plusone}
\unexpanded\def\leftboundarycharacter#1#2%
{\ifcase\boundarycharactermode
\or
- \languageparameter#1%
+ \usedlanguageparameter#1%
\nobreak
- \hskip\hspaceamount\currentlanguage{#2}%
+ \hskip\hspaceamount\currentusedlanguage{#2}%
\or
- \languageparameter#1%
+ \usedlanguageparameter#1%
\fi
\boundarycharactermode\plusone}
@@ -94,10 +94,10 @@
{\ifcase\boundarycharactermode
\or
\prewordbreak %\nobreak
- \hskip\hspaceamount\currentlanguage{#2}%
- \languageparameter#1%
+ \hskip\hspaceamount\currentusedlanguage{#2}%
+ \usedlanguageparameter#1%
\or
- \languageparameter#1%
+ \usedlanguageparameter#1%
\fi
\boundarycharactermode\plusone}
@@ -142,13 +142,13 @@
{\beforesubsentence
\ifdim\lastkern=\d_typo_subsentence_signal
\unskip
- \kern\hspaceamount\currentlanguage{intersentence}%
+ \kern\hspaceamount\currentusedlanguage{intersentence}%
\fi
\global\advance\c_typo_subsentence_nesting\plusone
\ifnum\c_typo_subsentence_nesting=\plusone
\dontleavehmode % was \leaveoutervmode
\fi
- \dostarttagged\t!subsentence\empty
+ \dostarttagged\t!subsentence\empty % no chain
\symbol[\ifodd\c_typo_subsentence_nesting\c!leftsentence\else\c!leftsubsentence\fi]%
}% \ignorespaces}
@@ -166,7 +166,7 @@
\unexpanded\def\endofsubsentencespacing
{\ifdim\lastkern=\d_typo_subsentence_signal
\unskip
- \hskip\hspaceamount\currentlanguage{intersentence}%
+ \hskip\hspaceamount\currentusedlanguage{intersentence}%
% no good, actually language dependent:
% \ignorespaces
\else
@@ -193,8 +193,8 @@
%definehspace [quote] [\zeropoint]
%definehspace [speech] [\zeropoint]
-\definehspace [quote] [\hspaceamount\currentlanguage{quotation}]
-\definehspace [speech] [\hspaceamount\currentlanguage{quotation}]
+\definehspace [quote] [\hspaceamount\currentusedlanguage{quotation}]
+\definehspace [speech] [\hspaceamount\currentusedlanguage{quotation}]
\definesymbol
[\c!leftquotation]
@@ -204,6 +204,14 @@
[\c!rightquotation]
[\rightboundarycharacter\c!rightquotation{quotation}]
+\definesymbol
+ [\c!nextleftquotation]
+ [\rightboundarycharacter\c!leftquotation{quotation}]
+
+\definesymbol
+ [\c!nextrightquotation]
+ [\leftboundarycharacter\c!rightquotation{quotation}]
+
\definesymbol
[\c!leftquote]
[\leftboundarycharacter\c!leftquote{quote}]
@@ -248,6 +256,7 @@
\def\typo_delimited_push#1%
{\globalpushmacro\currentdelimitedtext
\def\currentdelimitedtext{#1}%
+ \setlanguageparameter\delimitedtextparameter
\let\currentparentdelimitedtext\currentdelimitedtext
\global\advance\c_typo_delimited_nesting\plusone
\edef\delimitedtextlevel{\number\c_typo_delimited_nesting}%
@@ -297,9 +306,9 @@
\unexpanded\def\startdelimitedtext[#1]%
{\begingroup
\typo_delimited_push{#1}%
- \dostarttagged\t!delimitedblock\currentdelimitedtext
- \edef\p_method{\delimitedtextparameter\c!method}%
- \ifx\p_method\s!font
+ \dostarttaggedchained\t!delimitedblock\currentdelimitedtext\??delimitedtext
+ \edef\p_delimited_method{\delimitedtextparameter\c!method}%
+ \ifx\p_delimited_method\s!font
\expandafter\typo_delimited_start_font
\else
\expandafter\typo_delimited_start_other
@@ -313,16 +322,16 @@
\ignorespaces}
\def\typo_delimited_start_other
- {\edef\p_repeat{\delimitedtextparameter\c!repeat}%
- \ifx\p_repeat\v!yes
+ {\edef\p_delimited_repeat{\delimitedtextparameter\c!repeat}%
+ \ifx\p_delimited_repeat\v!yes
\let\typo_delimited_repeat\typo_delimited_repeat_ideed
\else
\let\typo_delimited_repeat\relax
\fi
- \edef\p_location{\delimitedtextparameter\c!location}%
- \ifx\p_location\v!paragraph
+ \edef\p_delimited_location{\delimitedtextparameter\c!location}%
+ \ifx\p_delimited_location\v!paragraph
\singleexpandafter\typo_delimited_start_par
- \else\ifx\p_location\v!margin
+ \else\ifx\p_delimited_location\v!margin
\doubleexpandafter\typo_delimited_start_par
\else
\doubleexpandafter\typo_delimited_start_txt
@@ -338,8 +347,10 @@
\def\typo_delimited_start_par_indeed[#1]%
{\let\typo_delimited_stop\typo_delimited_stop_par
- \doifsomething{\delimitedtextparameter\c!spacebefore}
- {\blank[\delimitedtextparameter\c!spacebefore]}%
+ \edef\p_delimited_spacebefore{\delimitedtextparameter\c!spacebefore}%
+ \ifx\p_delimited_spacebefore\empty \else
+ \blank[\p_delimited_spacebefore]%
+ \fi
\delimitedtextparameter\c!before
\edef\m_typo_delimited_narrower{#1}%
\ifx\m_typo_delimited_narrower\empty
@@ -353,11 +364,21 @@
\fi
% so far
\pushmacro\checkindentation
- \doifsomething{\delimitedtextparameter\c!indenting} % WS
- {\setupindenting[\delimitedtextparameter\c!indenting]}%
+ \useindentingparameter\delimitedtextparameter
+ %
\begingroup
\usedelimitedtextstyleandcolor\c!style\c!color
+ %
+ \edef\p_delimited_left {\delimitedtextparameter{\c!left}}%
+ \edef\p_delimited_right {\delimitedtextparameter{\c!right}}%
+ \edef\p_delimited_nextleft {\delimitedtextparameter{\c!nextleft}}%
+ \edef\p_delimited_nextright{\delimitedtextparameter{\c!nextright}}%
+ %
\leftdelimitedtextmark
+ %
+ \setnextleftdelimitedtextmark
+ \setnextrightdelimitedtextmark
+ %
\ignorespaces}
\def\typo_delimited_stop_par
@@ -368,10 +389,12 @@
\popmacro\checkindentation
\typo_delimited_stop_par_indeed
\delimitedtextparameter\c!after
- \doifsomething{\delimitedtextparameter\c!spaceafter}
- {\blank[\delimitedtextparameter\c!spaceafter]}%
+ \edef\p_delimited_spaceafter{\delimitedtextparameter\c!spaceafter}%
+ \ifx\p_delimited_spaceafter\empty \else
+ \blank[\p_delimited_spaceafter]%
+ \fi
\useindentnextparameter\delimitedtextparameter
- \dorechecknextindentation}% AM: This was missing!
+ \aftergroup\dorechecknextindentation}% AM: This was missing!
\def\typo_delimited_start_txt
{\let\typo_delimited_stop\typo_delimited_stop_txt
@@ -394,18 +417,18 @@
\unexpanded\def\delimitedtext[#1]%
{\dontleavehmode % following ones can be omited
\typo_delimited_push{#1}%
- \edef\p_method{\delimitedtextparameter\c!method}%
- \ifx\p_method\s!font
+ \edef\p_delimited_method{\delimitedtextparameter\c!method}%
+ \ifx\p_delimited_method\s!font
\expandafter\typo_delimited_fontdriven
\else
\expandafter\typo_delimited_other
\fi}
\def\typo_delimited_other
- {\edef\p_location{\delimitedtextparameter\c!location}%
- \ifx\p_location\v!paragraph
+ {\edef\p_delimited_location{\delimitedtextparameter\c!location}%
+ \ifx\p_delimited_location\v!paragraph
\singleexpandafter\typo_delimited_par
- \else\ifx\p_location\v!margin
+ \else\ifx\p_delimited_location\v!margin
\doubleexpandafter\typo_delimited_par
\else
\doubleexpandafter\typo_delimited_txt
@@ -417,16 +440,89 @@
\unexpanded\def\stopdelimited {\stopdelimitedtext} % no let, dynamically assigned
\def\delimited {\delimitedtext}
+% todo: \dostarttagged\t!nothing\empty % for left/right boxes
+
+%D We have 4 different location and symbol handlers (two pairs):
+%D
+%D \starttyping
+%D \input tufte \startquotation \input tufte \stopquotation
+%D
+%D \setupdelimitedtext
+%D [quotation]
+%D [nextleft=right,
+%D nextright=left]
+%D
+%D \input tufte \startquotation \input tufte \stopquotation
+%D
+%D \setupdelimitedtext
+%D [quotation]
+%D [nextleft={\symbol[nextleftquotation]},
+%D nextright={\symbol[nextrightquotation]}]
+%D
+%D \input tufte \startquotation \input tufte \stopquotation
+%D \stoptyping
+
+\unexpanded\def\setnextleftdelimitedtextmark
+ {\ifx\p_delimited_nextleft\empty
+ % nothing
+ \else\ifx\p_delimited_nextleft\v!left
+ \typo_delimited_nextleft_symbol\p_delimited_left
+ \else\ifx\p_delimited_nextleft\v!right
+ \typo_delimited_nextleft_symbol\p_delimited_right
+ \else
+ \typo_delimited_nextleft_symbol\p_delimited_nextleft
+ \fi\fi\fi}
+
+\unexpanded\def\setnextrightdelimitedtextmark
+ {\ifx\p_delimited_nextright\empty
+ % nothing
+ \else\ifx\p_delimited_nextright\v!right
+ \typo_delimited_nextright_symbol\p_delimited_right
+ \else\ifx\p_delimited_nextright\v!left
+ \typo_delimited_nextright_symbol\p_delimited_left
+ \else
+ \typo_delimited_nextright_symbol\p_delimited_nextright
+ \fi\fi\fi}
+
\unexpanded\def\leftdelimitedtextmark
- {\doifsomething{\delimitedtextparameter\c!left}
- {\setbox\scratchbox\hbox{\delimitedtextparameter\c!left}%
- \dontleavehmode
- \doif{\delimitedtextparameter\c!location}\v!margin{\hskip-\wd\scratchbox}%
- \box\scratchbox}}
+ {\ifx\p_delimited_left\empty
+ % nothing
+ \else
+ \typo_delimited_left_symbol\p_delimited_left
+ \fi}
\unexpanded\def\rightdelimitedtextmark
- {\doifsomething{\delimitedtextparameter\c!right}
- {\hsmash{\delimitedtextparameter\c!right}}}
+ {\ifx\p_delimited_right\empty
+ % nothing
+ \else
+ \typo_delimited_right_symbol\p_delimited_right
+ \fi}
+
+\def\typo_delimited_left_symbol#1%
+ {\setbox\scratchbox\hbox{\usedelimitedtextstyleandcolor\c!symstyle\c!symcolor#1}%
+ \dontleavehmode
+ \edef\p_delimited_margin{\delimitedtextparameter\c!location}%
+ \ifx\p_delimited_margin\v!margin
+ \hskip-\wd\scratchbox
+ \fi
+ \box\scratchbox}
+
+\def\typo_delimited_right_symbol#1%
+ {\hsmash{\usedelimitedtextstyleandcolor\c!symstyle\c!symcolor#1}}
+
+\def\typo_delimited_nextleft_symbol#1%
+ {\localleftbox\bgroup
+ \swapmacros\leftboundarycharacter\rightboundarycharacter
+ \boundarycharactermode\plusone
+ \typo_delimited_left_symbol#1%
+ \egroup}
+
+\def\typo_delimited_nextright_symbol#1%
+ {\localrightbox\bgroup
+ \swapmacros\leftboundarycharacter\rightboundarycharacter
+ \boundarycharactermode\plusone
+ \typo_delimited_right_symbol#1%
+ \egroup}
% \starttext
% \hyphenatedword{groepsvrijstellingsverordeningen}\par
@@ -443,11 +539,12 @@
\def\typo_delimited_handle_middle#1%
{\begingroup
+ \usedelimitedtextstyleandcolor\c!symstyle\c!symcolor
\setbox\scratchbox\hbox{\delimitedtextparameter#1}%
\ifdim\wd\scratchbox>\zeropoint
\ifdim\lastkern=\d_typo_delimited_signal
\unkern
- \hskip\hspaceamount\currentlanguage{interquotation}%
+ \hskip\hspaceamount\currentusedlanguage{interquotation}%
\fi
\ifhmode % else funny pagebeaks
\penalty\plustenthousand
@@ -462,14 +559,15 @@
\def\typo_delimited_handle_left#1%
{\begingroup
+ \usedelimitedtextstyleandcolor\c!symstyle\c!symcolor
\setbox\scratchbox\hbox{\delimitedtextparameter#1}%
\ifdim\wd\scratchbox>\zeropoint
\ifdim\lastkern=\d_typo_delimited_signal
\unkern
- \hskip\hspaceamount\currentlanguage{interquotation}%
+ \hskip\hspaceamount\currentusedlanguage{interquotation}%
\else\ifdim\lastskip=\d_typo_delimited_signal
\unskip
- \hskip\hspaceamount\currentlanguage{interquotation}%
+ \hskip\hspaceamount\currentusedlanguage{interquotation}%
\fi\fi
\strut % new, needed below
\ifhmode % else funny pagebeaks
@@ -485,16 +583,17 @@
\def\typo_delimited_handle_right#1%
{\begingroup
+ \usedelimitedtextstyleandcolor\c!symstyle\c!symcolor
\setbox\scratchbox\hbox{\delimitedtextparameter#1}%
\ifdim\wd\scratchbox>\zeropoint
\ifdim\lastkern=\d_typo_delimited_signal
\unkern
\penalty\plustenthousand
- \hskip\hspaceamount\currentlanguage{interquotation}%
+ \hskip\hspaceamount\currentusedlanguage{interquotation}%
\else\ifdim\lastskip=\d_typo_delimited_signal
\unskip
\penalty\plustenthousand
- \hskip\hspaceamount\currentlanguage{interquotation}%
+ \hskip\hspaceamount\currentusedlanguage{interquotation}%
\fi\fi
\ifhmode % else funny pagebeaks
\penalty\plustenthousand
@@ -508,21 +607,57 @@
\unexpanded\def\typo_delimited_par
{\groupedcommand
- {\dostarttagged\t!delimited\currentdelimitedtext % block?
+ {\dostarttaggedchained\t!delimited\currentdelimitedtext\??delimitedtext % block?
\typo_delimited_handle_left\c!left}
{\typo_delimited_handle_right\c!right
\removelastskip
\dostoptagged
\typo_delimited_pop}}
+% \unexpanded\def\typo_delimited_txt
+% {\doifelse{\delimitedtextparameter\c!style}\v!normal
+% \typo_delimited_quoted
+% \typo_delimited_attributed}
+%
+% \def\typo_delimited_quoted_b
+% {\dostarttaggedchained\t!delimited\currentdelimitedtext\??delimitedtext
+% \typo_delimited_handle_left\c!left}
+%
+% \def\typo_delimited_quoted_e
+% {\typo_delimited_handle_right\c!right
+% \removelastskip
+% \dostoptagged
+% \typo_delimited_pop}
+%
+% \def\typo_delimited_attributed_b
+% {\dostarttaggedchained\t!delimited\currentdelimitedtext\??delimitedtext
+% \usedelimitedtextstyleandcolor\c!style\c!color}
+%
+% \def\typo_delimited_attributed_e
+% {\dostoptagged
+% \typo_delimited_pop}
+%
+% \def\typo_delimited_fontdriven_b
+% {\dostarttaggedchained\t!delimited\currentdelimitedtext\??delimitedtext
+% \languageparameter{\c!left\currentparentdelimitedtext}}% was: \currentdelimitedtext
+%
+% \def\typo_delimited_fontdriven_e
+% {\languageparameter{\c!right\currentparentdelimitedtext}% was: \currentdelimitedtext
+% \dostoptagged
+% \typo_delimited_pop}
+
\unexpanded\def\typo_delimited_txt
- {\doifelse{\delimitedtextparameter\c!style}\v!normal
- \typo_delimited_quoted
- \typo_delimited_attributed}
+ {\edef\p_left_right{\delimitedtextparameter\c!left\delimitedtextparameter\c!right}%
+ \ifx\p_left_right\empty
+ \expandafter\typo_delimited_attributed
+ \else
+ \expandafter\typo_delimited_quoted
+ \fi}
\def\typo_delimited_quoted_b
- {\dostarttagged\t!delimited\currentdelimitedtext
- \typo_delimited_handle_left\c!left}
+ {\dostarttaggedchained\t!delimited\currentdelimitedtext\??delimitedtext
+ \typo_delimited_handle_left\c!left
+ \usedelimitedtextstyleandcolor\c!style\c!color}
\def\typo_delimited_quoted_e
{\typo_delimited_handle_right\c!right
@@ -531,7 +666,7 @@
\typo_delimited_pop}
\def\typo_delimited_attributed_b
- {\dostarttagged\t!delimited\currentdelimitedtext
+ {\dostarttaggedchained\t!delimited\currentdelimitedtext\??delimitedtext
\usedelimitedtextstyleandcolor\c!style\c!color}
\def\typo_delimited_attributed_e
@@ -539,11 +674,12 @@
\typo_delimited_pop}
\def\typo_delimited_fontdriven_b
- {\dostarttagged\t!delimited\currentdelimitedtext
- \languageparameter{\c!left\currentparentdelimitedtext}}% was: \currentdelimitedtext
+ {\dostarttaggedchained\t!delimited\currentdelimitedtext\??delimitedtext
+ \usedlanguageparameter{\c!left\currentparentdelimitedtext}% was: \currentdelimitedtext
+ \usedelimitedtextstyleandcolor\c!style\c!color}
\def\typo_delimited_fontdriven_e
- {\languageparameter{\c!right\currentparentdelimitedtext}% was: \currentdelimitedtext
+ {\usedlanguageparameter{\c!right\currentparentdelimitedtext}% was: \currentdelimitedtext
\dostoptagged
\typo_delimited_pop}
diff --git a/Master/texmf-dist/tex/context/base/typo-dha.lua b/Master/texmf-dist/tex/context/base/typo-dha.lua
index 3410c2dfca0..904b774ec30 100644
--- a/Master/texmf-dist/tex/context/base/typo-dha.lua
+++ b/Master/texmf-dist/tex/context/base/typo-dha.lua
@@ -64,7 +64,6 @@ local getlist = nuts.getlist
local getfield = nuts.getfield
local setfield = nuts.setfield
local getattr = nuts.getattr
-local setattr = nuts.setattr
local getprop = nuts.getprop
local setprop = nuts.setprop
@@ -185,9 +184,9 @@ local function process(start)
finidir = finish
end
if embedded <= 0 then
- finish, autodir, done = "TRT", -1
+ finish, autodir = "TRT", -1
else
- finish, autodir, done = "TLT", 1
+ finish, autodir = "TLT", 1
end
done = true
if finidir == finish then
@@ -347,7 +346,7 @@ local function process(start)
top = top - 1
end
obsolete[#obsolete+1] = current
- else
+ elseif trace_directions then
setcolor(current)
end
else
diff --git a/Master/texmf-dist/tex/context/base/typo-dig.lua b/Master/texmf-dist/tex/context/base/typo-dig.lua
index 67849c6d47b..c753a03520a 100644
--- a/Master/texmf-dist/tex/context/base/typo-dig.lua
+++ b/Master/texmf-dist/tex/context/base/typo-dig.lua
@@ -103,15 +103,14 @@ end
actions[1] = function(head,start,attr)
local font = getfont(start)
local char = getchar(start)
- local unic = chardata[font][char].tounicode
- local what = unic and tonumber(unic,16) or char
- if charbase[what].category == "nd" then
+ local unic = chardata[font][char].unicode or char
+ if charbase[unic].category == "nd" then -- ignore unic tables
local oldwidth = getfield(start,"width")
local newwidth = getdigitwidth(font)
if newwidth ~= oldwidth then
if trace_digits then
report_digits("digit trigger %a, instance %a, char %C, unicode %U, delta %s",
- attr%100,div(attr,100),char,what,newwidth-oldwidth)
+ attr%100,div(attr,100),char,unic,newwidth-oldwidth)
end
head, start = nodes.aligned(head,start,start,newwidth,"middle")
return head, start, true
@@ -174,4 +173,8 @@ end
-- interface
-commands.setdigitsmanipulation = digits.set
+interfaces.implement {
+ name = "setdigitsmanipulation",
+ actions = digits.set,
+ arguments = "string"
+}
diff --git a/Master/texmf-dist/tex/context/base/typo-dig.mkiv b/Master/texmf-dist/tex/context/base/typo-dig.mkiv
index 71425c594a5..aa610b3c943 100644
--- a/Master/texmf-dist/tex/context/base/typo-dig.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-dig.mkiv
@@ -39,7 +39,7 @@
%D \stoplines
\unexpanded\def\setdigitsmanipulation[#1]%
- {\ctxcommand{setdigitsmanipulation("#1")}}
+ {\clf_setdigitsmanipulation{#1}}
\unexpanded\def\resetdigitsmanipulation
{\attribute\digitsattribute\attributeunsetvalue}
diff --git a/Master/texmf-dist/tex/context/base/typo-dir.lua b/Master/texmf-dist/tex/context/base/typo-dir.lua
index e7d3c686c4f..482b7114d63 100644
--- a/Master/texmf-dist/tex/context/base/typo-dir.lua
+++ b/Master/texmf-dist/tex/context/base/typo-dir.lua
@@ -50,6 +50,8 @@ local tracers = nodes.tracers
local setcolor = tracers.colors.set
local resetcolor = tracers.colors.reset
+local implement = interfaces.implement
+
local directions = typesetters.directions or { }
typesetters.directions = directions
@@ -137,9 +139,17 @@ function directions.setcolor(current,direction,reversed,mirror)
end
end
-function commands.getbidimode(specification)
- context(tomode(specification)) -- hash at tex end
-end
+implement {
+ name = "getbidimode",
+ actions = { tomode, context },
+ arguments = {
+ {
+ { "scope" },
+ { "method" },
+ { "fences" },
+ }
+ }
+}
local enabled = false
@@ -190,4 +200,8 @@ function directions.set(n) -- todo: names and numbers
texsetattribute(a_directions,n)
end
-commands.setdirection = directions.set
+implement {
+ name = "setdirection",
+ arguments = "integer",
+ actions = directions.set
+}
diff --git a/Master/texmf-dist/tex/context/base/typo-dir.mkiv b/Master/texmf-dist/tex/context/base/typo-dir.mkiv
index 0362af56cb0..f9b4ecb976c 100644
--- a/Master/texmf-dist/tex/context/base/typo-dir.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-dir.mkiv
@@ -13,6 +13,9 @@
\writestatus{loading}{ConTeXt Typesetting Macros / Directions}
+%D At some point we might default to method 'two' but first I need to make it more
+%D efficient (and provide some options). I also want to have some basic tracing.
+
\unprotect
\registerctxluafile{typo-dir}{1.001}
@@ -33,10 +36,14 @@
\edef\righttoleftmark{\normalUchar"200F} \let\rlm\righttoleftmark
\unexpanded\def\setdirection[#1]% todo: symbolic names
- {\ctxcommand{setdirection(\number#1)}}
+ {\clf_setdirection#1\relax}
+
+% \unexpanded\def\resetdirection
+% {\clf_setdirection\zerocount}
+%
+% is in fact:
\unexpanded\def\resetdirection
- %{\ctxcommand{setdirection(0)}}
{\attribute\directionsattribute\attributeunsetvalue}
\newconstant\directionsbidimode % this one might become pivate
@@ -46,12 +53,14 @@
% \setupdirections[bidi=global,method=two]
% \setupdirections[bidi=global,method=two,fences=no]
+% maybee use chardefs
+
\def\typo_dir_get_mode
- {\def\currentbidimode{\ctxcommand{getbidimode {
- scope = "\directionsparameter\c!bidi ",
- method = "\directionsparameter\c!method",
- fences = "\directionsparameter\c!fences",
- }}}%
+ {\def\currentbidimode{\clf_getbidimode
+ scope {\directionsparameter\c!bidi}%
+ method {\directionsparameter\c!method}%
+ fences {\directionsparameter\c!fences}%
+ }%
\expandafter\glet\csname\??directionsbidimode\currentbidistamp\endcsname\currentbidimode}
\appendtoks
diff --git a/Master/texmf-dist/tex/context/base/typo-drp.lua b/Master/texmf-dist/tex/context/base/typo-drp.lua
index 9151100b6f9..4bbf0b8e989 100644
--- a/Master/texmf-dist/tex/context/base/typo-drp.lua
+++ b/Master/texmf-dist/tex/context/base/typo-drp.lua
@@ -91,7 +91,27 @@ function initials.set(specification)
texsetattribute(a_initial,1)
end
-commands.setinitial = initials.set
+interfaces.implement {
+ name = "setinitial",
+ actions = initials.set,
+ arguments = {
+ {
+ { "location" },
+ { "enabled", "boolean" },
+ { "method" },
+ { "distance" ,"dimen" },
+ { "hoffset" ,"dimen" },
+ { "voffset" ,"dimen" },
+ { "font", "integer" },
+ { "dynamic", "integer" },
+ { "ca", "integer" },
+ { "ma", "integer" },
+ { "ta", "integer" },
+ { "n", "integer" },
+ { "m", "integer" },
+ }
+ }
+}
-- dropped caps experiment (will be done properly when luatex
-- stores the state in the local par node) .. btw, search still
@@ -324,6 +344,15 @@ actions[v_default] = function(head,setting)
if dynamic > 0 then
setattr(current,0,dynamic)
end
+-- apply font
+
+-- local g = nodes.copy(tonode(current))
+-- g.subtype = 0
+-- nodes.handlers.characters(g)
+-- nodes.handlers.protectglyphs(g)
+-- setfield(current,"char",g.char)
+-- nodes.free(g)
+
-- can be a helper
if ca and ca > 0 then
setattr(current,a_colorspace,ma == 0 and 1 or ma)
diff --git a/Master/texmf-dist/tex/context/base/typo-drp.mkiv b/Master/texmf-dist/tex/context/base/typo-drp.mkiv
index 3ac47466f7a..2520c3bfdef 100644
--- a/Master/texmf-dist/tex/context/base/typo-drp.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-drp.mkiv
@@ -99,21 +99,21 @@
{\useinitialstyleparameter\c!style}%
\useinitialcolorparameter\c!color
\edef\p_text{\initialparameter\c!text}% optional
- \ctxcommand{setinitial{
- location = "\initialparameter\c!location",
- enabled = true,
- n = \number\scratchcounter,
- m = \number\initialparameter\c!m,
- method = "\initialparameter\c!method",
- distance = \number\scratchdistance,
- hoffset = \number\scratchhoffset,
- voffset = \number\scratchvoffset,
- ma = \the\attribute\colormodelattribute,
- ca = \the\attribute\colorattribute,
- ta = \the\attribute\transparencyattribute,
- font = \fontid\font,
- dynamic = \number\attribute\zerocount, % it's a bit over the top to support this here
- }}%
+ \clf_setinitial
+ location {\initialparameter\c!location}%
+ enabled true\space
+ n \scratchcounter
+ m \numexpr\initialparameter\c!m\relax
+ method {\initialparameter\c!method}%
+ distance \scratchdistance
+ hoffset \scratchhoffset
+ voffset \scratchvoffset
+ ma \attribute\colormodelattribute
+ ca \attribute\colorattribute
+ ta \attribute\transparencyattribute
+ font \fontid\font
+ dynamic \attribute\zerocount % it's a bit over the top to support this here
+ \relax
\stopluacode
\kern\zeropoint % we need a node
\p_text
diff --git a/Master/texmf-dist/tex/context/base/typo-dua.lua b/Master/texmf-dist/tex/context/base/typo-dua.lua
index 73b00f033fd..1e9b325a623 100644
--- a/Master/texmf-dist/tex/context/base/typo-dua.lua
+++ b/Master/texmf-dist/tex/context/base/typo-dua.lua
@@ -710,7 +710,7 @@ local function apply_to_list(list,size,head,pardir)
if enddir and getsubtype(current) == parfillskip_code then
-- insert the last enddir before \parfillskip glue
local d = new_textdir(enddir)
--- setfield(d,"attr",copy_node(getfield(current,"attr")))
+ -- setfield(d,"attr",getfield(current,"attr"))
head = insert_node_before(head,current,d)
enddir = false
done = true
@@ -719,7 +719,7 @@ local function apply_to_list(list,size,head,pardir)
if begindir and getsubtype(current) == localpar_code then
-- local_par should always be the 1st node
local d = new_textdir(begindir)
--- setfield(d,"attr",copy_node(getfield(current,"attr")))
+ -- setfield(d,"attr",getfield(current,"attr"))
head, current = insert_node_after(head,current,d)
begindir = nil
done = true
@@ -727,7 +727,7 @@ local function apply_to_list(list,size,head,pardir)
end
if begindir then
local d = new_textdir(begindir)
--- setfield(d,"attr",copy_node(getfield(current,"attr")))
+ -- setfield(d,"attr",getfield(current,"attr"))
head = insert_node_before(head,current,d)
done = true
end
@@ -739,7 +739,7 @@ local function apply_to_list(list,size,head,pardir)
end
if enddir then
local d = new_textdir(enddir)
--- setfield(d,"attr",copy_node(getfield(current,"attr")))
+ -- setfield(d,"attr",getfield(current,"attr"))
head, current = insert_node_after(head,current,d)
done = true
end
diff --git a/Master/texmf-dist/tex/context/base/typo-dub.lua b/Master/texmf-dist/tex/context/base/typo-dub.lua
index b6581137b80..a1c9de75245 100644
--- a/Master/texmf-dist/tex/context/base/typo-dub.lua
+++ b/Master/texmf-dist/tex/context/base/typo-dub.lua
@@ -65,7 +65,6 @@ local getid = nuts.getid
local getsubtype = nuts.getsubtype
local getlist = nuts.getlist
local getattr = nuts.getattr
-local setattr = nuts.setattr
local getfield = nuts.getfield
local setfield = nuts.setfield
@@ -147,7 +146,7 @@ local report_directions = logs.reporter("typesetting","directions two")
--
-- l : left to right
-- r : right to left
--- al : right to legt arabic (esp punctuation issues)
+-- al : right to left arabic (esp punctuation issues)
-- explicit: (new)
--
@@ -327,7 +326,7 @@ end
-- ש ( ל ( א ) כ ) 2-8,4-6
-- ש ( ל [ א ] כ ) 2-8,4-6
-function resolve_fences(list,size,start,limit)
+local function resolve_fences(list,size,start,limit)
-- N0: funny effects, not always better, so it's an options
local stack = { }
local top = 0
@@ -820,7 +819,7 @@ local function apply_to_list(list,size,head,pardir)
if enddir and getsubtype(current) == parfillskip_code then
-- insert the last enddir before \parfillskip glue
local d = new_textdir(enddir)
--- setfield(d,"attr",copy_node(getfield(current,"attr")))
+ -- setfield(d,"attr",getfield(current,"attr"))
head = insert_node_before(head,current,d)
enddir = false
done = true
@@ -829,7 +828,7 @@ local function apply_to_list(list,size,head,pardir)
if begindir and getsubtype(current) == localpar_code then
-- local_par should always be the 1st node
local d = new_textdir(begindir)
--- setfield(d,"attr",copy_node(getfield(current,"attr")))
+ -- setfield(d,"attr",getfield(current,"attr"))
head, current = insert_node_after(head,current,d)
begindir = nil
done = true
@@ -837,7 +836,7 @@ local function apply_to_list(list,size,head,pardir)
end
if begindir then
local d = new_textdir(begindir)
--- setfield(d,"attr",copy_node(getfield(current,"attr")))
+ -- setfield(d,"attr",getfield(current,"attr"))
head = insert_node_before(head,current,d)
done = true
end
@@ -849,7 +848,7 @@ local function apply_to_list(list,size,head,pardir)
end
if enddir then
local d = new_textdir(enddir)
--- setfield(d,"attr",copy_node(getfield(current,"attr")))
+ -- setfield(d,"attr",getfield(current,"attr"))
head, current = insert_node_after(head,current,d)
done = true
end
diff --git a/Master/texmf-dist/tex/context/base/typo-fln.lua b/Master/texmf-dist/tex/context/base/typo-fln.lua
index 884a4c829f1..2076a7464ff 100644
--- a/Master/texmf-dist/tex/context/base/typo-fln.lua
+++ b/Master/texmf-dist/tex/context/base/typo-fln.lua
@@ -23,6 +23,9 @@ local firstlines = typesetters.firstlines
local nodes = nodes
local tasks = nodes.tasks
+local context = context
+local implement = interfaces.implement
+
local nuts = nodes.nuts
local tonut = nuts.tonut
local tonode = nuts.tonode
@@ -85,7 +88,21 @@ function firstlines.set(specification)
texsetattribute(a_firstline,1)
end
-commands.setfirstline = firstlines.set
+implement {
+ name = "setfirstline",
+ actions = firstlines.set,
+ arguments = {
+ {
+ { "alternative" },
+ { "font", "integer" },
+ { "dynamic", "integer" },
+ { "ma", "integer" },
+ { "ca", "integer" },
+ { "ta", "integer" },
+ { "n", "integer" },
+ }
+ }
+}
actions[v_line] = function(head,setting)
-- local attribute = fonts.specifiers.contextnumber(setting.feature) -- was experimental
@@ -262,7 +279,7 @@ end
-- goodie
-function commands.applytofirstcharacter(box,what)
+local function applytofirstcharacter(box,what)
local tbox = getbox(box) -- assumes hlist
local list = getlist(tbox)
local done = nil
@@ -283,3 +300,9 @@ function commands.applytofirstcharacter(box,what)
end
end
end
+
+implement {
+ name = "applytofirstcharacter",
+ actions = applytofirstcharacter,
+ arguments = { "integer", "string" }
+}
diff --git a/Master/texmf-dist/tex/context/base/typo-fln.mkiv b/Master/texmf-dist/tex/context/base/typo-fln.mkiv
index c092fc922e4..38a53bfa973 100644
--- a/Master/texmf-dist/tex/context/base/typo-fln.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-fln.mkiv
@@ -79,15 +79,15 @@
\begingroup
\edef\currentfirstline{#1}%
\usefirstlinestyleandcolor\c!style\c!color
- \ctxcommand{setfirstline {
- alternative = "\firstlineparameter\c!alternative",
- ma = \the\attribute\colormodelattribute,
- ca = \the\attribute\colorattribute,
- ta = \the\attribute\transparencyattribute,
- n = \number\firstlineparameter\c!n,
- font = \fontid\font,
- dynamic = \number\attribute\zerocount,
- }}%
+ \clf_setfirstline
+ alternative {\firstlineparameter\c!alternative}%
+ ma \attribute\colormodelattribute
+ ca \attribute\colorattribute
+ ta \attribute\transparencyattribute
+ n \numexpr\firstlineparameter\c!n\relax
+ font \fontid\font
+ dynamic \attribute\zerocount
+ \relax
\kern\zeropoint % we need a node
% \hskip\zeropoint\s!plus\emwidth\relax % can be an option
\endgroup
@@ -104,7 +104,7 @@
\unexpanded\def\applytofirstcharacter#1%
{\begingroup
\dowithnextbox
- {\ctxcommand{applytofirstcharacter(\number\nextbox,"\strippedcsname#1")}%
+ {\clf_applytofirstcharacter\nextbox{\strippedcsname#1}%
\unhbox\nextbox
\endgroup}%
\hbox}
diff --git a/Master/texmf-dist/tex/context/base/typo-inj.lua b/Master/texmf-dist/tex/context/base/typo-inj.lua
new file mode 100644
index 00000000000..b5d9e1c513a
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/typo-inj.lua
@@ -0,0 +1,94 @@
+if not modules then modules = { } end modules ['typo-inj'] = { -- was node-par
+ version = 1.001,
+ comment = "companion to typo-inj.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local tonumber = tonumber
+
+local context = context
+local implement = interfaces.implement
+
+local injectors = { }
+typesetters.injectors = injectors
+local list = { }
+injectors.list = list
+local showall = false
+
+local settings_to_array = utilities.parsers.settings_to_array
+
+local ctx_domarkinjector = context.domarkinjector
+local ctx_doactivateinjector = context.doactivateinjector
+
+table.setmetatableindex(list,function(t,k)
+ local v = {
+ counter = 0,
+ actions = { },
+ show = false,
+ active = false,
+ }
+ t[k] = v
+ return v
+end)
+
+function injectors.reset(name)
+ list[name] = nil
+end
+
+function injectors.set(name,numbers,command)
+ local injector = list[name]
+ local actions = injector.actions
+ local places = settings_to_array(numbers)
+ for i=1,#places do
+ actions[tonumber(places[i])] = command
+ end
+ if not injector.active then
+ ctx_doactivateinjector(name)
+ injector.active = true
+ end
+end
+
+function injectors.show(name)
+ if not name or name == "" then
+ showall = true
+ else
+ local list = settings_to_array(name)
+ for i=1,#list do
+ list[list[i]].show = true
+ end
+ end
+end
+
+function injectors.mark(name,show)
+ local injector = list[name]
+ local n = injector.counter + 1
+ injector.counter = n
+ if showall or injector.show then
+ ctx_domarkinjector(injector.actions[n] and 1 or 0,n)
+ end
+end
+
+function injectors.check(name,n) -- we could also accent n = number : +/- 2
+ local injector = list[name]
+ if n == false then
+ n = injector.counter
+ elseif n == nil then
+ n = injector.counter + 1 -- next (upcoming)
+ else
+ n = tonumber(n) or 0
+ end
+ local action = injector.actions[n]
+ if action then
+ context(action)
+ end
+end
+
+implement { name = "resetinjector", actions = injectors.reset, arguments = "string" }
+implement { name = "showinjector", actions = injectors.show, arguments = "string" }
+implement { name = "setinjector", actions = injectors.set, arguments = { "string", "string", "string" } }
+implement { name = "markinjector", actions = injectors.mark, arguments = "string" }
+implement { name = "checkinjector", actions = injectors.check, arguments = "string" }
+implement { name = "checkpreviousinjector", actions = injectors.check, arguments = { "string", true } }
+implement { name = "checknextinjector", actions = injectors.check }
diff --git a/Master/texmf-dist/tex/context/base/typo-inj.mkiv b/Master/texmf-dist/tex/context/base/typo-inj.mkiv
new file mode 100644
index 00000000000..46cd9fe4599
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/typo-inj.mkiv
@@ -0,0 +1,77 @@
+%D \module
+%D [ file=typo-inj,
+%D version=2014.10.13,
+%D title=\CONTEXT\ Typesetting Macros,
+%D subtitle=Triggering Actions,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Typesetting Macros / Triggering Actions}
+
+%D This is a sort of escape from too automatic typesetting of lists. I have
+%D been thinking fo a more generic injector for instance based on tags (as we
+%D already index each element) but thi sis sort of fuzzy because the number of a
+%D tag is not always incremented before we check for it. Also, registers and lists
+%D are among the few candidates that cannot be controlled directly by putting
+%D something in the input. So,m for the moment I stick to this mechanism but
+%D future versions of \CONTEXT\ might do it differently. Compatibility is not much
+%D of an issue here as this mechanism is only to be used in final production runs.
+
+\unprotect
+
+\registerctxluafile{typo-inj}{1.001}
+
+% todo: no need in trialmode
+
+%D \showinjector
+%D
+%D \setinjector[register][3][\column]
+%D \setinjector[list] [2][{\blank[3*big]}]
+%D
+%D \starttext
+%D \placelist[section][criterium=text]
+%D \blank[3*big]
+%D \placeregister[index][criterium=text]
+%D \page
+%D \startsection[title=Alpha] first \index{first} \stopsection
+%D \startsection[title=Beta] second \index{second} \stopsection
+%D \startsection[title=Gamma] third \index{third} \stopsection
+%D \startsection[title=Delta] fourth \index{fourth} \stopsection
+%D \stoptext
+
+\unexpanded\def\resetinjector [#1]{\clf_resetinjector{#1}}
+\unexpanded\def\markinjector [#1]{\dontleavehmode\clf_markinjector{#1}}
+\unexpanded\def\checkinjector [#1]{\clf_checkinjector{#1}}
+\unexpanded\def\checknextinjector {\clf_checknextinjector}
+\unexpanded\def\checkpreviousinjector {\clf_checkpreviousinjector}
+\unexpanded\def\dosetinjector [#1][#2][#3]{\clf_setinjector{#1}{#2}{#3}}
+\unexpanded\def\doshowinjector [#1]{\clf_showinjector{#1}}
+
+\unexpanded\def\setinjector {\dotripleargument\dosetinjector}
+\unexpanded\def\showinjector{\dosingleempty\doshowinjector}
+
+\unexpanded\def\domarkinjector#1#2% called at the lua end
+ {\dontleavehmode\llap{\infofont\ifcase#1\else\red\fi<#2>\quad}}
+
+% low level definers .. we could have \injectors_mark and \injectors_check and then
+% use \v!list instead of \s!list
+
+\unexpanded\def\doinstallinjector#1%
+ {\letvalue{typo_injectors_mark_#1}\donothing
+ \letvalue{typo_injectors_check_#1}\donothing}
+
+\unexpanded\def\doactivateinjector#1% used at lua end
+ {\setuxvalue{typo_injectors_mark_#1}{\dontleavehmode\noexpand\clf_markinjector{#1}}%
+ \setuxvalue{typo_injectors_check_#1}{\noexpand\clf_checkinjector{#1}}}
+
+\unexpanded\def\dotestinjector#1% only for testing outside unprotect
+ {\csname typo_injectors_check_#1\endcsname
+ \csname typo_injectors_mark_#1\endcsname}
+
+\protect \endinput
+
diff --git a/Master/texmf-dist/tex/context/base/typo-itc.lua b/Master/texmf-dist/tex/context/base/typo-itc.lua
index 7373c0321fb..f37549dc830 100644
--- a/Master/texmf-dist/tex/context/base/typo-itc.lua
+++ b/Master/texmf-dist/tex/context/base/typo-itc.lua
@@ -32,6 +32,7 @@ local tonode = nuts.tonode
local tonut = nuts.tonut
local getfield = nuts.getfield
+local getprev = nuts.getprev
local getnext = nuts.getnext
local getid = nuts.getid
local getfont = nuts.getfont
@@ -42,6 +43,7 @@ local setattr = nuts.setattr
local insert_node_after = nuts.insert_after
local delete_node = nuts.delete
local end_of_math = nuts.end_of_math
+local find_tail = nuts.tail
local texgetattribute = tex.getattribute
local texsetattribute = tex.setattribute
@@ -56,6 +58,8 @@ local fontdata = fonthashes.identifiers
local italicsdata = fonthashes.italics
local exheights = fonthashes.exheights
+local implement = interfaces.implement
+
local forcedvariant = false
function typesetters.italics.forcevariant(variant)
@@ -98,16 +102,55 @@ end
-- todo: clear attribute
+local function okay(data,current,font,prevchar,previtalic,char,what)
+ if not data then
+ if trace_italics then
+ report_italics("ignoring %p between %s italic %C and italic %C",previtalic,what,prevchar,char)
+ end
+ return false
+ end
+ if threshold then
+ local ht = getfield(current,"height")
+ local ex = exheights[font]
+ local th = threshold * ex
+ if ht <= th then
+ if trace_italics then
+ report_italics("ignoring correction between %s italic %C and regular %C, height %p less than threshold %p",prevchar,what,char,ht,th)
+ end
+ return false
+ end
+ end
+ if trace_italics then
+ report_italics("inserting %p between %s italic %C and regular %C",previtalic,what,prevchar,char)
+ end
+ return true
+end
+
function italics.handler(head)
- head = tonut(head)
- local done = false
- local italic = 0
- local lastfont = nil
- local lastattr = nil
- local previous = nil
- local prevchar = nil
- local current = head
- local inserted = nil
+
+ local prev = nil
+ local prevchar = nil
+ local prevhead = tonut(head)
+ local previtalic = 0
+ local previnserted = nil
+
+ local replace = nil
+ local replacechar = nil
+ local replacehead = nil
+ local replaceitalic = 0
+ local replaceinserted = nil
+
+ local post = nil
+ local postchar = nil
+ local posthead = nil
+ local postitalic = 0
+ local postinserted = nil
+
+ local current = prevhead
+ local done = false
+ local lastfont = nil
+ local lastattr = nil
+
while current do
local id = getid(current)
if id == glyph_code then
@@ -115,40 +158,45 @@ function italics.handler(head)
local char = getchar(current)
local data = italicsdata[font]
if font ~= lastfont then
- if italic ~= 0 then
- if data then
- if trace_italics then
- report_italics("ignoring %p between italic %C and italic %C",italic,prevchar,char)
+ if previtalic ~= 0 then
+ if okay(data,current,font,prevchar,previtalic,char,"glyph") then
+ insert_node_after(prevhead,prev,new_correction_kern(previtalic))
+ done = true
+ end
+ elseif previnserted and data then
+ if trace_italics then
+ report_italics("deleting last correction before %s %C",char,"glyph")
+ end
+ delete_node(prevhead,previnserted)
+ else
+ --
+ if replaceitalic ~= 0 then
+ if okay(data,replace,font,replacechar,replaceitalic,char,"replace") then
+ insert_node_after(replacehead,replace,new_correction_kern(replaceitalic))
+ done = true
end
- else
- local okay = true
- if threshold then
- local ht = getfield(current,"height")
- local ex = exheights[font]
- local th = threshold * ex
- if ht <= th then
- if trace_italics then
- report_italics("ignoring correction between italic %C and regular %C, height %p less than threshold %p",prevchar,char,ht,th)
- end
- okay = false
- end
+ replaceitalic = 0
+ elseif replaceinserted and data then
+ if trace_italics then
+ report_italics("deleting last correction before %s %C","replace",char)
end
- if okay then
- if trace_italics then
- report_italics("inserting %p between italic %C and regular %C",italic,prevchar,char)
- end
- insert_node_after(head,previous,new_correction_kern(italic))
+ delete_node(replacehead,replaceinserted)
+ end
+ --
+ if postitalic ~= 0 then
+ if okay(data,post,font,postchar,postitalic,char,"post") then
+ insert_node_after(posthead,post,new_correction_kern(postitalic))
done = true
end
+ postitalic = 0
+ elseif postinserted and data then
+ if trace_italics then
+ report_italics("deleting last correction before %s %C","post",char)
+ end
+ delete_node(posthead,postinserted)
end
- elseif inserted and data then
- if trace_italics then
- report_italics("deleting last correction before %C",char)
- end
- delete_node(head,inserted)
- else
- -- nothing
end
+ --
lastfont = font
end
if data then
@@ -157,63 +205,240 @@ function italics.handler(head)
local cd = data[char]
if not cd then
-- this really can happen
- italic = 0
+ previtalic = 0
else
- italic = cd.italic or cd.italic_correction
- if not italic then
- italic = setitalicinfont(font,char) -- calculated once
- -- italic = 0
+ previtalic = cd.italic or cd.italic_correction
+ if not previtalic then
+ previtalic = setitalicinfont(font,char) -- calculated once
+ -- previtalic = 0
end
- if italic ~= 0 then
+ if previtalic ~= 0 then
lastfont = font
lastattr = attr
- previous = current
+ prev = current
+ -- prevhead = head
prevchar = char
end
end
else
- italic = 0
+ previtalic = 0
end
else
- italic = 0
+ previtalic = 0
end
- inserted = nil
+ previnserted = nil
+ replaceinserted = nil
+ postinserted = nil
elseif id == disc_code then
- -- skip
- elseif id == kern_code then
- inserted = nil
- italic = 0
+ previnserted = nil
+ previtalic = 0
+ replaceinserted = nil
+ replaceitalic = 0
+ postinserted = nil
+ postitalic = 0
+ replace = getfield(current,"replace")
+ if replace then
+ local current = find_tail(replace)
+ if getid(current) ~= glyph_code then
+ current = getprev(current)
+ end
+ if current and getid(current) == glyph_code then
+ local font = getfont(current)
+ local char = getchar(current)
+ local data = italicsdata[font]
+ if data then
+ local attr = forcedvariant or getattr(current,a_italics)
+ if attr and attr > 0 then
+ local cd = data[char]
+ if not cd then
+ -- this really can happen
+ replaceitalic = 0
+ else
+ replaceitalic = cd.italic or cd.italic_correction
+ if not replaceitalic then
+ replaceitalic = setitalicinfont(font,char) -- calculated once
+ -- replaceitalic = 0
+ end
+ if replaceitalic ~= 0 then
+ lastfont = font
+ lastattr = attr
+ replacechar = char
+ replacehead = replace
+ replace = current
+ end
+ end
+-- else
+-- replaceitalic = 0
+ end
+-- else
+-- replaceitalic = 0
+ end
+-- else
+-- replaceitalic = 0
+ end
+-- replaceinserted = nil
+-- else
+-- replaceitalic = 0
+-- replaceinserted = nil
+ end
+ post = getfield(current,"post")
+ if post then
+ local current = find_tail(post)
+ if getid(current) ~= glyph_code then
+ current = getprev(current)
+ end
+ if current and getid(current) == glyph_code then
+ local font = getfont(current)
+ local char = getchar(current)
+ local data = italicsdata[font]
+ if data then
+ local attr = forcedvariant or getattr(current,a_italics)
+ if attr and attr > 0 then
+ local cd = data[char]
+ if not cd then
+ -- this really can happen
+-- postitalic = 0
+ else
+ postitalic = cd.italic or cd.italic_correction
+ if not postitalic then
+ postitalic = setitalicinfont(font,char) -- calculated once
+ -- postitalic = 0
+ end
+ if postitalic ~= 0 then
+ lastfont = font
+ lastattr = attr
+ postchar = char
+ posthead = post
+ post = current
+ end
+ end
+-- else
+-- postitalic = 0
+ end
+-- else
+-- postitalic = 0
+ end
+-- else
+-- postitalic = 0
+ end
+-- postinserted = nil
+-- else
+-- postitalic = 0
+-- postinserted = nil
+ end
+ elseif id == kern_code then -- how about fontkern ?
+ previnserted = nil
+ previtalic = 0
+ replaceinserted = nil
+ replaceitalic = 0
+ postinserted = nil
+ postitalic = 0
elseif id == glue_code then
- if italic ~= 0 then
+ if previtalic ~= 0 then
if trace_italics then
- report_italics("inserting %p between italic %C and glue",italic,prevchar)
+ report_italics("inserting %p between %s italic %C and glue",previtalic,"glyph",prevchar)
+ end
+ previnserted = new_correction_glue(previtalic) -- maybe just add ? else problem with penalties
+ previtalic = 0
+ done = true
+ insert_node_after(prevhead,prev,previnserted)
+ else
+ if replaceitalic ~= 0 then
+ if trace_italics then
+ report_italics("inserting %p between %s italic %C and glue",replaceitalic,"replace",replacechar)
+ end
+ replaceinserted = new_correction_kern(replaceitalic) -- needs to be a kern
+ replaceitalic = 0
+ done = true
+ insert_node_after(replacehead,replace,replaceinserted)
+ end
+ if postitalic ~= 0 then
+ if trace_italics then
+ report_italics("inserting %p between %s italic %C and glue",postitalic,"post",postchar)
+ end
+ postinserted = new_correction_kern(postitalic) -- needs to be a kern
+ postitalic = 0
+ done = true
+ insert_node_after(posthead,post,postinserted)
end
- inserted = new_correction_glue(italic) -- maybe just add ? else problem with penalties
- insert_node_after(head,previous,inserted)
- italic = 0
- done = true
end
elseif id == math_code then
current = end_of_math(current)
- elseif italic ~= 0 then
- if trace_italics then
- report_italics("inserting %p between italic %C and whatever",italic,prevchar)
+ previnserted = nil
+ previtalic = 0
+ replaceinserted = nil
+ replaceitalic = 0
+ postinserted = nil
+ postitalic = 0
+ else
+ if previtalic ~= 0 then
+ if trace_italics then
+ report_italics("inserting %p between %s italic %C and whatever",previtalic,"glyph",prevchar)
+ end
+ insert_node_after(prevhead,prev,new_correction_kern(previtalic))
+ previnserted = nil
+ previtalic = 0
+ replaceinserted = nil
+ replaceitalic = 0
+ postinserted = nil
+ postitalic = 0
+ done = true
+ else
+ if replaceitalic ~= 0 then
+ if trace_italics then
+ report_italics("inserting %p between %s italic %C and whatever",replaceritalic,"replace",replacechar)
+ end
+ insert_node_after(replacehead,replace,new_correction_kern(replaceitalic))
+ previnserted = nil
+ previtalic = 0
+ replaceinserted = nil
+ replaceitalic = 0
+ postinserted = nil
+ postitalic = 0
+ done = true
+ end
+ if postitalic ~= 0 then
+ if trace_italics then
+ report_italics("inserting %p between %s italic %C and whatever",postitalic,"post",postchar)
+ end
+ insert_node_after(posthead,post,new_correction_kern(postitalic))
+ previnserted = nil
+ previtalic = 0
+ replaceinserted = nil
+ replaceitalic = 0
+ postinserted = nil
+ postitalic = 0
+ done = true
+ end
end
- inserted = nil
- insert_node_after(head,previous,new_correction_kern(italic))
- italic = 0
- done = true
end
current = getnext(current)
end
- if italic ~= 0 and lastattr > 1 then -- more control is needed here
- if trace_italics then
- report_italics("inserting %p between italic %C and end of list",italic,prevchar)
+ if lastattr and lastattr > 1 then -- more control is needed here
+ if previtalic ~= 0 then
+ if trace_italics then
+ report_italics("inserting %p between %s italic %C and end of list",previtalic,"glyph",prevchar)
+ end
+ insert_node_after(prevhead,prev,new_correction_kern(previtalic))
+ done = true
+ else
+ if replaceitalic ~= 0 then
+ if trace_italics then
+ report_italics("inserting %p between %s italic %C and end of list",replaceitalic,"replace",replacechar)
+ end
+ insert_node_after(replacehead,replace,new_correction_kern(replaceitalic))
+ done = true
+ end
+ if postitalic ~= 0 then
+ if trace_italics then
+ report_italics("inserting %p between %s italic %C and end of list",postitalic,"post",postchar)
+ end
+ insert_node_after(posthead,post,new_correction_kern(postitalic))
+ done = true
+ end
end
- insert_node_after(head,previous,new_correction_kern(italic))
- done = true
end
- return tonode(head), done
+ return head, done
end
local enable
@@ -241,10 +466,21 @@ function italics.reset()
texsetattribute(a_italics,unsetvalue)
end
+implement {
+ name = "setitaliccorrection",
+ actions = italics.set,
+ arguments = "string"
+}
+
+implement {
+ name = "resetitaliccorrection",
+ actions = italics.reset,
+}
+
local variables = interfaces.variables
local settings_to_hash = utilities.parsers.settings_to_hash
-function commands.setupitaliccorrection(option) -- no grouping !
+local function setupitaliccorrection(option) -- no grouping !
if enable then
enable()
end
@@ -268,16 +504,28 @@ function commands.setupitaliccorrection(option) -- no grouping !
end
end
+implement {
+ name = "setupitaliccorrection",
+ actions = setupitaliccorrection,
+ arguments = "string"
+}
+
-- for manuals:
local stack = { }
-function commands.pushitaliccorrection()
- table.insert(stack,{forcedvariant, texgetattribute(a_italics) })
-end
+implement {
+ name = "pushitaliccorrection",
+ actions = function()
+ table.insert(stack,{forcedvariant, texgetattribute(a_italics) })
+ end
+}
-function commands.popitaliccorrection()
- local top = table.remove(stack)
- forcedvariant = top[1]
- texsetattribute(a_italics,top[2])
-end
+implement {
+ name = "popitaliccorrection",
+ actions = function()
+ local top = table.remove(stack)
+ forcedvariant = top[1]
+ texsetattribute(a_italics,top[2])
+ end
+}
diff --git a/Master/texmf-dist/tex/context/base/typo-itc.mkvi b/Master/texmf-dist/tex/context/base/typo-itc.mkvi
index 4a3bba51850..c0aa8e2f6dd 100644
--- a/Master/texmf-dist/tex/context/base/typo-itc.mkvi
+++ b/Master/texmf-dist/tex/context/base/typo-itc.mkvi
@@ -42,10 +42,10 @@
% 2 = end of word and end of a list
\unexpanded\def\setitaliccorrection[#code]% rather low level (might go away)
- {\ctxlua{typesetters.italics.set(\number#code)}}
+ {\clf_setitaliccorrection#code\relax}
\unexpanded\def\resetitaliccorrection% rather low level (might go away)
- {\ctxlua{typesetters.italics.reset()}}
+ {\clf_resetitaliccorrection}
% global : no attributes, just always (faster and less memory)
% text : only text
@@ -53,7 +53,7 @@
% none : -
\unexpanded\def\setupitaliccorrection[#settings]%
- {\ctxcommand{setupitaliccorrection("#settings")}}
+ {\clf_setupitaliccorrection{#settings}}
\appendtoks
\attribute\italicsattribute\attributeunsetvalue
diff --git a/Master/texmf-dist/tex/context/base/typo-itm.mkiv b/Master/texmf-dist/tex/context/base/typo-itm.mkiv
index eb47e407616..0bb8170c721 100644
--- a/Master/texmf-dist/tex/context/base/typo-itm.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-itm.mkiv
@@ -109,9 +109,9 @@
\let\p_typo_items_symbol\empty
\let\m_typo_items_symbol\firstofoneargument
\else
- \doifconversiondefinedelse\p_typo_items_symbol
+ \doifelseconversiondefined\p_typo_items_symbol
{\def\m_typo_items_symbol{\convertnumber\p_typo_items_symbol}}
- {\doifsymboldefinedelse\p_typo_items_symbol
+ {\doifelsesymboldefined\p_typo_items_symbol
{\def\m_typo_items_symbol{\symbol[\p_typo_items_symbol]\gobbleoneargument}}
{\let\m_typo_items_symbol\firstofoneargument}}%
\fi\fi
diff --git a/Master/texmf-dist/tex/context/base/typo-krn.lua b/Master/texmf-dist/tex/context/base/typo-krn.lua
index a8ffe557be4..46a977cfd49 100644
--- a/Master/texmf-dist/tex/context/base/typo-krn.lua
+++ b/Master/texmf-dist/tex/context/base/typo-krn.lua
@@ -11,7 +11,8 @@ if not modules then modules = { } end modules ['typo-krn'] = {
local next, type, tonumber = next, type, tonumber
local utfchar = utf.char
-local nodes, node, fonts = nodes, node, fonts
+local nodes = nodes
+local fonts = fonts
local tasks = nodes.tasks
local nuts = nodes.nuts
@@ -20,11 +21,10 @@ local nodepool = nuts.pool
local tonode = nuts.tonode
local tonut = nuts.tonut
+-- check what is used
+
local find_node_tail = nuts.tail
local free_node = nuts.free
-local free_nodelist = nuts.flush_list
-local copy_node = nuts.copy
-local copy_nodelist = nuts.copy_list
local insert_node_before = nuts.insert_before
local insert_node_after = nuts.insert_after
local end_of_math = nuts.end_of_math
@@ -51,6 +51,7 @@ local nodecodes = nodes.nodecodes
local kerncodes = nodes.kerncodes
local skipcodes = nodes.skipcodes
local disccodes = nodes.disccodes
+local listcodes = nodes.listcodes
local glyph_code = nodecodes.glyph
local kern_code = nodecodes.kern
@@ -60,7 +61,12 @@ local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
local math_code = nodecodes.math
+local box_list_code = listcodes.box
+local user_list_code = listcodes.unknown
+
local discretionary_code = disccodes.discretionary
+local automatic_code = disccodes.automatic
+
local kerning_code = kerncodes.kerning
local userkern_code = kerncodes.userkern
local userskip_code = skipcodes.userskip
@@ -203,39 +209,200 @@ local function spec_injector(fillup,width,stretch,shrink)
end
end
--- needs checking ... base mode / node mode -- also use insert_before/after etc
+-- a simple list injector, no components and such .. just disable ligatures in
+-- kern mode .. maybe not even hyphenate ... anyway, the next one is for simple
+-- sublists .. beware: we can have char -1
+
+local function inject_begin(boundary,prev,keeptogether,krn,ok) -- prev is a glyph
+ local id = getid(boundary)
+ if id == kern_code then
+ if getsubtype(boundary) == kerning_code or getattr(boundary,a_fontkern) then
+ local inject = true
+ if keeptogether then
+ local next = getnext(boundary)
+ if not next or (getid(next) == glyph_code and keeptogether(prev,next)) then
+ inject = false
+ end
+ end
+ if inject then
+ -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
+ setfield(boundary,"subtype",userkern_code)
+ setfield(boundary,"kern",getfield(boundary,"kern") + quaddata[getfont(prev)]*krn)
+ return boundary, true
+ end
+ end
+ elseif id == glyph_code then
+ if keeptogether and keeptogether(boundary,prev) then
+ -- keep 'm
+ else
+ local charone = getchar(prev)
+ if charone > 0 then
+ local font = getfont(boundary)
+ local chartwo = getchar(boundary)
+ local kerns = chardata[font][charone].kerns
+ local kern = new_kern((kerns and kerns[chartwo] or 0) + quaddata[font]*krn)
+ setfield(boundary,"prev",kern)
+ setfield(kern,"next",boundary)
+ return kern, true
+ end
+ end
+ end
+ return boundary, ok
+end
+
+local function inject_end(boundary,next,keeptogether,krn,ok)
+ local tail = find_node_tail(boundary)
+ local id = getid(tail)
+ if id == kern_code then
+ if getsubtype(tail) == kerning_code or getattr(tail,a_fontkern) then
+ local inject = true
+ if keeptogether then
+ local prev = getprev(tail)
+ if getid(prev) == glyph_code and keeptogether(prev,two) then
+ inject = false
+ end
+ end
+ if inject then
+ -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
+ setfield(tail,"subtype",userkern_code)
+ setfield(tail,"kern",getfield(tail,"kern") + quaddata[getfont(next)]*krn)
+ return boundary, true
+ end
+ end
+ elseif id == glyph_code then
+ if keeptogether and keeptogether(tail,two) then
+ -- keep 'm
+ else
+ local charone = getchar(tail)
+ if charone > 0 then
+ local font = getfont(tail)
+ local chartwo = getchar(next)
+ local kerns = chardata[font][charone].kerns
+ local kern = (kerns and kerns[chartwo] or 0) + quaddata[font]*krn
+ insert_node_after(boundary,tail,new_kern(kern))
+ return boundary, true
+ end
+ end
+ end
+ return boundary, ok
+end
-local function do_process(head,force) -- todo: glue so that we can fully stretch
- local start, done, lastfont = head, false, nil
+local function process_list(head,keeptogether,krn,font,okay)
+ local start = head
+ local prev = nil
+ local pid = nil
+ local kern = 0
+ local mark = font and markdata[font]
+ while start do
+ local id = getid(start)
+ if id == glyph_code then
+ if not font then
+ font = getfont(start)
+ mark = markdata[font]
+ kern = quaddata[font]*krn
+ end
+ if prev then
+ local char = getchar(start)
+ if mark[char] then
+ -- skip
+ elseif pid == kern_code then
+ if getsubtype(prev) == kerning_code or getattr(prev,a_fontkern) then
+ local inject = true
+ if keeptogether then
+ local prevprev = getprev(prev)
+ if getid(prevprev) == glyph_code and keeptogether(prevprev,start) then
+ inject = false
+ end
+ end
+ if inject then
+ -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
+ setfield(prev,"subtype",userkern_code)
+ setfield(prev,"kern",getfield(prev,"kern") + kern)
+ okay = true
+ end
+ end
+ elseif pid == glyph_code then
+ if keeptogether and keeptogether(prev,start) then
+ -- keep 'm
+ else
+ local prevchar = getchar(prev)
+ local kerns = chardata[font][prevchar].kerns
+ -- if kerns then
+ -- print("it happens indeed, basemode kerns not yet injected")
+ -- end
+ insert_node_before(head,start,new_kern((kerns and kerns[char] or 0) + kern))
+ okay = true
+ end
+ end
+ end
+ end
+ if start then
+ prev = start
+ pid = id
+ start = getnext(start)
+ end
+ end
+ return head, okay, prev
+end
+
+local function closest_bound(b,get)
+ b = get(b)
+ if b and getid(b) ~= glue_code then
+ while b do
+ if not getattr(b,a_kerns) then
+ break
+ elseif getid(b) == glyph_code then
+ return b, getfont(b)
+ else
+ b = get(b)
+ end
+ end
+ end
+end
+
+function kerns.handler(head)
+ local head = tonut(head)
+ local start = head
+ local done = false
+ local lastfont = nil
local keepligature = kerns.keepligature
local keeptogether = kerns.keeptogether
- local fillup = false
+ local fillup = false
+ local bound = false
+ local prev = nil
+ local previd = nil
+ local prevchar = nil
+ local prevfont = nil
+ local prevmark = nil
while start do
- -- faster to test for attr first
- local attr = force or getattr(start,a_kerns)
+ -- fontkerns don't get the attribute but they always sit between glyphs so
+ -- are always valid bound .. disc nodes also somtimes don't get them
+ local id = getid(start)
+ local attr = getattr(start,a_kerns)
if attr and attr > 0 then
- setattr(start,a_kerns,unsetvalue)
+ setattr(start,a_kerns,0) -- unsetvalue)
local krn = mapping[attr]
if krn == v_max then
- krn = .25
+ krn = .25
fillup = true
else
fillup = false
end
- if krn and krn ~= 0 then
- local id = getid(start)
- if id == glyph_code then -- we could use the subtype ligature
- lastfont = getfont(start)
- local c = getfield(start,"components")
- if not c then
- -- fine
- elseif keepligature and keepligature(start) then
- -- keep 'm
- else
- c = do_process(c,attr)
+ if not krn or krn == 0 then
+ bound = false
+ elseif id == glyph_code then -- we could use the subtype ligature
+ local c = getfield(start,"components")
+ if not c then
+ -- fine
+ elseif keepligature and keepligature(start) then
+ -- keep 'm
+ c = nil
+ else
+ while c do
local s = start
- local p, n = getprev(s), getnext(s)
- local tail = find_node_tail(c)
+ local t = find_node_tail(c)
+ local p = getprev(s)
+ local n = getnext(s)
if p then
setfield(p,"next",c)
setfield(c,"prev",p)
@@ -243,165 +410,190 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch
head = c
end
if n then
- setfield(n,"prev",tail)
+ setfield(n,"prev",t)
+ setfield(t,"next",n)
end
- setfield(tail,"next",n)
start = c
setfield(s,"components",nil)
- -- we now leak nodes !
- -- free_node(s)
- done = true
+ free_node(s)
+ c = getfield(start,"components")
end
- local prev = getprev(start)
- if not prev then
- -- skip
- elseif markdata[lastfont][getchar(start)] then
- -- skip
- else
- local pid = getid(prev)
- if not pid then
- -- nothing
- elseif pid == kern_code then
- if getsubtype(prev) == kerning_code or getattr(prev,a_fontkern) then
- if keeptogether and getid(getprev(prev)) == glyph_code and keeptogether(getprev(prev),start) then -- we could also pass start
- -- keep 'm
- else
- -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
- setfield(prev,"subtype",userkern_code)
- setfield(prev,"kern",getfield(prev,"kern") + quaddata[lastfont]*krn) -- here
- done = true
- end
- end
- elseif pid == glyph_code then
- if getfont(prev) == lastfont then
- local prevchar, lastchar = getchar(prev), getchar(start)
- if keeptogether and keeptogether(prev,start) then
- -- keep 'm
- else
- local kerns = chardata[lastfont][prevchar].kerns
- local kern = kerns and kerns[lastchar] or 0
- krn = kern + quaddata[lastfont]*krn -- here
- insert_node_before(head,start,kern_injector(fillup,krn))
- done = true
- end
- else
- krn = quaddata[lastfont]*krn -- here
- insert_node_before(head,start,kern_injector(fillup,krn))
- done = true
- end
- elseif pid == disc_code then
- -- a bit too complicated, we can best not copy and just calculate
- -- but we could have multiple glyphs involved so ...
- local disc = prev -- disc
- local prv, nxt = getprev(disc), getnext(disc)
- if getsubtype(disc) == discretionary_code then
- -- maybe we should forget about this variant as there is no glue
- -- possible
- local pre, post, replace = getfield(disc,"pre"), getfield(disc,"post"), getfield(disc,"replace")
- if pre and prv then -- must pair with getprev(start)
- local before = copy_node(prv)
- setfield(pre,"prev",before)
- setfield(before,"next",pre)
- setfield(before,"prev",nil)
- pre = do_process(before,attr)
- pre = getnext(pre)
- setfield(pre,"prev",nil)
- setfield(disc,"pre",pre)
- free_node(before)
- end
- if post and nxt then -- must pair with start
- local after = copy_node(nxt)
- local tail = find_node_tail(post)
- setfield(tail,"next",after)
- setfield(after,"prev",tail)
- setfield(after,"next",nil)
- post = do_process(post,attr)
- setfield(tail,"next",nil)
- setfield(disc,"post",post)
- free_node(after)
- end
- if replace and prv and nxt then -- must pair with start and start.prev
- local before = copy_node(prv)
- local after = copy_node(nxt)
- local tail = find_node_tail(replace)
- setfield(replace,"prev",before)
- setfield(before,"next",replace)
- setfield(before,"prev",nil)
- setfield(tail,"next",after)
- setfield(after,"prev",tail)
- setfield(after,"next",nil)
- replace = do_process(before,attr)
- replace = getnext(replace)
- setfield(replace,"prev",nil)
- setfield(getfield(after,"prev"),"next",nil)
- setfield(disc,"replace",replace)
- free_node(after)
- free_node(before)
- elseif prv and getid(prv) == glyph_code and getfont(prv) == lastfont then
- local prevchar, lastchar = getchar(prv), getchar(start)
- local kerns = chardata[lastfont][prevchar].kerns
- local kern = kerns and kerns[lastchar] or 0
- krn = kern + quaddata[lastfont]*krn -- here
- setfield(disc,"replace",kern_injector(false,krn)) -- only kerns permitted, no glue
- else
- krn = quaddata[lastfont]*krn -- here
- setfield(disc,"replace",kern_injector(false,krn)) -- only kerns permitted, no glue
- end
- else
- -- this one happens in most cases: automatic (-), explicit (\-), regular (patterns)
- if prv and getid(prv) == glyph_code and getfont(prv) == lastfont then
- -- the normal case
- local prevchar, lastchar = getchar(prv), getchar(start)
- local kerns = chardata[lastfont][prevchar].kerns
- local kern = kerns and kerns[lastchar] or 0
- krn = kern + quaddata[lastfont]*krn
- else
- krn = quaddata[lastfont]*krn
- end
- insert_node_before(head,start,kern_injector(fillup,krn))
+ end
+ local char = getchar(start)
+ local font = getfont(start)
+ local mark = markdata[font]
+ if not bound then
+ -- yet
+ elseif mark[char] then
+ -- skip
+ elseif previd == kern_code then
+ if getsubtype(prev) == kerning_code or getattr(prev,a_fontkern) then
+ local inject = true
+ if keeptogether then
+ if previd == glyph_code and keeptogether(prev,start) then
+ inject = false
end
end
+ if inject then
+ -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
+ setfield(prev,"subtype",userkern_code)
+ setfield(prev,"kern",getfield(prev,"kern") + quaddata[font]*krn)
+ done = true
+ end
end
- elseif id == glue_code then
- local subtype = getsubtype(start)
- if subtype == userskip_code or subtype == xspaceskip_code or subtype == spaceskip_code then
- local s = getfield(start,"spec")
- local w = getfield(s,"width")
- if w > 0 then
- local width, stretch, shrink = w+gluefactor*w*krn, getfield(s,"stretch"), getfield(s,"shrink")
- setfield(start,"spec",spec_injector(fillup,width,stretch*width/w,shrink*width/w))
+ elseif previd == glyph_code then
+ if prevfont == font then
+ if keeptogether and keeptogether(prev,start) then
+ -- keep 'm
+ else
+ local kerns = chardata[font][prevchar].kerns
+ local kern = (kerns and kerns[char] or 0) + quaddata[font]*krn
+ insert_node_before(head,start,kern_injector(fillup,kern))
done = true
end
+ else
+ insert_node_before(head,start,kern_injector(fillup,quaddata[font]*krn))
+ done = true
end
- elseif id == kern_code then
- -- if getsubtype(start) == kerning_code then -- handle with glyphs
- -- local sk = getfield(start,"kern")
- -- if sk > 0 then
- -- setfield(start,"kern",sk*krn)
- -- done = true
- -- end
- -- end
- elseif lastfont and (id == hlist_code or id == vlist_code) then -- todo: lookahead
- local p = getprev(start)
- if p and getid(p) ~= glue_code then
- insert_node_before(head,start,kern_injector(fillup,quaddata[lastfont]*krn))
+ end
+ prev = start
+ prevchar = char
+ prevfont = font
+ prevmark = mark
+ previd = id
+ bound = true
+ elseif id == disc_code then
+ local prev, next, pglyph, nglyph -- delayed till needed
+ local subtype = getsubtype(start)
+ if subtype == automatic_code then
+ -- this is kind of special, as we have already injected the
+ -- previous kern
+ local prev = getprev(start)
+ local pglyph = prev and getid(prev) == glyph_code
+ languages.expand(start,pglyph and prev)
+ -- we can have a different start now
+ elseif subtype ~= discretionary_code then
+ prev = getprev(start)
+ pglyph = prev and getid(prev) == glyph_code
+ languages.expand(start,pglyph and prev)
+ end
+ local pre = getfield(start,"pre")
+ local post = getfield(start,"post")
+ local replace = getfield(start,"replace")
+ -- we really need to reasign the fields as luatex keeps track of
+ -- the tail in a temp preceding head .. kind of messy so we might
+ -- want to come up with a better solution some day like a real
+ -- pretail etc fields in a disc node
+ --
+ -- maybe i'll merge the now split functions
+ if pre then
+ local okay = false
+ if not prev then
+ prev = prev or getprev(start)
+ pglyph = prev and getid(prev) == glyph_code
+ end
+ if pglyph then
+ pre, okay = inject_begin(pre,prev,keeptogether,krn,okay)
+ end
+ pre, okay = process_list(pre,keeptogether,krn,false,okay)
+ if okay then
+ setfield(start,"pre",pre)
done = true
end
- local n = getnext(start)
- if n and getid(n) ~= glue_code then
- insert_node_after(head,start,kern_injector(fillup,quaddata[lastfont]*krn))
+ end
+ if post then
+ local okay = false
+ if not next then
+ next = getnext(start)
+ nglyph = next and getid(next) == glyph_code
+ end
+ if nglyph then
+ post, okay = inject_end(post,next,keeptogether,krn,okay)
+ end
+ post, okay = process_list(post,keeptogether,krn,false,okay)
+ if okay then
+ setfield(start,"post",post)
done = true
end
- elseif id == math_code then
- start = end_of_math(start)
end
+ if replace then
+ local okay = false
+ if not prev then
+ prev = prev or getprev(start)
+ pglyph = prev and getid(prev) == glyph_code
+ end
+ if pglyph then
+ replace, okay = inject_begin(replace,prev,keeptogether,krn,okay)
+ end
+ if not next then
+ next = getnext(start)
+ nglyph = next and getid(next) == glyph_code
+ end
+ if nglyph then
+ replace, okay = inject_end(replace,next,keeptogether,krn,okay)
+ end
+ replace, okay = process_list(replace,keeptogether,krn,false,okay)
+ if okay then
+ setfield(start,"replace",replace)
+ done = true
+ end
+ elseif prevfont then
+ setfield(start,"replace",new_kern(quaddata[prevfont]*krn))
+ done = true
+ end
+ bound = false
+ elseif id == kern_code then
+ bound = getsubtype(start) == kerning_code or getattr(start,a_fontkern)
+ prev = start
+ previd = id
+ elseif id == glue_code then
+ local subtype = getsubtype(start)
+ if subtype == userskip_code or subtype == xspaceskip_code or subtype == spaceskip_code then
+ local s = getfield(start,"spec")
+ local w = getfield(s,"width")
+ if w > 0 then
+ local width = w+gluefactor*w*krn
+ local stretch = getfield(s,"stretch")
+ local shrink = getfield(s,"shrink")
+ setfield(start,"spec",spec_injector(fillup,width,stretch*width/w,shrink*width/w))
+ done = true
+ end
+ end
+ bound = false
+ elseif id == hlist_code or id == vlist_code then
+ local subtype = getsubtype(start)
+ if subtype == user_list_code or subtype == box_list_code then
+ -- special case
+ local b, f = closest_bound(start,getprev)
+ if b then
+ insert_node_before(head,start,kern_injector(fillup,quaddata[f]*krn))
+ done = true
+ end
+ local b, f = closest_bound(start,getnext)
+ if b then
+ insert_node_after(head,start,kern_injector(fillup,quaddata[f]*krn))
+ done = true
+ end
+ end
+ bound = false
+ elseif id == math_code then
+ start = end_of_math(start)
+ bound = false
end
- end
- if start then
+ if start then
+ start = getnext(start)
+ end
+ elseif id == kern_code then
+ bound = getsubtype(start) == kerning_code or getattr(start,a_fontkern)
+ prev = start
+ previd = id
+ start = getnext(start)
+ else
+ bound = false
start = getnext(start)
end
end
- return head, done
+ return tonode(head), done
end
local enabled = false
@@ -428,11 +620,11 @@ function kerns.set(factor)
return factor
end
-function kerns.handler(head)
- local head, done = do_process(tonut(head)) -- no direct map, because else fourth argument is tail == true
- return tonode(head), done
-end
-
-- interface
-commands.setcharacterkerning = kerns.set
+interfaces.implement {
+ name = "setcharacterkerning",
+ actions = kerns.set,
+ arguments = "string"
+}
+
diff --git a/Master/texmf-dist/tex/context/base/typo-krn.mkiv b/Master/texmf-dist/tex/context/base/typo-krn.mkiv
index 92689f07b85..6d6126542bf 100644
--- a/Master/texmf-dist/tex/context/base/typo-krn.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-krn.mkiv
@@ -35,13 +35,10 @@
\typo_kerning_set
\fi}
-% \def\typo_kerning_set
-% {\ctxcommand{setcharacterkerning(\characterkerningparameter\c!factor)}}
-
\def\typo_kerning_set
{\usecharacterkerningstyleandcolor\c!style\c!color % goodie, maybe also strut
\useaddfontfeatureparameter\characterkerningparameter
- \ctxcommand{setcharacterkerning("\characterkerningparameter\c!factor")}}
+ \clf_setcharacterkerning{\characterkerningparameter\c!factor}}
\unexpanded\def\resetcharacterkerning % fast one
{\attribute\kernattribute\attributeunsetvalue}
@@ -89,9 +86,9 @@
\appendtoks
\setuevalue{\currentcharacterkerning}%
- {\doifnextoptionalelse
+ {\doifelsenextoptional
{\typo_kerning_apply_yes{\currentcharacterkerning}}%
- {\typo_kerning_apply_nop{\currentcharacterkerning}}}
+ {\typo_kerning_apply_nop{\currentcharacterkerning}}}%
\to \everydefinecharacterkerning
\unexpanded\def\typo_kerning_apply_yes#1[#2]%
diff --git a/Master/texmf-dist/tex/context/base/typo-lan.lua b/Master/texmf-dist/tex/context/base/typo-lan.lua
index 50927f74493..c42d2119eb6 100644
--- a/Master/texmf-dist/tex/context/base/typo-lan.lua
+++ b/Master/texmf-dist/tex/context/base/typo-lan.lua
@@ -67,6 +67,8 @@ function frequencies.averagecharwidth(language,font)
return frequencycache[language or "en"][font or currentfont()]
end
-function commands.averagecharwidth(language,font)
- context(frequencycache[language or "en"][font or currentfont()])
-end
+interfaces.implement {
+ name = "averagecharwidth",
+ actions = { frequencies.averagecharwidth, context },
+ arguments = "string"
+}
diff --git a/Master/texmf-dist/tex/context/base/typo-lan.mkiv b/Master/texmf-dist/tex/context/base/typo-lan.mkiv
index bb4ed204205..8b633957bca 100644
--- a/Master/texmf-dist/tex/context/base/typo-lan.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-lan.mkiv
@@ -30,7 +30,7 @@
\def\charwidthlanguage{\currentmainlanguage}
-\def\averagecharwidth{\dimexpr\ctxcommand{averagecharwidth("\charwidthlanguage")}\scaledpoint\relax}
+\def\averagecharwidth{\dimexpr\clf_averagecharwidth{\charwidthlanguage}\scaledpoint\relax}
\protect
diff --git a/Master/texmf-dist/tex/context/base/typo-lig.mkiv b/Master/texmf-dist/tex/context/base/typo-lig.mkiv
new file mode 100644
index 00000000000..6171441d6d3
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/typo-lig.mkiv
@@ -0,0 +1,31 @@
+%D \module
+%D [ file=typo-lig,
+%D version=2014.12.01,
+%D title=\CONTEXT\ Typesetting Macros,
+%D subtitle=Ligatures,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Typesetting Macros / Ligatures}
+
+%D This macro is mostly used for testing an attribute that blocks ligatures
+%D in the nodemode handler. It is not really used in practice, and mostly
+%D there as a plug in the generic font handler.
+
+\unprotect
+
+\definesystemattribute[noligature][public]
+
+\unexpanded\def\noligature#1%
+ {\dontleavehmode
+ \begingroup
+ \attribute\noligatureattribute\plusone
+ #1%
+ \endgroup}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/typo-man.lua b/Master/texmf-dist/tex/context/base/typo-man.lua
new file mode 100644
index 00000000000..6c6d7926f37
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/typo-man.lua
@@ -0,0 +1,113 @@
+if not modules then modules = { } end modules ['typo-man'] = {
+ version = 1.001,
+ comment = "companion to typo-prc.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if not characters then
+ -- for testing stand-alone
+ require("char-def")
+ require("char-ini")
+end
+
+local lpegmatch = lpeg.match
+local P, R, C, Ct, Cs, Carg = lpeg.P, lpeg.R, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Carg
+local global = global or _G
+
+local methods = {
+ uppercase = characters.upper,
+ lowercase = characters.lower,
+ Word = converters.Word,
+ Words = converters.Words,
+}
+
+local function nothing(s) return s end -- we already have that one somewhere
+
+-- table.setmetatableindex(methods,function(t,k)
+-- t[k] = nothing
+-- return nothing
+-- end)
+
+local splitter = lpeg.tsplitat(".")
+
+table.setmetatableindex(methods,function(t,k)
+ local s = lpegmatch(splitter,k)
+ local v = global
+ for i=1,#s do
+ v = v[s[i]]
+ if not v then
+ break
+ end
+ end
+ if not v or v == global then
+ v = nothing
+ end
+ t[k] = v
+ return v
+end)
+
+local whitespace = lpeg.patterns.whitespace^0
+local separator = whitespace * P("->") * whitespace
+local pair = C((1-separator)^1) * separator * C(P(1)^0)
+local list = Ct((C((1-separator)^1) * separator)^1) * C(P(1)^0)
+
+local pattern = Carg(1) * pair / function(methods,operation,str)
+ return methods[operation](str) or str
+end
+
+local function apply(str,m)
+ return lpegmatch(pattern,str,1,m or methods) or str
+end
+
+local function splitspecification(field,m)
+ local m, f = lpegmatch(list,field,1,m or methods)
+ if m then
+ return m, f or field
+ else
+ return nil, field
+ end
+end
+
+local function applyspecification(actions,str)
+ if actions then
+ for i=1,#actions do
+ local action = methods[actions[i]]
+ if action then
+ str = action(str) or str
+ end
+ end
+ end
+ return str
+end
+
+if not typesetters then typesetters = { } end
+
+typesetters.manipulators = {
+ methods = methods,
+ apply = apply,
+ patterns = {
+ pair = pair,
+ list = list,
+ },
+ splitspecification = splitspecification,
+ applyspecification = applyspecification,
+}
+
+local pattern = Cs((1 - P(1) * P(-1))^0 * (P(".")/"" + P(1)))
+
+methods.stripperiod = function(str) return lpegmatch(pattern,str) end
+
+-- print(apply("hans"))
+-- print(apply("uppercase->hans"))
+-- print(apply("string.reverse -> hans"))
+-- print(apply("uppercase->hans",{ uppercase = string.reverse } ))
+
+-- print(applyspecification(splitspecification("hans")))
+-- print(applyspecification(splitspecification("lowercase->uppercase->hans")))
+-- print(applyspecification(splitspecification("uppercase->stripperiod->hans.")))
+
+function commands.manipulated(str)
+ context(apply(str))
+end
diff --git a/Master/texmf-dist/tex/context/base/typo-mar.lua b/Master/texmf-dist/tex/context/base/typo-mar.lua
index 4ea6b1e1d86..fed9e0745d6 100644
--- a/Master/texmf-dist/tex/context/base/typo-mar.lua
+++ b/Master/texmf-dist/tex/context/base/typo-mar.lua
@@ -77,6 +77,7 @@ local format, validstring = string.format, string.valid
local insert, remove = table.insert, table.remove
local setmetatable, next = setmetatable, next
local formatters = string.formatters
+local toboolean = toboolean
local attributes, nodes, node, variables = attributes, nodes, node, variables
@@ -115,6 +116,7 @@ local v_continue = variables.continue
local v_first = variables.first
local v_text = variables.text
local v_column = variables.column
+local v_line = variables.line
local nuts = nodes.nuts
local nodepool = nuts.pool
@@ -165,9 +167,6 @@ local localpar_code = whatsitcodes.localpar
local nodepool = nuts.pool
local new_kern = nodepool.kern
-local new_glue = nodepool.glue
-local new_penalty = nodepool.penalty
-local new_stretch = nodepool.stretch
local new_usernumber = nodepool.usernumber
local new_latelua = nodepool.latelua
@@ -177,8 +176,6 @@ local texgetcount = tex.getcount
local texgetdimen = tex.getdimen
local texget = tex.get
-local points = number.points
-
local isleftpage = layouts.status.isleftpage
local registertogether = builders.paragraphs.registertogether -- tonode
@@ -374,11 +371,13 @@ end
local status, nofstatus = { }, 0
local f_anchor = formatters["_plib_.set('md:h',%i,{x=true,c=true})"]
+
local function setanchor(h_anchor)
return new_latelua(f_anchor(h_anchor))
end
-- local t_anchor = { x = true, c = true }
+--
-- local function setanchor(h_anchor)
-- return lateluafunction(function() setposition("md:h",h_anchor,t_anchor) end)
-- end
@@ -449,7 +448,7 @@ local function realign(current,candidate)
anchor = v_text
end
if inline or anchor ~= v_text or candidate.psubtype == alignment_code then
- -- the alignment_code check catches margintexts ste before a tabulate
+ -- the alignment_code check catches margintexts before a tabulate
h_anchors = h_anchors + 1
anchornode = setanchor(h_anchors)
local blob = getposition('md:h',h_anchors)
@@ -555,6 +554,9 @@ end
local function inject(parent,head,candidate)
local box = candidate.box
+ if not box then
+ return head, nil, false -- we can have empty texts
+ end
local width = getfield(box,"width")
local height = getfield(box,"height")
local depth = getfield(box,"depth")
@@ -574,6 +576,11 @@ local function inject(parent,head,candidate)
nofdelayed = nofdelayed + 1
status[nofstatus] = candidate
-- yet untested
+ baseline = tonumber(baseline)
+ if not baseline then
+ baseline = toboolean(baseline)
+ end
+ --
if baseline == true then
baseline = false
-- hbox vtop
@@ -600,10 +607,10 @@ local function inject(parent,head,candidate)
-- offset = offset + height
end
if stack == v_yes then
- offset = offset + candidate.dy
+ offset = offset + candidate.dy -- always
shift = shift + offset
elseif stack == v_continue then
- offset = offset + candidate.dy
+ offset = offset + candidate.dy -- always
if firstonstack then
offset = offset + getovershoot(location)
end
@@ -620,9 +627,19 @@ local function inject(parent,head,candidate)
if trace_margindata then
report_margindata("top aligned by %p",delta)
end
- if delta < candidate.threshold then
+ if delta < candidate.threshold then -- often we need a negative threshold here
shift = shift + voffset + delta
end
+ elseif method == v_line then
+ if getfield(parent,"depth") == 0 then
+ local delta = height - getfield(parent,"height")
+ if trace_margindata then
+ report_margindata("top aligned by %p (no depth)",delta)
+ end
+ if delta < candidate.threshold then -- often we need a negative threshold here
+ shift = shift + voffset + delta
+ end
+ end
elseif method == v_first then
if baseline then
shift = shift + voffset + height - baseline -- option
@@ -740,17 +757,23 @@ local function flushed(scope,parent) -- current is hlist
for l=1,#locations do
local location = locations[l]
local store = displaystore[category][location][scope]
- while true do
- local candidate = remove(store,1) -- brr, local stores are sparse
- if candidate then -- no vpack, as we want to realign
- head, room, con = inject(parent,head,candidate)
- done = true
- continue = continue or con
- nofstored = nofstored - 1
- registertogether(tonode(parent),room) -- !! tonode
- else
- break
+ if store then
+ while true do
+ local candidate = remove(store,1) -- brr, local stores are sparse
+ if candidate then -- no vpack, as we want to realign
+ head, room, con = inject(parent,head,candidate)
+ done = true
+ continue = continue or con
+ nofstored = nofstored - 1
+ if room then
+ registertogether(tonode(parent),room) -- !! tonode
+ end
+ else
+ break
+ end
end
+ else
+ -- report_margindata("fatal error: invalid category %a",category or "?")
end
end
end
@@ -836,15 +859,15 @@ function margins.globalhandler(head,group) -- check group
end
return head, false
elseif group == "hmode_par" then
- return handler("global",head,group)
+ return handler(v_global,head,group)
elseif group == "vmode_par" then -- experiment (for alignments)
- return handler("global",head,group)
+ return handler(v_global,head,group)
-- this needs checking as we then get quite some one liners to process and
-- we cannot look ahead then:
elseif group == "box" then -- experiment (for alignments)
- return handler("global",head,group)
+ return handler(v_global,head,group)
elseif group == "alignment" then -- experiment (for alignments)
- return handler("global",head,group)
+ return handler(v_global,head,group)
else
if trace_margingroup then
report_margindata("ignored 2, group %a, stored %s, inhibit %a",group,nofstored,inhibit)
@@ -885,9 +908,9 @@ function margins.finalhandler(head)
-- if trace_margindata then
-- report_margindata("flushing stage two, instore: %s, delayed: %s",nofstored,nofdelayed)
-- end
-head = tonut(head)
-local head, done = finalhandler(head)
-head = tonode(head)
+ head = tonut(head)
+ local head, done = finalhandler(head)
+ head = tonode(head)
return head, done
else
return head, false
@@ -928,4 +951,32 @@ statistics.register("margin data", function()
end
end)
-commands.savemargindata = margins.save
+interfaces.implement {
+ name = "savemargindata",
+ actions = margins.save,
+ arguments = {
+ {
+ { "location" },
+ { "method" },
+ { "category" },
+ { "name" },
+ { "scope" },
+ { "number", "integer" },
+ { "margin" },
+ { "distance", "dimen" },
+ { "hoffset", "dimen" },
+ { "voffset", "dimen" },
+ { "dy", "dimen" },
+ { "bottomspace", "dimen" },
+ { "baseline"}, -- dimen or string or
+ { "threshold", "dimen" },
+ { "inline", "boolean" },
+ { "anchor" },
+ -- { "leftskip", "dimen" },
+ -- { "rightskip", "dimen" },
+ { "align" },
+ { "line", "integer" },
+ { "stack" },
+ }
+ }
+}
diff --git a/Master/texmf-dist/tex/context/base/typo-mar.mkiv b/Master/texmf-dist/tex/context/base/typo-mar.mkiv
index 2b89f57774d..d5869b45998 100644
--- a/Master/texmf-dist/tex/context/base/typo-mar.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-mar.mkiv
@@ -14,6 +14,8 @@
%C details.
% todo: tags
+% todo: force inline with option (saves pos)
+% todo: margintitle (also less position then)
\writestatus{loading}{ConTeXt Typesetting Macros / Margindata}
@@ -113,7 +115,7 @@
\c!color=, % maybe \maintextcolor
% \c!name=,
% \c!category=,
- \c!threshold=.25ex,
+ \c!threshold=.25\exheight,
\c!margin=\v!normal,
\c!scope=\v!global,
\c!width=,
@@ -163,7 +165,7 @@
\unexpanded\def\typo_margins_data_synchronize
{\doforcedtrackpagestate\s!margintext\nofmargintexts % includes increment
\docheckpagestate\s!margintext\nofmargintexts
- %\doifrightpagestateelse\s!margintext\nofmargintexts\relax\relax
+ %\doifelserightpagestate\s!margintext\nofmargintexts\relax\relax
\realpageno\realpagestateno
\swapmargins}
@@ -199,13 +201,13 @@
\strc_references_set_page_only_destination_box_attribute\currentmarginreference\currentmarginreference
\fi
\edef\currentmargindatastrut{\margindataparameter\c!strut}%
- \dostarttagged\t!margintext\currentmargindata
+ \dostarttaggedchained\t!margintext\currentmargindata\??margindata
\ifcsname\currentmarginframedhash\s!parent\endcsname
\setbox\nextbox\hbox \currentmarginreference \bgroup
\the\everymargindatacontent
\usemargindatastyleandcolor\c!style\c!color
\setupcurrentmarginframed[\c!location=\v!normal,#textparameters]%
-\typo_margins_data_synchronize
+ \typo_margins_data_synchronize
\inheritedmarginframedframed\bgroup
\ifx\currentmargindatastrut\empty \else
\synchronizestrut\currentmargindatastrut
@@ -221,7 +223,7 @@
\edef\currentmargindatawidth{\margindataparameter\c!width}%
\ifx\currentmargindatawidth\empty
\setbox\nextbox\hbox \currentmarginreference \bgroup
-\typo_margins_data_synchronize
+ \typo_margins_data_synchronize
\the\everymargindatacontent
\usemargindatastyleandcolor\c!style\c!color
\ifx\currentmargindatastrut\empty \else
@@ -235,7 +237,7 @@
\let\currentmarginfirstheight\empty
\else
\setbox\nextbox\hbox \currentmarginreference \bgroup
-\typo_margins_data_synchronize
+ \typo_margins_data_synchronize
\dosetraggedcommand{\margindataparameter\c!align}%
\vtop \bgroup
\the\everymargindatacontent
@@ -258,49 +260,49 @@
\fi
\ifdone
\anch_positions_initialize % we use positions at the lua end
- \ctxcommand{savemargindata{
- location = "\margindataparameter\c!location",
- method = "\margindataparameter\c!method",
- category = "\margindataparameter\c!category",
- name = "\margindataparameter\c!name",
- scope = "\margindataparameter\c!scope",
- number = \number\nextbox,
- margin = "\margindataparameter\c!margin", % local normal margin edge
- distance = \number\dimexpr\margindataparameter\c!distance,
- hoffset = \number\dimexpr\margindataparameter\c!hoffset,
- voffset = \number\dimexpr\margindataparameter\c!voffset,
- dy = \number\dimexpr\margindataparameter\c!dy,
- bottomspace = \number\dimexpr\margindataparameter\c!bottomspace,
+ \clf_savemargindata
+ location {\margindataparameter\c!location}%
+ method {\margindataparameter\c!method}%
+ category {\margindataparameter\c!category}%
+ name {\margindataparameter\c!name}%
+ scope {\margindataparameter\c!scope}%
+ number \nextbox
+ margin {\margindataparameter\c!margin}% local normal margin edge
+ distance \dimexpr\margindataparameter\c!distance\relax
+ hoffset \dimexpr\margindataparameter\c!hoffset\relax
+ voffset \dimexpr\margindataparameter\c!voffset\relax
+ dy \dimexpr\margindataparameter\c!dy\relax
+ bottomspace \dimexpr\margindataparameter\c!bottomspace\relax
\ifx\currentmarginfirstheight\empty \else
- baseline = \currentmarginfirstheight,
+ baseline {\currentmarginfirstheight}%
\fi
- threshold = \number\dimexpr\margindataparameter\c!threshold, % overlap related, will change
+ threshold \dimexpr\margindataparameter\c!threshold\relax % overlap related, will change
\ifhmode
- inline = true,
+ inline true %
\fi
- anchor = "\margindataparameter\c!anchor",
+ anchor {\margindataparameter\c!anchor}%
%
% we're not in forgetall
%
% \ifzeropt\leftskip \else
- % leftskip = \number\leftskip,
+ % leftskip \dimexpr\leftskip\relax
% \fi
% \ifzeropt\leftskip \else
- % rightskip = \number\rightskip,
+ % rightskip \dimexpr\rightskip\relax
% \fi
- align = "\margindataparameter\c!align",
- line = \number\margindataparameter\c!line,
- stack = "\margindataparameter\c!stack",
- }}%
+ align {\margindataparameter\c!align}%
+ line \numexpr\margindataparameter\c!line\relax
+ stack {\margindataparameter\c!stack}%
+ \relax
\else
- \ctxcommand{savemargindata{
- location = "\margindataparameter\c!location",
- method = "\margindataparameter\c!method",
- category = "\margindataparameter\c!category",
- name = "\margindataparameter\c!name",
- scope = "\margindataparameter\c!scope",
- number = \number\nextbox,
- }}%
+ \clf_savemargindata
+ location {\margindataparameter\c!location}%
+ method {\margindataparameter\c!method}%
+ category {\margindataparameter\c!category}%
+ name {\margindataparameter\c!name}%
+ scope {\margindataparameter\c!scope}%
+ number \nextbox
+ \relax
\fi
\endgroup}
diff --git a/Master/texmf-dist/tex/context/base/typo-pag.lua b/Master/texmf-dist/tex/context/base/typo-pag.lua
index 5b96e9c2113..53f79fcfc69 100644
--- a/Master/texmf-dist/tex/context/base/typo-pag.lua
+++ b/Master/texmf-dist/tex/context/base/typo-pag.lua
@@ -52,6 +52,9 @@ trackers.register("parbuilders.keeptogether", function(v) trace_keeptogether =
-- when no hlists are there ? ... maybe the local_par
function parbuilders.registertogether(line,specification) -- might change
+ if not specification then
+ return
+ end
if not enabled then
nodes.tasks.enableaction("finalizers","builders.paragraphs.keeptogether")
end
@@ -87,18 +90,16 @@ function parbuilders.registertogether(line,specification) -- might change
if trace_keeptogether then
local a = a or last
local c = cache[a]
- if trace_keeptogether then
- local noflines = specification.lineheight
- local height = c.height
- local depth = c.depth
- local slack = c.slack
- if not noflines or noflines == 0 then
- noflines = "unknown"
- else
- noflines = math.round((height + depth - slack) / noflines)
- end
- report_keeptogether("registered, index %s, height %p, depth %p, slack %p, noflines %a",a,height,depth,slack,noflines)
+ local noflines = specification.lineheight
+ local height = c.height
+ local depth = c.depth
+ local slack = c.slack
+ if not noflines or noflines == 0 then
+ noflines = "unknown"
+ else
+ noflines = math.round((height + depth - slack) / noflines)
end
+ report_keeptogether("registered, index %s, height %p, depth %p, slack %p, noflines %a",a,height,depth,slack,noflines)
end
end
diff --git a/Master/texmf-dist/tex/context/base/typo-prc.lua b/Master/texmf-dist/tex/context/base/typo-prc.lua
index 959cabbb8e5..cde66df0087 100644
--- a/Master/texmf-dist/tex/context/base/typo-prc.lua
+++ b/Master/texmf-dist/tex/context/base/typo-prc.lua
@@ -6,14 +6,15 @@ if not modules then modules = { } end modules ['typo-prc'] = {
license = "see context related readme files"
}
--- moved from strc-ini.lua
-
-local context, commands = context, commands
-local formatters = string.formatters
local lpegmatch, patterns, P, C, Cs = lpeg.match, lpeg.patterns, lpeg.P, lpeg.C, lpeg.Cs
-- processors: syntax: processor->data ... not ok yet
+local context = context
+local implement = interfaces.implement
+
+local formatters = string.formatters
+
typesetters.processors = typesetters.processors or { }
local processors = typesetters.processors
@@ -21,8 +22,8 @@ local trace_processors = false
local report_processors = logs.reporter("processors")
local registered = { }
-context_applyprocessor = context.applyprocessor
-context_firstofoneargument = context.firstofoneargument
+local ctx_applyprocessor = context.applyprocessor
+local ctx_firstofoneargument = context.firstofoneargument
trackers.register("typesetters.processors", function(v) trace_processors = v end)
@@ -58,7 +59,7 @@ function processors.apply(p,s)
if trace_processors then
report_processors("applying %s processor %a, argument: %s","known",p,s)
end
- context_applyprocessor(p,s)
+ ctx_applyprocessor(p,s)
elseif s then
if trace_processors then
report_processors("applying %s processor %a, argument: %s","unknown",p,s)
@@ -81,21 +82,21 @@ function processors.startapply(p,s)
if trace_processors then
report_processors("start applying %s processor %a","known",p)
end
- context_applyprocessor(p)
+ ctx_applyprocessor(p)
context("{")
return s
elseif p then
if trace_processors then
report_processors("start applying %s processor %a","unknown",p)
end
- context_firstofoneargument()
+ ctx_firstofoneargument()
context("{")
return s
else
if trace_processors then
report_processors("start applying %s processor","ignored")
end
- context_firstofoneargument()
+ ctx_firstofoneargument()
context("{")
return str
end
@@ -124,5 +125,5 @@ end
-- interface
-commands.registerstructureprocessor = processors.register
-commands.resetstructureprocessor = processors.reset
+implement { name = "registerstructureprocessor", actions = processors.register, arguments = "string" }
+implement { name = "resetstructureprocessor", actions = processors.reset, arguments = "string" }
diff --git a/Master/texmf-dist/tex/context/base/typo-prc.mkvi b/Master/texmf-dist/tex/context/base/typo-prc.mkvi
index de221f2419b..49a16569647 100644
--- a/Master/texmf-dist/tex/context/base/typo-prc.mkvi
+++ b/Master/texmf-dist/tex/context/base/typo-prc.mkvi
@@ -13,7 +13,11 @@
\writestatus{loading}{ConTeXt Typesetting Macros / Processors}
+%D For the moment manipulators are loaded here too, as they're in the same
+%D category as processors. This might change. (They are used in publications.)
+
\registerctxluafile{typo-prc}{1.001}
+\registerctxluafile{typo-man}{1.001}
\unprotect
@@ -51,7 +55,7 @@
\appendtoks
\letvalue{\??processorcheck\currentprocessor}\relax
- \ctxcommand{registerstructureprocessor("\currentprocessor")}% global, but it permits using processor that are yet undefined
+ \clf_registerstructureprocessor{\currentprocessor}% global, but it permits using processor that are yet undefined
\to \everydefineprocessor
%D The following command can be used by users but normally it will be
@@ -68,9 +72,12 @@
\fi}
\def\typo_processor_apply
- {\doifelse{\processorparameter\c!state}\v!stop
- \firstofoneargument
- \typo_processor_apply_indeed}
+ {\edef\p_state{\processorparameter\c!state}%
+ \ifx\p_state\v!stop
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\typo_processor_apply_indeed
+ \fi}
\def\typo_processor_apply_indeed#content%
{\begingroup
diff --git a/Master/texmf-dist/tex/context/base/typo-rep.lua b/Master/texmf-dist/tex/context/base/typo-rep.lua
index 15e3f97465e..d95eff68e0f 100644
--- a/Master/texmf-dist/tex/context/base/typo-rep.lua
+++ b/Master/texmf-dist/tex/context/base/typo-rep.lua
@@ -29,7 +29,6 @@ local getchar = nuts.getchar
local getid = nuts.getid
local getattr = nuts.getattr
-local setattr = nuts.setattr
local delete_node = nuts.delete
local replace_node = nuts.replace
@@ -139,4 +138,8 @@ tasks.disableaction("processors","nodes.handlers.stripping")
-- interface
-commands.setcharacterstripping = stripping.set
+interfaces.implement {
+ name = "setcharacterstripping",
+ actions = stripping.set,
+ arguments = "string"
+}
diff --git a/Master/texmf-dist/tex/context/base/typo-rep.mkiv b/Master/texmf-dist/tex/context/base/typo-rep.mkiv
index 46b43949151..c1146997e33 100644
--- a/Master/texmf-dist/tex/context/base/typo-rep.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-rep.mkiv
@@ -38,7 +38,7 @@
\definesystemattribute[stripping][public]
\unexpanded\def\setcharacterstripping[#1]%
- {\ctxcommand{setcharacterstripping("#1")}}
+ {\clf_setcharacterstripping{#1}}
\unexpanded\def\resetcharacterstripping
{\attribute\strippingattribute\attributeunsetvalue}
diff --git a/Master/texmf-dist/tex/context/base/typo-spa.lua b/Master/texmf-dist/tex/context/base/typo-spa.lua
index eb84eb7d7e3..519ba3f34fb 100644
--- a/Master/texmf-dist/tex/context/base/typo-spa.lua
+++ b/Master/texmf-dist/tex/context/base/typo-spa.lua
@@ -230,6 +230,30 @@ end
-- interface
-commands.definecharacterspacing = spacings.define
-commands.setupcharacterspacing = spacings.setup
-commands.setcharacterspacing = spacings.set
+local implement = interfaces.implement
+
+implement {
+ name = "definecharacterspacing",
+ actions = spacings.define,
+ arguments = "string"
+}
+
+implement {
+ name = "setupcharacterspacing",
+ actions = spacings.setup,
+ arguments = {
+ "string",
+ "integer",
+ {
+ { "left", "number" },
+ { "right", "number" },
+ { "alternative", "integer" },
+ }
+ }
+}
+
+implement {
+ name = "setcharacterspacing",
+ actions = spacings.set,
+ arguments = "string"
+}
diff --git a/Master/texmf-dist/tex/context/base/typo-spa.mkiv b/Master/texmf-dist/tex/context/base/typo-spa.mkiv
index d783353d67d..2e3e71bf3b3 100644
--- a/Master/texmf-dist/tex/context/base/typo-spa.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-spa.mkiv
@@ -35,7 +35,7 @@
\c!alternative=0]
\unexpanded\def\definecharacterspacing[#1]%
- {\ctxcommand{definecharacterspacing("#1")}}
+ {\clf_definecharacterspacing{#1}}
\unexpanded\def\setupcharacterspacing
{\dotripleargument\typo_characterspacing_setup}
@@ -43,15 +43,19 @@
\def\typo_characterspacing_setup[#1][#2][#3]% todo: #2 list
{\begingroup
\setupcurrent_p_characterspacing[#3]%
- \ctxcommand{setupcharacterspacing("#1",\number#2, { % todo: just pass #3 to the lua end
- left = \direct_p_characterspacingparameter\c!left,
- right = \direct_p_characterspacingparameter\c!right,
- alternative = \direct_p_characterspacingparameter\c!alternative
- })}%
+ \clf_setupcharacterspacing
+ {#1}%
+ \numexpr#2\relax
+ {%
+ left \direct_p_characterspacingparameter\c!left\space
+ right \direct_p_characterspacingparameter\c!right\space
+ alternative \direct_p_characterspacingparameter\c!alternative
+ }%
+ \relax
\endgroup}
\unexpanded\def\setcharacterspacing[#1]% we can store the attribute if we want speed
- {\ctxcommand{setcharacterspacing("#1")}}
+ {\clf_setcharacterspacing{#1}}
\unexpanded\def\resetcharacterspacing % fast one
{\attribute\spacingattribute\attributeunsetvalue}
diff --git a/Master/texmf-dist/tex/context/base/typo-sus.lua b/Master/texmf-dist/tex/context/base/typo-sus.lua
new file mode 100644
index 00000000000..9eef6196bb0
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/typo-sus.lua
@@ -0,0 +1,304 @@
+if not modules then modules = { } end modules ['typo-sus'] = {
+ version = 1.001,
+ comment = "companion to typo-sus.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local punctuation = {
+ po = true,
+}
+
+local openquote = {
+ ps = true,
+ pi = true,
+}
+
+local closequote = {
+ pe = true,
+ pf = true,
+}
+
+local categories = characters.categories
+
+local nodecodes = nodes.nodecodes
+
+local glyph_code = nodecodes.glyph
+local kern_code = nodecodes.kern
+local penalty_code = nodecodes.penalty
+local glue_code = nodecodes.glue
+local math_code = nodecodes.math
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+
+local nuts = nodes.nuts
+local tonut = nodes.tonut
+local tonode = nodes.tonode
+
+local getid = nuts.getid
+local getchar = nuts.getchar
+local getprev = nuts.getprev
+local getnext = nuts.getnext
+local getfield = nuts.getfield
+local getattr = nuts.getattr
+local getfont = nuts.getfont
+local getlist = nuts.getlist
+
+local setfield = nuts.setfield
+local setattr = nuts.setattr
+
+local setcolor = nodes.tracers.colors.set
+local insert_before = nuts.insert_before
+local insert_after = nuts.insert_after
+local end_of_math = nuts.end_of_math
+
+local nodepool = nuts.pool
+
+local new_rule = nodepool.rule
+local new_kern = nodepool.kern
+local new_hlist = nodepool.hlist
+----- new_penalty = nodepool.penalty
+
+local a_characters = attributes.private("characters")
+local a_suspecting = attributes.private('suspecting')
+local a_suspect = attributes.private('suspect')
+local texsetattribute = tex.setattribute
+local enabled = false
+
+local threshold = 65536 / 4
+
+local function special(n)
+ if n then
+ local id = getid(n)
+ if id == kern_code then
+ local kern = getfield(n,"kern")
+ return kern < threshold
+ elseif id == penalty_code then
+ return true
+ elseif id == glue_code then
+ local width = getfield(getfield(n,"spec"),"width")
+ return width < threshold
+ elseif id == hlist_code then
+ local width = getfield(n,"width")
+ return width < threshold
+ end
+ else
+ return false
+ end
+end
+
+local function goback(current)
+ local prev = getprev(current)
+ while prev and special(prev) do
+ prev = getprev(prev)
+ end
+ if prev then
+ return prev, getid(prev)
+ end
+end
+
+local function goforward(current)
+ local next = getnext(current)
+ while next and special(next) do
+ next = getnext(next)
+ end
+ if next then
+ return next, getid(next)
+ end
+end
+
+local function mark(head,current,id,color)
+ if id == glue_code then
+ -- the glue can have stretch and/or shrink so the rule can overlap with the
+ -- following glyph .. no big deal as that one then sits on top of the rule
+ local width = getfield(getfield(current,"spec"),"width")
+ local rule = new_rule(width)
+ local kern = new_kern(-width)
+ head = insert_before(head,current,rule)
+ head = insert_before(head,current,kern)
+ setcolor(rule,color)
+ -- elseif id == kern_code then
+ -- local width = getfield(current,"kern")
+ -- local rule = new_rule(width)
+ -- local kern = new_kern(-width)
+ -- head = insert_before(head,current,rule)
+ -- head = insert_before(head,current,kern)
+ -- setcolor(rule,color)
+ else
+ local width = getfield(current,"width")
+ local extra = fonts.hashes.xheights[getfont(current)] / 2
+ local rule = new_rule(width,getfield(current,"height")+extra,getfield(current,"depth")+extra)
+ local hlist = new_hlist(rule)
+ head = insert_before(head,current,hlist)
+ setcolor(rule,color)
+ setcolor(current,"white")
+ end
+ return head, current
+end
+
+-- we can cache the font and skip ahead to next but it doesn't
+-- save enough time and it makes the code looks bad too ... after
+-- all, we seldom use this
+
+local colors = {
+ "darkred",
+ "darkgreen",
+ "darkblue",
+ "darkcyan",
+ "darkmagenta",
+ "darkyellow",
+ "darkgray",
+ "orange",
+}
+
+local found = 0
+
+function typesetters.marksuspects(head)
+ local head = tonut(head)
+ local current = head
+ local lastdone = nil
+ while current do
+ if getattr(current,a_suspecting) then
+ local id = getid(current)
+ if id == glyph_code then
+ local char = getchar(current)
+ local code = categories[char]
+ local done = false
+ if punctuation[code] then
+ local prev, pid = goback(current)
+ if prev and pid == glue_code then
+ done = 3 -- darkblue
+ elseif prev and pid == math_code then
+ done = 3 -- darkblue
+ else
+ local next, nid = goforward(current)
+ if next and nid ~= glue_code then
+ done = 3 -- darkblue
+ end
+ end
+ elseif openquote[code] then
+ local next, nid = goforward(current)
+ if next and nid == glue_code then
+ done = 1 -- darkred
+ end
+ elseif closequote[code] then
+ local prev, pid = goback(current)
+ if prev and pid == glue_code then
+ done = 1 -- darkred
+ end
+ else
+ local prev, pid = goback(current)
+ if prev then
+ if pid == math_code then
+ done = 7-- darkgray
+ elseif pid == glyph_code and getfont(current) ~= getfont(prev) then
+ if lastdone ~= prev then
+ done = 2 -- darkgreen
+ end
+ end
+ end
+ if not done then
+ local next, nid = goforward(current)
+ if next then
+ if nid == math_code then
+ done = 7 -- darkgray
+ elseif nid == glyph_code and getfont(current) ~= getfont(next) then
+ if lastdone ~= prev then
+ done = 2 -- darkgreen
+ end
+ end
+ end
+ end
+ end
+ if done then
+ setattr(current,a_suspect,done)
+ lastdone = current
+ found = found + 1
+ end
+ current = getnext(current)
+ elseif id == math_code then
+ current = getnext(end_of_math(current))
+ elseif id == glue_code then
+ local a = getattr(current,a_characters)
+ if a then
+ local prev = getprev(current)
+ local prid = prev and getid(prev)
+ local done = false
+ if prid == penalty_code and getfield(prev,"penalty") == 10000 then
+ done = 8 -- orange
+ else
+ done = 5 -- darkmagenta
+ end
+ if done then
+ setattr(current,a_suspect,done)
+ -- lastdone = current
+ found = found + 1
+ end
+ end
+ current = getnext(current)
+ else
+ current = getnext(current)
+ end
+ else
+ current = getnext(current)
+ end
+ end
+ return tonode(head), found > 0
+end
+
+local function showsuspects(head)
+ local current = head
+ while current do
+ local id = getid(current)
+ if id == glyph_code then
+ local a = getattr(current,a_suspect)
+ if a then
+ head, current = mark(head,current,id,colors[a])
+ end
+ elseif id == glue_code then
+ local a = getattr(current,a_suspect)
+ if a then
+ head, current = mark(head,current,id,colors[a])
+ end
+ elseif id == math_code then
+ current = end_of_math(current)
+ elseif id == hlist_code or id == vlist_code then
+ local list = getlist(current)
+ if list then
+ local l = showsuspects(list)
+ if l ~= list then
+ setfield(current,"list",l)
+ end
+ end
+ end
+ current = getnext(current)
+ end
+ return head
+end
+
+function typesetters.showsuspects(head)
+ if found > 0 then
+ return tonode(showsuspects(tonut(head))), true
+ else
+ return head, false
+ end
+end
+
+nodes.tasks.appendaction ("processors","after", "typesetters.marksuspects")
+nodes.tasks.prependaction("shipouts", "normalizers","typesetters.showsuspects")
+
+nodes.tasks.disableaction("processors","typesetters.marksuspects")
+nodes.tasks.disableaction("shipouts", "typesetters.showsuspects")
+
+-- or maybe a directive
+
+trackers.register("typesetters.suspects",function(v)
+ texsetattribute(a_suspecting,v and 1 or unsetvalue)
+ if v and not enabled then
+ nodes.tasks.enableaction("processors","typesetters.marksuspects")
+ nodes.tasks.enableaction("shipouts", "typesetters.showsuspects")
+ enabled = true
+ end
+end)
+
diff --git a/Master/texmf-dist/tex/context/base/typo-sus.mkiv b/Master/texmf-dist/tex/context/base/typo-sus.mkiv
new file mode 100644
index 00000000000..fe44e63277b
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/typo-sus.mkiv
@@ -0,0 +1,51 @@
+%D \module
+%D [ file=typo-sus,
+%D version=2014.11.06,
+%D title=\CONTEXT\ Typesetting Macros,
+%D subtitle=Checking Suspects,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Typesetting Macros / Checking Suspects}
+
+%D This is a rather special module, mostly needed by ourselves for
+%D projects where copy||editing is not that precise.
+
+\registerctxluafile{typo-sus}{1.001}
+
+\unexpanded\def\showsuspects{\enabletrackers[typesetters.suspects]}
+
+%D The suspicious spacing will be colored in the text. There can be false
+%D positives but this features is mostly used when proofreading. So, we
+%D don't worry too much about interference (and efficiency).
+%D
+%D \unexpanded\def\showsample#1%
+%D {\NC \type{#1}%
+%D \NC \enabletrackers[typesetters.suspects]#1\disabletrackers[typesetters.spacing]%
+%D \NC \NR}
+%D
+%D \starttabulate[|||][before=,after=]
+%D \showsample{foo$x$}
+%D \showsample{$x$bar}
+%D \showsample{foo$x$bar}
+%D \showsample{$f+o+o$:}
+%D \showsample{;$f+o+o$}
+%D \showsample{; bar}
+%D \showsample{foo:bar}
+%D \showsample{\quote{ foo }}
+%D \showsample{\quote{bar }}
+%D \showsample{\quote{ bar}}
+%D \showsample{(foo )}
+%D \showsample{\{foo \}}
+%D \showsample{foo{\bf gnu}bar}
+%D \showsample{foo$x^2$bar}
+%D \showsample{foo\nobreakspace bar}
+%D \stoptabulate
+
+\endinput
+
diff --git a/Master/texmf-dist/tex/context/base/typo-tal.lua b/Master/texmf-dist/tex/context/base/typo-tal.lua
index 3a2d80e519e..5663c3bd995 100644
--- a/Master/texmf-dist/tex/context/base/typo-tal.lua
+++ b/Master/texmf-dist/tex/context/base/typo-tal.lua
@@ -6,20 +6,32 @@ if not modules then modules = { } end modules ['typo-tal'] = {
license = "see context related readme files"
}
--- I'll make it a bit more efficient and provide named instances too.
+-- I'll make it a bit more efficient and provide named instances too which is needed for
+-- nested tables.
+--
+-- Currently we have two methods: text and number with some downward compatible
+-- defaulting.
+
+-- We can speed up by saving the current fontcharacters[font] + lastfont.
local next, type = next, type
local div = math.div
local utfbyte = utf.byte
+local splitmethod = utilities.parsers.splitmethod
+
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
local glue_code = nodecodes.glue
local fontcharacters = fonts.hashes.characters
-local unicodes = fonts.hashes.unicodes
+----- unicodes = fonts.hashes.unicodes
local categories = characters.categories -- nd
+local variables = interfaces.variables
+local v_text = variables.text
+local v_number = variables.number
+
local nuts = nodes.nuts
local tonut = nuts.tonut
local tonode = nuts.tonode
@@ -62,6 +74,8 @@ local enabled = false
local datasets = false
+local implement = interfaces.implement
+
local comma = 0x002C
local period = 0x002E
local punctuationspace = 0x2008
@@ -80,6 +94,66 @@ local validsigns = {
[0x2213] = 0x2213, -- minusplus
}
+-- If needed we can have more modes which then also means a faster simple handler
+-- for non numbers.
+
+local function setcharacteralign(column,separator)
+ if not enabled then
+ nodes.tasks.enableaction("processors","typesetters.characteralign.handler")
+ enabled = true
+ end
+ if not datasets then
+ datasets = { }
+ end
+ local dataset = datasets[column] -- we can use a metatable
+ if not dataset then
+ local method, token
+ if separator then
+ method, token = splitmethod(separator)
+ if method and token then
+ separator = utfbyte(token) or comma
+ else
+ separator = utfbyte(separator) or comma
+ method = validseparators[separator] and v_number or v_text
+ end
+ else
+ separator = comma
+ method = v_number
+ end
+ dataset = {
+ separator = separator,
+ list = { },
+ maxafter = 0,
+ maxbefore = 0,
+ collected = false,
+ method = method,
+ separators = validseparators,
+ signs = validsigns,
+ }
+ datasets[column] = dataset
+ used = true
+ end
+ return dataset
+end
+
+local function resetcharacteralign()
+ datasets = false
+end
+
+characteralign.setcharacteralign = setcharacteralign
+characteralign.resetcharacteralign = resetcharacteralign
+
+implement {
+ name = "setcharacteralign",
+ actions = setcharacteralign,
+ arguments = { "integer", "string" }
+}
+
+implement {
+ name = "resetcharacteralign",
+ actions = resetcharacteralign
+}
+
local function traced_kern(w)
return tracedrule(w,nil,nil,"darkgray")
end
@@ -102,8 +176,8 @@ function characteralign.handler(originalhead,where)
if not a or a == 0 then
return originalhead, false
end
- local column = div(a,100)
- local row = a % 100
+ local column = div(a,0xFFFF)
+ local row = a % 0xFFFF
local dataset = datasets and datasets[column] or setcharacteralign(column)
local separator = dataset.separator
local list = dataset.list
@@ -114,82 +188,128 @@ function characteralign.handler(originalhead,where)
local c = nil
local current = first
local sign = nil
+ --
+ local validseparators = dataset.separators
+ local validsigns = dataset.signs
+ local method = dataset.method
-- we can think of constraints
- while current do
- local id = getid(current)
- if id == glyph_code then
- local char = getchar(current)
- local font = getfont(current)
- local unicode = unicodes[font][char]
- if not unicode then
- -- no unicode so forget about it
- elseif unicode == separator then
- c = current
- if trace_split then
- setcolor(current,"darkred")
- end
- dataset.hasseparator = true
- elseif categories[unicode] == "nd" or validseparators[unicode] then
- if c then
- if not a_start then
- a_start = current
- end
- a_stop = current
+ if method == v_number then
+ while current do
+ local id = getid(current)
+ if id == glyph_code then
+ local char = getchar(current)
+ local font = getfont(current)
+ -- local unicode = unicodes[font][char]
+ local unicode = fontcharacters[font][char].unicode or char -- ignore tables
+ if not unicode then
+ -- no unicode so forget about it
+ elseif unicode == separator then
+ c = current
if trace_split then
- setcolor(current,validseparators[unicode] and "darkcyan" or "darkblue")
+ setcolor(current,"darkred")
end
- else
- if not b_start then
- if sign then
- b_start = sign
- local new = validsigns[getchar(sign)]
- if char == new or not fontcharacters[getfont(sign)][new] then
- if trace_split then
- setcolor(sign,"darkyellow")
+ dataset.hasseparator = true
+ elseif categories[unicode] == "nd" or validseparators[unicode] then
+ if c then
+ if not a_start then
+ a_start = current
+ end
+ a_stop = current
+ if trace_split then
+ setcolor(current,validseparators[unicode] and "darkcyan" or "darkblue")
+ end
+ else
+ if not b_start then
+ if sign then
+ b_start = sign
+ local new = validsigns[getchar(sign)]
+ if char == new or not fontcharacters[getfont(sign)][new] then
+ if trace_split then
+ setcolor(sign,"darkyellow")
+ end
+ else
+ setfield(sign,"char",new)
+ if trace_split then
+ setcolor(sign,"darkmagenta")
+ end
end
+ sign = nil
+ b_stop = current
else
- setfield(sign,"char",new)
- if trace_split then
- setcolor(sign,"darkmagenta")
- end
+ b_start = current
+ b_stop = current
end
- sign = nil
- b_stop = current
else
- b_start = current
b_stop = current
- if trace_split then
- setcolor(current,validseparators[unicode] and "darkcyan" or "darkblue")
- end
end
- else
- b_stop = current
- if trace_split then
+ if trace_split and current ~= sign then
setcolor(current,validseparators[unicode] and "darkcyan" or "darkblue")
end
end
+ elseif not b_start then
+ sign = validsigns[unicode] and current
+ -- if trace_split then
+ -- setcolor(current,"darkgreen")
+ -- end
+ end
+ elseif (b_start or a_start) and id == glue_code then
+ -- maybe only in number mode
+ -- somewhat inefficient
+ local next = getnext(current)
+ local prev = getprev(current)
+ if next and prev and getid(next) == glyph_code and getid(prev) == glyph_code then -- too much checking
+ local width = fontcharacters[getfont(b_start)][separator or period].width
+ -- local spec = getfield(current,"spec")
+ -- free_spec(spec)
+ setfield(current,"spec",new_gluespec(width))
+ setattr(current,a_character,punctuationspace)
+ if a_start then
+ a_stop = current
+ elseif b_start then
+ b_stop = current
+ end
end
- elseif not b_start then
- sign = validsigns[unicode] and current
end
- elseif (b_start or a_start) and id == glue_code then
- -- somewhat inefficient
- local next = getnext(current)
- local prev = getprev(current)
- if next and prev and getid(next) == glyph_code and getid(prev) == glyph_code then -- too much checking
- local width = fontcharacters[getfont(b_start)][separator or period].width
- -- local spec = getfield(current,"spec")
- -- free_spec(spec)
- setfield(current,"spec",new_gluespec(width))
- setattr(current,a_character,punctuationspace)
- if a_start then
- a_stop = current
- elseif b_start then
- b_stop = current
+ current = getnext(current)
+ end
+ else
+ while current do
+ local id = getid(current)
+ if id == glyph_code then
+ local char = getchar(current)
+ local font = getfont(current)
+ -- local unicode = unicodes[font][char]
+ local unicode = fontcharacters[font][char].unicode or char -- ignore tables
+ if not unicode then
+ -- no unicode so forget about it
+ elseif unicode == separator then
+ c = current
+ if trace_split then
+ setcolor(current,"darkred")
+ end
+ dataset.hasseparator = true
+ else
+ if c then
+ if not a_start then
+ a_start = current
+ end
+ a_stop = current
+ if trace_split then
+ setcolor(current,"darkgreen")
+ end
+ else
+ if not b_start then
+ b_start = current
+ end
+ b_stop = current
+ if trace_split then
+ setcolor(current,"darkblue")
+ end
+ end
end
end
+ current = getnext(current)
end
- current = getnext(current)
end
local entry = list[row]
if entry then
@@ -215,7 +335,7 @@ function characteralign.handler(originalhead,where)
local maxafter = dataset.maxafter
local before = entry.before or 0
local after = entry.after or 0
- local new_kern = trace_split and traced_kern or new_kern
+ local new_kern = trace_split and traced_kern or new_kern
if b_start then
if before < maxbefore then
head = insert_node_before(head,b_start,new_kern(maxbefore-before))
@@ -269,37 +389,3 @@ function characteralign.handler(originalhead,where)
end
return tonode(head), true
end
-
-function setcharacteralign(column,separator)
- if not enabled then
- nodes.tasks.enableaction("processors","typesetters.characteralign.handler")
- enabled = true
- end
- if not datasets then
- datasets = { }
- end
- local dataset = datasets[column] -- we can use a metatable
- if not dataset then
- dataset = {
- separator = separator and utfbyte(separator) or comma,
- list = { },
- maxafter = 0,
- maxbefore = 0,
- collected = false,
- }
- datasets[column] = dataset
- used = true
- end
- return dataset
-end
-
-local function resetcharacteralign()
- datasets = false
-end
-
-characteralign.setcharacteralign = setcharacteralign
-characteralign.resetcharacteralign = resetcharacteralign
-
-commands.setcharacteralign = setcharacteralign
-commands.resetcharacteralign = resetcharacteralign
-
diff --git a/Master/texmf-dist/tex/context/base/typo-tal.mkiv b/Master/texmf-dist/tex/context/base/typo-tal.mkiv
index 7de10a6ec1d..570f1a1f56e 100644
--- a/Master/texmf-dist/tex/context/base/typo-tal.mkiv
+++ b/Master/texmf-dist/tex/context/base/typo-tal.mkiv
@@ -40,25 +40,26 @@
%D
%D \typebuffer \blank \getbuffer \blank
-%D \startbuffer
-%D \bTABLE
-%D \bTR \bTD[aligncharacter=yes] € 1,1 \eTD \eTR
-%D \bTR \bTD[aligncharacter=yes] € 11,11 \eTD \eTR
-%D \bTR \bTD[aligncharacter=yes] € 12\punctuationspace111,11 \eTD \eTR
-%D \bTR \bTD[aligncharacter=yes] € 12 111,11 \eTD \eTR
-%D \bTR \bTD[aligncharacter=yes] € 1.234.451,22222 \eTD \eTR
-%D \bTR \bTD[aligncharacter=yes] € 234.451,2 \eTD \eTR
-%D \bTR \bTD[aligncharacter=yes] € 234.451 \eTD \eTR
-%D \bTR \bTD[aligncharacter=yes] € 451 \eTD \eTR
-%D \bTR \bTD \bf some text \eTD \eTR
-%D \eTABLE
-%D \stopbuffer
-%D
-%D \typebuffer \blank \getbuffer \blank
-
-\unexpanded\def\signalcharacteralign#1#2{\attribute\characteralignattribute=\numexpr#1*\plushundred+#2\relax}
-\unexpanded\def\setcharacteralign #1#2{\ctxcommand{setcharacteralign(\number#1,"#2")}}
-\unexpanded\def\resetcharacteralign {\ctxcommand{resetcharacteralign()}}
+% D \startbuffer
+% D \bTABLE
+% D \bTR \bTD[aligncharacter=yes] € 1,1 \eTD \eTR
+% D \bTR \bTD[aligncharacter=yes] € 11,11 \eTD \eTR
+% D \bTR \bTD[aligncharacter=yes] € 12\punctuationspace111,11 \eTD \eTR
+% D \bTR \bTD[aligncharacter=yes] € 12 111,11 \eTD \eTR
+% D \bTR \bTD[aligncharacter=yes] € 1.234.451,22222 \eTD \eTR
+% D \bTR \bTD[aligncharacter=yes] € 234.451,2 \eTD \eTR
+% D \bTR \bTD[aligncharacter=yes] € 234.451 \eTD \eTR
+% D \bTR \bTD[aligncharacter=yes] € 451 \eTD \eTR
+% D \bTR \bTD \bf some text \eTD \eTR
+% D \eTABLE
+% D \stopbuffer
+% D
+% D \typebuffer \blank \getbuffer \blank
+
+\unexpanded\def\signalcharacteralign#1#2{\attribute\characteralignattribute\numexpr#1*\maxcardminusone+#2\relax} % 0xFFFF
+\unexpanded\def\setcharacteralign #1#2{\clf_setcharacteralign#1{#2}}
+\unexpanded\def\resetcharacteralign {\clf_resetcharacteralign}
+\unexpanded\def\nocharacteralign {\attribute\characteralignattribute\attributeunsetvalue}
%D Mostly downward compatible:
%D
@@ -73,6 +74,15 @@
%D
%D \typebuffer \blank \getbuffer \blank
+%D We have (currently) two modes: \type {text} and \type {number}. The handler tries
+%D to determine the mode automatically. When using periods and commas as separators
+%D the \type {number} mode is chosen. If you use for instance a \type {-} as
+%D separator, \type {text} is chosen, but you can enforce \type {number} with \type
+%D {number->-} (as with other mechanisms, the arrow indicates a methot to apply).
+%D
+%D One can use \type {\nocharacteralign} to disable this mechanism, for instance in
+%D a table cell.
+
\def\alignmentcharacter{,}
\unexpanded\def\typo_charalign_pass_one
@@ -86,19 +96,26 @@
\def\typo_charalign_pass
{\hbox\bgroup\signalcharacteralign\plusone\scratchcounter\let\next}
-\unexpanded\def\startcharacteralign#1\stopcharacteralign
+\unexpanded\def\startcharacteralign
+ {\dosingleempty\typo_charalign_start}
+
+\def\typo_charalign_start[#1]#2\stopcharacteralign
{\bgroup
+ \edef\m_temp{#1}%
+ \ifx\m_temp\empty \else
+ \let\alignmentcharacter\m_temp
+ \fi
\setcharacteralign\plusone\alignmentcharacter
\begingroup
\scratchcounter\zerocount
\let\checkcharacteralign\typo_charalign_pass_one
\settrialtypesetting
- #1\relax
+ #2\relax
\endgroup
\begingroup
\scratchcounter\zerocount
\let\checkcharacteralign\typo_charalign_pass_two
- #1\relax
+ #2\relax
\endgroup
\resetcharacteralign
\egroup}
diff --git a/Master/texmf-dist/tex/context/base/typo-txt.mkvi b/Master/texmf-dist/tex/context/base/typo-txt.mkvi
index fa79a4f6b87..7562fe70cd0 100644
--- a/Master/texmf-dist/tex/context/base/typo-txt.mkvi
+++ b/Master/texmf-dist/tex/context/base/typo-txt.mkvi
@@ -194,4 +194,51 @@
%D \HL
%D \stoptabulate
+%D This is used in the beginners manual. One needs to set the font size to an
+%D acceptable value for this to work.
+
+\unexpanded\def\startnicelyfilledbox
+ {\vbox\bgroup
+ \forgetall
+ \dosingleempty\dostartnicelyfilledbox}
+
+\def\dostartnicelyfilledbox[#1]%
+ {\letdummyparameter\c!width \hsize
+ \letdummyparameter\c!height\vsize
+ \letdummyparameter\c!offset\exheight % we obey to the outer exheight
+ \letdummyparameter\c!strut \v!yes % we obey to the inner strut !
+ \getdummyparameters[#1]%
+ \scratchoffset\dummyparameter\c!offset\relax
+ \setbox\scratchbox\vbox to \dummyparameter\c!height \bgroup
+ \hsize\dummyparameter\c!width\relax
+ \emergencystretch10\scratchoffset
+ \parfillskip\zeropoint
+ \baselineskip\zeropoint plus \onepoint minus \onepoint
+ \beginofshapebox
+ \leftskip \scratchoffset
+ \rightskip\scratchoffset}
+
+\unexpanded\def\stopnicelyfilledbox
+ {\doifelse{\dummyparameter\c!strut}\v!yes
+ {\xdef\doflushnicelyfilledbox
+ {\ht\shapebox\the\strutht
+ \dp\shapebox\the\strutdp
+ \box\shapebox}}%
+ {\gdef\doflushnicelyfilledbox
+ {\box\shapebox}}%
+ \endofshapebox
+ \doreshapebox
+ {\doflushnicelyfilledbox}
+ {\penalty\shapepenalty}
+ {\kern\shapekern}
+ {\vfil}%
+ \kern\scratchoffset
+ \vfilneg
+ \flushshapebox
+ \vfilneg
+ \kern\scratchoffset
+ \egroup
+ \box\scratchbox
+ \egroup}
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/typo-wrp.lua b/Master/texmf-dist/tex/context/base/typo-wrp.lua
new file mode 100644
index 00000000000..07639392ff7
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/typo-wrp.lua
@@ -0,0 +1,76 @@
+if not modules then modules = { } end modules ['typo-wrp'] = {
+ version = 1.001,
+ comment = "companion to typo-wrp.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- begin/end par wrapping stuff ... more to come
+
+local nodecodes = nodes.nodecodes
+
+local glue_code = nodecodes.glue
+local penalty_code = nodecodes.penalty
+local parfill_skip_code = nodes.gluecodes.parfillskip
+local user_penalty_code = nodes.penaltycodes.userpenalty
+
+local nuts = nodes.nuts
+local tonut = nodes.tonut
+local tonode = nodes.tonode
+
+local findtail = nuts.tail
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getfield = nuts.getfield
+local remove = nuts.remove
+
+local wrappers = { }
+typesetters.wrappers = wrappers
+
+local trace_wrappers = trackers.register("typesetters.wrappers",function(v) trace_wrappers = v end)
+
+local report = logs.reporter("paragraphs","wrappers")
+
+-- we really need to pass tail too ... but then we need to check all the plugins
+-- bah ... slowdown
+
+local function remove_dangling_crlf(head,tail)
+ if tail and getid(tail) == glue_code and getsubtype(tail) == parfill_skip_code then
+ tail = getprev(tail)
+ if tail and getid(tail) == penalty_code and getsubtype(tail) == user_penalty_code and getfield(tail,"penalty") == 10000 then
+ tail = getprev(tail)
+ if tail and getid(tail) == penalty_code and getsubtype(tail) == user_penalty_code and getfield(tail,"penalty") == -10000 then
+ if tail == head then
+ -- can't happen
+ else
+ if trace_wrappers then
+ report("removing a probably unwanted end-of-par break in line %s (guess)",tex.inputlineno)
+ end
+ remove(head,tail,true)
+ return head, tail, true
+ end
+ end
+ end
+ end
+ return head, tail, false
+end
+
+function wrappers.handler(head)
+ local head = tonut(head)
+ if head then
+ local tail = findtail(head)
+ local done = false
+ head, tail, done = remove_dangling_crlf(head,tail) -- will be action chain
+ end
+ return head, true
+end
+
+interfaces.implement {
+ name = "enablecrlf",
+ onlyonce = true,
+ actions = function()
+ nodes.tasks.enableaction("processors","typesetters.wrappers.handler")
+ end
+}
diff --git a/Master/texmf-dist/tex/context/base/typo-wrp.mkiv b/Master/texmf-dist/tex/context/base/typo-wrp.mkiv
new file mode 100644
index 00000000000..0538a966273
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/typo-wrp.mkiv
@@ -0,0 +1,65 @@
+%D \module
+%D [ file=typo-wrp,
+%D version=2014.11.09,
+%D title=\CONTEXT\ Typesetting Macros,
+%D subtitle=Wrappers,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Typesetting Macros / Wrapping}
+
+\unprotect
+
+\registerctxluafile{typo-wrp}{1.001}
+
+%D This definition has moved from page-lin.tex to spac-hor.tex (due to
+%D visualization added in august 2003) and now to here (november 2014)
+%D due to cacthing border cases in dirty and messy \XML\ sources).
+
+% \unexpanded\def\crlf
+% {\ifhmode
+% \unskip
+% \prewordbreak\crlfplaceholder
+% \ifcase\raggedstatus\hfil\or\or\or\hfil\fi
+% \break
+% \else
+% \crlfplaceholder
+% \endgraf
+% \fi}
+
+\unexpanded\def\crlf
+ {\ifhmode
+ \expandafter\spac_crlf
+ \fi}
+
+\unexpanded\def\spac_crlf
+ {\clf_enablecrlf % once
+ \unskip
+ \prewordbreak % here or in \spac_crlf_placeholder
+ \spac_crlf_placeholder
+ \ifcase\raggedstatus\hfil\or\or\or\hfil\fi
+ \break
+ \ignorespaces}
+
+\unexpanded\def\spac_crlf_placeholder
+ {\strut}
+
+\unexpanded\def\spac_crlf_placeholder_show
+ {\hbox to \zeropoint{\strut{\infofont\kern.25\emwidth}\lohi{\infofont CR}{\infofont LF}\hss}}
+
+\unexpanded\def\settestcrlf
+ {\let\spac_crlf_placeholder\spac_crlf_placeholder_show}
+
+\unexpanded\def\crlfplaceholder % for old times sake
+ {\spac_crlf_placeholder}
+
+\appendtoks
+ \let\spac_crlf_placeholder\empty
+\to \everysetnostrut
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/unic-ini.lua b/Master/texmf-dist/tex/context/base/unic-ini.lua
index cca1f06175a..132c92efaab 100644
--- a/Master/texmf-dist/tex/context/base/unic-ini.lua
+++ b/Master/texmf-dist/tex/context/base/unic-ini.lua
@@ -11,9 +11,13 @@ local utfchar = utf.char
-- Beware, initializing unicodechar happens at first usage and takes
-- 0.05 -- 0.1 second (lots of function calls).
-function commands.unicodechar(asked)
- local n = characters.unicodechar(asked)
- if n then
- context(utfchar(n))
+interfaces.implement {
+ name = "unicodechar",
+ arguments = "string",
+ actions = function(asked)
+ local n = characters.unicodechar(asked)
+ if n then
+ context(utfchar(n))
+ end
end
-end
+}
diff --git a/Master/texmf-dist/tex/context/base/unic-ini.mkiv b/Master/texmf-dist/tex/context/base/unic-ini.mkiv
index ece0da28355..13ad4bdb98f 100644
--- a/Master/texmf-dist/tex/context/base/unic-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/unic-ini.mkiv
@@ -26,8 +26,7 @@
%D
%D \typebuffer \getbuffer
-%def\unicodechar#1{\char\numexpr#1\relax} % no lookahead
-\def\unicodechar#1{\ctxcommand{unicodechar("#1")}}
+\def\unicodechar#1{\clf_unicodechar{#1}}
\unexpanded\def\unknownchar
{\dontleavehmode\hbox{\vrule\s!width.5\emwidth\s!height\exheight\s!depth\zeropoint}}
diff --git a/Master/texmf-dist/tex/context/base/util-dim.lua b/Master/texmf-dist/tex/context/base/util-dim.lua
index 69061495f94..2bdb870e7a4 100644
--- a/Master/texmf-dist/tex/context/base/util-dim.lua
+++ b/Master/texmf-dist/tex/context/base/util-dim.lua
@@ -24,13 +24,15 @@ local formatters = string.formatters
local texget = tex and tex.get or function() return 65536*10*100 end
+local p_stripzeros = lpeg.patterns.stripzeros
+
--this might become another namespace
number = number or { }
local number = number
-number.tonumberf = function(n) return match(format("%.20f",n),"(.-0?)0*$") end -- one zero too much but alas
-number.tonumberg = function(n) return format("%.20g",n) end
+number.tonumberf = function(n) return lpegmatch(p_stripzeros,format("%.20f",n)) end
+number.tonumberg = function(n) return format("%.20g",n) end
local dimenfactors = allocate {
["pt"] = 1/65536,
@@ -46,66 +48,65 @@ local dimenfactors = allocate {
["nc"] = ( 5080/65043)/65536
}
---~ print(table.serialize(dimenfactors))
---~
---~ %.99g:
---~
---~ t={
---~ ["bp"]=1.5201782378580324e-005,
---~ ["cc"]=1.1883696112892098e-006,
---~ ["cm"]=5.3628510057769479e-007,
---~ ["dd"]=1.4260435335470516e-005,
---~ ["em"]=0.000152587890625,
---~ ["ex"]=6.103515625e-005,
---~ ["in"]=2.1113586636917117e-007,
---~ ["mm"]=5.3628510057769473e-008,
---~ ["nc"]=1.1917446679504327e-006,
---~ ["nd"]=1.4300936015405194e-005,
---~ ["pc"]=1.2715657552083333e-006,
---~ ["pt"]=1.52587890625e-005,
---~ ["sp"]=1,
---~ }
---~
---~ patched %s and tonumber
---~
---~ t={
---~ ["bp"]=0.00001520178238,
---~ ["cc"]=0.00000118836961,
---~ ["cm"]=0.0000005362851,
---~ ["dd"]=0.00001426043534,
---~ ["em"]=0.00015258789063,
---~ ["ex"]=0.00006103515625,
---~ ["in"]=0.00000021113587,
---~ ["mm"]=0.00000005362851,
---~ ["nc"]=0.00000119174467,
---~ ["nd"]=0.00001430093602,
---~ ["pc"]=0.00000127156576,
---~ ["pt"]=0.00001525878906,
---~ ["sp"]=1,
---~ }
+-- print(table.serialize(dimenfactors))
+--
+-- %.99g:
+--
+-- t={
+-- ["bp"]=1.5201782378580324e-005,
+-- ["cc"]=1.1883696112892098e-006,
+-- ["cm"]=5.3628510057769479e-007,
+-- ["dd"]=1.4260435335470516e-005,
+-- ["em"]=0.000152587890625,
+-- ["ex"]=6.103515625e-005,
+-- ["in"]=2.1113586636917117e-007,
+-- ["mm"]=5.3628510057769473e-008,
+-- ["nc"]=1.1917446679504327e-006,
+-- ["nd"]=1.4300936015405194e-005,
+-- ["pc"]=1.2715657552083333e-006,
+-- ["pt"]=1.52587890625e-005,
+-- ["sp"]=1,
+-- }
+--
+-- patched %s and tonumber
+--
+-- t={
+-- ["bp"]=0.00001520178238,
+-- ["cc"]=0.00000118836961,
+-- ["cm"]=0.0000005362851,
+-- ["dd"]=0.00001426043534,
+-- ["em"]=0.00015258789063,
+-- ["ex"]=0.00006103515625,
+-- ["in"]=0.00000021113587,
+-- ["mm"]=0.00000005362851,
+-- ["nc"]=0.00000119174467,
+-- ["nd"]=0.00001430093602,
+-- ["pc"]=0.00000127156576,
+-- ["pt"]=0.00001525878906,
+-- ["sp"]=1,
+-- }
--[[ldx--
A conversion function that takes a number, unit (string) and optional
format (string) is implemented using this table.
--ldx]]--
+local f_none = formatters["%s%s"]
+local f_true = formatters["%0.5F%s"]
-local function numbertodimen(n,unit,fmt)
+local function numbertodimen(n,unit,fmt) -- will be redefined later !
if type(n) == 'string' then
return n
else
unit = unit or 'pt'
+ n = n * dimenfactors[unit]
if not fmt then
- fmt = "%s%s"
+ fmt = f_none(n,unit)
elseif fmt == true then
- fmt = "%0.5f%s"
+ fmt = f_true(n,unit)
+ else
+ return formatters[fmt](n,unit)
end
- return format(fmt,n*dimenfactors[unit],unit)
- -- if fmt then
- -- return format(fmt,n*dimenfactors[unit],unit)
- -- else
- -- return match(format("%.20f",n*dimenfactors[unit]),"(.-0?)0*$") .. unit
- -- end
end
end
diff --git a/Master/texmf-dist/tex/context/base/util-env.lua b/Master/texmf-dist/tex/context/base/util-env.lua
index e96a464b03a..b72226900a9 100644
--- a/Master/texmf-dist/tex/context/base/util-env.lua
+++ b/Master/texmf-dist/tex/context/base/util-env.lua
@@ -9,11 +9,11 @@ if not modules then modules = { } end modules ['util-env'] = {
local allocate, mark = utilities.storage.allocate, utilities.storage.mark
local format, sub, match, gsub, find = string.format, string.sub, string.match, string.gsub, string.find
-local unquoted, quoted = string.unquoted, string.quoted
+local unquoted, quoted, optionalquoted = string.unquoted, string.quoted, string.optionalquoted
local concat, insert, remove = table.concat, table.insert, table.remove
-environment = environment or { }
-local environment = environment
+environment = environment or { }
+local environment = environment
-- precautions
@@ -182,26 +182,14 @@ function environment.splitarguments(separator) -- rather special, cut-off before
end
function environment.reconstructcommandline(arg,noquote)
+ local resolveprefix = resolvers.resolve -- something rather special
arg = arg or environment.originalarguments
if noquote and #arg == 1 then
- -- we could just do: return unquoted(resolvers.resolve(arg[i]))
- local a = arg[1]
- a = resolvers.resolve(a)
- a = unquoted(a)
- return a
+ return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1])
elseif #arg > 0 then
local result = { }
for i=1,#arg do
- -- we could just do: result[#result+1] = format("%q",unquoted(resolvers.resolve(arg[i])))
- local a = arg[i]
- a = resolvers.resolve(a)
- a = unquoted(a)
- a = gsub(a,'"','\\"') -- tricky
- if find(a," ",1,true) then
- result[#result+1] = quoted(a)
- else
- result[#result+1] = a
- end
+ result[i] = optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix)
end
return concat(result," ")
else
@@ -238,26 +226,10 @@ end
-- print(environment.relativepath("//x")) -- //x
-- print(environment.relativepath()) -- e:/tmp
--- -- to be tested:
---
--- function environment.reconstructcommandline(arg,noquote)
--- arg = arg or environment.originalarguments
--- if noquote and #arg == 1 then
--- return unquoted(resolvers.resolve(arg[1]))
--- elseif #arg > 0 then
--- local result = { }
--- for i=1,#arg do
--- result[#result+1] = format("%q",unquoted(resolvers.resolve(arg[i]))) -- always quote
--- end
--- return concat(result," ")
--- else
--- return ""
--- end
--- end
-
if arg then
-- new, reconstruct quoted snippets (maybe better just remove the " then and add them later)
+
local newarg, instring = { }, false
for index=1,#arg do
diff --git a/Master/texmf-dist/tex/context/base/util-prs.lua b/Master/texmf-dist/tex/context/base/util-prs.lua
index 2cede919b1e..ea34c2c279d 100644
--- a/Master/texmf-dist/tex/context/base/util-prs.lua
+++ b/Master/texmf-dist/tex/context/base/util-prs.lua
@@ -167,7 +167,7 @@ local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace)
+ C((nestedbraces + (1-comma))^0)
local pattern = spaces * Ct(value*(separator*value)^0)
--- "aap, {noot}, mies" : outer {} removes, leading spaces ignored
+-- "aap, {noot}, mies" : outer {} removed, leading spaces ignored
patterns.settings_to_array = pattern
@@ -195,12 +195,40 @@ end
--
-- "{123} , 456 " -> "123" "456"
-local separator = space^0 * comma * space^0
-local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace)
- + C((nestedbraces + (1-(space^0*(comma+P(-1)))))^0)
-local withvalue = Carg(1) * value / function(f,s) return f(s) end
-local pattern_a = spaces * Ct(value*(separator*value)^0)
-local pattern_b = spaces * withvalue * (separator*withvalue)^0
+-- local separator = space^0 * comma * space^0
+-- local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace)
+-- + C((nestedbraces + (1-(space^0*(comma+P(-1)))))^0)
+-- local withvalue = Carg(1) * value / function(f,s) return f(s) end
+-- local pattern_a = spaces * Ct(value*(separator*value)^0)
+-- local pattern_b = spaces * withvalue * (separator*withvalue)^0
+
+local cache_a = { }
+local cache_b = { }
+
+function parsers.groupedsplitat(symbol,withaction)
+ if not symbol then
+ symbol = ","
+ end
+ local pattern = (withaction and cache_b or cache_a)[symbol]
+ if not pattern then
+ local symbols = S(symbol)
+ local separator = space^0 * symbols * space^0
+ local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace)
+ + C((nestedbraces + (1-(space^0*(symbols+P(-1)))))^0)
+ if withaction then
+ local withvalue = Carg(1) * value / function(f,s) return f(s) end
+ pattern = spaces * withvalue * (separator*withvalue)^0
+ cache_b[symbol] = pattern
+ else
+ pattern = spaces * Ct(value*(separator*value)^0)
+ cache_a[symbol] = pattern
+ end
+ end
+ return pattern
+end
+
+local pattern_a = parsers.groupedsplitat(",",false)
+local pattern_b = parsers.groupedsplitat(",",true)
function parsers.stripped_settings_to_array(str)
if not str or str == "" then
@@ -221,8 +249,6 @@ end
-- parsers.process_stripped_settings("{123} , 456 ",function(s) print("["..s.."]") end)
-- parsers.process_stripped_settings("123 , 456 ",function(s) print("["..s.."]") end)
---
-
local function set(t,v)
t[#t+1] = v
end
@@ -275,15 +301,25 @@ function parsers.array_to_string(a,separator)
end
end
-function parsers.settings_to_set(str,t) -- tohash? -- todo: lpeg -- duplicate anyway
- t = t or { }
--- for s in gmatch(str,"%s*([^, ]+)") do -- space added
- for s in gmatch(str,"[^, ]+") do -- space added
- t[s] = true
- end
- return t
+-- function parsers.settings_to_set(str,t) -- tohash? -- todo: lpeg -- duplicate anyway
+-- if str then
+-- t = t or { }
+-- for s in gmatch(str,"[^, ]+") do -- space added
+-- t[s] = true
+-- end
+-- return t
+-- else
+-- return { }
+-- end
+-- end
+
+local pattern = Cf(Ct("") * Cg(C((1-S(", "))^1) * S(", ")^0 * Cc(true))^1,rawset)
+
+function utilities.parsers.settings_to_set(str,t)
+ return str and lpegmatch(pattern,str) or { }
end
+
function parsers.simple_hash_to_string(h, separator)
local t, tn = { }, 0
for k, v in sortedhash(h) do
@@ -297,7 +333,7 @@ end
-- for mtx-context etc: aaaa bbbb cccc=dddd eeee=ffff
-local str = C((1-whitespace-equal)^1)
+local str = Cs(lpegpatterns.unquoted) + C((1-whitespace-equal)^1)
local setting = Cf( Carg(1) * (whitespace^0 * Cg(str * whitespace^0 * (equal * whitespace^0 * str + Cc(""))))^1,rawset)
local splitter = setting^1
@@ -305,6 +341,12 @@ function utilities.parsers.options_to_hash(str,target)
return str and lpegmatch(splitter,str,1,target or { }) or { }
end
+local splitter = lpeg.tsplitat(" ")
+
+function utilities.parsers.options_to_array(str)
+ return str and lpegmatch(splitter,str) or { }
+end
+
-- for chem (currently one level)
local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace)
@@ -488,7 +530,7 @@ function parsers.rfc4180splitter(specification)
local field = escaped + non_escaped + Cc("")
local record = Ct(field * (separator * field)^1)
local headerline = record * Cp()
- local wholeblob = Ct((newline^-1 * record)^0)
+ local wholeblob = Ct((newline^(specification.strict and -1 or 1) * record)^0)
return function(data,getheader)
if getheader then
local header, position = lpegmatch(headerline,data)
@@ -542,8 +584,8 @@ end
--
-local pattern_math = Cs((P("%")/"\\percent " + P("^") * Cc("{") * lpegpatterns.integer * Cc("}") + P(1))^0)
-local pattern_text = Cs((P("%")/"\\percent " + (P("^")/"\\high") * Cc("{") * lpegpatterns.integer * Cc("}") + P(1))^0)
+local pattern_math = Cs((P("%")/"\\percent " + P("^") * Cc("{") * lpegpatterns.integer * Cc("}") + anything)^0)
+local pattern_text = Cs((P("%")/"\\percent " + (P("^")/"\\high") * Cc("{") * lpegpatterns.integer * Cc("}") + anything)^0)
patterns.unittotex = pattern
@@ -551,7 +593,7 @@ function parsers.unittotex(str,textmode)
return lpegmatch(textmode and pattern_text or pattern_math,str)
end
-local pattern = Cs((P("^") / "" * lpegpatterns.integer * Cc("") + P(1))^0)
+local pattern = Cs((P("^") / "" * lpegpatterns.integer * Cc("") + anything)^0)
function parsers.unittoxml(str)
return lpegmatch(pattern,str)
@@ -648,3 +690,27 @@ function utilities.parsers.runtime(time)
local seconds = mod(time,60)
return days, hours, minutes, seconds
end
+
+--
+
+local spacing = whitespace^0
+local apply = P("->")
+local method = C((1-apply)^1)
+local token = lbrace * C((1-rbrace)^1) * rbrace + C(anything^1)
+
+local pattern = spacing * (method * spacing * apply + Carg(1)) * spacing * token
+
+function utilities.parsers.splitmethod(str,default)
+ if str then
+ return lpegmatch(pattern,str,1,default or false)
+ else
+ return default or false, ""
+ end
+end
+
+-- print(utilities.parsers.splitmethod(" foo -> {bar} "))
+-- print(utilities.parsers.splitmethod("foo->{bar}"))
+-- print(utilities.parsers.splitmethod("foo->bar"))
+-- print(utilities.parsers.splitmethod("foo"))
+-- print(utilities.parsers.splitmethod("{foo}"))
+-- print(utilities.parsers.splitmethod())
diff --git a/Master/texmf-dist/tex/context/base/util-sbx.lua b/Master/texmf-dist/tex/context/base/util-sbx.lua
new file mode 100644
index 00000000000..260e8b3b5a7
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/util-sbx.lua
@@ -0,0 +1,415 @@
+if not modules then modules = { } end modules ['util-sbx'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Note: we use expandname and collapsepath and these use chdir
+-- which is overloaded so we need to use originals there. Just
+-- something to keep in mind.
+
+if not sandbox then require("l-sandbox") end -- for testing
+
+local next, type = next, type
+
+local replace = utilities.templates.replace
+local collapsepath = file.collapsepath
+local expandname = dir.expandname
+local sortedhash = table.sortedhash
+local lpegmatch = lpeg.match
+local platform = os.type
+local P, S, C = lpeg.P, lpeg.S, lpeg.C
+local gsub = string.gsub
+local lower = string.lower
+local unquoted = string.unquoted
+local optionalquoted = string.optionalquoted
+
+local sandbox = sandbox
+local validroots = { }
+local validrunners = { }
+local validbinaries = { }
+local validators = { }
+local p_validroot = nil
+local finalized = nil
+local norunners = false
+local trace = false
+local p_split = lpeg.tsplitat(" ") -- more spaces?
+
+local report = logs.reporter("sandbox")
+
+trackers.register("sandbox",function(v) trace = v end) -- often too late anyway
+
+sandbox.setreporter(report)
+
+sandbox.finalizer(function()
+ finalized = true
+end)
+
+local function registerroot(root,what) -- what == read|write
+ if finalized then
+ report("roots are already finalized")
+ else
+ root = collapsepath(expandname(root))
+ if platform == "windows" then
+ root = lower(root) -- we assume ascii names
+ end
+ -- true: read & write | false: read
+ validroots[root] = what == "write" or false
+ end
+end
+
+sandbox.finalizer(function() -- initializers can set the path
+ if p_validroot then
+ report("roots are already initialized")
+ else
+ sandbox.registerroot(".","write") -- always ok
+ -- also register texmf as read
+ for name in sortedhash(validroots) do
+ if p_validroot then
+ p_validroot = P(name) + p_validroot
+ else
+ p_validroot = P(name)
+ end
+ end
+ p_validroot = p_validroot / validroots
+ end
+end)
+
+local function registerrunner(specification)
+ if finalized then
+ report("runners are already finalized")
+ else
+ local name = specification.name
+ if not name then
+ report("no runner name specified")
+ return
+ end
+ local program = specification.program
+ if type(program) == "string" then
+ -- common for all platforms
+ elseif type(program) == "table" then
+ program = program[platform]
+ end
+ if type(program) ~= "string" or program == "" then
+ report("invalid runner %a specified for platform %a",name,platform)
+ return
+ end
+ specification.program = program
+ validrunners[name] = specification
+ end
+end
+
+local function registerbinary(name)
+ if finalized then
+ report("binaries are already finalized")
+ elseif type(name) == "string" and name ~= "" then
+ validbinaries[name] = true
+ end
+end
+
+-- begin of validators
+
+local p_write = S("wa") p_write = (1 - p_write)^0 * p_write
+local p_path = S("\\/~$%:") p_path = (1 - p_path )^0 * p_path -- be easy on other arguments
+
+local function normalized(name) -- only used in executers
+ if platform == "windows" then
+ name = gsub(name,"/","\\")
+ end
+ return name
+end
+
+function sandbox.possiblepath(name)
+ return lpegmatch(p_path,name) and true or false
+end
+
+local filenamelogger = false
+
+function sandbox.setfilenamelogger(l)
+ filenamelogger = type(l) == "function" and l or false
+end
+
+local function validfilename(name,what)
+ if p_validroot and type(name) == "string" and lpegmatch(p_path,name) then
+ local asked = collapsepath(expandname(name))
+ if platform == "windows" then
+ asked = lower(asked) -- we assume ascii names
+ end
+ local okay = lpegmatch(p_validroot,asked)
+ if okay == true then
+ -- read and write access
+ if filenamelogger then
+ filenamelogger(name,"w",asked,true)
+ end
+ return name
+ elseif okay == false then
+ -- read only access
+ if not what then
+ -- no further argument to io.open so a readonly case
+ if filenamelogger then
+ filenamelogger(name,"r",asked,true)
+ end
+ return name
+ elseif lpegmatch(p_write,what) then
+ if filenamelogger then
+ filenamelogger(name,"w",asked,false)
+ end
+ return -- we want write access
+ else
+ if filenamelogger then
+ filenamelogger(name,"r",asked,true)
+ end
+ return name
+ end
+ else
+ if filenamelogger then
+ filenamelogger(name,"*",name,false)
+ end
+ end
+ else
+ return name
+ end
+end
+
+local function readable(name)
+ if platform == "windows" then
+ name = lower(name) -- we assume ascii names
+ end
+ local valid = validfilename(name,"r")
+ if valid then
+ return normalized(valid)
+ end
+end
+
+local function writeable(name)
+ if platform == "windows" then
+ name = lower(name) -- we assume ascii names
+ end
+ local valid = validfilename(name,"w")
+ if valid then
+ return normalized(valid)
+ end
+end
+
+validators.readable = readable
+validators.writeable = writeable
+validators.filename = readable
+
+table.setmetatableindex(validators,function(t,k)
+ if k then
+ t[k] = readable
+ end
+ return readable
+end)
+
+function validators.string(s)
+ return s -- can be used to prevent filename checking
+end
+
+-- end of validators
+
+sandbox.registerroot = registerroot
+sandbox.registerrunner = registerrunner
+sandbox.registerbinary = registerbinary
+sandbox.validfilename = validfilename
+
+local function filehandlerone(action,one,...)
+ local checkedone = validfilename(one)
+ if checkedone then
+ return action(one,...)
+ else
+-- report("file %a is unreachable",one)
+ end
+end
+
+local function filehandlertwo(action,one,two,...)
+ local checkedone = validfilename(one)
+ if checkedone then
+ local checkedtwo = validfilename(two)
+ if checkedtwo then
+ return action(one,two,...)
+ else
+-- report("file %a is unreachable",two)
+ end
+ else
+-- report("file %a is unreachable",one)
+ end
+end
+
+local function iohandler(action,one,...)
+ if type(one) == "string" then
+ local checkedone = validfilename(one)
+ if checkedone then
+ return action(one,...)
+ end
+ elseif one then
+ return action(one,...)
+ else
+ return action()
+ end
+end
+
+-- runners can be strings or tables
+--
+-- os.execute : string
+-- os.exec : table with program in [0|1]
+-- os.spawn : table with program in [0|1]
+--
+-- our execute: registered program with specification
+
+local function runhandler(action,name,specification)
+ local kind = type(name)
+ if kind ~= "string" then
+ return
+ end
+ if norunners then
+ report("no runners permitted, ignoring command: %s",name)
+ return
+ end
+ local spec = validrunners[name]
+ if not spec then
+ report("unknown runner: %s",name)
+ return
+ end
+ -- specs are already checked
+ local program = spec.program
+ local variables = { }
+ local checkers = spec.checkers or { }
+ if specification then
+ -- we only handle runners that are defined before the sandbox is
+ -- closed so in principle we cannot have user runs with no files
+ -- while for context runners we assume a robust specification
+ for k, v in next, specification do
+ local checker = validators[checkers[k]]
+ local value = checker(unquoted(v)) -- todo: write checkers
+ if value then
+ variables[k] = optionalquoted(value)
+ else
+ report("suspicious argument found, run blocked: %s",v)
+ return
+ end
+ end
+ end
+ local command = replace(program,variables)
+ if trace then
+ report("executing runner: %s",command)
+ end
+ return action(command)
+end
+
+-- only registered (from list) -- no checking on writable so let's assume harmless
+-- runs
+
+local function binaryhandler(action,name)
+ local kind = type(name)
+ local list = name
+ if kind == "string" then
+ list = lpegmatch(p_split,name)
+ end
+ local program = name[0] or name[1]
+ if type(program) ~= "string" or program == "" then
+ return --silently ignore
+ end
+ if norunners then
+ report("no binaries permitted, ignoring command: %s",program)
+ return
+ end
+ if not validbinaries[program] then
+ report("binary is not permitted: %s",program)
+ return
+ end
+ for i=0,#list do
+ local n = list[i]
+ if n then
+ local v = readable(unquoted(n))
+ if v then
+ list[i] = optionalquoted(v)
+ else
+ report("suspicious argument found, run blocked: %s",n)
+ return
+ end
+ end
+ end
+ return action(name)
+end
+
+sandbox.filehandlerone = filehandlerone
+sandbox.filehandlertwo = filehandlertwo
+sandbox.iohandler = iohandler
+sandbox.runhandler = runhandler
+sandbox.binaryhandler = binaryhandler
+
+function sandbox.disablerunners()
+ norunners = true
+end
+
+local execute = sandbox.original(os.execute)
+
+function sandbox.run(name,specification)
+ return runhandler(execute,name,specification)
+end
+
+-------------------
+
+local overload = sandbox.overload
+local register = sandbox.register
+
+ overload(loadfile, filehandlerone,"loadfile") -- todo
+
+if io then
+ overload(io.open, filehandlerone,"io.open")
+ overload(io.popen, filehandlerone,"io.popen")
+ overload(io.input, iohandler, "io.input")
+ overload(io.output, iohandler, "io.output")
+ overload(io.lines, filehandlerone,"io.lines")
+end
+
+if os then
+ overload(os.execute, binaryhandler, "os.execute")
+ overload(os.spawn, binaryhandler, "os.spawn")
+ overload(os.exec, binaryhandler, "os.exec")
+ overload(os.rename, filehandlertwo,"os.rename")
+ overload(os.remove, filehandlerone,"os.remove")
+end
+
+if lfs then
+ overload(lfs.chdir, filehandlerone,"lfs.chdir")
+ overload(lfs.mkdir, filehandlerone,"lfs.mkdir")
+ overload(lfs.rmdir, filehandlerone,"lfs.rmdir")
+ overload(lfs.isfile, filehandlerone,"lfs.isfile")
+ overload(lfs.isdir, filehandlerone,"lfs.isdir")
+ overload(lfs.attributes, filehandlerone,"lfs.attributes")
+ overload(lfs.dir, filehandlerone,"lfs.dir")
+ overload(lfs.lock_dir, filehandlerone,"lfs.lock_dir")
+ overload(lfs.touch, filehandlerone,"lfs.touch")
+ overload(lfs.link, filehandlertwo,"lfs.link")
+ overload(lfs.setmode, filehandlerone,"lfs.setmode")
+ overload(lfs.readlink, filehandlerone,"lfs.readlink")
+ overload(lfs.shortname, filehandlerone,"lfs.shortname")
+ overload(lfs.symlinkattributes,filehandlerone,"lfs.symlinkattributes")
+end
+
+-- these are used later on
+
+if zip then
+ zip.open = register(zip.open, filehandlerone,"zip.open")
+end
+
+if fontloader then
+ fontloader.open = register(fontloader.open,filehandlerone,"fontloader.open")
+ fontloader.info = register(fontloader.info,filehandlerone,"fontloader.info")
+end
+
+if epdf then
+ epdf.open = register(epdf.open, filehandlerone,"epdf.open")
+end
+
+-- not used in a normal mkiv run : os.spawn = os.execute
+-- not used in a normal mkiv run : os.exec = os.exec
+
+-- print(io.open("test.log"))
+-- sandbox.enable()
+-- print(io.open("test.log"))
+-- print(io.open("t:/test.log"))
diff --git a/Master/texmf-dist/tex/context/base/util-seq.lua b/Master/texmf-dist/tex/context/base/util-seq.lua
index 35e6932855c..08fc4e95cb8 100644
--- a/Master/texmf-dist/tex/context/base/util-seq.lua
+++ b/Master/texmf-dist/tex/context/base/util-seq.lua
@@ -17,13 +17,15 @@ use locals to refer to them when compiling the chain.
-- todo: protect groups (as in tasks)
-local format, gsub, concat, gmatch = string.format, string.gsub, table.concat, string.gmatch
+local gsub, concat, gmatch = string.gsub, table.concat, string.gmatch
local type, load = type, load
utilities = utilities or { }
local tables = utilities.tables
local allocate = utilities.storage.allocate
+local formatters = string.formatters
+
local sequencers = { }
utilities.sequencers = sequencers
@@ -31,6 +33,7 @@ local functions = allocate()
sequencers.functions = functions
local removevalue = tables.removevalue
+local replacevalue = tables.replacevalue
local insertaftervalue = tables.insertaftervalue
local insertbeforevalue = tables.insertbeforevalue
@@ -189,6 +192,18 @@ function sequencers.removeaction(t,group,action,force)
end
end
+function sequencers.replaceaction(t,group,oldaction,newaction,force)
+ t = known[t]
+ if t then
+ local g = t.list[group]
+ if g and (force or validaction(oldaction)) then
+ replacevalue(g,oldaction,newaction)
+ t.dirty = true
+ t.runner = nil
+ end
+ end
+end
+
local function localize(str)
return (gsub(str,"[%.: ]+","_"))
end
@@ -204,20 +219,23 @@ local function construct(t)
for i=1,#actions do
local action = actions[i]
if not askip[action] then
+ local localized
if type(action) == "function" then
local name = localize(tostring(action))
functions[name] = action
- action = format("utilities.sequencers.functions.%s",name)
+ action = formatters["utilities.sequencers.functions.%s"](name)
+ localized = localize(name) -- shorter than action
+ else
+ localized = localize(action)
end
- local localized = localize(action)
n = n + 1
- variables[n] = format("local %s = %s",localized,action)
+ variables[n] = formatters["local %s = %s"](localized,action)
if not returnvalues then
- calls[n] = format("%s(%s)",localized,arguments)
+ calls[n] = formatters["%s(%s)"](localized,arguments)
elseif n == 1 then
- calls[n] = format("local %s = %s(%s)",returnvalues,localized,arguments)
+ calls[n] = formatters["local %s = %s(%s)"](returnvalues,localized,arguments)
else
- calls[n] = format("%s = %s(%s)",returnvalues,localized,arguments)
+ calls[n] = formatters["%s = %s(%s)"](returnvalues,localized,arguments)
end
end
end
@@ -230,9 +248,9 @@ local function construct(t)
variables = concat(variables,"\n")
calls = concat(calls,"\n")
if results then
- t.compiled = format("%s\nreturn function(%s)\n%s\nreturn %s\nend",variables,arguments,calls,results)
+ t.compiled = formatters["%s\nreturn function(%s)\n%s\nreturn %s\nend"](variables,arguments,calls,results)
else
- t.compiled = format("%s\nreturn function(%s)\n%s\nend",variables,arguments,calls)
+ t.compiled = formatters["%s\nreturn function(%s)\n%s\nend"](variables,arguments,calls)
end
end
-- print(t.compiled)
@@ -258,6 +276,7 @@ compile = function(t,compiler,n) -- already referred to in sequencers.new
if compiled == "" then
runner = false
else
+-- inspect(compiled)
runner = compiled and load(compiled)() -- we can use loadstripped here
end
t.runner = runner
@@ -314,12 +333,12 @@ function sequencers.nodeprocessor(t,nofarguments) -- todo: handle 'kind' in plug
if not askip[action] then
local localized = localize(action)
n = n + 1
- vars[n] = format("local %s = %s",localized,action)
+ vars[n] = formatters["local %s = %s"](localized,action)
-- only difference with tostring is kind and rets (why no return)
if kind[action] == "nohead" then
- calls[n] = format(" ok = %s(head%s) done = done or ok",localized,args)
+ calls[n] = formatters[" ok = %s(head%s) done = done or ok"](localized,args)
else
- calls[n] = format(" head, ok = %s(head%s) done = done or ok",localized,args)
+ calls[n] = formatters[" head, ok = %s(head%s) done = done or ok"](localized,args)
end
-- local s = " print('" .. tostring(group) .. " " .. tostring(action) .. " : ' .. tostring(head)) "
-- calls[n] = s .. calls[n] .. s
@@ -327,6 +346,6 @@ function sequencers.nodeprocessor(t,nofarguments) -- todo: handle 'kind' in plug
end
end
end
- local processor = #calls > 0 and format(template_yes,concat(vars,"\n"),args,concat(calls,"\n")) or template_nop
+ local processor = #calls > 0 and formatters[template_yes](concat(vars,"\n"),args,concat(calls,"\n")) or template_nop
return processor
end
diff --git a/Master/texmf-dist/tex/context/base/util-sql-loggers.lua b/Master/texmf-dist/tex/context/base/util-sql-loggers.lua
index 7fceb8032c0..ceb1ff75cfa 100644
--- a/Master/texmf-dist/tex/context/base/util-sql-loggers.lua
+++ b/Master/texmf-dist/tex/context/base/util-sql-loggers.lua
@@ -52,7 +52,7 @@ table.setmetatableindex(fromtype,function() return "info" end)
loggers.totype = totype
loggers.fromtype = fromtype
-local template =[[
+local template = [[
CREATE TABLE IF NOT EXISTS %basename% (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time` int(11) NOT NULL,
diff --git a/Master/texmf-dist/tex/context/base/util-sta.lua b/Master/texmf-dist/tex/context/base/util-sta.lua
index 1a61ec4e6c4..27ab5a624b6 100644
--- a/Master/texmf-dist/tex/context/base/util-sta.lua
+++ b/Master/texmf-dist/tex/context/base/util-sta.lua
@@ -81,6 +81,8 @@ end
function stacker.new(name)
+ local report = logs.reporter("stacker",name or nil)
+
local s
local stack = { }
@@ -126,8 +128,18 @@ function stacker.new(name)
end
end
- local tops = { }
- local top, switch
+ local tops = { }
+ local top = nil
+ local switch = nil
+
+ local function resolve_reset(mode)
+ if #tops > 0 then
+ report("resetting %s left-over states of %a",#tops,name)
+ end
+ tops = { }
+ top = nil
+ switch = nil
+ end
local function resolve_begin(mode)
if mode then
@@ -206,8 +218,7 @@ function stacker.new(name)
local function resolve_end()
-- resolve_step(s.unset)
- local noftop = #top
- if noftop > 0 then
+ if #tops > 0 then -- was #top brrr
local result = s.stop(s,top,1,#top)
remove(tops)
top = tops[#tops]
@@ -224,8 +235,6 @@ function stacker.new(name)
resolve_end()
end
- local report = logs.reporter("stacker",name or nil)
-
s = {
name = name or "unknown",
unset = -1,
@@ -240,6 +249,7 @@ function stacker.new(name)
resolve_begin = resolve_begin,
resolve_step = resolve_step,
resolve_end = resolve_end,
+ resolve_reset = resolve_reset,
}
return s -- we can overload functions
diff --git a/Master/texmf-dist/tex/context/base/util-str.lua b/Master/texmf-dist/tex/context/base/util-str.lua
index 5609cdf255d..a677a82ed5c 100644
--- a/Master/texmf-dist/tex/context/base/util-str.lua
+++ b/Master/texmf-dist/tex/context/base/util-str.lua
@@ -216,14 +216,19 @@ local striplinepatterns = {
["retain"] = p_retain_normal,
["retain and collapse"] = p_retain_collapse,
["retain and no empty"] = p_retain_noempty,
+ ["collapse"] = patterns.collapser, -- how about: stripper fullstripper
}
+setmetatable(striplinepatterns,{ __index = function(t,k) return p_prune_collapse end })
+
strings.striplinepatterns = striplinepatterns
function strings.striplines(str,how)
- return str and lpegmatch(how and striplinepatterns[how] or p_prune_collapse,str) or str
+ return str and lpegmatch(striplinepatterns[how],str) or str
end
+-- also see: string.collapsespaces
+
strings.striplong = strings.striplines -- for old times sake
-- local str = table.concat( {
@@ -356,10 +361,10 @@ strings.tracers = tracedchars
function string.tracedchar(b)
-- todo: table
if type(b) == "number" then
- return tracedchars[b] or (utfchar(b) .. " (U+" .. format('%05X',b) .. ")")
+ return tracedchars[b] or (utfchar(b) .. " (U+" .. format("%05X",b) .. ")")
else
local c = utfbyte(b)
- return tracedchars[c] or (b .. " (U+" .. format('%05X',c) .. ")")
+ return tracedchars[c] or (b .. " (U+" .. (c and format("%05X",c) or "?????") .. ")")
end
end
@@ -525,12 +530,21 @@ local format_f = function(f)
return format("format('%%%sf',a%s)",f,n)
end
-local format_F = function(f)
+-- The next one formats an integer as integer and very small values as zero. This is needed
+-- for pdf backend code.
+--
+-- 1.23 % 1 : 0.23
+-- - 1.23 % 1 : 0.77
+--
+-- We could probably use just %s with integers but who knows what Lua 5.3 will do? So let's
+-- for the moment use %i.
+
+local format_F = function(f) -- beware, no cast to number
n = n + 1
if not f or f == "" then
- return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or (a%s == 1 and '1') or format('%%.9f',a%s))",n,n,n,n)
+ return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n)
else
- return format("((a%s == 0 and '0') or (a%s == 1 and '1') or format('%%%sf',a%s))",n,n,f,n)
+ return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n)
end
end
@@ -830,7 +844,7 @@ local builder = Cs { "start",
+ V("m") + V("M") -- new
+ V("z") -- new
--
- + V("*") -- ignores probably messed up %
+ -- + V("?") -- ignores probably messed up %
)
+ V("*")
)
@@ -885,6 +899,7 @@ local builder = Cs { "start",
["A"] = (prefix_any * P("A")) / format_A, -- %A => "..." (forces tostring)
--
["*"] = Cs(((1-P("%"))^1 + P("%%")/"%%")^1) / format_rest, -- rest (including %%)
+ ["?"] = Cs(((1-P("%"))^1 )^1) / format_rest, -- rest (including %%)
--
["!"] = Carg(2) * prefix_any * P("!") * C((1-P("!"))^1) * P("!") / format_extension,
}
@@ -1082,3 +1097,23 @@ end
-- string.formatteds = formatteds
--
-- setmetatable(formatteds, { __index = make, __call = use })
+
+-- This is a somewhat silly one used in commandline reconstruction but the older
+-- method, using a combination of fine, gsub, quoted and unquoted was not that
+-- reliable.
+--
+-- '"foo"bar \"and " whatever"' => "foo\"bar \"and \" whatever"
+-- 'foo"bar \"and " whatever' => "foo\"bar \"and \" whatever"
+
+local dquote = patterns.dquote -- P('"')
+local equote = patterns.escaped + dquote / '\\"' + 1
+local space = patterns.space
+local cquote = Cc('"')
+
+local pattern =
+ Cs(dquote * (equote - P(-2))^0 * dquote) -- we keep the outer but escape unescaped ones
+ + Cs(cquote * (equote - space)^0 * space * equote^0 * cquote) -- we escape unescaped ones
+
+function string.optionalquoted(str)
+ return lpegmatch(pattern,str) or str
+end
diff --git a/Master/texmf-dist/tex/context/base/util-tab.lua b/Master/texmf-dist/tex/context/base/util-tab.lua
index f9e9b318df3..5eae0d5f676 100644
--- a/Master/texmf-dist/tex/context/base/util-tab.lua
+++ b/Master/texmf-dist/tex/context/base/util-tab.lua
@@ -98,6 +98,17 @@ function tables.removevalue(t,value) -- todo: n
end
end
+function tables.replacevalue(t,oldvalue,newvalue)
+ if oldvalue and newvalue then
+ for i=1,#t do
+ if t[i] == oldvalue then
+ t[i] = newvalue
+ -- replace all, so no: return
+ end
+ end
+ end
+end
+
function tables.insertbeforevalue(t,value,extra)
for i=1,#t do
if t[i] == extra then
@@ -612,7 +623,7 @@ function table.serialize(root,name,specification)
depth = depth + 1
end
-- we could check for k (index) being number (cardinal)
- if root and next(root) then
+ if root and next(root) ~= nil then
local first = nil
local last = 0
last = #root
@@ -637,7 +648,7 @@ function table.serialize(root,name,specification)
elseif tv == "string" then
n = n + 1 t[n] = f_val_str(depth,v)
elseif tv == "table" then
- if not next(v) then
+ if next(v) == nil then
n = n + 1 t[n] = f_val_not(depth)
else
local st = simple_table(v)
@@ -667,7 +678,7 @@ function table.serialize(root,name,specification)
n = n + 1 t[n] = f_key_boo_value_str(depth,k,v)
end
elseif tv == "table" then
- if not next(v) then
+ if next(v) == nil then
if tk == "number" then
n = n + 1 t[n] = f_key_num_value_not(depth,k,v)
elseif tk == "string" then
@@ -731,7 +742,7 @@ function table.serialize(root,name,specification)
root._w_h_a_t_e_v_e_r_ = nil
end
-- Let's forget about empty tables.
- if next(root) then
+ if next(root) ~= nil then
do_serialize(root,name,1,0)
end
end
diff --git a/Master/texmf-dist/tex/context/base/util-tpl.lua b/Master/texmf-dist/tex/context/base/util-tpl.lua
index 67d05822116..468dd429c98 100644
--- a/Master/texmf-dist/tex/context/base/util-tpl.lua
+++ b/Master/texmf-dist/tex/context/base/util-tpl.lua
@@ -52,7 +52,7 @@ local sqlescape = lpeg.replacer {
-- { "\t", "\\t" },
}
-local sqlquoted = lpeg.Cs(lpeg.Cc("'") * sqlescape * lpeg.Cc("'"))
+local sqlquoted = Cs(Cc("'") * sqlescape * Cc("'"))
lpegpatterns.sqlescape = sqlescape
lpegpatterns.sqlquoted = sqlquoted
@@ -111,13 +111,26 @@ local luaescaper = escapers.lua
local quotedluaescaper = quotedescapers.lua
local function replacekeyunquoted(s,t,how,recurse) -- ".. \" "
- local escaper = how and escapers[how] or luaescaper
- return escaper(replacekey(s,t,how,recurse))
+ if how == false then
+ return replacekey(s,t,how,recurse)
+ else
+ local escaper = how and escapers[how] or luaescaper
+ return escaper(replacekey(s,t,how,recurse))
+ end
end
local function replacekeyquoted(s,t,how,recurse) -- ".. \" "
- local escaper = how and quotedescapers[how] or quotedluaescaper
- return escaper(replacekey(s,t,how,recurse))
+ if how == false then
+ return replacekey(s,t,how,recurse)
+ else
+ local escaper = how and quotedescapers[how] or quotedluaescaper
+ return escaper(replacekey(s,t,how,recurse))
+ end
+end
+
+local function replaceoptional(l,m,r,t,how,recurse)
+ local v = t[l]
+ return v and v ~= "" and lpegmatch(replacer,r,1,t,how or "lua",recurse or false) or ""
end
local single = P("%") -- test %test% test : resolves test
@@ -135,12 +148,19 @@ local norquoted = rquoted / ''
local nolquotedq = lquotedq / ''
local norquotedq = rquotedq / ''
-local key = nosingle * ((C((1-nosingle )^1) * Carg(1) * Carg(2) * Carg(3)) / replacekey ) * nosingle
-local quoted = nolquotedq * ((C((1-norquotedq)^1) * Carg(1) * Carg(2) * Carg(3)) / replacekeyquoted ) * norquotedq
-local unquoted = nolquoted * ((C((1-norquoted )^1) * Carg(1) * Carg(2) * Carg(3)) / replacekeyunquoted) * norquoted
+local noloptional = P("%?") / ''
+local noroptional = P("?%") / ''
+local nomoptional = P(":") / ''
+
+
+local args = Carg(1) * Carg(2) * Carg(3)
+local key = nosingle * ((C((1-nosingle )^1) * args) / replacekey ) * nosingle
+local quoted = nolquotedq * ((C((1-norquotedq )^1) * args) / replacekeyquoted ) * norquotedq
+local unquoted = nolquoted * ((C((1-norquoted )^1) * args) / replacekeyunquoted) * norquoted
+local optional = noloptional * ((C((1-nomoptional)^1) * nomoptional * C((1-noroptional)^1) * args) / replaceoptional) * noroptional
local any = P(1)
- replacer = Cs((unquoted + quoted + escape + key + any)^0)
+ replacer = Cs((unquoted + quoted + escape + optional + key + any)^0)
local function replace(str,mapping,how,recurse)
if mapping and str then
@@ -156,6 +176,7 @@ end
-- print(replace("test '%[x]%' test",{ x = [[a '%y%' a]], y = "oeps" },'sql',true))
-- print(replace([[test %[x]% test]],{ x = [[a "x" a]]}))
-- print(replace([[test %(x)% test]],{ x = [[a "x" a]]}))
+-- print(replace([[convert %?x: -x "%x%" ?% %?y: -y "%y%" ?%]],{ x = "yes" }))
templates.replace = replace
@@ -188,3 +209,5 @@ end
-- inspect(utilities.templates.replace("test %one% test", { one = "%two%", two = "two" }))
-- inspect(utilities.templates.resolve({ one = "%two%", two = "two", three = "%three%" }))
+-- inspect(utilities.templates.replace("test %one% test", { one = "%two%", two = "two" },false,true))
+-- inspect(utilities.templates.replace("test %one% test", { one = "%two%", two = "two" },false))
diff --git a/Master/texmf-dist/tex/context/base/x-asciimath.lua b/Master/texmf-dist/tex/context/base/x-asciimath.lua
index 87f04b5ff7d..7ddf5a6379a 100644
--- a/Master/texmf-dist/tex/context/base/x-asciimath.lua
+++ b/Master/texmf-dist/tex/context/base/x-asciimath.lua
@@ -7,268 +7,2058 @@ if not modules then modules = { } end modules ['x-asciimath'] = {
}
--[[ldx--
-Some backgrounds are discussed in x-asciimath.mkiv .
+Some backgrounds are discussed in x-asciimath.mkiv . This is a third version. I first
+tried a to make a proper expression parser but it's not that easy. First we have to avoid left
+recursion, which is not that trivial (maybe a future version of lpeg will provide that), and
+second there is not really a syntax but a mix of expressions and sequences with some fuzzy logic
+applied. Most problematic are fractions and we also need to handle incomplete expressions. So,
+instead we (sort of) tokenize the string and then do some passes over the result. Yes, it's real
+ugly and unsatisfying code mess down here. Don't take this as an example.
--ldx]]--
-local trace_mapping = false if trackers then trackers.register("modules.asciimath.mapping", function(v) trace_mapping = v end) end
+-- todo: spaces around all elements in cleanup?
+-- todo: filter from files listed in tuc file
-local asciimath = { }
-local moduledata = moduledata or { }
-moduledata.asciimath = asciimath
+local trace_mapping = false if trackers then trackers.register("modules.asciimath.mapping", function(v) trace_mapping = v end) end
+local trace_detail = false if trackers then trackers.register("modules.asciimath.detail", function(v) trace_detail = v end) end
+local trace_digits = false if trackers then trackers.register("modules.asciimath.digits", function(v) trace_digits = v end) end
local report_asciimath = logs.reporter("mathematics","asciimath")
-local format = string.format
-local lpegmatch = lpeg.match
-local S, P, R, C, V, Cc, Ct, Cs = lpeg.S, lpeg.P, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc, lpeg.Ct, lpeg.Cs
-
-local letter = lpeg.patterns.utf8
-local space = S(" \n\r\t")
-local spaces = space^0/""
-local integer = P("-")^-1 * R("09")^1
-local realpart = P("-")^-1 * R("09")^1 * S(".")^1 * R("09")^1
-local number = integer -- so we can support nice formatting if needed
-local real = realpart -- so we can support nice formatting if needed
-local float = realpart * P("E") * integer -- so we can support nice formatting if needed
-local texnic = P("\\") * (R("az","AZ")^1)
-
-local premapper = Cs ( (
-
- P("@") / "\\degrees " +
- P("O/") / "\\varnothing " +
- P("o+") / "\\oplus " +
- P("o.") / "\\ocirc " +
- P("!in") / "\\not\\in " +
- P("!=") / "\\neq " +
- P("**") / "\\star " +
- P("*") / "\\cdot " +
- P("//") / "\\slash " +
- P("/_") / "\\angle " +
- P("\\\\") / "\\backslash " +
- P("^^^") / "\\wedge " +
- P("^^") / "\\wedge " +
- P("<<") / "\\left\\langle " +
- P(">>") / "\\right\\rangle " +
- P("<=") / "\\leq " +
- P(">=") / "\\geq " +
- P("-<") / "\\precc " +
- P(">-") / "\\succ " +
- P("~=") / "\\cong " +
- P("~~") / "\\approx " +
- P("=>") / "\\Rightarrow " +
- P("(:") / "\\left\\langle " +
- P(":)") / "\\right\\rangle " +
- P(":.") / "\\therefore " +
- P("~|") / "\\right\\rceil " +
- P("_|_") / "\\bot " +
- P("_|") / "\\right\\rfloor " +
- P("+-") / "\\pm " +
- P("|--") / "\\vdash " +
- P("|==") / "\\models " +
- P("|_") / "\\left\\lfloor " +
- P("|~") / "\\left\\lceil " +
- P("-:") / "\\div " +
- P("_=") / "\\equiv " +
-
- P("|") / "\\middle\\| " +
-
- P("dx") / "(dx)" +
- P("dy") / "(dy)" +
- P("dz") / "(dz)" +
-
- letter + P(1)
+local asciimath = { }
+local moduledata = moduledata or { }
+moduledata.asciimath = asciimath
-)^0 )
+if not characters then
+ require("char-def")
+ require("char-ini")
+ require("char-ent")
+end
+
+local type, rawget = type, rawget
+local concat, insert, remove = table.concat, table.insert, table.remove
+local rep, gmatch, gsub, find = string.rep, string.gmatch, string.gsub, string.find
+local utfchar = utf.char
+
+local lpegmatch, patterns = lpeg.match, lpeg.patterns
+local S, P, R, C, V, Cc, Ct, Cs, Carg = lpeg.S, lpeg.P, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc, lpeg.Ct, lpeg.Cs, lpeg.Carg
+
+local sortedhash = table.sortedhash
+local sortedkeys = table.sortedkeys
+local formatters = string.formatters
+
+local entities = characters.entities or { }
+
+local xmltext = xml.text
+local xmlinclusion = xml.inclusion
+local xmlcollected = xml.collected
+
+-- todo: use private unicodes as temporary slots ... easier to compare
+
+local s_lparent = "\\left\\lparent"
+local s_lbrace = "\\left\\lbrace"
+local s_lbracket = "\\left\\lbracket"
+local s_langle = "\\left\\langle"
+local s_lfloor = "\\left\\lfloor"
+local s_lceil = "\\left\\lceil"
+local s_left = "\\left."
+
+local s_rparent = "\\right\\rparent"
+local s_rbrace = "\\right\\rbrace"
+local s_rbracket = "\\right\\rbracket"
+local s_rangle = "\\right\\rangle"
+local s_rfloor = "\\right\\rfloor"
+local s_rceil = "\\right\\rceil"
+local s_right = "\\right."
+
+local s_mslash = "\\middle/"
+
+local s_lbar = "\\left\\|"
+local s_mbar = "\\middle\\|"
+local s_rbar = "\\right\\|"
+
+local s_lnothing = "\\left ." -- space fools checker
+local s_rnothing = "\\right ." -- space fools checker
local reserved = {
- ["aleph"] = "\\aleph ",
- ["vdots"] = "\\vdots ",
- ["ddots"] = "\\ddots ",
- ["oint"] = "\\oint ",
- ["grad"] = "\\nabla ",
- ["prod"] = "\\prod ",
- ["prop"] = "\\propto ",
- ["sube"] = "\\subseteq ",
- ["supe"] = "\\supseteq ",
- ["sinh"] = "\\sinh ",
- ["cosh"] = "\\cosh ",
- ["tanh"] = "\\tanh ",
- ["sum"] = "\\sum ",
- ["vvv"] = "\\vee ",
- ["nnn"] = "\\cap ",
- ["uuu"] = "\\cup ",
- ["sub"] = "\\subset ",
- ["sup"] = "\\supset ",
- ["not"] = "\\lnot ",
- ["iff"] = "\\Leftrightarrow ",
- ["int"] = "\\int ",
- ["del"] = "\\partial ",
- ["and"] = "\\and ",
- ["not"] = "\\not ",
- ["sin"] = "\\sin ",
- ["cos"] = "\\cos ",
- ["tan"] = "\\tan ",
- ["csc"] = "\\csc ",
- ["sec"] = "\\sec ",
- ["cot"] = "\\cot ",
- ["log"] = "\\log ",
- ["det"] = "\\det ",
- ["lim"] = "\\lim ",
- ["mod"] = "\\mod ",
- ["gcd"] = "\\gcd ",
- ["lcm"] = "\\lcm ",
- ["min"] = "\\min ",
- ["max"] = "\\max ",
- ["xx"] = "\\times ",
- ["in"] = "\\in ",
- ["ox"] = "\\otimes ",
- ["vv"] = "\\vee ",
- ["nn"] = "\\cap ",
- ["uu"] = "\\cup ",
- ["oo"] = "\\infty ",
- ["ln"] = "\\ln ",
- ["or"] = "\\or ",
-
- ["AA"] = "\\forall ",
- ["EE"] = "\\exists ",
- ["TT"] = "\\top ",
- ["CC"] = "\\Bbb{C}",
- ["NN"] = "\\Bbb{N}",
- ["QQ"] = "\\Bbb{Q}",
- ["RR"] = "\\Bbb{R}",
- ["ZZ"] = "\\Bbb{Z}",
+
+ ["prod"] = { false, "\\prod" },
+ ["sinh"] = { false, "\\sinh" },
+ ["cosh"] = { false, "\\cosh" },
+ ["tanh"] = { false, "\\tanh" },
+ ["sum"] = { false, "\\sum" },
+ ["int"] = { false, "\\int" },
+ ["sin"] = { false, "\\sin" },
+ ["cos"] = { false, "\\cos" },
+ ["tan"] = { false, "\\tan" },
+ ["csc"] = { false, "\\csc" },
+ ["sec"] = { false, "\\sec" },
+ ["cot"] = { false, "\\cot" },
+ ["log"] = { false, "\\log" },
+ ["det"] = { false, "\\det" },
+ ["lim"] = { false, "\\lim" },
+ ["mod"] = { false, "\\mod" },
+ ["gcd"] = { false, "\\gcd" },
+ ["min"] = { false, "\\min" },
+ ["max"] = { false, "\\max" },
+ ["ln"] = { false, "\\ln" },
+
+ ["atan"] = { false, "\\atan" }, -- extra
+ ["acos"] = { false, "\\acos" }, -- extra
+ ["asin"] = { false, "\\asin" }, -- extra
+ -- extra
+ ["arctan"] = { false, "\\arctan" }, -- extra
+ ["arccos"] = { false, "\\arccos" }, -- extra
+ ["arcsin"] = { false, "\\arcsin" }, -- extra
+
+ ["and"] = { false, "\\text{and}" },
+ ["or"] = { false, "\\text{or}" },
+ ["if"] = { false, "\\text{if}" },
+
+ ["sqrt"] = { false, "\\asciimathsqrt", "unary" },
+ ["root"] = { false, "\\asciimathroot", "binary" },
+ ["frac"] = { false, "\\frac", "binary" },
+ ["stackrel"] = { false, "\\asciimathstackrel", "binary" },
+ ["hat"] = { false, "\\widehat", "unary" },
+ ["bar"] = { false, "\\overbar", "unary" },
+ ["overbar"] = { false, "\\overbar", "unary" },
+ ["underline"] = { false, "\\underline", "unary" },
+ ["vec"] = { false, "\\overrightarrow", "unary" },
+ ["dot"] = { false, "\\dot", "unary" }, -- 0x2D9
+ ["ddot"] = { false, "\\ddot", "unary" }, -- 0xA8
+
+ -- binary operators
+
+ ["+"] = { true, "+" },
+ ["-"] = { true, "-" },
+ ["*"] = { true, "⋅" },
+ ["**"] = { true, "⋆" },
+ ["//"] = { true, "⁄" }, -- \slash
+ ["\\"] = { true, "\\" },
+ ["xx"] = { true, "×" },
+ ["times"] = { true, "×" },
+ ["-:"] = { true, "÷" },
+ ["@"] = { true, "∘" },
+ ["o+"] = { true, "⊕" },
+ ["ox"] = { true, "⊗" },
+ ["o."] = { true, "⊙" },
+ ["^^"] = { true, "∧" },
+ ["vv"] = { true, "∨" },
+ ["nn"] = { true, "∩" },
+ ["uu"] = { true, "∪" },
+
+ -- big operators
+
+ ["^^^"] = { true, "⋀" },
+ ["vvv"] = { true, "⋁" },
+ ["nnn"] = { true, "⋂" },
+ ["uuu"] = { true, "⋃" },
+ ["int"] = { true, "∫" },
+ ["oint"] = { true, "∮" },
+
+ -- brackets
+
+ ["("] = { true, "(" },
+ [")"] = { true, ")" },
+ ["["] = { true, "[" },
+ ["]"] = { true, "]" },
+ ["{"] = { true, "{" },
+ ["}"] = { true, "}" },
+
+ -- binary relations
+
+ ["="] = { true, "=" },
+ ["eq"] = { true, "=" },
+ ["!="] = { true, "≠" },
+ ["ne"] = { true, "≠" },
+ ["neq"] = { true, "≠" },
+ ["<"] = { true, "<" },
+ ["lt"] = { true, "<" },
+ [">"] = { true, ">" },
+ ["gt"] = { true, ">" },
+ ["<="] = { true, "≤" },
+ ["le"] = { true, "≤" },
+ ["leq"] = { true, "≤" },
+ [">="] = { true, "≥" },
+ ["ge"] = { true, "≥" },
+ ["geq"] = { true, "≥" },
+ ["-<"] = { true, "≺" },
+ [">-"] = { true, "≻" },
+ ["in"] = { true, "∈" },
+ ["!in"] = { true, "∉" },
+ ["sub"] = { true, "⊂" },
+ ["sup"] = { true, "⊃" },
+ ["sube"] = { true, "⊆" },
+ ["supe"] = { true, "⊇" },
+ ["-="] = { true, "≡" },
+ ["~="] = { true, "≅" },
+ ["~~"] = { true, "≈" },
+ ["prop"] = { true, "∝" },
+
+ -- arrows
+
+ ["rarr"] = { true, "→" },
+ ["->"] = { true, "→" },
+ ["larr"] = { true, "←" },
+ ["harr"] = { true, "↔" },
+ ["uarr"] = { true, "↑" },
+ ["darr"] = { true, "↓" },
+ ["rArr"] = { true, "⇒" },
+ ["lArr"] = { true, "⇐" },
+ ["hArr"] = { true, "⇔" },
+ ["|->"] = { true, "↦" },
+
+ -- logical
+
+ ["not"] = { true, "¬" },
+ ["=>"] = { true, "⇒" },
+ ["iff"] = { true, "⇔" },
+ ["AA"] = { true, "∀" },
+ ["EE"] = { true, "∃" },
+ ["_|_"] = { true, "⊥" },
+ ["TT"] = { true, "⊤" },
+ ["|--"] = { true, "⊢" },
+ ["|=="] = { true, "⊨" },
+
+ -- miscellaneous
+
+ ["del"] = { true, "∂" },
+ ["grad"] = { true, "∇" },
+ ["+-"] = { true, "±" },
+ ["O/"] = { true, "∅" },
+ ["oo"] = { true, "∞" },
+ ["aleph"] = { true, "ℵ" },
+ ["angle"] = { true, "∠" },
+ ["/_"] = { true, "∠" },
+ [":."] = { true, "∴" },
+ ["..."] = { true, "..." }, -- ldots
+ ["ldots"] = { true, "..." }, -- ldots
+ ["cdots"] = { true, "⋯" },
+ ["vdots"] = { true, "⋮" },
+ ["ddots"] = { true, "⋱" },
+ ["diamond"] = { true, "⋄" },
+ ["square"] = { true, "□" },
+ ["|__"] = { true, "⌊" },
+ ["__|"] = { true, "⌋" },
+ ["|~"] = { true, "⌈" },
+ ["~|"] = { true, "⌉" },
+
+ -- more
+
+ ["_="] = { true, "≡" },
+
+ -- bonus
+
+ ["prime"] = { true, "′" }, -- bonus
+ ["'"] = { true, "′" }, -- bonus
+ ["''"] = { true, "″" }, -- bonus
+ ["'''"] = { true, "‴" }, -- bonus
+
+ -- special
+
+ ["%"] = { false, "\\mathpercent" },
+ ["&"] = { false, "\\mathampersand" },
+ ["#"] = { false, "\\mathhash" },
+ ["$"] = { false, "\\mathdollar" },
+
+ -- blackboard
+
+ ["CC"] = { true, "ℂ" },
+ ["NN"] = { true, "ℕ" },
+ ["QQ"] = { true, "ℚ" },
+ ["RR"] = { true, "ℝ" },
+ ["ZZ"] = { true, "ℤ" },
+
+ -- greek lowercase
+
+ ["alpha"] = { true, "α" },
+ ["beta"] = { true, "β" },
+ ["gamma"] = { true, "γ" },
+ ["delta"] = { true, "δ" },
+ ["epsilon"] = { true, "ε" },
+ ["varepsilon"] = { true, "ɛ" },
+ ["zeta"] = { true, "ζ" },
+ ["eta"] = { true, "η" },
+ ["theta"] = { true, "θ" },
+ ["vartheta"] = { true, "ϑ" },
+ ["iota"] = { true, "ι" },
+ ["kappa"] = { true, "κ" },
+ ["lambda"] = { true, "λ" },
+ ["mu"] = { true, "μ" },
+ ["nu"] = { true, "ν" },
+ ["xi"] = { true, "ξ" },
+ ["pi"] = { true, "π" },
+ ["rho"] = { true, "ρ" },
+ ["sigma"] = { true, "σ" },
+ ["tau"] = { true, "τ" },
+ ["upsilon"] = { true, "υ" },
+ ["phi"] = { true, "φ" },
+ ["varphi"] = { true, "ϕ" },
+ ["chi"] = { true, "χ" },
+ ["psi"] = { true, "ψ" },
+ ["omega"] = { true, "ω" },
+
+ -- greek uppercase
+
+ ["Gamma"] = { true, "Γ" },
+ ["Delta"] = { true, "Δ" },
+ ["Theta"] = { true, "Θ" },
+ ["Lambda"] = { true, "Λ" },
+ ["Xi"] = { true, "Ξ" },
+ ["Pi"] = { true, "Π" },
+ ["Sigma"] = { true, "Σ" },
+ ["Phi"] = { true, "Φ" },
+ ["Psi"] = { true, "Ψ" },
+ ["Omega"] = { true, "Ω" },
+
+ -- blackboard
+
+ ["bbb a"] = { true, "𝕒" },
+ ["bbb b"] = { true, "𝕓" },
+ ["bbb c"] = { true, "𝕔" },
+ ["bbb d"] = { true, "𝕕" },
+ ["bbb e"] = { true, "𝕖" },
+ ["bbb f"] = { true, "𝕗" },
+ ["bbb g"] = { true, "𝕘" },
+ ["bbb h"] = { true, "𝕙" },
+ ["bbb i"] = { true, "𝕚" },
+ ["bbb j"] = { true, "𝕛" },
+ ["bbb k"] = { true, "𝕜" },
+ ["bbb l"] = { true, "𝕝" },
+ ["bbb m"] = { true, "𝕞" },
+ ["bbb n"] = { true, "𝕟" },
+ ["bbb o"] = { true, "𝕠" },
+ ["bbb p"] = { true, "𝕡" },
+ ["bbb q"] = { true, "𝕢" },
+ ["bbb r"] = { true, "𝕣" },
+ ["bbb s"] = { true, "𝕤" },
+ ["bbb t"] = { true, "𝕥" },
+ ["bbb u"] = { true, "𝕦" },
+ ["bbb v"] = { true, "𝕧" },
+ ["bbb w"] = { true, "𝕨" },
+ ["bbb x"] = { true, "𝕩" },
+ ["bbb y"] = { true, "𝕪" },
+ ["bbb z"] = { true, "𝕫" },
+
+ ["bbb A"] = { true, "𝔸" },
+ ["bbb B"] = { true, "𝔹" },
+ ["bbb C"] = { true, "ℂ" },
+ ["bbb D"] = { true, "𝔻" },
+ ["bbb E"] = { true, "𝔼" },
+ ["bbb F"] = { true, "𝔽" },
+ ["bbb G"] = { true, "𝔾" },
+ ["bbb H"] = { true, "ℍ" },
+ ["bbb I"] = { true, "𝕀" },
+ ["bbb J"] = { true, "𝕁" },
+ ["bbb K"] = { true, "𝕂" },
+ ["bbb L"] = { true, "𝕃" },
+ ["bbb M"] = { true, "𝕄" },
+ ["bbb N"] = { true, "ℕ" },
+ ["bbb O"] = { true, "𝕆" },
+ ["bbb P"] = { true, "ℙ" },
+ ["bbb Q"] = { true, "ℚ" },
+ ["bbb R"] = { true, "ℝ" },
+ ["bbb S"] = { true, "𝕊" },
+ ["bbb T"] = { true, "𝕋" },
+ ["bbb U"] = { true, "𝕌" },
+ ["bbb V"] = { true, "𝕍" },
+ ["bbb W"] = { true, "𝕎" },
+ ["bbb X"] = { true, "𝕏" },
+ ["bbb Y"] = { true, "𝕐" },
+ ["bbb Z"] = { true, "ℤ" },
+
+ -- fraktur
+
+ ["fr a"] = { true, "𝔞" },
+ ["fr b"] = { true, "𝔟" },
+ ["fr c"] = { true, "𝔠" },
+ ["fr d"] = { true, "𝔡" },
+ ["fr e"] = { true, "𝔢" },
+ ["fr f"] = { true, "𝔣" },
+ ["fr g"] = { true, "𝔤" },
+ ["fr h"] = { true, "𝔥" },
+ ["fr i"] = { true, "𝔦" },
+ ["fr j"] = { true, "𝔧" },
+ ["fr k"] = { true, "𝔨" },
+ ["fr l"] = { true, "𝔩" },
+ ["fr m"] = { true, "𝔪" },
+ ["fr n"] = { true, "𝔫" },
+ ["fr o"] = { true, "𝔬" },
+ ["fr p"] = { true, "𝔭" },
+ ["fr q"] = { true, "𝔮" },
+ ["fr r"] = { true, "𝔯" },
+ ["fr s"] = { true, "𝔰" },
+ ["fr t"] = { true, "𝔱" },
+ ["fr u"] = { true, "𝔲" },
+ ["fr v"] = { true, "𝔳" },
+ ["fr w"] = { true, "𝔴" },
+ ["fr x"] = { true, "𝔵" },
+ ["fr y"] = { true, "𝔶" },
+ ["fr z"] = { true, "𝔷" },
+
+ ["fr A"] = { true, "𝔄" },
+ ["fr B"] = { true, "𝔅" },
+ ["fr C"] = { true, "ℭ" },
+ ["fr D"] = { true, "𝔇" },
+ ["fr E"] = { true, "𝔈" },
+ ["fr F"] = { true, "𝔉" },
+ ["fr G"] = { true, "𝔊" },
+ ["fr H"] = { true, "ℌ" },
+ ["fr I"] = { true, "ℑ" },
+ ["fr J"] = { true, "𝔍" },
+ ["fr K"] = { true, "𝔎" },
+ ["fr L"] = { true, "𝔏" },
+ ["fr M"] = { true, "𝔐" },
+ ["fr N"] = { true, "𝔑" },
+ ["fr O"] = { true, "𝔒" },
+ ["fr P"] = { true, "𝔓" },
+ ["fr Q"] = { true, "𝔔" },
+ ["fr R"] = { true, "ℜ" },
+ ["fr S"] = { true, "𝔖" },
+ ["fr T"] = { true, "𝔗" },
+ ["fr U"] = { true, "𝔘" },
+ ["fr V"] = { true, "𝔙" },
+ ["fr W"] = { true, "𝔚" },
+ ["fr X"] = { true, "𝔛" },
+ ["fr Y"] = { true, "𝔜" },
+ ["fr Z"] = { true, "ℨ" },
+
+ -- script
+
+ ["cc a"] = { true, "𝒶" },
+ ["cc b"] = { true, "𝒷" },
+ ["cc c"] = { true, "𝒸" },
+ ["cc d"] = { true, "𝒹" },
+ ["cc e"] = { true, "ℯ" },
+ ["cc f"] = { true, "𝒻" },
+ ["cc g"] = { true, "ℊ" },
+ ["cc h"] = { true, "𝒽" },
+ ["cc i"] = { true, "𝒾" },
+ ["cc j"] = { true, "𝒿" },
+ ["cc k"] = { true, "𝓀" },
+ ["cc l"] = { true, "𝓁" },
+ ["cc m"] = { true, "𝓂" },
+ ["cc n"] = { true, "𝓃" },
+ ["cc o"] = { true, "ℴ" },
+ ["cc p"] = { true, "𝓅" },
+ ["cc q"] = { true, "𝓆" },
+ ["cc r"] = { true, "𝓇" },
+ ["cc s"] = { true, "𝓈" },
+ ["cc t"] = { true, "𝓉" },
+ ["cc u"] = { true, "𝓊" },
+ ["cc v"] = { true, "𝓋" },
+ ["cc w"] = { true, "𝓌" },
+ ["cc x"] = { true, "𝓍" },
+ ["cc y"] = { true, "𝓎" },
+ ["cc z"] = { true, "𝓏" },
+
+ ["cc A"] = { true, "𝒜" },
+ ["cc B"] = { true, "ℬ" },
+ ["cc C"] = { true, "𝒞" },
+ ["cc D"] = { true, "𝒟" },
+ ["cc E"] = { true, "ℰ" },
+ ["cc F"] = { true, "ℱ" },
+ ["cc G"] = { true, "𝒢" },
+ ["cc H"] = { true, "ℋ" },
+ ["cc I"] = { true, "ℐ" },
+ ["cc J"] = { true, "𝒥" },
+ ["cc K"] = { true, "𝒦" },
+ ["cc L"] = { true, "ℒ" },
+ ["cc M"] = { true, "ℳ" },
+ ["cc N"] = { true, "𝒩" },
+ ["cc O"] = { true, "𝒪" },
+ ["cc P"] = { true, "𝒫" },
+ ["cc Q"] = { true, "𝒬" },
+ ["cc R"] = { true, "ℛ" },
+ ["cc S"] = { true, "𝒮" },
+ ["cc T"] = { true, "𝒯" },
+ ["cc U"] = { true, "𝒰" },
+ ["cc V"] = { true, "𝒱" },
+ ["cc W"] = { true, "𝒲" },
+ ["cc X"] = { true, "𝒳" },
+ ["cc Y"] = { true, "𝒴" },
+ ["cc Z"] = { true, "𝒵" },
+
+ -- bold
+
+ ["bb a"] = { true, "𝒂" },
+ ["bb b"] = { true, "𝒃" },
+ ["bb c"] = { true, "𝒄" },
+ ["bb d"] = { true, "𝒅" },
+ ["bb e"] = { true, "𝒆" },
+ ["bb f"] = { true, "𝒇" },
+ ["bb g"] = { true, "𝒈" },
+ ["bb h"] = { true, "𝒉" },
+ ["bb i"] = { true, "𝒊" },
+ ["bb j"] = { true, "𝒋" },
+ ["bb k"] = { true, "𝒌" },
+ ["bb l"] = { true, "𝒍" },
+ ["bb m"] = { true, "𝒎" },
+ ["bb n"] = { true, "𝒏" },
+ ["bb o"] = { true, "𝒐" },
+ ["bb p"] = { true, "𝒑" },
+ ["bb q"] = { true, "𝒒" },
+ ["bb r"] = { true, "𝒓" },
+ ["bb s"] = { true, "𝒔" },
+ ["bb t"] = { true, "𝒕" },
+ ["bb u"] = { true, "𝒖" },
+ ["bb v"] = { true, "𝒗" },
+ ["bb w"] = { true, "𝒘" },
+ ["bb x"] = { true, "𝒙" },
+ ["bb y"] = { true, "𝒚" },
+ ["bb z"] = { true, "𝒛" },
+
+ ["bb A"] = { true, "𝑨" },
+ ["bb B"] = { true, "𝑩" },
+ ["bb C"] = { true, "𝑪" },
+ ["bb D"] = { true, "𝑫" },
+ ["bb E"] = { true, "𝑬" },
+ ["bb F"] = { true, "𝑭" },
+ ["bb G"] = { true, "𝑮" },
+ ["bb H"] = { true, "𝑯" },
+ ["bb I"] = { true, "𝑰" },
+ ["bb J"] = { true, "𝑱" },
+ ["bb K"] = { true, "𝑲" },
+ ["bb L"] = { true, "𝑳" },
+ ["bb M"] = { true, "𝑴" },
+ ["bb N"] = { true, "𝑵" },
+ ["bb O"] = { true, "𝑶" },
+ ["bb P"] = { true, "𝑷" },
+ ["bb Q"] = { true, "𝑸" },
+ ["bb R"] = { true, "𝑹" },
+ ["bb S"] = { true, "𝑺" },
+ ["bb T"] = { true, "𝑻" },
+ ["bb U"] = { true, "𝑼" },
+ ["bb V"] = { true, "𝑽" },
+ ["bb W"] = { true, "𝑾" },
+ ["bb X"] = { true, "𝑿" },
+ ["bb Y"] = { true, "𝒀" },
+ ["bb Z"] = { true, "𝒁" },
+
+ -- sans
+
+ ["sf a"] = { true, "𝖺" },
+ ["sf b"] = { true, "𝖻" },
+ ["sf c"] = { true, "𝖼" },
+ ["sf d"] = { true, "𝖽" },
+ ["sf e"] = { true, "𝖾" },
+ ["sf f"] = { true, "𝖿" },
+ ["sf g"] = { true, "𝗀" },
+ ["sf h"] = { true, "𝗁" },
+ ["sf i"] = { true, "𝗂" },
+ ["sf j"] = { true, "𝗃" },
+ ["sf k"] = { true, "𝗄" },
+ ["sf l"] = { true, "𝗅" },
+ ["sf m"] = { true, "𝗆" },
+ ["sf n"] = { true, "𝗇" },
+ ["sf o"] = { true, "𝗈" },
+ ["sf p"] = { true, "𝗉" },
+ ["sf q"] = { true, "𝗊" },
+ ["sf r"] = { true, "𝗋" },
+ ["sf s"] = { true, "𝗌" },
+ ["sf t"] = { true, "𝗍" },
+ ["sf u"] = { true, "𝗎" },
+ ["sf v"] = { true, "𝗏" },
+ ["sf w"] = { true, "𝗐" },
+ ["sf x"] = { true, "𝗑" },
+ ["sf y"] = { true, "𝗒" },
+ ["sf z"] = { true, "𝗓" },
+
+ ["sf A"] = { true, "𝖠" },
+ ["sf B"] = { true, "𝖡" },
+ ["sf C"] = { true, "𝖢" },
+ ["sf D"] = { true, "𝖣" },
+ ["sf E"] = { true, "𝖤" },
+ ["sf F"] = { true, "𝖥" },
+ ["sf G"] = { true, "𝖦" },
+ ["sf H"] = { true, "𝖧" },
+ ["sf I"] = { true, "𝖨" },
+ ["sf J"] = { true, "𝖩" },
+ ["sf K"] = { true, "𝖪" },
+ ["sf L"] = { true, "𝖫" },
+ ["sf M"] = { true, "𝖬" },
+ ["sf N"] = { true, "𝖭" },
+ ["sf O"] = { true, "𝖮" },
+ ["sf P"] = { true, "𝖯" },
+ ["sf Q"] = { true, "𝖰" },
+ ["sf R"] = { true, "𝖱" },
+ ["sf S"] = { true, "𝖲" },
+ ["sf T"] = { true, "𝖳" },
+ ["sf U"] = { true, "𝖴" },
+ ["sf V"] = { true, "𝖵" },
+ ["sf W"] = { true, "𝖶" },
+ ["sf X"] = { true, "𝖷" },
+ ["sf Y"] = { true, "𝖸" },
+ ["sf Z"] = { true, "𝖹" },
+
+ -- monospace
+
+ ["tt a"] = { true, "𝚊" },
+ ["tt b"] = { true, "𝚋" },
+ ["tt c"] = { true, "𝚌" },
+ ["tt d"] = { true, "𝚍" },
+ ["tt e"] = { true, "𝚎" },
+ ["tt f"] = { true, "𝚏" },
+ ["tt g"] = { true, "𝚐" },
+ ["tt h"] = { true, "𝚑" },
+ ["tt i"] = { true, "𝚒" },
+ ["tt j"] = { true, "𝚓" },
+ ["tt k"] = { true, "𝚔" },
+ ["tt l"] = { true, "𝚕" },
+ ["tt m"] = { true, "𝚖" },
+ ["tt n"] = { true, "𝚗" },
+ ["tt o"] = { true, "𝚘" },
+ ["tt p"] = { true, "𝚙" },
+ ["tt q"] = { true, "𝚚" },
+ ["tt r"] = { true, "𝚛" },
+ ["tt s"] = { true, "𝚜" },
+ ["tt t"] = { true, "𝚝" },
+ ["tt u"] = { true, "𝚞" },
+ ["tt v"] = { true, "𝚟" },
+ ["tt w"] = { true, "𝚠" },
+ ["tt x"] = { true, "𝚡" },
+ ["tt y"] = { true, "𝚢" },
+ ["tt z"] = { true, "𝚣" },
+
+ ["tt A"] = { true, "𝙰" },
+ ["tt B"] = { true, "𝙱" },
+ ["tt C"] = { true, "𝙲" },
+ ["tt D"] = { true, "𝙳" },
+ ["tt E"] = { true, "𝙴" },
+ ["tt F"] = { true, "𝙵" },
+ ["tt G"] = { true, "𝙶" },
+ ["tt H"] = { true, "𝙷" },
+ ["tt I"] = { true, "𝙸" },
+ ["tt J"] = { true, "𝙹" },
+ ["tt K"] = { true, "𝙺" },
+ ["tt L"] = { true, "𝙻" },
+ ["tt M"] = { true, "𝙼" },
+ ["tt N"] = { true, "𝙽" },
+ ["tt O"] = { true, "𝙾" },
+ ["tt P"] = { true, "𝙿" },
+ ["tt Q"] = { true, "𝚀" },
+ ["tt R"] = { true, "𝚁" },
+ ["tt S"] = { true, "𝚂" },
+ ["tt T"] = { true, "𝚃" },
+ ["tt U"] = { true, "𝚄" },
+ ["tt V"] = { true, "𝚅" },
+ ["tt W"] = { true, "𝚆" },
+ ["tt X"] = { true, "𝚇" },
+ ["tt Y"] = { true, "𝚈" },
+ ["tt Z"] = { true, "𝚉" },
+
+ -- some more undocumented
+
+ ["dx"] = { false, { "d", "x" } }, -- "{dx}" "\\left(dx\\right)"
+ ["dy"] = { false, { "d", "y" } }, -- "{dy}" "\\left(dy\\right)"
+ ["dz"] = { false, { "d", "z" } }, -- "{dz}" "\\left(dz\\right)"
+
+ -- fences
+
+ ["(:"] = { true, "(:" },
+ ["{:"] = { true, "{:" },
+ ["[:"] = { true, "[:" },
+ ["("] = { true, "(" },
+ ["["] = { true, "[" },
+ ["{"] = { true, "{" },
+ ["<<"] = { true, "⟨" }, -- why not <:
+ ["|_"] = { true, "⌊" },
+ ["|~"] = { true, "⌈" },
+ ["⟨"] = { true, "⟨" },
+ ["〈"] = { true, "⟨" },
+ ["〈"] = { true, "⟨" },
+
+ [":)"] = { true, ":)" },
+ [":}"] = { true, ":}" },
+ [":]"] = { true, ":]" },
+ [")"] = { true, ")" },
+ ["]"] = { true, "]" },
+ ["}"] = { true, "}" },
+ [">>"] = { true, "⟩" }, -- why not :>
+ ["~|"] = { true, "⌉" },
+ ["_|"] = { true, "⌋" },
+ ["⟩"] = { true, "⟩" },
+ ["〉"] = { true, "⟩" },
+ ["〉"] = { true, "⟩" },
+
+ ["lparent"] = { true, "(" },
+ ["lbracket"] = { true, "[" },
+ ["lbrace"] = { true, "{" },
+ ["langle"] = { true, "⟨" },
+ ["lfloor"] = { true, "⌊" },
+ ["lceil"] = { true, "⌈" },
+
+ ["rparent"] = { true, ")" },
+ ["rbracket"] = { true, "]" },
+ ["rbrace"] = { true, "}" },
+ ["rangle"] = { true, "⟩" },
+ ["rfloor"] = { true, "⌋" },
+ ["rceil"] = { true, "⌉" },
+
+ -- a bit special:
+
+ ["\\frac"] = { true, "frac" },
}
-table.setmetatableindex(reserved,characters.entities)
+local isbinary = {
+ ["\\frac"] = true,
+ ["\\root"] = true,
+ ["\\asciimathroot"] = true,
+ ["\\asciimathstackrel"] = true,
+}
-local postmapper = Cs ( (
+local isunary = {
+ ["\\sqrt"] = true,
+ ["\\asciimathsqrt"] = true,
+ ["\\text"] = true, -- mathoptext
+ ["\\mathoptext"] = true, -- mathoptext
+ ["\\asciimathoptext"] = true, -- mathoptext
+ ["\\hat"] = true, -- widehat
+ ["\\widehat"] = true, -- widehat
+ ["\\bar"] = true, --
+ ["\\overbar"] = true, --
+ ["\\underline"] = true, --
+ ["\\vec"] = true, -- overrightarrow
+ ["\\overrightarrow"] = true, -- overrightarrow
+ ["\\dot"] = true, --
+ ["\\ddot"] = true, --
- P("\\mathoptext ") * spaces * (P("\\bgroup ")/"{") * (1-P("\\egroup "))^1 * (P("\\egroup ")/"}") +
+}
- (P("\\bgroup ")) / "{" +
- (P("\\egroup ")) / "}" +
+local isfunny = {
+ ["\\sin"] = true,
+}
- P("\\") * (R("az","AZ")^2) +
+local isinfix = {
+ ["^"] = true,
+ ["_"] = true,
+}
- (R("AZ","az")^2) / reserved +
+local isleft = {
+ [s_lparent] = true,
+ [s_lbrace] = true,
+ [s_lbracket] = true,
+ [s_langle] = true,
+ [s_lfloor] = true,
+ [s_lceil] = true,
+ [s_left] = true,
+}
- P("{:") / "\\left." +
- P(":}") / "\\right." +
- P("(") / "\\left(" +
- P(")") / "\\right)" +
- P("[") / "\\left[" +
- P("]") / "\\right]" +
- P("{") / "\\left\\{" +
- P("}") / "\\right\\}" +
+local isright = {
+ [s_rparent] = true,
+ [s_rbrace] = true,
+ [s_rbracket] = true,
+ [s_rangle] = true,
+ [s_rfloor] = true,
+ [s_rceil] = true,
+ [s_right] = true,
+}
- letter + P(1)
+local issimplified = {
+}
+
+--
+
+-- special mess
+
+local d_one = R("09")
+local d_two = d_one * d_one
+local d_three = d_two * d_one
+local d_four = d_three * d_one
+local d_split = P(-1) + P(",")
+
+local d_spaced = (Carg(1) * d_three)^1
+
+local digitized_1 = Cs ( (
+ d_three * d_spaced * d_split +
+ d_two * d_spaced * d_split +
+ d_one * d_spaced * d_split +
+ P(1)
+ )^1 )
+
+local p_fourbefore = d_four * d_split
+local p_fourafter = d_four * P(-1)
+
+local p_beforecomma = d_three * d_spaced * d_split
+ + d_two * d_spaced * d_split
+ + d_one * d_spaced * d_split
+ + d_one * d_split
+
+local p_aftercomma = p_fourafter
+ + d_three * d_spaced
+ + d_two * d_spaced
+ + d_one * d_spaced
+
+local digitized_2 = Cs (
+ p_fourbefore * (p_aftercomma^0) +
+ p_beforecomma * ((p_aftercomma + d_one^1)^0)
+ )
+
+local p_fourbefore = d_four * d_split
+local p_fourafter = d_four
+local d_spaced = (Carg(1) * (d_three + d_two + d_one))^1
+local p_aftercomma = p_fourafter * P(-1)
+ + d_three * d_spaced * P(1)^0
+ + d_one^1
+
+-- local digitized_3 = Cs (
+-- p_fourbefore * p_aftercomma^0 +
+-- p_beforecomma * p_aftercomma^0
+-- )
+
+local digitized_3 = Cs((p_fourbefore + p_beforecomma) * p_aftercomma^0)
+
+local splitmethods = {
+ digitized_1,
+ digitized_2,
+ digitized_3,
+}
+
+local splitmethod = nil
+
+function asciimath.setup(settings)
+ splitmethod = splitmethods[tonumber(settings.splitmethod) or 0]
+ if splitmethod then
+ local separator = settings.separator
+ if separator == true or not interfaces or interfaces.variables.yes then
+ digitseparator = utfchar(0x2008)
+ elseif type(separator) == "string" and separator ~= "" then
+ digitseparator = separator
+ else
+ splitmethod = nil
+ end
+ end
+end
+
+local collected_digits = { }
+local collected_filename = "asciimath-digits.lua"
+
+function numbermess(s)
+ if splitmethod then
+ local d = lpegmatch(splitmethod,s,1,digitseparator)
+ if d then
+ if trace_digits and s ~= d then
+ collected_digits[s] = d
+ end
+ return d
+ end
+ end
+ return s
+end
+
+-- asciimath.setup { splitmethod = 3 }
+-- local t = {
+-- "1", "12", "123", "1234", "12345", "123456", "1234567", "12345678", "123456789",
+-- "1,1",
+-- "12,12",
+-- "123,123",
+-- "1234,123",
+-- "1234,1234",
+-- "12345,1234",
+-- "1234,12345",
+-- "12345,12345",
+-- "123456,123456",
+-- "1234567,1234567",
+-- "12345678,12345678",
+-- "123456789,123456789",
+-- "0,1234",
+-- "1234,0",
+-- "1234,00",
+-- "0,123456789",
+-- }
+-- for i=1,#t do print(formatters["%-20s : [%s]"](t[i],numbermess(t[i]))) end
+
+statistics.register("asciimath",function()
+ if trace_digits then
+ local n = table.count(collected_digits)
+ if n > 0 then
+ table.save(collected_filename,collected_digits)
+ return string.format("%s digit conversions saved in %s",n,collected_filename)
+ else
+ os.remove(collected_filename)
+ end
+ end
+end)
+
+local p_number_base = patterns.cpnumber or patterns.cnumber or patterns.number
+local p_number = C(p_number_base)
+----- p_number = p_number_base
+local p_spaces = patterns.whitespace
+
+local p_utf_base = patterns.utf8character
+local p_utf = C(p_utf_base)
+local p_entity = (P("&") * C((1-P(";"))^2) * P(";"))/ entities
+
+entities["gt"] = ">"
+entities["lt"] = "<"
+entities["amp"] = "&"
+entities["dquot"] = '"'
+entities["quot"] = "'"
+
+local p_onechar = p_utf_base * P(-1)
+
+----- p_number = Cs((patterns.cpnumber or patterns.cnumber or patterns.number)/function(s) return (gsub(s,",","{,}")) end)
+
+local sign = P("-")^-1
+local digits = R("09")^1
+local integer = sign * digits
+local real = digits * (S(".") * digits)^-1
+local float = real * (P("E") * integer)^-1
+
+-- local number = C(float + integer)
+-- local p_number = C(float)
+local p_number = float / numbermess
+
+local k_reserved = sortedkeys(reserved)
+local k_commands = { }
+local k_unicode = { }
+
+asciimath.keys = {
+ reserved = k_reserved
+}
+
+local k_reserved_different = { }
+local k_reserved_words = { }
+
+for k, v in sortedhash(reserved) do
+ local replacement = v[2]
+ if v[1] then
+ k_unicode[k] = replacement
+ else
+ k_unicode[k] = k -- keep them ... later we remap these
+ if k ~= replacement then
+ k_reserved_different[#k_reserved_different+1] = k
+ end
+ end
+
+for k, v in next, entities do
+ k_unicode[k] = v
+ k_unicode["\\"..k] = v
+end
+
+if not find(k,"[^[a-zA-Z]+$]") then
+ k_unicode["\\"..k] = k -- dirty trick, no real unicode
+end
+
+ if not find(k,"[^a-zA-Z]") then
+ k_reserved_words[#k_reserved_words+1] = k
+ end
+ k_commands[k] = replacement
+end
+
+local p_reserved =
+ lpeg.utfchartabletopattern(k_reserved_different) / k_commands
+
+local p_unicode =
+ lpeg.utfchartabletopattern(table.keys(k_unicode)) / k_unicode
+
+local p_texescape = patterns.texescape
+
+local function texescaped(s)
+ return lpegmatch(p_texescape,s)
+end
+
+local p_text =
+ P("text")
+ * p_spaces^0
+ * Cc("\\asciimathoptext")
+ * ( -- maybe balanced
+ Cs( P("{") * ((1-P("}"))^0/texescaped) * P("}") )
+ + Cs((P("(")/"{") * ((1-P(")"))^0/texescaped) * (P(")")/"}"))
+ )
+ + Cc("\\asciimathoptext") * Cs(Cc("{") * (patterns.undouble/texescaped) * Cc("}"))
+
+local m_left = {
+ ["(:"] = s_langle,
+ ["{:"] = s_left,
+ ["[:"] = s_left,
+ ["("] = s_lparent,
+ ["["] = s_lbracket,
+ ["{"] = s_lbrace,
+ ["⟨"] = s_langle,
+ ["⌈"] = s_lceil,
+ ["⌊"] = s_lfloor,
+
+ -- ["<<"] = s_langle, -- why not <:
+ -- ["|_"] = s_lfloor,
+ -- ["|~"] = s_lceil,
+ -- ["〈"] = s_langle,
+ -- ["〈"] = s_langle,
+
+ -- ["lparent"] = s_lparent,
+ -- ["lbracket"] = s_lbracket,
+ -- ["lbrace"] = s_lbrace,
+ -- ["langle"] = s_langle,
+ -- ["lfloor"] = s_lfloor,
+ -- ["lceil"] = s_lceil,
+}
+
+local m_right = {
+ [":)"] = s_rangle,
+ [":}"] = s_right,
+ [":]"] = s_right,
+ [")"] = s_rparent,
+ ["]"] = s_rbracket,
+ ["}"] = s_rbrace,
+ ["⟩"] = s_rangle,
+ ["⌉"] = s_rceil,
+ ["⌋"] = s_rfloor,
+
+ -- [">>"] = s_rangle, -- why not :>
+ -- ["~|"] = s_rceil,
+ -- ["_|"] = s_rfloor,
+ -- ["〉"] = s_rangle,
+ -- ["〉"] = s_rangle,
+
+ -- ["rparent"] = s_rparent,
+ -- ["rbracket"] = s_rbracket,
+ -- ["rbrace"] = s_rbrace,
+ -- ["rangle"] = s_rangle,
+ -- ["rfloor"] = s_rfloor,
+ -- ["rceil"] = s_rceil,
+}
+
+local islimits = {
+ ["\\sum"] = true,
+ -- ["∑"] = true,
+ ["\\prod"] = true,
+ -- ["∏"] = true,
+ ["\\lim"] = true,
+}
+
+local p_left =
+ lpeg.utfchartabletopattern(m_left) / m_left
+local p_right =
+ lpeg.utfchartabletopattern(m_right) / m_right
+
+-- special cases
+
+-- local p_special =
+-- C("/")
+-- + P("\\ ") * Cc("{}") * p_spaces^0 * C(S("^_"))
+-- + P("\\ ") * Cc("\\space")
+-- + P("\\\\") * Cc("\\backslash")
+-- + P("\\") * (R("az","AZ")^1/entities)
+-- + P("|") * Cc("\\|")
+--
+-- faster bug also uglier:
+
+local p_special =
+ P("|") * Cc("\\|") -- s_mbar -- maybe always add left / right as in mml ?
+ + P("\\") * (
+ (
+ P(" ") * (
+ Cc("{}") * p_spaces^0 * C(S("^_"))
+ + Cc("\\space")
+ )
+ )
+ + P("\\") * Cc("\\backslash")
+ -- + (R("az","AZ")^1/entities)
+ + C(R("az","AZ")^1)
+ )
+
+-- open | close :: {: | :}
+
+local e_parser = Cs ( (
+ p_entity +
+ p_utf_base
)^0 )
-local parser
-local function converted(original,totex)
- local ok, result
- if trace_mapping then
- report_asciimath("original : %s",original)
+local u_parser = Cs ( (
+ patterns.doublequoted +
+ P("text") * p_spaces^0 * P("(") * (1-P(")"))^0 * P(")") + -- -- todo: balanced
+ p_unicode +
+ p_utf_base
+)^0 )
+
+local a_parser = Ct { "tokenizer",
+ tokenizer = (
+ p_spaces
+ + p_number
+ + p_text
+ -- + Ct(p_open * V("tokenizer") * p_close) -- {: (a+b,=,1),(a+b,=,7) :}
+ -- + Ct(p_open * V("tokenizer") * p_close_right) -- { (a+b,=,1),(a+b,=,7) :}
+ -- + Ct(p_open_left * V("tokenizer") * p_right) -- {: (a+b,=,1),(a+b,=,7) }
+ + Ct(p_left * V("tokenizer") * p_right) -- { (a+b,=,1),(a+b,=,7) }
+ + p_special
+ + p_reserved
+ -- + p_utf - p_close - p_right
+ + (p_utf - p_right)
+ )^1,
+}
+
+local collapse = nil
+local serialize = table.serialize
+local f_state = formatters["level %s : %s : intermediate"]
+
+local function show_state(t,level,state)
+ report_asciimath(serialize(t,f_state(level,state)))
+end
+
+local function show_result(original,entified,unicoded,texcoded)
+ report_asciimath("original > %s",original)
+ report_asciimath("entified > %s",entified)
+ report_asciimath("unicoded > %s",unicoded)
+ report_asciimath("texcoded > %s",texcoded)
+end
+
+local function collapse_matrices(t)
+ local n = #t
+ if n > 4 and t[3] == "," then
+ local l1 = t[1]
+ local r1 = t[n]
+ if isleft[l1] and isright[r1] then
+ local l2 = t[2]
+ local r2 = t[n-1]
+ if type(l2) == "table" and type(r2) == "table" then
+ -- we have a matrix
+ local valid = true
+ for i=3,n-2,2 do
+ if t[i] ~= "," then
+ valid = false
+ break
+ end
+ end
+ if valid then
+ for i=2,n-1,2 do
+ local ti = t[i]
+ local tl = ti[1]
+ local tr = ti[#ti]
+ if isleft[tl] and isright[tr] then
+ -- ok
+ else
+ valid = false
+ break
+ end
+ end
+ if valid then
+ local omit = l1 == s_left and r1 == s_right
+ if omit then
+ t[1] = "\\startmatrix"
+ else
+ t[1] = l1 .. "\\startmatrix"
+ end
+ for i=2,n-1 do
+ if t[i] == "," then
+ t[i] = "\\NR"
+ else
+ local ti = t[i]
+ ti[1] = "\\NC"
+ for i=2,#ti-1 do
+ if ti[i] == "," then
+ ti[i] = "\\NC"
+ end
+ end
+ ti[#ti] = nil
+ end
+ end
+ if omit then
+ t[n] = "\\NR\\stopmatrix"
+ else
+ t[n] = "\\NR\\stopmatrix" .. r1
+ end
+ end
+ end
+ end
+ end
end
- local premapped = lpegmatch(premapper,original)
- if premapped then
- if trace_mapping then
- report_asciimath("prepared : %s",premapped)
+ return t
+end
+
+local function collapse_bars(t)
+ local n, i, l, m = #t, 1, false, 0
+ while i <= n do
+ local current = t[i]
+ if current == "\\|" then
+ if l then
+ m = m + 1
+ t[l] = s_lbar
+ t[i] = s_rbar
+ t[m] = { unpack(t,l,i) }
+ l = false
+ else
+ l = i
+ end
+ elseif not l then
+ m = m + 1
+ t[m] = current
end
- local parsed = lpegmatch(parser,premapped)
- if parsed then
- if trace_mapping then
- report_asciimath("parsed : %s",parsed)
+ i = i + 1
+ end
+ if l then
+ local tt = { s_lnothing } -- space fools final checker
+ local tm = 1
+ for i=1,m do
+ tm = tm + 1
+ tt[tm] = t[i]
+ end
+ tm = tm + 1
+ tt[tm] = s_mbar
+ for i=l+1,n do
+ tm = tm + 1
+ tt[tm] = t[i]
+ end
+ tm = tm + 1
+ tt[tm] = s_rnothing -- space fools final checker
+ m = tm
+ t = tt
+ elseif m < n then
+ for i=n,m+1,-1 do
+ t[i] = nil
+ end
+ end
+ return t
+end
+
+local function collapse_pairs(t)
+ local n, i = #t, 1
+ while i < n do
+ local current = t[i]
+ if current == "/" and i > 1 then
+ local tl = t[i-1]
+ local tr = t[i+1]
+ local tn = t[i+2]
+ if type(tl) == "table" then
+ if isleft[tl[1]] and isright[tl[#tl]] then
+ tl[1] = "" -- todo: remove
+ tl[#tl] = nil
+ end
end
- local postmapped = lpegmatch(postmapper,parsed)
- if postmapped then
- if trace_mapping then
- report_asciimath("finalized: %s",postmapped)
+ if type(tr) == "table" then
+ if tn == "^" then
+ -- brr 1/(1+x)^2
+ elseif isleft[tr[1]] and isright[tr[#tr]] then
+ tr[1] = "" -- todo: remove
+ tr[#tr] = nil
end
- result, ok = postmapped, true
+ end
+ i = i + 2
+ elseif current == "," or current == ";" then
+ -- t[i] = current .. "\\thinspace" -- look sbad in (a,b)
+ i = i + 1
+ else
+ i = i + 1
+ end
+ end
+ return t
+end
+
+local function collapse_parentheses(t)
+ local n, i = #t, 1
+ if n > 2 then
+ while i < n do
+ local current = t[i]
+ if type(current) == "table" and isleft[t[i-1]] and isright[t[i+1]] then
+ local c = #current
+ if c > 2 and isleft[current[1]] and isright[current[c]] then
+ remove(current,c)
+ remove(current,1)
+ end
+ i = i + 3
else
- result = "error in postmapping"
+ i = i + 1
+ end
+ end
+ end
+ return t
+end
+
+local function collapse_signs(t)
+ local n, m, i = #t, 0, 1
+ while i <= n do
+ m = m + 1
+ local current = t[i]
+ if isunary[current] then
+ local one = t[i+1]
+ if not one then
+ m = m + 1
+ t[m] = current .. "{}" -- error
+ break
+ end
+ if type(one) == "table" then
+ if isleft[one[1]] and isright[one[#one]] then
+ remove(one,#one)
+ remove(one,1)
+ end
+ one = collapse(one,level)
+ elseif one == "-" and i + 2 <= n then -- or another sign ? or unary ?
+ local t2 = t[i+2]
+ if type(t2) == "string" then
+ one = one .. t2
+ i = i + 1
+ end
+ end
+ t[m] = current .. "{" .. one .. "}"
+ i = i + 2
+ elseif i + 2 <= n and isfunny[current] then
+ local one = t[i+1]
+ if isinfix[one] then
+ local two = t[i+2]
+ if two == "-" then -- or another sign ? or unary ?
+ local three = t[i+3]
+ if three then
+ if type(three) == "table" then
+ three = collapse(three,level)
+ end
+ t[m] = current .. one .. "{" .. two .. three .. "}"
+ i = i + 4
+ else
+ t[m] = current
+ i = i + 1
+ end
+ else
+ t[m] = current
+ i = i + 1
+ end
+ else
+ t[m] = current
+ i = i + 1
end
else
- result = "error in mapping"
+ t[m] = current
+ i = i + 1
end
+ end
+ if i == n then -- yes?
+ m = m + 1
+ t[m] = t[n]
+ end
+ if m < n then
+ for i=n,m+1,-1 do
+ t[i] = nil
+ end
+ end
+ return t
+end
+
+local function collapse_binaries(t)
+ local n, m, i = #t, 0, 1
+ while i <= n do
+ m = m + 1
+ local current = t[i]
+ if isbinary[current] then
+ local one = t[i+1]
+ local two = t[i+2]
+ if not one then
+ t[m] = current .. "{}{}" -- error
+ break
+ end
+ if type(one) == "table" then
+ if isleft[one[1]] and isright[one[#one]] then
+ remove(one,#one)
+ remove(one,1)
+ end
+ one = collapse(one,level)
+ end
+ if not two then
+ t[m] = current .. "{" .. one .. "}{}"
+ break
+ end
+ if type(two) == "table" then
+ if isleft[two[1]] and isright[two[#two]] then
+ remove(two,#two)
+ remove(two,1)
+ end
+ two = collapse(two,level)
+ end
+ t[m] = current .. "{" .. one .. "}{" .. two .. "}"
+ i = i + 3
+ else
+ t[m] = current
+ i = i + 1
+ end
+ end
+ if i == n then -- yes?
+ m = m + 1
+ t[m] = t[n]
+ end
+ if m < n then
+ for i=n,m+1,-1 do
+ t[i] = nil
+ end
+ end
+ return t
+end
+
+local function collapse_infixes_1(t)
+ local n, i = #t, 1
+ while i <= n do
+ local current = t[i]
+ if isinfix[current] then
+ local what = t[i+1]
+ if what then
+ if type(what) == "table" then
+ local f, l = what[1], what[#what]
+ if isleft[f] and isright[l] then
+ remove(what,#what)
+ remove(what,1)
+ end
+ t[i+1] = collapse(what,level) -- collapse ?
+ end
+ i = i + 2
+ else
+ break
+ end
+ else
+ i = i + 1
+ end
+ end
+ return t
+end
+
+function collapse_limits(t)
+ local n, m, i = #t, 0, 1
+ while i <= n do
+ m = m + 1
+ local current = t[i]
+ if islimits[current] then
+ local one, two, first, second = nil, nil, t[i+1], t[i+3]
+ if first and isinfix[first] then
+ one = t[i+2]
+ if one then
+ -- if type(one) == "table" then
+ -- if isleft[one[1]] and isright[one[#one]] then
+ -- remove(one,#one)
+ -- remove(one,1)
+ -- end
+ -- one = collapse(one,level)
+ -- end
+ if second and isinfix[second] then
+ two = t[i+4]
+ -- if type(two) == "table" then
+ -- if isleft[two[1]] and isright[two[#two]] then
+ -- remove(two,#two)
+ -- remove(two,1)
+ -- end
+ -- two = collapse(two,level)
+ -- end
+ end
+ if two then
+ t[m] = current .. "\\limits" .. first .. "{" .. one .. "}" .. second .. "{" .. two .. "}"
+ i = i + 5
+ else
+ t[m] = current .. "\\limits" .. first .. "{" .. one .. "}"
+ i = i + 3
+ end
+ else
+ t[m] = current
+ i = i + 1
+ end
+ else
+ t[m] = current
+ i = i + 1
+ end
+ else
+ t[m] = current
+ i = i + 1
+ end
+ end
+ if i == n then -- yes?
+ m = m + 1
+ t[m] = t[n]
+ end
+ if m < n then
+ for i=n,m+1,-1 do
+ t[i] = nil
+ end
+ end
+ return t
+end
+
+local function collapse_tables(t)
+ local n, m, i = #t, 0, 1
+ while i <= n do
+ m = m + 1
+ local current = t[i]
+ if type(current) == "table" then
+ if current[1] == "\\NC" then
+ t[m] = collapse(current,level)
+ else
+ t[m] = "{" .. collapse(current,level) .. "}"
+ end
+ i = i + 1
+ else
+ t[m] = current
+ i = i + 1
+ end
+ end
+ if i == n then -- yes?
+ m = m + 1
+ t[m] = t[n]
+ end
+ if m < n then
+ for i=n,m+1,-1 do
+ t[i] = nil
+ end
+ end
+ return t
+end
+
+local function collapse_infixes_2(t)
+ local n, m, i = #t, 0, 1
+ while i < n do
+ local current = t[i]
+ if isinfix[current] and i > 1 then
+ local tl = t[i-1]
+ local tr = t[i+1]
+ local ti = t[i+2]
+ local tn = t[i+3]
+ if ti and tn and isinfix[ti] then
+ t[m] = tl .. current .. "{" .. tr .. "}" .. ti .. "{" .. tn .. "}"
+ i = i + 4
+ else
+ t[m] = tl .. current .. "{" .. tr .. "}"
+ i = i + 2
+ end
+ else
+ m = m + 1
+ t[m] = current
+ i = i + 1
+ end
+ end
+ if i == n then
+ m = m + 1
+ t[m] = t[n]
+ end
+ if m < n then
+ for i=n,m+1,-1 do
+ t[i] = nil
+ end
+ end
+ return t
+end
+
+local function collapse_fractions_1(t)
+ local n, m, i = #t, 0, 1
+ while i < n do
+ local current = t[i]
+ if current == "/" and i > 1 then
+ local tl = t[i-1]
+ local tr = t[i+1]
+ t[m] = "\\frac{" .. tl .. "}{" .. tr .. "}"
+ i = i + 2
+ if i < n then
+ m = m + 1
+ t[m] = t[i]
+ i = i + 1
+ end
+ else
+ m = m + 1
+ t[m] = current
+ i = i + 1
+ end
+ end
+ if i == n then
+ m = m + 1
+ t[m] = t[n]
+ end
+ if m < n then
+ for i=n,m+1,-1 do
+ t[i] = nil
+ end
+ end
+ return t
+end
+
+local function collapse_fractions_2(t)
+ local n, m, i = #t, 0, 1
+ while i < n do
+ local current = t[i]
+ if current == "⁄" and i > 1 then -- \slash
+ t[m] = "{" .. s_left .. t[i-1] .. s_mslash .. t[i+1] .. s_right .. "}"
+ i = i + 2
+ if i < n then
+ m = m + 1
+ t[m] = t[i]
+ i = i + 1
+ end
+ else
+ m = m + 1
+ t[m] = current
+ i = i + 1
+ end
+ end
+ if i == n then
+ m = m + 1
+ t[m] = t[n]
+ end
+ if m < n then
+ for i=n,m+1,-1 do
+ t[i] = nil
+ end
+ end
+ return t
+end
+
+local function collapse_result(t)
+ local n = #t
+ if t[1] == s_left and t[n] == s_right then -- see bar .. space needed there
+ return concat(t," ",2,n-1)
else
- result = "error in premapping"
+ return concat(t," ")
end
- if totex then
- if ok then
- context.mathematics(result)
+end
+
+collapse = function(t,level)
+ -- check
+ if not t then
+ return ""
+ end
+ -- tracing
+ if trace_detail then
+ if level then
+ level = level + 1
else
- context.type(result) -- some day monospaced
+ level = 1
+ end
+ show_state(t,level,"parsed")
+ end
+ -- steps
+ t = collapse_matrices (t) if trace_detail then show_state(t,level,"matrices") end
+ t = collapse_bars (t) if trace_detail then show_state(t,level,"bars") end
+ t = collapse_pairs (t) if trace_detail then show_state(t,level,"pairs") end
+ t = collapse_parentheses(t) if trace_detail then show_state(t,level,"parentheses") end
+ t = collapse_signs (t) if trace_detail then show_state(t,level,"signs") end
+ t = collapse_binaries (t) if trace_detail then show_state(t,level,"binaries") end
+ t = collapse_infixes_1 (t) if trace_detail then show_state(t,level,"infixes (1)") end
+ t = collapse_limits (t) if trace_detail then show_state(t,level,"limits") end
+ t = collapse_tables (t) if trace_detail then show_state(t,level,"tables") end
+ t = collapse_infixes_2 (t) if trace_detail then show_state(t,level,"infixes (2)") end
+ t = collapse_fractions_1(t) if trace_detail then show_state(t,level,"fractions (1)") end
+ t = collapse_fractions_2(t) if trace_detail then show_state(t,level,"fractions (2)") end
+ -- done
+ return collapse_result(t)
+end
+
+-- todo: cache simple ones, say #str < 10, maybe weak
+
+local context = context
+local ctx_mathematics = context and context.mathematics or report_asciimath
+local ctx_type = context and context.type or function() end
+local ctx_inleft = context and context.inleft or function() end
+
+local function convert(str,totex)
+ local entified = lpegmatch(e_parser,str) or str -- when used in text
+ local unicoded = lpegmatch(u_parser,entified) or entified
+ local texcoded = collapse(lpegmatch(a_parser,unicoded))
+ if trace_mapping then
+ show_result(str,entified,unicoded,texcoded)
+ end
+ if totex then
+ ctx_mathematics(texcoded)
+ else
+ return texcoded
+ end
+end
+
+local n = 0
+local p = (
+ (S("{[(") + P("\\left" )) / function() n = n + 1 end
+ + (S("}])") + P("\\right")) / function() n = n - 1 end
+ + p_utf_base
+)^0
+
+local function invalidtex(str)
+ n = 0
+ lpegmatch(p,str)
+ if n == 0 then
+ return false
+ elseif n < 0 then
+ return formatters["too many left fences: %s"](-n)
+ elseif n > 0 then
+ return formatters["not enough right fences: %s"](n)
+ end
+end
+
+local collected = { }
+local indexed = { }
+
+-- bonus
+
+local p_reserved_spaced =
+ C(lpeg.utfchartabletopattern(k_reserved_words)) / " %1 "
+
+local p_text =
+ C(P("text")) / " %1 "
+ * p_spaces^0
+ * ( -- maybe balanced
+ (P("{") * (1-P("}"))^0 * P("}"))
+ + (P("(") * (1-P(")"))^0 * P(")"))
+ )
+ + patterns.doublequoted
+
+local p_expand = Cs((p_text + p_reserved_spaced + p_utf_base)^0)
+local p_compress = patterns.collapser
+
+local function cleanedup(str)
+ return lpegmatch(p_compress,lpegmatch(p_expand,str)) or str
+end
+
+-- so far
+
+local function register(s,cleanedup,collected,shortname)
+ local c = cleanedup(s)
+ local f = collected[c]
+ if f then
+ f.count = f.count + 1
+ f.files[shortname] = (f.files[shortname] or 0) + 1
+ if s ~= c then
+ f.cleanedup = f.cleanedup + 1
+ end
+ f.dirty[s] = (f.dirty[s] or 0) + 1
+ else
+ local texcoded = convert(s)
+ local message = invalidtex(texcoded)
+ if message then
+ report_asciimath("%s: %s : %s",message,s,texcoded)
end
+ collected[c] = {
+ count = 1,
+ files = { [shortname] = 1 },
+ texcoded = texcoded,
+ message = message,
+ cleanedup = s ~= c and 1 or 0,
+ dirty = { [s] = 1 }
+ }
+ end
+end
+
+local function wrapup(collected,indexed)
+ local n = 0
+ for k, v in sortedhash(collected) do
+ n = n + 1
+ v.n= n
+ indexed[n] = k
+ end
+end
+
+function collect(fpattern,element,collected,indexed)
+ local element = element or "am"
+ local mpattern = formatters["<%s>(.-)%s>"](element,element)
+ local filenames = resolvers.findtexfile(fpattern)
+ if filenames and filenames ~= "" then
+ filenames = { filenames }
else
- return result
- end
-end
-
-local function onlyconverted(str)
- local parsed = lpegmatch(parser,str)
- return parsed or str
-end
-
-local sqrt = P("sqrt") / "\\rootradical \\bgroup \\egroup "
-local root = P("root") / "\\rootradical "
-local frac = P("frac") / "\\frac "
-local stackrel = P("stackrel") / "\\stackrel "
-local text = P("text") / "\\mathoptext "
-local hat = P("hat") / "\\widehat "
-local overbar = P("bar") / "\\overbar "
-local underline = P("ul") / "\\underline "
-local vec = P("vec") / "\\overrightarrow "
-local dot = P("dot") / "\\dot "
-local ddot = P("ddot") / "\\ddot "
-
-local left = P("(:") + P("{:") + P("(") + P("[") + P("{")
-local right = P(":)") + P(":}") + P(")") + P("]") + P("}")
-local leftnorright = 1 - left - right
-local singles = sqrt + text + hat + underline + overbar + vec + ddot + dot
-local doubles = root + frac + stackrel
-local ignoreleft = (left/"") * spaces * spaces
-local ignoreright = spaces * (right/"") * spaces
-local ignoreslash = spaces * (P("/")/"") * spaces
-local comma = P(",")
-local nocomma = 1-comma
-local anychar = P(1)
-local openmatrix = left * spaces * Cc("\\matrix\\bgroup ")
-local closematrix = Cc("\\egroup ") * spaces * right
-local nextcolumn = spaces * (comma/"&") * spaces
-local nextrow = spaces * (comma/"\\cr ") * spaces
-local finishrow = Cc("\\cr ")
-local opengroup = left/"\\bgroup "
-local closegroup = right/"\\egroup "
-local somescript = S("^_") * spaces
-local beginargument = Cc("\\bgroup ")
-local endargument = Cc("\\egroup ")
-
-parser = Cs { "main",
-
- scripts = somescript * V("argument"),
- division = Cc("\\frac") * V("argument") * spaces * ignoreslash * spaces * V("argument"),
- double = doubles * spaces * V("argument") * spaces * V("argument"),
- single = singles * spaces * V("argument"),
-
- balanced = opengroup * (C((leftnorright + V("balanced"))^0)/onlyconverted) * closegroup,
- argument = V("balanced") + V("token"),
-
- element = (V("step") + (V("argument") + V("step")) - ignoreright - nextcolumn - comma)^1,
- commalist = ignoreleft * V("element") * (nextcolumn * spaces * V("element"))^0 * ignoreright,
- matrix = openmatrix * spaces * (V("commalist") * (nextrow * V("commalist"))^0) * finishrow * closematrix,
-
- token = beginargument * (texnic + float + real + number + letter) * endargument,
-
- step = V("scripts") + V("division") + V("single") + V("double"),
- main = (V("matrix") + V("step") + anychar)^0,
+ filenames = dir.glob(fpattern)
+ end
+ local cfpattern = gsub(fpattern,"^%./",lfs.currentdir())
+ local cfpattern = gsub(cfpattern,"\\","/")
+ local wildcard = string.split(cfpattern,"*")[1]
+ if not collected then
+ collected = { }
+ indexed = { }
+ end
+ for i=1,#filenames do
+ filename = gsub(filenames[i],"\\","/")
+ local splitname = (wildcard and wildcard ~= "" and string.split(filename,wildcard)[2]) or filename
+ local shortname = gsub(splitname or file.basename(filename),"^%./","")
+ if shortname == "" then
+ shortname = filename
+ end
+ local fullname = resolvers.findtexfile(filename) or filename
+ if fullname ~= "" then
+ for s in gmatch(io.loaddata(fullname),mpattern) do
+ register(s,cleanedup,collected,shortname)
+ end
+ end
+ end
+ wrapup(collected,indexed)
+ return collected, indexed
+end
+
+function filter(root,pattern,collected,indexed)
+ if not pattern or pattern == "" then
+ pattern = "am"
+ end
+ if not collected then
+ collected = { }
+ indexed = { }
+ end
+ for c in xmlcollected(root,pattern) do
+ register(xmltext(c),cleanedup,collected,xmlinclusion(c) or "" )
+ end
+ wrapup(collected,indexed)
+ return collected, indexed
+end
+
+asciimath.convert = convert
+asciimath.reserved = reserved
+asciimath.collect = collect
+asciimath.filter = filter
+asciimath.invalidtex = invalidtex
+asciimath.cleanedup = cleanedup
+-- sin(x) = 1 : 3.3 uncached 1.2 cached , so no real gain (better optimize the converter then)
+
+local function convert(str)
+ if #str > 0 then
+ local entified = lpegmatch(e_parser,str) or str -- when used in text
+ local unicoded = lpegmatch(u_parser,entified) or entified
+ if lpegmatch(p_onechar,unicoded) then
+ ctx_mathematics(unicoded)
+ else
+ local texcoded = collapse(lpegmatch(a_parser,unicoded))
+ if trace_mapping then
+ show_result(str,entified,unicoded,texcoded)
+ end
+ if #texcoded == 0 then
+ report_asciimath("error in asciimath: %s",str)
+ else
+ local message = invalidtex(texcoded)
+ if message then
+ report_asciimath("%s: %s : %s",message,str,texcoded)
+ ctx_type(formatters["<%s>"](message))
+ else
+ ctx_mathematics(texcoded)
+ end
+ end
+ end
+ end
+end
+
+local context = context
+
+if not context then
+
+-- trace_mapping = true
+-- trace_detail = true
+
+-- report_asciimath(cleanedup([[ac+sinx+xsqrtx+sinsqrtx+sinsqrt(x)]]))
+-- report_asciimath(cleanedup([[a "αsinsqrtx" b]]))
+-- report_asciimath(cleanedup([[a "α" b]]))
+-- report_asciimath(cleanedup([[//4]]))
+
+-- convert("\\frac{a}{b}")
+-- convert("frac{a}{b}")
+-- convert("\\sin{a}{b}")
+-- convert("sin{a}{b}")
+-- convert("1: rightarrow")
+-- convert("2: \\rightarrow")
+
+-- convert("((1,2,3),(4,5,6),(7,8,9))")
+
+-- convert("1/(t+x)^2")
+
+-- convert("AA a > 0 ^^ b > 0 | {:log_g:} a + {:log_g:} b")
+-- convert("AA a > 0 ^^ b > 0 | {:log_g:} a + {:log_g:} b")
+
+-- convert("10000,00001")
+-- convert("4/18*100text(%)~~22,2")
+-- convert("4/18*100text(%)≈22,2")
+-- convert("62541/(197,6)≈316,05")
+
+-- convert([[sum x]])
+-- convert([[sum^(1)_(2) x]])
+-- convert([[lim_(1)^(2) x]])
+-- convert([[lim_(1) x]])
+-- convert([[lim^(2) x]])
+
+-- convert([[{: rangle]])
+-- convert([[\langle\larr]])
+-- convert([[langlelarr]])
+-- convert([[D_f=[0 ,→〉]])
+-- convert([[ac+sinx+xsqrtx]])
+-- convert([[ac+\alpha x+xsqrtx-cc b*pi**psi-3alephx / bb X]])
+-- convert([[ac+\ ^ x+xsqrtx]])
+-- convert([[d/dx(x^2+1)]])
+-- convert([[a "αsinsqrtx" b]])
+-- convert([[a "α" b]])
+-- convert([[//4]])
+-- convert([[ {(a+b,=,1),(a+b,=,7)) ]])
+
+-- convert([[ 2/a // 5/b = (2 b) / ( a b) // ( 5 a ) / ( a b ) = (2 b ) / ( 5 a ) ]])
+-- convert([[ (2+x)/a // 5/b ]])
+
+-- convert([[ ( 2/a ) // ( 5/b ) = ( (2 b) / ( a b) ) // ( ( 5 a ) / ( a b ) ) = (2 b ) / ( 5 a ) ]])
+
+-- convert([[ (x/y)^3 = x^3/y^3 ]])
+
+-- convert([[ {: (1,2) :} ]])
+-- convert([[ {: (a+b,=,1),(a+b,=,7) :} ]])
+-- convert([[ { (a+b,=,1),(a+b,=,7) :} ]])
+-- convert([[ {: (a+b,=,1),(a+b,=,7) } ]])
+-- convert([[ { (a+b,=,1),(a+b,=,7) } ]])
+
+-- convert([[(1,5 ±sqrt(1,25 ),0 )]])
+-- convert([[1//2]])
+-- convert([[(p)/sqrt(p)]])
+-- convert([[u_tot]])
+-- convert([[u_tot=4,4 L+0,054 T]])
+
+-- convert([[ [←;0,2] ]])
+-- convert([[ [←;0,2⟩ ]])
+-- convert([[ ⟨←;0,2 ) ]])
+-- convert([[ ⟨←;0,2 ] ]])
+-- convert([[ ⟨←;0,2⟩ ]])
+
+-- convert([[ x^2(x-1/16)=0 ]])
+-- convert([[ y = ax + 3 - 3a ]])
+-- convert([[ y= ((1/4)) ^x ]])
+-- convert([[ x=\ ^ (1/4) log(0 ,002 )= log(0,002) / (log(1/4) ]])
+-- convert([[ x=\ ^glog(y) ]])
+-- convert([[ x^ (-1 1/2) =1/x^ (1 1/2)=1/ (x^1*x^ (1/2)) =1/ (xsqrt(x)) ]])
+-- convert([[ x^2(10 -x)>2 x^2 ]])
+-- convert([[ x^4>x ]])
+
+ return
+
+end
+
+interfaces.implement {
+ name = "asciimath", -- module_asciimath_convert
+ actions = convert,
+ arguments = "string"
}
-asciimath.reserved = reserved
-asciimath.convert = converted
+local ctx_typebuffer = context.typebuffer
+local ctx_mathematics = context.mathematics
+local ctx_color = context.color
+
+local sequenced = table.sequenced
+local assign_buffer = buffers.assign
+
+local show = { }
+asciimath.show = show
+
+local collected, indexed, ignored = { }, { }, { }
+
+local color = { "darkred" }
+
+function show.ignore(n)
+ if type(n) == "string" then
+ local c = collected[n]
+ n = c and c.n
+ end
+ if n then
+ ignored[n] = true
+ end
+end
+
+function show.count(n,showcleanedup)
+ local v = collected[indexed[n]]
+ local count = v.count
+ local cleanedup = v.cleanedup
+ if not showcleanedup or cleanedup == 0 then
+ context(count)
+ elseif count == cleanedup then
+ ctx_color(color,count)
+ else
+ context("%s+",count-cleanedup)
+ ctx_color(color,cleanedup)
+ end
+end
+
+local h = { }
+local am = { "am" }
+
+function show.nofdirty(n)
+ local k = indexed[n]
+ local v = collected[k]
+ local n = v.cleanedup
+ h = { }
+ if n > 0 then
+ for d, n in sortedhash(v.dirty) do
+ if d ~= k then
+ h[#h+1] = { d, n }
+ end
+ end
+ end
+ context(#h)
+end
+
+function show.dirty(m,wrapped)
+ local d = h[m]
+ if d then
+ ctx_inleft(d[2])
+ if wrapped then
+ assign_buffer("am",'"' .. d[1] .. '"')
+ else
+ assign_buffer("am",d[1])
+ end
+ ctx_typebuffer(am)
+ end
+end
+
+function show.files(n)
+ context(sequenced(collected[indexed[n]].files," "))
+end
-commands.convert = converted
+function show.input(n,wrapped)
+ if wrapped then
+ assign_buffer("am",'"' .. indexed[n] .. '"')
+ else
+ assign_buffer("am",indexed[n])
+ end
+ ctx_typebuffer(am)
+end
+
+function show.result(n)
+ local v = collected[indexed[n]]
+ if ignored[n] then
+ context("ignored")
+ elseif v.message then
+ ctx_color(color, v.message)
+ else
+ ctx_mathematics(v.texcoded)
+ end
+end
+
+function show.load(str,element)
+ collected, indexed, ignored = { }, { }, { }
+ local t = utilities.parsers.settings_to_array(str)
+ for i=1,#t do
+ asciimath.collect(t[i],element or "am",collected,indexed)
+ end
+end
+
+function show.filter(id,element)
+ collected, indexed, ignored = { }, { }, { }
+ asciimath.filter(lxml.getid(id),element or "am",collected,indexed)
+end
+
+function show.max()
+ context(#indexed)
+end
+
+function show.statistics()
+ local usedfiles = { }
+ local noffiles = 0
+ local nofokay = 0
+ local nofbad = 0
+ local nofcleanedup = 0
+ for k, v in next, collected do
+ if ignored[v.n] then
+ nofbad = nofbad + v.count
+ elseif v.message then
+ nofbad = nofbad + v.count
+ else
+ nofokay = nofokay + v.count
+ end
+ nofcleanedup = nofcleanedup + v.cleanedup
+ for k, v in next, v.files do
+ local u = usedfiles[k]
+ if u then
+ usedfiles[k] = u + 1
+ else
+ noffiles = noffiles + 1
+ usedfiles[k] = 1
+ end
+ end
+ end
+ local NC = context.NC
+ local NR = context.NR
+ local EQ = context.EQ
+ context.starttabulate { "|B||" }
+ NC() context("files") EQ() context(noffiles) NC() NR()
+ NC() context("formulas") EQ() context(nofokay+nofbad) NC() NR()
+ NC() context("uniques") EQ() context(#indexed) NC() NR()
+ NC() context("cleanedup") EQ() context(nofcleanedup) NC() NR()
+ NC() context("errors") EQ() context(nofbad) NC() NR()
+ context.stoptabulate()
+end
+
+function show.save(name)
+ table.save(name ~= "" and name or "dummy.lua",collected)
+end
diff --git a/Master/texmf-dist/tex/context/base/x-asciimath.mkiv b/Master/texmf-dist/tex/context/base/x-asciimath.mkiv
index fd385671a50..cc98b54acca 100644
--- a/Master/texmf-dist/tex/context/base/x-asciimath.mkiv
+++ b/Master/texmf-dist/tex/context/base/x-asciimath.mkiv
@@ -1,6 +1,6 @@
%D \module
-%D [ file=m-asciimath,
-%D version=2006.04.24, % 1999.11.06,
+%D [ file=x-asciimath,
+%D version=2014.06.01, % 2006.04.24, % 1999.11.06,
%D title=\CONTEXT\ Modules,
%D subtitle=AsciiMath,
%D author=Hans Hagen,
@@ -11,90 +11,371 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D Lua code.
-
\registerctxluafile{x-asciimath}{}
-\def\ctxmoduleasciimath#1{\ctxlua{moduledata.asciimath.#1}}
-
-%D The following code is not officially supported and is only meant
-%D for the Math4All project.
+%D When the Math4All project started, we immediately started using content \MATHML.
+%D Because in school math there is often a reference to calculator input, we also
+%D provided what we called \quote {calcmath}: a predictable expression based way
+%D entering math. At some point \OPENMATH\ was also used but that was later
+%D abandoned because editing is more cumbersome.
+%D
+%D Due to limitations in the web variant (which is independent of rendering for
+%D paper but often determines the coding of document, not seldom for the worse) the
+%D switch was made to presentational \MATHML. But even that proved to be too complex
+%D for rendering on the web, so it got converted to so called \ASCIIMATH\ which
+%D can be rendered using some \JAVASCRIPT\ magic. However, all the formulas (and
+%D we're talking of tens of thousands of them) were very precisely coded by the main
+%D author. Because in intermediate stages of the editing (by additional authors) a
+%D mixture of \MATHML\ and \ASCIIMATH\ was used, we wrote the first version of this
+%D module. As reference we took \url
+%D {http://www1.chapman.edu/~jipsen/mathml/asciimath.html} and. The idea was to
+%D stick to \MATHML\ as reference and if needed use \ASCIIMATH\ as annotation.
%D
-%D The following code kind of maps ascii math
-%D http://www1.chapman.edu/~jipsen/mathml/asciimath.html onto \TEX. The
-%D code was written for the math4all project but in retrospect we
-%D could have used just tex code as the web version can handle that
-%D as well. Anyhow, as we use \MATHML\ as basis it makes sense to add
-%D this to the repertoire as annotation variant, so now we have
-%D content \MATHML\ (prefered), presentation \MATHML\ (often messy),
-%D \OPENMATH\ (what was which we started with in this project)
-%D calcmath (handy for students who are accustomed to calculators),
-%D asciimath (to make Frits's live easier) and of course \TEX. Of
-%D course all are used mixed.
+%D Eventually we ended up with supporting several math encodings in \CONTEXT\ that
+%D could be used mixed: content \MATHML\ (preferred), presentation \MATHML\ (often
+%D messy), \OPENMATH\ (somewhat minimalistic) calcmath (handy for students who are
+%D accustomed to calculators), \ASCIIMATH\ (to make web support easier) and of
+%D course \TEX.
%D
-%D We don't support all quirks of asciimath as I am not in the mood to
-%D write a complex parser while a bit of sane coding can work as well.
+%D The first version had some limitations as we didn't want to support all quirks of
+%D \ASCIIMATH\ and also because I was not really in the mood to write a complex parser
+%D when a bit of sane coding can work equally well. Some comments from that version:
%D
+%D \startnarrower
%D \startitemize
-%D \item We support only the syntactically clear variants and as long
-%D as lpeg does not support left recursion this is as far as we
-%D want to go.
-%D \item The parser is rather insensitive for spaces but yet the advice is
-%D to avoid weird coding like \type {d/dxf(x)} but use \type {d/dx
-%D f(x)} instead. After all we're not in a compact coding cq.\
-%D parser challenge.
-%D \item We also don't support the somewhat confusing \type {sqrt sqrt 2}
-%D nor \type {root3x} (although the second one kind of works). A bit
-%D of defensive coding does not hurt.
-%D \item We can process \type {a/b/c/d} but it's not compatible with the
-%D default behaviour of asciimath. Use grouping instead. Yes, we do
-%D support the somewhat nonstandard grouping token mix.
-%D \item You should use explicit \type {text(..)} directives as one can
-%D never be sure what is a reserved word and not.
+%D \item We support only the syntactically clear variants and as long as lpeg does
+%D not support left recursion this is as far as we want to go.
+%D \item The parser is rather insensitive for spaces but yet the advice is to avoid
+%D weird coding like \type {d/dxf(x)} but use \type {d/dx f(x)} instead. After
+%D all we're not in a compact coding cq.\ parser challenge.
+%D \item We also don't support the somewhat confusing \type {sqrt sqrt 2} nor \type
+%D {root3x} (although the second one kind of works). A bit of defensive coding
+%D does not hurt.
+%D \item We can process \type {a/b/c/d} but it's not compatible with the default
+%D behaviour of \ASCIIMATH. Use grouping instead. Yes, we do support the somewhat
+%D nonstandard grouping token mix.
+%D \item You should use explicit \type {text(..)} directives as one can never be sure
+%D what is a reserved word and not.
%D \stopitemize
%D
-%D Actually, as the only parsing sensitive elements of \TEX\ are
-%D fractions (\type {\over} and friends, a restricted use of \TEX\
-%D coding is probably as comprehensive and parseble.
-%D
-%D The webpage with examples served as starting point so anything beyond
+%D Actually, as the only parsing sensitive elements of \TEX\ are fractions (\type {\over}
+%D and friends, a restricted use of \TEX\ coding is probably as comprehensive and
+%D parsable. The webpage with examples served as starting point so anything beyond
%D what can be found there isn't supported.
+%D \stopnarrower
+%D
+%D Then in 2014 something bad happened. Following the fashion of minimal encoding
+%D (which of course means messy encoding of complex cases and which can make authors
+%D sloppy too) the web based support workflow of the mentioned project ran into some
+%D limitations and magically one day all carefully coded \MATHML\ was converted into
+%D \ASCIIMATH. As there was no way to recover the original thousands of files and
+%D tens of thousands of formulas we were suddenly stuck with \ASCIIMATH. Because the
+%D conversion had be done automagically, we also saw numerous errors and were forced
+%D to come up with some methods to check formulas. Because \MATHML\ poses some
+%D restrictions it has predictable rendering; \ASCIIMATH\ on the other hand enforces
+%D no structure. Also, because \MATHML\ has to be valid \XML\ it always processes.
+%D Of course, during the decade that the project had run we also had to built in
+%D some catches for abuse but at least we had a relatively stable and configurable
+%D subsystem. So, in order to deal with less predictable cases as well as extensive
+%D checking, a new \ASCIIMATH\ parser was written, one that could also be used to
+%D trace bad coding.
+%D
+%D Because the formal description is incomplete, and because some links to resources
+%D are broken, and because some testing on the web showed that sequences of characters
+%D are interpreted that were not mentioned anywhere (visible), and because we noticed
+%D that the parser was dangerously tolerant, the new code is quite different from the
+%D old code.
+%D
+%D One need to keep in mind that because spaces are optional, the only robust way to
+%D edit \ASCIIMATH\ is to use a \WYSIWYG\ editor and hope that the parser doesn't
+%D change ever. Keys are picked up from spaceless sequences and when not recognized
+%D a (sequence) of characters is considered to be variables. So, \type {xsqrtx} is
+%D valid and renders as \type {$x\sqrt{x}$}, \type {xx} becomes \type {×} (times)
+%D but \type {ac} becomes \type {$a c$} (a times c). We're lucky that \type {AC} is
+%D not turned into Alternating Current, but who knows what happens a few years from
+%D now. So, we do support this spaceless mess, but users are warned: best use a
+%D spacy sequence. The extra amount of spaces (at one byte each) an author has to
+%D include in his|/|her active writing time probably stays below the size of one
+%D holiday picture. Another complication is that numbers (in Dutch) use commas instead
+%D of periods, but vectors use commas as well. We also hav esome different names for
+%D functions which then can conflict with the expectations about collapsed variables.
+%D
+%D It must be noted that simplified encodings (that seem to be the fashion today)
+%D can demand from applications to apply fuzzy logic to make something work out
+%D well. Because we have sequential data that gets rendered, sometimes wrong input
+%D gets obscured simply by the rendering: like the comma's in numbers as well as
+%D for separators (depending on space usage), or plain wrong symbols that somehow
+%D get a representation anyway. This in itself is more a side effect of trying to
+%D use the simplified encoding without applying rules (in the input) or to use it
+%D beyong its intended usage, which then of course can lead to adapted parsers and
+%D catches that themselves trigger further abuse. Imagine that instead of developing
+%D new cars, planes, space ships, mobile phones, computers we would have adapted
+%D horse cars, kites, firework, old fashioned phones and mechanical calculators in a
+%D similar way: patch upon patch of traditional means for sure would not have
+%D worked. So, when you use \ASCIIMATH\ best check immediately how it gets rendered
+%D in the browser as well as on paper. And be prepared to check the more complex
+%D code in the future again. We don't offer any guarantees but of course will try to
+%D keep up.
+%D
+%D In retrospect I sometimes wonder if the energy put into constantly adapting to
+%D the fashion of the day pays off. Probably not. It definitely doesn't pay of.
+%D
+%D More complex crap:
+%D
+%D 1: $x + \stackrel{comment}{\stackrel{\utfchar{"23DE}}{yyyyyyyy}} = y$ \blank
+%D 2: \asciimath{x + stackrel{\utfchar{"23DE}}{yyyyyyyy} = y} \blank
+%D 3: \asciimath{x + stackrel{yyyyyyyy}{\utfchar{"23DE}} = y} \blank
+%D 4: \asciimath{x + stackrel{"comment"}{stackrel{\utfchar{"23DE}}{yyyyyyyy}} = y} \blank
+
+\usemodule[mathml-basics]
+
+\startmodule[asciimath]
\unprotect
\writestatus{asciimath}{beware, this is an experimental (m4all only) module}
-%unexpanded\def\asciimath#1{\ctxmoduleasciimath{convert(\!!bs\detokenize{#1}\!!es,true)}}
-\unexpanded\def\asciimath#1{\ctxcommand{convert(\!!bs\detokenize\expandafter{\normalexpanded{#1}}\!!es,true)}}
+%D Hacks:
+
+\unexpanded\def\asciimathoptext #1{\ifmmode\mathoptext{#1}\else#1\fi}
+\unexpanded\def\asciimathoptexttraced #1{\ifmmode\mathoptext{\color[darkgreen]{#1}}\else\color[darkgreen]{#1}\fi}
+\unexpanded\def\asciimathstackrel #1#2{\mathematics{\mathop{\let\limits\relax\mover{#2}{#1}}}}
+\unexpanded\def\asciimathroot #1#2{\sqrt[#1]{#2}}
+\unexpanded\def\asciimathsqrt #1{\sqrt{#1}}
+
+%D The core commands:
+
+% if we need to set
+
+\installsetuponlycommandhandler {asciimath} {asciimath}
+
+\appendtoks
+ \ctxlua{moduledata.asciimath.setup {
+ splitmethod = "\asciimathparameter\c!splitmethod",
+ separator = "\asciimathparameter\c!separator",
+ }}%
+\to \everysetupasciimath
+
+\unexpanded\def\asciimath#1%
+ {\clf_asciimath{\detokenize\expandafter{\normalexpanded{#1}}}}
+
+\unexpanded\def\ctxmoduleasciimath#1%
+ {\ctxlua{moduledata.asciimath.#1}}
+
+%D Some tracing commands. Using tex commands is 10\% slower that directly piping
+%D from \LUA, but this is non|-|critical code.
+
+\unexpanded\def\ShowAsciiMathLoad [#1]{\ctxlua{moduledata.asciimath.show.load("#1")}}
+\unexpanded\def\ShowAsciiMathIgnore[#1]{\ctxlua{moduledata.asciimath.show.ignore("#1")}}
+\unexpanded\def\ShowAsciiMathXML #1#2{\ctxlua{moduledata.asciimath.show.filter("#1","#2")}}
+\unexpanded\def\ShowAsciiMathStats {\ctxlua{moduledata.asciimath.show.statistics()}}
+\unexpanded\def\ShowAsciiMathMax {\ctxlua{moduledata.asciimath.show.max()}}
+
+\unexpanded\def\ShowAsciiMathResult#1%
+ {\begingroup
+ \blank
+ % if we are in vmode, we don't get positions i.e. a smaller tuc file
+ \inleft{\ttbf#1\hfill\ctxlua{moduledata.asciimath.show.count(#1,true)}}%
+ \dontleavehmode
+ \begingroup
+ \ttbf
+ \ctxlua{moduledata.asciimath.show.files(#1)}
+ \endgroup
+ \blank[medium,samepage]
+ \startcolor[darkblue]
+ \ctxlua{moduledata.asciimath.show.input(#1,true)}
+ \stopcolor
+ \blank[medium,samepage]
+ \doifmode{asciimath:show:dirty} {
+ \dorecurse{\ctxlua{moduledata.asciimath.show.nofdirty(#1)}} {
+ \ctxlua{moduledata.asciimath.show.dirty(\recurselevel,true)}
+ \blank[medium,samepage]
+ }
+ }
+ \ctxlua{moduledata.asciimath.show.result(#1)}
+ \blank
+ \endgroup}
+
+\unexpanded\def\ShowAsciiMathStart
+ {\begingroup
+ \let\asciimathoptext\asciimathoptexttraced
+ \setuptyping[\v!buffer][\c!before=,\c!after=]
+ \setupmargindata[\v!left][\c!style=]}
+
+\unexpanded\def\ShowAsciiMathStop
+ {\endgroup}
+
+\unexpanded\def\ShowAsciiMath
+ {\dodoubleempty\doShowAsciiMath}
+
+\unexpanded\def\doShowAsciiMath[#1][#2]%
+ {\iffirstargument
+ \ShowAsciiMathStart
+ \ShowAsciiMathLoad[#1]
+ \ifsecondargument
+ \ShowAsciiMathIgnore[#2]
+ \fi
+ \dorecurse{\ShowAsciiMathMax}{\ShowAsciiMathResult\recurselevel}
+ \page
+ \ShowAsciiMathStats
+ \ShowAsciiMathStop
+ \fi}
+
+\unexpanded\def\xmlShowAsciiMath#1#2%
+ {\iffirstargument
+ \ShowAsciiMathStart
+ \ShowAsciiMathXML{#1}{#2}%
+ \dorecurse{\ShowAsciiMathMax}{\ShowAsciiMathResult\recurselevel}
+ \page
+ \ShowAsciiMathStats
+ \ShowAsciiMathStop
+ \fi}
+
+\unexpanded\def\ShowAsciiMathSave
+ {\dosingleempty\doShowAsciiMathSave}
+
+\unexpanded\def\doShowAsciiMathSave[#1]%
+ {\ctxlua{moduledata.asciimath.show.save("#1")}}
\protect
+\startsetups asciimath:layout
+
+ \setupbodyfont
+ % [pagella,10pt]
+ [dejavu,10pt]
+
+ \setuplayout
+ [backspace=35mm,
+ leftmargin=20mm,
+ rightmargindistance=0pt,
+ leftmargindistance=5mm,
+ cutspace=1cm,
+ topspace=1cm,
+ bottomspace=1cm,
+ width=middle,
+ height=middle,
+ header=0cm,
+ footer=1cm]
+
+ \setupheadertexts
+ []
+
+ \setupfootertexts
+ [\currentdate][\pagenumber]
+
+ \setupalign
+ [flushleft,verytolerant,stretch]
+
+ \dontcomplain
+
+\stopsetups
+
+\stopmodule
+
\continueifinputfile{x-asciimath.mkiv}
-\enabletrackers[modules.asciimath.mapping]
+%D This will become an extra.
-\starttext
+\showframe
+\setups[asciimath:layout]
+
+% \enabletrackers[modules.asciimath.mapping]
+% \enabletrackers[modules.asciimath.detail]
+
+% \starttext
+% \enablemode[asciimath:show:dirty]
+% \ShowAsciiMath[e:/temporary/asciimath/*.xml]
+% % \ShowAsciiMathSave[e:/temporary/asciimath/asciimath.lua]
+% \stoptext
+
+\starttext
+\unexpanded\def\MyAsciiMath#1{\startformula\asciimath{#1}\stopformula}
\startlines
-\asciimath{x^2+y_1+z_12^34}
-\asciimath{sin^-1(x)}
-\asciimath{d/dx f(x)=lim_(h->0) (f(x+h)-f(x))/h}
-\asciimath{f(x)=sum_(n=0)^oo(f^((n))(a))/(n!)(x-a)^n}
-\asciimath{int_0^1 f(x)dx}
-\asciimath{int^1_0 f(x)dx}
-\asciimath{a//b}
-\asciimath{a//\alpha}
-\asciimath{(a/b)/(d/c)}
-\asciimath{((a*b))/(d/c)}
-\asciimath{[[a,b],[c,d]]((n),(k))}
-\asciimath{1/x={(1,text{if } x!=0),(text{undefined},if x=0):}}
-\asciimath{{ (1,2), (x,(x + text(x))) }}
-\asciimath{{(1,2),(x,(x+text(x))),(x,text(x))}}
-\asciimath{{(1,2),(x,(x+text(x))),(x,x text(x))}}
-\asciimath{{(1,2/2),(x,(x+x^22+sqrt(xx))),(x,x text(xyz))}}
-\asciimath{{(1,2/2),(x,(x+x^22+sqrt(xx))),(x,text(xyz)+1+text(hans))}}
-\asciimath{<> text{and} {:(x,y),(u,v):}}
-\asciimath{(a,b] = {x text(in) RR | a < x <= b}}
+\MyAsciiMath{x^2 / 10 // z_12^34 / 20}
+% \MyAsciiMath{{:{:x^2:} / 10:} // {:{:z_12^34 :} / 20:}}
+% \MyAsciiMath{x^2+y_1+z_12^34}
+% \MyAsciiMath{sin^-1(x)}
+% \MyAsciiMath{d/dx f(x)=lim_(h->0) (f(x+h)-f(x))/h}
+% \MyAsciiMath{f(x)=sum_(n=0)^oo(f^((n))(a))/(n!)(x-a)^n}
+% \MyAsciiMath{int_0^1 f(x)dx}
+% \MyAsciiMath{int^1_0 f(x)dx}
+% \MyAsciiMath{a//b}
+% \MyAsciiMath{a//\alpha}
+% \MyAsciiMath{(a/b)/(d/c)}
+% \MyAsciiMath{((a*b))/(d/c)}
+% \MyAsciiMath{[[a,b],[c,d]]((n),(k))}
+% \MyAsciiMath{1/x={(1,text{if } x!=0),(text{undefined},if x=0):}}
+% \MyAsciiMath{{ (1,2), (x,(x + text(x))) }}
+% \MyAsciiMath{{(1,2),(x,(x+text(x))),(x,text(x))}}
+% \MyAsciiMath{{(1,2),(x,(x+text(x))),(x,x text(x))}}
+% \MyAsciiMath{{(1,2/2),(x,(x+x^22+sqrt(xx))),(x,x text(xyz))}}
+% \MyAsciiMath{{(1,2/2),(x,(x+x^22+sqrt(xx))),(x,text(xyz)+1+text(hans))}}
+% \MyAsciiMath{<> text{and} {:(x,y),(u,v):}}
+% \MyAsciiMath{(a,b] = {x text(in) RR | a < x <= b}}
+% \MyAsciiMath{a/b / c/d = (a * d) / (b * d) / (b * c) / (b * d) = (a * d) / (b * c)}
+% \MyAsciiMath{ (a/b) // (c/d) = ( (a * d) / (b * d) ) // ( (b * c) / (b * d) ) = (a * d) / (b * c)}
+% \MyAsciiMath{sin(x+1)_3^2/b / c/d}
+% \MyAsciiMath{{:{:sin(x+1)_3^2:}/b:} / {:c/d:}}
+% \MyAsciiMath{cos(a) + sin(x+1)_3^2/b / c/d = (a * d) / (b * d) / (b * c) / (b * d) = (a * d) / (b * c)}
+% \MyAsciiMath{S_(11)}
+% \MyAsciiMath{f(x)}
+% \MyAsciiMath{sin(x)}
+% \MyAsciiMath{sin(x+1)}
+% \MyAsciiMath{sin^-1(x)}
+% \MyAsciiMath{sin(2x)}
+% \MyAsciiMath{a_2^2}
+% \MyAsciiMath{( (S_(11),S_(12),S_(1n)),(vdots,ddots,vdots),(S_(m1),S_(m2),S_(mn)) ]}
+% \MyAsciiMath{frac a b}
+% \MyAsciiMath{sin(x)/2 // cos(x)/pi}
+% \MyAsciiMath{a/13 // c/d}
+% \MyAsciiMath{a/b // c/d}
+% \MyAsciiMath{x}
+% \MyAsciiMath{x^2}
+% \MyAsciiMath{sqrt x}
+% \MyAsciiMath{sqrt (x)}
+% \MyAsciiMath{root 2 x}
+% \MyAsciiMath{x+x}
+% \MyAsciiMath{x/3}
+% \MyAsciiMath{x^2 / 10}
+% \MyAsciiMath{x^2 / 10 // z_12^34 / 20}
+% \MyAsciiMath{a^23}
+% \MyAsciiMath{a^{:b^23:}+3x}
+% \MyAsciiMath{a/b / c/d}
+% \MyAsciiMath{sin(x)/b / c/d}
+% \MyAsciiMath{sin(x)/b // c/d}
+% \MyAsciiMath{a/b / c/d = (a * d) / (b * d) / (b * c) / (b * d) = (a * d) / (b * c) }
+% \MyAsciiMath{{:{:x^2:} / 10:} // {:{:z_12^34 :} / 20:}}
+% \MyAsciiMath{x^2+y_1+z_12^34}
+% \MyAsciiMath{sin^-1(x)}
+% \MyAsciiMath{d/dx f(x)=lim_(h->0) (f(x+h)-f(x))/h}
+% \MyAsciiMath{f(x)=sum_(n=0)^oo(f^((n))(a))/(n!)(x-a)^n}
+% \MyAsciiMath{int_0^1 f(x)dx}
+% \MyAsciiMath{int^1_0 f(x)dx}
+% \MyAsciiMath{2x}
+% \MyAsciiMath{a//b}
+% \MyAsciiMath{a//\alpha}
+% \MyAsciiMath{(a/b)/(d/c)}
+% \MyAsciiMath{((a*b))/(d/c)}
+% \MyAsciiMath{[[a,b],[c,d]]((n),(k))}
+% \MyAsciiMath{1/x={(1,text{if } x!=0),(text{undefined},if x=0):}}
+% \MyAsciiMath{{ (1,2), (x,(x + text(x))) }}
+% \MyAsciiMath{{(1,2),(x,(x+text(x))),(x,text(x))}}
+% \MyAsciiMath{{(1,2),(x,(x+text(x))),(x,x text(x))}}
+% \MyAsciiMath{{(1,2/2),(x,(x+x^22+sqrt(xx))),(x,x text(xyz))}}
+% \MyAsciiMath{{(1,2/2),(x,(x+x^22+sqrt(xx))),(x,text(xyz)+1+text(hans))}}
+% \MyAsciiMath{<> text{and} {:(x,y),(u,v):}}
+% \MyAsciiMath{(a,b] = {x text(in) RR | a < x <= b}}
+% \MyAsciiMath{x^-2}
+% \MyAsciiMath{x^2(x-1/16)=0}
+% \MyAsciiMath{y= ((1/4)) ^x}
+% \MyAsciiMath{log (0,002) / (log(1/4))}
+% \MyAsciiMath{x=ax+b \ oeps}
+% \MyAsciiMath{x=\ ^ (1/4) log(x)}
+% \MyAsciiMath{x=\ ^ (1/4) log(0 ,002 )= log(0,002) / (log(1/4))}
+% \MyAsciiMath{x^ (-1 1/2) =1/x^ (1 1/2)=1/ (x^1*x^ (1/2)) =1/ (xsqrt(x))}
+% \MyAsciiMath{x^2(10 -x)>2 x^2}
+% \MyAsciiMath{x^4>x}
\stoplines
-
\stoptext
diff --git a/Master/texmf-dist/tex/context/base/x-cals.lua b/Master/texmf-dist/tex/context/base/x-cals.lua
index 36bc1aaba2d..3af6106d803 100644
--- a/Master/texmf-dist/tex/context/base/x-cals.lua
+++ b/Master/texmf-dist/tex/context/base/x-cals.lua
@@ -6,6 +6,7 @@ if not modules then modules = { } end modules ['x-cals'] = {
license = "see context related readme files"
}
+local next = next
local format, lower = string.format, string.lower
local xmlsprint, xmlcprint, xmlcollected, xmlelements = xml.sprint, xml.cprint, xml.collected, xml.elements
local n_todimen, s_todimen = number.todimen, string.todimen
@@ -65,8 +66,10 @@ end
local function getspecs(root, pattern, names, widths)
-- here, but actually we need this in core-ntb.tex
-- but ideally we need an mkiv enhanced core-ntb.tex
- local ignore_widths = cals.ignore_widths
- local shrink_widths = cals.shrink_widths
+ local ignore_widths = cals.ignore_widths
+-- local shrink_widths = at.option == "shrink" or cals.shrink_widths
+-- local stretch_widths = at.option == "stretch" or cals.stretch_widths
+ local shrink_widths = cals.shrink_widths
local stretch_widths = cals.stretch_widths
for e in xmlcollected(root,pattern) do
local at = e.at
diff --git a/Master/texmf-dist/tex/context/base/x-ct.lua b/Master/texmf-dist/tex/context/base/x-ct.lua
index 2dee985c329..9c647e8e790 100644
--- a/Master/texmf-dist/tex/context/base/x-ct.lua
+++ b/Master/texmf-dist/tex/context/base/x-ct.lua
@@ -122,6 +122,8 @@ function moduledata.ct.tabulate(root,namespace)
end
+-- todo: use content and caption
+
function moduledata.ct.combination(root,namespace)
if not root then
diff --git a/Master/texmf-dist/tex/context/base/x-html.mkiv b/Master/texmf-dist/tex/context/base/x-html.mkiv
new file mode 100644
index 00000000000..e1806eb9eb0
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/x-html.mkiv
@@ -0,0 +1,379 @@
+%D \module
+%D [ file=x-html,
+%D version=2011.02.03, % adapted 2014.11.08
+%D title=\CONTEXT\ Modules,
+%D subtitle=HTML,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\startmodule[html]
+
+%D Usage:
+%D
+%D \starttyping
+%D \xmlregistersetup{xml:html:basics}
+%D \xmlregistersetup{xml:html:tables}
+%D \stoptyping
+
+% \xmlsetsetup{#1}{(p|span)[@lang]}{xml:html:lang}
+%
+% \startxmlsetups xml:html:lang
+% \begingroup
+% \language[\xmlatt{#1}{lang}]
+% \xmlsetup{#1}{xml:html:\xmltag{#1}}
+% \endgroup
+% \stopxmlsetups
+
+\unprotect
+
+\definehighlight[b] [\c!command=\v!no,\c!style=\v!bold]
+\definehighlight[i] [\c!command=\v!no,\c!style=\v!italic]
+\definehighlight[bi] [\c!command=\v!no,\c!style=\v!bolditalic]
+\definehighlight[em] [\c!command=\v!no,\c!style=\em]
+\definehighlight[tt] [\c!command=\v!no,\c!style=\v!mono]
+\definehighlight[strong][\c!command=\v!no,\c!style=\v!bold]
+\definehighlight[u] [\c!command=\v!no,\c!style=\directsetbar{\v!underbar}]
+\definehighlight[code] [\c!command=\v!no,\c!style=\v!mono]
+\definehighlight[pre] [\c!command=\v!no]
+
+\protect
+
+% todo: pre
+
+\startxmlsetups xml:html:basics
+ \xmlsetsetup{#1}{p|br|b|i|u|em|tt|strong|ul|ol|li|table|thead|tbody|tfoot|tr|td|th|span|img}{xml:html:*}
+ \xmlsetsetup{#1}{b/i}{xml:html:bi}
+ \xmlsetsetup{#1}{i/b}{xml:html:bi}
+ \xmlstripanywhere{#1}{!pre}
+\stopxmlsetups
+
+\startxmlsetups xml:html:tables
+ \xmlsetsetup{#1}{table|thead|tbody|tfoot|tr|td|th}{xml:html:*}
+\stopxmlsetups
+
+\startxmlsetups xml:html:p
+ \xmldoifnotselfempty {#1} {
+ \dontleavehmode
+ \ignorespaces
+ \xmlflush{#1}
+ \removeunwantedspaces
+ }
+ \par
+\stopxmlsetups
+
+\startxmlsetups xml:html:br
+ \crlf
+\stopxmlsetups
+
+\startxmlsetups xml:html:b
+ \directhighlight{b}{\xmlflush{#1}}
+\stopxmlsetups
+
+\startxmlsetups xml:html:i
+ \directhighlight{i}{\xmlflush{#1}}
+\stopxmlsetups
+
+\startxmlsetups xml:html:bi
+ \directhighlight{bi}{\xmlflush{#1}}
+\stopxmlsetups
+
+\startxmlsetups xml:html:em
+ \directhighlight{em}{\xmlflush{#1}}
+\stopxmlsetups
+
+\startxmlsetups xml:html:tt
+ \directhighlight{tt}{\xmlflush{#1}}
+\stopxmlsetups
+
+\startxmlsetups xml:html:strong
+ \directhighlight{strong}{\xmlflush{#1}}
+\stopxmlsetups
+
+\startxmlsetups xml:html:u
+ \directhighlight{u}{\xmlflush{#1}}
+\stopxmlsetups
+
+\startxmlsetups xml:html:ul
+ \startitemize[packed]
+ \xmlflush{#1}
+ \stopitemize
+\stopxmlsetups
+
+\startxmlsetups xml:html:ol
+ \startitemize[packed,n]
+ \xmlflush{#1}
+ \stopitemize
+\stopxmlsetups
+
+\startxmlsetups xml:html:li
+ \startitem
+ \xmlflush{#1}
+ \stopitem
+\stopxmlsetups
+
+\startxmlsetups xml:html:code
+ \directhighlight{code}{\xmlflushspacewise{#1}}
+\stopxmlsetups
+
+\startxmlsetups xml:html:pre
+ \directhighlight{pre}{\xmlflushspacewise{#1}}
+\stopxmlsetups
+
+\startxmlsetups xml:html:span
+ \xmlflush{#1}
+\stopxmlsetups
+
+\startxmlsetups xml:html:img
+ \ifhmode
+ \dontleavehmode
+ \externalfigure[\xmlatt{#1}{src}]
+ \else
+ \startlinecorrection
+ \externalfigure[\xmlatt{#1}{src}]
+ \stoplinecorrection
+ \fi
+\stopxmlsetups
+
+% tables, maybe we need a generic html table module
+%
+% todo: align
+
+% beware, the padding code is somewhat experimental, eventually the
+% table will be done in cld code
+%
+% we can also use \xmlmap for border etc
+
+\starttexdefinition cssgetsinglepadding #1
+ \ctxlua {
+ context((moduledata.css.padding(
+ "#1",
+ \number\dimexpr0.1ex,
+ \number\dimexpr0.01\hsize,
+ \number\dimexpr1ex,
+ \number\dimexpr1em
+ ))) % returns 4 values therefore ()
+ }sp
+\stoptexdefinition
+
+\startxmlsetups xml:html:table
+ \edef\CellPadding{\xmlatt{#1}{cellpadding}}
+ \ifx\CellPadding\empty
+ \edef\CellPadding{.25ex}
+ \else
+ \edef\CellPadding{\cssgetsinglepadding\CellPadding}
+ \fi
+ \startlinecorrection[blank]
+ \doifelse {\xmlatt{#1}{border}} {0} {
+ \bTABLE[frame=off,offset=\CellPadding]
+ \xmlflush{#1}
+ \eTABLE
+ } {
+ \bTABLE[offset=\CellPadding]
+ \xmlflush{#1}
+ \eTABLE
+ }
+ \stoplinecorrection
+\stopxmlsetups
+
+\startxmlsetups xml:html:thead
+ \bTABLEhead
+ \xmlflush{#1}
+ \eTABLEhead
+\stopxmlsetups
+
+\startxmlsetups xml:html:tbody
+ \bTABLEbody
+ \xmlflush{#1}
+ \eTABLEbody
+\stopxmlsetups
+
+\startxmlsetups xml:html:tfoot
+ \bTABLEfoot
+ \xmlflush{#1}
+ \eTABLEfoot
+\stopxmlsetups
+
+\startxmlsetups xml:html:tr
+ \bTR[ny=\xmlattdef{#1}{rowspan}{1}]
+ \xmlflush{#1}
+ \eTR
+\stopxmlsetups
+
+\startxmlsetups xml:html:td
+ \bTD[nx=\xmlattdef{#1}{colspan}{1}]
+ \xmlflush{#1}
+ \eTD
+\stopxmlsetups
+
+\startxmlsetups xml:html:th
+ \bTH[nx=\xmlattdef{#1}{colspan}{1}]
+ \xmlflush{#1}
+ \eTH
+\stopxmlsetups
+
+% \xmlregistersetup{xml:html:basics}
+
+%D For old times sake:
+
+\startxmlsetups xml:setups:common
+ \xmlsetup{#1}{xml:html:basics}
+ \xmlsetup{#1}{xml:html:tables}
+% \ifconditional\qmlcleanuptwo
+% \xmlsetsetup{#1}{html/br[index() == 1]}{xml:noppes:1}
+% \xmlsetsetup{#1}{html/p[index() == lastindex()]/br[index() == lastindex()]}{xml:noppes:2}
+% \xmlsetsetup{#1}{html/br[index() == lastindex()]}{xml:noppes:3}
+% \xmlsetsetup{#1}{br[name(1) == 'img']}{xml:noppes}
+% \xmlsetsetup{#1}{br[name(1) == 'br' and name(2) == 'img']}{xml:noppes}
+% % \xmlsetsetup{#1}{br/following-sibling::img[position()==1]}{xml:noppes}
+% \fi
+\stopxmlsetups
+
+\stopmodule
+
+\continueifinputfile{x-html.mkiv}
+
+\xmlregistersetup{xml:html:basics}
+\xmlregistersetup{xml:html:tables}
+
+\startxmlsetups xml:whatever
+ \xmlsetsetup {#1} {
+ html|body
+ } {xml:html:*}
+\stopxmlsetups
+
+\xmlregisterdocumentsetup{main}{xml:whatever}
+
+\startxmlsetups xml:html:html
+ \xmlflush{#1}
+\stopxmlsetups
+
+\startxmlsetups xml:html:body
+ \xmlflush{#1}
+\stopxmlsetups
+
+\setuphead[subject][page=yes,style=\bfa]
+
+\starttexdefinition ShowExample#1
+ \startsubject[title=#1]
+ \typebuffer[#1]
+ \starttextrule{result}
+ \xmlprocessbuffer{main}{#1}{}
+ \stoptextrule
+ \stopsubject
+\stoptexdefinition
+
+\starttext
+
+\startbuffer[test 1]
+
+test
+
+test
+
+\stopbuffer
+
+\startbuffer[test 2]
+
+test (hierna een lf)
+test
+
+\stopbuffer
+
+\startbuffer[test 3]
+
+test (hierna een lf met lege regel)
+
+test
+
+\stopbuffer
+
+\startbuffer[test 4]
+
+test (hierna een lf met twee lege regels)
+
+
+test
+
+\stopbuffer
+
+\startbuffer[test 5]
+
+test (hierna br geen lf)
test
+
+\stopbuffer
+
+\startbuffer[test 6]
+
+test (hierna br met lf)
+test
+
+\stopbuffer
+
+\startbuffer[test 7]
+
+test (hierna br met lf en lege regel)
+
+test
+
+\stopbuffer
+
+\startbuffer[test 8]
+
+test (hierna br met lf en twee lege regels)
+
+
+test
+
+\stopbuffer
+
+\startbuffer[test 9]
+
+test (hierna bold) bold test
+
+\stopbuffer
+
+\startbuffer[test 10]
+
+test (hierna lf met bold)
+bold underlined test
+
+\stopbuffer
+
+\startbuffer[test 11]
+
+test (hierna lf met lege regel en bold)
+
+bold test
+
+\stopbuffer
+
+\startbuffer[test 12]
+
+test (hierna lf met lege regel en lf in bold)
+
+
+bold
+ test
+
+\stopbuffer
+
+\startbuffer[test 13]
+
+test (hierna lf met lege regel en lf en lege regel in bold)
+
+
+
+bold
+
+ test
+
+\stopbuffer
+
+\dorecurse{13}{\ShowExample{test #1}}
+
+\stoptext
diff --git a/Master/texmf-dist/tex/context/base/x-math-svg.lua b/Master/texmf-dist/tex/context/base/x-math-svg.lua
new file mode 100644
index 00000000000..263827f92f5
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/x-math-svg.lua
@@ -0,0 +1,169 @@
+if not modules then modules = { } end modules ['x-math-svg'] = {
+ version = 1.001,
+ comment = "companion to x-math-svg.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local tostring, type, next = tostring, type, next
+local lpegmatch, P, Cs = lpeg.match, lpeg.P, lpeg.Cs
+
+local xmlfirst = xml.first
+local xmlconvert = xml.convert
+local xmlload = xml.load
+local xmlsave = xml.save
+local xmlcollected = xml.collected
+local xmldelete = xml.delete
+
+local loadtable = table.load
+local savetable = table.save
+
+local replacesuffix = file.replacesuffix
+local addsuffix = file.addsuffix
+local removefile = os.remove
+local isfile = lfs.isfile
+
+local formatters = string.formatters
+
+moduledata = moduledata or table.setmetatableindex("table")
+local svgmath = moduledata.svgmath -- autodefined
+
+local namedata = { }
+local pagedata = { }
+
+local statusname = "x-math-svg-status.lua"
+local pdfname = "x-math-svg.pdf"
+
+local pdftosvg = os.which("mudraw")
+
+local f_make_tex = formatters[ [[context --global kpse:x-math-svg.mkvi --inputfile="%s" --svgstyle="%s" --batch --noconsole --once --purgeall]] ]
+local f_make_svg = formatters[ [[mudraw -o "math-%%d.svg" "%s" 1-9999]] ]
+
+local f_inline = formatters[ [[]] ]
+local f_display = formatters[ [[]] ]
+
+local f_math_tmp = formatters[ [[math-%i]] ]
+
+function svgmath.process(filename)
+ if not filename then
+ -- no filename given
+ return
+ elseif not isfile(filename) then
+ -- invalid filename
+ return
+ end
+ local index = 0
+ local page = 0
+ local blobs = { }
+ local root = xmlload(filename)
+ for mth in xmlcollected(root,"math") do
+ index = index + 1
+ local blob = tostring(mth)
+ if blobs[blob] then
+ context.ReuseSVGMath(index,blobs[blob])
+ else
+ page = page + 1
+ buffers.assign(f_math_tmp(page),blob)
+ context.MakeSVGMath(index,page,mth.at.display)
+ blobs[blob] = page
+ end
+ end
+ context(function()
+ -- for tracing purposes:
+ for mathdata, pagenumber in next, blobs do
+ local p = pagedata[pagenumber]
+ p.mathml = mathdata
+ p.number = pagenumber
+ end
+ --
+ savetable(statusname, {
+ pagedata = pagedata,
+ namedata = namedata,
+ })
+ end)
+end
+
+function svgmath.register(index,page,specification)
+ if specification then
+ pagedata[page] = specification
+ end
+ namedata[index] = page
+end
+
+function svgmath.convert(filename,svgstyle)
+ if not filename then
+ -- no filename given
+ return false, "no filename"
+ elseif not isfile(filename) then
+ -- invalid filename
+ return false, "invalid filename"
+ elseif not pdftosvg then
+ return false, "mudraw is not installed"
+ end
+
+ os.execute(f_make_tex(filename,svgstyle))
+
+ local data = loadtable(statusname)
+ if not data then
+ -- invalid tex run
+ return false, "invalid tex run"
+ elseif not next(data) then
+ return false, "no converson needed"
+ end
+
+ local pagedata = data.pagedata
+ local namedata = data.namedata
+
+ os.execute(f_make_svg(pdfname))
+
+ local root = xmlload(filename)
+ local index = 0
+ local done = { }
+ local unique = 0
+
+ local between = (1-P("<"))^1/""
+ local strip = Cs((
+ (P(""))^1) * P(" ")) * between^0 / "" +
+ P(">") * between +
+ P(1)
+ )^1)
+
+ for mth in xmlcollected(root,"m:math") do
+ index = index + 1
+ local page = namedata[index]
+ if done[page] then
+ mth.__p__.dt[mth.ni] = done[page]
+ else
+ local info = pagedata[page]
+ local depth = info.depth
+ local mode = info.mode
+ local svgname = addsuffix(f_math_tmp(page),"svg")
+ local action = mode == "inline" and f_inline or f_display
+ local x_div = xmlfirst(xmlconvert(action(-depth)),"/div")
+ local svgdata = io.loaddata(svgname)
+ if not svgdata or svgdata == "" then
+ print("error in:",svgname,tostring(mth))
+ else
+ -- svgdata = string.gsub(svgdata,">%s<","")
+ svgdata = lpegmatch(strip,svgdata)
+ local x_svg = xmlfirst(xmlconvert(svgdata),"/svg")
+ -- xmldelete(x_svg,"text")
+ x_div.dt = { x_svg }
+ mth.__p__.dt[mth.ni] = x_div -- use helper
+ end
+ done[page] = x_div
+ unique = unique + 1
+ end
+ end
+
+-- for k, v in next, data do
+-- removefile(addsuffix(k,"svg"))
+-- end
+-- removefile(statusname)
+-- removefile(pdfname)
+
+ xmlsave(root,filename)
+
+ return true, index, unique
+end
diff --git a/Master/texmf-dist/tex/context/base/x-mathml-basics.mkiv b/Master/texmf-dist/tex/context/base/x-mathml-basics.mkiv
new file mode 100644
index 00000000000..e166995b0c8
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/x-mathml-basics.mkiv
@@ -0,0 +1,276 @@
+% macros=mkvi
+
+% makes sense (but rel vs op ...):
+
+% \unexpanded\def\stackrel#1#2{\mathematics{\mathop{\let\limits\relax\mover{#2}{#1}}}}
+
+% this can become a core helper
+
+% bwe could do all of them in lua
+
+\startluacode
+local find = string.find
+local lpegmatch = lpeg.match
+
+local splitter = lpeg.Ct(lpeg.C(lpeg.patterns.nestedbraces + lpeg.patterns.utf8character)^1)
+
+function commands.xmfenced(left,middle,right,content)
+ local l = left ~= "" and left or "("
+ local r = right ~= "" and right or ")"
+ local m = middle ~= "" and middle and lpegmatch(splitter,middle) or { "," }
+ local c = find(content,"{") and lpegmatch(splitter,content) or { content }
+ local n = #c
+ if n > 1 then
+ context("\\left%s",l)
+ for i=1,n do
+ if i > 1 then
+ context("%s %s",m[i] or m[#m],c[i])
+ else
+ context(c[i])
+ end
+ end
+ context("\\right%s",r)
+ else
+ context("\\left%s %s \\right%s",l,content,r)
+ end
+end
+
+\stopluacode
+
+\unprotect
+
+\unexpanded\def\mexecuteifdefined#1%
+ {\ifx#1\empty
+ \expandafter\secondoftwoarguments
+ \else\ifcsname#1\endcsname
+ \doubleexpandafter\firstoftwoarguments
+ \else
+ \doubleexpandafter\secondoftwoarguments
+ \fi\fi
+ {\csname#1\endcsname}}
+
+% mrow
+
+\let\mrow\mathematics
+
+% msub msup msubsup
+
+\starttexdefinition msub #1#2
+ \mathematics {
+ #1_{#2}
+ }
+\stoptexdefinition
+
+\starttexdefinition msup #1#2
+ \mathematics {
+ #1^{#2}
+ }
+\stoptexdefinition
+
+\starttexdefinition msubsup #1#2#3
+ \mathematics {
+ #1_{#2}^{#3}
+ }
+\stoptexdefinition
+
+% mn mo mi
+
+\let\mn\mathematics
+\let\mo\mathematics
+\let\mi\mathematics
+
+% ms mtext
+
+\starttexdefinition ms #1
+ \text {
+ "#1"
+ }
+\stoptexdefinition
+
+\starttexdefinition mtext #1
+ \text {
+ #1
+ }
+\stoptexdefinition
+
+% mover
+
+\starttexdefinition unexpanded moverabove #1
+ \edef\movercommand{\utfmathfiller\movertoken}
+ \mexecuteifdefined\movercommand {#1} \relax
+\stoptexdefinition
+\starttexdefinition unexpanded moverbase #1
+ \edef\mbasecommand{\utfmathfiller\mbasetoken}
+ \mexecuteifdefined\mbasecommand {#1}
+ \relax
+\stoptexdefinition
+\starttexdefinition unexpanded moverbasefiller #1#2
+ \edef\mbasecommand{e\utfmathcommandfiller\mbasetoken}
+ \mexecuteifdefined\mbasecommand \relax {#2} {}
+\stoptexdefinition
+\starttexdefinition unexpanded moveraccent #1#2
+ \edef\movercommand{\utfmathcommandabove\movertoken}
+ \mexecuteifdefined\movercommand \relax {#1}
+\stoptexdefinition
+\starttexdefinition unexpanded movertext #1#2
+ % \mathtriplet {\mathstylehbox{#1}} {#2} {}
+ \mathtriplet {\mathematics{#1}} {#2} {}
+\stoptexdefinition
+\starttexdefinition unexpanded moveraccentchecker #1#2
+ \edef\movertoken{\tochar{#2}}
+ \doifelseutfmathabove\movertoken \moveraccent \movertext {#1}{#2}
+\stoptexdefinition
+
+\starttexdefinition unexpanded mover #1#2
+ \mathematics {
+ \edef\mbasetoken{\tochar{#1}}
+ \doifelseutfmathfiller\mbasetoken \moverbasefiller \moveraccentchecker {#1}{#2}
+ }
+\stoptexdefinition
+
+% munder
+
+\starttexdefinition unexpanded munderbelow #1
+ \edef\mundercommand{\utfmathfiller\mundertoken}
+ \mexecuteifdefined\mundercommand {#1} \relax
+\stoptexdefinition
+\starttexdefinition unexpanded munderbase #1
+ \edef\mbasecommand{\utfmathfiller\mbasetoken}
+ \mexecuteifdefined\mbasecommand {#1}
+ \relax
+\stoptexdefinition
+\starttexdefinition unexpanded munderbasefiller #1#2
+ \edef\mbasecommand{e\utfmathcommandfiller\mbasetoken}
+ \mexecuteifdefined\mbasecommand \relax {#2} {}
+\stoptexdefinition
+\starttexdefinition unexpanded munderaccent #1#2
+ \edef\mundercommand{\utfmathcommandbelow\mundertoken}
+ \mexecuteifdefined\mundercommand \relax {#1}
+\stoptexdefinition
+\starttexdefinition unexpanded mundertext #1#2
+ % \mathtriplet {\mathstylehbox{#1}} {} {#2}
+ \mathtriplet {\mathematics{#1}} {} {#2}
+\stoptexdefinition
+\starttexdefinition unexpanded munderaccentchecker #1#2
+ \edef\mundertoken{\tochar{#2}}
+ \doifelseutfmathbelow\mundertoken \munderaccent \mundertext {#1}{#2}
+\stoptexdefinition
+
+\starttexdefinition unexpanded munder #1#2
+ \mathematics {
+ \edef\mbasetoken{\tochar{#1}}
+ \doifelseutfmathfiller\mbasetoken \munderbasefiller \munderaccentchecker {#1}{#2}
+ }
+\stoptexdefinition
+
+% munderover
+
+% mfenced
+
+% \mfenced{x,y}
+% \mfenced{{x}{y}}
+% \mfenced[separators]{{x}{y}}
+% \mfenced[left][right]{{x}{y}}
+% \mfenced[left][separators][right]{{x}{y}}
+
+\starttexdefinition unexpanded mfenced
+ \dotripleempty\do_mfenced
+\stoptexdefinition
+
+\starttexdefinition unexpanded do_mfenced [#1][#2][#3]#4
+ \mathematics {
+ \ctxcommand{xmfenced(
+ \ifthirdargument "#1","#2","#3"\else
+ \ifsecondargument "#1",",","#2"\else
+ \iffirstargument "(","#1",")"\else
+ "(",",",")"\fi\fi\fi
+ ,"#4")}
+ }
+\stoptexdefinition
+
+% mfrac
+
+\starttexdefinition unexpanded mfrac #1#2
+ \mathematics {
+ \frac{#1}{#2}
+ }
+\stoptexdefinition
+
+% mroot msqrt
+
+\starttexdefinition unexpanded mroot #1#2
+ \mathematics {
+ \sqrt[#1]{#2}
+ }
+\stoptexdefinition
+
+\starttexdefinition unexpanded msqrt #1
+ \mathematics {
+ \sqrt{#1}
+ }
+\stoptexdefinition
+
+% menclose
+
+% merror
+
+% mglyph
+
+% mmultiscripts
+
+% mpadded
+
+% mphantom
+
+% mspace
+
+% mstyle
+
+% mtable mtr mlabeledtr mtd
+
+% maction
+
+% semantics
+
+\protect
+
+\continueifinputfile{x-mathml-basics.mkiv}
+
+\starttext
+
+$\mfenced{1+a}$\par
+$\mfenced[,]{1+a}$\par
+$\mfenced[,]{{1+a}{1+b}}$\par
+
+% $\mover{←}{test}$\par
+% $\mover{\utfchar{"2190}}{test}$\par
+% $\mover{e:leftarrow}{test}$\par
+% $\mover{x:2190}{test}$\par
+
+% $\mover{test}{⏞}$\par
+% $\mover{test}{\utfchar{"23DE}}$\par
+% $\mover{test}{e:overbrace}$\par
+% $\mover{test}{x:23DE}$\par
+% $\mover{test}{over}$\par
+
+% \mover{test}{⏞}\par
+% \mover{test}{\utfchar{"23DE}}\par
+% \mover{test}{e:overbrace}\par
+% \mover{test}{x:23DE}\par
+
+% $\munder{←}{test}$\par
+% $\munder{\utfchar{"2190}}{test}$\par
+% $\munder{e:leftarrow}{test}$\par
+% $\munder{x:2190}{test}$\par
+
+% $\munder{test}{⏟}$\par
+% $\munder{test}{\utfchar{"23DF}}$\par
+% $\munder{test}{e:underbrace}$\par
+% $\munder{test}{x:23DF}$\par
+% $\munder{test}{under}$\par
+
+% \math{{\msup{x}{2}\mo{+}\mn{2}\mi{x}\mo{+}\mi{b}}}
+
+% \mrow{\msup{x}{2}\mo{+}\mn{2}\mi{x}\mo{+}\mi{b}}
+
+\stoptext
diff --git a/Master/texmf-dist/tex/context/base/x-mathml.lua b/Master/texmf-dist/tex/context/base/x-mathml.lua
index 15739eec76e..a0db339bc61 100644
--- a/Master/texmf-dist/tex/context/base/x-mathml.lua
+++ b/Master/texmf-dist/tex/context/base/x-mathml.lua
@@ -6,20 +6,56 @@ if not modules then modules = { } end modules ['x-mathml'] = {
license = "see context related readme files"
}
--- This needs an upgrade to the latest greatest mechanisms.
+-- This needs an upgrade to the latest greatest mechanisms. But ... it
+-- probably doesn't pay back as no mathml support ever did.
local type, next = type, next
-local format, lower, find, gsub = string.format, string.lower, string.find, string.gsub
+local formatters, lower, find, gsub, match = string.formatters, string.lower, string.find, string.gsub, string.match
local strip = string.strip
-local xmlsprint, xmlcprint, xmltext, xmlcontent = xml.sprint, xml.cprint, xml.text, xml.content
+local xmlsprint, xmlcprint, xmltext, xmlcontent, xmlempty = xml.sprint, xml.cprint, xml.text, xml.content, xml.empty
+local lxmlcollected, lxmlfilter = lxml.collected, lxml.filter
local getid = lxml.getid
-local utfchar, utfcharacters, utfvalues = utf.char, utf.characters, utf.values
-local lpegmatch = lpeg.match
+local utfchar, utfcharacters, utfvalues, utfsplit, utflen = utf.char, utf.characters, utf.values, utf.split, utf.len
+local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
+local P, Cs = lpeg.P, lpeg.Cs
local mathml = { }
moduledata.mathml = mathml
lxml.mathml = mathml -- for the moment
+local context = context
+
+local ctx_enabledelimiter = context.enabledelimiter
+local ctx_disabledelimiter = context.disabledelimiter
+local ctx_xmlflush = context.xmlflush -- better xmlsprint
+
+local ctx_halign = context.halign
+local ctx_noalign = context.noalign
+local ctx_bgroup = context.bgroup
+local ctx_egroup = context.egroup
+local ctx_crcr = context.crcr
+
+local ctx_bTABLE = context.bTABLE
+local ctx_eTABLE = context.eTABLE
+local ctx_bTR = context.bTR
+local ctx_eTR = context.eTR
+local ctx_bTD = context.bTD
+local ctx_eTD = context.eTD
+
+local ctx_mn = context.mn
+local ctx_mi = context.mi
+local ctx_mo = context.mo
+local ctx_startimath = context.startimath
+local ctx_ignorespaces = context.ignorespaces
+local ctx_removeunwantedspaces = context.removeunwantedspaces
+local ctx_stopimath = context.stopimath
+
+local ctx_mmlapplycsymbol = context.mmlapplycsymbol
+
+local ctx_mathopnolimits = context.mathopnolimits
+local ctx_left = context.left
+local ctx_right = context.right
+
-- an alternative is to remap to private codes, where we can have
-- different properties .. to be done; this will move and become
-- generic; we can then make the private ones active in math mode
@@ -62,6 +98,7 @@ local o_replacements = { -- in main table
["{"] = "\\mmlleftdelimiter \\lbrace",
["}"] = "\\mmlrightdelimiter\\rbrace",
["|"] = "\\mmlleftorrightdelimiter\\vert",
+ -- ["."] = "\\mmlleftorrightdelimiter.",
["/"] = "\\mmlleftorrightdelimiter\\solidus",
[doublebar] = "\\mmlleftorrightdelimiter\\Vert",
["("] = "\\mmlleftdelimiter(",
@@ -467,20 +504,39 @@ function mathml.stripped(str)
context(strip(str))
end
+local p_entity = (P("&") * ((1-P(";"))^0) * P(";"))
+local p_utfchar = lpegpatterns.utf8character
+local p_spacing = lpegpatterns.whitespace^1
+
+local p_mn = Cs((p_entity/"" + p_spacing/utfchar(0x205F) + p_utfchar/n_replacements)^0)
+local p_strip = Cs((p_entity/"" + p_utfchar )^0)
+local p_mi = Cs((p_entity/"" + p_utfchar/i_replacements)^0)
+
+-- function mathml.mn(id,pattern)
+-- -- maybe at some point we need to interpret the number, but
+-- -- currently we assume an upright font
+-- local str = xmlcontent(getid(id)) or ""
+-- local rep = gsub(str,"&.-;","")
+-- local rep = gsub(rep,"(%s+)",utfchar(0x205F)) -- medspace e.g.: twenty one (nbsp is not seen)
+-- local rep = gsub(rep,".",n_replacements)
+-- ctx_mn(rep)
+-- end
+
function mathml.mn(id,pattern)
-- maybe at some point we need to interpret the number, but
-- currently we assume an upright font
- local str = xmlcontent(getid(id)) or ""
- local rep = gsub(str,"&.-;","")
- local rep = gsub(rep,"(%s+)",utfchar(0x205F)) -- medspace e.g.: twenty one (nbsp is not seen)
- local rep = gsub(rep,".",n_replacements)
- context.mn(rep)
+ ctx_mn(lpegmatch(p_mn,xmlcontent(getid(id)) or ""))
end
+-- function mathml.mo(id)
+-- local str = xmlcontent(getid(id)) or ""
+-- local rep = gsub(str,"&.-;","") -- todo
+-- context(simpleoperatorremapper(rep) or rep)
+-- end
+
function mathml.mo(id)
- local str = xmlcontent(getid(id)) or ""
- local rep = gsub(str,"&.-;","") -- todo
- context(simpleoperatorremapper(rep) or rep)
+ local str = lpegmatch(p_strip,xmlcontent(getid(id)) or "")
+ context(simpleoperatorremapper(str) or str)
end
function mathml.mi(id)
@@ -494,37 +550,43 @@ function mathml.mi(id)
elseif n == 1 then
local first = str[1]
if type(first) == "string" then
- local str = gsub(first,"&.-;","") -- bah
- local rep = i_replacements[str]
- if not rep then
- rep = gsub(str,".",i_replacements)
- end
+ -- local str = gsub(first,"&.-;","") -- bah
+ -- local rep = i_replacements[str]
+ -- if not rep then
+ -- rep = gsub(str,".",i_replacements)
+ -- end
+ local str = lpegmatch(p_strip,first)
+ local rep = i_replacements[str] or lpegmatch(p_mi,str)
context(rep)
- -- context.mi(rep)
+ -- ctx_mi(rep)
else
- context.xmlflush(id) -- xmlsprint or so
+ ctx_xmlflush(id) -- xmlsprint or so
end
else
- context.xmlflush(id) -- xmlsprint or so
+ ctx_xmlflush(id) -- xmlsprint or so
end
else
- context.xmlflush(id) -- xmlsprint or so
+ ctx_xmlflush(id) -- xmlsprint or so
end
end
function mathml.mfenced(id) -- multiple separators
id = getid(id)
- local left, right, separators = id.at.open or "(", id.at.close or ")", id.at.separators or ","
- local l, r = l_replacements[left], r_replacements[right]
- context.enabledelimiter()
+ local at = id.at
+ local left = at.open or "("
+ local right = at.close or ")"
+ local separators = at.separators or ","
+ local l = l_replacements[left]
+ local r = r_replacements[right]
+ ctx_enabledelimiter()
if l then
context(l_replacements[left] or o_replacements[left] or "")
else
context(o_replacements["@l"])
context(left)
end
- context.disabledelimiter()
- local collected = lxml.filter(id,"/*") -- check the *
+ ctx_disabledelimiter()
+ local collected = lxmlfilter(id,"/*") -- check the *
if collected then
local n = #collected
if n == 0 then
@@ -532,7 +594,7 @@ function mathml.mfenced(id) -- multiple separators
elseif n == 1 then
xmlsprint(collected[1]) -- to be checked
else
- local t = utf.split(separators,true)
+ local t = utfsplit(separators,true)
for i=1,n do
xmlsprint(collected[i]) -- to be checked
if i < n then
@@ -551,35 +613,16 @@ function mathml.mfenced(id) -- multiple separators
end
end
end
- context.enabledelimiter()
+ ctx_enabledelimiter()
if r then
context(r_replacements[right] or o_replacements[right] or "")
else
context(right)
context(o_replacements["@r"])
end
- context.disabledelimiter()
+ ctx_disabledelimiter()
end
---~ local function flush(e,tag,toggle)
---~ if toggle then
---~ context("^{")
---~ else
---~ context("_{")
---~ end
---~ if tag == "none" then
---~ context("{}")
---~ else
---~ xmlsprint(e.dt)
---~ end
---~ if not toggle then
---~ context("}")
---~ else
---~ context("}{}")
---~ end
---~ return not toggle
---~ end
-
local function flush(e,tag,toggle)
if tag == "none" then
-- if not toggle then
@@ -599,7 +642,7 @@ end
function mathml.mmultiscripts(id)
local done, toggle = false, false
- for e in lxml.collected(id,"/*") do
+ for e in lxmlcollected(id,"/*") do
local tag = e.tg
if tag == "mprescripts" then
context("{}")
@@ -609,14 +652,14 @@ function mathml.mmultiscripts(id)
end
end
local done, toggle = false, false
- for e in lxml.collected(id,"/*") do
+ for e in lxmlcollected(id,"/*") do
local tag = e.tg
if tag == "mprescripts" then
break
elseif done then
toggle = flush(e,tag,toggle)
else
- xmlsprint(e.dt)
+ xmlsprint(e)
done = true
end
end
@@ -651,12 +694,12 @@ function mathml.mcolumn(root)
local tag = e.tg
if tag == "mi" or tag == "mn" or tag == "mo" or tag == "mtext" then
local str = xmltext(e)
- str = gsub(str,"&.-;","")
+ str = lpegmatch(p_strip,str)
for s in utfcharacters(str) do
m[#m+1] = { tag, s }
end
if tag == "mn" then
- local n = utf.len(str)
+ local n = utflen(str)
if n > numbers then
numbers = n
end
@@ -670,20 +713,20 @@ function mathml.mcolumn(root)
-- m[#m+1] = { tag, e }
end
end
- for e in lxml.collected(root,"/*") do
+ for e in lxmlcollected(root,"/*") do
local m = { }
matrix[#matrix+1] = m
if e.tg == "mrow" then
-- only one level
- for e in lxml.collected(e,"/*") do
+ for e in lxmlcollected(e,"/*") do
collect(m,e)
end
else
collect(m,e)
end
end
- context.halign()
- context.bgroup()
+ ctx_halign()
+ ctx_bgroup()
context([[\hss\startimath\alignmark\stopimath\aligntab\startimath\alignmark\stopimath\cr]])
for i=1,#matrix do
local m = matrix[i]
@@ -695,7 +738,7 @@ function mathml.mcolumn(root)
end
end
if mline then
- context.noalign([[\obeydepth\nointerlineskip]])
+ ctx_noalign([[\obeydepth\nointerlineskip]])
end
for j=1,#m do
local mm = m[j]
@@ -738,9 +781,9 @@ function mathml.mcolumn(root)
local nchr = n_replacements[chr]
context(nchr or chr)
end
- context.crcr()
+ ctx_crcr()
end
- context.egroup()
+ ctx_egroup()
end
local spacesplitter = lpeg.tsplitat(" ")
@@ -758,42 +801,47 @@ function mathml.mtable(root)
local framespacing = at.framespacing or "0pt"
local framespacing = at.framespacing or "-\\ruledlinewidth" -- make this an option
- context.bTABLE { frame = frametypes[frame or "none"] or "off", offset = framespacing, background = "" } -- todo: use xtables and definextable
- for e in lxml.collected(root,"/(mml:mtr|mml:mlabeledtr)") do
- context.bTR()
+ ctx_bTABLE { frame = frametypes[frame or "none"] or "off", offset = framespacing, background = "" } -- todo: use xtables and definextable
+ for e in lxmlcollected(root,"/(mml:mtr|mml:mlabeledtr)") do
+ ctx_bTR()
local at = e.at
local col = 0
local rfr = at.frame or (frames and frames [#frames])
local rra = at.rowalign or (rowaligns and rowaligns [#rowaligns])
local rca = at.columnalign or (columnaligns and columnaligns[#columnaligns])
local ignorelabel = e.tg == "mlabeledtr"
- for e in lxml.collected(e,"/mml:mtd") do -- nested we can use xml.collected
+ for e in lxmlcollected(e,"/mml:mtd") do -- nested we can use xml.collected
col = col + 1
if ignorelabel and col == 1 then
-- get rid of label, should happen at the document level
else
local at = e.at
- local rowspan, columnspan = at.rowspan or 1, at.columnspan or 1
+ local rowspan = at.rowspan or 1
+ local columnspan = at.columnspan or 1
local cra = rowalignments [at.rowalign or (rowaligns and rowaligns [col]) or rra or "center"] or "lohi"
local cca = columnalignments[at.columnalign or (columnaligns and columnaligns[col]) or rca or "center"] or "middle"
local cfr = frametypes [at.frame or (frames and frames [col]) or rfr or "none" ] or "off"
- context.bTD { align = format("{%s,%s}",cra,cca), frame = cfr, nx = columnspan, ny = rowspan }
- context.startimath()
- context.ignorespaces()
- xmlcprint(e)
- context.stopimath()
- context.removeunwantedspaces()
- context.eTD()
+ ctx_bTD { align = formatters["{%s,%s}"](cra,cca), frame = cfr, nx = columnspan, ny = rowspan }
+ if xmlempty(e,".") then
+ -- nothing, else hsize max
+ else
+ ctx_startimath()
+ -- ctx_ignorespaces()
+ xmlcprint(e)
+ -- ctx_removeunwantedspaces()
+ ctx_stopimath()
+ end
+ ctx_eTD()
end
end
-- if e.tg == "mlabeledtr" then
- -- context.bTD()
+ -- ctx_bTD()
-- xmlcprint(xml.first(e,"/!mml:mtd"))
- -- context.eTD()
+ -- ctx_eTD()
-- end
- context.eTR()
+ ctx_eTR()
end
- context.eTABLE()
+ ctx_eTABLE()
end
function mathml.csymbol(root)
@@ -804,14 +852,16 @@ function mathml.csymbol(root)
local full = hash.original or ""
local base = hash.path or ""
local text = strip(xmltext(root) or "")
- context.mmlapplycsymbol(full,base,encoding,text)
+ ctx_mmlapplycsymbol(full,base,encoding,text)
end
+local p = lpeg.Cs(((1-lpegpatterns.whitespace)^1 / "mml:enclose:%0" + (lpegpatterns.whitespace^1)/",")^1)
+
function mathml.menclosepattern(root)
root = getid(root)
local a = root.at.notation
if a and a ~= "" then
- context("mml:enclose:",(gsub(a," +",",mml:enclose:")))
+ context(lpegmatch(p,a))
end
end
@@ -822,8 +872,8 @@ end
function mathml.cpolar_a(root)
root = getid(root)
local dt = root.dt
- context.mathopnolimits("Polar")
- context.left(false,"(")
+ ctx_mathopnolimits("Polar")
+ ctx_left(false,"(")
for k=1,#dt do
local dk = dt[k]
if xml.is_element(dk,"sep") then
@@ -832,7 +882,7 @@ function mathml.cpolar_a(root)
xmlsprint(dk)
end
end
- context.right(false,")")
+ ctx_right(false,")")
end
-- crap .. maybe in char-def a mathml overload
diff --git a/Master/texmf-dist/tex/context/base/x-mathml.mkiv b/Master/texmf-dist/tex/context/base/x-mathml.mkiv
index 5520dbbe6fc..65a7223ce59 100644
--- a/Master/texmf-dist/tex/context/base/x-mathml.mkiv
+++ b/Master/texmf-dist/tex/context/base/x-mathml.mkiv
@@ -1,4 +1,4 @@
-%D \modul
+%D \module
%D [ file=x-mathml,
%D version=2008.05.29,
%D title=\CONTEXT\ XML Modules,
@@ -16,12 +16,17 @@
% This module is under construction and will be cleaned up. We use a funny mix of
% xml, tex and lua. I could rewrite the lot but it also shows how context evolves.
%
-% I might en dup with a lua-only implementation some day.
+% I might end up with a lua-only implementation some day. I must find a good reason
+% to spend time on it. In fact, it might even be more messy.
%
% no m:text strip (needs checking, maybe nbsp is mandate
%
% todo: more will be moved to lua (less hassle)
% todo: move left/right to the lua end
+%
+% this implememation looks like a hack ... this is because we deal with all weird cases we
+% ran into, including abuse that was supposed to render ok (even if it didn't in other
+% renderers) .. it was simply expected to work that way.
\writestatus{loading}{ConTeXt XML Macros / MathML Renderer}
@@ -51,10 +56,10 @@
\xmlregistersetup{xml:mml:define}
-\unexpanded\def\MMLhack
- {\let\MMLpar\par
- \let\par\relax
- \everyvbox{\let\par\MMLpar}}
+% \unexpanded\def\MMLhack % no longer needed
+% {\let\MMLpar\par
+% \let\par\relax
+% \everyvbox{\let\par\MMLpar}}
\xmlmapvalue {mml:math:mode} {display} {\displaymathematics} % we had this already
\xmlmapvalue {mml:math:mode} {inline} {\inlinemathematics }
@@ -75,7 +80,7 @@
}
{
\math_fences_checked_start
- \MMLhack
+ %\MMLhack
\xmlflush{#1}
\math_fences_checked_stop
}
@@ -85,7 +90,7 @@
\startxmlsetups mml:imath
\inlinemathematics {
\math_fences_checked_start
- \MMLhack
+ %\MMLhack
\xmlflush{#1}
\math_fences_checked_stop
}
@@ -94,7 +99,7 @@
\startxmlsetups mml:dmath
\displaymathematics {
\math_fences_checked_start
- \MMLhack
+ %\MMLhack
\xmlflush{#1}
\math_fences_checked_stop
}
@@ -106,7 +111,10 @@
\edef\mmlformulalabel {\xmlatt{#1}{label}\xmlatt{#1}{id}}
\edef\mmlformulasublabel{\xmlatt{#1}{sublabel}\xmlatt{#1}{id}}
\doifsomething\mmlformulalabel{\placeformula[\mmlformulalabel]{\mmlformulasublabel}}
- \startformula\MMLhack\xmlfirst{#1}{/mml:math}\stopformula
+ \startformula
+ %\MMLhack
+ \xmlfirst{#1}{/mml:math}
+ \stopformula
\stopxmlsetups
% old delimiter hacks
@@ -164,11 +172,6 @@
%D filter. There is an intermediate cleaner module but it has
%D some namespace limitations. Here we do it the \MKIV\ way.
-\def\widevec#1%
- {\vbox{\mathsurround\zeropoint\ialign{##\crcr
- \rightarrowfill\crcr\noalign{\nointerlineskip}%
- \startimath\hfil\displaystyle{#1}\hfil\stopimath\crcr}}}
-
%D The rendering macros:
\def\MMLrm{\mr}
@@ -209,7 +212,9 @@
%D We start with the parent elements and the option handler.
-\def\xmlmathmldirective#1{\dosetvalue{MML#1}}
+\unexpanded\def\xmlmathmldirective#1{\dosetvalue{MML#1}}
+
+\xmlinstalldirective{mathml}{xmlmathmldirective}
%def\xmlmathmldirective#1#2#3{[#1][#2][#3]\dosetvalue{MML#1}{#2}{#3}}
@@ -378,7 +383,7 @@
% \MMLdoR
% } {
\edef\mmlapplyaction{\xmlfilter{#1}{/*/name()}}
- \doifsetupselse {mml:apply:mml:\mmlapplyaction} {
+ \doifelsesetups {mml:apply:mml:\mmlapplyaction} {
\xmlsetup{#1}{mml:apply:mml:\mmlapplyaction}
} {
% \MMLdoL
@@ -399,7 +404,7 @@
\startxmlsetups mml:apply:mml:fn
\xmldoifelse {#1} {/mml:fn/mml:ci} {
\edef\mmlfnci{\xmlstripped{#1}{/mml:fn/mml:ci}}% was xmlcontent
- \doifsetupselse{mmc:fn:\mmlfnci} { % was mmc:fn:...
+ \doifelsesetups{mmc:fn:\mmlfnci} { % was mmc:fn:...
\xmlsetup{#1}{mmc:fn:\mmlfnci} % \MMLdoL/MMLdoR to be handled in plugin
} {
\MMLcreset
@@ -466,7 +471,7 @@
\fi
\xmldoifelse {#1} {/mml:ci} { % first
\edef\mmlfnci{\xmltext{#1}{/mml:ci}}% was xmlcontent
- \doifsetupselse{mmc:fn:\mmlfnci} { % was mmc:fn:...
+ \doifelsesetups{mmc:fn:\mmlfnci} { % was mmc:fn:...
\xmlsetup{#1}{mmc:fn:\mmlfnci} % \MMLdoL/MMLdoR to be handled in plugin
} {
\MMLcreset
@@ -497,7 +502,7 @@
\startxmlsetups mmc:fn:apply % where used?
\xmldoifelse {#1} {/mml:ci} { % first
\edef\mmlfnci{\xmltext{#1}{/mml:ci}}% was xmlcontent
- \doifsetupselse{mmc:fn:\mmlfnci} { % was mmc:fn:...
+ \doifelsesetups{mmc:fn:\mmlfnci} { % was mmc:fn:...
\xmlsetup{#1}{mmc:fn:\mmlfnci} % \MMLdoL/MMLdoR to be handled in plugin
} {
\MMLcreset
@@ -524,16 +529,15 @@
\starttexdefinition mmlapplycsymbol #1#2#3#4
% #1=full url, #2=name, #3=encoding, #4=text
\doifelse {#3} {text} {
-% {\mr #4}
\text{#4}
} {
- \doifsetupselse {mml:csymbol:#1} {
+ \doifelsesetups {mml:csymbol:#1} {
% full url
- \directsetup{mml:csymbol:#1}
+ \fastsetup{mml:csymbol:#1}
} {
% somename (fallback)
- \doifsetupselse {mml:csymbol:#2} {
- \directsetup{mml:csymbol:#2}
+ \doifelsesetups {mml:csymbol:#2} {
+ \fastsetup{mml:csymbol:#2}
} {
\xmlval{mmc:cs}{#3}{}% todo
}
@@ -580,7 +584,7 @@
\stopxmlsetups
\startxmlsetups mml:ci:vector
- \widevec{\xmlflush{#1}}
+ \overrightarrow{\xmlflush{#1}}
\stopxmlsetups
\startxmlsetups mml:ci:matrix
@@ -720,7 +724,7 @@
\startxmlsetups mml:cn:rational
\xmldoifelse {#1} {/mml:sep} {
- \frac
+ \mmlfrac
{\xmlsnippet{#1}{1}}
{\xmlsnippet{#1}{3}}
} {
@@ -905,7 +909,7 @@
\mmlsecond{#1}/\mmlthird{#1}
\else
\MMLcreset
- \frac{\MMLcreset\mmlsecond{#1}}{\MMLcreset\mmlthird{#1}}
+ \mmlfrac{\MMLcreset\mmlsecond{#1}}{\MMLcreset\mmlthird{#1}}
\fi
}
\advance\mmldividelevel\minusone
@@ -1051,7 +1055,7 @@
\let\MMLtimes@@symbol\MMLtimessymbol
} {
\xmldoifelse {#1} {/mml:cn[name(1) == 'mml:cn']} {% name(1) is next one
- \doifinsetelse\MMLtimessymbol{\v!yes,\v!no} {
+ \doifelseinset\MMLtimessymbol{\v!yes,\v!no} {
\let\MMLtimes@@symbol\v!yes
} {
\let\MMLtimes@@symbol\MMLtimessymbol
@@ -1303,7 +1307,7 @@
\doifelse \MMLdiffalternative \v!a {
\xmldoifelse {#1} {/mml:lambda} {
% a special case (mathadore/openmath)
- \frac {
+ \mmlfrac {
d
\normalsuperscript
{\xmlfirst{#1}{/mml:bvar}\xmlfirst{#1}{/mml:cn}}
@@ -1316,7 +1320,7 @@
}
} {
\xmldoifelse {#1} {/mml:bvar} {
- \frac {
+ \mmlfrac {
{\mr d}{
\xmldoifelse {#1} {/mml:degree} {
\normalsuperscript{\xmlconcat{#1}{/mml:degree}\empty}
@@ -1331,13 +1335,11 @@
\xmlfirst{#1}{/mml:ci}
} {
\MMLcreset
-\ifnum\xmlcount{#1}{/mml:apply/*}>\plustwo % hack
- \left(
- \xmlfirst{#1}{/mml:apply}
- \right)
-\else
- \xmlfirst{#1}{/mml:apply}
-\fi
+ \ifnum\xmlcount{#1}{/mml:apply/*}>\plustwo % hack
+ \left(\xmlfirst{#1}{/mml:apply}\right)
+ \else
+ \xmlfirst{#1}{/mml:apply}
+ \fi
}
}
} {
@@ -1387,7 +1389,7 @@
\xmlfirst{#1}{/(mml:apply\string|mml:reln\string|mml:ci\string|mml:cn)}
} {
\xmldoifelse {#1} {/mml:bvar} {
- \frac {
+ \mmlfrac {
{\mr d}\normalsuperscript{
\xmldoifelse {#1} {/mml:degree} {
\xmlconcat{#1}{/mml:degree}\empty
@@ -1709,7 +1711,7 @@
\stopxmlsetups
\startxmlsetups mml:annotation
- \xmldoifelse {#1} {.[oneof(@encoding,'TeX','tex','TEX','ConTeXt','context','CONTEXT','ctx')]} {
+ \xmldoifelse {#1} {.[oneof(@encoding,'TeX','tex','application/x-tex','TEX','ConTeXt','context','CONTEXT','ctx')]} {
\xmlflushcontext{#1}
} {
\xmldoifelse {#1} {.[oneof(@encoding,'calcmath','cm')]} {
@@ -1745,7 +1747,7 @@
\startxmlsetups mml:notanumber \mathopnolimits{NaN} \stopxmlsetups
\startxmlsetups mml:true \mathopnolimits{true} \stopxmlsetups
\startxmlsetups mml:false \mathopnolimits{false} \stopxmlsetups
-\startxmlsetups mml:emptyset \mathopnolimits{\O} \stopxmlsetups
+\startxmlsetups mml:emptyset \mathopnolimits{Ø} \stopxmlsetups
\startxmlsetups mml:pi \pi \stopxmlsetups
\startxmlsetups mml:eulergamma \gamma \stopxmlsetups
\startxmlsetups mml:infinity \infty \stopxmlsetups
@@ -1824,25 +1826,33 @@
% helpers: maybe we can need a setting for the uprights
-\xmlmapvalue {mml} {normal} {\mathupright} % {\mathtf}
-\xmlmapvalue {mml} {double-struck} {\mathblackboard}
-\xmlmapvalue {mml} {italic} {\mathit}
-\xmlmapvalue {mml} {fraktur} {\mathfraktur}
-\xmlmapvalue {mml} {script} {\mathscript}
-\xmlmapvalue {mml} {bold} {\mb} % {\mathbf}
-\xmlmapvalue {mml} {bold-italic} {\mathbi}
-\xmlmapvalue {mml} {bold-fraktur} {\mathfraktur\mathbf}
-\xmlmapvalue {mml} {bold-script} {\mathscript\mathbf}
-\xmlmapvalue {mml} {sans-serif} {\mathss}
-\xmlmapvalue {mml} {bold-sans-serif} {\mathss\mathbf}
-\xmlmapvalue {mml} {sans-serif-italic} {\mathss\mathit}
-\xmlmapvalue {mml} {sans-serif-bold-italic} {\mathss\mathbi}
-\xmlmapvalue {mml} {monospace} {\mathtt}
+\xmlmapvalue {mml:s} {normal} {\mathupright} % {\mathtf}
+\xmlmapvalue {mml:s} {double-struck} {\mathblackboard}
+\xmlmapvalue {mml:s} {italic} {\mathit}
+\xmlmapvalue {mml:s} {fraktur} {\mathfraktur}
+\xmlmapvalue {mml:s} {script} {\mathscript}
+\xmlmapvalue {mml:s} {bold} {\mb} % {\mathbf}
+\xmlmapvalue {mml:s} {bold-italic} {\mathbi}
+\xmlmapvalue {mml:s} {bold-fraktur} {\mathfraktur\mathbf}
+\xmlmapvalue {mml:s} {bold-script} {\mathscript\mathbf}
+\xmlmapvalue {mml:s} {sans-serif} {\mathss}
+\xmlmapvalue {mml:s} {bold-sans-serif} {\mathss\mathbf}
+\xmlmapvalue {mml:s} {sans-serif-italic} {\mathss\mathit}
+\xmlmapvalue {mml:s} {sans-serif-bold-italic} {\mathss\mathbi}
+\xmlmapvalue {mml:s} {monospace} {\mathtt}
+
+\xmlmapvalue {mml:l} {-} {\let\mmlfrac\tfrac}
+ \let\mmlfrac\frac
+\xmlmapvalue {mml:l} {+} {\let\mmlfrac\sfrac}
% todo: displaystyle=true/false (or whatever else shows up)
\starttexdefinition setmmlmathstyle #1
- \xmlval {mml} {\xmlatt{#1}{mathvariant}} \empty % was: \mmmr
+ \xmlval{mml:s}{\xmlatt{#1}{mathvariant}}\empty % was: \mmmr
+\stoptexdefinition
+
+\starttexdefinition setmmlscriptlevel #1
+ \xmlval{mml:l}{\xmlatt{#1}{scriptlevel}}{\let\mmlfrac\frac}
\stoptexdefinition
\starttexdefinition applymmlmathcolor #1#2
@@ -1899,8 +1909,11 @@
\startxmlsetups mml:mi % todo: mathsize (unlikely) mathcolor (easy) mathbackground (easy)
\begingroup
+ \pushmathstyle
\setmmlmathstyle{#1}
+ \setmmlscriptlevel{#1}
\ctxmodulemathml{mi("#1")}
+ \popmathstyle
\endgroup
\stopxmlsetups
@@ -2000,7 +2013,7 @@
\overline{\left)\strut\xmlflush{#1}\right.}
} {
\doifelse \mmlmenclosenotation {mml:enclose:actuarial} {
- \overline{\left.\strut\xmlflush{#1}\right|}
+ \overline{\left.\strut\xmlflush{#1}\right\vert}
} {
\doifelse \mmlmenclosenotation {mml:enclose:radical} {
\sqrt{\xmlflush{#1}}
@@ -2010,13 +2023,13 @@
\framed
[frame=off,strut=no,background={\mmlmenclosenotation}] % offset is kind of undefined
{\startimath
- \expanded{\doifinsetelse {mml:enclose:longdiv} {\mmlmenclosenotation}} {
+ \expanded{\doifelseinset {mml:enclose:longdiv} {\mmlmenclosenotation}} {
\overline{\left)\strut\xmlflush{#1}\right.}
} {
- \expanded{\doifinsetelse {mml:enclose:actuarial} {\mmlmenclosenotation}} {
- \overline{\left.\strut\xmlflush{#1}\right|}
+ \expanded{\doifelseinset {mml:enclose:actuarial} {\mmlmenclosenotation}} {
+ \overline{\left.\strut\xmlflush{#1}\right\vert}
} {
- \expanded{\doifinsetelse {mml:enclose:radical} {\mmlmenclosenotation}} {
+ \expanded{\doifelseinset {mml:enclose:radical} {\mmlmenclosenotation}} {
\sqrt{\xmlflush{#1}}
} {
\xmlflush{#1}
@@ -2043,7 +2056,7 @@
\doifelse{\xmlatt{#1}{bevelled}}{true} {
\left.\mmlfirst{#1}\middle/\mmlsecond{#1}\right.% \thinspace\middle/\thinspace
} {
- \frac{\mmlfirst{#1}}{\mmlsecond{#1}}
+ \mmlfrac{\mmlfirst{#1}}{\mmlsecond{#1}}
}
\else
\doifelse {\xmlval{mml:mfrac:linethickness}{\mmlfraclinethickness}{}} {} {
@@ -2074,8 +2087,11 @@
\startxmlsetups mml:mstyle
\begingroup
+ \pushmathstyle
\setmmlmathstyle{#1}
+ \setmmlscriptlevel{#1}
\xmlflush{#1}
+ \popmathstyle
\endgroup
\stopxmlsetups
@@ -2230,6 +2246,8 @@
}
\stopxmlsetups
+% helpers
+
\unexpanded\def\mmlexecuteifdefined#1%
{\ifx#1\empty
\expandafter\secondoftwoarguments
@@ -2240,140 +2258,166 @@
\fi\fi
{\csname#1\endcsname}}
-% todo: combine topaccent/over/bottomaccent/under check
-
-\definemathextensible [\v!mathematics] [mml:overleftarrow] ["2190] % ["27F5]
-\definemathextensible [\v!mathematics] [mml:overrightarrow] ["2192] % ["27F6]
-\definemathextensible [\v!mathematics] [mml:overleftrightarrow] ["27F7]
-\definemathextensible [\v!mathematics] [mml:overtwoheadrightarrow] ["27F9]
-\definemathextensible [\v!mathematics] [mml:overleftharpoondown] ["21BD]
-\definemathextensible [\v!mathematics] [mml:overleftharpoonup] ["21BC]
-\definemathextensible [\v!mathematics] [mml:overrightharpoondown] ["21C1]
-\definemathextensible [\v!mathematics] [mml:overrightharpoonup] ["21C0]
-
-\definemathextensible [\v!mathematics] [mml:underleftarrow] ["2190] % ["27F5]
-\definemathextensible [\v!mathematics] [mml:underrightarrow] ["2192] % ["27F6]
-\definemathextensible [\v!mathematics] [mml:underleftrightarrow] ["27F7]
-\definemathextensible [\v!mathematics] [mml:undertwoheadrightarrow] ["27F9]
-\definemathextensible [\v!mathematics] [mml:underleftharpoondown] ["21BD]
-\definemathextensible [\v!mathematics] [mml:underleftharpoonup] ["21BC]
-\definemathextensible [\v!mathematics] [mml:underrightharpoondown] ["21C1]
-\definemathextensible [\v!mathematics] [mml:underrightharpoonup] ["21C0]
-
-\definemathtriplet [\v!mathematics] [mmlovertriplet]
-\definemathtriplet [\v!mathematics] [mmlundertriplet]
-\definemathtriplet [\v!mathematics] [mmldoubletriplet]
-
-% alternative:
-%
-% \definemathextensible [\v!mathematics] [mml:\utfchar{0x2190}] ["2190] % ["27F5]
-% \definemathextensible [\v!mathematics] [mml:\utfchar{0x2192}] ["2192] % ["27F6]
-% \definemathextensible [\v!mathematics] [mml:\utfchar{0x27F5}] ["2190] % ["27F5]
-% \definemathextensible [\v!mathematics] [mml:\utfchar{0x27F6}] ["2192] % ["27F6]
-% \definemathextensible [\v!mathematics] [mml:\utfchar{0x27F7}] ["27F7]
-% \definemathextensible [\v!mathematics] [mml:\utfchar{0x27F9}] ["27F9]
-% \definemathextensible [\v!mathematics] [mml:\utfchar{0x21BD}] ["21BD]
-% \definemathextensible [\v!mathematics] [mml:\utfchar{0x21BC}] ["21BC]
-% \definemathextensible [\v!mathematics] [mml:\utfchar{0x21C1}] ["21C1]
-% \definemathextensible [\v!mathematics] [mml:\utfchar{0x21C0}] ["21C0]
-
-\unexpanded\def\mmloverof#1{\mmlexecuteifdefined\mmlovercommand\relax{\mmlunexpandedfirst {#1}}\relax}
-\unexpanded\def\mmloveros#1{\mmlexecuteifdefined\mmlovercommand {\mmlunexpandedsecond{#1}}\relax}
-\unexpanded\def\mmloverbf#1{\mmlexecuteifdefined\mmlbasecommand {\mmlunexpandedfirst {#1}}\relax}
-\unexpanded\def\mmloverbs#1{\mmlexecuteifdefined\mmlbasecommand\relax{\mmlunexpandedsecond{#1}}\relax}
+\def\mmlextensible#1{\ctxmodulemathml{extensible(\!!bs#1\!!es)}}
-\startxmlsetups mml:mover
+\definemathtriplet [\v!mathematics] [mmlovertriplet] % or will we use a special instance
+\definemathtriplet [\v!mathematics] [mmlundertriplet] % or will we use a special instance
+\definemathtriplet [\v!mathematics] [mmldoubletriplet] % or will we use a special instance
+
+% common to munder/mover/munderover
+
+\starttexdefinition unexpanded mmlfencedfirst #1
+ \math_fences_checked_start
+ \mmlunexpandedfirst{#1}
+ \math_fences_checked_stop
+\stoptexdefinition
+\starttexdefinition unexpanded mmlfencedsecond #1
+ \math_fences_checked_start
+ \mmlunexpandedsecond{#1}
+ \math_fences_checked_stop
+\stoptexdefinition
+\starttexdefinition unexpanded mmlfencedthird #1
+ \math_fences_checked_start
+ \mmlunexpandedthird{#1}
+ \math_fences_checked_stop
+\stoptexdefinition
+
+% mover
+
+\starttexdefinition unexpanded mmloverabove #1
+ \edef\mmlovercommand{\utfmathfiller\mmlovertoken}
+ \mmlexecuteifdefined\mmlovercommand {\mmlfencedsecond{#1}} \relax
+\stoptexdefinition
+\starttexdefinition unexpanded mmloverbase #1
+ \edef\mmlbasecommand{\utfmathfiller\mmlbasetoken}
+ \mmlexecuteifdefined\mmlbasecommand {\mmlfencedfirst{#1}}
+ \relax
+\stoptexdefinition
+\starttexdefinition unexpanded mmloverbasefiller #1
+ \edef\mmlbasecommand{e\utfmathcommandfiller\mmlbasetoken}
+ \mmlexecuteifdefined\mmlbasecommand \relax {\mmlfencedsecond{#1}} {}
+\stoptexdefinition
+\starttexdefinition unexpanded mmloveraccent #1
+ \edef\mmlovercommand{\utfmathcommandabove\mmlovertoken}
+ \mmlexecuteifdefined\mmlovercommand \relax {\mmlfencedfirst{#1}}
+\stoptexdefinition
+\starttexdefinition unexpanded mmlovertext #1
+ \mmlovertriplet {\mmloverbase{#1}} {\mmloverabove{#1}} {}
+\stoptexdefinition
+\starttexdefinition unexpanded mmloveraccentchecker #1
\edef\mmlovertoken{\mmlextensible{\xmlraw{#1}{/mml:*[2]}}}% /text()
- \doifelseutfmathabove\mmlovertoken {
- \edef\mmlovercommand{\utfmathcommandabove\mmlovertoken}
- \mmloverof{#1}
- } {
- \edef\mmlbasetoken{\xmlraw{#1}{/mml:*[1]}}% /text()
- \doifelseutfmathabove\mmlbasetoken {
- \edef\mmlbasecommand{mml:\utfmathcommandabove\mmlbasetoken}
- \mmloverbs{#1}
- } {
- \edef\mmlbasecommand{\utfmathfiller\mmlbasetoken}
- \edef\mmlovercommand{\utfmathfiller\mmlovertoken}
- \mmlundertriplet{\mmloverbf{#1}}{\mmloveros{#1}}{}%\relax
- }
- }
- % \limits % spoils spacing
+ \doifelseutfmathabove\mmlovertoken \mmloveraccent \mmlovertext {#1}
+\stoptexdefinition
+
+\startxmlsetups mml:mover
+ \edef\mmlbasetoken{\mmlextensible{\xmlraw{#1}{/mml:*[1]}}}% /text()
+ \doifelseutfmathfiller\mmlbasetoken \mmloverbasefiller \mmloveraccentchecker {#1}
\stopxmlsetups
-% alternative:
-%
-% \startxmlsetups mml:mover
-% \edef\mmlovertoken{\xmlraw{#1}{/mml:*[2]}}% /text()
-% \doifelseutfmathabove\mmlovertoken {
-% \edef\mmlovercommand{\utfmathcommandabove\mmlovertoken}
-% \mmloverof{#1}
-% } {
-% \edef\mmlbasetoken{\xmlraw{#1}{/mml:*[1]/text()}}
-% \ifcsname mml:\mmlbasetoken\endcsname
-% \csname mml:\mmlbasetoken\endcsname{\mmlunexpandedsecond{#1}}\relax
-% \else
-% \edef\mmlbasecommand{\utfmathfiller\mmlbasetoken}
-% \edef\mmlovercommand{\utfmathfiller\mmlovertoken}
-% \mmlovertriplet{\mmloveros{#1}}{\mmloverbf{#1}}\relax
-% \fi
-% }
-% % \limits % spoils spacing
-% \stopxmlsetups
+% munder
-% do this in lua
+\starttexdefinition unexpanded mmlunderbelow #1
+ \edef\mmlundercommand{\utfmathfiller\mmlundertoken}
+ \mmlexecuteifdefined\mmlundercommand {\mmlfencedsecond{#1}} \relax
+\stoptexdefinition
+\starttexdefinition unexpanded mmlunderbase #1
+ \edef\mmlbasecommand{\utfmathfiller\mmlbasetoken}
+ \mmlexecuteifdefined\mmlbasecommand {\mmlfencedfirst{#1}}
+ \relax
+\stoptexdefinition
+\starttexdefinition unexpanded mmlunderbasefiller #1
+ \edef\mmlbasecommand{e\utfmathcommandfiller\mmlbasetoken}%
+ \mmlexecuteifdefined\mmlbasecommand \relax {} {\mmlfencedsecond{#1}}
+\stoptexdefinition
+\starttexdefinition unexpanded mmlunderaccent #1
+ \edef\mmlundercommand{\utfmathcommandbelow\mmlundertoken}
+ \mmlexecuteifdefined\mmlundercommand \relax {\mmlfencedfirst{#1}}
+\stoptexdefinition
+\starttexdefinition unexpanded mmlundertext #1
+ \mmlundertriplet {\mmlunderbase{#1}} {} {\mmlunderbelow{#1}}
+\stoptexdefinition
+\starttexdefinition unexpanded mmlunderaccentchecker #1
+ \edef\mmlundertoken{\mmlextensible{\xmlraw{#1}{/mml:*[2]}}}% /text()
+ \doifelseutfmathbelow\mmlundertoken \mmlunderaccent \mmlundertext {#1}
+\stoptexdefinition
-\def\mmlextensible#1{\ctxmodulemathml{extensible(\!!bs#1\!!es)}}
+\startxmlsetups mml:munder
+ \edef\mmlbasetoken{\mmlextensible{\xmlraw{#1}{/mml:*[1]}}}% /text()
+ \doifelseutfmathfiller\mmlbasetoken \mmlunderbasefiller \mmlunderaccentchecker {#1}
+\stopxmlsetups
-\unexpanded\def\mmlunderuf#1{\mmlexecuteifdefined\mmlundercommand\relax {\mmlunexpandedfirst {#1}}\relax}
-\unexpanded\def\mmlunderus#1{\mmlexecuteifdefined\mmlundercommand {\mmlunexpandedsecond{#1}}\relax}
-\unexpanded\def\mmlunderbf#1{\mmlexecuteifdefined\mmlbasecommand {\mmlunexpandedfirst {#1}}\relax}
-%unexpanded\def\mmlunderbs#1{\mmlexecuteifdefined\mmlbasecommand \relax{}{\mmlunexpandedsecond{#1}}\relax}
-\unexpanded\def\mmlunderbs#1{\mmlexecuteifdefined\mmlbasecommand \relax {\mmlunexpandedsecond{#1}}\relax}
+% munderover
-\startxmlsetups mml:munder
+\starttexdefinition unexpanded mmlunderoveraccentcheckerUO #1
+ \edef\mmlundercommand{\utfmathcommandbelow\mmlundertoken}
+ \edef\mmlovercommand {\utfmathcommandabove\mmlovertoken}
+ \edef\mmlbasecommand {\mmlovercommand\mmlundercommand}
+ \ifcsname\mmlbasecommand\endcsname
+ \csname\mmlbasecommand\endcsname {\mmlfencedfirst{#1}}
+ \else\ifcsname\mmlundercommand\endcsname
+ \ifcsname\mmlovercommand\endcsname
+ \csname\mmlovercommand\endcsname {\csname\mmlundercommand\endcsname{\mmlfencedfirst{#1}}}
+ \else
+ \mmldoubletriplet {\csname\mmlundercommand\endcsname{\mmlfencedfirst{#1}}} {\mmlfencedthird{#1}\mmlfencedthird{#1}} {}
+ \fi
+ \else\ifcsname\mmlovercommand\endcsname
+ \mmldoubletriplet {\csname\mmlovercommand\endcsname{\mmlfencedfirst{#1}}} {} {\mmlfencedsecond{#1}}
+ \else
+ \mmlunderoveraccentcheckerTT {#1}
+ \fi\fi\fi
+\stoptexdefinition
+\starttexdefinition unexpanded mmlunderoveraccentcheckerUT #1
+ \edef\mmlundercommand{\utfmathcommandbelow\mmlundertoken}
+ \edef\mmlbasecommand {\mmlundercommand text}
+ \ifcsname\mmlbasecommand\endcsname
+ \csname\mmlbasecommand\endcsname {\mmlfencedfirst{#1}} {\mmlfencedthird{#1}}
+ \else\ifcsname\mmlundercommand\endcsname
+ \mmldoubletriplet {\csname\mmlundercommand\endcsname{\mmlfencedfirst{#1}}} {\mmlfencedthird{#1}} {}
+ \else
+ \mmlunderoveraccentcheckerTT {#1}
+ \fi\fi
+\stoptexdefinition
+\starttexdefinition unexpanded mmlunderoveraccentcheckerOT #1
+ \edef\mmlovercommand{\utfmathcommandabove\mmlovertoken}
+ \edef\mmlbasecommand{\mmlovercommand text}
+ \ifcsname\mmlbasecommand\endcsname
+ \csname\mmlbasecommand\endcsname {\mmlfencedfirst{#1}} {\mmlfencedsecond{#1}}
+ \else\ifcsname\mmlovercommand\endcsname
+ \mmldoubletriplet {\csname\mmlovercommand\endcsname{\mmlfencedfirst{#1}}} {} {\mmlfencedsecond{#1}}
+ \else
+ \mmlunderoveraccentcheckerTT {#1}
+ \fi\fi
+\stoptexdefinition
+\starttexdefinition unexpanded mmlunderoveraccentcheckerTT #1
+ \mmldoubletriplet {\mmlfencedfirst{#1}} {\mmlfencedthird{#1}} {\mmlfencedsecond{#1}} \relax
+\stoptexdefinition
+\starttexdefinition unexpanded mmlunderoveraccentchecker #1
\edef\mmlundertoken{\mmlextensible{\xmlraw{#1}{/mml:*[2]}}}% /text()
- \doifelseutfmathbelow\mmlundertoken {%
- \edef\mmlundercommand{\utfmathcommandbelow\mmlundertoken}
- \mmlunderuf{#1}
+ \edef\mmlovertoken {\mmlextensible{\xmlraw{#1}{/mml:*[3]}}}% /text()
+ \doifelseutfmathbelow\mmlundertoken {
+ \doifelseutfmathabove\mmlovertoken \mmlunderoveraccentcheckerUO \mmlunderoveraccentcheckerUT {#1}
} {
- \edef\mmlbasetoken{\xmlraw{#1}{/mml:*[1]}}% /text()
- \doifelseutfmathbelow\mmlbasetoken {
- \edef\mmlbasecommand{mml:\utfmathcommandbelow\mmlbasetoken}
- \mmlunderbs{#1}
- } {
- \edef\mmlbasecommand {\utfmathfiller\mmlbasetoken}
- \edef\mmlundercommand{\utfmathfiller\mmlundertoken}
- \mmlundertriplet{\mmlunderbf{#1}}{}{\mmlunderus{#1}}%\relax
- }
+ \doifelseutfmathabove\mmlovertoken \mmlunderoveraccentcheckerOT \mmlunderoveraccentcheckerTT {#1}
}
- % \limits % spoils spacing
-\stopxmlsetups
-
-\unexpanded\def\mmlunderoverst#1{\mmlexecuteifdefined\mmlbasecommand \relax{\mmlunexpandedsecond{#1}}{\mmlunexpandedthird{#1}}\relax}
-\unexpanded\def\mmlunderoverbf#1{\mmlexecuteifdefined\mmlbasecommand {\mmlunexpandedfirst {#1}}\relax}
-\unexpanded\def\mmlunderoverus#1{\mmlexecuteifdefined\mmlundercommand {\mmlunexpandedsecond{#1}}\relax}
-\unexpanded\def\mmlunderoverot#1{\mmlexecuteifdefined\mmlovercommand {\mmlunexpandedthird {#1}}\relax}
+\stoptexdefinition
+\starttexdefinition unexpanded mmlunderoverbasefiller #1
+ \edef\mmlbasecommand{e\utfmathcommandfiller\mmlbasetoken}%
+ \mmlexecuteifdefined\mmlbasecommand \relax {\mmlfencedthird{#1}} {\mmlfencedsecond{#1}}
+\stoptexdefinition
\startxmlsetups mml:munderover
- \edef\mmlbasetoken{\xmlraw{#1}{/mml:*[1]}}% /text()
- \doifelseutfmathbelow\mmlbasetoken {
- \edef\mmlbasecommand{mml:\utfmathcommandbelow\mmlbasetoken}
- \mmlunderoverst{#1}
- } {
- \edef\mmlundertoken {\xmlraw{#1}{/mml:*[2]}}% /text()
- \edef\mmlovertoken {\xmlraw{#1}{/mml:*[3]}}% /text()
- \edef\mmlbasecommand {\utfmathfiller\mmlbasetoken}
- \edef\mmlundercommand{\utfmathfiller\mmlundertoken}
- \edef\mmlovercommand {\utfmathfiller\mmlovertoken}
- \mmldoubletriplet{\mmlunderoverbf{#1}}{\mmlunderoverot{#1}}{\mmlunderoverus{#1}}\relax
- }
+ \edef\mmlbasetoken{\mmlextensible{\xmlraw{#1}{/mml:*[1]}}}% /text()
+ \doifelseutfmathfiller\mmlbasetoken \mmlunderoverbasefiller \mmlunderoveraccentchecker {#1}
\stopxmlsetups
% tables (mml:mtable, mml:mtr, mml:mlabledtr, mml:mtd)
\startxmlsetups mml:mtable % some more attributes need to be supported
- \vcenter{\ctxmodulemathml{mtable("#1")}}
+ \vcenter {
+ \hbox {% needed because otherwise positions makr the vcenter wide
+ \ctxmodulemathml{mtable("#1")}
+ }
+ }
\stopxmlsetups
\startxmlsetups mml:mcolumn
@@ -2383,29 +2427,39 @@
\def\mmlsetfakewidth#1{\setbox\scratchbox\hbox{#1}\scratchdimen\wd\scratchbox}
\def\mmlmcolumndigitspace {\mmlsetfakewidth {0}\kern\scratchdimen}
-\def\mmlmcolumndigitrule {\mmlsetfakewidth {0}\vrule width \scratchdimen height .2pt depth .2pt\relax}
-\def\mmlmcolumnsymbolrule {\mmlsetfakewidth{\times}\vrule width \scratchdimen height .2pt depth .2pt\relax}
-\def\mmlmcolumnpunctuationrule{\mmlsetfakewidth {.}\vrule width \scratchdimen height .2pt depth .2pt\relax}
+\def\mmlmcolumndigitrule {\mmlsetfakewidth {0}\vrule \s!width \scratchdimen \s!height .2\points \s!depth .2\points\relax}
+\def\mmlmcolumnsymbolrule {\mmlsetfakewidth{\times}\vrule \s!width \scratchdimen \s!height .2\points \s!depth .2\points\relax}
+\def\mmlmcolumnpunctuationrule{\mmlsetfakewidth {.}\vrule \s!width \scratchdimen \s!height .2\points \s!depth .2\points\relax}
+
+\setupMMLappearance[mspace][\c!option=] % \v!test
\startxmlsetups mml:mspace
\begingroup
\edef\mmlspacetext{\xmlatt{#1}{spacing}}
\ifx\mmlspacetext\empty
- \!!widtha \xmlattdef{#1}{width} \!!zeropoint % must be string
- \!!heighta\xmlattdef{#1}{height}\!!zeropoint
- \!!deptha \xmlattdef{#1}{depth} \!!zeropoint
- \ifdim\!!heighta=\zeropoint
- \ifdim\!!deptha=\zeropoint\else
- \hbox{\vrule\s!depth\!!deptha\s!height\zeropoint\s!width\zeropoint}%
+ \scratchwidth \xmlattdef{#1}{width} \!!zeropoint % must be string
+ \scratchheight\xmlattdef{#1}{height}\!!zeropoint
+ \scratchdepth \xmlattdef{#1}{depth} \!!zeropoint
+ \ifdim\scratchheight=\zeropoint
+ \ifdim\scratchdepth=\zeropoint\else
+ \hbox{\vrule\s!depth\scratchdepth\s!height\zeropoint\s!width\zeropoint}%
\fi
\else
- \hbox{\vrule\s!depth\zeropoint\s!height\!!heighta\s!width\zeropoint}%
+ \hbox{\vrule\s!depth\zeropoint\s!height\scratchheight\s!width\zeropoint}%
\fi
- \ifdim\!!widtha=\zeropoint\else
- \hskip\!!widtha
+ \ifdim\scratchwidth=\zeropoint\else
+ \ifx\MMLmspaceoption\v!test
+ \hbox to \scratchwidth{\showstruts\strut\hss\lower2\exheight\hbox{\infofont\xmlattdef{#1}{width}}\hss\strut}
+ \else
+ \hskip\scratchwidth
+ \fi
\fi
\else
- \phantom{\triggermathstyle\normalmathstyle\mmlspacetext}
+ \ifx\MMLmspaceoption\v!test
+ \hbox{\showstruts\strut\phantom{\triggermathstyle\normalmathstyle\mmlspacetext}\strut}
+ \else
+ \phantom{\triggermathstyle\normalmathstyle\mmlspacetext}
+ \fi
\fi
\endgroup
\stopxmlsetups
diff --git a/Master/texmf-dist/tex/context/base/x-mathml.xsd b/Master/texmf-dist/tex/context/base/x-mathml.xsd
index 17f0bea2aa4..1c29452b06a 100644
--- a/Master/texmf-dist/tex/context/base/x-mathml.xsd
+++ b/Master/texmf-dist/tex/context/base/x-mathml.xsd
@@ -3,9 +3,9 @@
-
+
-
-
+
+
diff --git a/Master/texmf-dist/tex/context/base/x-res-01.mkiv b/Master/texmf-dist/tex/context/base/x-res-01.mkiv
index e234e98677a..36070c61599 100644
--- a/Master/texmf-dist/tex/context/base/x-res-01.mkiv
+++ b/Master/texmf-dist/tex/context/base/x-res-01.mkiv
@@ -256,7 +256,7 @@
\vfill
}
\advance\hsize by -30pt
- \doifmodeelse {clipgrid-distance,clipgrid-steps} {
+ \doifelsemode {clipgrid-distance,clipgrid-steps} {
\xmlsetup{#1}{xml:resource:a}
} {
\xmlsetup{#1}{xml:resource:b}
diff --git a/Master/texmf-dist/tex/context/base/x-set-11.mkiv b/Master/texmf-dist/tex/context/base/x-set-11.mkiv
index 12854dc92d8..73e68e0738c 100644
--- a/Master/texmf-dist/tex/context/base/x-set-11.mkiv
+++ b/Master/texmf-dist/tex/context/base/x-set-11.mkiv
@@ -57,7 +57,7 @@
2: -- wordt verwerkt
3: -- is niet gedefinieerd
4: -- wordt nogmaals verwerkt
- optional: optioneel
+ optional: opt
displaymath: formule
index: ingang
math: formule
@@ -95,7 +95,7 @@
2: -- is processed
3: -- is undefined
4: -- is processed again
- optional: optional
+ optional: opt
displaymath: formula
index: entry
math: formula
@@ -133,7 +133,7 @@
2: -- wird verarbeitet
3: -- ist undefiniert
4: -- ist mehrmals verarbeitet
- optional: optioneel
+ optional: opt
displaymath: formula
index: entry
math: formula
@@ -171,7 +171,7 @@
2: -- je zpracovano
3: -- je nedefinovano
4: -- je zpracovano znovu
- optional: optioneel
+ optional: opt
displaymath: formula
index: entry
math: formula
@@ -209,7 +209,7 @@
2: -- is processed
3: -- is undefined
4: -- is processed again
- optional: optioneel
+ optional: opt
displaymath: formula
index: entry
math: formula
@@ -247,7 +247,7 @@
2: este procesat --
3: -- este nedefinit
4: -- este procesat din nou
- optional: optioneel
+ optional: opt
displaymath: formula
index: entry
math: formula
@@ -285,7 +285,7 @@
2: -- est traité
3: -- n'est pas défini
4: -- est traité de nouveau
- optional: optionel
+ optional: opt
displaymath: formule
index: entrée
math: formule
@@ -369,7 +369,8 @@
} {
\let\currentSETUPprefix\empty
}
- \edef\currentSETUPname{\xmlatt{#1}{name}}
+ % \edef\currentSETUPname{\xmlatt{#1}{name}}
+ \edef\currentSETUPname{\xmlattribute{#1}{/sequence/string[1]}{value}}%
\doifelse {\xmlatt{#1}{generated}} {yes} {
\def\currentSETUPgenerated{*}
} {
@@ -457,7 +458,7 @@
\def\showsetupindeed#1%
{\startelement[setup][name=#1]%
\startelement[noexport][comment={setup definition #1}]
- \xmlfilterlist{\loadedsetups}{/interface/command['#1' == (@type=='environment' and 'start' or '') .. @name]/command(xml:setups:typeset)}%
+ \xmlfilterlist{\loadedsetups}{/interface/command['#1' == (@type=='environment' and '\e!start' or '') .. @name]/command(xml:setups:typeset)}%
\stopelement
\stopelement}
@@ -469,7 +470,7 @@
%D Typesetting:
\setupxml
- [\c!method=mkiv, % mixed mode
+ [%\c!method=mkiv, % mixed mode
\c!default=\v!hidden, % ignore elements that are not defined
\c!compress=\v!yes, % strip comment
\c!entities=\v!yes] % replace entities
@@ -499,37 +500,41 @@
\xmlfilter{#1}{/sequence/first()}
\ignorespaces
\egroup
- \xmldoif{#1}{/arguments} {
- \bgroup
- \enablemode[setups-pass-one]
- \doglobal\newcounter\currentSETUPargument
- \ignorespaces
- \xmlfilter{#1}{/arguments/text()}
- \egroup
- }
- \doif {\xmlatt{#1}{type}} {environment} {
- \bgroup
- \enablemode[setups-pass-one]%
- \hskip.5em\unknown\hskip.5em
- \doif {\xmlatt{#1}{generated}} {yes} {
- \ttsl
- }
- \tex{\e!stop}
- \xmlfilter{#1}{/sequence/first()}
- \ignorespaces
- \egroup
- }
- \endgraf
- \xmldoif{#1}{/arguments} {
- \bgroup
- \enablemode[setups-pass-two]
- \doglobal\newcounter\currentSETUPargument
- %\blank[\v!line] % packed mode (we could do \startunpacked ...)
- \godown[.75\lineheight]
- \switchtobodyfont[\v!small]
- \ignorespaces\xmlfilter{#1}{/arguments/text()}\endgraf
- \egroup
- }
+ \ifshortsetup
+ % nothing
+ \else
+ \xmldoif{#1}{/arguments} {
+ \bgroup
+ \enablemode[setups-pass-one]
+ \doglobal\newcounter\currentSETUPargument
+ \ignorespaces
+ \xmlfilter{#1}{/arguments/text()}
+ \egroup
+ }
+ \doif {\xmlatt{#1}{type}} {environment} {
+ \bgroup
+ \enablemode[setups-pass-one]%
+ \hskip.5em\unknown\hskip.5em
+ \doif {\xmlatt{#1}{generated}} {yes} {
+ \ttsl
+ }
+ \tex{\e!stop}
+ \xmlfilter{#1}{/sequence/first()}
+ \ignorespaces
+ \egroup
+ }
+ \endgraf
+ \xmldoif{#1}{/arguments} {
+ \bgroup
+ \enablemode[setups-pass-two]
+ \doglobal\newcounter\currentSETUPargument
+ %\blank[\v!line] % packed mode (we could do \startunpacked ...)
+ \godown[.75\lineheight]
+ \switchtobodyfont[\v!small]
+ \ignorespaces\xmlfilter{#1}{/arguments/text()}\endgraf
+ \egroup
+ }
+ \fi
\getvalue{\e!stop setuptext}
\stopxmlsetups
@@ -572,7 +577,7 @@
\startxmlsetups xml:setups:word \showSETUPcomponent{#1}{word} {word} \stopxmlsetups
\def\showSETUPcomponent#1#2#3%
- {\doifmodeelse{setups-pass-one}
+ {\doifelsemode{setups-pass-one}
{\getvalue{showSETUP#2}{#1}}
{\simpleSETUPargument{#3}}}
@@ -607,7 +612,7 @@
\stopxmlsetups
\startxmlsetups xml:setups:assignments
- \doifmodeelse{setups-pass-one} {
+ \doifelsemode{setups-pass-one} {
\showSETUPassignment{#1}
} {
\xdef\currentSETUPwidth{0pt}%
@@ -629,7 +634,7 @@
\stopxmlsetups
\startxmlsetups xml:setups:keywords
- \doifmodeelse{setups-pass-one} {
+ \doifelsemode{setups-pass-one} {
\showSETUPkeyword{#1}
} {
\startfirstSETUPcolumn{\showSETUPnumber}%
@@ -665,7 +670,7 @@
\stopxmlsetups
\startxmlsetups xml:setups:constant
- \doifmodeelse {setups-pass-one} {
+ \doifelsemode {setups-pass-one} {
} {
\doif {\xmlatt{#1}{default}} {yes} {
\underbar % next needs to be {braced}
@@ -677,7 +682,7 @@
\stopxmlsetups
\startxmlsetups xml:setups:variable
- \doifmodeelse {setups-pass-one} {
+ \doifelsemode {setups-pass-one} {
\expanded{\setupintfont{\xmlatt{#1}{value}}}\ignorespaces
} {
\c!setup!reserved!{\xmlatt{#1}{value}}
diff --git a/Master/texmf-dist/tex/context/base/x-set-12.mkiv b/Master/texmf-dist/tex/context/base/x-set-12.mkiv
index 6590bfe9e03..c60445313ee 100644
--- a/Master/texmf-dist/tex/context/base/x-set-12.mkiv
+++ b/Master/texmf-dist/tex/context/base/x-set-12.mkiv
@@ -146,8 +146,7 @@
[\c!alternative=\v!doublesided]
\setupsetup
- [\c!criterium=\v!all,
- \c!reference=0]
+ [\c!criterium=\v!all]
\setupframedtexts
[setuptext]
diff --git a/Master/texmf-dist/tex/context/base/x-xtag.mkiv b/Master/texmf-dist/tex/context/base/x-xtag.mkiv
index 09490cc8ff4..ab95c567eec 100644
--- a/Master/texmf-dist/tex/context/base/x-xtag.mkiv
+++ b/Master/texmf-dist/tex/context/base/x-xtag.mkiv
@@ -14,7 +14,7 @@
%D Here we load the \MKII\ (mostly) streaming \XML\ parser. We
%D define a couple of catcode regimes first.
-\ifdefined\XMLbanner \endinput \fi
+\endinput
\writestatus{xtag}{this module is obsolete, use the mkiv-xml features or use mkii instead}
--
cgit v1.2.3