diff options
53 files changed, 2349 insertions, 1797 deletions
diff --git a/context/data/scite/lexers/data/scite-context-data-context.lua b/context/data/scite/lexers/data/scite-context-data-context.lua index aa36277b7..4c8947229 100644 --- a/context/data/scite/lexers/data/scite-context-data-context.lua +++ b/context/data/scite/lexers/data/scite-context-data-context.lua @@ -1,4 +1,4 @@ return { ["constants"]={ "zerocount", "minusone", "minustwo", "plusone", "plustwo", "plusthree", "plusfour", "plusfive", "plussix", "plusseven", "pluseight", "plusnine", "plusten", "plussixteen", "plushundred", "plusthousand", "plustenthousand", "plustwentythousand", "medcard", "maxcard", "zeropoint", "onepoint", "halfapoint", "onebasepoint", "maxdimen", "scaledpoint", "thousandpoint", "points", "halfpoint", "zeroskip", "pluscxxvii", "pluscxxviii", "pluscclv", "pluscclvi", "normalpagebox", "endoflinetoken", "outputnewlinechar", "emptytoks", "empty", "undefined", "voidbox", "emptybox", "emptyvbox", "emptyhbox", "bigskipamount", "medskipamount", "smallskipamount", "fmtname", "fmtversion", "texengine", "texenginename", "texengineversion", "luatexengine", "pdftexengine", "xetexengine", "unknownengine", "etexversion", "pdftexversion", "xetexversion", "xetexrevision", "activecatcode", "bgroup", "egroup", "endline", "conditionaltrue", "conditionalfalse", "attributeunsetvalue", "uprotationangle", "rightrotationangle", "downrotationangle", "leftrotationangle", "inicatcodes", "ctxcatcodes", "texcatcodes", "notcatcodes", "txtcatcodes", "vrbcatcodes", "prtcatcodes", "nilcatcodes", "luacatcodes", "tpacatcodes", "tpbcatcodes", "xmlcatcodes", "escapecatcode", "begingroupcatcode", "endgroupcatcode", "mathshiftcatcode", "alignmentcatcode", "endoflinecatcode", "parametercatcode", "superscriptcatcode", "subscriptcatcode", "ignorecatcode", "spacecatcode", "lettercatcode", "othercatcode", "activecatcode", "commentcatcode", "invalidcatcode", "tabasciicode", "newlineasciicode", "formfeedasciicode", "endoflineasciicode", "endoffileasciicode", "spaceasciicode", "hashasciicode", "dollarasciicode", "commentasciicode", "ampersandasciicode", "colonasciicode", "backslashasciicode", "circumflexasciicode", "underscoreasciicode", "leftbraceasciicode", "barasciicode", "rightbraceasciicode", "tildeasciicode", "delasciicode", "lessthanasciicode", "morethanasciicode", "doublecommentsignal", "atsignasciicode", "exclamationmarkasciicode", "questionmarkasciicode", "doublequoteasciicode", "singlequoteasciicode", "forwardslashasciicode", "primeasciicode", "activemathcharcode", "activetabtoken", "activeformfeedtoken", "activeendoflinetoken", "batchmodecode", "nonstopmodecode", "scrollmodecode", "errorstopmodecode", "bottomlevelgroupcode", "simplegroupcode", "hboxgroupcode", "adjustedhboxgroupcode", "vboxgroupcode", "vtopgroupcode", "aligngroupcode", "noaligngroupcode", "outputgroupcode", "mathgroupcode", "discretionarygroupcode", "insertgroupcode", "vcentergroupcode", "mathchoicegroupcode", "semisimplegroupcode", "mathshiftgroupcode", "mathleftgroupcode", "vadjustgroupcode", "charnodecode", "hlistnodecode", "vlistnodecode", "rulenodecode", "insertnodecode", "marknodecode", "adjustnodecode", "ligaturenodecode", "discretionarynodecode", "whatsitnodecode", "mathnodecode", "gluenodecode", "kernnodecode", "penaltynodecode", "unsetnodecode", "mathsnodecode", "charifcode", "catifcode", "numifcode", "dimifcode", "oddifcode", "vmodeifcode", "hmodeifcode", "mmodeifcode", "innerifcode", "voidifcode", "hboxifcode", "vboxifcode", "xifcode", "eofifcode", "trueifcode", "falseifcode", "caseifcode", "definedifcode", "csnameifcode", "fontcharifcode", "fontslantperpoint", "fontinterwordspace", "fontinterwordstretch", "fontinterwordshrink", "fontexheight", "fontemwidth", "fontextraspace", "slantperpoint", "interwordspace", "interwordstretch", "interwordshrink", "exheight", "emwidth", "extraspace", "mathsupdisplay", "mathsupnormal", "mathsupcramped", "mathsubnormal", "mathsubcombined", "mathaxisheight", "startmode", "stopmode", "startnotmode", "stopnotmode", "startmodeset", "stopmodeset", "doifmode", "doifmodeelse", "doifnotmode", "startallmodes", "stopallmodes", "startnotallmodes", "stopnotallmodes", "doifallmodes", "doifallmodeselse", "doifnotallmodes", "startenvironment", "stopenvironment", "environment", "startcomponent", "stopcomponent", "component", "startproduct", "stopproduct", "product", "startproject", "stopproject", "project", "starttext", "stoptext", "startnotext", "stopnotext", "startdocument", "stopdocument", "documentvariable", "startmodule", "stopmodule", "usemodule", "startTEXpage", "stopTEXpage", "enablemode", "disablemode", "preventmode", "pushmode", "popmode", "typescriptone", "typescripttwo", "typescriptthree", "mathsizesuffix", "mathordcode", "mathopcode", "mathbincode", "mathrelcode", "mathopencode", "mathclosecode", "mathpunctcode", "mathalphacode", "mathinnercode", "mathnothingcode", "mathlimopcode", "mathnolopcode", "mathboxcode", "mathchoicecode", "mathaccentcode", "mathradicalcode", "constantnumber", "constantnumberargument", "constantdimen", "constantdimenargument", "constantemptyargument", "continueifinputfile" }, - ["helpers"]={ "startsetups", "stopsetups", "startxmlsetups", "stopxmlsetups", "startluasetups", "stopluasetups", "starttexsetups", "stoptexsetups", "startrawsetups", "stoprawsetups", "startlocalsetups", "stoplocalsetups", "starttexdefinition", "stoptexdefinition", "starttexcode", "stoptexcode", "doifsetupselse", "doifsetups", "doifnotsetups", "setup", "setups", "texsetup", "xmlsetup", "luasetup", "directsetup", "newmode", "setmode", "resetmode", "newsystemmode", "setsystemmode", "resetsystemmode", "pushsystemmode", "popsystemmode", "booleanmodevalue", "newcount", "newdimen", "newskip", "newmuskip", "newbox", "newtoks", "newread", "newwrite", "newmarks", "newinsert", "newattribute", "newif", "newlanguage", "newfamily", "newfam", "newhelp", "then", "donothing", "dontcomplain", "donetrue", "donefalse", "htdp", "unvoidbox", "vfilll", "mathbox", "mathlimop", "mathnolop", "mathnothing", "mathalpha", "currentcatcodetable", "defaultcatcodetable", "catcodetablename", "newcatcodetable", "startcatcodetable", "stopcatcodetable", "startextendcatcodetable", "stopextendcatcodetable", "pushcatcodetable", "popcatcodetable", "restorecatcodes", "setcatcodetable", "letcatcodecommand", "defcatcodecommand", "uedcatcodecommand", "hglue", "vglue", "hfillneg", "vfillneg", "hfilllneg", "vfilllneg", "ruledhss", "ruledhfil", "ruledhfill", "ruledhfilneg", "ruledhfillneg", "normalhfillneg", "ruledvss", "ruledvfil", "ruledvfill", "ruledvfilneg", "ruledvfillneg", "normalvfillneg", "ruledhbox", "ruledvbox", "ruledvtop", "ruledvcenter", "ruledhskip", "ruledvskip", "ruledkern", "ruledmskip", "ruledmkern", "ruledhglue", "ruledvglue", "normalhglue", "normalvglue", "ruledpenalty", "scratchcounter", "globalscratchcounter", "scratchdimen", "globalscratchdimen", "scratchskip", "globalscratchskip", "scratchmuskip", "globalscratchmuskip", "scratchtoks", "globalscratchtoks", "scratchbox", "globalscratchbox", "nextbox", "dowithnextbox", "dowithnextboxcs", "dowithnextboxcontent", "dowithnextboxcontentcs", "scratchwidth", "scratchheight", "scratchdepth", "scratchoffset", "scratchdistance", "scratchhsize", "scratchvsize", "scratchcounterone", "scratchcountertwo", "scratchcounterthree", "scratchdimenone", "scratchdimentwo", "scratchdimenthree", "scratchskipone", "scratchskiptwo", "scratchskipthree", "scratchmuskipone", "scratchmuskiptwo", "scratchmuskipthree", "scratchtoksone", "scratchtokstwo", "scratchtoksthree", "scratchboxone", "scratchboxtwo", "scratchboxthree", "doif", "doifnot", "doifelse", "doifinset", "doifnotinset", "doifinsetelse", "doifnextcharelse", "doifnextoptionalelse", "doifnextbgroupelse", "doifnextparenthesiselse", "doiffastoptionalcheckelse", "doifundefinedelse", "doifdefinedelse", "doifundefined", "doifdefined", "doifelsevalue", "doifvalue", "doifnotvalue", "doifnothing", "doifsomething", "doifelsenothing", "doifsomethingelse", "doifvaluenothing", "doifvaluesomething", "doifelsevaluenothing", "doifdimensionelse", "doifnumberelse", "doifcommonelse", "doifcommon", "doifnotcommon", "doifinstring", "doifnotinstring", "doifinstringelse", "doifassignmentelse", "tracingall", "tracingnone", "loggingall", "appendtoks", "prependtoks", "appendtotoks", "prependtotoks", "to", "endgraf", "empty", "null", "space", "quad", "enspace", "obeyspaces", "obeylines", "normalspace", "executeifdefined", "singleexpandafter", "doubleexpandafter", "tripleexpandafter", "dontleavehmode", "removelastspace", "removeunwantedspaces", "wait", "writestatus", "define", "redefine", "setmeasure", "setemeasure", "setgmeasure", "setxmeasure", "definemeasure", "measure", "getvalue", "setvalue", "setevalue", "setgvalue", "setxvalue", "letvalue", "letgvalue", "resetvalue", "undefinevalue", "ignorevalue", "setuvalue", "setuevalue", "setugvalue", "setuxvalue", "globallet", "glet", "getparameters", "geteparameters", "getgparameters", "getxparameters", "forgetparameters", "copyparameters", "processcommalist", "processcommacommand", "quitcommalist", "quitprevcommalist", "processaction", "processallactions", "processfirstactioninset", "processallactionsinset", "unexpanded", "expanded", "startexpanded", "stopexpanded", "protected", "protect", "unprotect", "firstofoneargument", "firstoftwoarguments", "secondoftwoarguments", "firstofthreearguments", "secondofthreearguments", "thirdofthreearguments", "firstoffourarguments", "secondoffourarguments", "thirdoffourarguments", "fourthoffourarguments", "firstoffivearguments", "secondoffivearguments", "thirdoffivearguments", "fourthoffivearguments", "fifthoffivearguments", "firstofsixarguments", "secondofsixarguments", "thirdofsixarguments", "fourthofsixarguments", "fifthofsixarguments", "sixthofsixarguments", "firstofoneunexpanded", "gobbleoneargument", "gobbletwoarguments", "gobblethreearguments", "gobblefourarguments", "gobblefivearguments", "gobblesixarguments", "gobblesevenarguments", "gobbleeightarguments", "gobbleninearguments", "gobbletenarguments", "gobbleoneoptional", "gobbletwooptionals", "gobblethreeoptionals", "gobblefouroptionals", "gobblefiveoptionals", "dorecurse", "doloop", "exitloop", "dostepwiserecurse", "recurselevel", "recursedepth", "dofastloopcs", "newconstant", "setnewconstant", "newconditional", "settrue", "setfalse", "setconstant", "newmacro", "setnewmacro", "newfraction", "dosingleempty", "dodoubleempty", "dotripleempty", "doquadrupleempty", "doquintupleempty", "dosixtupleempty", "doseventupleempty", "dosingleargument", "dodoubleargument", "dotripleargument", "doquadrupleargument", "dosinglegroupempty", "dodoublegroupempty", "dotriplegroupempty", "doquadruplegroupempty", "doquintuplegroupempty", "nopdfcompression", "maximumpdfcompression", "normalpdfcompression", "modulonumber", "dividenumber", "getfirstcharacter", "doiffirstcharelse", "startnointerference", "stopnointerference", "strut", "setstrut", "strutbox", "strutht", "strutdp", "strutwd", "begstrut", "endstrut" }, + ["helpers"]={ "startsetups", "stopsetups", "startxmlsetups", "stopxmlsetups", "startluasetups", "stopluasetups", "starttexsetups", "stoptexsetups", "startrawsetups", "stoprawsetups", "startlocalsetups", "stoplocalsetups", "starttexdefinition", "stoptexdefinition", "starttexcode", "stoptexcode", "doifsetupselse", "doifsetups", "doifnotsetups", "setup", "setups", "texsetup", "xmlsetup", "luasetup", "directsetup", "doifelsecommandhandler", "doifnotcommandhandler", "doifcommandhandler", "newmode", "setmode", "resetmode", "newsystemmode", "setsystemmode", "resetsystemmode", "pushsystemmode", "popsystemmode", "booleanmodevalue", "newcount", "newdimen", "newskip", "newmuskip", "newbox", "newtoks", "newread", "newwrite", "newmarks", "newinsert", "newattribute", "newif", "newlanguage", "newfamily", "newfam", "newhelp", "then", "donothing", "dontcomplain", "donetrue", "donefalse", "htdp", "unvoidbox", "vfilll", "mathbox", "mathlimop", "mathnolop", "mathnothing", "mathalpha", "currentcatcodetable", "defaultcatcodetable", "catcodetablename", "newcatcodetable", "startcatcodetable", "stopcatcodetable", "startextendcatcodetable", "stopextendcatcodetable", "pushcatcodetable", "popcatcodetable", "restorecatcodes", "setcatcodetable", "letcatcodecommand", "defcatcodecommand", "uedcatcodecommand", "hglue", "vglue", "hfillneg", "vfillneg", "hfilllneg", "vfilllneg", "ruledhss", "ruledhfil", "ruledhfill", "ruledhfilneg", "ruledhfillneg", "normalhfillneg", "ruledvss", "ruledvfil", "ruledvfill", "ruledvfilneg", "ruledvfillneg", "normalvfillneg", "ruledhbox", "ruledvbox", "ruledvtop", "ruledvcenter", "ruledhskip", "ruledvskip", "ruledkern", "ruledmskip", "ruledmkern", "ruledhglue", "ruledvglue", "normalhglue", "normalvglue", "ruledpenalty", "scratchcounter", "globalscratchcounter", "scratchdimen", "globalscratchdimen", "scratchskip", "globalscratchskip", "scratchmuskip", "globalscratchmuskip", "scratchtoks", "globalscratchtoks", "scratchbox", "globalscratchbox", "nextbox", "dowithnextbox", "dowithnextboxcs", "dowithnextboxcontent", "dowithnextboxcontentcs", "scratchwidth", "scratchheight", "scratchdepth", "scratchoffset", "scratchdistance", "scratchhsize", "scratchvsize", "scratchcounterone", "scratchcountertwo", "scratchcounterthree", "scratchdimenone", "scratchdimentwo", "scratchdimenthree", "scratchskipone", "scratchskiptwo", "scratchskipthree", "scratchmuskipone", "scratchmuskiptwo", "scratchmuskipthree", "scratchtoksone", "scratchtokstwo", "scratchtoksthree", "scratchboxone", "scratchboxtwo", "scratchboxthree", "doif", "doifnot", "doifelse", "doifinset", "doifnotinset", "doifinsetelse", "doifnextcharelse", "doifnextoptionalelse", "doifnextbgroupelse", "doifnextparenthesiselse", "doiffastoptionalcheckelse", "doifundefinedelse", "doifdefinedelse", "doifundefined", "doifdefined", "doifelsevalue", "doifvalue", "doifnotvalue", "doifnothing", "doifsomething", "doifelsenothing", "doifsomethingelse", "doifvaluenothing", "doifvaluesomething", "doifelsevaluenothing", "doifdimensionelse", "doifnumberelse", "doifcommonelse", "doifcommon", "doifnotcommon", "doifinstring", "doifnotinstring", "doifinstringelse", "doifassignmentelse", "tracingall", "tracingnone", "loggingall", "appendtoks", "prependtoks", "appendtotoks", "prependtotoks", "to", "endgraf", "empty", "null", "space", "quad", "enspace", "obeyspaces", "obeylines", "normalspace", "executeifdefined", "singleexpandafter", "doubleexpandafter", "tripleexpandafter", "dontleavehmode", "removelastspace", "removeunwantedspaces", "wait", "writestatus", "define", "redefine", "setmeasure", "setemeasure", "setgmeasure", "setxmeasure", "definemeasure", "measure", "getvalue", "setvalue", "setevalue", "setgvalue", "setxvalue", "letvalue", "letgvalue", "resetvalue", "undefinevalue", "ignorevalue", "setuvalue", "setuevalue", "setugvalue", "setuxvalue", "globallet", "glet", "getparameters", "geteparameters", "getgparameters", "getxparameters", "forgetparameters", "copyparameters", "processcommalist", "processcommacommand", "quitcommalist", "quitprevcommalist", "processaction", "processallactions", "processfirstactioninset", "processallactionsinset", "unexpanded", "expanded", "startexpanded", "stopexpanded", "protected", "protect", "unprotect", "firstofoneargument", "firstoftwoarguments", "secondoftwoarguments", "firstofthreearguments", "secondofthreearguments", "thirdofthreearguments", "firstoffourarguments", "secondoffourarguments", "thirdoffourarguments", "fourthoffourarguments", "firstoffivearguments", "secondoffivearguments", "thirdoffivearguments", "fourthoffivearguments", "fifthoffivearguments", "firstofsixarguments", "secondofsixarguments", "thirdofsixarguments", "fourthofsixarguments", "fifthofsixarguments", "sixthofsixarguments", "firstofoneunexpanded", "gobbleoneargument", "gobbletwoarguments", "gobblethreearguments", "gobblefourarguments", "gobblefivearguments", "gobblesixarguments", "gobblesevenarguments", "gobbleeightarguments", "gobbleninearguments", "gobbletenarguments", "gobbleoneoptional", "gobbletwooptionals", "gobblethreeoptionals", "gobblefouroptionals", "gobblefiveoptionals", "dorecurse", "doloop", "exitloop", "dostepwiserecurse", "recurselevel", "recursedepth", "dofastloopcs", "newconstant", "setnewconstant", "newconditional", "settrue", "setfalse", "setconstant", "newmacro", "setnewmacro", "newfraction", "dosingleempty", "dodoubleempty", "dotripleempty", "doquadrupleempty", "doquintupleempty", "dosixtupleempty", "doseventupleempty", "dosingleargument", "dodoubleargument", "dotripleargument", "doquadrupleargument", "dosinglegroupempty", "dodoublegroupempty", "dotriplegroupempty", "doquadruplegroupempty", "doquintuplegroupempty", "nopdfcompression", "maximumpdfcompression", "normalpdfcompression", "modulonumber", "dividenumber", "getfirstcharacter", "doiffirstcharelse", "startnointerference", "stopnointerference", "strut", "setstrut", "strutbox", "strutht", "strutdp", "strutwd", "begstrut", "endstrut" }, }
\ No newline at end of file diff --git a/context/data/scite/scite-context-data-context.properties b/context/data/scite/scite-context-data-context.properties index 37a39e1e0..39a7178a7 100644 --- a/context/data/scite/scite-context-data-context.properties +++ b/context/data/scite/scite-context-data-context.properties @@ -4,70 +4,71 @@ startluasetups stopluasetups starttexsetups stoptexsetups startrawsetups \ stoprawsetups startlocalsetups stoplocalsetups starttexdefinition stoptexdefinition \ starttexcode stoptexcode doifsetupselse doifsetups doifnotsetups \ setup setups texsetup xmlsetup luasetup \ -directsetup newmode setmode resetmode newsystemmode \ -setsystemmode resetsystemmode pushsystemmode popsystemmode booleanmodevalue \ -newcount newdimen newskip newmuskip newbox \ -newtoks newread newwrite newmarks newinsert \ -newattribute newif newlanguage newfamily newfam \ -newhelp then donothing dontcomplain donetrue \ -donefalse htdp unvoidbox vfilll mathbox \ -mathlimop mathnolop mathnothing mathalpha currentcatcodetable \ -defaultcatcodetable catcodetablename newcatcodetable startcatcodetable stopcatcodetable \ -startextendcatcodetable stopextendcatcodetable pushcatcodetable popcatcodetable restorecatcodes \ -setcatcodetable letcatcodecommand defcatcodecommand uedcatcodecommand hglue \ -vglue hfillneg vfillneg hfilllneg vfilllneg \ -ruledhss ruledhfil ruledhfill ruledhfilneg ruledhfillneg \ -normalhfillneg ruledvss ruledvfil ruledvfill ruledvfilneg \ -ruledvfillneg normalvfillneg ruledhbox ruledvbox ruledvtop \ -ruledvcenter ruledhskip ruledvskip ruledkern ruledmskip \ -ruledmkern ruledhglue ruledvglue normalhglue normalvglue \ -ruledpenalty scratchcounter globalscratchcounter scratchdimen globalscratchdimen \ -scratchskip globalscratchskip scratchmuskip globalscratchmuskip scratchtoks \ -globalscratchtoks scratchbox globalscratchbox nextbox dowithnextbox \ -dowithnextboxcs dowithnextboxcontent dowithnextboxcontentcs scratchwidth scratchheight \ -scratchdepth scratchoffset scratchdistance scratchhsize scratchvsize \ -scratchcounterone scratchcountertwo scratchcounterthree scratchdimenone scratchdimentwo \ -scratchdimenthree scratchskipone scratchskiptwo scratchskipthree scratchmuskipone \ -scratchmuskiptwo scratchmuskipthree scratchtoksone scratchtokstwo scratchtoksthree \ -scratchboxone scratchboxtwo scratchboxthree doif doifnot \ -doifelse doifinset doifnotinset doifinsetelse doifnextcharelse \ -doifnextoptionalelse doifnextbgroupelse doifnextparenthesiselse doiffastoptionalcheckelse doifundefinedelse \ -doifdefinedelse doifundefined doifdefined doifelsevalue doifvalue \ -doifnotvalue doifnothing doifsomething doifelsenothing doifsomethingelse \ -doifvaluenothing doifvaluesomething doifelsevaluenothing doifdimensionelse doifnumberelse \ -doifcommonelse doifcommon doifnotcommon doifinstring doifnotinstring \ -doifinstringelse doifassignmentelse tracingall tracingnone loggingall \ -appendtoks prependtoks appendtotoks prependtotoks to \ -endgraf empty null space quad \ -enspace obeyspaces obeylines normalspace executeifdefined \ -singleexpandafter doubleexpandafter tripleexpandafter dontleavehmode removelastspace \ -removeunwantedspaces wait writestatus define redefine \ -setmeasure setemeasure setgmeasure setxmeasure definemeasure \ -measure getvalue setvalue setevalue setgvalue \ -setxvalue letvalue letgvalue resetvalue undefinevalue \ -ignorevalue setuvalue setuevalue setugvalue setuxvalue \ -globallet glet getparameters geteparameters getgparameters \ -getxparameters forgetparameters copyparameters processcommalist processcommacommand \ -quitcommalist quitprevcommalist processaction processallactions processfirstactioninset \ -processallactionsinset unexpanded expanded startexpanded stopexpanded \ -protected protect unprotect firstofoneargument firstoftwoarguments \ -secondoftwoarguments firstofthreearguments secondofthreearguments thirdofthreearguments firstoffourarguments \ -secondoffourarguments thirdoffourarguments fourthoffourarguments firstoffivearguments secondoffivearguments \ -thirdoffivearguments fourthoffivearguments fifthoffivearguments firstofsixarguments secondofsixarguments \ -thirdofsixarguments fourthofsixarguments fifthofsixarguments sixthofsixarguments firstofoneunexpanded \ -gobbleoneargument gobbletwoarguments gobblethreearguments gobblefourarguments gobblefivearguments \ -gobblesixarguments gobblesevenarguments gobbleeightarguments gobbleninearguments gobbletenarguments \ -gobbleoneoptional gobbletwooptionals gobblethreeoptionals gobblefouroptionals gobblefiveoptionals \ -dorecurse doloop exitloop dostepwiserecurse recurselevel \ -recursedepth dofastloopcs newconstant setnewconstant newconditional \ -settrue setfalse setconstant newmacro setnewmacro \ -newfraction dosingleempty dodoubleempty dotripleempty doquadrupleempty \ -doquintupleempty dosixtupleempty doseventupleempty dosingleargument dodoubleargument \ -dotripleargument doquadrupleargument dosinglegroupempty dodoublegroupempty dotriplegroupempty \ -doquadruplegroupempty doquintuplegroupempty nopdfcompression maximumpdfcompression normalpdfcompression \ -modulonumber dividenumber getfirstcharacter doiffirstcharelse startnointerference \ -stopnointerference strut setstrut strutbox strutht \ -strutdp strutwd begstrut endstrut +directsetup doifelsecommandhandler doifnotcommandhandler doifcommandhandler newmode \ +setmode resetmode newsystemmode setsystemmode resetsystemmode \ +pushsystemmode popsystemmode booleanmodevalue newcount newdimen \ +newskip newmuskip newbox newtoks newread \ +newwrite newmarks newinsert newattribute newif \ +newlanguage newfamily newfam newhelp then \ +donothing dontcomplain donetrue donefalse htdp \ +unvoidbox vfilll mathbox mathlimop mathnolop \ +mathnothing mathalpha currentcatcodetable defaultcatcodetable catcodetablename \ +newcatcodetable startcatcodetable stopcatcodetable startextendcatcodetable stopextendcatcodetable \ +pushcatcodetable popcatcodetable restorecatcodes setcatcodetable letcatcodecommand \ +defcatcodecommand uedcatcodecommand hglue vglue hfillneg \ +vfillneg hfilllneg vfilllneg ruledhss ruledhfil \ +ruledhfill ruledhfilneg ruledhfillneg normalhfillneg ruledvss \ +ruledvfil ruledvfill ruledvfilneg ruledvfillneg normalvfillneg \ +ruledhbox ruledvbox ruledvtop ruledvcenter ruledhskip \ +ruledvskip ruledkern ruledmskip ruledmkern ruledhglue \ +ruledvglue normalhglue normalvglue ruledpenalty scratchcounter \ +globalscratchcounter scratchdimen globalscratchdimen scratchskip globalscratchskip \ +scratchmuskip globalscratchmuskip scratchtoks globalscratchtoks scratchbox \ +globalscratchbox nextbox dowithnextbox dowithnextboxcs dowithnextboxcontent \ +dowithnextboxcontentcs scratchwidth scratchheight scratchdepth scratchoffset \ +scratchdistance scratchhsize scratchvsize scratchcounterone scratchcountertwo \ +scratchcounterthree scratchdimenone scratchdimentwo scratchdimenthree scratchskipone \ +scratchskiptwo scratchskipthree scratchmuskipone scratchmuskiptwo scratchmuskipthree \ +scratchtoksone scratchtokstwo scratchtoksthree scratchboxone scratchboxtwo \ +scratchboxthree doif doifnot doifelse doifinset \ +doifnotinset doifinsetelse doifnextcharelse doifnextoptionalelse doifnextbgroupelse \ +doifnextparenthesiselse doiffastoptionalcheckelse doifundefinedelse doifdefinedelse doifundefined \ +doifdefined doifelsevalue doifvalue doifnotvalue doifnothing \ +doifsomething doifelsenothing doifsomethingelse doifvaluenothing doifvaluesomething \ +doifelsevaluenothing doifdimensionelse doifnumberelse doifcommonelse doifcommon \ +doifnotcommon doifinstring doifnotinstring doifinstringelse doifassignmentelse \ +tracingall tracingnone loggingall appendtoks prependtoks \ +appendtotoks prependtotoks to endgraf empty \ +null space quad enspace obeyspaces \ +obeylines normalspace executeifdefined singleexpandafter doubleexpandafter \ +tripleexpandafter dontleavehmode removelastspace removeunwantedspaces wait \ +writestatus define redefine setmeasure setemeasure \ +setgmeasure setxmeasure definemeasure measure getvalue \ +setvalue setevalue setgvalue setxvalue letvalue \ +letgvalue resetvalue undefinevalue ignorevalue setuvalue \ +setuevalue setugvalue setuxvalue globallet glet \ +getparameters geteparameters getgparameters getxparameters forgetparameters \ +copyparameters processcommalist processcommacommand quitcommalist quitprevcommalist \ +processaction processallactions processfirstactioninset processallactionsinset unexpanded \ +expanded startexpanded stopexpanded protected protect \ +unprotect firstofoneargument firstoftwoarguments secondoftwoarguments firstofthreearguments \ +secondofthreearguments thirdofthreearguments firstoffourarguments secondoffourarguments thirdoffourarguments \ +fourthoffourarguments firstoffivearguments secondoffivearguments thirdoffivearguments fourthoffivearguments \ +fifthoffivearguments firstofsixarguments secondofsixarguments thirdofsixarguments fourthofsixarguments \ +fifthofsixarguments sixthofsixarguments firstofoneunexpanded gobbleoneargument gobbletwoarguments \ +gobblethreearguments gobblefourarguments gobblefivearguments gobblesixarguments gobblesevenarguments \ +gobbleeightarguments gobbleninearguments gobbletenarguments gobbleoneoptional gobbletwooptionals \ +gobblethreeoptionals gobblefouroptionals gobblefiveoptionals dorecurse doloop \ +exitloop dostepwiserecurse recurselevel recursedepth dofastloopcs \ +newconstant setnewconstant newconditional settrue setfalse \ +setconstant newmacro setnewmacro newfraction dosingleempty \ +dodoubleempty dotripleempty doquadrupleempty doquintupleempty dosixtupleempty \ +doseventupleempty dosingleargument dodoubleargument dotripleargument doquadrupleargument \ +dosinglegroupempty dodoublegroupempty dotriplegroupempty doquadruplegroupempty doquintuplegroupempty \ +nopdfcompression maximumpdfcompression normalpdfcompression modulonumber dividenumber \ +getfirstcharacter doiffirstcharelse startnointerference stopnointerference strut \ +setstrut strutbox strutht strutdp strutwd \ +begstrut endstrut keywordclass.context.constants=\ zerocount minusone minustwo plusone \ diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua index e07ecdfc7..fdca3c89a 100644 --- a/scripts/context/lua/mtx-context.lua +++ b/scripts/context/lua/mtx-context.lua @@ -6,11 +6,18 @@ if not modules then modules = { } end modules ['mtx-context'] = { license = "see context related readme files" } +-- todo: more local functions +-- todo: pass jobticket/ctxdata table around + local format, gmatch, match, gsub, find = string.format, string.gmatch, string.match, string.gsub, string.find local quote = string.quote local concat = table.concat +local settings_to_array = utilities.parsers.settings_to_array +local appendtable = table.append +local lpegpatterns, lpegmatch, Cs, P = lpeg.patterns, lpeg.match, lpeg.Cs, lpeg.P -local getargument = environment.argument +local getargument = environment.getargument or environment.argument +local setargument = environment.setargument local basicinfo = [[ --run process (one or more) files (default action) @@ -35,7 +42,7 @@ local basicinfo = [[ --noconsole disable logging to the console (logfile only) --purgeresult purge result file before run ---forcexml force xml stub (optional flag: --mkii) +--forcexml force xml stub --forcecld force cld (context lua document) stub --arrange run extra imposition pass, given that the style sets up imposition @@ -50,23 +57,16 @@ local basicinfo = [[ --version report installed context version --global assume given file present elsewhere +--nofile use dummy file as jobname --expert expert options ]] --- filter=list is kind of obsolete --- color is obsolete for mkiv, always on --- separation is obsolete for mkiv, no longer available --- output is currently obsolete for mkiv --- setuppath=list must check --- modefile=name must check --- input=name load the given inputfile (must check) - local expertinfo = [[ expert options: --touch update context version number (remake needed afterwards, also provide --expert) ---nostats omit runtime statistics at the end of the run +--nostatistics omit runtime statistics at the end of the run --update update context from website (not to be confused with contextgarden) --profile profile job (use: mtxrun --script profile --analyze) --timing generate timing and statistics overview @@ -80,13 +80,14 @@ special options: --pdftex process file with texexec using pdftex --xetex process file with texexec using xetex +--mkii process file with texexec --pipe don't check for file and enter scroll mode (--dummyfile=whatever.tmp) ]] local application = logs.application { name = "mtx-context", - banner = "ConTeXt Process Management 0.52", + banner = "ConTeXt Process Management 0.60", helpinfo = { basic = basicinfo, extra = extrainfo, @@ -94,159 +95,105 @@ local application = logs.application { } } +-- local luatexflags = { +-- ["8bit"] = true, -- ignored, input is assumed to be in UTF-8 encoding +-- ["default-translate-file"] = true, -- ignored, input is assumed to be in UTF-8 encoding +-- ["translate-file"] = true, -- ignored, input is assumed to be in UTF-8 encoding +-- ["etex"] = true, -- ignored, the etex extensions are always active +-- +-- ["credits"] = true, -- display credits and exit +-- ["debug-format"] = true, -- enable format debugging +-- ["disable-write18"] = true, -- disable \write18{SHELL COMMAND} +-- ["draftmode"] = true, -- switch on draft mode (generates no output PDF) +-- ["enable-write18"] = true, -- enable \write18{SHELL COMMAND} +-- ["file-line-error"] = true, -- enable file:line:error style messages +-- ["file-line-error-style"] = true, -- aliases of --file-line-error +-- ["no-file-line-error"] = true, -- disable file:line:error style messages +-- ["no-file-line-error-style"] = true, -- aliases of --no-file-line-error +-- ["fmt"] = true, -- load the format file FORMAT +-- ["halt-on-error"] = true, -- stop processing at the first error +-- ["help"] = true, -- display help and exit +-- ["ini"] = true, -- be iniluatex, for dumping formats +-- ["interaction"] = true, -- set interaction mode (STRING=batchmode/nonstopmode/scrollmode/errorstopmode) +-- ["jobname"] = true, -- set the job name to STRING +-- ["kpathsea-debug"] = true, -- set path searching debugging flags according to the bits of NUMBER +-- ["lua"] = true, -- load and execute a lua initialization script +-- ["mktex"] = true, -- enable mktexFMT generation (FMT=tex/tfm) +-- ["no-mktex"] = true, -- disable mktexFMT generation (FMT=tex/tfm) +-- ["nosocket"] = true, -- disable the lua socket library +-- ["output-comment"] = true, -- use STRING for DVI file comment instead of date (no effect for PDF) +-- ["output-directory"] = true, -- use existing DIR as the directory to write files in +-- ["output-format"] = true, -- use FORMAT for job output; FORMAT is 'dvi' or 'pdf' +-- ["parse-first-line"] = true, -- enable parsing of the first line of the input file +-- ["no-parse-first-line"] = true, -- disable parsing of the first line of the input file +-- ["progname"] = true, -- set the program name to STRING +-- ["recorder"] = true, -- enable filename recorder +-- ["safer"] = true, -- disable easily exploitable lua commands +-- ["shell-escape"] = true, -- enable \write18{SHELL COMMAND} +-- ["no-shell-escape"] = true, -- disable \write18{SHELL COMMAND} +-- ["shell-restricted"] = true, -- restrict \write18 to a list of commands given in texmf.cnf +-- ["synctex"] = true, -- enable synctex +-- ["version"] = true, -- display version and exit +-- ["luaonly"] = true, -- run a lua file, then exit +-- ["luaconly"] = true, -- byte-compile a lua file, then exit +-- } + local report = application.report scripts = scripts or { } scripts.context = scripts.context or { } --- a demo cld file: --- --- context.starttext() --- context.chapter("Hello There") --- context.readfile("tufte","","not found") --- context.stoptext() +-- constants --- l-file / todo +local usedfiles = { + nop = "cont-nop.mkiv", + yes = "cont-yes.mkiv", +} -function file.needsupdate(oldfile,newfile) - return true -end -function file.syncmtimes(oldfile,newfile) -end +local usedsuffixes = { + before = { + "tuc" + }, + after = { + "pdf", "tuc", "log" + }, + keep = { + "log" + }, +} --- l-io +local formatofinterface = { + en = "cont-en", + uk = "cont-uk", + de = "cont-de", + fr = "cont-fr", + nl = "cont-nl", + cs = "cont-cs", + it = "cont-it", + ro = "cont-ro", + pe = "cont-pe", +} -function io.copydata(fromfile,tofile) - io.savedata(tofile,io.loaddata(fromfile) or "") -end +local defaultformats = { + "cont-en", + "cont-nl", +} --- ctx (will become util-ctx) - -local ctxrunner = { } - -function ctxrunner.filtered(str,method) - str = tostring(str) - if method == 'name' then str = file.removesuffix(file.basename(str)) - elseif method == 'path' then str = file.dirname(str) - elseif method == 'suffix' then str = file.extname(str) - elseif method == 'nosuffix' then str = file.removesuffix(str) - elseif method == 'nopath' then str = file.basename(str) - elseif method == 'base' then str = file.basename(str) --- elseif method == 'full' then --- elseif method == 'complete' then --- elseif method == 'expand' then -- str = file.expandpath(str) - end - return str:gsub("\\","/") -end +-- process information -function ctxrunner.substitute(e,str) - local attributes = e.at - if str and attributes then - if attributes['method'] then - str = ctxrunner.filtered(str,attributes['method']) - end - if str == "" and attributes['default'] then - str = attributes['default'] - end - end - return str -end +local ctxrunner = { } -- namespace will go -function ctxrunner.reflag(flags) - local t = { } - for _, flag in next, flags do - local key, value = match(flag,"^(.-)=(.+)$") - if key and value then - t[key] = value - else - t[flag] = true - end - end - return t -end - -function ctxrunner.substitute(str) - return str -end - -function ctxrunner.justtext(str) - str = xml.unescaped(tostring(str)) - str = xml.cleansed(str) - str = str:gsub("\\+",'/') - str = str:gsub("%s+",' ') - return str -end +local ctx_locations = { '..', '../..' } function ctxrunner.new() return { - ctxname = "", - jobname = "", - xmldata = nil, - suffix = "prep", - locations = { '..', '../..' }, - variables = { }, - messages = { }, - environments = { }, - modules = { }, - filters = { }, - flags = { }, - modes = { }, - prepfiles = { }, - paths = { }, + ctxname = "", + jobname = "", + flags = { }, } end -function ctxrunner.savelog(ctxdata,ctlname) - local function yn(b) - if b then return 'yes' else return 'no' end - end - if not ctlname or ctlname == "" or ctlname == ctxdata.jobname then - if ctxdata.jobname then - ctlname = file.replacesuffix(ctxdata.jobname,'ctl') - elseif ctxdata.ctxname then - ctlname = file.replacesuffix(ctxdata.ctxname,'ctl') - else - report("invalid ctl name: %s",ctlname or "?") - return - end - end - local prepfiles = ctxdata.prepfiles - if prepfiles and next(prepfiles) then - report("saving logdata in: %s",ctlname) - f = io.open(ctlname,'w') - if f then - f:write("<?xml version='1.0' standalone='yes'?>\n\n") - f:write(format("<ctx:preplist local='%s'>\n",yn(ctxdata.runlocal))) - local sorted = table.sortedkeys(prepfiles) - for i=1,#sorted do - local name = sorted[i] - f:write(format("\t<ctx:prepfile done='%s'>%s</ctx:prepfile>\n",yn(prepfiles[name]),name)) - end - f:write("</ctx:preplist>\n") - f:close() - end - else - report("nothing prepared, no ctl file saved") - os.remove(ctlname) - end -end - -function ctxrunner.register_path(ctxdata,path) - -- test if exists - ctxdata.paths[ctxdata.paths+1] = path -end - -function ctxrunner.trace(ctxdata) - print(table.serialize(ctxdata.messages)) - print(table.serialize(ctxdata.flags)) - print(table.serialize(ctxdata.environments)) - print(table.serialize(ctxdata.modules)) - print(table.serialize(ctxdata.filters)) - print(table.serialize(ctxdata.modes)) - print(xml.tostring(ctxdata.xmldata)) -end - -function ctxrunner.manipulate(ctxdata,ctxname,defaultname) +function ctxrunner.checkfile(ctxdata,ctxname,defaultname) if not ctxdata.jobname or ctxdata.jobname == "" then return @@ -269,13 +216,14 @@ function ctxrunner.manipulate(ctxdata,ctxname,defaultname) local usedname = ctxdata.ctxname local found = lfs.isfile(usedname) - -- no futher test if qualified path + -- no further test if qualified path if not found then - for _, path in next, ctxdata.locations do + for _, path in next, ctx_locations do local fullname = file.join(path,ctxdata.ctxname) if lfs.isfile(fullname) then - usedname, found = fullname, true + usedname = fullname + found = true break end end @@ -283,194 +231,69 @@ function ctxrunner.manipulate(ctxdata,ctxname,defaultname) if not found then usedname = resolvers.findfile(ctxdata.ctxname,"tex") - found = usedname ~= "" + found = usedname ~= "" end if not found and defaultname and defaultname ~= "" and lfs.isfile(defaultname) then - usedname, found = defaultname, true + usedname = defaultname + found = true end if not found then return end - ctxdata.xmldata = xml.load(usedname) + local xmldata = xml.load(usedname) - if not ctxdata.xmldata then + if not xmldata then return else -- test for valid, can be text file end - xml.include(ctxdata.xmldata,'ctx:include','name', table.append({'.', file.dirname(ctxdata.ctxname)},ctxdata.locations)) - - ctxdata.variables['job'] = ctxdata.jobname + local ctxpaths = table.append({'.', file.dirname(ctxdata.ctxname)}, ctx_locations) - ctxdata.flags = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:flags/ctx:flag",true) - ctxdata.environments = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:environment",true) - ctxdata.modules = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:module",true) - ctxdata.filters = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:filter",true) - ctxdata.modes = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:mode",true) - ctxdata.messages = xml.collect_texts(ctxdata.xmldata,"ctx:message",true) + xml.include(xmldata,'ctx:include','name', ctxpaths) - ctxdata.flags = ctxrunner.reflag(ctxdata.flags) + local flags = ctxdata.flags - local messages = ctxdata.messages - for i=1,#messages do - report("ctx comment: %s", xml.tostring(messages[i])) - end - - for r, d, k in xml.elements(ctxdata.xmldata,"ctx:value[@name='job']") do - d[k] = ctxdata.variables['job'] or "" - end - - local commands = { } - for e in xml.collected(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:processors/ctx:processor") do - commands[e.at and e.at['name'] or "unknown"] = e - end - - local suffix = xml.filter(ctxdata.xmldata,"/ctx:job/ctx:preprocess/attribute('suffix')") or ctxdata.suffix - local runlocal = xml.filter(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:processors/attribute('local')") - - runlocal = toboolean(runlocal) - - for files in xml.collected(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:files") do - for pattern in xml.collected(files,"ctx:file") do - - preprocessor = pattern.at['processor'] or "" - - if preprocessor ~= "" then - - ctxdata.variables['old'] = ctxdata.jobname - for r, d, k in xml.elements(ctxdata.xmldata,"ctx:value") do - local ek = d[k] - local ekat = ek.at['name'] - if ekat == 'old' then - d[k] = ctxrunner.substitute(ctxdata.variables[ekat] or "") - end - end - - pattern = ctxrunner.justtext(xml.tostring(pattern)) - - local oldfiles = dir.glob(pattern) - - local pluspath = false - if #oldfiles == 0 then - -- message: no files match pattern - local paths = ctxdata.paths - for i=1,#paths do - local p = paths[i] - local oldfiles = dir.glob(path.join(p,pattern)) - if #oldfiles > 0 then - pluspath = true - break - end - end - end - if #oldfiles == 0 then - -- message: no old files - else - for i=1,#oldfiles do - local oldfile = oldfiles[i] - local newfile = oldfile .. "." .. suffix -- addsuffix will add one only - if ctxdata.runlocal then - newfile = file.basename(newfile) - end - if oldfile ~= newfile and file.needsupdate(oldfile,newfile) then - -- message: oldfile needs preprocessing - -- os.remove(newfile) - local splitted = preprocessor:split(',') - for i=1,#splitted do - local pp = splitted[i] - local command = commands[pp] - if command then - command = xml.copy(command) - local suf = (command.at and command.at['suffix']) or ctxdata.suffix - if suf then - newfile = oldfile .. "." .. suf - end - if ctxdata.runlocal then - newfile = file.basename(newfile) - end - for r, d, k in xml.elements(command,"ctx:old") do - d[k] = ctxrunner.substitute(oldfile) - end - for r, d, k in xml.elements(command,"ctx:new") do - d[k] = ctxrunner.substitute(newfile) - end - ctxdata.variables['old'] = oldfile - ctxdata.variables['new'] = newfile - for r, d, k in xml.elements(command,"ctx:value") do - local ek = d[k] - local ekat = ek.at and ek.at['name'] - if ekat then - d[k] = ctxrunner.substitute(ctxdata.variables[ekat] or "") - end - end - -- potential optimization: when mtxrun run internal - command = xml.content(command) - command = ctxrunner.justtext(command) - report("command: %s",command) - local result = os.spawn(command) or 0 - -- somehow we get the wrong return value - if result > 0 then - report("error, return code: %s",result) - end - if ctxdata.runlocal then - oldfile = file.basename(oldfile) - end - end - end - if lfs.isfile(newfile) then - file.syncmtimes(oldfile,newfile) - ctxdata.prepfiles[oldfile] = true - else - report("error, check target location of new file: %s", newfile) - ctxdata.prepfiles[oldfile] = false - end - else - report("old file needs no preprocessing") - ctxdata.prepfiles[oldfile] = lfs.isfile(newfile) - end - end - end - end + for e in xml.collected(xmldata,"/ctx:job/ctx:flags/ctx:flag") do + local key, value = match(flag,"^(.-)=(.+)$") + if key and value then + flags[key] = value + else + flags[flag] = true end end - ctxrunner.savelog(ctxdata) - end -function ctxrunner.preppedfile(ctxdata,filename) - if ctxdata.prepfiles[file.basename(filename)] then - return filename .. ".prep" - else - return filename +function ctxrunner.checkflags(ctxdata) + if ctxdata then + for k,v in next, ctxdata.flags do + if getargument(k) == nil then + setargument(k,v) + end + end end end --- rest +-- multipass control -scripts.context.multipass = { --- suffixes = { ".tuo", ".tuc" }, - suffixes = { ".tuc" }, - nofruns = 8, --- nofruns = 7, -- test oscillation -} +local multipass_suffixes = { ".tuc" } +local multipass_nofruns = 8 -- or 7 to test oscillation -function scripts.context.multipass.hashfiles(jobname) +local function multipass_hashfiles(jobname) local hash = { } - local suffixes = scripts.context.multipass.suffixes - for i=1,#suffixes do - local suffix = suffixes[i] + for i=1,#multipass_suffixes do + local suffix = multipass_suffixes[i] local full = jobname .. suffix hash[full] = md5.hex(io.loaddata(full) or "unknown") end return hash end -function scripts.context.multipass.changed(oldhash, newhash) +local function multipass_changed(oldhash, newhash) for k,v in next, oldhash do if v ~= newhash[k] then return true @@ -479,126 +302,7 @@ function scripts.context.multipass.changed(oldhash, newhash) return false end -function scripts.context.multipass.makeoptionfile(jobname,ctxdata,kindofrun,currentrun,finalrun,once) - -- take jobname from ctx - jobname = file.removesuffix(jobname) - local f = io.open(jobname..".top","w") - if f then - local function someflag(flag) - return (ctxdata and ctxdata.flags[flag]) or getargument(flag) - end - local function setvalue(flag,template,hash,default) - local a = someflag(flag) or default - if a and a ~= "" then - if hash then - if hash[a] then - f:write(format(template,a),"\n") - end - else - f:write(format(template,a),"\n") - end - end - end - local function setvalues(flag,template,plural) - if type(flag) == "table" then - for k, v in next, flag do - f:write(format(template,v),"\n") - end - else - local a = someflag(flag) or (plural and someflag(flag.."s")) - if a and a ~= "" then - for v in gmatch(a,"%s*([^,]+)") do - f:write(format(template,v),"\n") - end - end - end - end - local function setfixed(flag,template,...) - if someflag(flag) then - f:write(format(template,...),"\n") - end - end - local function setalways(template,...) - f:write(format(template,...),"\n") - end - -- - -- This might change ... we can just pass the relevant flags directly. - -- - setalways("%% runtime options files (command line driven)") - -- - setalways("\\unprotect") - -- - setalways("%% feedback and basic job control") - -- - -- Option file, we can pass more on the commandline some day soon. Actually we - -- should use directives and trackers. - -- - setfixed ("timing" , "\\usemodule[timing]") - setfixed ("batchmode" , "\\batchmode") - setfixed ("batch" , "\\batchmode") - setfixed ("nonstopmode" , "\\nonstopmode") - setfixed ("nonstop" , "\\nonstopmode") - -- setfixed ("tracefiles" , "\\tracefilestrue") - setfixed ("nostats" , "\\nomkivstatistics") - setfixed ("paranoid" , "\\def\\maxreadlevel{1}") - -- - setalways("%% handy for special styles") - -- - setalways("\\startluacode") - setalways("document = document or { }") - setalways(table.serialize(environment.arguments, "document.arguments")) - setalways(table.serialize(environment.files, "document.files")) - setalways("\\stopluacode") - -- - setalways("%% process info") - -- - setalways( "\\setupsystem[inputfile=%s]",getargument("input") or environment.files[1] or "\\jobname") - setvalue ("result" , "\\setupsystem[file=%s]") - setalways( "\\setupsystem[\\c!n=%s,\\c!m=%s]", kindofrun or 0, currentrun or 0) - setvalues("path" , "\\usepath[%s]") - setvalue ("setuppath" , "\\setupsystem[\\c!directory={%s}]") - setvalue ("randomseed" , "\\setupsystem[\\c!random=%s]") - setvalue ("arguments" , "\\setupenv[%s]") - if once then - setalways("\\enabledirectives[system.runonce]") - end - setalways("%% modes") - setvalues("modefile" , "\\readlocfile{%s}{}{}") - setvalues("mode" , "\\enablemode[%s]", true) - if ctxdata then - setvalues(ctxdata.modes, "\\enablemode[%s]") - end - -- - setalways("%% options (not that important)") - -- - setalways("\\startsetups *runtime:options") - setfixed ("color" , "\\setupcolors[\\c!state=\\v!start]") - setvalue ("separation" , "\\setupcolors[\\c!split=%s]") - setfixed ("noarrange" , "\\setuparranging[\\v!disable]") - if getargument('arrange') and not finalrun then - setalways( "\\setuparranging[\\v!disable]") - end - setalways("\\stopsetups") - -- - setalways("%% styles and modules") - -- - setalways("\\startsetups *runtime:modules") - setvalues("usemodule" , "\\usemodule[%s]", true) - setvalues("environment" , "\\environment %s ", true) - if ctxdata then - setvalues(ctxdata.modules, "\\usemodule[%s]") - setvalues(ctxdata.environments, "\\environment %s ") - end - setalways("\\stopsetups") - -- - setalways("%% done") - -- - setalways("\\protect \\endinput") - f:close() - end -end - -function scripts.context.multipass.copyluafile(jobname) -- obsolete +local function multipass_copyluafile(jobname) local tuaname, tucname = jobname..".tua", jobname..".tuc" if lfs.isfile(tuaname) then os.remove(tucname) @@ -606,120 +310,54 @@ function scripts.context.multipass.copyluafile(jobname) -- obsolete end end -scripts.context.cldsuffixes = table.tohash { - "cld", -} - -scripts.context.xmlsuffixes = table.tohash { - "xml", -} - -scripts.context.luasuffixes = table.tohash { - "lua", -} - -scripts.context.beforesuffixes = { - "tuo", "tuc" -} -scripts.context.aftersuffixes = { - "pdf", "tuo", "tuc", "log" -} - -scripts.context.errorsuffixes = { - "log" -} - -scripts.context.interfaces = { - en = "cont-en", - uk = "cont-uk", - de = "cont-de", - fr = "cont-fr", - nl = "cont-nl", - cs = "cont-cs", - it = "cont-it", - ro = "cont-ro", - pe = "cont-pe", -} - -scripts.context.defaultformats = { - "cont-en", - "cont-nl", --- "mptopdf", -- todo: mak emkiv variant --- "metatex", -- will show up soon --- "metafun", -- todo: mp formats --- "plain" -} - -local lpegpatterns, Cs, P = lpeg.patterns, lpeg.Cs, lpeg.P +-- local pattern = lpegpatterns.utfbom^-1 * (P("%% ") + P("% ")) * Cs((1-lpegpatterns.newline)^1) -local function analyze(filename) -- only files on current path - local f = io.open(file.addsuffix(filename,"tex")) - if f then - local t = { } - local line = f:read("*line") or "" - local preamble = lpeg.match(pattern,line) +local function preamble_analyze(filename) -- only files on current path + local t = { } + local line = io.loadlines(file.addsuffix(filename,"tex")) + if line then + local preamble = lpegmatch(pattern,line) if preamble then for key, value in gmatch(preamble,"(%S+)%s*=%s*(%S+)") do t[key] = value end t.type = "tex" - elseif line:find("^<?xml ") then + elseif find(line,"^<?xml ") then t.type = "xml" end if t.nofruns then - scripts.context.multipass.nofruns = t.nofruns + multipass_nofruns = t.nofruns end if not t.engine then t.engine = 'luatex' end - f:close() - return t - end -end - -local function makestub(wrap,template,filename,prepname) - local stubname = file.replacesuffix(file.basename(filename),'run') - local f = io.open(stubname,'w') - if f then - if wrap then - f:write("\\starttext\n") - end - f:write(format(template,prepname or filename),"\n") - if wrap then - f:write("\\stoptext\n") - end - f:close() - filename = stubname end - return filename + return t end ---~ function scripts.context.openpdf(name) ---~ os.spawn(format('pdfopen --file "%s" 2>&1', file.replacesuffix(name,"pdf"))) ---~ end ---~ function scripts.context.closepdf(name) ---~ os.spawn(format('pdfclose --file "%s" 2>&1', file.replacesuffix(name,"pdf"))) ---~ end +-- automatically opening and closing pdf files -local pdfview -- delayed loading +local pdfview -- delayed -function scripts.context.openpdf(name,method) +local function pdf_open(name,method) pdfview = pdfview or dofile(resolvers.findfile("l-pdfview.lua","tex")) pdfview.setmethod(method) report(pdfview.status()) pdfview.open(file.replacesuffix(name,"pdf")) end -function scripts.context.closepdf(name,method) +local function pdf_close(name,method) pdfview = pdfview or dofile(resolvers.findfile("l-pdfview.lua","tex")) pdfview.setmethod(method) pdfview.close(file.replacesuffix(name,"pdf")) end -local function push_result_purge(oldbase,newbase) - for _, suffix in next, scripts.context.aftersuffixes do +-- result file handling + +local function result_push_purge(oldbase,newbase) + for _, suffix in next, usedsuffixes.after do local oldname = file.addsuffix(oldbase,suffix) local newname = file.addsuffix(newbase,suffix) os.remove(newname) @@ -727,8 +365,8 @@ local function push_result_purge(oldbase,newbase) end end -local function push_result_keep(oldbase,newbase) - for _, suffix in next, scripts.context.beforesuffixes do +local function result_push_keep(oldbase,newbase) + for _, suffix in next, usedsuffixes.before do local oldname = file.addsuffix(oldbase,suffix) local newname = file.addsuffix(newbase,suffix) local tmpname = "keep-"..oldname @@ -739,8 +377,8 @@ local function push_result_keep(oldbase,newbase) end end -local function save_result_error(oldbase,newbase) - for _, suffix in next, scripts.context.errorsuffixes do +local function result_save_error(oldbase,newbase) + for _, suffix in next, usedsuffixes.keep do local oldname = file.addsuffix(oldbase,suffix) local newname = file.addsuffix(newbase,suffix) os.remove(newname) -- to be sure @@ -748,8 +386,8 @@ local function save_result_error(oldbase,newbase) end end -local function save_result_purge(oldbase,newbase) - for _, suffix in next, scripts.context.aftersuffixes do +local function result_save_purge(oldbase,newbase) + for _, suffix in next, usedsuffixes.after do local oldname = file.addsuffix(oldbase,suffix) local newname = file.addsuffix(newbase,suffix) os.remove(newname) -- to be sure @@ -757,8 +395,8 @@ local function save_result_purge(oldbase,newbase) end end -local function save_result_keep(oldbase,newbase) - for _, suffix in next, scripts.context.aftersuffixes do +local function result_save_keep(oldbase,newbase) + for _, suffix in next, usedsuffixes.after do local oldname = file.addsuffix(oldbase,suffix) local newname = file.addsuffix(newbase,suffix) local tmpname = "keep-"..oldname @@ -768,313 +406,342 @@ local function save_result_keep(oldbase,newbase) end end -function scripts.context.run(ctxdata,filename) - -- filename overloads environment.files - local files = (filename and { filename }) or environment.files - if ctxdata then - -- todo: interface - for k,v in next, ctxdata.flags do - environment.setargument(k,v) +-- executing luatex + +local function flags_to_string(flags,prefix) -- context flags get prepended by c: + local t = { } + for k, v in table.sortedhash(flags) do + if prefix then + k = format("c:%s",k) + end + if not v or v == "" or v == '""' then + -- no need to flag false + elseif v == true then + t[#t+1] = format('--%s',k) + elseif type(v) == "string" then + t[#t+1] = format('--%s=%s',k,quote(v)) + else + t[#t+1] = format('--%s=%s',k,tostring(v)) end end - if #files > 0 then + return concat(t," ") +end + +local function luatex_command(l_flags,c_flags,filename) + return format('luatex %s %s "%s"', + flags_to_string(l_flags), + flags_to_string(c_flags,true), + filename + ) +end + +local function run_texexec(filename,a_purge,a_purgeall) + if false then + -- we need to write a top etc too and run mp etc so it's not worth the + -- trouble, so it will take a while before the next is finished -- - local interface = getargument("interface") - -- todo: getargument("interface","en") - interface = (type(interface) == "string" and interface) or "en" + -- context --extra=texutil --convert myfile + else + local texexec = resolvers.findfile("texexec.rb") or "" + if texexec ~= "" then + os.setenv("RUBYOPT","") + local options = environment.reconstructcommandline(environment.arguments_after) + options = gsub(options,"--purge","") + options = gsub(options,"--purgeall","") + local command = format("ruby %s %s",texexec,options) + if a_purge then + os.execute(command) + scripts.context.purge_job(filename,false,true) + elseif a_purgeall then + os.execute(command) + scripts.context.purge_job(filename,true,true) + else + os.exec(command) + end + end + end +end + +-- + +local function validstring(s) + return type(s) == "string" and s ~= "" and s or nil +end + +function scripts.context.run(ctxdata,filename) + -- + local a_nofile = getargument("nofile") + -- + local files = environment.files or { } + -- + local filelist, mainfile + -- + if filename then + -- the given forced name is processed, the filelist is passed to context + mainfile = filename + filelist = { filename } + -- files = files + elseif a_nofile then + -- the list of given files is processed using the dummy file + mainfile = usedfiles.nop + filelist = { usedfiles.nop } + -- files = { } + elseif #files > 0 then + -- the list of given files is processed using the stub file + mainfile = usedfiles.yes + filelist = files + files = { } + else + return + end + -- + local interface = validstring(getargument("interface")) or "en" + local formatname = formatofinterface[interface] or "cont-en" + local formatfile, scriptfile = resolvers.locateformat(formatname) + if not formatfile or not scriptfile then + report("warning: no format found, forcing remake (commandline driven)") + scripts.context.make(formatname) + formatfile, scriptfile = resolvers.locateformat(formatname) + end + if formatfile and scriptfile then + -- okay + elseif formatname then + report("error, no format found with name: %s, aborting",formatname) + return + else + report("error, no format found (provide formatname or interface)") + return + end + -- + local a_mkii = getargument("mkii") or getargument("pdftex") or getargument("xetex") + local a_purge = getargument("purge") + local a_purgeall = getargument("purgeall") + local a_purgeresult = getargument("purgeresult") + local a_global = getargument("global") + local a_timing = getargument("timing") + local a_batchmode = getargument("batchmode") + local a_nonstopmode = getargument("nonstopmode") + local a_once = getargument("once") + local a_synctex = getargument("synctex") + local a_backend = getargument("backend") + local a_arrange = getargument("arrange") + local a_noarrange = getargument("noarrange") + -- + for i=1,#filelist do -- - local formatname = scripts.context.interfaces[interface] or "cont-en" - local formatfile, scriptfile = resolvers.locateformat(formatname) - -- this catches the command line - if not formatfile or not scriptfile then - report("warning: no format found, forcing remake (commandline driven)") - scripts.context.make(formatname) - formatfile, scriptfile = resolvers.locateformat(formatname) + local filename = filelist[i] + local basename = file.basename(filename) + local pathname = file.dirname(filename) + local jobname = file.removesuffix(basename) + local ctxname = ctxdata and ctxdata.ctxname + -- + if pathname == "" and not a_global and filename ~= usedfiles.nop then + filename = "./" .. filename end -- - if formatfile and scriptfile then - for i=1,#files do - local filename = files[i] - local basename, pathname = file.basename(filename), file.dirname(filename) - local jobname = file.removesuffix(basename) - if pathname == "" and not getargument("global") then - filename = "./" .. filename + local analysis = preamble_analyze(filename) + -- + if a_mkii or analysis.engine == 'pdftex' or analysis.engine == 'xetex' then + run_texexec(filename,a_purge,a_purgeall) + else + if analysis.interface and analysis.interface ~= interface then + formatname = formatofinterface[analysis.interface] or formatname + formatfile, scriptfile = resolvers.locateformat(formatname) + end + if not formatfile or not scriptfile then + report("warning: no format found, forcing remake (source driven)") + scripts.context.make(formatname) + formatfile, scriptfile = resolvers.locateformat(formatname) + end + if formatfile and scriptfile then + -- + local suffix = validstring(getargument("suffix")) + local resultname = validstring(getargument("result")) + if suffix then + resultname = file.removesuffix(jobname) .. suffix end - -- look at the first line - local a = analyze(filename) - if a and (a.engine == 'pdftex' or a.engine == 'xetex' or getargument("pdftex") or getargument("xetex")) then - if false then - -- we need to write a top etc too and run mp etc so it's not worth the - -- trouble, so it will take a while before the next is finished - -- - -- context --extra=texutil --convert myfile - else - local texexec = resolvers.findfile("texexec.rb") or "" - if texexec ~= "" then - os.setenv("RUBYOPT","") - local options = environment.reconstructcommandline(environment.arguments_after) - options = gsub(options,"--purge","") - options = gsub(options,"--purgeall","") - local command = format("ruby %s %s",texexec,options) - if getargument("purge") then - os.execute(command) - scripts.context.purge_job(filename,false,true) - elseif getargument("purgeall") then - os.execute(command) - scripts.context.purge_job(filename,true,true) - else - os.exec(command) - end + local oldbase = "" + local newbase = "" + if resultname then + oldbase = file.removesuffix(jobname) + newbase = file.removesuffix(resultname) + if oldbase ~= newbase then + if a_purgeresult then + result_push_purge(oldbase,newbase) + else + result_push_keep(oldbase,newbase) end + else + resultname = nil end - else - if a and a.interface and a.interface ~= interface then - formatname = scripts.context.interfaces[a.interface] or formatname - formatfile, scriptfile = resolvers.locateformat(formatname) + end + -- + local pdfview = getargument("autopdf") or getargument("closepdf") + if pdfview then + pdf_close(filename,pdfview) + if resultname then + pdf_close(resultname,pdfview) end - -- this catches the command line - if not formatfile or not scriptfile then - report("warning: no format found, forcing remake (source driven)") - scripts.context.make(formatname) - formatfile, scriptfile = resolvers.locateformat(formatname) + end + -- + local okay = statistics.checkfmtstatus(formatfile) + if okay ~= true then + report("warning: %s, forcing remake",tostring(okay)) + scripts.context.make(formatname) + end + -- + local oldhash = multipass_hashfiles(jobname) + local newhash = { } + local maxnofruns = once and 1 or multipass_nofruns + -- + local c_flags = { + directives = validstring(environment.directives), -- gets passed via mtxrun + trackers = validstring(environment.trackers), -- gets passed via mtxrun + experiments = validstring(environment.experiments), -- gets passed via mtxrun + -- + result = validstring(resultname), + input = validstring(filename), + files = concat(files,","), + ctx = validstring(ctxname), + } + -- + for k, v in next, environment.arguments do + if c_flags[k] == nil then + c_flags[k] = v end - if formatfile and scriptfile then - -- we default to mkiv xml ! - -- the --prep argument might become automatic (and noprep) - local suffix = file.extname(filename) or "?" - if scripts.context.xmlsuffixes[suffix] or getargument("forcexml") then - if getargument("mkii") then - filename = makestub(true,"\\processXMLfilegrouped{%s}",filename) - else - filename = makestub(true,"\\xmlprocess{\\xmldocument}{%s}{}",filename) - end - elseif scripts.context.cldsuffixes[suffix] or getargument("forcecld") then - -- self contained cld files need to have a starttext/stoptext (less fontloading) - filename = makestub(false,"\\ctxlua{context.runfile('%s')}",filename) - elseif scripts.context.luasuffixes[suffix] or getargument("forcelua") then - filename = makestub(true,"\\ctxlua{dofile('%s')}",filename) - elseif getargument("prep") then - -- we need to keep the original jobname - filename = makestub(true,"\\readfile{%s}{}{}",filename,ctxrunner.preppedfile(ctxdata,filename)) - end - -- - -- todo: also other stubs - -- - local suffix, resultname = getargument("suffix"), getargument("result") - if type(suffix) == "string" then - resultname = file.removesuffix(jobname) .. suffix - end - local oldbase, newbase = "", "" - if type(resultname) == "string" then - oldbase = file.removesuffix(jobname) - newbase = file.removesuffix(resultname) - if oldbase ~= newbase then - if getargument("purgeresult") then - push_result_purge(oldbase,newbase) - else - push_result_keep(oldbase,newbase) - end - else - resultname = nil - end - else - resultname = nil - end - -- - local pdfview = getargument("autopdf") or getargument("closepdf") - if pdfview then - scripts.context.closepdf(filename,pdfview) - if resultname then - scripts.context.closepdf(resultname,pdfview) - end - end - -- - local okay = statistics.checkfmtstatus(formatfile) - if okay ~= true then - report("warning: %s, forcing remake",tostring(okay)) - scripts.context.make(formatname) - end - -- - local flags = { } - if getargument("batchmode") or getargument("batch") then - flags[#flags+1] = "--interaction=batchmode" - end - if getargument("synctex") then - -- this should become a directive - report("warning: synctex is enabled") -- can add upto 5% runtime - flags[#flags+1] = "--synctex=1" - end - flags[#flags+1] = "--fmt=" .. quote(formatfile) - flags[#flags+1] = "--lua=" .. quote(scriptfile) - -- - -- We pass these directly. - -- - ---~ local silent = getargument("silent") ---~ local noconsole = getargument("noconsole") ---~ local directives = getargument("directives") ---~ local trackers = getargument("trackers") ---~ if silent == true then ---~ silent = "*" ---~ end ---~ if type(silent) == "string" then ---~ if type(directives) == "string" then ---~ directives = format("%s,logs.blocked={%s}",directives,silent) ---~ else ---~ directives = format("logs.blocked={%s}",silent) ---~ end ---~ end ---~ if noconsole then ---~ if type(directives) == "string" then ---~ directives = format("%s,logs.target=file",directives) ---~ else ---~ directives = format("logs.target=file") ---~ end ---~ end - - local directives = environment.directives - local trackers = environment.trackers - local experiments = environment.experiments - - -- - if type(directives) == "string" then - flags[#flags+1] = format('--directives="%s"',directives) - end - if type(trackers) == "string" then - flags[#flags+1] = format('--trackers="%s"',trackers) - end - -- - local backend = getargument("backend") - if type(backend) ~= "string" then - backend = "pdf" - end - flags[#flags+1] = format('--backend="%s"',backend) - -- - local command = format("luatex %s %s \\stoptext", concat(flags," "), quote(filename)) - local oldhash, newhash = scripts.context.multipass.hashfiles(jobname), { } - local once = getargument("once") - local maxnofruns = (once and 1) or scripts.context.multipass.nofruns - local arrange = getargument("arrange") - for i=1,maxnofruns do - -- 1:first run, 2:successive run, 3:once, 4:last of maxruns - local kindofrun = (once and 3) or (i==1 and 1) or (i==maxnofruns and 4) or 2 - scripts.context.multipass.makeoptionfile(jobname,ctxdata,kindofrun,i,false,once) -- kindofrun, currentrun, final - report("run %s: %s",i,command) ---~ print("\n") -- cleaner, else continuation on same line - print("") -- cleaner, else continuation on same line - local returncode, errorstring = os.spawn(command) - --~ if returncode == 3 then - --~ scripts.context.make(formatname) - --~ returncode, errorstring = os.spawn(command) - --~ if returncode == 3 then - --~ report("ks: return code 3, message: %s",errorstring or "?") - --~ os.exit(1) - --~ end - --~ end - if not returncode then - report("fatal error: no return code, message: %s",errorstring or "?") - if resultname then - save_result_error(oldbase,newbase) - end - os.exit(1) - break - elseif returncode > 0 then - report("fatal error: return code: %s",returncode or "?") - if resultname then - save_result_error(oldbase,newbase) - end - os.exit(returncode) - break - else - scripts.context.multipass.copyluafile(jobname) - -- scripts.context.multipass.copytuifile(jobname) - newhash = scripts.context.multipass.hashfiles(jobname) - if scripts.context.multipass.changed(oldhash,newhash) then - oldhash = newhash - else - break - end - end - end - -- - if arrange then - local kindofrun = 3 - scripts.context.multipass.makeoptionfile(jobname,ctxdata,kindofrun,i,true) -- kindofrun, currentrun, final - report("arrange run: %s",command) - local returncode, errorstring = os.spawn(command) - if not returncode then - report("fatal error: no return code, message: %s",errorstring or "?") - os.exit(1) - elseif returncode > 0 then - report("fatal error: return code: %s",returncode or "?") - os.exit(returncode) - end - end - -- - if getargument("purge") then - scripts.context.purge_job(jobname) - elseif getargument("purgeall") then - scripts.context.purge_job(jobname,true) - end - -- - os.remove(jobname..".top") - -- + end + -- + local l_flags = { + ["interaction"] = (a_batchmode and "batchmode") or (a_nonstopmode and "nonstopmode") or nil, + ["synctex"] = a_synctex and 1 or nil, + ["no-parse-first-line"] = true, + -- ["no-mktex"] = true, + -- ["file-line-error"] = true, + ["fmt"] = formatfile, + ["lua"] = scriptfile, + ["jobname"] = jobname, + } + -- + if a_synctex then + report("warning: synctex is enabled") -- can add upto 5% runtime + end + -- + -- kindofrun: 1:first run, 2:successive run, 3:once, 4:last of maxruns + -- + for currentrun=1,maxnofruns do + -- + c_flags.final = false + c_flags.kindofrun = (a_once and 3) or (currentrun==1 and 1) or (currentrun==maxnofruns and 4) or 2 + c_flags.currentrun = currentrun + c_flags.noarrange = a_noarrange or a_arrange or nil + -- + local command = luatex_command(l_flags,c_flags,mainfile) + -- + report("run %s: %s",i,command) + print("") -- cleaner, else continuation on same line + local returncode, errorstring = os.spawn(command) + if not returncode then + report("fatal error: no return code, message: %s",errorstring or "?") if resultname then - if getargument("purgeresult") then - -- so, if there is no result then we don't get the old one, but - -- related files (log etc) are still there for tracing purposes - save_result_purge(oldbase,newbase) - else - save_result_keep(oldbase,newbase) - end - report("result renamed to: %s",newbase) + result_save_error(oldbase,newbase) end - -- - if getargument("purge") then - scripts.context.purge_job(resultname) - elseif getargument("purgeall") then - scripts.context.purge_job(resultname,true) - end - -- - local pdfview = getargument("autopdf") - if pdfview then - scripts.context.openpdf(resultname or filename,pdfview) - end - -- - if getargument("timing") then - report() - report("you can process (timing) statistics with:",jobname) - report() - report("context --extra=timing '%s'",jobname) - report("mtxrun --script timing --xhtml [--launch --remove] '%s'",jobname) - report() + os.exit(1) + break + elseif returncode > 0 then + report("fatal error: return code: %s",returncode or "?") + if resultname then + result_save_error(oldbase,newbase) end + os.exit(returncode) + break else - if formatname then - report("error, no format found with name: %s, skipping",formatname) + multipass_copyluafile(jobname) + newhash = multipass_hashfiles(jobname) + if multipass_changed(oldhash,newhash) then + oldhash = newhash else - report("error, no format found (provide formatname or interface)") + break end - break end + -- + end + -- + if a_arrange then + -- + c_flags.final = true + c_flags.kindofrun = 3 + c_flags.currentrun = c_flags.currentrun + 1 + c_flags.noarrange = a_arrange and true or nil + -- + local command = luatex_command(l_flags,c_flags,mainfile) + -- + report("arrange run: %s",command) + local returncode, errorstring = os.spawn(command) + if not returncode then + report("fatal error: no return code, message: %s",errorstring or "?") + os.exit(1) + elseif returncode > 0 then + report("fatal error: return code: %s",returncode or "?") + os.exit(returncode) + end + -- + end + -- + if a_purge then + scripts.context.purge_job(jobname) + elseif a_purgeall then + scripts.context.purge_job(jobname,true) + end + -- + if resultname then + if a_purgeresult then + -- so, if there is no result then we don't get the old one, but + -- related files (log etc) are still there for tracing purposes + result_save_purge(oldbase,newbase) + else + result_save_keep(oldbase,newbase) + end + report("result renamed to: %s",newbase) + end + -- + if purge then + scripts.context.purge_job(resultname) + elseif purgeall then + scripts.context.purge_job(resultname,true) + end + -- + local pdfview = getargument("autopdf") + if pdfview then + pdf_open(resultname or jobname,pdfview) + end + -- + if a_timing then + report() + report("you can process (timing) statistics with:",jobname) + report() + report("context --extra=timing '%s'",jobname) + report("mtxrun --script timing --xhtml [--launch --remove] '%s'",jobname) + report() end - end - else - if formatname then - report("error, no format found with name: %s, aborting",formatname) else - report("error, no format found (provide formatname or interface)") + if formatname then + report("error, no format found with name: %s, skipping",formatname) + else + report("error, no format found (provide formatname or interface)") + end + break end end end + -- end -function scripts.context.pipe() +function scripts.context.pipe() -- still used? -- context --pipe -- context --pipe --purge --dummyfile=whatever.tmp local interface = getargument("interface") interface = (type(interface) == "string" and interface) or "en" - local formatname = scripts.context.interfaces[interface] or "cont-en" + local formatname = formatofinterface[interface] or "cont-en" local formatfile, scriptfile = resolvers.locateformat(formatname) if not formatfile or not scriptfile then report("warning: no format found, forcing remake (commandline driven)") @@ -1087,11 +754,16 @@ function scripts.context.pipe() report("warning: %s, forcing remake",tostring(okay)) scripts.context.make(formatname) end - local flags = { - "--interaction=scrollmode", - "--fmt=" .. quote(formatfile), - "--lua=" .. quote(scriptfile), - "--backend=pdf", + local l_flags = { + interaction = "scrollmode", + fmt = formatfile, + lua = scriptfile, + } + local c_flags = { + backend = "pdf", + final = false, + kindofrun = 3, + currentrun = 1, } local filename = getargument("dummyfile") or "" if filename == "" then @@ -1100,10 +772,9 @@ function scripts.context.pipe() else filename = file.addsuffix(filename,"tmp") io.savedata(filename,"\\relax") - scripts.context.multipass.makeoptionfile(filename,{ flags = flags },3,1,false) -- kindofrun, currentrun, final report("entering scrollmode using '%s' with optionfile, end job with \\end",filename) end - local command = format("luatex %s %s", concat(flags," "), quote(filename)) + local command = luatex_command(l_flags,c_flags,filename) os.spawn(command) if getargument("purge") then scripts.context.purge_job(filename) @@ -1123,11 +794,9 @@ end local make_mkiv_format = environment.make_format local function make_mkii_format(name,engine) - if getargument(engine) then - local command = format("mtxrun texexec.rb --make --%s %s",name,engine) - report("running command: %s",command) - os.spawn(command) - end + local command = format("mtxrun texexec.rb --make --%s %s",name,engine) + report("running command: %s",command) + os.spawn(command) end function scripts.context.generate() @@ -1140,14 +809,17 @@ function scripts.context.make(name) if not getargument("fast") then -- as in texexec scripts.context.generate() end - local list = (name and { name }) or (environment.files[1] and environment.files) or scripts.context.defaultformats + local list = (name and { name }) or (environment.files[1] and environment.files) or defaultformats + local engine = getargument("engine") or "luatex" for i=1,#list do local name = list[i] - name = scripts.context.interfaces[name] or name or "" - if name ~= "" then + name = formatofinterface[name] or name or "" + if name == "" then + -- nothing + elseif engine == "luatex" then make_mkiv_format(name) - make_mkii_format(name,"pdftex") - make_mkii_format(name,"xetex") + elseif engine == "pdftex" or engine == "xetex" then + make_mkii_format(name,engine) end end end @@ -1155,25 +827,30 @@ end function scripts.context.ctx() local ctxdata = ctxrunner.new() ctxdata.jobname = environment.files[1] - ctxrunner.manipulate(ctxdata,getargument("ctx")) + ctxrunner.checkfile(ctxdata,getargument("ctx")) + ctxrunner.checkflags(ctxdata) scripts.context.run(ctxdata) end function scripts.context.autoctx() local ctxdata = nil - local files = (filename and { filename }) or environment.files + local files = environment.files local firstfile = #files > 0 and files[1] - if firstfile and file.extname(firstfile) == "xml" then - local f = io.open(firstfile) - if f then - local chunk = f:read(512) or "" - f:close() - local ctxname = match(chunk,"<%?context%-directive%s+job%s+ctxfile%s+([^ ]-)%s*?>") - if ctxname then - ctxdata = ctxrunner.new() - ctxdata.jobname = firstfile - ctxrunner.manipulate(ctxdata,ctxname) + if firstfile then + local suffix = file.suffix(firstfile) + if suffix == "xml" then + local chunk = io.loadchunk(firstfile) -- 1024 + if chunk then + local ctxname = match(chunk,"<%?context%-directive%s+job%s+ctxfile%s+([^ ]-)%s*?>") + if ctxname then + ctxdata = ctxrunner.new() + ctxdata.jobname = firstfile + ctxrunner.checkfile(ctxdata,ctxname) + ctxrunner.checkflags(ctxdata) + end end + elseif suffix == "tex" then + -- maybe but we scan the preamble later too end end scripts.context.run(ctxdata) @@ -1206,8 +883,8 @@ function scripts.context.metapost() local tempname = file.addsuffix(jobname,"tex") io.savedata(tempname,format(template,"metafun",filename)) environment.files[1] = tempname - environment.setargument("result",resultname) - environment.setargument("once",true) + setargument("result",resultname) + setargument("once",true) scripts.context.run() scripts.context.purge_job(jobname,true) scripts.context.purge_job(resultname,true) @@ -1238,6 +915,8 @@ function scripts.context.version() end end +-- purging files + local generic_files = { "texexec.tex", "texexec.tui", "texexec.tuo", "texexec.tuc", "texexec.tua", @@ -1262,7 +941,6 @@ local persistent_runfiles = { } local special_runfiles = { ---~ "-mpgraph*", "-mprun*", "-temp-*" -- hm, wasn't this escaped? "-mpgraph", "-mprun", "-temp-" } @@ -1278,9 +956,6 @@ local function purge_file(dfile,cfile) end end -local function remove_special_files(pattern) -end - function scripts.context.purge_job(jobname,all,mkiitoo) if jobname and jobname ~= "" then jobname = file.basename(jobname) @@ -1335,12 +1010,14 @@ function scripts.context.purge(all,pattern,mkiitoo) end end +-- touching files (signals regeneration of formats) + local function touch(name,pattern) local name = resolvers.findfile(name) local olddata = io.loaddata(name) if olddata then local oldversion, newversion = "", os.date("%Y.%m.%d %H:%M") - local newdata, ok = olddata:gsub(pattern,function(pre,mid,post) + local newdata, ok = gsub(olddata,pattern,function(pre,mid,post) oldversion = mid return pre .. newversion .. post end) @@ -1374,6 +1051,8 @@ function scripts.context.touch() touchfiles("mkii") touchfiles("mkiv") touchfiles("mkvi") + else + report("touching needs --expert") end end @@ -1387,12 +1066,12 @@ function scripts.context.modules(pattern) local found = resolvers.findfile("context.mkiv") if not pattern or pattern == "" then -- official files in the tree - for _, card in ipairs(cards) do - resolvers.findwildcardfiles(card,list) + for i=1,#cards do + resolvers.findwildcardfiles(cards[i],list) end -- my dev path - for _, card in ipairs(cards) do - dir.glob(file.join(file.dirname(found),card),list) + for i=1,#cards do + dir.glob(file.join(file.dirname(found),cards[i]),list) end else resolvers.findwildcardfiles(pattern,list) @@ -1462,30 +1141,28 @@ end function scripts.context.extra() local extra = getargument("extra") - if type(extra) == "string" then - if getargument("help") then - scripts.context.extras(extra) + if type(extra) ~= "string" then + scripts.context.extras() + elseif getargument("help") then + scripts.context.extras(extra) + else + local fullextra = extra + if not find(fullextra,"mtx%-context%-") then + fullextra = "mtx-context-" .. extra + end + local foundextra = resolvers.findfile(fullextra) + if foundextra == "" then + scripts.context.extras() + return else - local fullextra = extra - if not find(fullextra,"mtx%-context%-") then - fullextra = "mtx-context-" .. extra - end - local foundextra = resolvers.findfile(fullextra) - if foundextra == "" then - scripts.context.extras() - return - else - report("processing extra: %s", foundextra) - end - environment.setargument("purgeall",true) - local result = environment.setargument("result") or "" - if result == "" then - environment.setargument("result","context-extra") - end - scripts.context.run(nil,foundextra) + report("processing extra: %s", foundextra) end - else - scripts.context.extras() + setargument("purgeall",true) + local result = getargument("result") or "" + if result == "" then + setargument("result","context-extra") + end + scripts.context.run(nil,foundextra) end end @@ -1493,25 +1170,27 @@ end function scripts.context.trackers() environment.files = { resolvers.findfile("m-trackers.mkiv") } - scripts.context.multipass.nofruns = 1 - environment.setargument("purgeall",true) + multipass_nofruns = 1 + setargument("purgeall",true) scripts.context.run() end function scripts.context.directives() environment.files = { resolvers.findfile("m-directives.mkiv") } - scripts.context.multipass.nofruns = 1 - environment.setargument("purgeall",true) + multipass_nofruns = 1 + setargument("purgeall",true) scripts.context.run() end function scripts.context.logcategories() environment.files = { resolvers.findfile("m-logcategories.mkiv") } - scripts.context.multipass.nofruns = 1 - environment.setargument("purgeall",true) + multipass_nofruns = 1 + setargument("purgeall",true) scripts.context.run() end +-- updating (often one will use mtx-update instead) + function scripts.context.timed(action) statistics.timed(action) end @@ -1548,7 +1227,7 @@ function scripts.context.update() local function is_okay(basetree) for _, tree in next, validtrees do local pattern = gsub(tree,"%-","%%-") - if basetree:find(pattern) then + if find(basetree,pattern) then return tree end end @@ -1614,7 +1293,7 @@ function scripts.context.update() end for k in zipfile:files() do local filename = k.filename - if filename:find("/$") then + if find(filename,"/$") then lfs.mkdir(filename) else local data = zip.loaddata(zipfile,filename) @@ -1652,6 +1331,23 @@ function scripts.context.update() end end +-- getting it done + +if getargument("nostats") then + setargument("nostatistics",true) + setargument("nostat",nil) +end + +if getargument("batch") then + setargument("batchmode",true) + setargument("batch",nil) +end + +if getargument("nonstop") then + setargument("nonstopmode",true) + setargument("nonstop",nil) +end + do local silent = getargument("silent") @@ -1664,9 +1360,9 @@ do end if getargument("once") then - scripts.context.multipass.nofruns = 1 + multipass_nofruns = 1 elseif getargument("runs") then - scripts.context.multipass.nofruns = tonumber(getargument("runs")) or nil + multipass_nofruns = tonumber(getargument("runs")) or nil end if getargument("profile") then @@ -1674,7 +1370,6 @@ if getargument("profile") then end if getargument("run") then --- scripts.context.timed(scripts.context.run) scripts.context.timed(scripts.context.autoctx) elseif getargument("make") then scripts.context.timed(function() scripts.context.make() end) @@ -1711,10 +1406,7 @@ elseif getargument("showdirectives") or getargument("directives") == true then scripts.context.directives() elseif getargument("showlogcategories") then scripts.context.logcategories() -elseif getargument("track") and type(getargument("track")) == "boolean" then -- for old times sake, will go - scripts.context.trackers() -elseif environment.files[1] then --- scripts.context.timed(scripts.context.run) +elseif environment.files[1] or getargument("nofile") then scripts.context.timed(scripts.context.autoctx) elseif getargument("pipe") then scripts.context.timed(scripts.context.pipe) diff --git a/scripts/context/lua/mtx-epub.lua b/scripts/context/lua/mtx-epub.lua index 7d1c15774..000ac0670 100644 --- a/scripts/context/lua/mtx-epub.lua +++ b/scripts/context/lua/mtx-epub.lua @@ -263,20 +263,18 @@ function scripts.epub.make() application.report("creating archive\n\n") - local done = false - local list = { } - lfs.chdir(epubpath) os.remove(epubfile) + local done = false + for i=1,#zippers do local zipper = zippers[i] if os.execute(format(zipper.uncompressed,epubfile,"mimetype")) then os.execute(format(zipper.compressed,epubfile,"META-INF")) os.execute(format(zipper.compressed,epubfile,"OPS")) done = zipper.name - else - list[#list+1] = zipper.name + break end end @@ -285,6 +283,10 @@ function scripts.epub.make() if done then application.report("epub archive made using %s: %s",done,file.join(epubpath,epubfile)) else + local list = { } + for i=1,#zippers do + list[#list+1] = zipper.name + end application.report("no epub archive made, install one of: %s",concat(list," ")) end diff --git a/scripts/context/lua/mtx-fcd.lua b/scripts/context/lua/mtx-fcd.lua new file mode 100644 index 000000000..7ab48707a --- /dev/null +++ b/scripts/context/lua/mtx-fcd.lua @@ -0,0 +1,366 @@ +if not modules then modules = { } end modules ['mtx-fcd'] = { + version = 1.002, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", + comment = "based on the ruby version from 2005", +} + +-- This is a kind of variant of the good old ncd (norton change directory) program. This +-- script uses the same indirect cmd trick as Erwin Waterlander's wcd program. +-- +-- The program is called via the stubs fcd.cmd or fcd.sh. On unix one should probably source +-- the file: ". fcd args" in order to make the chdir persistent. +-- +-- You need to create a stub with: +-- +-- mtxrun --script fcd --stub > fcd.cmd +-- mtxrun --script fcd --stub > fcd.sh +-- +-- The stub starts this script and afterwards runs the created directory change script as +-- part if the same run, so that indeed we change. + +local helpinfo = [[ +--clear clear the cache +--clear --history [entyr] clear the history +--scan clear the cache and add given path(s) +--add add given path(s) +--find file given path (can be substring) +--find --nohistory file given path (can be substring) but don't use history +--stub print platform stub file +--list show roots of cached dirs +--list --history show history of chosen dirs +--help show this help + +usage: + + fcd --scan t:\ + fcd --add f:\project + fcd [--find] whatever + fcd --list +]] + +local application = logs.application { + name = "mtx-fcd", + banner = "Fast Directory Change", + helpinfo = helpinfo, +} + +local report = application.report +local writeln = print -- texio.write_nl + +local find, char, byte, lower, gsub, format = string.find, string.char, string.byte, string.lower, string.gsub, string.format + +local mswinstub = [[@echo off + +rem this is: fcd.cmd + +@echo off + +if not exist "%HOME%" goto homepath + +:home + +mtxrun --script mtx-fcd.lua %1 %2 %3 %4 %5 %6 %7 %8 %9 + +if exist "%HOME%\mtx-fcd-goto.cmd" call "%HOME%\mtx-fcd-goto.cmd" + +goto end + +:homepath + +if not exist "%HOMEDRIVE%\%HOMEPATH%" goto end + +mtxrun --script mtx-fcd.lua %1 %2 %3 %4 %5 %6 %7 %8 %9 + +if exist "%HOMEDRIVE%\%HOMEPATH%\mtx-fcd-goto.cmd" call "%HOMEDRIVE%\%HOMEPATH%\mtx-fcd-goto.cmd" + +goto end + +:end +]] + +local unixstub = [[#!/usr/bin/env sh + +# this is: fcd.sh + +# mv fcd.sh fcd +# chmod fcd 755 +# . fcd [args] + +ruby -S fcd_start.rb $1 $2 $3 $4 $5 $6 $7 $8 $9 + +if test -f "$HOME/fcd_stage.sh" ; then + . $HOME/fcd_stage.sh ; +fi; + +]] + +local gotofile +local datafile +local stubfile +local stubdata +local stubdummy +local stubchdir + +if os.platform == 'mswin' then + gotofile = 'mtx-fcd-goto.cmd' + datafile = 'mtx-fcd-data.lua' + stubfile = 'fcd.cmd' + stubdata = mswinstub + stubdummy = 'rem no dir to change to' + stubchdir = 'cd /d "%s"' +else + gotofile = 'mtx-fcd-goto.sh' + datafile = 'mtx-fcd-data.lua' + stubfile = 'fcd.sh' + stubdata = unixstub + stubdummy = '# no dir to change to' + stubchdir = '# cd "%s"' +end + +local homedir = os.env["HOME"] or "" -- no longer TMP etc + +if homedir == "" then + homedir = format("%s/%s",os.env["HOMEDRIVE"] or "",os.env["HOMEPATH"] or "") +end + +if homedir == "/" or not lfs.isdir(homedir) then + os.exit() +end + +local datafile = file.join(homedir,datafile) +local gotofile = file.join(homedir,gotofile) +local hash = nil +local found = { } +local pattern = "" +local version = modules['mtx-fcd'].version + +io.savedata(gotofile,stubdummy) + +if not lfs.isfile(gotofile) then + -- write error + os.exit() +end + +local function fcd_clear(onlyhistory,what) + if onlyhistory and hash and hash.history then + if what and what ~= "" then + hash.history[what] = nil + else + hash.history = { } + end + else + hash = { + name = "fcd cache", + comment = "generated by mtx-fcd.lua", + created = os.date(), + version = version, + paths = { }, + history = { }, + } + end +end + +local function fcd_changeto(dir) + if dir and dir ~= "" then + io.savedata(gotofile,format(stubchdir,dir)) + end +end + +local function fcd_load(forcecreate) + if lfs.isfile(datafile) then + hash = dofile(datafile) + end + if not hash or hash.version ~= version then + if forcecache then + fcd_clear() + else + writeln("empty dir cache") + fcd_clear() + os.exit() + end + end +end + +local function fcd_save() + if hash then + io.savedata(datafile,table.serialize(hash,true)) + end +end + +local function fcd_list(onlyhistory) + if hash then + writeln("") + if onlyhistory then + if next(hash.history) then + for k, v in table.sortedhash(hash.history) do + writeln(format("%s => %s",k,v)) + end + else + writeln("no history") + end + else + local paths = hash.paths + if #paths > 0 then + for i=1,#paths do + local path = paths[i] + writeln(format("%4i %s",#path[2],path[1])) + end + else + writeln("empty cache") + end + end + end +end + +local function fcd_find() + found = { } + pattern = environment.files[1] or "" + if pattern ~= "" then + pattern = string.escapedpattern(pattern) + local paths = hash.paths + for i=1,#paths do + local paths = paths[i][2] + for i=1,#paths do + local path = paths[i] + if find(path,pattern) then + found[#found+1] = path + end + end + end + end +end + +local function fcd_choose(new) + if pattern == "" then + writeln(format("staying in dir %q",(gsub(lfs.currentdir(),"\\","/")))) + return + end + if #found == 0 then + writeln(format("dir %q not found",pattern)) + return + end + local okay = #found == 1 and found[1] or (not new and hash.history[pattern]) + if okay then + writeln(format("changing to %q",okay)) + fcd_changeto(okay) + return + end + local offset = 0 + while true do + if not found[offset] then + offset = 0 + end + io.write("\n") + for i=1,26 do + local v = found[i+offset] + if v then + writeln(format("%s %3i %s",char(i+96),offset+i,v)) + else + break + end + end + offset = offset + 26 + if found[offset+1] then + io.write("\n[press enter for more or select letter]\n\n>> ") + else + io.write("\n[select letter]\n\n>> ") + end + local answer = lower(io.read() or "") + if not answer or answer == 'quit' then + break + elseif #answer > 0 then + local choice = tonumber(answer) + if not choice then + if answer >= "a" and answer <= "z" then + choice = byte(answer) - 96 + offset - 26 + end + end + local newdir = found[choice] + if newdir then + hash.history[pattern] = newdir + writeln(format("changing to %q",newdir)) + fcd_changeto(newdir) + fcd_save() + return + end + else + -- try again + end + end +end + +local function globdirs(path,dirs) + local dirs = dirs or { } + for name in lfs.dir(path) do + if not find(name,"%.$") then + local fullname = path .. "/" .. name + if lfs.isdir(fullname) then + dirs[#dirs+1] = fullname + globdirs(fullname,dirs) + end + end + end + return dirs +end + +local function fcd_scan() + if hash then + local paths = hash.paths + for i=1,#environment.files do + local name = environment.files[i] + local name = gsub(name,"\\","/") + local name = gsub(name,"/$","") + local list = globdirs(name) + local done = false + for i=1,#paths do + if paths[i][1] == name then + paths[i][2] = list + done = true + break + end + end + if not done then + paths[#paths+1] = { name, list } + end + end + end +end + +local argument = environment.argument + +if argument("clear") then + if argument("history") then + fcd_load() + fcd_clear(true) + else + fcd_clear() + end + fcd_save() +elseif argument("scan") then + fcd_clear() + fcd_scan() + fcd_save() +elseif argument("add") then + fcd_load(true) + fcd_scan() + fcd_save() +elseif argument("stub") then + writeln(stubdata) +elseif argument("list") then + fcd_load() + if argument("history") then + fcd_list(true) + else + fcd_list() + end +elseif argument("help") then + application.help() +else -- also argument("find") + fcd_load() + fcd_find() + fcd_choose(argument("nohistory")) +end + diff --git a/scripts/context/lua/mtx-grep.lua b/scripts/context/lua/mtx-grep.lua index 3cbc1421a..98a97279d 100644 --- a/scripts/context/lua/mtx-grep.lua +++ b/scripts/context/lua/mtx-grep.lua @@ -60,7 +60,7 @@ function scripts.grep.find(pattern, files, offset) if m > 0 then nofmatches = nofmatches + m nofmatchedfiles = nofmatchedfiles + 1 - write_nl(format("%s: %s",name,m)) + write_nl(format("%5i %s",m,name)) io.flush() end else @@ -127,7 +127,7 @@ function scripts.grep.find(pattern, files, offset) if count and m > 0 then nofmatches = nofmatches + m nofmatchedfiles = nofmatchedfiles + 1 - write_nl(format("%s: %s",name,m)) + write_nl(format("%5i %s",m,name)) io.flush() end end diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index 108f2a8a1..cc29845b5 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -1341,12 +1341,16 @@ function lpeg.split(separator,str) end function string.split(str,separator) - local c = cache[separator] - if not c then - c = tsplitat(separator) - cache[separator] = c + if separator then + local c = cache[separator] + if not c then + c = tsplitat(separator) + cache[separator] = c + end + return match(c,str) + else + return { str } end - return match(c,str) end local spacing = patterns.spacer^0 * newline -- sort of strip @@ -1851,14 +1855,14 @@ else io.fileseparator, io.pathseparator = "/" , ":" end -function io.loaddata(filename,textmode) +function io.loaddata(filename,textmode) -- return nil if empty local f = io.open(filename,(textmode and 'r') or 'rb') if f then local data = f:read('*all') f:close() - return data - else - return nil + if #data > 0 then + return data + end end end @@ -1880,6 +1884,45 @@ function io.savedata(filename,data,joiner) end end +function io.loadlines(filename,n) -- return nil if empty + local f = io.open(filename,'r') + if f then + if n then + local lines = { } + for i=1,n do + local line = f:read("*lines") + if line then + lines[#lines+1] = line + else + break + end + end + f:close() + lines = concat(lines,"\n") + if #lines > 0 then + return lines + end + else + local line = f:read("*line") or "" + assert(f:close()) + if #line > 0 then + return line + end + end + end +end + +function io.loadchunk(filename,n) + local f = io.open(filename,'rb') + if f then + local data = f:read(n or 1024) + f:close() + if #data > 0 then + return data + end + end +end + function io.exists(filename) local f = io.open(filename) if f == nil then @@ -3081,15 +3124,30 @@ 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 -function file.needs_updating(oldname,newname,threshold) -- size modification access change - local oldtime = lfs.attributes(oldname, modification) - local newtime = lfs.attributes(newname, modification) - if newtime >= oldtime then - return false - elseif oldtime - newtime < (threshold or 1) then - return false +function file.needsupdating(oldname,newname,threshold) -- size modification access change + local oldtime = lfs.attributes(oldname,"modification") + if oldtime then + local newtime = lfs.attributes(newname,"modification") + if not newtime then + return true -- no new file, so no updating needed + elseif newtime >= oldtime then + return false -- new file definitely needs updating + elseif oldtime - newtime < (threshold or 1) then + return false -- new file is probably still okay + else + return true -- new file has to be updated + end else - return true + return false -- no old file, so no updating needed + end +end + +file.needs_updating = file.needsupdating + +function file.syncmtimes(oldname,newname) + local oldtime = lfs.attributes(oldname,"modification") + if oldtime and lfs.isfile(newname) then + lfs.touch(newname,oldtime,oldtime) end end @@ -3111,7 +3169,7 @@ function file.loadchecksum(name) return nil end -function file.savechecksum(name, checksum) +function file.savechecksum(name,checksum) if not checksum then checksum = file.checksum(name) end if checksum then io.savedata(name .. ".md5",checksum) @@ -5586,7 +5644,7 @@ function setters.show(t) local value, default, modules = functions.value, functions.default, #functions value = value == nil and "unset" or tostring(value) default = default == nil and "unset" or tostring(default) - t.report("%-30s modules: %2i default: %6s value: %6s",name,modules,default,value) + t.report("%-50s modules: %2i default: %6s value: %6s",name,modules,default,value) end end t.report() @@ -5678,17 +5736,31 @@ end) -- experiment -local flags = environment and environment.engineflags +if environment then -if flags then - if trackers and flags.trackers then - setters.initialize("flags","trackers", settings_to_hash(flags.trackers)) - -- t_enable(flags.trackers) - end - if directives and flags.directives then - setters.initialize("flags","directives", settings_to_hash(flags.directives)) - -- d_enable(flags.directives) + -- The engineflags are known earlier than environment.arguments but maybe we + -- need to handle them both as the later are parsed differently. The c: prefix + -- is used by mtx-context to isolate the flags from those that concern luatex. + + local engineflags = environment.engineflags + + if engineflags then + if trackers then + local list = engineflags["c:trackers"] or engineflags["trackers"] + if type(list) == "string" then + setters.initialize("flags","trackers",settings_to_hash(list)) + -- t_enable(list) + end + end + if directives then + local list = engineflags["c:directives"] or engineflags["directives"] + if type(list) == "string" then + setters.initialize("flags","directives", settings_to_hash(list)) + -- d_enable(list) + end + end end + end -- here @@ -6619,6 +6691,8 @@ local mt = { setmetatable(environment,mt) +-- context specific arguments (in order not to confuse the engine) + function environment.initializearguments(arg) local arguments, files = { }, { } environment.arguments, environment.files, environment.sortedflags = arguments, files, nil @@ -6627,10 +6701,12 @@ function environment.initializearguments(arg) if index > 0 then local flag, value = match(argument,"^%-+(.-)=(.-)$") if flag then + flag = gsub(flag,"^c:","") arguments[flag] = unquoted(value or "") else flag = match(argument,"^%-+(.+)") if flag then + flag = gsub(flag,"^c:","") arguments[flag] = true else files[#files+1] = argument @@ -6650,7 +6726,7 @@ end -- tricky: too many hits when we support partials unless we add -- a registration of arguments so from now on we have 'partial' -function environment.argument(name,partial) +function environment.getargument(name,partial) local arguments, sortedflags = environment.arguments, environment.sortedflags if arguments[name] then return arguments[name] @@ -6673,6 +6749,8 @@ function environment.argument(name,partial) return nil end +environment.argument = environment.getargument + function environment.splitarguments(separator) -- rather special, cut-off before separator local done, before, after = false, { }, { } local originalarguments = environment.originalarguments diff --git a/scripts/context/ruby/fcd_start.rb b/scripts/context/ruby/fcd_start.rb deleted file mode 100644 index b1fa42a2a..000000000 --- a/scripts/context/ruby/fcd_start.rb +++ /dev/null @@ -1,472 +0,0 @@ -# Hans Hagen / PRAGMA ADE / 2005 / www.pragma-ade.com -# -# Fast Change Dir -# -# This is a kind of variant of the good old ncd -# program. This script uses the same indirect cmd -# trick as Erwin Waterlander's wcd program. -# -# === windows: fcd.cmd === -# -# @echo off -# ruby -S fcd_start.rb %1 %2 %3 %4 %5 %6 %7 %8 %9 -# if exist "%HOME%/fcd_stage.cmd" call %HOME%/fcd_stage.cmd -# -# === linux: fcd (fcd.sh) === -# -# !/usr/bin/env sh -# ruby -S fcd_start.rb $1 $2 $3 $4 $5 $6 $7 $8 $9 -# if test -f "$HOME/fcd_stage.sh" ; then -# . $HOME/fcd_stage.sh ; -# fi; -# -# === -# -# On linux, one should source the file: ". fcd args" in order -# to make the chdir persistent. -# -# You can create a stub with: -# -# ruby fcd_start.rb --stub --verbose -# -# usage: -# -# fcd --make t:\ -# fcd --add f:\project -# fcd [--find] whatever -# fcd [--find] whatever c (c being a list entry) -# fcd [--find] whatever . (last choice with this pattern) -# fcd --list - -# todo: HOMEDRIVE\HOMEPATH - -require 'rbconfig' - -class FastCD - - @@rootpath = nil - - ['HOME','TEMP','TMP','TMPDIR'].each do |key| - if ENV[key] then - if FileTest.directory?(ENV[key]) then - @@rootpath = ENV[key] - break - end - end - end - - exit unless @@rootpath - - @@mswindows = Config::CONFIG['host_os'] =~ /mswin/ - @@maxlength = 26 - - require 'Win32API' if @@mswindows - - if @@mswindows then - @@stubcode = [ - '@echo off', - '', - 'if not exist "%HOME%" goto temp', - '', - ':home', - '', - 'ruby -S fcd_start.rb %1 %2 %3 %4 %5 %6 %7 %8 %9', - '', - 'if exist "%HOME%\fcd_stage.cmd" call %HOME%\fcd_stage.cmd', - 'goto end', - '', - ':temp', - '', - 'ruby -S fcd_start.rb %1 %2 %3 %4 %5 %6 %7 %8 %9', - '', - 'if exist "%TEMP%\fcd_stage.cmd" call %TEMP%\fcd_stage.cmd', - 'goto end', - '', - ':end' - ].join("\n") - else - @@stubcode = [ - '#!/usr/bin/env sh', - '', - 'ruby -S fcd_start.rb $1 $2 $3 $4 $5 $6 $7 $8 $9', - '', - 'if test -f "$HOME/fcd_stage.sh" ; then', - ' . $HOME/fcd_stage.sh ;', - 'fi;' - ].join("\n") - end - - @@selfpath = File.dirname($0) - @@datafile = File.join(@@rootpath,'fcd_state.dat') - @@histfile = File.join(@@rootpath,'fcd_state.his') - @@cdirfile = File.join(@@rootpath,if @@mswindows then 'fcd_stage.cmd' else 'fcd_stage.sh' end) - @@stubfile = File.join(@@selfpath,if @@mswindows then 'fcd.cmd' else 'fcd' end) - - def initialize(verbose=false) - @list = Array.new - @hist = Hash.new - @result = Array.new - @pattern = '' - @result = '' - @verbose = verbose - if f = File.open(@@cdirfile,'w') then - f << "#{if @@mswindows then 'rem' else '#' end} no dir to change to" - f.close - else - report("unable to create stub #{@@cdirfile}") - end - end - - def filename(name) - File.join(@@root,name) - end - - def report(str,verbose=@verbose) - puts(">> #{str}") if verbose - end - - def flush(str,verbose=@verbose) - print(str) if verbose - end - - def clear - if FileTest.file?(@@histfile) - begin - File.delete(@@histfile) - rescue - report("error in deleting history file '#{@histfile}'") - else - report("history file '#{@histfile}' is deleted") - end - else - report("no history file '#{@histfile}'") - end - end - - def scan(dir='.') - begin - [dir].flatten.sort.uniq.each do |dir| - begin - Dir.chdir(dir) - report("scanning '#{dir}'") - # flush(">> ") - Dir.glob("**/*").each do |d| - if FileTest.directory?(d) then - @list << File.expand_path(d) - # flush(".") - end - end - # flush("\n") - @list = @list.sort.uniq - report("#{@list.size} entries found") - rescue - report("unknown directory '#{dir}'") - end - end - rescue - report("invalid dir specification ") - end - end - - def save - begin - if f = File.open(@@datafile,'w') then - @list.each do |l| - f.puts(l) - end - f.close - report("#{@list.size} status bytes saved in #{@@datafile}") - else - report("unable to save status in #{@@datafile}") - end - rescue - report("error in saving status in #{@@datafile}") - end - end - - def remember - if @hist[@pattern] == @result then - # no need to save result - else - begin - if f = File.open(@@histfile,'w') then - @hist[@pattern] = @result - @hist.keys.each do |k| - f.puts("#{k} #{@hist[k]}") - end - f.close - report("#{@hist.size} history entries saved in #{@@histfile}") - else - report("unable to save history in #{@@histfile}") - end - rescue - report("error in saving history in #{@@histfile}") - end - end - end - - def load - begin - @list = IO.read(@@datafile).split("\n") - report("#{@list.length} status bytes loaded from #{@@datafile}") - rescue - report("error in loading status from #{@@datafile}") - end - begin - IO.readlines(@@histfile).each do |line| - if line =~ /^(.*?)\s+(.*)$/i then - @hist[$1] = $2 - end - end - report("#{@hist.length} history entries loaded from #{@@histfile}") - rescue - report("error in loading history from #{@@histfile}") - end - end - - def show - begin - puts("directories:") - puts("\n") - if @list.length > 0 then - @list.each do |l| - puts(l) - end - else - puts("no entries") - end - puts("\n") - puts("history:") - puts("\n") - if @hist.length > 0 then - @hist.keys.sort.each do |h| - puts("#{h} >> #{@hist[h]}") - end - else - puts("no entries") - end - rescue - end - end - - def find(pattern=nil) - begin - if pattern = [pattern].flatten.first then - if pattern.length > 0 and @pattern = pattern then - @result = @list.grep(/\/#{@pattern}$/i) - if @result.length == 0 then - @result = @list.grep(/\/#{@pattern}[^\/]*$/i) - end - end - else - puts(Dir.pwd.gsub(/\\/o, '/')) - end - rescue - puts("some error") - end - end - - def chdir(dir) - begin - if dir then - if f = File.open(@@cdirfile,'w') then - if @@mswindows then - f.puts("cd /d #{dir.gsub('/','\\')}") - else - f.puts("cd #{dir.gsub("\\",'/')}") - end - f.close - end - @result = dir - report("changing to #{dir}",true) - else - report("not changing dir") - end - rescue - end - end - - def choose(args=[]) - offset = 97 - unless @pattern.empty? then - begin - case @result.size - when 0 then - report("dir '#{@pattern}' not found",true) - when 1 then - chdir(@result[0]) - else - list = @result.dup - begin - if answer = args[1] then # assignment & test - if answer == '.' and @hist.key?(@pattern) then - if FileTest.directory?(@hist[@pattern]) then - print("last choice ") - chdir(@hist[@pattern]) - return - end - else - index = answer[0] - offset - if dir = list[index] then - chdir(dir) - return - end - end - end - rescue - puts("some error") - end - loop do - print("\n") - list.each_index do |i| -begin - if i < @@maxlength then - # puts("#{(i+?a).chr} #{list[i]}") - puts("#{(i+offset).chr} #{list[i]}") - else - puts("\n there are #{list.length-@@maxlength} entries more") - break - end -rescue - puts("some error") -end - end - print("\n>> ") - if answer = wait then - if answer >= offset and answer <= offset+25 then - index = answer - offset - if dir = list[index] then - print("#{answer.chr} ") - chdir(dir) - elsif @hist.key?(@pattern) and FileTest.directory?(@hist[@pattern]) then - print("last choice ") - chdir(@hist[@pattern]) - else - print("quit\n") - end - break - elsif list.length >= @@maxlength then - @@maxlength.times do |i| list.shift end - print("next set") - print("\n") - elsif @hist.key?(@pattern) and FileTest.directory?(@hist[@pattern]) then - print("last choice ") - chdir(@hist[@pattern]) - break - else - print("quit\n") - break - end - end - end - end - rescue - report($!) - end - end - end - - def wait - begin - $stdout.flush - return getc - rescue - return nil - end - end - - def getc - begin - if @@mswindows then - ch = Win32API.new('crtdll','_getch',[],'L').call - else - system('stty raw -echo') - ch = $stdin.getc - system('stty -raw echo') - end - rescue - ch = nil - end - return ch - end - - def check - unless FileTest.file?(@@stubfile) then - report("creating stub #{@@stubfile}") - begin - if f = File.open(@@stubfile,'w') then - f.puts(@@stubcode) - f.close - end - rescue - report("unable to create stub #{@@stubfile}") - else - unless @mswindows then - begin - File.chmod(0755,@@stubfile) - rescue - report("unable to change protections on #{@@stubfile}") - end - end - end - else - report("stub #{@@stubfile} already present") - end - end - -end - -$stdout.sync = true - -verbose, action, args = false, :find, Array.new - -usage = "fcd [--add|clear|find|list|make|show|stub] [--verbose] [pattern]" -version = "1.0.2" - -def quit(message) - puts(message) - exit -end - -ARGV.each do |a| - case a - when '-a', '--add' then action = :add - when '-c', '--clear' then action = :clear - when '-f', '--find' then action = :find - when '-l', '--list' then action = :show - when '-m', '--make' then action = :make - when '-s', '--show' then action = :show - when '--stub' then action = :stub - when '-v', '--verbose' then verbose = true - when '--version' then quit("version: #{version}") - when '-h', '--help' then quit("usage: #{usage}") - when /^\-\-.*/ then quit("error: unknown switch #{a}, try --help") - else args << a - end -end - -fcd = FastCD.new(verbose) -fcd.report("Fast Change Dir / version #{version}") - -case action - when :make then - fcd.clear - fcd.scan(args) - fcd.save - when :clear then - fcd.clear - when :add then - fcd.load - fcd.scan(args) - fcd.save - when :show then - fcd.load - fcd.show - when :find then - fcd.load - fcd.find(args) - fcd.choose(args) - fcd.remember - when :stub - fcd.check -end diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index 108f2a8a1..cc29845b5 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -1341,12 +1341,16 @@ function lpeg.split(separator,str) end function string.split(str,separator) - local c = cache[separator] - if not c then - c = tsplitat(separator) - cache[separator] = c + if separator then + local c = cache[separator] + if not c then + c = tsplitat(separator) + cache[separator] = c + end + return match(c,str) + else + return { str } end - return match(c,str) end local spacing = patterns.spacer^0 * newline -- sort of strip @@ -1851,14 +1855,14 @@ else io.fileseparator, io.pathseparator = "/" , ":" end -function io.loaddata(filename,textmode) +function io.loaddata(filename,textmode) -- return nil if empty local f = io.open(filename,(textmode and 'r') or 'rb') if f then local data = f:read('*all') f:close() - return data - else - return nil + if #data > 0 then + return data + end end end @@ -1880,6 +1884,45 @@ function io.savedata(filename,data,joiner) end end +function io.loadlines(filename,n) -- return nil if empty + local f = io.open(filename,'r') + if f then + if n then + local lines = { } + for i=1,n do + local line = f:read("*lines") + if line then + lines[#lines+1] = line + else + break + end + end + f:close() + lines = concat(lines,"\n") + if #lines > 0 then + return lines + end + else + local line = f:read("*line") or "" + assert(f:close()) + if #line > 0 then + return line + end + end + end +end + +function io.loadchunk(filename,n) + local f = io.open(filename,'rb') + if f then + local data = f:read(n or 1024) + f:close() + if #data > 0 then + return data + end + end +end + function io.exists(filename) local f = io.open(filename) if f == nil then @@ -3081,15 +3124,30 @@ 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 -function file.needs_updating(oldname,newname,threshold) -- size modification access change - local oldtime = lfs.attributes(oldname, modification) - local newtime = lfs.attributes(newname, modification) - if newtime >= oldtime then - return false - elseif oldtime - newtime < (threshold or 1) then - return false +function file.needsupdating(oldname,newname,threshold) -- size modification access change + local oldtime = lfs.attributes(oldname,"modification") + if oldtime then + local newtime = lfs.attributes(newname,"modification") + if not newtime then + return true -- no new file, so no updating needed + elseif newtime >= oldtime then + return false -- new file definitely needs updating + elseif oldtime - newtime < (threshold or 1) then + return false -- new file is probably still okay + else + return true -- new file has to be updated + end else - return true + return false -- no old file, so no updating needed + end +end + +file.needs_updating = file.needsupdating + +function file.syncmtimes(oldname,newname) + local oldtime = lfs.attributes(oldname,"modification") + if oldtime and lfs.isfile(newname) then + lfs.touch(newname,oldtime,oldtime) end end @@ -3111,7 +3169,7 @@ function file.loadchecksum(name) return nil end -function file.savechecksum(name, checksum) +function file.savechecksum(name,checksum) if not checksum then checksum = file.checksum(name) end if checksum then io.savedata(name .. ".md5",checksum) @@ -5586,7 +5644,7 @@ function setters.show(t) local value, default, modules = functions.value, functions.default, #functions value = value == nil and "unset" or tostring(value) default = default == nil and "unset" or tostring(default) - t.report("%-30s modules: %2i default: %6s value: %6s",name,modules,default,value) + t.report("%-50s modules: %2i default: %6s value: %6s",name,modules,default,value) end end t.report() @@ -5678,17 +5736,31 @@ end) -- experiment -local flags = environment and environment.engineflags +if environment then -if flags then - if trackers and flags.trackers then - setters.initialize("flags","trackers", settings_to_hash(flags.trackers)) - -- t_enable(flags.trackers) - end - if directives and flags.directives then - setters.initialize("flags","directives", settings_to_hash(flags.directives)) - -- d_enable(flags.directives) + -- The engineflags are known earlier than environment.arguments but maybe we + -- need to handle them both as the later are parsed differently. The c: prefix + -- is used by mtx-context to isolate the flags from those that concern luatex. + + local engineflags = environment.engineflags + + if engineflags then + if trackers then + local list = engineflags["c:trackers"] or engineflags["trackers"] + if type(list) == "string" then + setters.initialize("flags","trackers",settings_to_hash(list)) + -- t_enable(list) + end + end + if directives then + local list = engineflags["c:directives"] or engineflags["directives"] + if type(list) == "string" then + setters.initialize("flags","directives", settings_to_hash(list)) + -- d_enable(list) + end + end end + end -- here @@ -6619,6 +6691,8 @@ local mt = { setmetatable(environment,mt) +-- context specific arguments (in order not to confuse the engine) + function environment.initializearguments(arg) local arguments, files = { }, { } environment.arguments, environment.files, environment.sortedflags = arguments, files, nil @@ -6627,10 +6701,12 @@ function environment.initializearguments(arg) if index > 0 then local flag, value = match(argument,"^%-+(.-)=(.-)$") if flag then + flag = gsub(flag,"^c:","") arguments[flag] = unquoted(value or "") else flag = match(argument,"^%-+(.+)") if flag then + flag = gsub(flag,"^c:","") arguments[flag] = true else files[#files+1] = argument @@ -6650,7 +6726,7 @@ end -- tricky: too many hits when we support partials unless we add -- a registration of arguments so from now on we have 'partial' -function environment.argument(name,partial) +function environment.getargument(name,partial) local arguments, sortedflags = environment.arguments, environment.sortedflags if arguments[name] then return arguments[name] @@ -6673,6 +6749,8 @@ function environment.argument(name,partial) return nil end +environment.argument = environment.getargument + function environment.splitarguments(separator) -- rather special, cut-off before separator local done, before, after = false, { }, { } local originalarguments = environment.originalarguments diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index 108f2a8a1..cc29845b5 100755 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -1341,12 +1341,16 @@ function lpeg.split(separator,str) end function string.split(str,separator) - local c = cache[separator] - if not c then - c = tsplitat(separator) - cache[separator] = c + if separator then + local c = cache[separator] + if not c then + c = tsplitat(separator) + cache[separator] = c + end + return match(c,str) + else + return { str } end - return match(c,str) end local spacing = patterns.spacer^0 * newline -- sort of strip @@ -1851,14 +1855,14 @@ else io.fileseparator, io.pathseparator = "/" , ":" end -function io.loaddata(filename,textmode) +function io.loaddata(filename,textmode) -- return nil if empty local f = io.open(filename,(textmode and 'r') or 'rb') if f then local data = f:read('*all') f:close() - return data - else - return nil + if #data > 0 then + return data + end end end @@ -1880,6 +1884,45 @@ function io.savedata(filename,data,joiner) end end +function io.loadlines(filename,n) -- return nil if empty + local f = io.open(filename,'r') + if f then + if n then + local lines = { } + for i=1,n do + local line = f:read("*lines") + if line then + lines[#lines+1] = line + else + break + end + end + f:close() + lines = concat(lines,"\n") + if #lines > 0 then + return lines + end + else + local line = f:read("*line") or "" + assert(f:close()) + if #line > 0 then + return line + end + end + end +end + +function io.loadchunk(filename,n) + local f = io.open(filename,'rb') + if f then + local data = f:read(n or 1024) + f:close() + if #data > 0 then + return data + end + end +end + function io.exists(filename) local f = io.open(filename) if f == nil then @@ -3081,15 +3124,30 @@ 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 -function file.needs_updating(oldname,newname,threshold) -- size modification access change - local oldtime = lfs.attributes(oldname, modification) - local newtime = lfs.attributes(newname, modification) - if newtime >= oldtime then - return false - elseif oldtime - newtime < (threshold or 1) then - return false +function file.needsupdating(oldname,newname,threshold) -- size modification access change + local oldtime = lfs.attributes(oldname,"modification") + if oldtime then + local newtime = lfs.attributes(newname,"modification") + if not newtime then + return true -- no new file, so no updating needed + elseif newtime >= oldtime then + return false -- new file definitely needs updating + elseif oldtime - newtime < (threshold or 1) then + return false -- new file is probably still okay + else + return true -- new file has to be updated + end else - return true + return false -- no old file, so no updating needed + end +end + +file.needs_updating = file.needsupdating + +function file.syncmtimes(oldname,newname) + local oldtime = lfs.attributes(oldname,"modification") + if oldtime and lfs.isfile(newname) then + lfs.touch(newname,oldtime,oldtime) end end @@ -3111,7 +3169,7 @@ function file.loadchecksum(name) return nil end -function file.savechecksum(name, checksum) +function file.savechecksum(name,checksum) if not checksum then checksum = file.checksum(name) end if checksum then io.savedata(name .. ".md5",checksum) @@ -5586,7 +5644,7 @@ function setters.show(t) local value, default, modules = functions.value, functions.default, #functions value = value == nil and "unset" or tostring(value) default = default == nil and "unset" or tostring(default) - t.report("%-30s modules: %2i default: %6s value: %6s",name,modules,default,value) + t.report("%-50s modules: %2i default: %6s value: %6s",name,modules,default,value) end end t.report() @@ -5678,17 +5736,31 @@ end) -- experiment -local flags = environment and environment.engineflags +if environment then -if flags then - if trackers and flags.trackers then - setters.initialize("flags","trackers", settings_to_hash(flags.trackers)) - -- t_enable(flags.trackers) - end - if directives and flags.directives then - setters.initialize("flags","directives", settings_to_hash(flags.directives)) - -- d_enable(flags.directives) + -- The engineflags are known earlier than environment.arguments but maybe we + -- need to handle them both as the later are parsed differently. The c: prefix + -- is used by mtx-context to isolate the flags from those that concern luatex. + + local engineflags = environment.engineflags + + if engineflags then + if trackers then + local list = engineflags["c:trackers"] or engineflags["trackers"] + if type(list) == "string" then + setters.initialize("flags","trackers",settings_to_hash(list)) + -- t_enable(list) + end + end + if directives then + local list = engineflags["c:directives"] or engineflags["directives"] + if type(list) == "string" then + setters.initialize("flags","directives", settings_to_hash(list)) + -- d_enable(list) + end + end end + end -- here @@ -6619,6 +6691,8 @@ local mt = { setmetatable(environment,mt) +-- context specific arguments (in order not to confuse the engine) + function environment.initializearguments(arg) local arguments, files = { }, { } environment.arguments, environment.files, environment.sortedflags = arguments, files, nil @@ -6627,10 +6701,12 @@ function environment.initializearguments(arg) if index > 0 then local flag, value = match(argument,"^%-+(.-)=(.-)$") if flag then + flag = gsub(flag,"^c:","") arguments[flag] = unquoted(value or "") else flag = match(argument,"^%-+(.+)") if flag then + flag = gsub(flag,"^c:","") arguments[flag] = true else files[#files+1] = argument @@ -6650,7 +6726,7 @@ end -- tricky: too many hits when we support partials unless we add -- a registration of arguments so from now on we have 'partial' -function environment.argument(name,partial) +function environment.getargument(name,partial) local arguments, sortedflags = environment.arguments, environment.sortedflags if arguments[name] then return arguments[name] @@ -6673,6 +6749,8 @@ function environment.argument(name,partial) return nil end +environment.argument = environment.getargument + function environment.splitarguments(separator) -- rather special, cut-off before separator local done, before, after = false, { }, { } local originalarguments = environment.originalarguments diff --git a/tex/context/base/anch-bck.mkvi b/tex/context/base/anch-bck.mkvi index 8ec056468..8f22d8a6d 100644 --- a/tex/context/base/anch-bck.mkvi +++ b/tex/context/base/anch-bck.mkvi @@ -276,7 +276,7 @@ \kern\textbackgroundskip\nobreak \fi \fi \nobreak - \vskip-\dimexpr\lineheight+\parskip\relax + \vskip-\dimexpr\lineheight+\parskip\relax % problem: we loose the hangindent \nobreak \endgroup \begingroup @@ -307,7 +307,7 @@ \setuptextbackground [\c!mp=mpos:region:draw, - \c!method=mpos:region, + \c!method=mpos:region, % mpos:regionshape \c!state=\v!start, \c!location=\v!text, \c!leftoffset=\!!zeropoint, % 1em, @@ -397,6 +397,14 @@ \includeMPgraphic{mpos:region:anchor} ; \stopMPpositiongraphic +\startMPpositiongraphic{mpos:regionshape}{fillcolor,filloffset,linecolor,gridcolor,linewidth,gridwidth,gridshift,lineradius,lineoffset} + \includeMPgraphic{mpos:region:setup} ; + \includeMPgraphic{mpos:region:extra} ; + \MPgetmultishapes{\MPvar{self}}{\MPanchorid} ; + \includeMPgraphic{\MPvar{mp}} ; + \includeMPgraphic{mpos:region:anchor} ; +\stopMPpositiongraphic + \startMPpositionmethod{mpos:region} \MPpositiongraphic{mpos:region}{}% \stopMPpositionmethod diff --git a/tex/context/base/anch-pgr.lua b/tex/context/base/anch-pgr.lua index bf4dcbe02..6143d166e 100644 --- a/tex/context/base/anch-pgr.lua +++ b/tex/context/base/anch-pgr.lua @@ -51,30 +51,44 @@ local function add(t,x,y,last) local n = #t if n == 0 then t[n+1] = { x, y } - elseif n == 1 then - local tn = t[1] - if abs(tn[1]-x) <= eps or abs(tn[2]-y) <= eps then - t[n+1] = { x, y } - end else - local tm = t[n-1] local tn = t[n] local lx = tn[1] local ly = tn[2] - if abs(lx-tm[1]) <= eps and abs(lx-x) <= eps then - if abs(ly-y) > eps then - tn[2] = y + if x == lx and y == ly then + -- quick skip + elseif n == 1 then +-- if abs(lx-x) <= eps or abs(ly-y) <= eps then + if abs(lx-x) > eps or abs(ly-y) > eps then + t[n+1] = { x, y } end - elseif abs(ly-tm[2]) <= eps and abs(ly-y) <= eps then - if abs(lx-x) > eps then - tn[1] = x + else + local tm = t[n-1] + local px = tm[1] + local py = tm[2] +if y > ly then + -- move back from too much hang +else + if abs(lx-px) <= eps and abs(lx-x) <= eps then + if abs(ly-y) > eps then + tn[2] = y + end + elseif abs(ly-py) <= eps and abs(ly-y) <= eps then + if abs(lx-x) > eps then + tn[1] = x + end + elseif not last then + t[n+1] = { x, y } end - elseif not last then - t[n+1] = { x, y } +end end end end +-- local function add(t,x,y,last) +-- t[#t+1] = { x, y } +-- end + local function finish(t) local n = #t if n > 1 then @@ -109,105 +123,103 @@ end -- todo: mark regions and free paragraphs in collected -local function shapes(r,rx,ry,rw,rh,rd,lytop,lybot,rytop,rybot) +local function shapes(r,rx,ry,rw,rh,rd,lytop,lybot,rytop,rybot,obeyhang) -- we assume that we only hang per page and not cross pages -- which makes sense as hanging is only uses in special cases -- -- we can remove data as soon as a page is done so we could -- remember per page and discard areas after each shipout local leftshape, rightshape --- leftshape = r.leftshape --- rightshape = r.rightshape --- if not leftshape then - leftshape = { { rx, rh } } - rightshape = { { rw, rh } } - local paragraphs = r.paragraphs - local extending = false - if paragraphs then - for i=1,#paragraphs do - local p = paragraphs[i] - local ha = p.ha - if ha and ha ~= 0 then + leftshape = { { rx, rh } } -- spikes get removed so we can start at the edge + rightshape = { { rw, rh } } -- even if we hang next + local paragraphs = r.paragraphs + local extending = false + if paragraphs then + for i=1,#paragraphs do + local p = paragraphs[i] + local ha = p.ha + if obeyhang and ha and ha ~= 0 then + local py = p.y + local ph = p.h + local pd = p.d + local hi = p.hi + local hang = ha * (ph + pd) + local py_ph = py + ph + -- ha < 0 hi < 0 : right top + -- ha < 0 hi > 0 : left top + if ha < 0 then + if hi < 0 then -- right + add(rightshape,rw , py_ph) + add(rightshape,rw + hi, py_ph) + add(rightshape,rw + hi, py_ph + hang) + add(rightshape,rw , py_ph + hang) + else + -- left + add(leftshape,rx, py_ph) + add(leftshape,rx + hi, py_ph) + add(leftshape,rx + hi, py_ph + hang) + add(leftshape,rx, py_ph + hang) + end + else + -- maybe some day + end + extending = true -- false + else -- we need to clip to the next par + local ps = p.ps + if ps then local py = p.y local ph = p.h local pd = p.d - local hi = p.hi - local hang = ha * (ph + pd) + local step = ph + pd + local size = #ps * step local py_ph = py + ph - -- ha < 0 hi < 0 : right top - -- ha < 0 hi > 0 : left top - if ha < 0 then - if hi < 0 then -- right - add(rightshape,rw , py_ph) - add(rightshape,rw + hi, py_ph) - add(rightshape,rw + hi, py_ph + hang) - add(rightshape,rw , py_ph + hang) - else - -- left - add(leftshape,rx, py_ph) - add(leftshape,rx + hi, py_ph) - add(leftshape,rx + hi, py_ph + hang) - add(leftshape,rx, py_ph + hang) - end - end -extending = false - else -- we need to clip to the next par - local ps = p.ps - if ps then - local py = p.y - local ph = p.h - local pd = p.d - local step = ph + pd - local size = #ps * step - local py_ph = py + ph - add(leftshape,rx,py_ph) - add(rightshape,rw,py_ph) - for i=1,#ps do - local p = ps[i] - local l = p[1] - local w = p[2] - add(leftshape,rx + l, py_ph) - add(rightshape,rx + l + w, py_ph) - py_ph = py_ph - step - add(leftshape,rx + l, py_ph) - add(rightshape,rx + l + w, py_ph) - end - extending = true --- add(left,rx,py_ph) --- add(right,rw,py_ph) - else - if extending then - local py = p.y - local ph = p.h - local pd = p.d - local py_ph = py + ph - local py_pd = py - pd - add(leftshape,leftshape[#leftshape][1],py_ph) - add(rightshape,rightshape[#rightshape][1],py_ph) - add(leftshape,rx,py_ph) - add(rightshape,rw,py_ph) -extending = false - end + add(leftshape,rx,py_ph) + add(rightshape,rw,py_ph) + for i=1,#ps do + local p = ps[i] + local l = p[1] + local w = p[2] + add(leftshape,rx + l, py_ph) + add(rightshape,rx + l + w, py_ph) + py_ph = py_ph - step + add(leftshape,rx + l, py_ph) + add(rightshape,rx + l + w, py_ph) end + extending = true + elseif extending then + local py = p.y + local ph = p.h + local pd = p.d + local py_ph = py + ph + local py_pd = py - pd + add(leftshape,leftshape[#leftshape][1],py_ph) + add(rightshape,rightshape[#rightshape][1],py_ph) + add(leftshape,rx,py_ph) -- shouldn't this be py_pd + add(rightshape,rw,py_ph) -- shouldn't this be py_pd + extending = false end end end - -- we can have a simple variant when no paragraphs - if extending then - -- not ok - leftshape[#leftshape][2] = rd - rightshape[#rightshape][2] = rw - else - add(leftshape,rx,rd) - add(rightshape,rw,rd) - end --- r.leftshape = leftshape --- r.rightshape = rightshape --- end + end + -- we can have a simple variant when no paragraphs + if extending then + -- not ok + leftshape[#leftshape][2] = rd + rightshape[#rightshape][2] = rw + else + add(leftshape,rx,rd) + add(rightshape,rw,rd) + end return clip(leftshape,lytop,lybot), clip(rightshape,rytop,rybot) end -local function singlepart(b,e,r,left,right) +-- local function shapes(r,rx,ry,rw,rh,rd,lytop,lybot,rytop,rybot,obeyhang) +-- local leftshape = { { rx, rh }, { rx, rd } } +-- local rightshape = { { rw, rh }, { rw, rd } } +-- return clip(leftshape,lytop,lybot), clip(rightshape,rytop,rybot) +-- end + +local function singlepart(b,e,r,left,right,obeyhang) local bx, by = b.x, b.y local ex, ey = e.x, e.y local rx, ry = r.x, r.y @@ -238,7 +250,7 @@ local function singlepart(b,e,r,left,right) } else area = { } - local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,bd,ed,bh,eh) + local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,bd,ed,bh,eh,obeyhang) add(area,bx,bh-ry) for i=1,#rightshapes do local ri = rightshapes[i] @@ -265,7 +277,7 @@ local function singlepart(b,e,r,left,right) } end -local function firstpart(b,r,left,right) +local function firstpart(b,r,left,right,obeyhang) local bx, by = b.x, b.y local rx, ry = r.x, r.y local rw = rx + r.w @@ -278,7 +290,7 @@ local function firstpart(b,r,left,right) local bh = by + b.h local bd = by - b.d local area = { } - local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,bd,rd,bh,rd) + local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,bd,rd,bh,rd,obeyhang) add(area,bx,bh-ry) for i=1,#rightshapes do local ri = rightshapes[i] @@ -302,7 +314,7 @@ local function firstpart(b,r,left,right) } end -local function middlepart(r,left,right) +local function middlepart(r,left,right,obeyhang) local rx, ry = r.x, r.y local rw = rx + r.w local rh = ry + r.h @@ -312,7 +324,7 @@ local function middlepart(r,left,right) rw = rw - right end local area = { } - local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,rh,rd,rh,rd) + local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,rh,rd,rh,rd,obeyhang) for i=#leftshapes,1,-1 do local li = leftshapes[i] add(area,li[1],li[2]-ry) @@ -333,7 +345,7 @@ local function middlepart(r,left,right) } end -local function lastpart(e,r,left,right) +local function lastpart(e,r,left,right,obeyhang) local ex, ey = e.x, e.y local rx, ry = r.x, r.y local rw = rx + r.w @@ -347,7 +359,7 @@ local function lastpart(e,r,left,right) local ed = ey - e.d local area = { } -- two cases: till end and halfway e line - local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,rh,ed,rh,eh) + local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,rh,ed,rh,eh,obeyhang) for i=1,#rightshapes do local ri = rightshapes[i] add(area,ri[1],ri[2]-ry) @@ -375,7 +387,7 @@ local backgrounds = { } graphics.backgrounds = backgrounds -local function calculatemultipar(tag) +local function calculatemultipar(tag,obeyhang) local collected = jobpositions.collected local b = collected[format("b:%s",tag)] local e = collected[format("e:%s",tag)] @@ -429,13 +441,13 @@ local function calculatemultipar(tag) -- if bindex == eindex then return { - list = { [b.p] = { singlepart(b,e,collected[br],left,right) } }, + list = { [b.p] = { singlepart(b,e,collected[br],left,right,obeyhang) } }, bpos = b, epos = e, } else local list = { - [b.p] = { firstpart(b,collected[br],left,right) }, + [b.p] = { firstpart(b,collected[br],left,right,obeyhang) }, } for i=bindex+1,eindex-1 do br = format("%s:%s",btag,i) @@ -446,18 +458,18 @@ local function calculatemultipar(tag) local p = r.p local pp = list[p] if pp then - pp[#pp+1] = middlepart(r,left,right) + pp[#pp+1] = middlepart(r,left,right,obeyhang) else - list[p] = { middlepart(r,left,right) } + list[p] = { middlepart(r,left,right,obeyhang) } end end end local p = e.p local pp = list[p] if pp then - pp[#pp+1] = lastpart(e,collected[er],left,right) + pp[#pp+1] = lastpart(e,collected[er],left,right,obeyhang) else - list[p] = { lastpart(e,collected[er],left,right) } + list[p] = { lastpart(e,collected[er],left,right,obeyhang) } end return { list = list, @@ -537,10 +549,10 @@ local template_d = [[ setbounds currentpicture to multibox ; ]] -function backgrounds.fetchmultipar(n,anchor,page) +function backgrounds.fetchmultipar(n,anchor,page,obeyhang) local data = pbg[n] if not data then - data = calculatemultipar(n) + data = calculatemultipar(n,obeyhang) pbg[n] = data -- can be replaced by register -- register(data.list,n,anchor) end @@ -590,6 +602,10 @@ function commands.fetchmultipar(n,anchor,page) context(backgrounds.fetchmultipar(n,anchor,page)) end +function commands.fetchmultishape(n,anchor,page) + context(backgrounds.fetchmultipar(n,anchor,page,true)) +end + local template_a = [[ path posboxes[], posregions[] ; numeric pospages[] ; @@ -642,10 +658,10 @@ end local doifelse = commands.doifelse -function commands.doifelsemultipar(n,page) +function commands.doifelsemultipar(n,page,obeyhang) local data = pbg[n] if not data then - data = calculatemultipar(n) + data = calculatemultipar(n,obeyhang) pbg[n] = data end if page then diff --git a/tex/context/base/anch-pgr.mkiv b/tex/context/base/anch-pgr.mkiv index a417d26e3..38e0ff0af 100644 --- a/tex/context/base/anch-pgr.mkiv +++ b/tex/context/base/anch-pgr.mkiv @@ -492,7 +492,8 @@ % Helpers: -\def\MPgetposboxes #1#2{\ctxcommand{fetchposboxes("#1","#2",\the\realpageno)}} -\def\MPgetmultipars#1#2{\ctxcommand{fetchmultipar("#1","#2",\the\realpageno)}} +\def\MPgetposboxes #1#2{\ctxcommand{fetchposboxes("#1","#2",\the\realpageno)}} +\def\MPgetmultipars #1#2{\ctxcommand{fetchmultipar("#1","#2",\the\realpageno)}} +\def\MPgetmultishapes#1#2{\ctxcommand{fetchmultishape("#1","#2",\the\realpageno)}} \protect \endinput diff --git a/tex/context/base/char-def.lua b/tex/context/base/char-def.lua index 1e3b8a595..804468c2d 100644 --- a/tex/context/base/char-def.lua +++ b/tex/context/base/char-def.lua @@ -64501,6 +64501,8 @@ characters.data={ description="TOP SQUARE BRACKET", direction="on", linebreak="al", + mathclass="topaccent", + mathname="overbracket", unicodeslot=0x23B4, }, [0x23B5]={ @@ -64508,6 +64510,8 @@ characters.data={ description="BOTTOM SQUARE BRACKET", direction="on", linebreak="al", + mathclass="botaccent", + mathname="underbracket", unicodeslot=0x23B5, }, [0x23B6]={ diff --git a/tex/context/base/cldf-ini.lua b/tex/context/base/cldf-ini.lua index ed86c2923..c35ca4b4a 100644 --- a/tex/context/base/cldf-ini.lua +++ b/tex/context/base/cldf-ini.lua @@ -410,7 +410,11 @@ local function writer(parent,command,first,...) -- already optimized before call done = true end end - flush(currentcatcodes,"]") + if done then + flush(currentcatcodes,"]") + else + flush(currentcatcodes,"[]") + end elseif tn == 1 then -- some 20% faster than the next loop local tj = ti[1] if type(tj) == "function" then diff --git a/tex/context/base/colo-ini.mkiv b/tex/context/base/colo-ini.mkiv index 5721bb513..a46555534 100644 --- a/tex/context/base/colo-ini.mkiv +++ b/tex/context/base/colo-ini.mkiv @@ -242,8 +242,8 @@ \setfalse\c_colo_convert_gray \getvalue{\??colorconversions\directcolorsparameter\c!conversion}% could be a nice \ifcsname % too often: - \ifconditional\c_colo_rgb_supported \colo_helpers_show_message\m!colors9\v!rgb \fi - \ifconditional\c_colo_cmyk_supported\colo_helpers_show_message\m!colors9\v!cmyk\fi + \ifconditional\c_colo_rgb_supported \colo_helpers_show_message\m!colors{10}\v!rgb \fi + \ifconditional\c_colo_cmyk_supported\colo_helpers_show_message\m!colors{10}\v!cmyk\fi \colo_helpers_set_current_model \ifproductionrun \edef\p_pagecolormodel{\directcolorsparameter\c!pagecolormodel}% @@ -802,9 +802,19 @@ \def\defaulttextcolor {black} \def\s!themaintextcolor{themaintextcolor} +\unexpanded\def\inheritmaintextcolor + {\ifx\maintextcolor\empty\else\colo_helpers_activate\maintextcolor\fi} + +\unexpanded\def\onlyinheritmaintextcolor + {\ifx\maintextcolor\empty + \deactivatecolor + \else + \colo_helpers_activate\maintextcolor + \fi} + \appendtoks \deactivatecolor % public? - \ifx\maintextcolor\empty\else\colo_helpers_activate\maintextcolor\fi + \inheritmaintextcolor \to \everybeforeoutput \def\colo_helpers_switch_to_maintextcolor#1% diff --git a/tex/context/base/cont-new.mkii b/tex/context/base/cont-new.mkii index b4958762f..2f49f0bd4 100644 --- a/tex/context/base/cont-new.mkii +++ b/tex/context/base/cont-new.mkii @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2012.05.30 11:26} +\newcontextversion{2012.06.05 09:16} %D This file is loaded at runtime, thereby providing an %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv index 5a28f8e29..2c7ae9942 100644 --- a/tex/context/base/cont-new.mkiv +++ b/tex/context/base/cont-new.mkiv @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2012.05.30 11:26} +\newcontextversion{2012.06.05 09:16} %D This file is loaded at runtime, thereby providing an %D excellent place for hacks, patches, extensions and new @@ -48,7 +48,7 @@ % \let\cs\getvalue % no, we want \cs to be czech -% experimental so this may change +% experimental so this may change ! ! ! not adapted to new low level description names \def\startdescriptions {\dosingleempty\dostartdescriptions} @@ -231,7 +231,7 @@ \egroup -\def\inlinedbox +\unexpanded\def\inlinedbox {\bgroup \dowithnextbox {\scratchdimen\nextboxht @@ -256,7 +256,7 @@ #2\expandafter\expandafter\expandafter\doxprecurse\expandafter \fi\expandafter{\the\numexpr#1-1\relax}{#2}} -\def\buttonframed{\dodoubleempty\localframed[\??bt]} % goodie +\unexpanded\def\buttonframed{\dodoubleempty\localframed[\??bt]} % goodie \unexpanded\def\asciistr#1{\dontleavehmode{\defconvertedargument\ascii{#1}\verbatimfont\ascii}} @@ -345,13 +345,13 @@ % \tableifelse{\doifelse{a}{a}}{\NC Xtest \NC test \NC \NR}{}% % \stoptabulate} -\long\def\tableifelse#1% +\def\tableifelse#1% {\tablenoalign {#1% {\aftergroup \firstoftwoarguments}% {\aftergroup\secondoftwoarguments}}} -\long \def\tableiftextelse#1{\tableifelse{\doiftextelse{#1}}} +\def\tableiftextelse#1{\tableifelse{\doiftextelse{#1}}} \def\tightvbox{\dowithnextbox{\nextboxdp\zeropoint\flushnextbox}\vbox} \def\tightvtop{\dowithnextbox{\nextboxht\zeropoint\flushnextbox}\vtop} diff --git a/tex/context/base/cont-nop.mkiv b/tex/context/base/cont-nop.mkiv new file mode 100644 index 000000000..c8188503e --- /dev/null +++ b/tex/context/base/cont-nop.mkiv @@ -0,0 +1,22 @@ +%D \module +%D [ file=cont-nop, +%D version=2012.06.01, +%D title=\CONTEXT\ Miscellaneous Macros, +%D subtitle=Startup Dummy, +%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 + +\writestatus\m!system{loading dummy replacement for jobname} + +\protect + +\finishjob + +\endinput diff --git a/tex/context/base/cont-yes.mkiv b/tex/context/base/cont-yes.mkiv new file mode 100644 index 000000000..51be3a569 --- /dev/null +++ b/tex/context/base/cont-yes.mkiv @@ -0,0 +1,72 @@ +%D \module +%D [ file=cont-yes, +%D version=2012.06.01, +%D title=\CONTEXT\ Miscellaneous Macros, +%D subtitle=Startup Stub, +%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. + +% At some point I will reconsider the \starttext .. \stoptext +% wraping as we can assume proper styling. It's a left-over from +% mkii that we need to get rid of. + +\startluacode + + -- When a style is loaded there is a good change that we never enter + -- this code. + + local arguments = environment.arguments + local filename = arguments.input or tex.jobname + local suffix = file.suffix(filename) + + if suffix == "xml" or arguments.forcexml then + + -- Maybe we should move the preamble parsing here as it + -- can be part of (any) loaded (sub) file. The \starttext + -- wrapping might go away. + + context.starttext() + context.xmlprocess("main",filename,"") + context.stoptext() + + elseif suffix == "cld" or arguments.forcecld then + + context.runfile(filename) + + elseif suffix == "lua" or arguments.forcelua then + + -- The wrapping might go away. Why is is it there in the + -- first place. + + context.starttext() + context.ctxlua(string.format('dofile("%s")',filename)) + context.stoptext() + + -- elseif suffix == "prep" then + -- + -- -- Why do we wrap here. Because it can be xml? Let's get rid + -- -- of prepping in general. + -- + -- context.starttext() + -- context.input(filename) + -- context.stoptext() + + else + + -- We have a regular tex file so no \starttext yet as we can + -- load fonts. + + context.input(filename) + + end + + context.finishjob() + +\stopluacode + +\endinput diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf Binary files differindex 7b8733c88..edf4268a2 100644 --- a/tex/context/base/context-version.pdf +++ b/tex/context/base/context-version.pdf diff --git a/tex/context/base/context-version.png b/tex/context/base/context-version.png Binary files differindex bb280817c..eb6d3d9ea 100644 --- a/tex/context/base/context-version.png +++ b/tex/context/base/context-version.png diff --git a/tex/context/base/context.mkii b/tex/context/base/context.mkii index 8cd02fd9e..3686f12d0 100644 --- a/tex/context/base/context.mkii +++ b/tex/context/base/context.mkii @@ -20,7 +20,7 @@ %D your styles an modules. \edef\contextformat {\jobname} -\edef\contextversion{2012.05.30 11:26} +\edef\contextversion{2012.06.05 09:16} %D For those who want to use this: diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv index 5044edae1..896baecbf 100644 --- a/tex/context/base/context.mkiv +++ b/tex/context/base/context.mkiv @@ -23,7 +23,7 @@ %D up and the dependencies are more consistent. \edef\contextformat {\jobname} -\edef\contextversion{2012.05.30 11:26} +\edef\contextversion{2012.06.05 09:16} %D For those who want to use this: @@ -454,7 +454,7 @@ \loadmarkfile{cldf-ver} % verbatim, this can come late \loadmarkfile{cldf-com} % commands, this can come late -\loadmarkfile{core-ctx} +\loadmarkfile{core-ctx} % this order might change but we need to check depedencies / move to another namespace \loadmarkfile{core-ini} \loadmarkfile{core-def} @@ -465,7 +465,7 @@ % now we hook in backend code (needs checking) -\loadmarkfile{back-pdf} % actually, this one should load the next three +\loadmarkfile{back-pdf} % actually, this one should load the next three using document.arguments.backend \loadmarkfile{mlib-pdf} \loadmarkfile{mlib-pps} \loadmarkfile{meta-pdf} diff --git a/tex/context/base/core-ctx.ctx b/tex/context/base/core-ctx.ctx new file mode 100644 index 000000000..5126ad2d2 --- /dev/null +++ b/tex/context/base/core-ctx.ctx @@ -0,0 +1,23 @@ +<?xml version='1.0' standalone='yes'?> + +<ctx:job> + <ctx:message>demo file</ctx:message> + <ctx:preprocess suffix='prep'> + <ctx:processors> + <ctx:processor name='step-1' suffix='one' >dummy-prep-command-1 <ctx:value name='old'/> <ctx:value name='new'/></ctx:processor> + <ctx:processor name='step-2' suffix='prep'>dummy-prep-command-2 <ctx:value name='old'/> <ctx:value name='new'/></ctx:processor> + </ctx:processors> + <ctx:files> + <ctx:file processor='step-1' >one*.xml</ctx:file> + <ctx:file processor='step-2' >two*.xml</ctx:file> + <ctx:file processor='step-1,step-2'>all*.xml</ctx:file> + </ctx:files> + </ctx:preprocess> + <ctx:process> + <ctx:resources> + <ctx:environment>step-1-step-2.tex</ctx:environment> + </ctx:resources> + </ctx:process> + <ctx:postprocess> + </ctx:postprocess> +</ctx:job> diff --git a/tex/context/base/core-ctx.lua b/tex/context/base/core-ctx.lua index e6fb7bb5f..616f82a58 100644 --- a/tex/context/base/core-ctx.lua +++ b/tex/context/base/core-ctx.lua @@ -6,72 +6,271 @@ if not modules then modules = { } end modules ['core-ctx'] = { license = "see context related readme files" } +--[[ +Job control files aka ctx files are rather old and date from the mkii times. +They were handled in texexec and mtx-context and deals with modes, modules, +environments and preprocessing in projects where one such file drives the +processing of lots of files without the need to provide command line +arguments. + +In mkiv this concept was of course supported as well. The first implementation +of mtx-context took much of the approach of texexec, but by now we have gotten +rid of the option file (for passing modes, modules and environments), the stubs +(for directly processing cld and xml) as well as the preprocessing component +of the ctx files. Special helper features, like typesetting listings, were +already moved to the extras (a direct side effect of the ability to pass along +command line arguments.) All this made mtx-context more simple than its ancestor +texexec. + +Because some of the modes might affect the mtx-context end, the ctx file is +still loaded there but only for getting the modes. The file is loaded again +during the run but as loading and basic processing takes less than a +millisecond it's not that much of a burden. +--]] + +-- the ctxrunner tabel might either become private or move to the job namespace +-- which also affects the loading order + local trace_prepfiles = false trackers.register("system.prepfiles", function(v) trace_prepfiles = v end) +local gsub, find = string.gsub, string.find + local report_prepfiles = logs.reporter("system","prepfiles") commands = commands or { } local commands = commands -local list, suffix, islocal, found = { }, "prep", false, false - -function commands.loadctxpreplist() - local ctlname = file.replacesuffix(tex.jobname,"ctl") - if lfs.isfile(ctlname) then - local x = xml.load(ctlname) - if x then - islocal = xml.found(x,"ctx:preplist[@local=='yes']") ---~ if trace_prepfiles then - if islocal then - report_prepfiles("loading ctx log file (local)") -- todo: m!system - else - report_prepfiles("loading ctx log file (specified)") -- todo: m!system +ctxrunner = ctxrunner or { } + +ctxrunner.prepfiles = utilities.storage.allocate() + +local function dontpreparefile(t,k) + return k -- we only store when we have a prepper +end + +table.setmetatableindex(ctxrunner.prepfiles,dontpreparefile) + +local function filtered(str,method) -- in resolvers? + str = tostring(str) + if method == 'name' then str = file.removesuffix(file.basename(str)) + elseif method == 'path' then str = file.dirname(str) + elseif method == 'suffix' then str = file.extname(str) + elseif method == 'nosuffix' then str = file.removesuffix(str) + elseif method == 'nopath' then str = file.basename(str) + elseif method == 'base' then str = file.basename(str) +-- elseif method == 'full' then +-- elseif method == 'complete' then +-- elseif method == 'expand' then -- str = file.expandpath(str) + end + return (gsub(str,"\\","/")) +end + +-- local function substitute(e,str) +-- local attributes = e.at +-- if str and attributes then +-- if attributes['method'] then +-- str = filtered(str,attributes['method']) +-- end +-- if str == "" and attributes['default'] then +-- str = attributes['default'] +-- end +-- end +-- return str +-- end + +local function substitute(str) + return str +end + +local function justtext(str) + str = xml.unescaped(tostring(str)) + str = xml.cleansed(str) + str = gsub(str,"\\+",'/') + str = gsub(str,"%s+",' ') + return str +end + +function ctxrunner.load(ctxname) + + local xmldata = xml.load(ctxname) + + local jobname = tex.jobname -- todo + + local variables = { job = jobname } + local commands = { } + local flags = { } + local paths = { } -- todo + local treatments = { } + local suffix = "prep" + + xml.include(xmldata,'ctx:include','name', {'.', file.dirname(ctxname), "..", "../.." }) + + for e in xml.collected(xmldata,"/ctx:job/ctx:flags/ctx:flag") do + local key, value = match(flag,"^(.-)=(.+)$") + if key and value then + environment.setargument(key,value) + else + environment.setargument(flag,true) + end + end + + -- add to document.options.ctxfile[...] + + local ctxfile = document.options.ctxfile + + local modes = ctxfile.modes + local modules = ctxfile.modules + local environments = ctxfile.environments + + for e in xml.collected(xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:mode") do + modes[#modes+1] = xml.text(e) + -- context.enablemode { xml.text(e) } + end + + for e in xml.collected(xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:module") do + modules[#modules+1] = xml.text(e) + -- context.module { xml.text(e) } + end + + for e in xml.collected(xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:environment") do + environments[#environments+1] = xml.text(e) + -- context.environment { xml.text(e) } + end + + for e in xml.collected(xmldata,"ctx:message") do + report_prepfiles("ctx comment: %s", xml.text(e)) + end + + for r, d, k in xml.elements(xmldata,"ctx:value[@name='job']") do + d[k] = variables['job'] or "" + end + + for e in xml.collected(xmldata,"/ctx:job/ctx:preprocess/ctx:processors/ctx:processor") do + commands[e.at and e.at['name'] or "unknown"] = e + end + + local suffix = xml.filter(xmldata,"xml:///ctx:job/ctx:preprocess/attribute('suffix')") -- or ... + local runlocal = xml.filter(xmldata,"xml:///ctx:job/ctx:preprocess/ctx:processors/attribute('local')") + + runlocal = toboolean(runlocal) + + -- todo: only collect, then plug into file handler + + for files in xml.collected(xmldata,"/ctx:job/ctx:preprocess/ctx:files") do + for pattern in xml.collected(files,"ctx:file") do + local preprocessor = pattern.at['processor'] or "" + if preprocessor ~= "" then + treatments[#treatments+1] = { + pattern = string.topattern(justtext(xml.tostring(pattern))), + preprocessors = utilities.parsers.settings_to_array(preprocessor), + } + end + end + end + + variables.old = jobname + + local function needstreatment(oldfile) + for i=1,#treatments do + local treatment = treatments[i] + local pattern = treatment.pattern + if find(oldfile,pattern) then + return treatment + end + end + end + + local preparefile = #treatments > 0 and function(prepfiles,filename) + + local treatment = needstreatment(filename) + if treatment then + local oldfile = filename + newfile = oldfile .. "." .. suffix + if runlocal then + newfile = file.basename(newfile) + end + + if file.needsupdating(oldfile,newfile) then + local preprocessors = treatment.preprocessors + local runners = { } + for i=1,#preprocessors do + local preprocessor = preprocessors[i] + local command = commands[preprocessor] + if command then + command = xml.copy(command) + local suf = command.at and command.at['suffix'] or suffix + if suf then + newfile = oldfile .. "." .. suf + end + if runlocal then + newfile = file.basename(newfile) + end + for r, d, k in xml.elements(command,"ctx:old") do + d[k] = substitute(oldfile) + end + for r, d, k in xml.elements(command,"ctx:new") do + d[k] = substitute(newfile) + end + variables.old = oldfile + variables.new = newfile + for r, d, k in xml.elements(command,"ctx:value") do + local ek = d[k] + local ekat = ek.at and ek.at['name'] + if ekat then + d[k] = substitute(variables[ekat] or "") + end + end + command = xml.content(command) + runners[#runners+1] = justtext(command) + oldfile = newfile + if runlocal then + oldfile = file.basename(oldfile) + end + end end ---~ end - for e in xml.collected(x,"ctx:prepfile") do - local name = xml.text(e) - if islocal then - name = file.basename(name) + -- for tracing we have collected commands first + for i=1,#runners do + report_prepfiles("step %i: %s",i,runners[i]) end - local done = e.at['done'] or 'no' - if trace_prepfiles then - report_prepfiles("registering %s -> %s",done) + -- + for i=1,#runners do + local command = runners[i] + report_prepfiles("command: %s",command) + local result = os.spawn(command) or 0 + -- if result > 0 then + -- report_prepfiles("error, return code: %s",result) + -- end end - found = true - list[name] = done -- 'yes' or 'no' + if lfs.isfile(newfile) then + file.syncmtimes(filename,newfile) + report_prepfiles("%q is converted to %q",filename,newfile) + else + report_prepfiles("%q is not converted to %q",filename,newfile) + newfile = filename + end + elseif lfs.isfile(newfile) then + report_prepfiles("%q is already converted to %q",filename,newfile) + else + -- report_prepfiles("%q is not converted to %q",filename,newfile) + newfile = filename end + else + newfile = filename end - end -end + prepfiles[filename] = newfile --- -- -- + return newfile -local function found(name) -- used in resolve - local prepname = name .. "." .. suffix - if list[name] and lfs.isfile(prepname) then - if trace_prepfiles then - report_prepfiles("preprocessing: using %s",prepname) - end - return prepname end - return false + + table.setmetatableindex(ctxrunner.prepfiles,preparefile or dontpreparefile) + end local function resolve(name) -- used a few times later on - local filename = file.collapsepath(name) - local prepname = islocal and found(file.basename(name)) - if prepname then - return prepname - end - prepname = found(filename) - if prepname then - return prepname - end - return false + return ctxrunner.prepfiles[file.collapsepath(name)] or false end ---~ support.doiffileexistelse(name) - local processfile = commands.processfile local doifinputfileelse = commands.doifinputfileelse @@ -94,3 +293,20 @@ end function commands.preparedfile(name) return resolve(name) or name end + +function commands.getctxfile() + local ctxfile = document.arguments.ctx or "" + if ctxfile ~= "" then + ctxrunner.load(ctxfile) -- do we need to locate it? + end +end + +-- ctxrunner.load("t:/sources/core-ctx.ctx") +-- +-- context(ctxrunner.prepfiles["one-a.xml"]) context.par() +-- context(ctxrunner.prepfiles["one-b.xml"]) context.par() +-- context(ctxrunner.prepfiles["two-c.xml"]) context.par() +-- context(ctxrunner.prepfiles["two-d.xml"]) context.par() +-- context(ctxrunner.prepfiles["all-x.xml"]) context.par() +-- +-- inspect(ctxrunner.prepfiles) diff --git a/tex/context/base/core-ctx.mkiv b/tex/context/base/core-ctx.mkiv index e178ee21b..c7298187d 100644 --- a/tex/context/base/core-ctx.mkiv +++ b/tex/context/base/core-ctx.mkiv @@ -13,18 +13,15 @@ \writestatus{loading}{ConTeXt Core Macros / Job Control} -\unprotect - -\setnewconstant\preprocessmethod\plustwo % always check in mkiv - \registerctxluafile{core-ctx}{1.000} -\def\loadctxpreplist - {\ctxcommand{loadctxpreplist()}% - \glet\loadctxpreplist\relax} +\unprotect -\appendtoks - \loadctxpreplist -\to \everystarttext % maybe too late but don't change it now +\unexpanded\def\job_options_get_commandline {\ctxcommand{getcommandline()}} +\unexpanded\def\job_options_get_ctxfile {\ctxcommand{getctxfile()}} +\unexpanded\def\job_options_log {\ctxcommand{logoptions()}} +\unexpanded\def\job_options_set_modes {\ctxcommand{setdocumentmodes()}} +\unexpanded\def\job_options_set_modules {\ctxcommand{setdocumentmodules()}} +\unexpanded\def\job_options_set_environments{\ctxcommand{setdocumentenvironments()}} \protect \endinput diff --git a/tex/context/base/core-def.mkiv b/tex/context/base/core-def.mkiv index 4f856f996..5423b97aa 100644 --- a/tex/context/base/core-def.mkiv +++ b/tex/context/base/core-def.mkiv @@ -33,28 +33,39 @@ \appendtoks \font_preloads_at_start_text \to \everystarttext \appendtoks \font_preloads_at_stop_text \to \everystoptext -%prependtoks \preloadtypescript \to \everyjob \appendtoks \showcontextbanner \to \everyjob \appendtoks \initializenewlinechar \to \everyjob \appendtoks \calculatecurrenttime \to \everyjob \appendtoks \loadsystemfiles \to \everyjob -\appendtoks \loadoptionfile \to \everyjob % can load files ! + +\appendtoks \loadoptionfile \to \everyjob % obsolete +\appendtoks + \job_options_get_commandline % expands some commands + \job_options_get_ctxfile % might expand some commands +\to \everyjob % ok here? + \appendtoks \font_preloads_at_every_job \to \everyjob \appendtoks \settopskip \to \everyjob \appendtoks \initializemainlanguage \to \everyjob -%appendtoks \MPLIBregister \to \everyjob -\appendtoks \xmlinitialize \to \everyjob +\appendtoks \xmlinitialize \to \everyjob % is this still needed? \appendtoks \setfalse\c_page_backgrounds_new \to \everyjob \appendtoks \setfalse\c_page_backgrounds_some \to \everyjob \appendtoks \initializepagecounters \to \everyjob -\appendtoks \directsetup{*runtime:options} \to \everyjob % we could erase them afterwards % order can change -\appendtoks \directsetup{*runtime:modules} \to \everyjob % we could erase them afterwards % order can change -%appendtoks \page[\v!last] \page \to \everybye % moved to core-job, we need to do this cleaner -\appendtoks \ifarrangingpages\poparrangedpages\fi \to \everybye -%appendtoks \registerfileinfo[end]\jobfilename \to \everybye +\appendtoks \directsetup{*runtime:options} \to \everyjob % obsolete +\appendtoks \directsetup{*runtime:modules} \to \everyjob % obsolete -%appendtoks \MPLIBallocate{1000} \to \everydump +\appendtoks + \job_options_set_modes + \job_options_set_modules + \job_options_set_environments +\to \everyjob + +\appendtoks + \job_options_log +\to \everystarttext + +\appendtoks \ifarrangingpages\poparrangedpages\fi \to \everybye \prependtoks \resetallattributes \to \everybeforeoutput diff --git a/tex/context/base/file-job.lua b/tex/context/base/file-job.lua index 992e4b7ec..f210f444d 100644 --- a/tex/context/base/file-job.lua +++ b/tex/context/base/file-job.lua @@ -9,22 +9,28 @@ if not modules then modules = { } end modules ['file-job'] = { -- in retrospect dealing it's not that bad to deal with the nesting -- and push/poppign at the tex end -local format, gsub, match = string.format, string.gsub, string.match +local format, gsub, match, find = string.format, string.gsub, string.match, string.find local insert, remove, concat = table.insert, table.remove, table.concat local commands, resolvers, context = commands, resolvers, context +local settings_to_array = utilities.parsers.settings_to_array +local write_nl = texio.write_nl + local trace_jobfiles = false trackers.register("system.jobfiles", function(v) trace_jobfiles = v end) local report_jobfiles = logs.reporter("system","jobfiles") local texsetcount = tex.setcount local elements = interfaces.elements +local constants = interfaces.constants local variables = interfaces.variables local logsnewline = logs.newline local logspushtarget = logs.pushtarget local logspoptarget = logs.poptarget +local allocate = utilities.storage.allocate + local v_outer = variables.outer local v_text = variables.text local v_project = variables.project @@ -683,3 +689,199 @@ function commands.loadexamodes(filename) report_examodes("no mode file %s",filename) -- todo: message system end end + +-- changed in mtx-context +-- code moved from luat-ini + +-- todo: locals when mtx-context is changed + +document = document or { + arguments = allocate(), + files = allocate(), + options = { + commandline = { + environments = allocate(), + modules = allocate(), + modes = allocate(), + }, + ctxfile = { + environments = allocate(), + modules = allocate(), + modes = allocate(), + }, + }, +} + +function document.setargument(key,value) + document.arguments[key] = value +end + +function document.setdefaultargument(key,default) + local v = document.arguments[key] + if v == nil or v == "" then + document.arguments[key] = default + end +end + +function document.setfilename(i,name) + if name then + document.files[tonumber(i)] = name + else + document.files[#document.files+1] = tostring(i) + end +end + +function document.getargument(key,default) -- commands + local v = document.arguments[key] + if type(v) == "boolean" then + v = (v and "yes") or "no" + document.arguments[key] = v + end + context(v or default or "") +end + +function document.getfilename(i) -- commands + context(document.files[i] or "") +end + +local function validstring(s) + return type(s) == "string" and s ~= "" and s or nil +end + +function commands.getcommandline() -- has to happen at the tex end in order to expand + + -- the document[arguments|files] tables are copies + + local arguments = document.arguments + local files = document.files + local options = document.options + + for k, v in next, environment.arguments do + k = gsub(k,"^c:","") -- already done, but better be safe than sorry + if arguments[k] == nil then + arguments[k] = v + end + end + + -- in the new mtx=context approach we always pass a stub file so we need to + -- to trick the files table which actually only has one entry in a tex job + + if arguments.timing then + context.usemodule("timing") + end + + if arguments.batchmode then + context.batchmode(false) + end + + if arguments.nonstopmode then + context.nonstopmode(false) + end + + if arguments.nostatistics then + directives.enable("system.nostatistics") + end + + if arguments.paranoid then + context.setvalue("maxreadlevel",1) + end + + if validstring(arguments.path) then + context.usepath { arguments.path } + end + + local inputfile = validstring(arguments.input) + + if inputfile and file.dirname(inputfile) == "." and lfs.isfile(inputfile) then + -- nicer in checks + inputfile = file.basename(inputfile) + end + + context.setupsystem { + [constants.directory] = validstring(arguments.setuppath), + [constants.inputfile] = inputfile, + [constants.file] = validstring(arguments.result), + [constants.random] = validstring(arguments.randomseed), + [constants.n] = validstring(arguments.kindofrun), + [constants.m] = validstring(arguments.currentrun), + } + + if validstring(arguments.arguments) then + context.setupenv { arguments.arguments } + end + + if arguments.once then + directives.enable("system.runonce") + end + + if arguments.noarrange then + context.setuparranging { variables.disable } + end + + -- + + local commandline = options.commandline + + commandline.environments = table.append(commandline.environments,settings_to_array(validstring(arguments.environments))) + commandline.modules = table.append(commandline.modules, settings_to_array(validstring(arguments.modules))) + commandline.modes = table.append(commandline.modes, settings_to_array(validstring(arguments.modes))) + + -- + + if #files == 0 then + local list = settings_to_array(validstring(arguments.files)) + if list and #list > 0 then + files = list + end + end + + if #files == 0 then + files = { validstring(arguments.input) } + end + + -- + + document.arguments = arguments + document.files = files + +end + +-- commandline wins over ctxfile + +local function apply(list,action) + if list then + for i=1,#list do + action { list[i] } + end + end +end + +function commands.setdocumentmodes() -- was setup: *runtime:modes + apply(document.options.ctxfile .modes,context.enablemode) + apply(document.options.commandline.modes,context.enablemode) +end + +function commands.setdocumentmodules() -- was setup: *runtime:modules + apply(document.options.ctxfile .modules,context.usemodule) + apply(document.options.commandline.modules,context.usemodule) +end + +function commands.setdocumentenvironments() -- was setup: *runtime:environments + apply(document.options.ctxfile .environments,context.environment) + apply(document.options.commandline.environments,context.environment) +end + +function commands.logoptions() + local arguments = document.arguments + local files = document.files + write_nl("log","\n% begin of command line arguments\n%\n") + for k, v in next, arguments do + write_nl("log",format("%% %-20s = %s",k,tostring(v))) + end + write_nl("log","%\n% end of command line arguments\n") + write_nl("log","\n% begin of command line files\n%\n") + for i=1,#files do + write_nl("log",format("%% %i %s",i,files[i])) + end + write_nl("log","%\n% end of command line files\n\n") +end diff --git a/tex/context/base/file-job.mkvi b/tex/context/base/file-job.mkvi index 112400cbd..a801f7309 100644 --- a/tex/context/base/file-job.mkvi +++ b/tex/context/base/file-job.mkvi @@ -75,11 +75,16 @@ \def\syst_files_load#name% only mkiv files {\readsysfile{#name.\mksuffix}{\showmessage\m!system2{#name.\mksuffix}}\donothing} -\unexpanded\def\loadoptionfile +% \unexpanded\def\loadoptionfile +% {\readjobfile{\jobname.\f!optionextension} +% {\writestatus\m!system{\jobname.\f!optionextension\space loaded}% +% \ctxcommand{copyfiletolog("\jobname.\f!optionextension")}}% +% {\writestatus\m!system{no \jobname.\f!optionextension}}} + +\unexpanded\def\loadoptionfile % this one is soon obsolete {\readjobfile{\jobname.\f!optionextension} - {\writestatus\m!system{\jobname.\f!optionextension\space loaded}% - \ctxcommand{copyfiletolog("\jobname.\f!optionextension")}}% - {\writestatus\m!system{no \jobname.\f!optionextension}}} + {\ctxcommand{copyfiletolog("\jobname.\f!optionextension")}}% + {}} % document structure @@ -110,6 +115,8 @@ \unexpanded\def\autostarttext{\ctxcommand{autostarttext()}} \unexpanded\def\autostoptext {\ctxcommand{autostoptext()}} +\unexpanded\def\finishjob{\stoptext} % nicer in luatex call commandline + \newtoks\everystartnotext \newtoks\everystopnotext @@ -190,7 +197,7 @@ %D Handy for modules that have a test/demo appended. -\def\continueifinputfile#name{\doifnot\inputfilename{#name}\endinput} +\def\continueifinputfile#name{\doifnot\inputfilename{#name}\endinput} % will be lua call ./ check %def\processifinputfile #name{\doif \inputfilename{#name}} % \startproject test diff --git a/tex/context/base/font-pre.mkiv b/tex/context/base/font-pre.mkiv index 9a2c45172..141bfd2ff 100644 --- a/tex/context/base/font-pre.mkiv +++ b/tex/context/base/font-pre.mkiv @@ -365,6 +365,9 @@ \definealternativestyle [\v!sans,\v!sansserif] [\ss] [] \definealternativestyle [\v!sansbold] [\ss\bf] [] +\definealternativestyle [\v!roman,\v!serif,\v!regular] [\rm] +\definealternativestyle [\v!handwritten] [\hw] +\definealternativestyle [\v!calligraphic] [\cg] % % maybe we need interface neutral as well (for use in cld): % diff --git a/tex/context/base/l-io.lua b/tex/context/base/l-io.lua index 4f27dc1dc..657b755b8 100644 --- a/tex/context/base/l-io.lua +++ b/tex/context/base/l-io.lua @@ -17,14 +17,14 @@ else io.fileseparator, io.pathseparator = "/" , ":" end -function io.loaddata(filename,textmode) +function io.loaddata(filename,textmode) -- return nil if empty local f = io.open(filename,(textmode and 'r') or 'rb') if f then local data = f:read('*all') f:close() - return data - else - return nil + if #data > 0 then + return data + end end end @@ -46,6 +46,45 @@ function io.savedata(filename,data,joiner) end end +function io.loadlines(filename,n) -- return nil if empty + local f = io.open(filename,'r') + if f then + if n then + local lines = { } + for i=1,n do + local line = f:read("*lines") + if line then + lines[#lines+1] = line + else + break + end + end + f:close() + lines = concat(lines,"\n") + if #lines > 0 then + return lines + end + else + local line = f:read("*line") or "" + assert(f:close()) + if #line > 0 then + return line + end + end + end +end + +function io.loadchunk(filename,n) + local f = io.open(filename,'rb') + if f then + local data = f:read(n or 1024) + f:close() + if #data > 0 then + return data + end + end +end + function io.exists(filename) local f = io.open(filename) if f == nil then diff --git a/tex/context/base/l-lpeg.lua b/tex/context/base/l-lpeg.lua index 13294ab0d..50b14db06 100644 --- a/tex/context/base/l-lpeg.lua +++ b/tex/context/base/l-lpeg.lua @@ -234,12 +234,16 @@ function lpeg.split(separator,str) end function string.split(str,separator) - local c = cache[separator] - if not c then - c = tsplitat(separator) - cache[separator] = c + if separator then + local c = cache[separator] + if not c then + c = tsplitat(separator) + cache[separator] = c + end + return match(c,str) + else + return { str } end - return match(c,str) end local spacing = patterns.spacer^0 * newline -- sort of strip diff --git a/tex/context/base/l-md5.lua b/tex/context/base/l-md5.lua index 1d471c966..6abf2e17d 100644 --- a/tex/context/base/l-md5.lua +++ b/tex/context/base/l-md5.lua @@ -31,15 +31,30 @@ if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end --~ function md5.dec(str) return (gsub(md5.sum(str),".",remap)) end --~ end -function file.needs_updating(oldname,newname,threshold) -- size modification access change - local oldtime = lfs.attributes(oldname, modification) - local newtime = lfs.attributes(newname, modification) - if newtime >= oldtime then - return false - elseif oldtime - newtime < (threshold or 1) then - return false +function file.needsupdating(oldname,newname,threshold) -- size modification access change + local oldtime = lfs.attributes(oldname,"modification") + if oldtime then + local newtime = lfs.attributes(newname,"modification") + if not newtime then + return true -- no new file, so no updating needed + elseif newtime >= oldtime then + return false -- new file definitely needs updating + elseif oldtime - newtime < (threshold or 1) then + return false -- new file is probably still okay + else + return true -- new file has to be updated + end else - return true + return false -- no old file, so no updating needed + end +end + +file.needs_updating = file.needsupdating + +function file.syncmtimes(oldname,newname) + local oldtime = lfs.attributes(oldname,"modification") + if oldtime and lfs.isfile(newname) then + lfs.touch(newname,oldtime,oldtime) end end @@ -61,7 +76,7 @@ function file.loadchecksum(name) return nil end -function file.savechecksum(name, checksum) +function file.savechecksum(name,checksum) if not checksum then checksum = file.checksum(name) end if checksum then io.savedata(name .. ".md5",checksum) diff --git a/tex/context/base/luat-cod.lua b/tex/context/base/luat-cod.lua index b022f31c3..8c721aa15 100644 --- a/tex/context/base/luat-cod.lua +++ b/tex/context/base/luat-cod.lua @@ -103,7 +103,7 @@ if not environment.luafilechunk then end -if not environment.engineflags then +if not environment.engineflags then -- raw flags local engineflags = { } for i=-10,#arg do local a = arg[i] diff --git a/tex/context/base/luat-env.lua b/tex/context/base/luat-env.lua index 4f1b661c2..840b2344f 100644 --- a/tex/context/base/luat-env.lua +++ b/tex/context/base/luat-env.lua @@ -79,6 +79,8 @@ local mt = { setmetatable(environment,mt) +-- context specific arguments (in order not to confuse the engine) + function environment.initializearguments(arg) local arguments, files = { }, { } environment.arguments, environment.files, environment.sortedflags = arguments, files, nil @@ -87,10 +89,12 @@ function environment.initializearguments(arg) if index > 0 then local flag, value = match(argument,"^%-+(.-)=(.-)$") if flag then + flag = gsub(flag,"^c:","") arguments[flag] = unquoted(value or "") else flag = match(argument,"^%-+(.+)") if flag then + flag = gsub(flag,"^c:","") arguments[flag] = true else files[#files+1] = argument @@ -110,7 +114,7 @@ end -- tricky: too many hits when we support partials unless we add -- a registration of arguments so from now on we have 'partial' -function environment.argument(name,partial) +function environment.getargument(name,partial) local arguments, sortedflags = environment.arguments, environment.sortedflags if arguments[name] then return arguments[name] @@ -133,6 +137,8 @@ function environment.argument(name,partial) return nil end +environment.argument = environment.getargument + function environment.splitarguments(separator) -- rather special, cut-off before separator local done, before, after = false, { }, { } local originalarguments = environment.originalarguments diff --git a/tex/context/base/luat-ini.lua b/tex/context/base/luat-ini.lua index 204cc7bd1..1f7cca4af 100644 --- a/tex/context/base/luat-ini.lua +++ b/tex/context/base/luat-ini.lua @@ -12,8 +12,6 @@ local debug = require "debug" local string, table, lpeg, math, io, system = string, table, lpeg, math, io, system local next, setfenv = next, setfenv or debug.setfenv -local mark = utilities.storage.mark - --[[ldx-- <p>We cannot load anything yet. However what we will do us reserve a fewtables. These can be used for runtime user data or third party modules and will not be @@ -26,15 +24,6 @@ moduledata = moduledata or { } -- only for development team documentdata = documentdata or { } -- for users (e.g. raw data) parametersets = parametersets or { } -- experimental for team -document = document or { } -- only for context itself - ---[[ldx-- -<p>These can be used/set by the caller program; <t>mtx-context.lua</t> does it.</p> ---ldx]]-- - -document.arguments = mark(document.arguments or { }) -document.files = mark(document.files or { }) - --[[ldx-- <p>Please create a namespace within these tables before using them!</p> @@ -157,33 +146,3 @@ end storage.register("lua/numbers", lua.numbers, "lua.numbers") storage.register("lua/messages", lua.messages, "lua.messages") - ---~ local arguments, files = document.arguments, document.files -- set later - -function document.setargument(key,value) - document.arguments[key] = value -end - -function document.setdefaultargument(key,default) - local v = document.arguments[key] - if v == nil or v == "" then - document.arguments[key] = default - end -end - -function document.getargument(key,default) - local v = document.arguments[key] - if type(v) == "boolean" then - v = (v and "yes") or "no" - document.arguments[key] = v - end - context(v or default or "") -end - -function document.setfilename(i,name) - document.files[tonumber(i)] = name -end - -function document.getfilename(i) - context(document.files[i] or "") -end diff --git a/tex/context/base/lxml-ini.mkiv b/tex/context/base/lxml-ini.mkiv index 84ebc5823..14fbd68e6 100644 --- a/tex/context/base/lxml-ini.mkiv +++ b/tex/context/base/lxml-ini.mkiv @@ -313,7 +313,7 @@ \xmlprocessingmode\executeifdefined{\??xmldefaults\directxmlparameter\c!default}\plusone \to \everysetupxml -\unexpanded\def\xmlinitialize +\unexpanded\def\xmlinitialize % is this still needed? {\the\everysetupxml} \let\p_lxml_entities\empty diff --git a/tex/context/base/math-def.mkiv b/tex/context/base/math-def.mkiv index 43a511e43..1c602187f 100644 --- a/tex/context/base/math-def.mkiv +++ b/tex/context/base/math-def.mkiv @@ -330,6 +330,8 @@ \let\normalunderbrace \underbrace \let\normaloverparent \overparent \let\normalunderparent \underparent +\let\normaloverbracket \overbracket +\let\normalunderbracket \underbracket \let\normalunderleftarrow \underleftarrow \let\normaloverleftarrow \overleftarrow \let\normalunderrightarrow\underrightarrow @@ -343,6 +345,8 @@ \unexpanded\def\doublebrace {\mathopwithlimits\normaldoublebrace } \unexpanded\def\overparent {\mathopwithlimits\normaloverparent } \unexpanded\def\underparent {\mathopwithlimits\normalunderparent } +\unexpanded\def\overbracket {\mathopwithlimits\normaloverbracket } +\unexpanded\def\underbracket {\mathopwithlimits\normalunderbracket } \unexpanded\def\doubleparent {\mathopwithlimits\normaldoubleparent } \unexpanded\def\underleftarrow {\mathopwithlimits\normalunderleftarrow } \unexpanded\def\overleftarrow {\mathopwithlimits\normaloverleftarrow } diff --git a/tex/context/base/math-noa.lua b/tex/context/base/math-noa.lua index 8caf21cc2..02288432f 100644 --- a/tex/context/base/math-noa.lua +++ b/tex/context/base/math-noa.lua @@ -799,9 +799,20 @@ italics[math_char] = function(pointer,what,n,parent) end end end + + -- maybe also correction when next == nil + if correction and correction ~= 0 then local next_noad = parent.next - if next_noad and next_noad.id == math_noad then + if not next_noad then + if true then -- this might become an option + if trace_italics then + report_italics("method %s: adding %s italic correction between %s (0x%05X) and end math", + method,number.points(correction),utfchar(char),char) + end + insert_node_after(parent,parent,new_kern(correction)) + end + elseif next_noad.id == math_noad then local next_subtype = next_noad.subtype if next_subtype == noad_punct or next_subtype == noad_ord then local next_nucleus = next_noad.nucleus diff --git a/tex/context/base/mult-aux.mkiv b/tex/context/base/mult-aux.mkiv index b4c6ad039..011fba7d3 100644 --- a/tex/context/base/mult-aux.mkiv +++ b/tex/context/base/mult-aux.mkiv @@ -707,6 +707,31 @@ \expandafter\mult_interfaces_show_parent_chain\csname#1:\s!parent\endcsname \fi} +%D Another helper: + +\unexpanded\def\doifelsecommandhandler#1#2% namespace name + {\ifcsname#1#2:\s!parent\endcsname + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\unexpanded\def\doifcommandhandler#1#2% namespace name + {\ifcsname#1#2:\s!parent\endcsname + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +\unexpanded\def\doifnotcommandhandler#1#2% namespace name + {\ifcsname#1#2:\s!parent\endcsname + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +\let\doifcommandhandlerelse\doifelsecommandhandler + %D Conventions: %D %D \starttyping diff --git a/tex/context/base/mult-low.lua b/tex/context/base/mult-low.lua index 7d61d0427..134e4c82a 100644 --- a/tex/context/base/mult-low.lua +++ b/tex/context/base/mult-low.lua @@ -124,6 +124,7 @@ return { "starttexcode", "stoptexcode", -- "doifsetupselse", "doifsetups", "doifnotsetups", "setup", "setups", "texsetup", "xmlsetup", "luasetup", "directsetup", + "doifelsecommandhandler","doifnotcommandhandler","doifcommandhandler", -- "newmode", "setmode", "resetmode", "newsystemmode", "setsystemmode", "resetsystemmode", "pushsystemmode", "popsystemmode", diff --git a/tex/context/base/page-mak.mkvi b/tex/context/base/page-mak.mkvi index f37c4f613..e5a722676 100644 --- a/tex/context/base/page-mak.mkvi +++ b/tex/context/base/page-mak.mkvi @@ -88,7 +88,10 @@ \newbox \b_page_makeup \newtoks\t_page_makeup_every_setup -\def\page_makeup_start_yes[#name][#settings]% +\def\page_makeup_start_yes[#name]% [#settings]% + {\doifelsecommandhandler\??makeup{#name}\page_makeup_start_indeed\page_makeup_start_nop[#name]}% + +\def\page_makeup_start_indeed[#name][#settings]% {\doifelsenothing{\namedmakeupparameter{#name}\c!page} {\page}% new, so best not have dangling mess here like references (we could capture then and flush embedded) {\page[\namedmakeupparameter{#name}\c!page]}% diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf Binary files differindex 8d2ac5857..d92622355 100644 --- a/tex/context/base/status-files.pdf +++ b/tex/context/base/status-files.pdf diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf Binary files differindex 0d58d1b16..d8ab22c4e 100644 --- a/tex/context/base/status-lua.pdf +++ b/tex/context/base/status-lua.pdf diff --git a/tex/context/base/status-mkiv.lua b/tex/context/base/status-mkiv.lua index d7ab099a6..cbb7040db 100644 --- a/tex/context/base/status-mkiv.lua +++ b/tex/context/base/status-mkiv.lua @@ -344,6 +344,16 @@ return { status = "okay", }, { + filename = "cont-nop", + marktype = "mkiv", + status = "okay", + }, + { + filename = "cont-yes", + marktype = "mkiv", + status = "okay", + }, + { filename = "regi-ini", marktype = "mkiv", status = "okay", diff --git a/tex/context/base/strc-lst.lua b/tex/context/base/strc-lst.lua index 48aab78db..4666738d5 100644 --- a/tex/context/base/strc-lst.lua +++ b/tex/context/base/strc-lst.lua @@ -597,7 +597,7 @@ function lists.hasnumberdata(name,n) local data = lists.result[n] if data then local numberdata = data.numberdata - if numberdata then + if numberdata and not numberdata.hidenumber then -- th ehide number is true return true end end diff --git a/tex/context/base/tabl-xnt.mkvi b/tex/context/base/tabl-xnt.mkvi index 35451abe0..ffa1f501e 100644 --- a/tex/context/base/tabl-xnt.mkvi +++ b/tex/context/base/tabl-xnt.mkvi @@ -129,7 +129,7 @@ \unexpanded\def\tabl_x_TABLE_start_indeed[#settings]% {\bgroup \tabl_x_prepare{#settings}% - \edef\tabl_x_current_buffer{\x_table_default_buffer}% + \edef\tabl_x_current_buffer{\tabl_x_default_buffer}% \buff_pickup\tabl_x_current_buffer{bTABLE}{eTABLE}\relax\tabl_x_process} \protect \endinput diff --git a/tex/context/base/tabl-xtb.lua b/tex/context/base/tabl-xtb.lua index 395d65a03..e999cbd74 100644 --- a/tex/context/base/tabl-xtb.lua +++ b/tex/context/base/tabl-xtb.lua @@ -391,7 +391,7 @@ function xtables.reflow_width() for c=1,nofcolumns do local drc = row[c] if drc.list then - --- flush_node_list(drc.list) + -- flush_node_list(drc.list) drc.list = false end end @@ -512,7 +512,6 @@ function xtables.reflow_width() end -- maybe also options[v_width] here but tricky as width does not say -- much about amount - if options[v_width] then -- not that much (we could have a clever vpack loop balancing .. no fun) local factor = (widetotal + delta) / width if trace_xtable then diff --git a/tex/context/base/trac-deb.mkiv b/tex/context/base/trac-deb.mkiv index 4f5f0e931..10e462a31 100644 --- a/tex/context/base/trac-deb.mkiv +++ b/tex/context/base/trac-deb.mkiv @@ -31,7 +31,7 @@ \unexpanded\def\enableexperiments [#1]{\ctxlua{experiments.enable("#1")}} \unexpanded\def\disableexperiments[#1]{\ctxlua{experiments.disable("#1")}} -\unexpanded\def\showdebuginfo{\ctxlua{lmx.showdebuginfo()}} -\unexpanded\def\overloaderror{\ctxlua{lmx.overloaderror()}} % \enabledirectives[system.showerror] +\unexpanded\def\showdebuginfo {\ctxlua{lmx.showdebuginfo()}} +\unexpanded\def\overloaderror {\ctxlua{lmx.overloaderror()}} % \enabledirectives[system.showerror] \unexpanded\def\showlogcategories {\ctxlua{logs.show()}} diff --git a/tex/context/base/trac-set.lua b/tex/context/base/trac-set.lua index bc0070eb4..ed7367b4f 100644 --- a/tex/context/base/trac-set.lua +++ b/tex/context/base/trac-set.lua @@ -205,7 +205,7 @@ function setters.show(t) local value, default, modules = functions.value, functions.default, #functions value = value == nil and "unset" or tostring(value) default = default == nil and "unset" or tostring(default) - t.report("%-30s modules: %2i default: %6s value: %6s",name,modules,default,value) + t.report("%-50s modules: %2i default: %6s value: %6s",name,modules,default,value) end end t.report() @@ -297,17 +297,31 @@ end) -- experiment -local flags = environment and environment.engineflags +if environment then -if flags then - if trackers and flags.trackers then - setters.initialize("flags","trackers", settings_to_hash(flags.trackers)) - -- t_enable(flags.trackers) - end - if directives and flags.directives then - setters.initialize("flags","directives", settings_to_hash(flags.directives)) - -- d_enable(flags.directives) + -- The engineflags are known earlier than environment.arguments but maybe we + -- need to handle them both as the later are parsed differently. The c: prefix + -- is used by mtx-context to isolate the flags from those that concern luatex. + + local engineflags = environment.engineflags + + if engineflags then + if trackers then + local list = engineflags["c:trackers"] or engineflags["trackers"] + if type(list) == "string" then + setters.initialize("flags","trackers",settings_to_hash(list)) + -- t_enable(list) + end + end + if directives then + local list = engineflags["c:directives"] or engineflags["directives"] + if type(list) == "string" then + setters.initialize("flags","directives", settings_to_hash(list)) + -- d_enable(list) + end + end end + end -- here diff --git a/tex/context/base/typo-mar.mkiv b/tex/context/base/typo-mar.mkiv index a393fc250..fbd06acc9 100644 --- a/tex/context/base/typo-mar.mkiv +++ b/tex/context/base/typo-mar.mkiv @@ -110,7 +110,7 @@ % \c!align=, % \c!method=, \c!style=\v!bold, - \c!color=, % maybe textcolor + \c!color=, % maybe \maintextcolor % \c!name=, % \c!category=, \c!threshold=.25ex, @@ -148,7 +148,7 @@ \appendtoks \forgetall \tf - \deactivatecolor + \deactivatecolor % needed, but maybe we should switch to maintextcolor: \onlyinheritmaintextcolor \to \everymargindatacontent % trialtypesetting: no need for margin stuff while trialing as diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index ea509c338..96a34326e 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 05/30/12 11:26:34 +-- merge date : 06/05/12 09:16:10 do -- begin closure to overcome local limits and interference @@ -1331,12 +1331,16 @@ function lpeg.split(separator,str) end function string.split(str,separator) - local c = cache[separator] - if not c then - c = tsplitat(separator) - cache[separator] = c + if separator then + local c = cache[separator] + if not c then + c = tsplitat(separator) + cache[separator] = c + end + return match(c,str) + else + return { str } end - return match(c,str) end local spacing = patterns.spacer^0 * newline -- sort of strip @@ -2468,14 +2472,14 @@ else io.fileseparator, io.pathseparator = "/" , ":" end -function io.loaddata(filename,textmode) +function io.loaddata(filename,textmode) -- return nil if empty local f = io.open(filename,(textmode and 'r') or 'rb') if f then local data = f:read('*all') f:close() - return data - else - return nil + if #data > 0 then + return data + end end end @@ -2497,6 +2501,45 @@ function io.savedata(filename,data,joiner) end end +function io.loadlines(filename,n) -- return nil if empty + local f = io.open(filename,'r') + if f then + if n then + local lines = { } + for i=1,n do + local line = f:read("*lines") + if line then + lines[#lines+1] = line + else + break + end + end + f:close() + lines = concat(lines,"\n") + if #lines > 0 then + return lines + end + else + local line = f:read("*line") or "" + assert(f:close()) + if #line > 0 then + return line + end + end + end +end + +function io.loadchunk(filename,n) + local f = io.open(filename,'rb') + if f then + local data = f:read(n or 1024) + f:close() + if #data > 0 then + return data + end + end +end + function io.exists(filename) local f = io.open(filename) if f == nil then |