From 15bbde433ae20973daca814631a22c558eaecd57 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Thu, 21 Mar 2019 20:54:31 +0000 Subject: luamplib (21mar19) git-svn-id: svn://tug.org/texlive/trunk@50510 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/luatex/luamplib/NEWS | 13 + Master/texmf-dist/doc/luatex/luamplib/luamplib.pdf | Bin 154238 -> 163569 bytes .../doc/luatex/luamplib/test-luamplib-latex.tex | 1 + .../doc/luatex/luamplib/test-luamplib-plain.tex | 1 + .../texmf-dist/source/luatex/luamplib/luamplib.dtx | 1530 +++++++++++--------- Master/texmf-dist/tex/luatex/luamplib/luamplib.lua | 887 ++++++------ Master/texmf-dist/tex/luatex/luamplib/luamplib.sty | 123 +- 7 files changed, 1357 insertions(+), 1198 deletions(-) (limited to 'Master') diff --git a/Master/texmf-dist/doc/luatex/luamplib/NEWS b/Master/texmf-dist/doc/luatex/luamplib/NEWS index 7eaf2ba8636..8fb7136dba6 100644 --- a/Master/texmf-dist/doc/luatex/luamplib/NEWS +++ b/Master/texmf-dist/doc/luatex/luamplib/NEWS @@ -1,5 +1,18 @@ History of the luamplib package +2019/03/20 2.20.0 + * huge changes, but mostly internal, so apparently not much difference + from previous version. + * '\mplibforcehmode' makes mplibcode typeset in horizontal mode. + '\mplibnoforcehmode' reverts the setting. The latter is default. + * '\mpliblegacybehavior{disable}' triggers a new mode of processing + verbatimtex .. etex: along with btex .. etex, they will be processed + sequentially one by one. Old behavior, being default, can be restored + by declaring '\mpliblegacybehavior{enable}'. + Incidentally, verbatimtex .. etex in MP input files is honored + from this version, save those that contain '\documentclass' + or '\begin{document}' etc, which is totally ignored. + 2018/09/27 2.12.5 * change dash.offset pattern from "%i" to "%f" (PR #77) * remove unnecessary variables that go back to context (issue #76) diff --git a/Master/texmf-dist/doc/luatex/luamplib/luamplib.pdf b/Master/texmf-dist/doc/luatex/luamplib/luamplib.pdf index 8cff394e46a..e119f2d6605 100644 Binary files a/Master/texmf-dist/doc/luatex/luamplib/luamplib.pdf and b/Master/texmf-dist/doc/luatex/luamplib/luamplib.pdf differ diff --git a/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-latex.tex b/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-latex.tex index a500e2181dd..237a2897480 100644 --- a/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-latex.tex +++ b/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-latex.tex @@ -3,6 +3,7 @@ \usepackage{xcolor} \everymplib{ beginfig(0); } \everyendmplib{ endfig; } +\mpliblegacybehavior{true}% \begin{document} \tracingcommands1 A% diff --git a/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-plain.tex b/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-plain.tex index d7a8ed90bcc..2161cf2f766 100644 --- a/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-plain.tex +++ b/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-plain.tex @@ -2,6 +2,7 @@ \input color \definecolor{orange}{rgb}{1,0.5,0} \input luamplib.sty +\mpliblegacybehavior{true}% \everymplib{ beginfig(0); }\everyendmplib{ endfig; } \tracingcommands1 A% diff --git a/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx b/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx index 1de69bafd8e..35ac43b3c02 100644 --- a/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx +++ b/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment -- by the way, this file contains UTF-8 % -% Copyright (C) 2008-2018 by Hans Hagen, Taco Hoekwater, Elie Roux, +% Copyright (C) 2008-2019 by Hans Hagen, Taco Hoekwater, Elie Roux, % Manuel Pégourié-Gonnard, Philipp Gesang and Kim Dohyun. % Currently maintained by the LuaLaTeX development team. % Support: @@ -85,7 +85,7 @@ See source file '\inFileName' for licencing and contact information. %<*driver> \NeedsTeXFormat{LaTeX2e} \ProvidesFile{luamplib.drv}% - [2018/09/27 v2.12.5 Interface for using the mplib library]% + [2019/03/20 v2.20.0 Interface for using the mplib library]% \documentclass{ltxdoc} \usepackage{metalogo,multicol,mdwlist,fancyvrb,xspace} \usepackage[x11names]{xcolor} @@ -153,18 +153,18 @@ See source file '\inFileName' for licencing and contact information. % \author{Hans Hagen, Taco Hoekwater, Elie Roux, Philipp Gesang and Kim Dohyun\\ % Maintainer: LuaLaTeX Maintainers --- % Support: \email{lualatex-dev@tug.org}} -% \date{2018/09/27 v2.12.5} +% \date{2019/03/20 v2.20.0} % % \maketitle % % \begin{abstract} -% Package to have metapost code typeset directly in a document with Lua\TeX . +% Package to have metapost code typeset directly in a document with \LuaTeX. % \end{abstract} % % \section{Documentation} % % This packages aims at providing a simple way to typeset directly metapost -% code in a document with \LuaTeX . \LuaTeX\ is built with the lua +% code in a document with \LuaTeX. \LuaTeX\ is built with the lua % \texttt{mplib} library, that runs metapost code. This package is basically a % wrapper (in Lua) for the Lua \texttt{mplib} functions and some \TeX\ % functions to have the output of the \texttt{mplib} functions in the pdf. @@ -194,15 +194,29 @@ See source file '\inFileName' for licencing and contact information. % |textext()| is a more versatile macro equivalent to |TEX()| from TEX.mp. % |TEX()| is also allowed and is a synomym of |textext()|.\par\smallskip % \textsc{n.b.} Since v2.5, |btex ... etex| input from external |mp| files -% will also be processed by \textsf{luamplib}. However, -% |verbatimtex ... etex| will be entirely ignored in this case. -% \item |verbatimtex ... etex| (in \TeX\ file) that comes just before |beginfig()| -% is not ignored, but the \TeX\ code inbetween will be inserted before the +% will also be processed by \textsf{luamplib}.\par\smallskip +% \textsc{n.b.} Since v2.20, |verbatimtex ... etex| from external |mp| files +% will be also processed by \textsf{luamplib}. Warning: This is a change +% from previous version. +% \end{itemize} +% +% Some more changes and cuations are: +% +% \paragraph{\cs{mplibforcehmode}} +% When this macro is declared, every mplibcode figure box will be +% typeset in horizontal mode, so \cs{centering}, \cs{raggedleft} etc +% will have effects. |\mplibnoforcehmode|, being default, reverts this +% setting. +% +% \paragraph{\cs{mpliblegacybehavior\{enable\}}} +% By default, |\mpliblegacybehavior{enable}| is already declared, +% in which case +% a |verbatimtex ... etex| that comes just before |beginfig()| +% is not ignored, but the \TeX\ code will be inserted before the % following mplib hbox. Using this command, % each mplib box can be freely moved horizontally and/or vertically. % Also, a box number might be assigned to mplib box, allowing it to be % reused later (see test files). -% \textsc{e.g.} % \begin{verbatim} % \mplibcode % verbatimtex \moveright 3cm etex; beginfig(0); ... endfig; @@ -213,11 +227,10 @@ See source file '\inFileName' for licencing and contact information. % \end{verbatim} % \textsc{n.b.} \cs{endgraf} should be used instead of \cs{par} inside % |verbatimtex ... etex|. -% \item -% \TeX\ code in |VerbatimTeX(...)| or |verbatimtex ... etex| (in \TeX\ file) +% +% By contrast, \TeX\ code in |VerbatimTeX(...)| or |verbatimtex ... etex| % between |beginfig()| and |endfig| will be inserted % after flushing out the mplib figure. -% \textsc{e.g.} % \begin{verbatim} % \mplibcode % D := sqrt(2)**7; @@ -228,32 +241,48 @@ See source file '\inFileName' for licencing and contact information. % \endmplibcode % diameter: \Dia bp. % \end{verbatim} -% \item Notice that, after each figure is processed, macro \cs{MPwidth} stores +% +% \paragraph{\cs{mpliblegacybehavior\{disable\}}} +% If |\mpliblegacybehavior{disabled}| is declared by user, any +% |verbatimtex ... etex| will be executed, along with |btex ... etex|, +% sequentially one by one. +% So, some \TeX\ code in |verbatimtex ... etex| will have effects on +% |btex ... etex| codes that follows. +% \begin{verbatim} +% \begin{mplibcode} +% beginfig(0); +% draw btex ABC etex; +% verbatimtex \bfseries etex; +% draw btex DEF etex shifted (1cm,0); % bold face +% draw btex GHI etex shifted (2cm,0); % bold face +% endfig; +% \end{mplibcode} +% \end{verbatim} +% +% \paragraph{About figure box metrics} +% Notice that, after each figure is processed, macro \cs{MPwidth} stores % the width value of latest figure; \cs{MPheight}, the height value. % Incidentally, also note that \cs{MPllx}, \cs{MPlly}, \cs{MPurx}, and % \cs{MPury} store the bounding box information of latest figure % without the unit |bp|. -% \item Since v2.3, new macros \cs{everymplib} and \cs{everyendmplib} redefine +% +% \paragraph{\cs{everymplib}, \cs{everyendmplib}} +% Since v2.3, new macros \cs{everymplib} and \cs{everyendmplib} redefine % token lists \cs{everymplibtoks} and \cs{everyendmplibtoks} respectively, % which will % be automatically inserted at the beginning and ending of each mplib code. -% \textsc{e.g.} % \begin{verbatim} -% \everymplib{ verbatimtex \leavevmode etex; beginfig(0); } +% \everymplib{ beginfig(0); } % \everyendmplib{ endfig; } -% \mplibcode % beginfig/endfig not needed; always in horizontal mode +% \mplibcode % beginfig/endfig not needed % draw fullcircle scaled 1cm; % \endmplibcode % \end{verbatim} -% \textsc{n.b.} Many users have complained that mplib figures do not -% respect alignment commands such as \cs{centering} or \cs{raggedleft}. -% That's because \textsf{luamplib} does not force horizontal or vertical mode. -% If you want all mplib figures center- (or right-) aligned, please use -% \cs{everymplib} command with \cs{leavevmode} as shown above. -% \item Since v2.3, \cs{mpdim} and other raw \TeX\ commands are allowed +% +% \paragraph{\cs{mpdim}} +% Since v2.3, \cs{mpdim} and other raw \TeX\ commands are allowed % inside mplib code. This feature is inpired by gmp.sty authored by % Enrico Gregorio. Please refer the manual of gmp package for details. -% \textsc{e.g.} % \begin{verbatim} % \begin{mplibcode} % draw origin--(\mpdim{\linewidth},0) withpen pencircle scaled 4 @@ -264,17 +293,24 @@ See source file '\inFileName' for licencing and contact information. % |btex ... etex| as provided by gmp package. As \textsf{luamplib} % automatically protects \TeX\ code inbetween, \cs{btex} is not supported % here. -% \item With \cs{mpcolor} command, color names or expressions of +% +% \paragraph{\cs{mpcolor}} +% With \cs{mpcolor} command, color names or expressions of % \textsf{color}/\textsf{xcolor} packages can be used inside mplibcode % enviroment, though \textsf{luamplib} does not automatically load these % packages. See the example code above. For spot colors, \textsf{(x)spotcolor} % (in PDF mode) and \textsf{xespotcolor} (in DVI mode) packages are supported % as well. -% \item Users can choose |numbersystem| option since v2.4. -% The default value |scaled| can be changed to |double| by declaring -% |\mplibnumbersystem{double}|. For details see +% +% \paragraph{\cs{mplibnumbersystem}} +% Users can choose |numbersystem| option since v2.4. +% The default value |scaled| can be changed to |double| or |decimal| +% by declaring |\mplibnumbersystem{double}| or |\mplibnumbersystem{decimal}|. +% For details see % \url{http://github.com/lualatex/luamplib/issues/21}. -% \item To support |btex ... etex| in external |.mp| files, \textsf{luamplib} +% +% \paragraph{Settings regarding cache files} +% To support |btex ... etex| in external |.mp| files, \textsf{luamplib} % inspects the content of each and every |.mp| input files and makes caches % if nececcsary, before returning their paths to \LuaTeX's mplib library. % This would make the compilation time longer wastefully, as most |.mp| files @@ -288,14 +324,17 @@ See source file '\inFileName' for licencing and contact information. % where || is a file name excluding |.mp| extension. % Note that |.mp| files under |$TEXMFMAIN/metapost/base| and % |$TEXMFMAIN/metapost/context/base| are already registered by default. -% \item By default, cache files will be stored in |$TEXMFVAR/luamplib_cache| -% or, if it's not available, in the same directory as where pdf/dvi output file +% +% By default, cache files will be stored in |$TEXMFVAR/luamplib_cache| or, +% if it's not available, in the same directory as where pdf/dvi output file % is saved. This however can be changed by the command % |\mplibcachedir{}|, where tilde (|~|) is interpreted % as the user's home directory (on a windows machine as well). % As backslashes (|\|) should be escaped by users, it would be easier to use % slashes (|/|) instead. -% \item Starting with v2.6, |\mplibtextextlabel{enable}| enables +% +% \paragraph{\cs{mplibtextextlabel}} +% Starting with v2.6, |\mplibtextextlabel{enable}| enables % string labels typeset via |textext()| instead of |infont| operator. % So, |label("my text",origin)| thereafter is exactly the same as % |label(textext("my text"),origin)|. \textsc{n.b.} In the background, @@ -304,13 +343,15 @@ See source file '\inFileName' for licencing and contact information. % therefore will be typeset with current \TeX\ font. % Also take care of |char| operator in the left side argument, % as this might bring unpermitted characters into \TeX. -% \item Starting with v2.9, |\mplibcodeinherit{enable}| enables the inheritance +% +% \paragraph{\cs{mplibcodeinherit}} +% Starting with v2.9, |\mplibcodeinherit{enable}| enables the inheritance % of variables, constants, and macros defined by previous |mplibcode| chunks. % On the contrary, the default value |\mplibcodeinherit{disable}| will make % each code chunks being treated as an independent instance, and never % affected by previous code chunks. % -% \textsc{n.b.} +% \paragraph{\cs{mplibglobaltextext}} % To inherit |btex ... etex| labels as well as metapost variables, % it is necessary to declare \cs{mplibglobaltextext\{enable\}} in advance. % On this case, be careful that normal \TeX\ boxes can conflict with @@ -331,17 +372,22 @@ See source file '\inFileName' for licencing and contact information. % currentpicture := pic scaled 2; % \endmplibcode % \end{verbatim} -% \item Starting with v2.11, users can issue |\mplibverbatim{enable}|, after which +% +% \paragraph{\cs{mplibverbatim}} +% Starting with v2.11, users can issue |\mplibverbatim{enable}|, after which % the contents of mplibcode environment will be read verbatim. As a result, -% users cannot use |\mpdim|, |\mpcolor| etc. All \TeX\ commands outside of +% users cannot use |\mpdim|, but |\mpcolor| is OK. +% All other \TeX\ commands outside % |btex ... etex| or |verbatimtex ... etex| are not expanded and will be fed % literally into the mplib process. -% \item At the end of package loading, \textsf{luamplib} searches +% +% \paragraph{luamplib.cfg} +% At the end of package loading, \textsf{luamplib} searches % |luamplib.cfg| and, if found, reads the file in automatically. -% Frequently used settings such as \cs{everymplib} or \cs{mplibcachedir} +% Frequently used settings such as \cs{everymplib} or \cs{mplibforcehmode} % are suitable for going into this file. % -% \end{itemize} +% \bigskip % % There are (basically) two formats for metapost: \emph{plain} and % \emph{metafun}. By default, the \emph{plain} format is used, but you can set @@ -355,46 +401,38 @@ See source file '\inFileName' for licencing and contact information. % \iffalse %<*lua> % \fi -% Use the |luamplib| namespace, since |mplib| is for the metapost library -% itself. \ConTeXt{} uses |metapost|. % % \begin{macrocode} -luamplib = luamplib or { } +luatexbase.provides_module { + name = "luamplib", + version = "2.20.0", + date = "2019/03/20", + description = "Lua package to typeset Metapost with LuaTeX's MPLib.", +} + +local format, abs = string.format, math.abs + +local err = function(...) return luatexbase.module_error ("luamplib", format(...)) end +local warn = function(...) return luatexbase.module_warning("luamplib", format(...)) end +local info = function(...) return luatexbase.module_info ("luamplib", format(...)) end % \end{macrocode} -% Identification. % +% Use the |luamplib| namespace, since |mplib| is for the metapost library +% itself. \ConTeXt{} uses |metapost|. % \begin{macrocode} - +luamplib = luamplib or { } local luamplib = luamplib + luamplib.showlog = luamplib.showlog or false luamplib.lastlog = "" -luatexbase.provides_module { - name = "luamplib", - version = "2.12.5", - date = "2018/09/27", - description = "Lua package to typeset Metapost with LuaTeX's MPLib.", -} - % \end{macrocode} +% % This module is a stripped down version of libraries that are used by % \ConTeXt. Provide a few ``shortcuts'' expected by the imported code. -% % \begin{macrocode} - -local format, abs = string.format, math.abs - -local err = function(...) return luatexbase.module_error ("luamplib", format(...)) end -local warn = function(...) return luatexbase.module_warning("luamplib", format(...)) end -local info = function(...) return luatexbase.module_info ("luamplib", format(...)) end - -local stringgsub = string.gsub -local stringfind = string.find -local stringmatch = string.match -local stringgmatch = string.gmatch -local stringexplode = string.explode local tableconcat = table.concat local texsprint = tex.sprint local textprint = tex.tprint @@ -402,6 +440,12 @@ local textprint = tex.tprint local texget = tex.get local texgettoks = tex.gettoks local texgetbox = tex.getbox +local texruntoks = tex.runtoks +local texscantoks = tex.scantoks + +if not texruntoks then + err("Your LuaTeX version is too old. Please upgrade it to the latest") +end local mplib = require ('mplib') local kpse = require ('kpse') @@ -413,25 +457,19 @@ local lfsmkdir = lfs.mkdir local lfstouch = lfs.touch local ioopen = io.open -local file = file or { } % \end{macrocode} -% This is a small trick for \LaTeX . In \LaTeX\ we read the metapost code -% line by line, but it needs to be passed entirely to |process()|, so we -% simply add the lines in |data| and at the end we call |process(data)|. -% -% A few helpers, taken from |l-file.lua|. % +% Some helper functions, prepared for the case when |l-file| etc +% is not loaded. % \begin{macrocode} +local file = file or { } local replacesuffix = file.replacesuffix or function(filename, suffix) - return (stringgsub(filename,"%.[%a%d]+$","")) .. "." .. suffix + return (filename:gsub("%.[%a%d]+$","")) .. "." .. suffix end local stripsuffix = file.stripsuffix or function(filename) - return (stringgsub(filename,"%.[%a%d]+$","")) + return (filename:gsub("%.[%a%d]+$","")) end -% \end{macrocode} -% |btex ... etex| in input .mp files will be replaced in finder. -% \begin{macrocode} local is_writable = file.is_writable or function(name) if lfsisdir(name) then name = name .. "/_luam_plib_temp_file_" @@ -444,12 +482,18 @@ local is_writable = file.is_writable or function(name) end local mk_full_path = lfs.mkdirs or function(path) local full = "" - for sub in stringgmatch(path,"(/*[^\\/]+)") do + for sub in path:gmatch("(/*[^\\/]+)") do full = full .. sub lfsmkdir(full) end end +% \end{macrocode} +% +% |btex ... etex| in input |.mp| files will be replaced in finder. +% Because of the limitation of MPLib regarding |make_text|, +% we might have to make cache files modified from input files. +% \begin{macrocode} local luamplibtime = kpse.find_file("luamplib.lua") luamplibtime = luamplibtime and lfsattributes(luamplibtime,"modification") @@ -459,7 +503,7 @@ local outputdir if lfstouch then local texmfvar = kpse.expand_var('$TEXMFVAR') if texmfvar and texmfvar ~= "" and texmfvar ~= '$TEXMFVAR' then - for _,dir in next,stringexplode(texmfvar,os.type == "windows" and ";" or ":") do + for _,dir in next, texmfvar:explode(os.type == "windows" and ";" or ":") do if not lfsisdir(dir) then mk_full_path(dir) end @@ -475,7 +519,7 @@ end if not outputdir then outputdir = "." for _,v in ipairs(arg) do - local t = stringmatch(v,"%-output%-directory=(.+)") + local t = v:match("%-output%-directory=(.+)") if t then outputdir = t break @@ -500,48 +544,32 @@ function luamplib.getcachedir(dir) end end +% \end{macrocode} +% +% Some basic MetaPost files not necessary to make cache files. +% \begin{macrocode} local noneedtoreplace = { - ["boxes.mp"] = true, - -- ["format.mp"] = true, - ["graph.mp"] = true, - ["marith.mp"] = true, - ["mfplain.mp"] = true, - ["mpost.mp"] = true, - ["plain.mp"] = true, - ["rboxes.mp"] = true, - ["sarith.mp"] = true, - ["string.mp"] = true, - ["TEX.mp"] = true, - ["metafun.mp"] = true, - ["metafun.mpiv"] = true, - ["mp-abck.mpiv"] = true, - ["mp-apos.mpiv"] = true, - ["mp-asnc.mpiv"] = true, - ["mp-bare.mpiv"] = true, - ["mp-base.mpiv"] = true, - ["mp-butt.mpiv"] = true, - ["mp-char.mpiv"] = true, - ["mp-chem.mpiv"] = true, - ["mp-core.mpiv"] = true, - ["mp-crop.mpiv"] = true, - ["mp-figs.mpiv"] = true, - ["mp-form.mpiv"] = true, - ["mp-func.mpiv"] = true, - ["mp-grap.mpiv"] = true, - ["mp-grid.mpiv"] = true, - ["mp-grph.mpiv"] = true, - ["mp-idea.mpiv"] = true, - ["mp-luas.mpiv"] = true, - ["mp-mlib.mpiv"] = true, - ["mp-node.mpiv"] = true, - ["mp-page.mpiv"] = true, - ["mp-shap.mpiv"] = true, - ["mp-step.mpiv"] = true, - ["mp-text.mpiv"] = true, + ["boxes.mp"] = true, -- ["format.mp"] = true, + ["graph.mp"] = true, ["marith.mp"] = true, ["mfplain.mp"] = true, + ["mpost.mp"] = true, ["plain.mp"] = true, ["rboxes.mp"] = true, + ["sarith.mp"] = true, ["string.mp"] = true, -- ["TEX.mp"] = true, + ["metafun.mp"] = true, ["metafun.mpiv"] = true, ["mp-abck.mpiv"] = true, + ["mp-apos.mpiv"] = true, ["mp-asnc.mpiv"] = true, ["mp-bare.mpiv"] = true, + ["mp-base.mpiv"] = true, ["mp-blob.mpiv"] = true, ["mp-butt.mpiv"] = true, + ["mp-char.mpiv"] = true, ["mp-chem.mpiv"] = true, ["mp-core.mpiv"] = true, + ["mp-crop.mpiv"] = true, ["mp-figs.mpiv"] = true, ["mp-form.mpiv"] = true, + ["mp-func.mpiv"] = true, ["mp-grap.mpiv"] = true, ["mp-grid.mpiv"] = true, + ["mp-grph.mpiv"] = true, ["mp-idea.mpiv"] = true, ["mp-luas.mpiv"] = true, + ["mp-mlib.mpiv"] = true, ["mp-node.mpiv"] = true, ["mp-page.mpiv"] = true, + ["mp-shap.mpiv"] = true, ["mp-step.mpiv"] = true, ["mp-text.mpiv"] = true, ["mp-tool.mpiv"] = true, } luamplib.noneedtoreplace = noneedtoreplace +% \end{macrocode} +% +% |format.mp| is much complicated, so specially treated. +% \begin{macrocode} local function replaceformatmp(file,newfile,ofmodify) local fh = ioopen(file,"r") if not fh then return file end @@ -560,25 +588,15 @@ local function replaceformatmp(file,newfile,ofmodify) return newfile end -local esctex = "!!!T!!!E!!!X!!!" -local esclbr = "!!!!!LEFTBRCE!!!!!" -local escrbr = "!!!!!RGHTBRCE!!!!!" -local escpcnt = "!!!!!PERCENT!!!!!" -local eschash = "!!!!!HASH!!!!!" -local begname = "%f[A-Z_a-z]" -local endname = "%f[^A-Z_a-z]" - -local btex_etex = begname.."btex"..endname.."%s*(.-)%s*"..begname.."etex"..endname -local verbatimtex_etex = begname.."verbatimtex"..endname.."%s*(.-)%s*"..begname.."etex"..endname - -local function protecttexcontents(str) - return str:gsub("\\%%", "\\"..escpcnt) - :gsub("%%.-\n", "") - :gsub("%%.-$", "") - :gsub('"', '"&ditto&"') - :gsub("\n%s*", " ") - :gsub(escpcnt, "%%") -end +% \end{macrocode} +% +% Replace |btex ... etex| and |verbatimtex ... etex| in input files, +% if needed. +% \begin{macrocode} +local name_b = "%f[A-Z_a-z]" +local name_e = "%f[^A-Z_a-z]" +local btex_etex = name_b.."btex"..name_e.."%s*(.-)%s*"..name_b.."etex"..name_e +local verbatimtex_etex = name_b.."verbatimtex"..name_e.."%s*(.-)%s*"..name_b.."etex"..name_e local function replaceinputmpfile (name,file) local ofmodify = lfsattributes(file,"modification") @@ -588,33 +606,29 @@ local function replaceinputmpfile (name,file) newfile = cachedir .."/luamplib_input_"..newfile if newfile and luamplibtime then local nf = lfsattributes(newfile) - if nf and nf.mode == "file" and ofmodify == nf.modification and luamplibtime < nf.access then + if nf and nf.mode == "file" and + ofmodify == nf.modification and luamplibtime < nf.access then return nf.size == 0 and file or newfile end end + if name == "format.mp" then return replaceformatmp(file,newfile,ofmodify) end local fh = ioopen(file,"r") if not fh then return file end local data = fh:read("*all"); fh:close() +% \end{macrocode} +% +% ``|etex|'' must be followed by a space or semicolon as specified in +% \LuaTeX\ manual, which is not the case of standalone MetaPost though. +% \begin{macrocode} local count,cnt = 0,0 - - data = data:gsub("\"[^\n]-\"", function(str) - return str:gsub("([bem])tex"..endname,"%1"..esctex) - end) - - data, cnt = data:gsub(btex_etex, function(str) - return format("rawtextext(\"%s\")",protecttexcontents(str)) - end) + data, cnt = data:gsub(btex_etex, "btex %1 etex ") -- space count = count + cnt - data, cnt = data:gsub(verbatimtex_etex, "") + data, cnt = data:gsub(verbatimtex_etex, "verbatimtex %1 etex;") -- semicolon count = count + cnt - data = data:gsub("\"[^\n]-\"", function(str) -- restore string btex .. etex - return str:gsub("([bem])"..esctex, "%1tex") - end) - if count == 0 then noneedtoreplace[name] = true fh = ioopen(newfile,"w"); @@ -624,6 +638,7 @@ local function replaceinputmpfile (name,file) end return file end + fh = ioopen(newfile,"w") if not fh then return file end fh:write(data); fh:close() @@ -631,14 +646,12 @@ local function replaceinputmpfile (name,file) return newfile end -local randomseed = nil % \end{macrocode} -% As the finder function for |mplib|, use the |kpse| library and -% make it behave like as if MetaPost was used (or almost, since the engine -% name is not set this way---not sure if this is a problem). % +% As the finder function for MPLib, use the |kpse| library and +% make it behave like as if MetaPost was used. And replace it with +% cache files if needed. % \begin{macrocode} - local mpkpse = kpse.new(arg[0], "mpost") local special_ftype = { @@ -658,193 +671,583 @@ local function finder(name, mode, ftype) end return replaceinputmpfile(name,file) end - return mpkpse:find_file(name,stringmatch(name,"[a-zA-Z]+$")) + return mpkpse:find_file(name, name:match("[a-zA-Z]+$")) end end luamplib.finder = finder % \end{macrocode} -% The rest of this module is not documented. More info can be found in the -% \LuaTeX{} manual, articles in user group journals and the files that -% ship with \ConTeXt. % +% Create and load MPLib instances. +% We do not support ancient version of MPLib any more. +% (Don't know which version of MPLib started to support +% |make_text| and |run_script|; let the users find it.) % \begin{macrocode} +if tonumber(mplib.version()) <= 1.50 then + err("luamplib no longer supports mplib v1.50 or lower. ".. + "Please upgrade to the latest version of LuaTeX") +end -function luamplib.resetlastlog() +local preamble = [[ + boolean mplib ; mplib := true ; + let dump = endinput ; + let normalfontsize = fontsize; + input %s ; +]] + +local function luamplibresetlastlog() luamplib.lastlog = "" end +local function reporterror (result) + if not result then + err("no result object returned") + else + local t, e, l = result.term, result.error, result.log + local log = t or l or "no-term" + log = log:gsub("^%s+","\n") + luamplib.lastlog = luamplib.lastlog .. "\n" .. (l or t or "no-log") + if result.status > 0 then + warn("%s",log) + if result.status > 1 then + err("%s",e or "see above messages") + end + end + return log + end +end + +local function luamplibload (name) + local mpx = mplib.new { + ini_version = true, + find_file = luamplib.finder, +% \end{macrocode} +% +% Make use of |make_text| and |run_script|, which will co-operate +% with \LuaTeX's |tex.runtoks|. And we +% provide |numbersystem| option since v2.4. Default value ``|scaled|'' +% can be changed by declaring |\mplibnumbersystem{double}| +% or |\mplibnumbersystem{decimal}|. +% See \url{https://github.com/lualatex/luamplib/issues/21}. +% \begin{macrocode} + make_text = luamplib.maketext, + run_script = luamplib.runscript, + math_mode = luamplib.numbersystem, + extensions = 1, + } +% \end{macrocode} +% +% Append our own MetaPost preamble to the preamble above. +% \begin{macrocode} + local preamble = preamble .. luamplib.mplibcodepreamble + if luamplib.legacy_verbatimtex then + preamble = preamble .. luamplib.legacyverbatimtexpreamble + end + if luamplib.textextlabel then + preamble = preamble .. luamplib.textextlabelpreamble + end + local result + if not mpx then + result = { status = 99, error = "out of memory"} + else + result = mpx:execute(format(preamble, replacesuffix(name,"mp"))) + end + reporterror(result) + return mpx, result +end + % \end{macrocode} -% Below included is section that defines fallbacks for older -% versions of mplib. % +% |plain| or |metafun|, +% though we cannot support |metafun| format fully. % \begin{macrocode} -local mplibone = tonumber(mplib.version()) <= 1.50 +local currentformat = "plain" -if mplibone then +local function setformat (name) + currentformat = name +end +luamplib.setformat = setformat - luamplib.make = luamplib.make or function(name,mem_name,dump) - local t = os.clock() - local mpx = mplib.new { - ini_version = true, - find_file = luamplib.finder, - job_name = stripsuffix(name) - } - mpx:execute(format("input %s ;",name)) - if dump then - mpx:execute("dump ;") - info("format %s made and dumped for %s in %0.3f seconds",mem_name,name,os.clock()-t) - else - info("%s read in %0.3f seconds",name,os.clock()-t) +% \end{macrocode} +% +% Here, excute each |mplibcode| data, +% ie |\begin{mplibcode} ... \end{mplibcode}|. +% \begin{macrocode} +local function process_indeed (mpx, data) + local converted, result = false, {} + if mpx and data then + result = mpx:execute(data) + local log = reporterror(result) + if log then + if luamplib.showlog then + info("%s",luamplib.lastlog) + luamplibresetlastlog() + elseif result.fig then +% \end{macrocode} +% +% v2.6.1: now luamplib does not disregard |show| command, +% even when |luamplib.showlog| is false. Incidentally, +% it does not raise error but just prints a warning, +% even if output has no figure. +% \begin{macrocode} + if log:find("\n>>") then info("%s",log) end + converted = luamplib.convert(result) + else + info("%s",log) + warn("No figure output. Maybe no beginfig/endfig") + end end - return mpx + else + err("Mem file unloadable. Maybe generated with a different version of mplib?") end + return converted, result +end - function luamplib.load(name) - local mem_name = replacesuffix(name,"mem") - local mpx = mplib.new { - ini_version = false, - mem_name = mem_name, - find_file = luamplib.finder - } - if not mpx and type(luamplib.make) == "function" then - -- when i have time i'll locate the format and dump - mpx = luamplib.make(name,mem_name) - end - if mpx then - info("using format %s",mem_name,false) - return mpx, nil - else - return nil, { status = 99, error = "out of memory or invalid format" } - end +% \end{macrocode} +% +% v2.9 has introduced the concept of ``code inherit'' +% \begin{macrocode} +luamplib.codeinherit = false +local mplibinstances = {} + +local function process (data) +% \end{macrocode} +% +% Workaround issue \#70 +% \begin{macrocode} + if not data:find(name_b.."beginfig%s*%([%+%-%s]*%d[%.%d%s]*%)") then + data = data .. "beginfig(-1);endfig;" + end + local standalone = not luamplib.codeinherit + local currfmt = currentformat .. (luamplib.numbersystem or "scaled") + .. tostring(luamplib.textextlabel) .. tostring(luamplib.legacy_verbatimtex) + local mpx = mplibinstances[currfmt] + if mpx and standalone then + mpx:finish() end + if standalone or not mpx then + mpx = luamplibload(currentformat) + mplibinstances[currfmt] = mpx + end + return process_indeed(mpx, data) +end -else +% \end{macrocode} +% +% |make_text| and some |run_script| uses \LuaTeX's |tex.runtoks|, +% which made possible running \TeX\ code snippets inside |\directlua|. +% \begin{macrocode} +local catlatex = luatexbase.registernumber("catcodetable@latex") +local catat11 = luatexbase.registernumber("catcodetable@atletter") % \end{macrocode} -% These are the versions called with sufficiently recent mplib. % +% |tex.scantoks| sometimes fail to read catcode properly, especially +% |\#|, |\&|, or |\%|. After some experiment, we dropped using it. +% Instead, a function containing |tex.script| seems to work nicely. % \begin{macrocode} - local preamble = [[ - boolean mplib ; mplib := true ; - let dump = endinput ; - let normalfontsize = fontsize; - input %s ; - ]] +local function run_tex_code_no_use (str, cat) + cat = cat or catlatex + texscantoks("mplibtmptoks", cat, str) + texruntoks("mplibtmptoks") +end - luamplib.make = luamplib.make or function() - end +local function run_tex_code (str, cat) + cat = cat or catlatex + texruntoks(function() texsprint(cat, str) end) +end - function luamplib.load(name,verbatim) - local mpx = mplib.new { - ini_version = true, - find_file = luamplib.finder, % \end{macrocode} -% Provides |numbersystem| option since v2.4. Default value |"scaled"| -% can be changed by declaring |\mplibnumbersystem{double}|. -% See \url{https://github.com/lualatex/luamplib/issues/21}. +% +% Indefinite number of boxes are needed for |btex ... etex|. +% So starts at somewhat huge number of box registry. Of course, +% this may conflict with other packages using many many boxes. +% (When |codeinherit| feature is enabled, boxes must be globally defined.) +% But I don't know any reliable way to escape this danger. % \begin{macrocode} - math_mode = luamplib.numbersystem, - random_seed = randomseed, - } +local tex_box_id = 2047 % \end{macrocode} -% Append our own preamble to the preamble above. +% +% For conversion of |sp| to |bp|. % \begin{macrocode} - local preamble = preamble .. (verbatim and "" or luamplib.mplibcodepreamble) - if luamplib.textextlabel then - preamble = preamble .. (verbatim and "" or luamplib.textextlabelpreamble) - end - local result - if not mpx then - result = { status = 99, error = "out of memory"} - else - result = mpx:execute(format(preamble, replacesuffix(name,"mp"))) +local factor = 65536*(7227/7200) + +local function process_tex_text (str) + if str then + tex_box_id = tex_box_id + 1 + local global = luamplib.globaltextext and "\\global" or "" + run_tex_code(format("%s\\setbox%i\\hbox{%s}", global, tex_box_id, str)) + local box = texgetbox(tex_box_id) + local wd = box.width / factor + local ht = box.height / factor + local dp = box.depth / factor + return format("image(addto currentpicture doublepath unitsquare ".. + "xscaled %f yscaled %f shifted (0,-%f) ".. + "withprescript \"mplibtexboxid=%i:%f:%f\")", + wd, ht+dp, dp, tex_box_id, wd, ht+dp) + end + return "" +end + +% \end{macrocode} +% +% Make |color| or |xcolor|'s color expressions usable, +% with \cs{mpcolor} or |mplibcolor| +% \begin{macrocode} +local function process_color (str) + if str then + if not str:find("{.-}") then + str = format("{%s}",str) end - luamplib.reporterror(result) - return mpx, result + run_tex_code(format( + "\\def\\set@color{\\toks0\\expandafter{\\current@color}}\\color %s", str), + catat11) + return format("1 withprescript \"MPlibOverrideColor=%s\"", texgettoks(0)) + end + return "" +end + +% \end{macrocode} +% +% \cs{mpdim} is expanded before MPLib process, so code below will not be +% used for |mplibcode| data. But who knows anyone would want it +% in |.mp| input file. If then, you can say |mplibdimen(".5\textwidth")| +% for example. +% \begin{macrocode} +local function process_dimen (str) + if str then + str = str:gsub("{(.+)}","%1") + run_tex_code(format("\\toks0\\expandafter{\\the\\dimexpr %s\\relax}", str)) + return format("begingroup %s endgroup", texgettoks(0)) end + return "" +end +% \end{macrocode} +% +% Newly introduced method of processing |verbatimtex ... etex|. +% Used when |\mpliblegacybehavior{false}| is declared. +% \begin{macrocode} +local function process_verbatimtex_text (str) + if str then + run_tex_code(str) + end + return "" end -local currentformat = "plain" +% \end{macrocode} +% +% For legacy verbatimtex process. +% |verbatimtex ... etex| before |beginfig()| is not ignored, +% but the \TeX\ code is inserted just before the mplib box. And +% \TeX\ code inside |beginfig() ... endfig| is inserted after the mplib box. +% \begin{macrocode} +local tex_code_pre_mplib = {} +luamplib.figid = 1 +luamplib.in_the_fig = false -local function setformat (name) --- used in .sty - currentformat = name +local function legacy_mplibcode_reset () + tex_code_pre_mplib = {} + luamplib.figid = 1 end -luamplib.setformat = setformat +local function process_verbatimtex_prefig (str) + if str then + tex_code_pre_mplib[luamplib.figid] = str + end + return "" +end -luamplib.reporterror = function (result) - if not result then - err("no result object returned") - else - local t, e, l = result.term, result.error, result.log - local log = stringgsub(t or l or "no-term","^%s+","\n") - luamplib.lastlog = luamplib.lastlog .. "\n " .. (l or t or "no-log") - if result.status > 0 then - warn("%s",log) - if result.status > 1 then - err("%s",e or "see above messages") +local function process_verbatimtex_infig (str) + if str then + return format("special \"postmplibverbtex=%s\";", str) + end + return "" +end + +local runscript_funcs = { + luamplibtext = process_tex_text, + luamplibcolor = process_color, + luamplibdimen = process_dimen, + luamplibprefig = process_verbatimtex_prefig, + luamplibinfig = process_verbatimtex_infig, + luamplibverbtex = process_verbatimtex_text, +} + +% \end{macrocode} +% +% As of 2019-03, |metafun| format is not usable (issue \#79). +% This might workarounds the problem. +% \begin{macrocode} +mp = mp or {} +local mp = mp +mp.mf_path_reset = mp.mf_path_reset or function() end +mp.mf_finish_saving_data = mp.mf_finish_saving_data or function() end +LUATEXFUNCTIONALITY = LUATEXFUNCTIONALITY or 0 + +% \end{macrocode} +% +% A function from \ConTeXt\ general. +% \begin{macrocode} +local function mpprint(buffer,...) + for i=1,select("#",...) do + local value = select(i,...) + if value ~= nil then + local t = type(value) + if t == "number" then + buffer[#buffer+1] = format("%.16f",value) + elseif t == "string" then + buffer[#buffer+1] = value + elseif t == "table" then + buffer[#buffer+1] = "(" .. concat(value,",") .. ")" + else -- boolean or whatever + buffer[#buffer+1] = tostring(value) end end - return log end end -local function process_indeed (mpx, data, indeed) - local converted, result = false, {} - if mpx and data then - result = mpx:execute(data) - local log = luamplib.reporterror(result) - if indeed and log then - if luamplib.showlog then - info("%s",luamplib.lastlog) - luamplib.resetlastlog() - elseif result.fig then +function luamplib.runscript (code) + local id, str = code:match("(.-){(.+)}") + if id and str and str ~= "" then + local f = runscript_funcs[id] + if f then + local t = f(str) + if t then return t end + end + end + local f = loadstring(code) + if type(f) == "function" then + local buffer = {} + function mp.print(...) + mpprint(buffer,...) + end + f() + return tableconcat(buffer,"") + end + return "" +end + +% \end{macrocode} +% +% |make_text| must be one liner, so comment sign is not allowed. +% \begin{macrocode} +local function protecttexcontents (str) + return str:gsub("\\%%", "\0PerCent\0") + :gsub("%%.-\n", "") + :gsub("%%.-$", "") + :gsub("%zPerCent%z", "\\%%") + :gsub("%s+", " ") +end + +luamplib.legacy_verbatimtex = true + +function luamplib.maketext (str, what) + if str and str ~= "" then + str = protecttexcontents(str) + if what == 1 then + if not str:find("\\documentclass"..name_e) and + not str:find("\\begin%s*{document}") and + not str:find("\\documentstyle"..name_e) and + not str:find("\\usepackage"..name_e) then + if luamplib.legacy_verbatimtex then + if luamplib.in_the_fig then + return process_verbatimtex_infig(str) + else + return process_verbatimtex_prefig(str) + end + else + return process_verbatimtex_text(str) + end + end + else + return process_tex_text(str) + end + end + return "" +end + +% \end{macrocode} +% +% Our MetaPost preambles +% \begin{macrocode} +local mplibcodepreamble = [[ +texscriptmode := 2; +def rawtextext (expr t) = runscript("luamplibtext{"&t&"}") enddef; +def mplibcolor (expr t) = runscript("luamplibcolor{"&t&"}") enddef; +def mplibdimen (expr t) = runscript("luamplibdimen{"&t&"}") enddef; +def VerbatimTeX (expr t) = runscript("luamplibverbtex{"&t&"}") enddef; +if known context_mlib: + defaultfont := "cmtt10"; + let infont = normalinfont; + let fontsize = normalfontsize; + vardef thelabel@#(expr p,z) = + if string p : + thelabel@#(p infont defaultfont scaled defaultscale,z) + else : + p shifted (z + labeloffset*mfun_laboff@# - + (mfun_labxf@#*lrcorner p + mfun_labyf@#*ulcorner p + + (1-mfun_labxf@#-mfun_labyf@#)*llcorner p)) + fi + enddef; + def graphictext primary filename = + if (readfrom filename = EOF): + errmessage "Please prepare '"&filename&"' in advance with"& + " 'pstoedit -ssp -dt -f mpost yourfile.ps "&filename&"'"; + fi + closefrom filename; + def data_mpy_file = filename enddef; + mfun_do_graphic_text (filename) + enddef; +else: + vardef textext@# (text t) = rawtextext (t) enddef; +fi +def externalfigure primary filename = + draw rawtextext("\includegraphics{"& filename &"}") +enddef; +def TEX = textext enddef; +]] +luamplib.mplibcodepreamble = mplibcodepreamble + +local legacyverbatimtexpreamble = [[ +def specialVerbatimTeX (text t) = runscript("luamplibprefig{"&t&"}") enddef; +def normalVerbatimTeX (text t) = runscript("luamplibinfig{"&t&"}") enddef; +let VerbatimTeX = specialVerbatimTeX; +extra_beginfig := extra_beginfig & " let VerbatimTeX = normalVerbatimTeX;"& + "runscript(" &ditto& "luamplib.in_the_fig=true" &ditto& ");"; +extra_endfig := extra_endfig & " let VerbatimTeX = specialVerbatimTeX;"& + "runscript(" &ditto& + "luamplib.in_the_fig=false luamplib.figid=luamplib.figid+1" &ditto& ");"; +]] +luamplib.legacyverbatimtexpreamble = legacyverbatimtexpreamble + +local textextlabelpreamble = [[ +primarydef s infont f = rawtextext(s) enddef; +def fontsize expr f = + begingroup + save size,pic; numeric size; picture pic; + pic := rawtextext("\hskip\pdffontsize\font"); + size := xpart urcorner pic - xpart llcorner pic; + if size = 0: 10pt else: size fi + endgroup +enddef; +]] +luamplib.textextlabelpreamble = textextlabelpreamble + +% \end{macrocode} +% +% When \cs{mplibverbatim} is enabled, do not expand |mplibcode| data. +% \begin{macrocode} +luamplib.verbatiminput = false + +% \end{macrocode} +% +% Do not expand |btex ... etex|, |verbatimtex ... etex|, and +% string expressions. +% \begin{macrocode} +local function protect_expansion (str) + if str then + str = str:gsub("\\","\1Control\1") + :gsub("%%","\1Comment\1") + :gsub("#", "\1HashSign\1") + :gsub("{", "\1LBrace\1") + :gsub("}", "\1RBrace\1") + return format("\\unexpanded{%s}",str) + end +end + +local function unprotect_expansion (str) + if str then + return str:gsub("\1Control\1", "\\") + :gsub("\1Comment\1", "%%") + :gsub("\1HashSign\1","#") + :gsub("\1LBrace\1", "{") + :gsub("\1RBrace\1", "}") + end +end + +local function process_mplibcode (data) +% \end{macrocode} +% +% This is needed for legacy behavior regarding |verbatimtex| +% \begin{macrocode} + legacy_mplibcode_reset() + + local everymplib = texgettoks('everymplibtoks') or '' + local everyendmplib = texgettoks('everyendmplibtoks') or '' + data = format("\n%s\n%s\n%s\n",everymplib, data, everyendmplib) + data = data:gsub("\r","\n") + + data = data:gsub("\\mpcolor%s+(.-%b{})","mplibcolor(\"%1\")") + + data = data:gsub(btex_etex, function(str) + return format("btex %s etex ", -- space + luamplib.verbatiminput and str or protect_expansion(str)) + end) + data = data:gsub(verbatimtex_etex, function(str) + return format("verbatimtex %s etex;", -- semicolon + luamplib.verbatiminput and str or protect_expansion(str)) + end) + +% \end{macrocode} +% +% If not |mplibverbatim|, expand |mplibcode| data, +% so that users can use \TeX\ codes in it. +% It has turned out that no comment sign is allowed. +% \begin{macrocode} + if not luamplib.verbatiminput then + data = data:gsub("\".-\"", protect_expansion) + data = data:gsub("%%.-\n","") + run_tex_code(format("\\toks0\\expanded{{%s}}",data)) + data = texgettoks(0) +% \end{macrocode} +% +% Next line to address issue \#55 +% \begin{macrocode} + data = data:gsub("##", "#") + data = data:gsub("\".-\"", unprotect_expansion) + data = data:gsub(btex_etex, function(str) + return format("btex %s etex", unprotect_expansion(str)) + end) + data = data:gsub(verbatimtex_etex, function(str) + return format("verbatimtex %s etex", unprotect_expansion(str)) + end) + end + + process(data) +end +luamplib.process_mplibcode = process_mplibcode + % \end{macrocode} -% v2.6.1: now luamplib does not disregard |show| command, -% even when |luamplib.showlog| is false. Incidentally, -% it does not raise error, but just prints a warning, -% even if output has no figure. +% +% For parsing |prescript| materials. % \begin{macrocode} - if stringfind(log,"\n>>") then info("%s",log) end - converted = luamplib.convert(result) +local further_split_keys = { + ["mplibtexboxid"] = true, + ["sh_color_a"] = true, + ["sh_color_b"] = true, +} + +local function script2table(s) + local t = {} + for _,i in ipairs(s:explode("\13+")) do + local k,v = i:match("(.-)=(.*)") -- v may contain = or empty. + if k and v and k ~= "" then + if further_split_keys[k] then + t[k] = v:explode(":") else - info("%s",log) - warn("No figure output. Maybe no beginfig/endfig") + t[k] = v end end - else - err("Mem file unloadable. Maybe generated with a different version of mplib?") end - return converted, result + return t end % \end{macrocode} -% v2.9 has introduced the concept of `code inherit' -% \begin{macrocode} -luamplib.codeinherit = false -local mplibinstances = {} -local process = function (data,indeed,verbatim) -% \end{macrocode} -% workaround issue \#70 +% +% Codes below for inserting PDF lieterals are mostly from ConTeXt general, +% with small changes when needed. % \begin{macrocode} - if not stringfind(data, begname.."beginfig%s*%([%+%-%s]*%d[%.%d%s]*%)") then - data = data .. "beginfig(-1);endfig;" - end - local standalone, firstpass = not luamplib.codeinherit, not indeed - local currfmt = currentformat .. (luamplib.numbersystem or "scaled") - currfmt = firstpass and currfmt or (currfmt.."2") - local mpx = mplibinstances[currfmt] - if standalone or not mpx then - randomseed = firstpass and math.random(65535) or randomseed - mpx = luamplib.load(currentformat,verbatim) - mplibinstances[currfmt] = mpx - end - return process_indeed(mpx, data, indeed) -end -luamplib.process = process - local function getobjects(result,figure,f) return figure:objects() end @@ -856,9 +1259,6 @@ end luamplib.convert = convert local function pdf_startfigure(n,llx,lly,urx,ury) -% \end{macrocode} -% The following line has been slightly modified by Kim. -% \begin{macrocode} texsprint(format("\\mplibstarttoPDF{%f}{%f}{%f}{%f}",llx,lly,urx,ury)) end @@ -867,25 +1267,20 @@ local function pdf_stopfigure() end % \end{macrocode} -% |tex.tprint| and catcode regime -2, as sometimes |#| gets doubled -% in the argument of pdfliteral. --- modified by Kim +% +% |tex.tprint| with catcode regime -2, as sometimes |#| gets doubled +% in the argument of pdfliteral. % \begin{macrocode} local function pdf_literalcode(fmt,...) -- table textprint({"\\mplibtoPDF{"},{-2,format(fmt,...)},{"}"}) end -luamplib.pdf_literalcode = pdf_literalcode local function pdf_textfigure(font,size,text,width,height,depth) -% \end{macrocode} -% The following three lines have been modified by Kim. -% \begin{macrocode} - -- if text == "" then text = "\0" end -- char(0) has gone text = text:gsub(".",function(c) return format("\\hbox{\\char%i}",string.byte(c)) -- kerning happens in metapost end) texsprint(format("\\mplibtextext{%s}{%f}{%s}{%s}{%f}",font,size,text,0,-( 7200/ 7227)/65536*depth)) end -luamplib.pdf_textfigure = pdf_textfigure local bend_tolerance = 131/65536 @@ -933,8 +1328,7 @@ local function flushnormalpath(path,open) else pdf_literalcode("%f %f l",one.x_coord,one.y_coord) end - elseif #path == 1 then - -- special case .. draw point + elseif #path == 1 then -- special case .. draw point local one = path[1] pdf_literalcode("%f %f l",one.x_coord,one.y_coord) end @@ -965,261 +1359,16 @@ local function flushconcatpath(path,open) else pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord)) end - elseif #path == 1 then - -- special case .. draw point + elseif #path == 1 then -- special case .. draw point local one = path[1] pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord)) end end % \end{macrocode} -% Below code has been contributed by Dohyun Kim. -% It implements |btex| / |etex| functions. -% -% v2.1: |textext()| is now available, which is equivalent to |TEX()| macro from TEX.mp. -% |TEX()| is synonym of |textext()| unless TEX.mp is loaded. % -% v2.2: Transparency and Shading -% -% v2.3: \cs{everymplib}, \cs{everyendmplib}, -% and allows naked \TeX\ commands. -% \begin{macrocode} -local further_split_keys = { - ["MPlibTEXboxID"] = true, - ["sh_color_a"] = true, - ["sh_color_b"] = true, -} - -local function script2table(s) - local t = {} - for _,i in ipairs(stringexplode(s,"\13+")) do - local k,v = stringmatch(i,"(.-)=(.*)") -- v may contain = or empty. - if k and v and k ~= "" then - if further_split_keys[k] then - t[k] = stringexplode(v,":") - else - t[k] = v - end - end - end - return t -end - -local mplibcodepreamble = [[ -vardef rawtextext (expr t) = - if unknown TEXBOX_: - image( special "MPlibmkTEXbox="&t; - addto currentpicture doublepath unitsquare; ) - else: - TEXBOX_ := TEXBOX_ + 1; - if known TEXBOX_wd_[TEXBOX_]: - image ( addto currentpicture doublepath unitsquare - xscaled TEXBOX_wd_[TEXBOX_] - yscaled (TEXBOX_ht_[TEXBOX_] + TEXBOX_dp_[TEXBOX_]) - shifted (0, -TEXBOX_dp_[TEXBOX_]) - withprescript "MPlibTEXboxID=" & - decimal TEXBOX_ & ":" & - decimal TEXBOX_wd_[TEXBOX_] & ":" & - decimal(TEXBOX_ht_[TEXBOX_]+TEXBOX_dp_[TEXBOX_]); ) - else: - image( special "MPlibTEXError=1"; ) - fi - fi -enddef; -if known context_mlib: - defaultfont := "cmtt10"; - let infont = normalinfont; - let fontsize = normalfontsize; - vardef thelabel@#(expr p,z) = - if string p : - thelabel@#(p infont defaultfont scaled defaultscale,z) - else : - p shifted (z + labeloffset*mfun_laboff@# - - (mfun_labxf@#*lrcorner p + mfun_labyf@#*ulcorner p + - (1-mfun_labxf@#-mfun_labyf@#)*llcorner p)) - fi - enddef; - def graphictext primary filename = - if (readfrom filename = EOF): - errmessage "Please prepare '"&filename&"' in advance with"& - " 'pstoedit -ssp -dt -f mpost yourfile.ps "&filename&"'"; - fi - closefrom filename; - def data_mpy_file = filename enddef; - mfun_do_graphic_text (filename) - enddef; -else: - vardef textext@# (text t) = rawtextext (t) enddef; -fi -def externalfigure primary filename = - draw rawtextext("\includegraphics{"& filename &"}") -enddef; -def TEX = textext enddef; -def specialVerbatimTeX (text t) = special "MPlibVerbTeX="&t; enddef; -def normalVerbatimTeX (text t) = special "PostMPlibVerbTeX="&t; enddef; -let VerbatimTeX = specialVerbatimTeX; -extra_beginfig := extra_beginfig & " let VerbatimTeX = normalVerbatimTeX;" ; -extra_endfig := extra_endfig & " let VerbatimTeX = specialVerbatimTeX;" ; -]] -luamplib.mplibcodepreamble = mplibcodepreamble - -local textextlabelpreamble = [[ -primarydef s infont f = rawtextext(s) enddef; -def fontsize expr f = - begingroup - save size,pic; numeric size; picture pic; - pic := rawtextext("\hskip\pdffontsize\font"); - size := xpart urcorner pic - xpart llcorner pic; - if size = 0: 10pt else: size fi - endgroup -enddef; -]] -luamplib.textextlabelpreamble = textextlabelpreamble - -local TeX_code_t = {} -local texboxnum = { 2047 } - -local function domakeTEXboxes (data) - local num = texboxnum[1] - texboxnum[2] = num - local global = luamplib.globaltextext and "\\global" or "" - if data and data.fig then - local figures = data.fig - for f=1, #figures do - TeX_code_t[f] = nil - local figure = figures[f] - local objects = getobjects(data,figure,f) - if objects then - for o=1,#objects do - local object = objects[o] - local prescript = object.prescript - prescript = prescript and script2table(prescript) - local str = prescript and prescript.MPlibmkTEXbox - if str then - num = num + 1 - texsprint(format("%s\\setbox%i\\hbox{%s}", global, num, str)) - end -% \end{macrocode} -% |verbatimtex ... etex| before |beginfig()| is not ignored, -% but the \TeX\ code inbetween is inserted before the mplib box. -% \begin{macrocode} - local texcode = prescript and prescript.MPlibVerbTeX - if texcode and texcode ~= "" then - TeX_code_t[f] = texcode - end - end - end - end - end - if luamplib.globaltextext then - texboxnum[1] = num - end -end - -local function protect_tex_text_common (data) - local everymplib = texgettoks('everymplibtoks') or '' - local everyendmplib = texgettoks('everyendmplibtoks') or '' - data = format("\n%s\n%s\n%s",everymplib, data, everyendmplib) - data = data:gsub("\r","\n") - - data = data:gsub("\"[^\n]-\"", function(str) - return str:gsub("([bem])tex"..endname,"%1"..esctex) - end) - - data = data:gsub(btex_etex, function(str) - return format("rawtextext(\"%s\")",protecttexcontents(str)) - end) - data = data:gsub(verbatimtex_etex, function(str) - return format("VerbatimTeX(\"%s\")",protecttexcontents(str)) - end) - - return data -end - -local function protecttextextVerbatim(data) - data = protect_tex_text_common(data) - - data = data:gsub("\"[^\n]-\"", function(str) -- restore string btex .. etex - return str:gsub("([bem])"..esctex, "%1tex") - end) - - local _,result = process(data, false) - domakeTEXboxes(result) - return data -end - -luamplib.protecttextextVerbatim = protecttextextVerbatim - -luamplib.mpxcolors = {} - -local function protecttextext(data) - data = protect_tex_text_common(data) - - data = data:gsub("\"[^\n]-\"", function(str) - str = str:gsub("([bem])"..esctex, "%1tex") - :gsub("%%", escpcnt) - :gsub("{", esclbr) - :gsub("}", escrbr) - :gsub("#", eschash) - return format("\\detokenize{%s}",str) - end) - - data = data:gsub("%%.-\n", "") - - local grouplevel = tex.currentgrouplevel - luamplib.mpxcolors[grouplevel] = {} - data = data:gsub("\\mpcolor"..endname.."(.-){(.-)}", function(opt,str) - local cnt = #luamplib.mpxcolors[grouplevel] + 1 - luamplib.mpxcolors[grouplevel][cnt] = format( - "\\expandafter\\mplibcolor\\csname mpxcolor%i:%i\\endcsname%s{%s}", - grouplevel,cnt,opt,str) - return format("\\csname mpxcolor%i:%i\\endcsname",grouplevel,cnt) - end) - -% \end{macrocode} -% Next line to address bug \#55 +% |dvipdfmx| is supported, though nobody seems to use it. % \begin{macrocode} - data = data:gsub("([^`\\])#","%1##") - - texsprint(data) -end - -luamplib.protecttextext = protecttextext - -local function makeTEXboxes (data) - data = data:gsub("##","#") - :gsub(escpcnt,"%%") - :gsub(esclbr,"{") - :gsub(escrbr,"}") - :gsub(eschash,"#") - local _,result = process(data, false) - domakeTEXboxes(result) - return data -end - -luamplib.makeTEXboxes = makeTEXboxes - -local factor = 65536*(7227/7200) - -local function processwithTEXboxes (data) - if not data then return end - local num = texboxnum[2] - local prepreamble = format("TEXBOX_:=%i;\n",num) - while true do - num = num + 1 - local box = texgetbox(num) - if not box then break end - prepreamble = format( - "%sTEXBOX_wd_[%i]:=%f;\nTEXBOX_ht_[%i]:=%f;\nTEXBOX_dp_[%i]:=%f;\n", - prepreamble, - num, box.width /factor, - num, box.height/factor, - num, box.depth /factor) - end - process(prepreamble .. data, true) -end -luamplib.processwithTEXboxes = processwithTEXboxes - local pdfoutput = tonumber(texget("outputmode")) or tonumber(texget("pdfoutput")) local pdfmode = pdfoutput > 0 @@ -1238,8 +1387,13 @@ local function stop_pdf_code() end end -local function putTEXboxes (object,prescript) - local box = prescript.MPlibTEXboxID +% \end{macrocode} +% +% Now we process hboxes created from |btex ... etex| or +% |textext(...)| or |TEX(...)|, all being the same internally. +% \begin{macrocode} +local function put_tex_boxes (object,prescript) + local box = prescript.mplibtexboxid local n,tw,th = box[1],tonumber(box[2]),tonumber(box[3]) if n and tw and th then local op = object.path @@ -1264,7 +1418,8 @@ local function putTEXboxes (object,prescript) end % \end{macrocode} -% Transparency and Shading +% +% Colors and Transparency % \begin{macrocode} local pdf_objs = {} local token, getpageres, setpageres = newtoken or token @@ -1278,7 +1433,6 @@ else "\\special{pdf:obj @MPlibSh<<>>}") end --- objstr => obj , new local function update_pdfobjs (os) local on = pdf_objs[os] if on then @@ -1348,11 +1502,15 @@ local function tr_pdf_pageresources(mode,opaq) return on_on, off_on end +% \end{macrocode} +% +% Shading with |metafun| format. (maybe legacy way) +% \begin{macrocode} local shading_res local function shading_initialize () shading_res = {} - if pdfmode and luatexbase.callbacktypes and luatexbase.callbacktypes.finish_pdffile then -- ltluatex + if pdfmode and luatexbase.callbacktypes.finish_pdffile then -- ltluatex local shading_obj = pdf.reserveobj() setpageres(format("%s/Shading %i 0 R",getpageres() or "",shading_obj)) luatexbase.add_to_callback("finish_pdffile", function() @@ -1377,7 +1535,7 @@ local function sh_pdfpageresources(shtype,domain,colorspace,colora,colorb,coordi shading_res[#shading_res+1] = res else local pageres = getpageres() or "" - if not stringfind(pageres,"/Shading<<.*>>") then + if not pageres:find("/Shading<<.*>>") then pageres = pageres.."/Shading<<>>" end pageres = pageres:gsub("/Shading<<","%1"..res) @@ -1408,7 +1566,10 @@ end local prev_override_color local function do_preobj_color(object,prescript) - -- transparency +% \end{macrocode} +% +% transparency +% \begin{macrocode} local opaq = prescript and prescript.tr_transparency local tron_no, troff_no if opaq then @@ -1417,7 +1578,10 @@ local function do_preobj_color(object,prescript) tron_no, troff_no = tr_pdf_pageresources(mode,opaq) pdf_literalcode("/MPlibTr%i gs",tron_no) end - -- color +% \end{macrocode} +% +% color +% \begin{macrocode} local override = prescript and prescript.MPlibOverrideColor if override then if pdfmode then @@ -1439,12 +1603,15 @@ local function do_preobj_color(object,prescript) end end end - -- shading +% \end{macrocode} +% +% shading +% \begin{macrocode} local sh_type = prescript and prescript.sh_type if sh_type then local domain = prescript.sh_domain - local centera = stringexplode(prescript.sh_center_a) - local centerb = stringexplode(prescript.sh_center_b) + local centera = prescript.sh_center_a:explode() + local centerb = prescript.sh_center_b:explode() for _,t in pairs({centera,centerb}) do for i,v in ipairs(t) do t[i] = format("%f",v) @@ -1501,10 +1668,9 @@ local function do_postobj_color(tr,over,sh) end % \end{macrocode} -% End of |btex| -- |etex| and Transparency/Shading patch. % +% Finally, flush figures by inserting PDF literals. % \begin{macrocode} - local function flush(result,flusher) if result then local figures = result.fig @@ -1513,27 +1679,32 @@ local function flush(result,flusher) info("flushing figure %s",f) local figure = figures[f] local objects = getobjects(result,figure,f) - local fignum = tonumber(stringmatch(figure:filename(),"([%d]+)$") or figure:charcode() or 0) + local fignum = tonumber(figure:filename():match("([%d]+)$") or figure:charcode() or 0) local miterlimit, linecap, linejoin, dashed = -1, -1, -1, false local bbox = figure:boundingbox() local llx, lly, urx, ury = bbox[1], bbox[2], bbox[3], bbox[4] -- faster than unpack if urx < llx then % \end{macrocode} -% \textsf{luamplib} silently ignores this invalid figure for those codes +% +% luamplib silently ignores this invalid figure for those % that do not contain |beginfig ... endfig|. (issue \#70) +% Original code of ConTeXt general was: +% \begin{verbatim} +% -- invalid +% pdf_startfigure(fignum,0,0,0,0) +% pdf_stopfigure() +% \end{verbatim} % \begin{macrocode} - -- invalid - -- pdf_startfigure(fignum,0,0,0,0) - -- pdf_stopfigure() else % \end{macrocode} -% Insert |verbatimtex| code before mplib box. -% And prepare for those codes that will be executed afterwards. +% +% For legacy behavior. Insert `pre-fig' \TeX\ code here, and +% prepare a table for `in-fig' codes. % \begin{macrocode} - if TeX_code_t[f] then - texsprint(TeX_code_t[f]) + if tex_code_pre_mplib[f] then + texsprint(tex_code_pre_mplib[f]) end - local TeX_code_bot = {} -- PostVerbatimTeX + local TeX_code_bot = {} pdf_startfigure(fignum,llx,lly,urx,ury) start_pdf_code() if objects then @@ -1543,20 +1714,16 @@ local function flush(result,flusher) local object = objects[o] local objecttype = object.type % \end{macrocode} -% Change from \ConTeXt{} code: the following 7 lines are part of the -% |btex...etex| patch. Again, colors are processed at this stage. -% Also, we collect \TeX\ codes that will be executed after flushing. % +% The following 5 lines are part of |btex...etex| patch. +% Again, colors are processed at this stage. % \begin{macrocode} local prescript = object.prescript prescript = prescript and script2table(prescript) -- prescript is now a table local tr_opaq,cr_over,shade_no = do_preobj_color(object,prescript) - if prescript and prescript.MPlibTEXboxID then - putTEXboxes(object,prescript) - elseif prescript and prescript.PostMPlibVerbTeX then - TeX_code_bot[#TeX_code_bot+1] = prescript.PostMPlibVerbTeX - elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then - -- skip + if prescript and prescript.mplibtexboxid then + put_tex_boxes(object,prescript) + elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then --skip elseif objecttype == "start_clip" then local evenodd = not object.istext and object.postscript == "evenodd" start_pdf_code() @@ -1566,9 +1733,13 @@ local function flush(result,flusher) stop_pdf_code() miterlimit, linecap, linejoin, dashed = -1, -1, -1, false elseif objecttype == "special" then - -- not supported - if prescript and prescript.MPlibTEXError then - warn("textext() anomaly. Try disabling \\mplibtextextlabel.") +% \end{macrocode} +% +% Collect \TeX\ codes that will be executed after flushing. +% Legacy behavior. +% \begin{macrocode} + if prescript and prescript.postmplibverbtex then + TeX_code_bot[#TeX_code_bot+1] = prescript.postmplibverbtex end elseif objecttype == "text" then local ot = object.transform -- 3,4,5,6,1,2 @@ -1577,9 +1748,6 @@ local function flush(result,flusher) pdf_textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth) stop_pdf_code() else -% \end{macrocode} -% Color stuffs are modified and moved to several lines above. -% \begin{macrocode} local evenodd, collect, both = false, false, false local postscript = object.postscript if not object.istext then @@ -1666,10 +1834,9 @@ local function flush(result,flusher) end % \end{macrocode} % -% Change from \ConTeXt{} code: color stuff -% +% Change from ConTeXt general: there was color stuffs. % \begin{macrocode} - if not shade_no then ----- conflict with shading + if not shade_no then -- conflict with shading if objecttype == "fill" then pdf_literalcode(evenodd and "h f*" or "h f") elseif objecttype == "outline" then @@ -1723,18 +1890,15 @@ local function flush(result,flusher) end % \end{macrocode} % -% Added to \ConTeXt{} code: color stuff. -% And execute |verbatimtex| codes. -% +% Added to ConTeXt general: color stuff. +% And execute legacy |verbatimtex| code. % \begin{macrocode} do_postobj_color(tr_opaq,cr_over,shade_no) end end stop_pdf_code() pdf_stopfigure() - if #TeX_code_bot > 0 then - texsprint(TeX_code_bot) - end + if #TeX_code_bot > 0 then texsprint(TeX_code_bot) end end end end @@ -1764,6 +1928,7 @@ luamplib.colorconverter = colorconverter % % \subsection{\texorpdfstring{\TeX}{TeX} package} % +% % \begin{macrocode} %<*package> % \end{macrocode} @@ -1777,7 +1942,7 @@ luamplib.colorconverter = colorconverter \else \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{luamplib} - [2018/09/27 v2.12.5 mplib package for LuaTeX] + [2019/03/20 v2.20.0 mplib package for LuaTeX] \ifx\newluafunction\@undefined \input ltluatex \fi @@ -1785,12 +1950,11 @@ luamplib.colorconverter = colorconverter % \end{macrocode} % % Loading of lua code. -% % \begin{macrocode} \directlua{require("luamplib")} % \end{macrocode} % -% Support older formats +% Support older engine. Seems we don't need it, but no harm. % \begin{macrocode} \ifx\scantextokens\undefined \let\scantextokens\luatexscantextokens @@ -1798,20 +1962,18 @@ luamplib.colorconverter = colorconverter \ifx\pdfoutput\undefined \let\pdfoutput\outputmode \protected\def\pdfliteral{\pdfextension literal} + \def\pdffontsize{\dimexpr\pdffeedback fontsize\relax} \fi % \end{macrocode} - % % Set the format for metapost. -% % \begin{macrocode} \def\mplibsetformat#1{\directlua{luamplib.setformat("#1")}} % \end{macrocode} % -% \textsf{luamplib} works in both PDF and DVI mode, +% luamplib works in both PDF and DVI mode, % but only DVIPDFMx is supported currently among a number of DVI tools. % So we output a warning. -% % \begin{macrocode} \ifnum\pdfoutput>0 \let\mplibtoPDF\pdfliteral @@ -1825,17 +1987,32 @@ luamplib.colorconverter = colorconverter \write128{} \fi \fi +% \end{macrocode} +% +% Make |mplibcode| typesetted always in horizontal mode. +% \begin{macrocode} +\def\mplibforcehmode{\let\mplibhmodeornot\leavevmode} +\def\mplibnoforcehmode{\let\mplibhmodeornot\relax} +\mplibnoforcehmode +% \end{macrocode} +% +% Catcode. We want to allow comment sign in |mplibcode|. +% \begin{macrocode} \def\mplibsetupcatcodes{% - %catcode`\{=12 %catcode`\}=12 + \mplibhmodeornot %catcode`\{=12 %catcode`\}=12 \catcode`\#=12 \catcode`\^=12 \catcode`\~=12 \catcode`\_=12 \catcode`\&=12 \catcode`\$=12 \catcode`\%=12 \catcode`\^^M=12 \endlinechar=10 } % \end{macrocode} % % Make |btex...etex| box zero-metric. -% % \begin{macrocode} \def\mplibputtextbox#1{\vbox to 0pt{\vss\hbox to 0pt{\raise\dp#1\copy#1\hss}}} +% \end{macrocode} +% +% As we have changed |^^J| catcode, the last line containing +% |\end{mplibcode}| has |\n| at the end. Replace it with |^^M|. +% \begin{macrocode} \newcount\mplibstartlineno \def\mplibpostmpcatcodes{% \catcode`\{=12 \catcode`\}=12 \catcode`\#=12 \catcode`\%=12 } @@ -1846,7 +2023,6 @@ luamplib.colorconverter = colorconverter % \end{macrocode} % % The Plain-specific stuff. -% % \begin{macrocode} \bgroup\expandafter\expandafter\expandafter\egroup \expandafter\ifx\csname selectfont\endcsname\relax @@ -1863,23 +2039,14 @@ luamplib.colorconverter = colorconverter } \long\def\mplibdocode#1\endmplibcode{% \endgroup - \ifdefined\mplibverbatimYes - \directlua{luamplib.tempdata\the\currentgrouplevel=luamplib.protecttextextVerbatim([===[\detokenize{#1}]===])}% - \directlua{luamplib.processwithTEXboxes(luamplib.tempdata\the\currentgrouplevel)}% - \else - \edef\mplibtemp{\directlua{luamplib.protecttextext([===[\unexpanded{#1}]===])}}% - \directlua{ tex.sprint(luamplib.mpxcolors[\the\currentgrouplevel]) }% - \directlua{luamplib.tempdata\the\currentgrouplevel=luamplib.makeTEXboxes([===[\mplibtemp]===])}% - \directlua{luamplib.processwithTEXboxes(luamplib.tempdata\the\currentgrouplevel)}% - \fi + \directlua{luamplib.process_mplibcode([===[\unexpanded{#1}]===])}% \endgroup \ifnum\mplibstartlineno<\inputlineno\expandafter\mplibreplacenewlinecs\fi } \else % \end{macrocode} % -% The \LaTeX-specific parts: a new environment. -% +% The \LaTeX-specific part: a new environment. % \begin{macrocode} \newenvironment{mplibcode}{% \global\mplibstartlineno\inputlineno @@ -1894,16 +2061,9 @@ luamplib.colorconverter = colorconverter \long\def\ltxdomplibcodeindeed#1\end#2{% \endgroup \toks@\expandafter{\the\toks@#1}% - \def\mplibtemp@a{#2}\ifx\mplib@mplibcode\mplibtemp@a - \ifdefined\mplibverbatimYes - \directlua{luamplib.tempdata\the\currentgrouplevel=luamplib.protecttextextVerbatim([===[\the\toks@]===])}% - \directlua{luamplib.processwithTEXboxes(luamplib.tempdata\the\currentgrouplevel)}% - \else - \edef\mplibtemp{\directlua{luamplib.protecttextext([===[\the\toks@]===])}}% - \directlua{ tex.sprint(luamplib.mpxcolors[\the\currentgrouplevel]) }% - \directlua{luamplib.tempdata\the\currentgrouplevel=luamplib.makeTEXboxes([===[\mplibtemp]===])}% - \directlua{luamplib.processwithTEXboxes(luamplib.tempdata\the\currentgrouplevel)}% - \fi + \def\mplibtemp@a{#2}% + \ifx\mplib@mplibcode\mplibtemp@a + \directlua{luamplib.process_mplibcode([===[\the\toks@]===])}% \end{mplibcode}% \ifnum\mplibstartlineno<\inputlineno \expandafter\expandafter\expandafter\mplibreplacenewlinebr @@ -1913,22 +2073,32 @@ luamplib.colorconverter = colorconverter \fi } \fi -\def\mplibverbatim#1{% - \begingroup - \def\mplibtempa{#1}\def\mplibtempb{enable}% - \expandafter\endgroup - \ifx\mplibtempa\mplibtempb - \let\mplibverbatimYes\relax - \else - \let\mplibverbatimYes\undefined - \fi -} +% \end{macrocode} +% +% User settings. +% \begin{macrocode} +\def\mpliblegacybehavior#1{\directlua{ + local s = string.lower("#1") + if s == "enable" or s == "true" or s == "yes" then + luamplib.legacy_verbatimtex = true + else + luamplib.legacy_verbatimtex = false + end +}} +\def\mplibverbatim#1{\directlua{ + local s = string.lower("#1") + if s == "enable" or s == "true" or s == "yes" then + luamplib.verbatiminput = true + else + luamplib.verbatiminput = false + end +}} % \end{macrocode} % % \cs{everymplib} \& \cs{everyendmplib}: macros redefining % \cs{everymplibtoks} \& \cs{everyendmplibtoks} respectively -% % \begin{macrocode} +\newtoks\mplibtmptoks \newtoks\everymplibtoks \newtoks\everyendmplibtoks \protected\def\everymplib{% @@ -1953,18 +2123,24 @@ luamplib.colorconverter = colorconverter \everyendmplibtoks{#1}% \ifnum\mplibstartlineno<\inputlineno\expandafter\mplibreplacenewlinebr\fi } +% \end{macrocode} +% +% Allow \TeX\ dimen macros in |mplibcode|. +% \begin{macrocode} \def\mpdim#1{ begingroup \the\dimexpr #1\relax\space endgroup } % gmp.sty % \end{macrocode} % -% Support color/xcolor packages. -% User interface is: |\mpcolor{teal}| or |\mpcolor[HTML]{008080}|, -% for example. +% MPLib's number system. Now |binary| has gone away. +% \begin{macrocode} +\def\mplibnumbersystem#1{\directlua{ + local t = "#1" + if t == "binary" then t = "decimal" end + luamplib.numbersystem = t +}} +% \end{macrocode} +% +% Settings for |.mp| cache files. % \begin{macrocode} -\def\mplibcolor#1{% - \def\set@color{\edef#1{1 withprescript "MPlibOverrideColor=\current@color"}}% - \color -} -\def\mplibnumbersystem#1{\directlua{luamplib.numbersystem = "#1"}} \def\mplibmakenocache#1{\mplibdomakenocache #1,*,} \def\mplibdomakenocache#1,{% \ifx\empty#1\empty @@ -1988,46 +2164,43 @@ luamplib.colorconverter = colorconverter \fi } \def\mplibcachedir#1{\directlua{luamplib.getcachedir("\unexpanded{#1}")}} -\def\mplibtextextlabel#1{% - \begingroup - \def\tempa{enable}\def\tempb{#1}% - \ifx\tempa\tempb - \directlua{luamplib.textextlabel = true}% - \else - \directlua{luamplib.textextlabel = false}% - \fi - \endgroup -} -\def\mplibcodeinherit#1{% - \begingroup - \def\tempa{enable}\def\tempb{#1}% - \ifx\tempa\tempb - \directlua{luamplib.codeinherit = true}% - \else - \directlua{luamplib.codeinherit = false}% - \fi - \endgroup -} -\def\mplibglobaltextext#1{% - \begingroup - \def\tempa{enable}\def\tempb{#1}% - \ifx\tempa\tempb - \directlua{luamplib.globaltextext = true}% - \else - \directlua{luamplib.globaltextext = false}% - \fi - \endgroup -} % \end{macrocode} % -% We use a dedicated scratchbox. +% More user settings. +% \begin{macrocode} +\def\mplibtextextlabel#1{\directlua{ + local s = string.lower("#1") + if s == "enable" or s == "true" or s == "yes" then + luamplib.textextlabel = true + else + luamplib.textextlabel = false + end +}} +\def\mplibcodeinherit#1{\directlua{ + local s = string.lower("#1") + if s == "enable" or s == "true" or s == "yes" then + luamplib.codeinherit = true + else + luamplib.codeinherit = false + end +}} +\def\mplibglobaltextext#1{\directlua{ + local s = string.lower("#1") + if s == "enable" or s == "true" or s == "yes" then + luamplib.globaltextext = true + else + luamplib.globaltextext = false + end +}} +% \end{macrocode} % +% The followings are from ConTeXt general, mostly. +% % We use a dedicated scratchbox. % \begin{macrocode} \ifx\mplibscratchbox\undefined \newbox\mplibscratchbox \fi % \end{macrocode} % % We encapsulate the litterals. -% % \begin{macrocode} \def\mplibstarttoPDF#1#2#3#4{% \hbox\bgroup @@ -2042,9 +2215,6 @@ luamplib.colorconverter = colorconverter \setbox\mplibscratchbox\vbox\bgroup \noindent } -% \end{macrocode} -% -% \begin{macrocode} \def\mplibstoptoPDF{% \egroup % \setbox\mplibscratchbox\hbox % @@ -2066,7 +2236,6 @@ luamplib.colorconverter = colorconverter % \end{macrocode} % % Text items have a special handler. -% % \begin{macrocode} \def\mplibtextext#1#2#3#4#5{% \begingroup @@ -2086,8 +2255,7 @@ luamplib.colorconverter = colorconverter } % \end{macrocode} % -% input luamplib.cfg when it exists -% +% Input |luamplib.cfg| when it exists. % \begin{macrocode} \openin0=luamplib.cfg \ifeof0 \else diff --git a/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua b/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua index 73449b7be97..c94fb761fc9 100644 --- a/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua +++ b/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua @@ -9,32 +9,25 @@ -- See source file 'luamplib.dtx' for licencing and contact information. -- -luamplib = luamplib or { } - - -local luamplib = luamplib -luamplib.showlog = luamplib.showlog or false -luamplib.lastlog = "" - luatexbase.provides_module { name = "luamplib", - version = "2.12.5", - date = "2018/09/27", + version = "2.20.0", + date = "2019/03/20", description = "Lua package to typeset Metapost with LuaTeX's MPLib.", } - local format, abs = string.format, math.abs local err = function(...) return luatexbase.module_error ("luamplib", format(...)) end local warn = function(...) return luatexbase.module_warning("luamplib", format(...)) end local info = function(...) return luatexbase.module_info ("luamplib", format(...)) end -local stringgsub = string.gsub -local stringfind = string.find -local stringmatch = string.match -local stringgmatch = string.gmatch -local stringexplode = string.explode +luamplib = luamplib or { } +local luamplib = luamplib + +luamplib.showlog = luamplib.showlog or false +luamplib.lastlog = "" + local tableconcat = table.concat local texsprint = tex.sprint local textprint = tex.tprint @@ -42,6 +35,12 @@ local textprint = tex.tprint local texget = tex.get local texgettoks = tex.gettoks local texgetbox = tex.getbox +local texruntoks = tex.runtoks +local texscantoks = tex.scantoks + +if not texruntoks then + err("Your LuaTeX version is too old. Please upgrade it to the latest") +end local mplib = require ('mplib') local kpse = require ('kpse') @@ -55,10 +54,10 @@ local ioopen = io.open local file = file or { } local replacesuffix = file.replacesuffix or function(filename, suffix) - return (stringgsub(filename,"%.[%a%d]+$","")) .. "." .. suffix + return (filename:gsub("%.[%a%d]+$","")) .. "." .. suffix end local stripsuffix = file.stripsuffix or function(filename) - return (stringgsub(filename,"%.[%a%d]+$","")) + return (filename:gsub("%.[%a%d]+$","")) end local is_writable = file.is_writable or function(name) @@ -73,7 +72,7 @@ local is_writable = file.is_writable or function(name) end local mk_full_path = lfs.mkdirs or function(path) local full = "" - for sub in stringgmatch(path,"(/*[^\\/]+)") do + for sub in path:gmatch("(/*[^\\/]+)") do full = full .. sub lfsmkdir(full) end @@ -88,7 +87,7 @@ local outputdir if lfstouch then local texmfvar = kpse.expand_var('$TEXMFVAR') if texmfvar and texmfvar ~= "" and texmfvar ~= '$TEXMFVAR' then - for _,dir in next,stringexplode(texmfvar,os.type == "windows" and ";" or ":") do + for _,dir in next, texmfvar:explode(os.type == "windows" and ";" or ":") do if not lfsisdir(dir) then mk_full_path(dir) end @@ -104,7 +103,7 @@ end if not outputdir then outputdir = "." for _,v in ipairs(arg) do - local t = stringmatch(v,"%-output%-directory=(.+)") + local t = v:match("%-output%-directory=(.+)") if t then outputdir = t break @@ -130,43 +129,19 @@ function luamplib.getcachedir(dir) end local noneedtoreplace = { - ["boxes.mp"] = true, - -- ["format.mp"] = true, - ["graph.mp"] = true, - ["marith.mp"] = true, - ["mfplain.mp"] = true, - ["mpost.mp"] = true, - ["plain.mp"] = true, - ["rboxes.mp"] = true, - ["sarith.mp"] = true, - ["string.mp"] = true, - ["TEX.mp"] = true, - ["metafun.mp"] = true, - ["metafun.mpiv"] = true, - ["mp-abck.mpiv"] = true, - ["mp-apos.mpiv"] = true, - ["mp-asnc.mpiv"] = true, - ["mp-bare.mpiv"] = true, - ["mp-base.mpiv"] = true, - ["mp-butt.mpiv"] = true, - ["mp-char.mpiv"] = true, - ["mp-chem.mpiv"] = true, - ["mp-core.mpiv"] = true, - ["mp-crop.mpiv"] = true, - ["mp-figs.mpiv"] = true, - ["mp-form.mpiv"] = true, - ["mp-func.mpiv"] = true, - ["mp-grap.mpiv"] = true, - ["mp-grid.mpiv"] = true, - ["mp-grph.mpiv"] = true, - ["mp-idea.mpiv"] = true, - ["mp-luas.mpiv"] = true, - ["mp-mlib.mpiv"] = true, - ["mp-node.mpiv"] = true, - ["mp-page.mpiv"] = true, - ["mp-shap.mpiv"] = true, - ["mp-step.mpiv"] = true, - ["mp-text.mpiv"] = true, + ["boxes.mp"] = true, -- ["format.mp"] = true, + ["graph.mp"] = true, ["marith.mp"] = true, ["mfplain.mp"] = true, + ["mpost.mp"] = true, ["plain.mp"] = true, ["rboxes.mp"] = true, + ["sarith.mp"] = true, ["string.mp"] = true, -- ["TEX.mp"] = true, + ["metafun.mp"] = true, ["metafun.mpiv"] = true, ["mp-abck.mpiv"] = true, + ["mp-apos.mpiv"] = true, ["mp-asnc.mpiv"] = true, ["mp-bare.mpiv"] = true, + ["mp-base.mpiv"] = true, ["mp-blob.mpiv"] = true, ["mp-butt.mpiv"] = true, + ["mp-char.mpiv"] = true, ["mp-chem.mpiv"] = true, ["mp-core.mpiv"] = true, + ["mp-crop.mpiv"] = true, ["mp-figs.mpiv"] = true, ["mp-form.mpiv"] = true, + ["mp-func.mpiv"] = true, ["mp-grap.mpiv"] = true, ["mp-grid.mpiv"] = true, + ["mp-grph.mpiv"] = true, ["mp-idea.mpiv"] = true, ["mp-luas.mpiv"] = true, + ["mp-mlib.mpiv"] = true, ["mp-node.mpiv"] = true, ["mp-page.mpiv"] = true, + ["mp-shap.mpiv"] = true, ["mp-step.mpiv"] = true, ["mp-text.mpiv"] = true, ["mp-tool.mpiv"] = true, } luamplib.noneedtoreplace = noneedtoreplace @@ -189,25 +164,10 @@ local function replaceformatmp(file,newfile,ofmodify) return newfile end -local esctex = "!!!T!!!E!!!X!!!" -local esclbr = "!!!!!LEFTBRCE!!!!!" -local escrbr = "!!!!!RGHTBRCE!!!!!" -local escpcnt = "!!!!!PERCENT!!!!!" -local eschash = "!!!!!HASH!!!!!" -local begname = "%f[A-Z_a-z]" -local endname = "%f[^A-Z_a-z]" - -local btex_etex = begname.."btex"..endname.."%s*(.-)%s*"..begname.."etex"..endname -local verbatimtex_etex = begname.."verbatimtex"..endname.."%s*(.-)%s*"..begname.."etex"..endname - -local function protecttexcontents(str) - return str:gsub("\\%%", "\\"..escpcnt) - :gsub("%%.-\n", "") - :gsub("%%.-$", "") - :gsub('"', '"&ditto&"') - :gsub("\n%s*", " ") - :gsub(escpcnt, "%%") -end +local name_b = "%f[A-Z_a-z]" +local name_e = "%f[^A-Z_a-z]" +local btex_etex = name_b.."btex"..name_e.."%s*(.-)%s*"..name_b.."etex"..name_e +local verbatimtex_etex = name_b.."verbatimtex"..name_e.."%s*(.-)%s*"..name_b.."etex"..name_e local function replaceinputmpfile (name,file) local ofmodify = lfsattributes(file,"modification") @@ -217,10 +177,12 @@ local function replaceinputmpfile (name,file) newfile = cachedir .."/luamplib_input_"..newfile if newfile and luamplibtime then local nf = lfsattributes(newfile) - if nf and nf.mode == "file" and ofmodify == nf.modification and luamplibtime < nf.access then + if nf and nf.mode == "file" and + ofmodify == nf.modification and luamplibtime < nf.access then return nf.size == 0 and file or newfile end end + if name == "format.mp" then return replaceformatmp(file,newfile,ofmodify) end local fh = ioopen(file,"r") @@ -228,22 +190,11 @@ local function replaceinputmpfile (name,file) local data = fh:read("*all"); fh:close() local count,cnt = 0,0 - - data = data:gsub("\"[^\n]-\"", function(str) - return str:gsub("([bem])tex"..endname,"%1"..esctex) - end) - - data, cnt = data:gsub(btex_etex, function(str) - return format("rawtextext(\"%s\")",protecttexcontents(str)) - end) + data, cnt = data:gsub(btex_etex, "btex %1 etex ") -- space count = count + cnt - data, cnt = data:gsub(verbatimtex_etex, "") + data, cnt = data:gsub(verbatimtex_etex, "verbatimtex %1 etex;") -- semicolon count = count + cnt - data = data:gsub("\"[^\n]-\"", function(str) -- restore string btex .. etex - return str:gsub("([bem])"..esctex, "%1tex") - end) - if count == 0 then noneedtoreplace[name] = true fh = ioopen(newfile,"w"); @@ -253,6 +204,7 @@ local function replaceinputmpfile (name,file) end return file end + fh = ioopen(newfile,"w") if not fh then return file end fh:write(data); fh:close() @@ -260,8 +212,6 @@ local function replaceinputmpfile (name,file) return newfile end -local randomseed = nil - local mpkpse = kpse.new(arg[0], "mpost") local special_ftype = { @@ -281,105 +231,35 @@ local function finder(name, mode, ftype) end return replaceinputmpfile(name,file) end - return mpkpse:find_file(name,stringmatch(name,"[a-zA-Z]+$")) + return mpkpse:find_file(name, name:match("[a-zA-Z]+$")) end end luamplib.finder = finder - -function luamplib.resetlastlog() - luamplib.lastlog = "" +if tonumber(mplib.version()) <= 1.50 then + err("luamplib no longer supports mplib v1.50 or lower. ".. + "Please upgrade to the latest version of LuaTeX") end -local mplibone = tonumber(mplib.version()) <= 1.50 - -if mplibone then - - luamplib.make = luamplib.make or function(name,mem_name,dump) - local t = os.clock() - local mpx = mplib.new { - ini_version = true, - find_file = luamplib.finder, - job_name = stripsuffix(name) - } - mpx:execute(format("input %s ;",name)) - if dump then - mpx:execute("dump ;") - info("format %s made and dumped for %s in %0.3f seconds",mem_name,name,os.clock()-t) - else - info("%s read in %0.3f seconds",name,os.clock()-t) - end - return mpx - end - - function luamplib.load(name) - local mem_name = replacesuffix(name,"mem") - local mpx = mplib.new { - ini_version = false, - mem_name = mem_name, - find_file = luamplib.finder - } - if not mpx and type(luamplib.make) == "function" then - -- when i have time i'll locate the format and dump - mpx = luamplib.make(name,mem_name) - end - if mpx then - info("using format %s",mem_name,false) - return mpx, nil - else - return nil, { status = 99, error = "out of memory or invalid format" } - end - end - -else - - local preamble = [[ - boolean mplib ; mplib := true ; - let dump = endinput ; - let normalfontsize = fontsize; - input %s ; - ]] - - luamplib.make = luamplib.make or function() - end - - function luamplib.load(name,verbatim) - local mpx = mplib.new { - ini_version = true, - find_file = luamplib.finder, - math_mode = luamplib.numbersystem, - random_seed = randomseed, - } - local preamble = preamble .. (verbatim and "" or luamplib.mplibcodepreamble) - if luamplib.textextlabel then - preamble = preamble .. (verbatim and "" or luamplib.textextlabelpreamble) - end - local result - if not mpx then - result = { status = 99, error = "out of memory"} - else - result = mpx:execute(format(preamble, replacesuffix(name,"mp"))) - end - luamplib.reporterror(result) - return mpx, result - end - -end - -local currentformat = "plain" +local preamble = [[ + boolean mplib ; mplib := true ; + let dump = endinput ; + let normalfontsize = fontsize; + input %s ; +]] -local function setformat (name) --- used in .sty - currentformat = name +local function luamplibresetlastlog() + luamplib.lastlog = "" end -luamplib.setformat = setformat -luamplib.reporterror = function (result) +local function reporterror (result) if not result then err("no result object returned") else local t, e, l = result.term, result.error, result.log - local log = stringgsub(t or l or "no-term","^%s+","\n") - luamplib.lastlog = luamplib.lastlog .. "\n " .. (l or t or "no-log") + local log = t or l or "no-term" + log = log:gsub("^%s+","\n") + luamplib.lastlog = luamplib.lastlog .. "\n" .. (l or t or "no-log") if result.status > 0 then warn("%s",log) if result.status > 1 then @@ -390,17 +270,50 @@ luamplib.reporterror = function (result) end end -local function process_indeed (mpx, data, indeed) +local function luamplibload (name) + local mpx = mplib.new { + ini_version = true, + find_file = luamplib.finder, + make_text = luamplib.maketext, + run_script = luamplib.runscript, + math_mode = luamplib.numbersystem, + extensions = 1, + } + local preamble = preamble .. luamplib.mplibcodepreamble + if luamplib.legacy_verbatimtex then + preamble = preamble .. luamplib.legacyverbatimtexpreamble + end + if luamplib.textextlabel then + preamble = preamble .. luamplib.textextlabelpreamble + end + local result + if not mpx then + result = { status = 99, error = "out of memory"} + else + result = mpx:execute(format(preamble, replacesuffix(name,"mp"))) + end + reporterror(result) + return mpx, result +end + +local currentformat = "plain" + +local function setformat (name) + currentformat = name +end +luamplib.setformat = setformat + +local function process_indeed (mpx, data) local converted, result = false, {} if mpx and data then result = mpx:execute(data) - local log = luamplib.reporterror(result) - if indeed and log then + local log = reporterror(result) + if log then if luamplib.showlog then info("%s",luamplib.lastlog) - luamplib.resetlastlog() + luamplibresetlastlog() elseif result.fig then - if stringfind(log,"\n>>") then info("%s",log) end + if log:find("\n>>") then info("%s",log) end converted = luamplib.convert(result) else info("%s",log) @@ -415,182 +328,206 @@ end luamplib.codeinherit = false local mplibinstances = {} -local process = function (data,indeed,verbatim) - if not stringfind(data, begname.."beginfig%s*%([%+%-%s]*%d[%.%d%s]*%)") then + +local function process (data) + if not data:find(name_b.."beginfig%s*%([%+%-%s]*%d[%.%d%s]*%)") then data = data .. "beginfig(-1);endfig;" end - local standalone, firstpass = not luamplib.codeinherit, not indeed + local standalone = not luamplib.codeinherit local currfmt = currentformat .. (luamplib.numbersystem or "scaled") - currfmt = firstpass and currfmt or (currfmt.."2") + .. tostring(luamplib.textextlabel) .. tostring(luamplib.legacy_verbatimtex) local mpx = mplibinstances[currfmt] + if mpx and standalone then + mpx:finish() + end if standalone or not mpx then - randomseed = firstpass and math.random(65535) or randomseed - mpx = luamplib.load(currentformat,verbatim) + mpx = luamplibload(currentformat) mplibinstances[currfmt] = mpx end - return process_indeed(mpx, data, indeed) + return process_indeed(mpx, data) end -luamplib.process = process -local function getobjects(result,figure,f) - return figure:objects() -end +local catlatex = luatexbase.registernumber("catcodetable@latex") +local catat11 = luatexbase.registernumber("catcodetable@atletter") -local function convert(result, flusher) - luamplib.flush(result, flusher) - return true -- done +local function run_tex_code_no_use (str, cat) + cat = cat or catlatex + texscantoks("mplibtmptoks", cat, str) + texruntoks("mplibtmptoks") end -luamplib.convert = convert -local function pdf_startfigure(n,llx,lly,urx,ury) - texsprint(format("\\mplibstarttoPDF{%f}{%f}{%f}{%f}",llx,lly,urx,ury)) +local function run_tex_code (str, cat) + cat = cat or catlatex + texruntoks(function() texsprint(cat, str) end) end -local function pdf_stopfigure() - texsprint("\\mplibstoptoPDF") +local tex_box_id = 2047 +local factor = 65536*(7227/7200) + +local function process_tex_text (str) + if str then + tex_box_id = tex_box_id + 1 + local global = luamplib.globaltextext and "\\global" or "" + run_tex_code(format("%s\\setbox%i\\hbox{%s}", global, tex_box_id, str)) + local box = texgetbox(tex_box_id) + local wd = box.width / factor + local ht = box.height / factor + local dp = box.depth / factor + return format("image(addto currentpicture doublepath unitsquare ".. + "xscaled %f yscaled %f shifted (0,-%f) ".. + "withprescript \"mplibtexboxid=%i:%f:%f\")", + wd, ht+dp, dp, tex_box_id, wd, ht+dp) + end + return "" end -local function pdf_literalcode(fmt,...) -- table - textprint({"\\mplibtoPDF{"},{-2,format(fmt,...)},{"}"}) +local function process_color (str) + if str then + if not str:find("{.-}") then + str = format("{%s}",str) + end + run_tex_code(format( + "\\def\\set@color{\\toks0\\expandafter{\\current@color}}\\color %s", str), + catat11) + return format("1 withprescript \"MPlibOverrideColor=%s\"", texgettoks(0)) + end + return "" end -luamplib.pdf_literalcode = pdf_literalcode -local function pdf_textfigure(font,size,text,width,height,depth) - -- if text == "" then text = "\0" end -- char(0) has gone - text = text:gsub(".",function(c) - return format("\\hbox{\\char%i}",string.byte(c)) -- kerning happens in metapost - end) - texsprint(format("\\mplibtextext{%s}{%f}{%s}{%s}{%f}",font,size,text,0,-( 7200/ 7227)/65536*depth)) +local function process_dimen (str) + if str then + str = str:gsub("{(.+)}","%1") + run_tex_code(format("\\toks0\\expandafter{\\the\\dimexpr %s\\relax}", str)) + return format("begingroup %s endgroup", texgettoks(0)) + end + return "" end -luamplib.pdf_textfigure = pdf_textfigure -local bend_tolerance = 131/65536 +local function process_verbatimtex_text (str) + if str then + run_tex_code(str) + end + return "" +end -local rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1 +local tex_code_pre_mplib = {} +luamplib.figid = 1 +luamplib.in_the_fig = false -local function pen_characteristics(object) - local t = mplib.pen_info(object) - rx, ry, sx, sy, tx, ty = t.rx, t.ry, t.sx, t.sy, t.tx, t.ty - divider = sx*sy - rx*ry - return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width +local function legacy_mplibcode_reset () + tex_code_pre_mplib = {} + luamplib.figid = 1 end -local function concat(px, py) -- no tx, ty here - return (sy*px-ry*py)/divider,(sx*py-rx*px)/divider +local function process_verbatimtex_prefig (str) + if str then + tex_code_pre_mplib[luamplib.figid] = str + end + return "" end -local function curved(ith,pth) - local d = pth.left_x - ith.right_x - if abs(ith.right_x - ith.x_coord - d) <= bend_tolerance and abs(pth.x_coord - pth.left_x - d) <= bend_tolerance then - d = pth.left_y - ith.right_y - if abs(ith.right_y - ith.y_coord - d) <= bend_tolerance and abs(pth.y_coord - pth.left_y - d) <= bend_tolerance then - return false - end +local function process_verbatimtex_infig (str) + if str then + return format("special \"postmplibverbtex=%s\";", str) end - return true + return "" end -local function flushnormalpath(path,open) - local pth, ith - for i=1,#path do - pth = path[i] - if not ith then - pdf_literalcode("%f %f m",pth.x_coord,pth.y_coord) - elseif curved(ith,pth) then - pdf_literalcode("%f %f %f %f %f %f c",ith.right_x,ith.right_y,pth.left_x,pth.left_y,pth.x_coord,pth.y_coord) - else - pdf_literalcode("%f %f l",pth.x_coord,pth.y_coord) +local runscript_funcs = { + luamplibtext = process_tex_text, + luamplibcolor = process_color, + luamplibdimen = process_dimen, + luamplibprefig = process_verbatimtex_prefig, + luamplibinfig = process_verbatimtex_infig, + luamplibverbtex = process_verbatimtex_text, +} + +mp = mp or {} +local mp = mp +mp.mf_path_reset = mp.mf_path_reset or function() end +mp.mf_finish_saving_data = mp.mf_finish_saving_data or function() end +LUATEXFUNCTIONALITY = LUATEXFUNCTIONALITY or 0 + +local function mpprint(buffer,...) + for i=1,select("#",...) do + local value = select(i,...) + if value ~= nil then + local t = type(value) + if t == "number" then + buffer[#buffer+1] = format("%.16f",value) + elseif t == "string" then + buffer[#buffer+1] = value + elseif t == "table" then + buffer[#buffer+1] = "(" .. concat(value,",") .. ")" + else -- boolean or whatever + buffer[#buffer+1] = tostring(value) + end end - ith = pth - end - if not open then - local one = path[1] - if curved(pth,one) then - pdf_literalcode("%f %f %f %f %f %f c",pth.right_x,pth.right_y,one.left_x,one.left_y,one.x_coord,one.y_coord ) - else - pdf_literalcode("%f %f l",one.x_coord,one.y_coord) - end - elseif #path == 1 then - -- special case .. draw point - local one = path[1] - pdf_literalcode("%f %f l",one.x_coord,one.y_coord) end end -local function flushconcatpath(path,open) - pdf_literalcode("%f %f %f %f %f %f cm", sx, rx, ry, sy, tx ,ty) - local pth, ith - for i=1,#path do - pth = path[i] - if not ith then - pdf_literalcode("%f %f m",concat(pth.x_coord,pth.y_coord)) - elseif curved(ith,pth) then - local a, b = concat(ith.right_x,ith.right_y) - local c, d = concat(pth.left_x,pth.left_y) - pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(pth.x_coord, pth.y_coord)) - else - pdf_literalcode("%f %f l",concat(pth.x_coord, pth.y_coord)) +function luamplib.runscript (code) + local id, str = code:match("(.-){(.+)}") + if id and str and str ~= "" then + local f = runscript_funcs[id] + if f then + local t = f(str) + if t then return t end end - ith = pth end - if not open then - local one = path[1] - if curved(pth,one) then - local a, b = concat(pth.right_x,pth.right_y) - local c, d = concat(one.left_x,one.left_y) - pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(one.x_coord, one.y_coord)) - else - pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord)) + local f = loadstring(code) + if type(f) == "function" then + local buffer = {} + function mp.print(...) + mpprint(buffer,...) end - elseif #path == 1 then - -- special case .. draw point - local one = path[1] - pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord)) + f() + return tableconcat(buffer,"") end + return "" end -local further_split_keys = { - ["MPlibTEXboxID"] = true, - ["sh_color_a"] = true, - ["sh_color_b"] = true, -} +local function protecttexcontents (str) + return str:gsub("\\%%", "\0PerCent\0") + :gsub("%%.-\n", "") + :gsub("%%.-$", "") + :gsub("%zPerCent%z", "\\%%") + :gsub("%s+", " ") +end -local function script2table(s) - local t = {} - for _,i in ipairs(stringexplode(s,"\13+")) do - local k,v = stringmatch(i,"(.-)=(.*)") -- v may contain = or empty. - if k and v and k ~= "" then - if further_split_keys[k] then - t[k] = stringexplode(v,":") - else - t[k] = v +luamplib.legacy_verbatimtex = true + +function luamplib.maketext (str, what) + if str and str ~= "" then + str = protecttexcontents(str) + if what == 1 then + if not str:find("\\documentclass"..name_e) and + not str:find("\\begin%s*{document}") and + not str:find("\\documentstyle"..name_e) and + not str:find("\\usepackage"..name_e) then + if luamplib.legacy_verbatimtex then + if luamplib.in_the_fig then + return process_verbatimtex_infig(str) + else + return process_verbatimtex_prefig(str) + end + else + return process_verbatimtex_text(str) + end end + else + return process_tex_text(str) end end - return t + return "" end local mplibcodepreamble = [[ -vardef rawtextext (expr t) = - if unknown TEXBOX_: - image( special "MPlibmkTEXbox="&t; - addto currentpicture doublepath unitsquare; ) - else: - TEXBOX_ := TEXBOX_ + 1; - if known TEXBOX_wd_[TEXBOX_]: - image ( addto currentpicture doublepath unitsquare - xscaled TEXBOX_wd_[TEXBOX_] - yscaled (TEXBOX_ht_[TEXBOX_] + TEXBOX_dp_[TEXBOX_]) - shifted (0, -TEXBOX_dp_[TEXBOX_]) - withprescript "MPlibTEXboxID=" & - decimal TEXBOX_ & ":" & - decimal TEXBOX_wd_[TEXBOX_] & ":" & - decimal(TEXBOX_ht_[TEXBOX_]+TEXBOX_dp_[TEXBOX_]); ) - else: - image( special "MPlibTEXError=1"; ) - fi - fi -enddef; +texscriptmode := 2; +def rawtextext (expr t) = runscript("luamplibtext{"&t&"}") enddef; +def mplibcolor (expr t) = runscript("luamplibcolor{"&t&"}") enddef; +def mplibdimen (expr t) = runscript("luamplibdimen{"&t&"}") enddef; +def VerbatimTeX (expr t) = runscript("luamplibverbtex{"&t&"}") enddef; if known context_mlib: defaultfont := "cmtt10"; let infont = normalinfont; @@ -620,14 +557,21 @@ def externalfigure primary filename = draw rawtextext("\includegraphics{"& filename &"}") enddef; def TEX = textext enddef; -def specialVerbatimTeX (text t) = special "MPlibVerbTeX="&t; enddef; -def normalVerbatimTeX (text t) = special "PostMPlibVerbTeX="&t; enddef; -let VerbatimTeX = specialVerbatimTeX; -extra_beginfig := extra_beginfig & " let VerbatimTeX = normalVerbatimTeX;" ; -extra_endfig := extra_endfig & " let VerbatimTeX = specialVerbatimTeX;" ; ]] luamplib.mplibcodepreamble = mplibcodepreamble +local legacyverbatimtexpreamble = [[ +def specialVerbatimTeX (text t) = runscript("luamplibprefig{"&t&"}") enddef; +def normalVerbatimTeX (text t) = runscript("luamplibinfig{"&t&"}") enddef; +let VerbatimTeX = specialVerbatimTeX; +extra_beginfig := extra_beginfig & " let VerbatimTeX = normalVerbatimTeX;"& + "runscript(" &ditto& "luamplib.in_the_fig=true" &ditto& ");"; +extra_endfig := extra_endfig & " let VerbatimTeX = specialVerbatimTeX;"& + "runscript(" &ditto& + "luamplib.in_the_fig=false luamplib.figid=luamplib.figid+1" &ditto& ");"; +]] +luamplib.legacyverbatimtexpreamble = legacyverbatimtexpreamble + local textextlabelpreamble = [[ primarydef s infont f = rawtextext(s) enddef; def fontsize expr f = @@ -641,142 +585,199 @@ enddef; ]] luamplib.textextlabelpreamble = textextlabelpreamble -local TeX_code_t = {} -local texboxnum = { 2047 } - -local function domakeTEXboxes (data) - local num = texboxnum[1] - texboxnum[2] = num - local global = luamplib.globaltextext and "\\global" or "" - if data and data.fig then - local figures = data.fig - for f=1, #figures do - TeX_code_t[f] = nil - local figure = figures[f] - local objects = getobjects(data,figure,f) - if objects then - for o=1,#objects do - local object = objects[o] - local prescript = object.prescript - prescript = prescript and script2table(prescript) - local str = prescript and prescript.MPlibmkTEXbox - if str then - num = num + 1 - texsprint(format("%s\\setbox%i\\hbox{%s}", global, num, str)) - end - local texcode = prescript and prescript.MPlibVerbTeX - if texcode and texcode ~= "" then - TeX_code_t[f] = texcode - end - end - end - end +luamplib.verbatiminput = false + +local function protect_expansion (str) + if str then + str = str:gsub("\\","\1Control\1") + :gsub("%%","\1Comment\1") + :gsub("#", "\1HashSign\1") + :gsub("{", "\1LBrace\1") + :gsub("}", "\1RBrace\1") + return format("\\unexpanded{%s}",str) end - if luamplib.globaltextext then - texboxnum[1] = num +end + +local function unprotect_expansion (str) + if str then + return str:gsub("\1Control\1", "\\") + :gsub("\1Comment\1", "%%") + :gsub("\1HashSign\1","#") + :gsub("\1LBrace\1", "{") + :gsub("\1RBrace\1", "}") end end -local function protect_tex_text_common (data) +local function process_mplibcode (data) + legacy_mplibcode_reset() + local everymplib = texgettoks('everymplibtoks') or '' local everyendmplib = texgettoks('everyendmplibtoks') or '' - data = format("\n%s\n%s\n%s",everymplib, data, everyendmplib) + data = format("\n%s\n%s\n%s\n",everymplib, data, everyendmplib) data = data:gsub("\r","\n") - data = data:gsub("\"[^\n]-\"", function(str) - return str:gsub("([bem])tex"..endname,"%1"..esctex) - end) + data = data:gsub("\\mpcolor%s+(.-%b{})","mplibcolor(\"%1\")") data = data:gsub(btex_etex, function(str) - return format("rawtextext(\"%s\")",protecttexcontents(str)) + return format("btex %s etex ", -- space + luamplib.verbatiminput and str or protect_expansion(str)) end) data = data:gsub(verbatimtex_etex, function(str) - return format("VerbatimTeX(\"%s\")",protecttexcontents(str)) + return format("verbatimtex %s etex;", -- semicolon + luamplib.verbatiminput and str or protect_expansion(str)) end) - return data -end + if not luamplib.verbatiminput then + data = data:gsub("\".-\"", protect_expansion) + data = data:gsub("%%.-\n","") + run_tex_code(format("\\toks0\\expanded{{%s}}",data)) + data = texgettoks(0) + data = data:gsub("##", "#") + data = data:gsub("\".-\"", unprotect_expansion) + data = data:gsub(btex_etex, function(str) + return format("btex %s etex", unprotect_expansion(str)) + end) + data = data:gsub(verbatimtex_etex, function(str) + return format("verbatimtex %s etex", unprotect_expansion(str)) + end) + end -local function protecttextextVerbatim(data) - data = protect_tex_text_common(data) + process(data) +end +luamplib.process_mplibcode = process_mplibcode - data = data:gsub("\"[^\n]-\"", function(str) -- restore string btex .. etex - return str:gsub("([bem])"..esctex, "%1tex") - end) +local further_split_keys = { + ["mplibtexboxid"] = true, + ["sh_color_a"] = true, + ["sh_color_b"] = true, +} - local _,result = process(data, false) - domakeTEXboxes(result) - return data +local function script2table(s) + local t = {} + for _,i in ipairs(s:explode("\13+")) do + local k,v = i:match("(.-)=(.*)") -- v may contain = or empty. + if k and v and k ~= "" then + if further_split_keys[k] then + t[k] = v:explode(":") + else + t[k] = v + end + end + end + return t end -luamplib.protecttextextVerbatim = protecttextextVerbatim +local function getobjects(result,figure,f) + return figure:objects() +end -luamplib.mpxcolors = {} +local function convert(result, flusher) + luamplib.flush(result, flusher) + return true -- done +end +luamplib.convert = convert -local function protecttextext(data) - data = protect_tex_text_common(data) +local function pdf_startfigure(n,llx,lly,urx,ury) + texsprint(format("\\mplibstarttoPDF{%f}{%f}{%f}{%f}",llx,lly,urx,ury)) +end - data = data:gsub("\"[^\n]-\"", function(str) - str = str:gsub("([bem])"..esctex, "%1tex") - :gsub("%%", escpcnt) - :gsub("{", esclbr) - :gsub("}", escrbr) - :gsub("#", eschash) - return format("\\detokenize{%s}",str) - end) +local function pdf_stopfigure() + texsprint("\\mplibstoptoPDF") +end - data = data:gsub("%%.-\n", "") +local function pdf_literalcode(fmt,...) -- table + textprint({"\\mplibtoPDF{"},{-2,format(fmt,...)},{"}"}) +end - local grouplevel = tex.currentgrouplevel - luamplib.mpxcolors[grouplevel] = {} - data = data:gsub("\\mpcolor"..endname.."(.-){(.-)}", function(opt,str) - local cnt = #luamplib.mpxcolors[grouplevel] + 1 - luamplib.mpxcolors[grouplevel][cnt] = format( - "\\expandafter\\mplibcolor\\csname mpxcolor%i:%i\\endcsname%s{%s}", - grouplevel,cnt,opt,str) - return format("\\csname mpxcolor%i:%i\\endcsname",grouplevel,cnt) +local function pdf_textfigure(font,size,text,width,height,depth) + text = text:gsub(".",function(c) + return format("\\hbox{\\char%i}",string.byte(c)) -- kerning happens in metapost end) + texsprint(format("\\mplibtextext{%s}{%f}{%s}{%s}{%f}",font,size,text,0,-( 7200/ 7227)/65536*depth)) +end + +local bend_tolerance = 131/65536 - data = data:gsub("([^`\\])#","%1##") +local rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1 - texsprint(data) +local function pen_characteristics(object) + local t = mplib.pen_info(object) + rx, ry, sx, sy, tx, ty = t.rx, t.ry, t.sx, t.sy, t.tx, t.ty + divider = sx*sy - rx*ry + return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width end -luamplib.protecttextext = protecttextext - -local function makeTEXboxes (data) - data = data:gsub("##","#") - :gsub(escpcnt,"%%") - :gsub(esclbr,"{") - :gsub(escrbr,"}") - :gsub(eschash,"#") - local _,result = process(data, false) - domakeTEXboxes(result) - return data +local function concat(px, py) -- no tx, ty here + return (sy*px-ry*py)/divider,(sx*py-rx*px)/divider end -luamplib.makeTEXboxes = makeTEXboxes +local function curved(ith,pth) + local d = pth.left_x - ith.right_x + if abs(ith.right_x - ith.x_coord - d) <= bend_tolerance and abs(pth.x_coord - pth.left_x - d) <= bend_tolerance then + d = pth.left_y - ith.right_y + if abs(ith.right_y - ith.y_coord - d) <= bend_tolerance and abs(pth.y_coord - pth.left_y - d) <= bend_tolerance then + return false + end + end + return true +end -local factor = 65536*(7227/7200) +local function flushnormalpath(path,open) + local pth, ith + for i=1,#path do + pth = path[i] + if not ith then + pdf_literalcode("%f %f m",pth.x_coord,pth.y_coord) + elseif curved(ith,pth) then + pdf_literalcode("%f %f %f %f %f %f c",ith.right_x,ith.right_y,pth.left_x,pth.left_y,pth.x_coord,pth.y_coord) + else + pdf_literalcode("%f %f l",pth.x_coord,pth.y_coord) + end + ith = pth + end + if not open then + local one = path[1] + if curved(pth,one) then + pdf_literalcode("%f %f %f %f %f %f c",pth.right_x,pth.right_y,one.left_x,one.left_y,one.x_coord,one.y_coord ) + else + pdf_literalcode("%f %f l",one.x_coord,one.y_coord) + end + elseif #path == 1 then -- special case .. draw point + local one = path[1] + pdf_literalcode("%f %f l",one.x_coord,one.y_coord) + end +end -local function processwithTEXboxes (data) - if not data then return end - local num = texboxnum[2] - local prepreamble = format("TEXBOX_:=%i;\n",num) - while true do - num = num + 1 - local box = texgetbox(num) - if not box then break end - prepreamble = format( - "%sTEXBOX_wd_[%i]:=%f;\nTEXBOX_ht_[%i]:=%f;\nTEXBOX_dp_[%i]:=%f;\n", - prepreamble, - num, box.width /factor, - num, box.height/factor, - num, box.depth /factor) +local function flushconcatpath(path,open) + pdf_literalcode("%f %f %f %f %f %f cm", sx, rx, ry, sy, tx ,ty) + local pth, ith + for i=1,#path do + pth = path[i] + if not ith then + pdf_literalcode("%f %f m",concat(pth.x_coord,pth.y_coord)) + elseif curved(ith,pth) then + local a, b = concat(ith.right_x,ith.right_y) + local c, d = concat(pth.left_x,pth.left_y) + pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(pth.x_coord, pth.y_coord)) + else + pdf_literalcode("%f %f l",concat(pth.x_coord, pth.y_coord)) + end + ith = pth + end + if not open then + local one = path[1] + if curved(pth,one) then + local a, b = concat(pth.right_x,pth.right_y) + local c, d = concat(one.left_x,one.left_y) + pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(one.x_coord, one.y_coord)) + else + pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord)) + end + elseif #path == 1 then -- special case .. draw point + local one = path[1] + pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord)) end - process(prepreamble .. data, true) end -luamplib.processwithTEXboxes = processwithTEXboxes local pdfoutput = tonumber(texget("outputmode")) or tonumber(texget("pdfoutput")) local pdfmode = pdfoutput > 0 @@ -796,8 +797,8 @@ local function stop_pdf_code() end end -local function putTEXboxes (object,prescript) - local box = prescript.MPlibTEXboxID +local function put_tex_boxes (object,prescript) + local box = prescript.mplibtexboxid local n,tw,th = box[1],tonumber(box[2]),tonumber(box[3]) if n and tw and th then local op = object.path @@ -833,7 +834,6 @@ else "\\special{pdf:obj @MPlibSh<<>>}") end --- objstr => obj , new local function update_pdfobjs (os) local on = pdf_objs[os] if on then @@ -907,7 +907,7 @@ local shading_res local function shading_initialize () shading_res = {} - if pdfmode and luatexbase.callbacktypes and luatexbase.callbacktypes.finish_pdffile then -- ltluatex + if pdfmode and luatexbase.callbacktypes.finish_pdffile then -- ltluatex local shading_obj = pdf.reserveobj() setpageres(format("%s/Shading %i 0 R",getpageres() or "",shading_obj)) luatexbase.add_to_callback("finish_pdffile", function() @@ -932,7 +932,7 @@ local function sh_pdfpageresources(shtype,domain,colorspace,colora,colorb,coordi shading_res[#shading_res+1] = res else local pageres = getpageres() or "" - if not stringfind(pageres,"/Shading<<.*>>") then + if not pageres:find("/Shading<<.*>>") then pageres = pageres.."/Shading<<>>" end pageres = pageres:gsub("/Shading<<","%1"..res) @@ -963,7 +963,6 @@ end local prev_override_color local function do_preobj_color(object,prescript) - -- transparency local opaq = prescript and prescript.tr_transparency local tron_no, troff_no if opaq then @@ -972,7 +971,6 @@ local function do_preobj_color(object,prescript) tron_no, troff_no = tr_pdf_pageresources(mode,opaq) pdf_literalcode("/MPlibTr%i gs",tron_no) end - -- color local override = prescript and prescript.MPlibOverrideColor if override then if pdfmode then @@ -994,12 +992,11 @@ local function do_preobj_color(object,prescript) end end end - -- shading local sh_type = prescript and prescript.sh_type if sh_type then local domain = prescript.sh_domain - local centera = stringexplode(prescript.sh_center_a) - local centerb = stringexplode(prescript.sh_center_b) + local centera = prescript.sh_center_a:explode() + local centerb = prescript.sh_center_b:explode() for _,t in pairs({centera,centerb}) do for i,v in ipairs(t) do t[i] = format("%f",v) @@ -1055,7 +1052,6 @@ local function do_postobj_color(tr,over,sh) end end - local function flush(result,flusher) if result then local figures = result.fig @@ -1064,19 +1060,16 @@ local function flush(result,flusher) info("flushing figure %s",f) local figure = figures[f] local objects = getobjects(result,figure,f) - local fignum = tonumber(stringmatch(figure:filename(),"([%d]+)$") or figure:charcode() or 0) + local fignum = tonumber(figure:filename():match("([%d]+)$") or figure:charcode() or 0) local miterlimit, linecap, linejoin, dashed = -1, -1, -1, false local bbox = figure:boundingbox() local llx, lly, urx, ury = bbox[1], bbox[2], bbox[3], bbox[4] -- faster than unpack if urx < llx then - -- invalid - -- pdf_startfigure(fignum,0,0,0,0) - -- pdf_stopfigure() else - if TeX_code_t[f] then - texsprint(TeX_code_t[f]) + if tex_code_pre_mplib[f] then + texsprint(tex_code_pre_mplib[f]) end - local TeX_code_bot = {} -- PostVerbatimTeX + local TeX_code_bot = {} pdf_startfigure(fignum,llx,lly,urx,ury) start_pdf_code() if objects then @@ -1088,12 +1081,9 @@ local function flush(result,flusher) local prescript = object.prescript prescript = prescript and script2table(prescript) -- prescript is now a table local tr_opaq,cr_over,shade_no = do_preobj_color(object,prescript) - if prescript and prescript.MPlibTEXboxID then - putTEXboxes(object,prescript) - elseif prescript and prescript.PostMPlibVerbTeX then - TeX_code_bot[#TeX_code_bot+1] = prescript.PostMPlibVerbTeX - elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then - -- skip + if prescript and prescript.mplibtexboxid then + put_tex_boxes(object,prescript) + elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then --skip elseif objecttype == "start_clip" then local evenodd = not object.istext and object.postscript == "evenodd" start_pdf_code() @@ -1103,9 +1093,8 @@ local function flush(result,flusher) stop_pdf_code() miterlimit, linecap, linejoin, dashed = -1, -1, -1, false elseif objecttype == "special" then - -- not supported - if prescript and prescript.MPlibTEXError then - warn("textext() anomaly. Try disabling \\mplibtextextlabel.") + if prescript and prescript.postmplibverbtex then + TeX_code_bot[#TeX_code_bot+1] = prescript.postmplibverbtex end elseif objecttype == "text" then local ot = object.transform -- 3,4,5,6,1,2 @@ -1198,7 +1187,7 @@ local function flush(result,flusher) else flushnormalpath(path,open) end - if not shade_no then ----- conflict with shading + if not shade_no then -- conflict with shading if objecttype == "fill" then pdf_literalcode(evenodd and "h f*" or "h f") elseif objecttype == "outline" then @@ -1255,9 +1244,7 @@ local function flush(result,flusher) end stop_pdf_code() pdf_stopfigure() - if #TeX_code_bot > 0 then - texsprint(TeX_code_bot) - end + if #TeX_code_bot > 0 then texsprint(TeX_code_bot) end end end end diff --git a/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty b/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty index fa85ecc852a..dfca44a5c3e 100644 --- a/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty +++ b/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty @@ -14,7 +14,7 @@ \else \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{luamplib} - [2018/09/27 v2.12.5 mplib package for LuaTeX] + [2019/03/20 v2.20.0 mplib package for LuaTeX] \ifx\newluafunction\@undefined \input ltluatex \fi @@ -26,8 +26,8 @@ \ifx\pdfoutput\undefined \let\pdfoutput\outputmode \protected\def\pdfliteral{\pdfextension literal} + \def\pdffontsize{\dimexpr\pdffeedback fontsize\relax} \fi - \def\mplibsetformat#1{\directlua{luamplib.setformat("#1")}} \ifnum\pdfoutput>0 \let\mplibtoPDF\pdfliteral @@ -41,8 +41,11 @@ \write128{} \fi \fi +\def\mplibforcehmode{\let\mplibhmodeornot\leavevmode} +\def\mplibnoforcehmode{\let\mplibhmodeornot\relax} +\mplibnoforcehmode \def\mplibsetupcatcodes{% - %catcode`\{=12 %catcode`\}=12 + \mplibhmodeornot %catcode`\{=12 %catcode`\}=12 \catcode`\#=12 \catcode`\^=12 \catcode`\~=12 \catcode`\_=12 \catcode`\&=12 \catcode`\$=12 \catcode`\%=12 \catcode`\^^M=12 \endlinechar=10 } @@ -69,15 +72,7 @@ } \long\def\mplibdocode#1\endmplibcode{% \endgroup - \ifdefined\mplibverbatimYes - \directlua{luamplib.tempdata\the\currentgrouplevel=luamplib.protecttextextVerbatim([===[\detokenize{#1}]===])}% - \directlua{luamplib.processwithTEXboxes(luamplib.tempdata\the\currentgrouplevel)}% - \else - \edef\mplibtemp{\directlua{luamplib.protecttextext([===[\unexpanded{#1}]===])}}% - \directlua{ tex.sprint(luamplib.mpxcolors[\the\currentgrouplevel]) }% - \directlua{luamplib.tempdata\the\currentgrouplevel=luamplib.makeTEXboxes([===[\mplibtemp]===])}% - \directlua{luamplib.processwithTEXboxes(luamplib.tempdata\the\currentgrouplevel)}% - \fi + \directlua{luamplib.process_mplibcode([===[\unexpanded{#1}]===])}% \endgroup \ifnum\mplibstartlineno<\inputlineno\expandafter\mplibreplacenewlinecs\fi } @@ -95,16 +90,9 @@ \long\def\ltxdomplibcodeindeed#1\end#2{% \endgroup \toks@\expandafter{\the\toks@#1}% - \def\mplibtemp@a{#2}\ifx\mplib@mplibcode\mplibtemp@a - \ifdefined\mplibverbatimYes - \directlua{luamplib.tempdata\the\currentgrouplevel=luamplib.protecttextextVerbatim([===[\the\toks@]===])}% - \directlua{luamplib.processwithTEXboxes(luamplib.tempdata\the\currentgrouplevel)}% - \else - \edef\mplibtemp{\directlua{luamplib.protecttextext([===[\the\toks@]===])}}% - \directlua{ tex.sprint(luamplib.mpxcolors[\the\currentgrouplevel]) }% - \directlua{luamplib.tempdata\the\currentgrouplevel=luamplib.makeTEXboxes([===[\mplibtemp]===])}% - \directlua{luamplib.processwithTEXboxes(luamplib.tempdata\the\currentgrouplevel)}% - \fi + \def\mplibtemp@a{#2}% + \ifx\mplib@mplibcode\mplibtemp@a + \directlua{luamplib.process_mplibcode([===[\the\toks@]===])}% \end{mplibcode}% \ifnum\mplibstartlineno<\inputlineno \expandafter\expandafter\expandafter\mplibreplacenewlinebr @@ -114,16 +102,23 @@ \fi } \fi -\def\mplibverbatim#1{% - \begingroup - \def\mplibtempa{#1}\def\mplibtempb{enable}% - \expandafter\endgroup - \ifx\mplibtempa\mplibtempb - \let\mplibverbatimYes\relax - \else - \let\mplibverbatimYes\undefined - \fi -} +\def\mpliblegacybehavior#1{\directlua{ + local s = string.lower("#1") + if s == "enable" or s == "true" or s == "yes" then + luamplib.legacy_verbatimtex = true + else + luamplib.legacy_verbatimtex = false + end +}} +\def\mplibverbatim#1{\directlua{ + local s = string.lower("#1") + if s == "enable" or s == "true" or s == "yes" then + luamplib.verbatiminput = true + else + luamplib.verbatiminput = false + end +}} +\newtoks\mplibtmptoks \newtoks\everymplibtoks \newtoks\everyendmplibtoks \protected\def\everymplib{% @@ -149,11 +144,11 @@ \ifnum\mplibstartlineno<\inputlineno\expandafter\mplibreplacenewlinebr\fi } \def\mpdim#1{ begingroup \the\dimexpr #1\relax\space endgroup } % gmp.sty -\def\mplibcolor#1{% - \def\set@color{\edef#1{1 withprescript "MPlibOverrideColor=\current@color"}}% - \color -} -\def\mplibnumbersystem#1{\directlua{luamplib.numbersystem = "#1"}} +\def\mplibnumbersystem#1{\directlua{ + local t = "#1" + if t == "binary" then t = "decimal" end + luamplib.numbersystem = t +}} \def\mplibmakenocache#1{\mplibdomakenocache #1,*,} \def\mplibdomakenocache#1,{% \ifx\empty#1\empty @@ -177,36 +172,30 @@ \fi } \def\mplibcachedir#1{\directlua{luamplib.getcachedir("\unexpanded{#1}")}} -\def\mplibtextextlabel#1{% - \begingroup - \def\tempa{enable}\def\tempb{#1}% - \ifx\tempa\tempb - \directlua{luamplib.textextlabel = true}% - \else - \directlua{luamplib.textextlabel = false}% - \fi - \endgroup -} -\def\mplibcodeinherit#1{% - \begingroup - \def\tempa{enable}\def\tempb{#1}% - \ifx\tempa\tempb - \directlua{luamplib.codeinherit = true}% - \else - \directlua{luamplib.codeinherit = false}% - \fi - \endgroup -} -\def\mplibglobaltextext#1{% - \begingroup - \def\tempa{enable}\def\tempb{#1}% - \ifx\tempa\tempb - \directlua{luamplib.globaltextext = true}% - \else - \directlua{luamplib.globaltextext = false}% - \fi - \endgroup -} +\def\mplibtextextlabel#1{\directlua{ + local s = string.lower("#1") + if s == "enable" or s == "true" or s == "yes" then + luamplib.textextlabel = true + else + luamplib.textextlabel = false + end +}} +\def\mplibcodeinherit#1{\directlua{ + local s = string.lower("#1") + if s == "enable" or s == "true" or s == "yes" then + luamplib.codeinherit = true + else + luamplib.codeinherit = false + end +}} +\def\mplibglobaltextext#1{\directlua{ + local s = string.lower("#1") + if s == "enable" or s == "true" or s == "yes" then + luamplib.globaltextext = true + else + luamplib.globaltextext = false + end +}} \ifx\mplibscratchbox\undefined \newbox\mplibscratchbox \fi \def\mplibstarttoPDF#1#2#3#4{% \hbox\bgroup -- cgit v1.2.3