diff options
Diffstat (limited to 'macros')
196 files changed, 4806 insertions, 2351 deletions
diff --git a/macros/latex/base/README.md b/macros/latex/base/README.md index d566ca97ce..7c6328be6d 100644 --- a/macros/latex/base/README.md +++ b/macros/latex/base/README.md @@ -1,7 +1,7 @@ The LaTeX kernel ================ -Release 2020-10-01 patch level 2 +Release 2020-10-01 patch level 3 Overview -------- diff --git a/macros/latex/base/alltt.pdf b/macros/latex/base/alltt.pdf Binary files differindex dce36a436c..5cb6410fa1 100644 --- a/macros/latex/base/alltt.pdf +++ b/macros/latex/base/alltt.pdf diff --git a/macros/latex/base/cfgguide.pdf b/macros/latex/base/cfgguide.pdf Binary files differindex 2f9e6e9974..c0cb3f3c6f 100644 --- a/macros/latex/base/cfgguide.pdf +++ b/macros/latex/base/cfgguide.pdf diff --git a/macros/latex/base/changes.txt b/macros/latex/base/changes.txt index 29f3d2937f..cc8d59b61b 100644 --- a/macros/latex/base/changes.txt +++ b/macros/latex/base/changes.txt @@ -11,6 +11,78 @@ All changes above are only part of the development branch for the next release. ================================================================================ ######################### +# 2020-10-01 PL 3 Release +######################### + +2020-12-18 Phelype Oleinik <phelype.oleinik@latex-project.org> + + * lthooks.dtx: + Moved 'top-level' code label at the very end of hooks. + - In reverse hooks, 'top-level' goes at the beginning. + - 'top-level' cannot be used as a label outside of the top-level. + - The label for the 'top-level' cannot be changed. + - Simplified internal managing of default label. + Renamed \DeclareDefaultHookLabel to \SetDefaultHookLabel (the old name + will be kept until the next release). + Provide \PushDefaultHookLabel and \PopDefaultHookLabel. + Fixed a small bug in \ShowHook and \LogHook. + + * ltclass.dtx: + Remove \@expl@@@hook@curr@name@push@@n from \@pushfilename to + follow changes to lthooks.dtx. + +2020-12-10 Frank Mittelbach <Frank.Mittelbach@latex-project.org> + + * ltfssbas.dtx (subsection{Macros for the user}): + Drop ``m'' if the series value is a member of a fixed list + and issue warning if doing it (gh/453) + +2020-11-24 Frank Mittelbach <Frank.Mittelbach@latex-project.org> + + * latexrelease.ins: + reorder module loading to match the order used + in the format to correctly resolve dependencies (gh/434) + + * ltexpl.dtx (subsection{Loader}): + Load xparse in latexrelease if necessary and add missing + IncludeInRelease guards (gh/434) + + * ltdefns.dtx, ltfilehook.dtx, lthooks.dtx, ltxshipout.dtx: + Add rollback support for forward case (gh/434) + +2020-11-20 Phelype Oleinik <phelype.oleinik@latex-project.org> + + * ltclass.dtx: + Remove file path from \@currname and use only \@currname to identify + a package internally (gh/422). + Add \@currpath and (temporarily) \@kernel@currpathstack. + In \ProvidesPackage check the argument with \strcmp instead of \ifx. + In case of substitution, copy the option list to the requested package. + + * ltfilehook.dtx: + Keep path in the replacement file (#2) in \declare@file@substitution. + In case of a replacement, pass the actually loaded file to \@addtofilelist. + Explicitly clear replacement flag after using it. + +2020-11-17 Frank Mittelbach <Frank.Mittelbach@latex-project.org> + + * fntguide.tex: + Updated documentation of virtual shapes \updefault and \ulcdefault + +2020-11-09 Frank Mittelbach <Frank.Mittelbach@latex-project.org> + + * ltmath.dtx: + \negmedspace and \negthickspace have been only in amsmath, + so we need to undefine for rollback because amsmath used + \newcommand back then (gh/423) + +2020-11-09 Frank Mittelbach <Frank.Mittelbach@latex-project.org> + + * ltclass.dtx (section{Package/class rollback mechanism}): + Change help text for suspicous rollback, because the package may have + existed then --- there is just no rollback data (gh/423) + +######################### # 2020-10-01 PL 2 Release ######################### diff --git a/macros/latex/base/classes.pdf b/macros/latex/base/classes.pdf Binary files differindex b0be55c53f..05b9379ef4 100644 --- a/macros/latex/base/classes.pdf +++ b/macros/latex/base/classes.pdf diff --git a/macros/latex/base/clsguide.pdf b/macros/latex/base/clsguide.pdf Binary files differindex 1a7e752cc3..c5d32dda9f 100644 --- a/macros/latex/base/clsguide.pdf +++ b/macros/latex/base/clsguide.pdf diff --git a/macros/latex/base/cmfonts.pdf b/macros/latex/base/cmfonts.pdf Binary files differindex c3502760ce..fe8f0083f6 100644 --- a/macros/latex/base/cmfonts.pdf +++ b/macros/latex/base/cmfonts.pdf diff --git a/macros/latex/base/cyrguide.pdf b/macros/latex/base/cyrguide.pdf Binary files differindex 1331bbc54f..6fa40a338b 100644 --- a/macros/latex/base/cyrguide.pdf +++ b/macros/latex/base/cyrguide.pdf diff --git a/macros/latex/base/doc.pdf b/macros/latex/base/doc.pdf Binary files differindex dcb78001b3..5feed95398 100644 --- a/macros/latex/base/doc.pdf +++ b/macros/latex/base/doc.pdf diff --git a/macros/latex/base/docstrip.pdf b/macros/latex/base/docstrip.pdf Binary files differindex aeda25af00..2e31d253a1 100644 --- a/macros/latex/base/docstrip.pdf +++ b/macros/latex/base/docstrip.pdf diff --git a/macros/latex/base/encguide.pdf b/macros/latex/base/encguide.pdf Binary files differindex 286a167553..249493684e 100644 --- a/macros/latex/base/encguide.pdf +++ b/macros/latex/base/encguide.pdf diff --git a/macros/latex/base/exscale.pdf b/macros/latex/base/exscale.pdf Binary files differindex 8d33cdefab..339a4d161a 100644 --- a/macros/latex/base/exscale.pdf +++ b/macros/latex/base/exscale.pdf diff --git a/macros/latex/base/fix-cm.pdf b/macros/latex/base/fix-cm.pdf Binary files differindex 07ff74d687..f39aca2525 100644 --- a/macros/latex/base/fix-cm.pdf +++ b/macros/latex/base/fix-cm.pdf diff --git a/macros/latex/base/fntguide.pdf b/macros/latex/base/fntguide.pdf Binary files differindex b3824b59a1..97c8a844f7 100644 --- a/macros/latex/base/fntguide.pdf +++ b/macros/latex/base/fntguide.pdf diff --git a/macros/latex/base/fntguide.tex b/macros/latex/base/fntguide.tex index b6576a0237..7e0928c51b 100644 --- a/macros/latex/base/fntguide.tex +++ b/macros/latex/base/fntguide.tex @@ -42,7 +42,7 @@ newer NFSS features of 2020}\\ All rights reserved.} -\date{July 2020} +\date{November 2020} \begin{document} @@ -340,22 +340,25 @@ box warning, for example: \end{verbatim} The author commands for fonts set the five attributes: \begin{center} + \hspace*{-1em}% \begin{tabular}{rcl} \emph{Author command} & \emph{Attribute} & \emph{Value in} |article| \emph{class} \\ |\textnormal{..}| or |\normalfont| & family & |cmr| \\ + & series & |m| \\ + & shape & |n| \\[1pt] |\textrm{..}| or |\rmfamily| & family & |cmr| \\ |\textsf{..}| or |\sffamily| & family & |cmss| \\ |\texttt{..}| or |\ttfamily| & family & |cmtt| \\ |\textmd{..}| or |\mdseries| & series & |m| \\ - |\textbf{..}| or |\bfseries| & series & |bx| \\ - |\textup{..}| or |\upshape| & shape & |n| \\ + |\textbf{..}| or |\bfseries| & series & |bx| \\[1pt] |\textit{..}| or |\itshape| & shape & |it| \\ |\textsl{..}| or |\slshape| & shape & |sl| \\ |\textsc{..}| or |\scshape| & shape & |sc| \\ |\textssc{..}| or |\sscshape| & shape & |ssc| \\ |\textsw{..}| or |\swshape| & shape & |sw| \\ - |\textulc{..}| or |\ulcshape| & shape & |ulc| \\ + |\textulc{..}| or |\ulcshape| & shape & |ulc| (virtual) $\to$ |n|, |it|, |sl| or |ssc| \\ + |\textup{..}| or |\upshape| & shape & |up| (virtual) $\to$ |n| or |sc| \\[1pt] |\tiny| & size & |5pt| \\ |\scriptsize| & size & |7pt| \\ |\footnotesize| & size & |8pt| \\ @@ -520,8 +523,9 @@ and the |ssub| size function, see Section~\ref{sec:sizefunct}. The shapes selected by |\textit|, |\itshape|, |\textsl|, |\slshape|, |\textsc|, |\scshape|, |\textssc|, |\sscshape|, |\textsw|, |\swshape|, |\textulc|, |\ulcshape|, |\textup| and |\upshape|. By default these are -|it|, |sl|, |sc|, |ssc|, |sw|, |ulc| and |n|. |ulc| is special here -since it is a virtual one; it doesn't exist as a real shape. The +|it|, |sl|, |sc|, |ssc|, |sw|, |ulc| and |up|. Note that |ulc| and |up| are special here +because they are virtual shapes; they don't exist as real shape values. Instead they alter +the existing shape value based on rules, i.e., the result depends on context. The respective macros |\textulc| or |\ulcshape| change small capitals back to upper/lower case but will not change the font with respect to italics, slanted or swash. |\upshape| or |\textup| in contrast will diff --git a/macros/latex/base/graphpap.pdf b/macros/latex/base/graphpap.pdf Binary files differindex 8ebd4c91d3..8cad84bb4c 100644 --- a/macros/latex/base/graphpap.pdf +++ b/macros/latex/base/graphpap.pdf diff --git a/macros/latex/base/ifthen.pdf b/macros/latex/base/ifthen.pdf Binary files differindex 6218e4883a..be2ea9f956 100644 --- a/macros/latex/base/ifthen.pdf +++ b/macros/latex/base/ifthen.pdf diff --git a/macros/latex/base/inputenc.pdf b/macros/latex/base/inputenc.pdf Binary files differindex 0ee0cdd0ff..4c06af39d5 100644 --- a/macros/latex/base/inputenc.pdf +++ b/macros/latex/base/inputenc.pdf diff --git a/macros/latex/base/latexchanges.pdf b/macros/latex/base/latexchanges.pdf Binary files differindex d78a1e3b5a..97fcc3330b 100644 --- a/macros/latex/base/latexchanges.pdf +++ b/macros/latex/base/latexchanges.pdf diff --git a/macros/latex/base/latexrelease.ins b/macros/latex/base/latexrelease.ins index 99af17e8fb..ffc92374c3 100644 --- a/macros/latex/base/latexrelease.ins +++ b/macros/latex/base/latexrelease.ins @@ -81,11 +81,16 @@ extension .ins) which are part of the distribution. %\keepsilent \usedir{tex/latex/base} +% the order should match the order in the format in case there are dependencies +% (something defined in one module and used in another) + \generateFile{latexrelease.sty}{t}{% \from{ltclass.dtx} {latexreleasefirst,tracerollback}% \from{ltvers.dtx} {latexrelease}% \from{latexrelease.dtx}{latexrelease}% \from{ltdirchk.dtx} {latexrelease}% + \from{ltplain.dtx} {latexrelease}% + \from{ltluatex.dtx} {latexrelease}% empty \from{ltexpl.dtx} {latexrelease}% empty \from{ltdefns.dtx} {latexrelease}% \from{lthooks.dtx} {latexrelease}% empty % L3 layer module @@ -93,42 +98,39 @@ extension .ins) which are part of the distribution. \from{ltcntrl.dtx} {latexrelease}% empty \from{lterror.dtx} {latexrelease}% empty \from{ltpar.dtx} {latexrelease}% empty + \from{ltspace.dtx} {latexrelease}% + \from{ltlogos.dtx} {latexrelease}% empty + \from{ltfiles.dtx} {latexrelease}% + \from{ltoutenc.dtx} {latexrelease}% + \from{ltcounts.dtx} {latexrelease}% + \from{ltlength.dtx} {latexrelease}% + \from{ltfssbas.dtx} {latexrelease}% + \from{ltfssaxes.dtx} {latexrelease}% + \from{ltfsstrc.dtx} {latexrelease}% + \from{ltfssdcl.dtx} {latexrelease}% + \from{ltfssini.dtx} {latexrelease}% + \from{fontdef.dtx} {latexrelease}% (covering fontmath and fonttext) + \from{ltfntcmd.dtx} {latexrelease}% empty + \from{lttextcomp.dtx} {latexrelease}% + \from{ltpageno.dtx} {latexrelease}% empty + \from{ltxref.dtx} {latexrelease}% empty + \from{ltmiscen.dtx} {latexrelease}% + \from{ltmath.dtx} {latexrelease}% \from{ltlists.dtx} {latexrelease}% empty \from{ltboxes.dtx} {latexrelease}% \from{lttab.dtx} {latexrelease}% empty - \from{ltmath.dtx} {latexrelease}% \from{ltpictur.dtx} {latexrelease}% \from{ltthm.dtx} {latexrelease}% empty \from{ltsect.dtx} {latexrelease}% empty - \from{ltfiles.dtx} {latexrelease}% - \from{ltoutenc.dtx} {latexrelease}% - \from{ltcounts.dtx} {latexrelease}% - \from{ltlength.dtx} {latexrelease}% \from{ltfloat.dtx} {latexrelease}% \from{ltidxglo.dtx} {latexrelease}% empty \from{ltbibl.dtx} {latexrelease}% empty \from{ltpage.dtx} {latexrelease}% empty + \from{ltclass.dtx} {latexrelease,tracerollback}% \from{ltfilehook.dtx} {latexrelease}% empty % L3 layer module \from{ltshipout.dtx} {latexrelease}% empty % L3 layer module \from{ltoutput.dtx} {latexrelease}% - \from{ltclass.dtx} {latexrelease,tracerollback}% - \from{ltspace.dtx} {latexrelease}% - \from{ltlogos.dtx} {latexrelease}% empty - \from{ltplain.dtx} {latexrelease}% - \from{ltfssdcl.dtx} {latexrelease}% - \from{ltfssini.dtx} {latexrelease}% - \from{fontdef.dtx} {latexrelease}% (covering fontmath and fonttext) - \from{ltfntcmd.dtx} {latexrelease}% empty - \from{lttextcomp.dtx} {latexrelease}% - \from{ltfssbas.dtx} {latexrelease}% - \from{ltfssaxes.dtx} {latexrelease}% - \from{ltfsstrc.dtx} {latexrelease}% - \from{ltfsscmp.dtx} {latexrelease}% - \from{ltpageno.dtx} {latexrelease}% empty - \from{ltxref.dtx} {latexrelease}% empty - \from{ltmiscen.dtx} {latexrelease}% - \from{ltluatex.dtx} {latexrelease}% - \from{ltexpl.dtx} {latexrelease}% + \from{ltfsscmp.dtx} {latexrelease}% only in latexrelease! \from{ltfinal.dtx} {latexrelease}% } diff --git a/macros/latex/base/latexrelease.pdf b/macros/latex/base/latexrelease.pdf Binary files differindex f458d1a97c..d619076782 100644 --- a/macros/latex/base/latexrelease.pdf +++ b/macros/latex/base/latexrelease.pdf diff --git a/macros/latex/base/latexsym.pdf b/macros/latex/base/latexsym.pdf Binary files differindex 88db5ce701..436ea23f3a 100644 --- a/macros/latex/base/latexsym.pdf +++ b/macros/latex/base/latexsym.pdf diff --git a/macros/latex/base/lb2.pdf b/macros/latex/base/lb2.pdf Binary files differindex 4885ef5646..7d989cb0a0 100644 --- a/macros/latex/base/lb2.pdf +++ b/macros/latex/base/lb2.pdf diff --git a/macros/latex/base/letter.pdf b/macros/latex/base/letter.pdf Binary files differindex 85986ca947..104f1157e2 100644 --- a/macros/latex/base/letter.pdf +++ b/macros/latex/base/letter.pdf diff --git a/macros/latex/base/lgc2.pdf b/macros/latex/base/lgc2.pdf Binary files differindex bfed998126..f900bfefb3 100644 --- a/macros/latex/base/lgc2.pdf +++ b/macros/latex/base/lgc2.pdf diff --git a/macros/latex/base/lppl.pdf b/macros/latex/base/lppl.pdf Binary files differindex 18c3995534..20a630928c 100644 --- a/macros/latex/base/lppl.pdf +++ b/macros/latex/base/lppl.pdf diff --git a/macros/latex/base/ltclass.dtx b/macros/latex/base/ltclass.dtx index b639ae9410..c62136c309 100644 --- a/macros/latex/base/ltclass.dtx +++ b/macros/latex/base/ltclass.dtx @@ -33,7 +33,7 @@ %<*driver> % \fi \ProvidesFile{ltclass.dtx} - [2020/10/18 v1.3t LaTeX Kernel (Class & Package Interface)] + [2020/12/17 v1.3v LaTeX Kernel (Class & Package Interface)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltclass.dtx} @@ -524,6 +524,27 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@currpath} +% Path to the current file if explicitly given. +% \changes{v1.3u}{2020/11/20}{Macro added} +% \begin{macrocode} +%</2ekernel> +%<*2ekernel|latexrelease> +%<latexrelease> +%<latexrelease>\IncludeInRelease{2020/10/01}{\@currpath}% +%<latexrelease> {Add \@currpath}% +\let\@currpath\@empty +%<latexrelease>\EndIncludeInRelease +% +%<latexrelease>\IncludeInRelease{0000/00/00}{\@currpath}% +%<latexrelease> {Add \@currpath}% +%<latexrelease>\let\@currpath\@undefined +%<latexrelease>\EndIncludeInRelease +%</2ekernel|latexrelease> +%<*2ekernel> +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\@currname} % Name of current package or option. % \begin{macrocode} @@ -562,6 +583,7 @@ % \changes{v1.3l}{2020/06/05}{Added \cs{@expl@push@filename@@} % and \cs{@expl@push@filename@aux@@}} % \changes{v1.3s}{2020/10/08}{Added missing 2020/02/02 \cs{IncludeInRelease}} +% \changes{v1.3v}{2020/12/14}{Removed \cs{@expl@@@hook@curr@name@push@@n}} % \begin{macrocode} %</2ekernel> %<*2ekernel|latexrelease> @@ -578,13 +600,22 @@ % here, e.g., \cs{@expl@push@filename@@} needs cleanup and (and % should probably not have this name either). % \begin{macrocode} - \@expl@@@hook@curr@name@push@@n{}% \@expl@push@filename@@ \xdef\@currnamestack{% {\@currname}% {\@currext}% {\the\catcode`\@}% \@currnamestack}% +% \end{macrocode} +% Temporarily add a stack for \cs{@currpath} here. This should be +% integrated in the main file stack eventually, but other packages +% rely on \cs{@currnamestack} having three elements per file, so that +% isn't a trivial change. The prefix \cs{@kernel@...} hopefully +% discourages people from using it. +% \begin{macrocode} + \xdef\@kernel@currpathstack{% + {\@currpath}% + \@kernel@currpathstack}% \@expl@push@filename@aux@@} %<latexrelease>\EndIncludeInRelease % \end{macrocode} @@ -632,6 +663,10 @@ %<latexrelease> {Add \@expl@pop@filename@@}% \def\@popfilename{\@expl@@@hook@curr@name@pop@@ \expandafter\@p@pfilename\@currnamestack\@nil +% \end{macrocode} +% Same for popping: +% \begin{macrocode} + \expandafter\@p@pfilepath\@kernel@currpathstack\@nil \@expl@pop@filename@@} %<latexrelease>\EndIncludeInRelease %<latexrelease> @@ -672,6 +707,36 @@ % \end{macro} % \end{macro} % +% +% \begin{macro}{\@kernel@currpathstack} +% Path to the current file if explicitly given. The auxiliary is +% needed here to insert a \cs{@empty} to prevent the loss of braces. +% \changes{v1.3u}{2020/11/20}{Macro added} +% \begin{macrocode} +%</2ekernel> +%<*2ekernel|latexrelease> +%<latexrelease> +%<latexrelease>\IncludeInRelease{2020/10/01}{\@kernel@currpathstack}% +%<latexrelease> {Add \@kernel@currpathstack}% +\gdef\@kernel@currpathstack{} +\def\@p@pfilepath#1{% + \gdef\@currpath{#1}\@p@pfilepath@aux\@empty} +\def\@p@pfilepath@aux#1\@nil{% + \xdef\@kernel@currpathstack{#1}} +%<latexrelease>\EndIncludeInRelease +% +%<latexrelease>\IncludeInRelease{0000/00/00}{\@kernel@currpathstack}% +%<latexrelease> {Add \@kernel@currpathstack}% +%<latexrelease>\let\@kernel@currpathstack\@undefined +%<latexrelease>\let\@p@pfilepath\@undefined +%<latexrelease>\let\@p@pfilepath@aux\@undefined +%<latexrelease>\EndIncludeInRelease +%</2ekernel|latexrelease> +%<*2ekernel> +% \end{macrocode} +% \end{macro} +% +% % \begin{macro}{\@ptionlist} % Returns the option list of the file. % \begin{macrocode} @@ -915,15 +980,42 @@ % \changes{v0.3c}{1994/03/12} % {use \cs{@gtempa}} % \begin{macrocode} +%</2ekernel> +%<latexrelease>\IncludeInRelease{2020/10/01}% +%<latexrelease> {\ProvidesPackage}{Check name with \strcmp}% +%<*2ekernel|latexrelease> \def\ProvidesPackage#1{% \xdef\@gtempa{#1}% - \ifx\@gtempa\@currname\else +% \end{macrocode} +% \changes{v1.3u}{2020/11/20} +% {Use string comparison instead of \cs{ifx}} +% Here \cs{@currpath} is explicitly added to the file name to report +% when a package or class is loaded using an explicit path. Loading +% using a path in the argument is supported but not encouraged. +% \begin{macrocode} + \@expandtwoargs\@expl@str@if@eq@@nnTF + {\@gtempa}{\@currpath\@currname}{}{% \@latex@warning@no@line{You have requested - \@cls@pkg\space`\@currname',\MessageBreak + \@cls@pkg\space`\@currpath\@currname',\MessageBreak but the \@cls@pkg\space provides `#1'}% - \fi + }% \@ifnextchar[\@pr@videpackage{\@pr@videpackage[]}}%] \@onlypreamble\ProvidesPackage +%</2ekernel|latexrelease> +%<latexrelease>\EndIncludeInRelease +% +%<latexrelease>\IncludeInRelease{0000/00/00}% +%<latexrelease> {\ProvidesPackage}{Undo: check name with \strcmp}% +%<latexrelease>\def\ProvidesPackage#1{% +%<latexrelease> \xdef\@gtempa{#1}% +%<latexrelease> \ifx\@gtempa\@currname\else +%<latexrelease> \@latex@warning@no@line{You have requested +%<latexrelease> \@cls@pkg\space`\@currname',\MessageBreak +%<latexrelease> but the \@cls@pkg\space provides `#1'}% +%<latexrelease> \fi +%<latexrelease> \@ifnextchar[\@pr@videpackage{\@pr@videpackage[]}}%] +%<latexrelease>\EndIncludeInRelease +%<*2ekernel> % \end{macrocode} % \end{macro} % @@ -1007,9 +1099,18 @@ % % \begin{macro}{\ProvidesClass} % Like |\ProvidesPackage|, but for classes. +% This needs a dummy \pkg{latexrelease} block to copy the definition +% of \cs{ProvidesPackage} as it changes across releases. % \begin{macrocode} +%</2ekernel> +%<latexrelease>\IncludeInRelease{0000/00/00}% +%<latexrelease> {\ProvidesClass}{Track \ProvidesPackage}% +%<*2ekernel|latexrelease> \let\ProvidesClass\ProvidesPackage \@onlypreamble\ProvidesClass +%</2ekernel|latexrelease> +%<latexrelease>\EndIncludeInRelease +%<*2ekernel> % \end{macrocode} % \end{macro} % @@ -1075,10 +1176,18 @@ \@expl@@@filehook@set@curr@file@@nNN {\@expl@@@filehook@resolve@file@subst@@w #3.#1\@nil}% \reserved@a\reserved@b + \@expl@@@filehook@clear@replacement@flag@@ \expandafter\xdef\csname opt@\reserved@a\endcsname{% \@ifundefined{opt@\reserved@a}\@empty {\csname opt@\reserved@a\endcsname,}% - \zap@space#2 \@empty}} + \zap@space#2 \@empty}% +% \end{macrocode} +% \changes{v1.3u}{2020/11/20} +% {Copy option list to the requested package.} +% \begin{macrocode} + \expandafter\let + \csname opt@#3.#1\expandafter\endcsname + \csname opt@\reserved@a\endcsname} %</2ekernel|latexrelease> %<latexrelease>\EndIncludeInRelease % @@ -1719,8 +1828,38 @@ %<latexrelease>\IncludeInRelease{2020/10/01}% %<latexrelease> {\@onefilewithoptions}{Hooks and unused options issue}% \def\@onefilewithoptions#1[#2][#3]#4{% +% \end{macrocode} +% We have to sanitise file names, so that something like +% \begin{verbatim} +% \usepackage{some/local/path/array} +% \usepackage{array} +% \end{verbatim} +% won't load \file{array.sty} twice. It is remotely possible that +% those are two different files, but as a matter of principles, we +% will consider that the base file name uniquely identifies a +% package, regardless of where it lives. This assumption already +% holds for file hooks, for example, which address the hook to a file +% by its base name only. +% +% We'll use \cs{@expl@@@filehook@set@curr@file@@nNN} to parse the +% file name and return the \meta{path} and \meta{base+ext} in +% separate token lists. Further ahead, most operations use +% \cs{@currname} which doesn't have a path attached to it; only few +% actions prepend \cs{@currpath} to \cs{@currname} (namely loading, +% as we have to respect the given path). +% +% A file substituiton isn't followed just yet because at this point +% we are parsing user input, so the file is still what the user +% asked for, and not the file actually loaded. +% \begin{macrocode} + \@expl@@@filehook@set@curr@file@@nNN{#1.#4}\reserved@a\reserved@b + \edef\reserved@c{\def\noexpand\reserved@c####1% + \detokenize\expandafter{\expanded{.#4}}% + \noexpand\@nil{\def\noexpand\reserved@a{####1}}}\reserved@c + \expandafter\reserved@c\reserved@a\@nil \@pushfilename - \xdef\@currname{#1}% + \xdef\@currname{\string@makeletter\reserved@a}% + \xdef\@currpath{\ifx\reserved@b\@empty\else\reserved@b/\fi}% \global\let\@currext#4% % \end{macrocode} % The command \cs{ver@\meta{file}.\meta{ext}} is used to signal that @@ -1765,9 +1904,11 @@ % \end{macrocode} % First we take the \meta{name} and \meta{ext} given in the argument % and check if the file exists, and issue an error otherwise asking -% for a correction with \cs{@missingfileerror}. +% for a correction with \cs{@missingfileerror}. For checking if the +% file exists we use \cs{@currpath} (usually empty) before +% \cs{@currname}. % \begin{macrocode} - \IfFileExists{\@currname.\@currext}{}% + \IfFileExists{\@currpath\@currname.\@currext}{}% {\@missing@onefilewithoptions{#2}}% % \end{macrocode} % If \cs{@currname} is empty (the user replied to the ``Enter file @@ -1784,11 +1925,12 @@ % do the bookkeeping with \cs{@filehook@file@push} % then call \cs{set@curr@file} to set \cs{@curr@file} (and do any % required substitution), then actually load the class/package with -% \cs{load@onefile@withoptions}. +% \cs{load@onefile@withoptions}. \cs{set@curr@file} also needs the +% file path. % \begin{macrocode} \@disable@packageload@do{\@currname.\@currext}% {\@expl@@@filehook@file@push@@ - \set@curr@file{\@currname.\@currext}% + \set@curr@file{\@currpath\@currname.\@currext}% \@filehook@set@CurrentFile % \end{macrocode} % \changes{v1.3q}{2020/09/06} @@ -1812,10 +1954,15 @@ \expandafter\@swaptwoargs\expandafter {\expandafter{\@currpkg@reqd}}% {% < +% \end{macrocode} +% \cs{@currpkg@reqd} doesn't take a path because it is used later to +% assign \cs[no-index]{opt@...} and \cs[no-index]{ver@...}. +% \begin{macrocode} \edef\@currpkg@reqd{\@currname.\@currext}% \ifx\CurrentFile\CurrentFileUsed \else \filename@parse\@curr@file + \edef\@currpath{\string@makeletter\filename@area}% \edef\@currname{\string@makeletter\filename@base}% \edef\@currext{\string@makeletter\filename@ext}% \fi @@ -1864,11 +2011,13 @@ % \end{macro} % % \begin{macro}{\@missing@onefilewithoptions} -% Now the action taken when a file is not found. +% Now the action taken when a file is not found. Path must be +% included here as it eventually leads to a file lookup. % \begin{macrocode} \def\@missing@onefilewithoptions#1{% - \@missingfileerror\@currname\@currext - \xdef\@currname{\@missingfile@area\@missingfile@base}% + \@missingfileerror{\@currpath\@currname}\@currext + \global\let\@currpath\@missingfile@area + \global\let\@currname\@missingfile@base \global\let\@currext\@missingfile@ext} % \end{macrocode} % \end{macro} @@ -1887,6 +2036,13 @@ % \begin{macrocode} \def\reserved@a{% \@pass@ptions\@currext{#1}{\@currname}% +% \end{macrocode} +% \changes{v1.3u}{2020/11/20} +% {Copy option list to the requested package.} +% \begin{macrocode} + \expandafter\let + \csname opt@\@currpkg@reqd\expandafter\endcsname + \csname opt@\@currname.\@currext\endcsname \global\expandafter \let\csname ver@\@currname.\@currext\endcsname\@empty % \end{macrocode} @@ -1912,11 +2068,12 @@ \fi % \end{macrocode} % Now actually load the file (at this point we are certain it exists, -% but use \cs{InputIfFileExists} so that file hooks are executed): +% but use \cs{InputIfFileExists} so that file hooks are executed). +% \cs{@currpath} is needed here too. % \begin{macrocode} - \InputIfFileExists{\@currpkg@reqd}{}% + \InputIfFileExists{\@currpath\@currpkg@reqd}{}% {\@latex@error - {The \@cls@pkg\space\@currpkg@reqd\space failed to load.}\@ehd}% + {The \@cls@pkg\space\@currpkg@reqd\space failed to load}\@ehd}% %----------------------------------------- % \end{macrocode} % In older versions of the code |\@unprocessedoptions| would @@ -3271,19 +3428,20 @@ % A similar error is given if global rollback date and min-date on % a specific package conflict with each other, but that case is % happens only once so it is inlined. +% \changes{v1.3u}{2020/11/09}{Change help text because the package may have +% existed then --- there is just no rollback data (gh/423).} % \begin{macrocode} \def\pkgcls@rollbackdate@error#1{% \@latex@error{Suspicious rollback date given}% - {The \@cls@pkg\space'\@currname' claims that it - came into existence on #1 which\MessageBreak + {The \@cls@pkg\space'\@currname' has no rollback data + before #1 which\MessageBreak is after your requested rollback date --- so - something is wrong here.\MessageBreak + something may be wrong here.\MessageBreak Continue and we use the earliest known release.}} % \end{macrocode} % \end{macro} % % -% % \begin{macro}{\DeclareCurrentRelease} % This declares the date (and possible name) of the current version % of a package or class. diff --git a/macros/latex/base/ltdefns.dtx b/macros/latex/base/ltdefns.dtx index 569c9db4df..920c1acde6 100644 --- a/macros/latex/base/ltdefns.dtx +++ b/macros/latex/base/ltdefns.dtx @@ -32,7 +32,7 @@ %<*driver> % \fi \ProvidesFile{ltdefns.dtx} - [2020/09/25 v1.5n LaTeX Kernel (definition commands)] + [2020/11/25 v1.5o LaTeX Kernel (definition commands)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltdefns.dtx} @@ -385,8 +385,19 @@ % \begin{macro}{\@carcube} % |\@carcube T1 ... Tn\@nil| = |T1| |T2| |T3| , $n > 3$ % \changes{v1.5k}{2020/08/19}{Made \cs{long} for \cs{NewCommandCopy}} +% \changes{v1.5o}{2020/11/25}{Added missing latexrelease entry} % \begin{macrocode} +%</2ekernel> +%<latexrelease>\IncludeInRelease{2020/10/01}{\@carcube}{Make \@carcube long}% +%<*2ekernel|latexrelease> \long\def\@carcube#1#2#3#4\@nil{#1#2#3} +%</2ekernel|latexrelease> +%<latexrelease>\EndIncludeInRelease +% +%<latexrelease>\IncludeInRelease{0000/00/00}{\@carcube}{Undo: Make \@carcube long}% +%<latexrelease>\def\@carcube#1#2#3#4\@nil{#1#2#3} +%<latexrelease>\EndIncludeInRelease +%<*2ekernel> % \end{macrocode} % \end{macro} % diff --git a/macros/latex/base/ltexpl.dtx b/macros/latex/base/ltexpl.dtx index 4100da79c2..7f9019ede3 100644 --- a/macros/latex/base/ltexpl.dtx +++ b/macros/latex/base/ltexpl.dtx @@ -33,7 +33,7 @@ %<*driver> % \fi \ProvidesFile{ltexpl.dtx} - [2020/09/06 v1.2f LaTeX Kernel (expl3-dependent code)] + [2020/12/18 v1.2h LaTeX Kernel (expl3-dependent code)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltexpl.dtx} @@ -72,16 +72,45 @@ % {Define a local version of some \LaTeXe{} basic macros to support % package loading} % +% \begin{macro}{\@kernel@after@enddocument, +% \@kernel@after@enddocument@afterlastpage} +% These two kernel hooks are used by the shipout code. They are +% defined earlier here because the \pkg{lthooks} code adds material +% to them. +% \changes{v1.2h}{2020/12/18} +% {Define kernel \cs{enddocument} hooks early} +% \begin{macrocode} +%<*2ekernel|latexrelease> +%<latexrelease>\IncludeInRelease{2020/10/01}% +%<latexrelease> {kernel@enddocument hooks}{Define kernel enddocument Hooks}% +\let\@kernel@after@enddocument\@empty +\let\@kernel@after@enddocument@afterlastpage\@empty +%<latexrelease>\EndIncludeInRelease +% \end{macrocode} +% +% \begin{macrocode} +%<latexrelease>\IncludeInRelease{0000/00/00}% +%<latexrelease> {kernel@enddocument hooks}{Define kernel enddocument Hooks}% +%<latexrelease>\let\@kernel@after@enddocument\@undefined +%<latexrelease>\let\@kernel@after@enddocument@afterlastpage\@undefined +%<latexrelease>\EndIncludeInRelease +%</2ekernel|latexrelease> +% \end{macrocode} +% \end{macro} +% % First define some blank commands, so that in case something goes wrong while % loading \textsf{expl3}, we won't get strange \texttt{Undefined control % sequence} errors. % \begin{macrocode} -%<*2ekernel> +%<*2ekernel|latexrelease> +%<latexrelease>\IncludeInRelease{2020/10/01}% +%<latexrelease> {\@expl@sys@load@backend@@}{Roll forward support}% \def\@expl@sys@load@backend@@{} \def\@expl@push@filename@@{} \def\@expl@push@filename@aux@@{} \def\@expl@pop@filename@@{} -%</2ekernel> +%<latexrelease>\EndIncludeInRelease +%</2ekernel|latexrelease> % \end{macrocode} % % \changes{v1.2d}{2020/07/08} @@ -183,9 +212,20 @@ \errmessage{LaTeX requires expl3}% \batchmode \read -1 to \reserved@a %</2ekernel> +% \end{macrocode} +% We do not support a roll forward across 2019. You need to start +% with 2019 if you want to get to 2020 or beyond. +% \changes{v1.2g}{2020/11/24}{Support for roll forward (gh/434)} +% \begin{macrocode} %<*latexrelease> - \@latex@error{LaTeX requires expl3}\@ehd - \@gobble + \@latex@warning@no@line + {You need a format that already contains a recent\MessageBreak + expl3 as part of the kernel, e.g. at least a kernel\MessageBreak + from 2019 to roll forward to that date!\MessageBreak + --- I'm giving up!\MessageBreak\MessageBreak + Note that manually loading the expl3 package\MessageBreak + from your distribution is not enough}% + \@@end % die %</latexrelease> }% {% @@ -222,6 +262,36 @@ %<latexrelease>\EndIncludeInRelease % \end{macrocode} % +% +% Starting with 2020-10 the kernel contains most of the +% \texttt{xparse} interfaces loaded above. These interfaces are +% later used to define various user command. However, if somebody +% with an earlier installation tries to roll forward (using a +% \texttt{latexrelease} package from a newer release) this will not +% work as the earlier kernel doesn't contain commands such as +% \cs{NewDocumentCommand}. +% +% We therefore add code into \texttt{latexrelease.sty} to load the +% \texttt{xparse} package of the current installation instead. this +% may not work if the installation is really old, but roll forward +% can't do miracles. +% +% If the kernel is 2020-10 or later \cs{NewDocumentCommand} is +% already known (whether or not you roll forward or back) so +% nothing happens, but if you start from am earlier kernel the +% \texttt{xparse} package gets loaded by \texttt{latexrelease}. +% \changes{v1.2g}{2020/11/24}{Load xparse in latexrelease if needed (gh/434)} +% \begin{macrocode} +%<latexrelease>\IncludeInRelease{2020/10/01}% +%<latexrelease> {\NewDocumentCommand}{Emergency loading xparse}% +%<latexrelease> +%<latexrelease>\ifdefined\NewDocumentCommand \else +%<latexrelease> \RequirePackage{xparse} +%<latexrelease>\fi +%<latexrelease> +%<latexrelease>\EndIncludeInRelease +% \end{macrocode} +% % \subsection{Using expl3 code} % % In order to ease the implemantation of some new features in @@ -242,9 +312,6 @@ % if that \pkg{expl3} command is needed in places that are others % coded in \LaTeXe{} conventions. % -% \begin{macrocode} -\ExplSyntaxOn -% \end{macrocode} % % In this file, each release of LaTeX adds an \cs{IncludeInRelease} % block, in which the macros copied for that release were defined. @@ -259,8 +326,16 @@ % redefinitions. % % \begin{macrocode} -%<latexrelease>\IncludeInRelease{2020/10/01}{expl3~2020-10-01}% -%<latexrelease> {expl3~macros~added~for~the~2020-10-01~release}% +%<latexrelease>\IncludeInRelease{2020/10/01}{\@expl@cs@to@str@@N}% +%<latexrelease> {expl3 macros added for the 2020-10-01 release}% +% \end{macrocode} +% +% The expl3 activation needs to be inside the release guards as +% otherwise rolling forward is broken in old kernels that do not +% have expl3 loaded. +% \changes{v1.2g}{2020/11/24}{Support for roll forward (gh/434)} +% \begin{macrocode} +\ExplSyntaxOn % \end{macrocode} % % \changes{v1.2e}{2020/08/19} @@ -290,21 +365,27 @@ % \end{macrocode} % % \begin{macrocode} +\ExplSyntaxOff +% \end{macrocode} +% +% +% Here we can't assume that expl3 is available. It will be if we +% roll back but if this code is executed rolling forward it needs +% to be pure 2e. +% \changes{v1.2g}{2020/11/24}{Support for roll forward (gh/434)} +% \begin{macrocode} %<latexrelease>\EndIncludeInRelease -%<latexrelease>\IncludeInRelease{0000/00/00}{expl3~2020-10-01}% -%<latexrelease> {expl3~macros~added~for~the~2020-10-01~release}% -%<latexrelease>\cs_undefine:N \@expl@cs@to@str@@N -%<latexrelease>\cs_undefine:N \@expl@str@if@eq@@nnTF -%<latexrelease>\cs_undefine:N \@expl@cs@prefix@spec@@N -%<latexrelease>\cs_undefine:N \@expl@cs@argument@spec@@N -%<latexrelease>\cs_undefine:N \@expl@cs@replacement@spec@@N -%<latexrelease>\cs_undefine:N \@expl@str@map@function@@NN +%<latexrelease>\IncludeInRelease{0000/00/00}{\@expl@cs@to@str@@N}% +%<latexrelease> {expl3 macros added for the 2020-10-01 release}% +%<latexrelease>\let \@expl@cs@to@str@@N \@undefined +%<latexrelease>\let \@expl@str@if@eq@@nnTF \@undefined +%<latexrelease>\let \@expl@cs@prefix@spec@@N \@undefined +%<latexrelease>\let \@expl@cs@argument@spec@@N \@undefined +%<latexrelease>\let \@expl@cs@replacement@spec@@N \@undefined +%<latexrelease>\let \@expl@str@map@function@@NN \@undefined %<latexrelease>\EndIncludeInRelease %</2ekernel|latexrelease> % \end{macrocode} % -% \begin{macrocode} -\ExplSyntaxOff -% \end{macrocode} % % \Finale diff --git a/macros/latex/base/ltfilehook-code.pdf b/macros/latex/base/ltfilehook-code.pdf Binary files differindex e35be13efe..fcbf09fe98 100644 --- a/macros/latex/base/ltfilehook-code.pdf +++ b/macros/latex/base/ltfilehook-code.pdf diff --git a/macros/latex/base/ltfilehook-doc.pdf b/macros/latex/base/ltfilehook-doc.pdf Binary files differindex 7bd9392a4d..bf7f37f22b 100644 --- a/macros/latex/base/ltfilehook-doc.pdf +++ b/macros/latex/base/ltfilehook-doc.pdf diff --git a/macros/latex/base/ltfilehook.dtx b/macros/latex/base/ltfilehook.dtx index ecb499f347..c7ed13f041 100644 --- a/macros/latex/base/ltfilehook.dtx +++ b/macros/latex/base/ltfilehook.dtx @@ -31,8 +31,8 @@ %%% From File: ltfilehook.dtx % % \begin{macrocode} -\providecommand\ltfilehookversion{v1.0c} -\providecommand\ltfilehookdate{2020/10/18} +\providecommand\ltfilehookversion{v1.0d} +\providecommand\ltfilehookdate{2020/11/24} % \end{macrocode} % %<*driver> @@ -615,6 +615,62 @@ % \begin{macrocode} %</2ekernel|latexrelease> %<latexrelease>\EndIncludeInRelease +% \end{macrocode} +% +% When rolling forward the following expl3 functions may not be defined. +% If we roll back the code does nothing. +% \changes{v1.0d}{2020/11/24}{Support for roll forward (gh/434)} +% \begin{macrocode} +%<latexrelease>\IncludeInRelease{2020/10/01}% +%<latexrelease> {\file_parse_full_name_apply:nN}{Roll forward help}% +%<latexrelease> +%<latexrelease>\ExplSyntaxOn +%<latexrelease>\cs_if_exist:NF\file_parse_full_name_apply:nN +%<latexrelease>{ +%<latexrelease>\cs_new:Npn \file_parse_full_name_apply:nN #1 +%<latexrelease> { +%<latexrelease> \exp_args:Ne \__file_parse_full_name_auxi:nN +%<latexrelease> { \__kernel_file_name_sanitize:n {#1} } +%<latexrelease> } +%<latexrelease>\cs_new:Npn \__file_parse_full_name_auxi:nN #1 +%<latexrelease> { +%<latexrelease> \__file_parse_full_name_area:nw { } #1 +%<latexrelease> / \s__file_stop +%<latexrelease> } +%<latexrelease>\cs_new:Npn \__file_parse_full_name_area:nw #1 #2 / #3 \s__file_stop +%<latexrelease> { +%<latexrelease> \tl_if_empty:nTF {#3} +%<latexrelease> { \__file_parse_full_name_base:nw { } #2 . \s__file_stop {#1} } +%<latexrelease> { \__file_parse_full_name_area:nw { #1 / #2 } #3 \s__file_stop } +%<latexrelease> } +%<latexrelease>\cs_new:Npn \__file_parse_full_name_base:nw #1 #2 . #3 \s__file_stop +%<latexrelease> { +%<latexrelease> \tl_if_empty:nTF {#3} +%<latexrelease> { +%<latexrelease> \tl_if_empty:nTF {#1} +%<latexrelease> { +%<latexrelease> \tl_if_empty:nTF {#2} +%<latexrelease> { \__file_parse_full_name_tidy:nnnN { } { } } +%<latexrelease> { \__file_parse_full_name_tidy:nnnN { .#2 } { } } +%<latexrelease> } +%<latexrelease> { \__file_parse_full_name_tidy:nnnN {#1} { .#2 } } +%<latexrelease> } +%<latexrelease> { \__file_parse_full_name_base:nw { #1 . #2 } #3 \s__file_stop } +%<latexrelease> } +%<latexrelease>\cs_new:Npn \__file_parse_full_name_tidy:nnnN #1 #2 #3 #4 +%<latexrelease> { +%<latexrelease> \exp_args:Nee #4 +%<latexrelease> { +%<latexrelease> \str_if_eq:nnF {#3} { / } { \use_none:n } +%<latexrelease> #3 \prg_do_nothing: +%<latexrelease> } +%<latexrelease> { \use_none:n #1 \prg_do_nothing: } +%<latexrelease> {#2} +%<latexrelease> } +%<latexrelease>} +%<latexrelease>\ExplSyntaxOff +%<latexrelease> +%<latexrelease>\EndIncludeInRelease %<*2ekernel> % \end{macrocode} % @@ -643,6 +699,8 @@ % kernel we do this only now and not in \texttt{ltfiles}. % % \begin{macro}{\InputIfFileExists} +% \begin{macro}{\@input@file@exists@with@hooks} +% \begin{macro}{\unqu@tefilef@und} % \cs{InputIfFileExists} loads any file if it is available so we % have to add the hooks \texttt{file/before} and % \texttt{file/after} in the right places. If the file doesn't @@ -665,7 +723,7 @@ % If the file exists then \cs{CurrentFile} holds its name. But we % can't rely on that still being true after the file has been % processed. Thus for using the name in the file hooks we need to -% preserve the name and then restored it for the +% preserve the name and then restore it for the % \texttt{file/after/...} hook. % % The hook always refers to the file requested by the user. The hook @@ -683,33 +741,68 @@ % refer to the file by their name only. The path to the file is % returned in \cs{CurrentFilePath}. % \begin{macrocode} - \edef\reserved@a{\@filef@und + \edef\reserved@a{% \@expl@@@filehook@file@pop@assign@@nnnn {\CurrentFilePathUsed}% {\CurrentFileUsed}% {\CurrentFilePath}% - {\CurrentFile}}% + {\CurrentFile}% +% \end{macrocode} +% +% We pre-expand \cs{@filef@und} so that in case another file is +% loaded in the true branch of \cs{InputIfFileExists}, these don't +% change their value meanwhile. This isn't a worry with +% \cs[no-index]{CurrentFile...} because they are kept in a stack. +% +% \changes{v1.0d}{2020/11/20} +% {Move loading to \cs{@input@file@exists@with@hooks} and expand +% \cs{@filef@und} to avoid getting the wrong file name in the case of +% a substitution.} +% \begin{macrocode} + \noexpand\@input@file@exists@with@hooks{\@filef@und}}% \expandafter\@swaptwoargs\expandafter {\reserved@a}% - {% - #2% - \@addtofilelist{#1}% - \UseHook{file/before}% + {#2}% + \@expl@@@filehook@file@pop@@ + }% +} +% \end{macrocode} +% +% Before adding to the file list we need to make all (letter) characters +% catcode~11, because several packages use constructions like +% \begin{verbatim} +% \filename@parse{<filename>} +% \ifx\filename@ext\@clsextension +% ... +% \fi +% \end{verbatim} +% and that doesn't work if \cs{filename@ext} is \cs{detokenize}d. +% Making \cs{@clsextension} a string doesn't help much because some +% packages define their own \cs[no-index]{<prefix>@someextension} with +% normal catcodes. This is not entirely correct because packages loaded +% (somehow) with catcode~12 alphabetic tokens (say, as the result of +% a \cs{string} or \cs{detokenize} command, or from a \TeX{} string like +% \cs{jobname}) will have these character tokens incorrectly turned into +% letter tokens. This however is rare, so we'll go for the all-letters +% approach (grepping the packages in \TeX{} Live didn't bring up any +% obvious candidate for breaking with this catcode change). +% \begin{macrocode} +\def\@input@file@exists@with@hooks#1{% + \edef\reserved@a{\unqu@tefilef@und#1\@nil}% + \@addtofilelist{\string@makeletter\reserved@a}% + \UseHook{file/before}% % \end{macrocode} % The current file name is available in \cs{CurrentFile} so we use % that in the specific hook. % \begin{macrocode} - \UseHook{file/before/\CurrentFile}% - \@@input - }% + \UseHook{file/before/\CurrentFile}% + \@@input #1% <- trailing space comes from \@filef@und % \end{macrocode} % And it is restored here so we can use it once more. % \begin{macrocode} - \UseHook{file/after/\CurrentFile}% - \UseHook{file/after}% - \@expl@@@filehook@file@pop@@ - }% -} + \UseHook{file/after/\CurrentFile}% + \UseHook{file/after}} +\def\unqu@tefilef@und"#1" \@nil{#1} %<latexrelease>\EndIncludeInRelease %</2ekernel|latexrelease> % \end{macrocode} @@ -737,6 +830,8 @@ %<latexrelease> {% %<latexrelease> \expandafter\@swaptwoargs\expandafter %<latexrelease> {\@filef@und}{#2\@addtofilelist{#1}\@@input}}} +%<latexrelease>\let\@input@file@exists@with@hooks\@undefined +%<latexrelease>\let\unqu@tefilef@und\@undefined %<latexrelease>\EndIncludeInRelease % \end{macrocode} % @@ -746,10 +841,14 @@ %<latexrelease>\long\def \InputIfFileExists#1#2{% %<latexrelease> \IfFileExists{#1}% %<latexrelease> {#2\@addtofilelist{#1}\@@input \@filef@und}} +%<latexrelease>\let\@input@file@exists@with@hooks\@undefined +%<latexrelease>\let\unqu@tefilef@und\@undefined %<latexrelease>\EndIncludeInRelease %<*2ekernel> % \end{macrocode} % \end{macro} +% \end{macro} +% \end{macro} % % % @@ -772,8 +871,8 @@ % % % \begin{macro}{\@@_subst_add:nn,\@@_subst_remove:n, -% \@@_subst_file_normalize:n,\@@_subst_empty_name_chk:NN} -% \cs{@@_substitution_lthooadd:nn} declares a file substitution by +% \@@_subst_file_normalize:Nn,\@@_subst_empty_name_chk:NN} +% \cs{@@_subst_add:nn} declares a file substitution by % doing a (global) definition of the form % |\def|\cs{@file-subst@\meta{file}}|{|\meta{replacement}|}|. % The file names are properly sanitised, and normalized with the same @@ -787,8 +886,12 @@ \group_begin: \cs_set:cpx { } { \exp_not:o { \cs:w\cs_end: } } \int_set:Nn \tex_escapechar:D { -1 } - \cs_gset:cpx { @file-subst@ \@@_subst_file_normalize:n {#1} } - { \@@_subst_file_normalize:n {#2} } + \cs_gset:cpx + { + @file-subst@ + \@@_subst_file_normalize:Nn \use_ii_iii:nnn {#1} + } + { \@@_subst_file_normalize:Nn \@@_file_name_compose:nnn {#2} } \group_end: } \cs_new_protected:Npn \@@_subst_remove:n #1 @@ -796,14 +899,18 @@ \group_begin: \cs_set:cpx { } { \exp_not:o { \cs:w\cs_end: } } \int_set:Nn \tex_escapechar:D { -1 } - \cs_undefine:c { @file-subst@ \@@_subst_file_normalize:n {#1} } + \cs_undefine:c + { + @file-subst@ + \@@_subst_file_normalize:Nn \use_ii_iii:nnn {#1} + } \group_end: } -\cs_new:Npn \@@_subst_file_normalize:n #1 +\cs_new:Npn \@@_subst_file_normalize:Nn #1 #2 { \exp_after:wN \@@_subst_empty_name_chk:NN \cs:w \exp_after:wN \cs_end: - \cs:w \@@_file_parse_full_name:nN {#1} \use_ii_iii:nnn \cs_end: + \cs:w \@@_file_parse_full_name:nN {#2} #1 \cs_end: } \cs_new:Npn \@@_subst_empty_name_chk:NN #1 #2 { \if_meaning:w #1 #2 .tex \else: \token_to_str:N #2 \fi: } @@ -929,6 +1036,7 @@ \if@tempswa \@expl@@@filehook@drop@extension@@N\@curr@file@reqd \fi}% {\if@tempswa \@expl@@@filehook@drop@extension@@N\@curr@file \fi \global\let\@curr@file@reqd\@curr@file}% + \@expl@@@filehook@clear@replacement@flag@@ \endgroup} %</2ekernel|latexrelease> %<latexrelease>\EndIncludeInRelease @@ -1079,18 +1187,25 @@ % % \begin{macro}{flag @@_file_replaced} % \begin{macro}{\@@_if_file_replaced:TF} +% \begin{macro}{\@@_clear_replacement_flag:} % Since the file replacement is done expandably in a \cs{csname}, use % a flag to remember if a substitution happened. We use this in % \cs{set@curr@file} to short-circuit some of it in case no % substitution happened (by far the most common case, so it's worth -% optimising). +% optimising). The flag raised during the file substitution algorithm +% must be explicitly cleared after the \cs{@@_if_file_replaced:TF} +% conditional is no longer needed, otherwise further uses of +% \cs{@@_if_file_replaced:TF} will wrongly return true. % \begin{macrocode} \flag_new:n { @@_file_replaced } \cs_new:Npn \@@_if_file_replaced:TF #1 #2 - { \flag_if_raised:nTF { @@_file_replaced } {#1} {#2} } + { \flag_if_raised:nTF { @@_file_replaced } {#1} {#2} } +\cs_new_protected:Npn \@@_clear_replacement_flag: + { \flag_clear:n { @@_file_replaced } } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}{\@@_file_subst_begin:nnn} % First off, start by checking if the current file ($\meta{name} + @@ -1343,7 +1458,12 @@ \cs_new_eq:NN \@expl@@@filehook@if@file@replaced@@TF \__filehook_if_file_replaced:TF % \end{macrocode} -% +% +% \begin{macrocode} +\cs_new_eq:NN \@expl@@@filehook@clear@replacement@flag@@ + \__filehook_clear_replacement_flag: +% \end{macrocode} +% % \begin{macrocode} \cs_new_eq:NN \@expl@@@filehook@drop@extension@@N \__filehook_drop_extension:N diff --git a/macros/latex/base/ltfssaxes.dtx b/macros/latex/base/ltfssaxes.dtx index d8e4286b78..a66a26cd39 100644 --- a/macros/latex/base/ltfssaxes.dtx +++ b/macros/latex/base/ltfssaxes.dtx @@ -836,7 +836,7 @@ % condensed series, etc.). We do this in all branches above because a user % might have written %\begin{verbatim} -\DeclareFontSeriesChangeRule {m}{sc}{msc}{mc} +% \DeclareFontSeriesChangeRule {m}{sc}{msc}{mc} %\end{verbatim} % instead of using \texttt{sc} and \texttt{c} as needed in the % \texttt{.fd} file. diff --git a/macros/latex/base/ltfssbas.dtx b/macros/latex/base/ltfssbas.dtx index 4a6afca3ac..30f500b6e4 100644 --- a/macros/latex/base/ltfssbas.dtx +++ b/macros/latex/base/ltfssbas.dtx @@ -35,7 +35,7 @@ % % \ProvidesFile{ltfssbas.dtx} - [2020/02/27 v3.2g LaTeX Kernel (NFSS Basic Macros)] + [2020/12/10 v3.2h LaTeX Kernel (NFSS Basic Macros)] % \iffalse \documentclass{ltxdoc} \begin{document} @@ -891,12 +891,31 @@ % series and shape which is not desired if we intend to use an % explicit font shape! % \changes{v3.2e}{2019/12/17}{Don't call \cs{fontseries} or \cs{fontshape}} +% \changes{v3.2h}{2020/12/10}{Drop ``m'' if the series value is a member +% of a fixed list and issue warning if doing it (gh/453)} % \begin{macrocode} +%</2ekernel> +%<*2ekernel|latexrelease> +%<latexrelease>\IncludeInRelease{2020/02/02}% +%<latexrelease> {\usefont}{Drop m in usefont}% \DeclareRobustCommand\usefont[4]{\fontencoding{#1}% \edef\f@family{#2}% - \edef\f@series{#3}% + \set@target@series{#3}% \edef\f@shape{#4}\selectfont \ignorespaces} +%</2ekernel|latexrelease> +%<latexrelease>\EndIncludeInRelease +%<latexrelease>\IncludeInRelease{0000/00/00}% +%<latexrelease> {\usefont}{Drop m in usefont}% +%<latexrelease> +%<latexrelease>\DeclareRobustCommand\usefont[4]{\fontencoding{#1}% +%<latexrelease> \edef\f@family{#2}% +%<latexrelease> \edef\f@series{#3}% +%<latexrelease> \edef\f@shape{#4}\selectfont +%<latexrelease> \ignorespaces} +%<latexrelease> +%<latexrelease>\EndIncludeInRelease +%<*2ekernel> % \end{macrocode} % \end{macro} % diff --git a/macros/latex/base/lthooks-code.pdf b/macros/latex/base/lthooks-code.pdf Binary files differindex e181e4bb27..5bb5d7899f 100644 --- a/macros/latex/base/lthooks-code.pdf +++ b/macros/latex/base/lthooks-code.pdf diff --git a/macros/latex/base/lthooks-doc.pdf b/macros/latex/base/lthooks-doc.pdf Binary files differindex 5949974141..1ca6ef3a6d 100644 --- a/macros/latex/base/lthooks-doc.pdf +++ b/macros/latex/base/lthooks-doc.pdf diff --git a/macros/latex/base/lthooks.dtx b/macros/latex/base/lthooks.dtx index e4ff7dd2ed..cc79892ca7 100644 --- a/macros/latex/base/lthooks.dtx +++ b/macros/latex/base/lthooks.dtx @@ -31,8 +31,8 @@ %%% From File: lthooks.dtx % % \begin{macrocode} -\def\lthooksversion{v1.0e} -\def\lthooksdate{2020/10/23} +\def\lthooksversion{v1.0g} +\def\lthooksdate{2020/12/18} % \end{macrocode} % %<*driver> @@ -222,11 +222,13 @@ % \begin{syntax} % \cs{AddToHook} \Arg{hook}\oarg{label}\Arg{code} % \end{syntax} -% Adds \meta{code} to the \meta{hook} labeled by \meta{label}. If -% the optional argument \meta{label} is not provided, if \cs{AddToHook} -% is used in a package/class, then the current -% package/class name is used, otherwise \hook{top-level} is -% used~(see section~\ref{sec:default-label}). +% Adds \meta{code} to the \meta{hook} labeled by \meta{label}. +% When the optional argument \meta{label} is not provided, the +% \meta{default label} is used (see section~\ref{sec:default-label}). +% If \cs{AddToHook} is used in a package/class, the +% \meta{default label} is the package/class name, otherwise it is +% \hook{top-level} (the \hook{top-level} label is treated +% differently: see section~\ref{sec:top-level}). % % If there already exists code under the \meta{label} then the new % \meta{code} is appended to the existing one (even if this is a reversed hook). @@ -234,10 +236,10 @@ % \meta{label}, first apply \cs{RemoveFromHook}. % % The hook doesn't have to exist for code to be added to -% it. However, if it is not declared later then obviously the +% it. However, if it is not declared, then obviously the % added \meta{code} will never be executed. This % allows for hooks to work regardless of package loading order and -% enables packages to add to hook of other packages without +% enables packages to add to hooks from other packages without % worrying whether they are actually used in the current document. % See section~\ref{sec:querying}. % @@ -251,10 +253,8 @@ % \cs{RemoveFromHook} \Arg{hook}\oarg{label} % \end{syntax} % Removes any code labeled by \meta{label} from the \meta{hook}. -% If the optional -% argument \meta{label} is not provided, if \cs{AddToHook} -% is used in a package/class, then the current -% package/class name is used, otherwise \hook{top-level} is used. +% When the optional argument \meta{label} is not provided, the +% \meta{default label} is used (see section~\ref{sec:default-label}). % % If the code for that \meta{label} wasn't yet added to the % \meta{hook}, an order is set so that when some code attempts to add @@ -273,7 +273,7 @@ % \medskip % % In contrast to the \texttt{voids} relationship between two labels -% in a \cs{DeclareHookrule} this is a destructive operation as the +% in a \cs{DeclareHookRule} this is a destructive operation as the % labeled code is removed from the hook data structure, whereas the % relationship setting can be undone by providing a different % relationship later. @@ -367,7 +367,8 @@ % token, a low-level \TeX{} error is raised (namely, the \meta{hook} is % expanded using \TeX's \cs{csname}\ldots\cs{endcsname}, as such, % Unicode characters are allowed in \meta{hook} and \meta{label} -% arguments). The arguments of \cs{UseHook} and \cs{UseOneTimeHook} are +% arguments). The arguments of \cs{UseHook}, \cs{UseOneTimeHook}, +% \cs{IfHookEmptyTF}, and \cs{IfHookExistsTF} are % processed much in the same way except that spaces are not trimmed % around the argument, for better performance. % @@ -377,10 +378,10 @@ % chunk and to prevent clashes. This should be the standard practice, % so this hook management code provides a shortcut to refer to the % current package in the name of a \meta{hook} and in a \meta{label}. -% If \meta{hook} name or \meta{label} consist just of a single dot +% If the \meta{hook} name or the \meta{label} consist just of a single dot % (|.|), or starts with a dot followed by a slash (|./|) then the dot % denotes the \meta{default label} (usually the current package or class -% name---see~\cs{DeclareDefaultHookLabel}). +% name---see~\cs{SetDefaultHookLabel}). % A \enquote{|.|} or \enquote{|./|} anywhere else in a \meta{hook} or in % \meta{label} is treated literally and is not replaced. % @@ -403,15 +404,15 @@ % \AddToHook {file/after/foo.tex}{code} % unchanged % \end{verbatim} % -% The \meta{default label} is automatically set to the name of the -% current package or class (using \cs{@currname}). If \cs{@currname} -% is not set (because the hook command is used outside of a package, or -% the current file wasn't loaded with \cs{usepackage} or -% \cs{documentclass}), then the \texttt{top-level} is used as the -% \meta{default label}. +% The \meta{default label} is automatically set equal to the name of the +% current package or class at the time the package is loaded. If the +% hook command is used outside of a package, or the current file wasn't +% loaded with \cs{usepackage} or \cs{documentclass}, then the +% \texttt{top-level} is used as the \meta{default label}. This may have +% exceptions---see \cs{PushDefaultHookLabel}. % % This syntax is available in all \meta{label} arguments and most -% \meta{hook}, both in the \LaTeXe{} interface, and the \LaTeX3 +% \meta{hook} arguments, both in the \LaTeXe{} interface, and the \LaTeX3 % interface described in section~\ref{sec:l3hook-interface}. % % Note, however, that the replacement of |.| by the \meta{default label} @@ -430,29 +431,104 @@ % In some cases, for example in large packages, one may want to separate % it in logical parts, but still use the main package name as % \meta{label}, then the \meta{default label} can be set using -% \cs{DeclareDefaultHookLabel}: +% \cs{SetDefaultHookLabel} or +% \cs{PushDefaultHookLabel}..\cs{PopDefaultHookLabel}. % -% \begin{function}{\DeclareDefaultHookLabel} +% \begin{function}{\PushDefaultHookLabel,\PopDefaultHookLabel} % \begin{syntax} -% \cs{DeclareDefaultHookLabel} \Arg{default label} +% \cs{PushDefaultHookLabel} \Arg{default label} +% \quad \meta{code} +% \cs{PopDefaultHookLabel} % \end{syntax} -% Sets the \meta{default label} to be used in \meta{label} arguments. -% If \cs{DeclareDefaultHookLabel} is not used in the -% current package, \cs{@currname} is used instead. If \cs{@currname} -% is not set, the code is assumed to be in the main document, in which -% case \texttt{top-level} is used. -% -% The effect of \cs{DeclareDefaultHookLabel} holds for the current -% file, and is reset to the previous value when the file is closed. +% \cs{PushDefaultHookLabel} sets the current \meta{default label} to +% be used in \meta{label} arguments, or when replacing a leading +% ``|.|'' (see above). \cs{PopDefaultHookLabel} reverts the +% \meta{default label} to its previous value. +% +% Inside a package or class, the \meta{default label} is equal to the +% package or class name, unless explicitly changed. Everywhere else, +% the \meta{default label} is |top-level| (see +% section~\ref{sec:top-level}) unless explicitly changed. +% +% The effect of \cs{PushDefaultHookLabel} holds until the next +% \cs{PopDefaultHookLabel}. \cs{usepackage} (and \cs{RequirePackage} +% and \cs{documentclass}) internally use +% \begin{quote} +% \cs{PushDefaultHookLabel}\Arg{package name} \\ +% \null \quad \meta{package code} \\ +% \cs{PopDefaultHookLabel} +% \end{quote} +% to set the \meta{default label} for the package or class file. +% Inside the \meta{package code} the \meta{default label} can also be +% changed with \cs{SetDefaultHookLabel}. \cs{input} and other +% file input-related commands from the \LaTeX{} kernel do not use +% \cs{PushDefaultHookLabel}, so code within files loaded by these +% commands does \emph{not} get a dedicated \meta{label}! (that is, the +% \meta{default label} is the current active one when the file was +% loaded.) +% +% Packages that provide their own package-like interfaces +% (Ti\textit{k}Z's \cs{usetikzlibrary}, for example) can use +% \cs{PushDefaultHookLabel} and \cs{PopDefaultHookLabel} to set +% dedicated labels and emulate \cs{usepackage}-like hook behaviour +% within those contexts. +% +% The |top-level| label is treated differently, and is reserved to the +% user document, so it is not allowed to change the +% \meta{default label} to |top-level|. +% \end{function} +% +% \begin{function}{\SetDefaultHookLabel} +% \begin{syntax} +% \cs{SetDefaultHookLabel} \Arg{default label} +% \end{syntax} +% Similarly to \cs{PushDefaultHookLabel}, +% sets the current \meta{default label} to +% be used in \meta{label} arguments, or when replacing a leading +% ``|.|''. The effect holds until the label is changed again or until +% the next \cs{PopDefaultHookLabel}. The difference between +% \cs{PushDefaultHookLabel} and \cs{SetDefaultHookLabel} is that the +% latter does not save the current \meta{default label}. +% +% This command is useful when a large package is composed of several +% smaller packages, but all should have the same \meta{label}, so +% \cs{SetDefaultHookLabel} can be used at the beginning of each +% package file to set the correct label. +% +% \cs{SetDefaultHookLabel} is not allowed in the main document, where +% the \meta{default label} is |top-level| and there is no +% \cs{PopDefaultHookLabel} to end its effect. +% It is also not allowed to change the \meta{default label} to +% |top-level|. % \end{function} % +% \subsubsection{The \texttt{top-level} label} +% \label{sec:top-level} +% +% The |top-level| label, assigned to code added from the main document, +% is different from other labels. Code added to hooks (usually +% \cs{AtBeginDocument}) in the preamble is almost always to change +% something defined by a package, so it should go at the very end of the +% hook. +% +% Therefore, code added in the |top-level| is always executed at the end +% of the hook, regardless of where it was declared. If the hook is +% reversed (see \cs{NewReversedHook}), the |top-level| chunk is executed +% at the very beginning instead. +% +% Rules regarding |top-level| have no effect: if a user wants to have a +% specific set of rules for a code chunk, they should use a different +% label to said code chunk, and provide a rule for that label instead. +% +% The |top-level| label is exclusive for the user, so trying to add code +% with that label from a package results in an error. % % \subsubsection{Defining relations between hook code} % % The default assumption is that code added to hooks by different -% packages is independent and the order in which it is executed is -% irrelevant. While this is true in many case it is obviously false -% in many others. +% packages are independent and the order in which they are executed is +% irrelevant. While this is true in many cases it is obviously false +% in others. % % Before the hook management system was introduced % packages had to take elaborate precaution to determine of some other @@ -589,7 +665,8 @@ % its permanent code pool, or to its ``next'' token list. The hook % doesn't need to be declared to have code added to its code pool. % A hook is said to exist when it was declared with \cs{NewHook} or -% some variant thereof. +% some variant thereof. Generic \hook{file} and \hook{env} hooks are +% automatically declared when code is added to them. % % \begin{function}[EXP]{\IfHookEmptyTF} % \begin{syntax} @@ -650,6 +727,7 @@ % \item % any code executed on the next invocation only. % \end{itemize} +% \end{function} % % \cs{LogHook} prints the information to the |.log| file, and % \cs{ShowHook} prints them to the terminal/command window and starts @@ -660,6 +738,7 @@ % %^^A % Code for the listing below: %^^A \NewHook{example-hook} +%^^A \AddToHook{example-hook}{[code from 'top-level']} %^^A \AddToHook{example-hook}[foo]{[code from package 'foo']} %^^A \AddToHook{example-hook}[bar]{[from package 'bar']} %^^A \AddToHook{example-hook}[baz]{[package 'baz' is here]} @@ -680,13 +759,15 @@ % > foo -> [code from package 'foo'] % > bar -> [from package 'bar'] % > baz -> [package 'baz' is here] +% > Document-level (top-level) code (executed last): +% > -> [code from 'top-level'] % > Extra code for next invocation: % > -> [one-time code] % > Rules: % > foo|baz with relation > % > baz|bar with default relation < % > Execution order (after applying rules): -% > bar, baz, foo. +% > baz, foo, bar. % \end{verbatim} % % In the listing above, lines~3 to~5 show the three code chunks added @@ -695,7 +776,18 @@ % \quad \meta{label}\verb| -> |\meta{code} % \end{quote} % -% Line~7 shows the code chunk for the next execution of the hook in +% Line~7 shows the code chunk added by the user in the main document +% (labeled |top-level|) in the format +% \begin{quote} +% \quad\verb|Document-level (top-level) code (executed |%^^A +% \meta{first\texttt{\string|}last}\verb|):|\\ +% \quad\verb| -> |\meta{\texttt{top-level} code} +% \end{quote} +% This code will be either the first or last code executed by the hook +% (|last| if the hook is normal, |first| if it is reversed). This +% chunk is not affected by rules and does not take part in sorting. +% +% Line~9 shows the code chunk for the next execution of the hook in % the format % \begin{quote} % \quad \verb|-> |\meta{next-code} @@ -705,7 +797,7 @@ % earlier, which can only be removed from that hook by doing % \verb|\RemoveFromHook{|\meta{label}|}[example-hook]|. % -% Lines~9 and~10 show the rules declared that affect this hook in the +% Lines~11 and~12 show the rules declared that affect this hook in the % format % \begin{quote} % \quad \meta{label-1}\verb+|+\meta{label-2}| with |%^^A @@ -717,9 +809,8 @@ % to \meta{label-1} and \meta{label-2} in \emph{all} hooks, (unless % overrided by a non-default relation). % -% Finally, line~12 lists the labels in the hook after sorting; +% Finally, line~14 lists the labels in the hook after sorting; % that is, in the order they will be executed when the hook is used. -% \end{function} % % % \subsubsection{Debugging hook code} @@ -749,8 +840,9 @@ % \begin{function} % {\hook_new:n,\hook_new_reversed:n,\hook_new_pair:nn} % \begin{syntax} -% \cs{hook_new:n}\Arg{hook} -% \cs{hook_new_pair:nn}\Arg{hook-1}\Arg{hook-2} +% \cs{hook_new:n} \Arg{hook} +% \cs{hook_new_reversed:n} \Arg{hook} +% \cs{hook_new_pair:nn} \Arg{hook-1} \Arg{hook-2} % \end{syntax} % Creates a new \meta{hook} with normal or reverse ordering of code % chunks. \cs{hook_new_pair:nn} creates a pair of such hooks with @@ -782,7 +874,6 @@ % Changes the \Arg{hook} status so that from now on any addition to % the hook code is executed immediately. Then execute any % \Arg{hook} code already set up. -% \fmi{better L3 name?} % % The \meta{hook} \emph{cannot} be specified using the dot-syntax. % A leading |.| is treated literally. @@ -954,17 +1045,19 @@ % \texttt{packageB}, \texttt{packageC} which you can verify with % \cs{ShowHook}\texttt{\{myhook\}}: %\begin{verbatim} -% The hook 'myhook': -% Code chunks: -% packageA -> \typeout {A} -% packageB -> \typeout {B} -% packageC -> \typeout {C} -% Extra code next invocation: -% --- -% Rules: -% --- -% Execution order: -% packageA, packageB, packageC +% -> The hook 'myhook': +% > Code chunks: +% > packageA -> \typeout {A} +% > packageB -> \typeout {B} +% > packageC -> \typeout {C} +% > Document-level (top-level) code (executed last): +% > --- +% > Extra code for next invocation: +% > --- +% > Rules: +% > --- +% > Execution order: +% > packageA, packageB, packageC. %\end{verbatim} % The reason is that the code chunks are internally saved in a property list % and the initial order of such a property list is the order in @@ -988,17 +1081,19 @@ %\end{verbatim} % instead of the previous lines we get %\begin{verbatim} -% The hook 'myhook': -% Code chunks: -% packageA -> \typeout {A} -% packageB -> \typeout {B} -% packageC -> \typeout {C} -% Extra code next invocation: -% --- -% Rules: -% packageA|packageB with relation before -% Execution order (after applying rules): -% packageA, packageC, packageB +% -> The hook 'myhook': +% > Code chunks: +% > packageA -> \typeout {A} +% > packageB -> \typeout {B} +% > packageC -> \typeout {C} +% > Document-level (top-level) code (executed last): +% > --- +% > Extra code for next invocation: +% > --- +% > Rules: +% > packageB|packageA with relation > +% > Execution order (after applying rules): +% > packageA, packageC, packageB. %\end{verbatim} % As you can see the code chunks are still in the same order, but % in the execution order for the labels \texttt{packageB} and @@ -1010,7 +1105,7 @@ % doesn't run at all as there is nothing to resolve). % Incidentally, if we had instead specified the redundant rule %\begin{verbatim} -% \DeclareHookRule{myhook}{packageB}{before}{label-3} +% \DeclareHookRule{myhook}{packageB}{before}{packageC} %\end{verbatim} % the execution order would not have changed. % @@ -1039,17 +1134,17 @@ % \AddToHook{env/quote/after} [package-1]{\end{itshape}} %\end{verbatim} % As a result, all quotes will be in italics. -% Now suppose further that the user wants the quotes also in blue -% and therefore adds: +% Now suppose further that another |package-too| makes the quotes +% also in blue and therefore adds: %\begin{verbatim} % \usepackage{color} -% \AddToHook{env/quote/before}{\begin{color}{blue}} -% \AddToHook{env/quote/after} {\end{color}} +% \AddToHook{env/quote/before}[package-too]{\begin{color}{blue}} +% \AddToHook{env/quote/after} [package-too]{\end{color}} %\end{verbatim} % Now if the \hook{env/quote/after} hook would be a normal hook we % would get the same execution order in both hooks, namely: %\begin{verbatim} -% package-1, top-level +% package-1, package-too %\end{verbatim} % (or vice versa) and as a result, would get: %\begin{verbatim} @@ -1063,16 +1158,18 @@ % the correct sequence and \cs{ShowHook} would give us the % following output: %\begin{verbatim} -% The hook 'env/quote/after': -% Code chunks: -% package-1 -> \end {itshape} -% top-level -> \end {color} -% Extra code next invocation: -% --- -% Rules: -% --- -% Execution order (after reversal): -% top-level, package-1 +% -> The hook 'env/quote/after': +% > Code chunks: +% > package-1 -> \end {itshape} +% > package-too -> \end {color} +% > Document-level (top-level) code (executed first): +% > --- +% > Extra code for next invocation: +% > --- +% > Rules: +% > --- +% > Execution order (after reversal): +% > package-too, package-1. %\end{verbatim} % % The reversal of the execution order happens before applying any @@ -1206,13 +1303,15 @@ % \hook{begindocument} % (which is executed inside \verb=\begin{document}=). % However, all code added this way is labeled with the label -% \hook{top-level} if done outside of a package or class or with the -% package/class name if called inside such a file. +% \hook{top-level} (see section~\ref{sec:top-level}) +% if done outside of a package or class or with the +% package/class name if called inside such a file +% (see section~\ref{sec:default-label}). % % This way one can add further code to the hook using % \cs{AddToHook} or \cs{AtBeginDocument} using a different label % and explicitly order the code chunks as necessary, e.g., run some -% code before or after the \hook{top-level} code. When using the +% code before or after another package's code. When using the % optional argument the call is equivalent to running % \cs{AddToHook} \texttt{\{begindocument\}} \oarg{label} % \Arg{code}. @@ -1251,7 +1350,7 @@ % The few hooks that existed previously in \LaTeXe{} used internally % commands such as \cs{@begindocumenthook} and packages sometimes % augemented them directly rather than working through -% \cs{AtBeginDocumement}. For that reason there is currently support +% \cs{AtBeginDocument}. For that reason there is currently support % for this, that is, if the system detects that such an internal % legacy hook command contains code it adds it to the new hook % system under the label \texttt{legacy} so that it doesn't get @@ -1333,8 +1432,8 @@ % \cs{BeforeBeginEnvironment} \oarg{label} \Arg{code} % \end{syntax} % This declaration adds to the \hook{env/\meta{env}/before} hook -% using by default the current package or class name as a label or -% \texttt{top-level} if used in the document directly. +% using the \meta{label}. If \meta{label} is not given, the +% \meta{default label} is used (see section~\ref{sec:default-label}). % \end{function} % % \begin{function}{\AtBeginEnvironment} @@ -1774,6 +1873,37 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_tl_set:Nn,\@@_tl_set:cn,\@@_tl_set:cx} +% \begin{macro}{\@@_tl_gset:Nn,\@@_tl_gset:cn,\@@_tl_gset:co,\@@_tl_gset:cx} +% \begin{macro}{\@@_tl_gput_right:Nn,\@@_tl_gput_right:No,\@@_tl_gput_right:cn} +% \begin{macro}{\@@_tl_gput_left:Nn,\@@_tl_gput_left:No} +% \begin{macro}{\@@_tl_gclear:N,\@@_tl_gclear:c} +% \begin{macro}{\@@_tl_gset_eq:NN} +% Private copies of a few \pkg{expl3} functions. \pkg{l3debug} will +% only add debugging to the public names, not to these copies, so we +% don't have to use \cs{debug_suspend:} and \cs{debug_resume:} +% everywhere. +% \begin{macrocode} +\cs_new_eq:NN \@@_tl_set:Nn \tl_set:Nn +\cs_generate_variant:Nn \@@_tl_set:Nn { cn, cx } +\cs_new_eq:NN \@@_tl_gset:Nn \tl_gset:Nn +\cs_generate_variant:Nn \@@_tl_gset:Nn { cn, co, cx } +\cs_new_eq:NN \@@_tl_gput_right:Nn \tl_gput_right:Nn +\cs_generate_variant:Nn \@@_tl_gput_right:Nn { No, cn } +\cs_new_eq:NN \@@_tl_gput_left:Nn \tl_gput_left:Nn +\cs_generate_variant:Nn \@@_tl_gput_left:Nn { No } +\cs_new_protected:Npn \@@_tl_gclear:N #1 + { \@@_tl_gset_eq:NN #1 \c_empty_tl } +\cs_generate_variant:Nn \@@_tl_gclear:N { c } +\cs_new_eq:NN \@@_tl_gset_eq:NN \tl_gset_eq:NN +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% % % \subsection{Providing new hooks} % @@ -1808,6 +1938,13 @@ % $\meta{reversed}1$ is $+1$ for normal hooks and $-1$ for reversed % ones. % +% \item[\cs{@@_toplevel~\meta{name}}] This token list stores the code +% inserted in the hook from the user's document, in the |top-level| +% label. This label is special, and doesn't participate in sorting. +% Instead, all code is appended to it and executed after (or before, +% if the hook is reversed) the normal +% hook code, but before the |next| code chunk. +% % \item[\cs{@@_next~\meta{name}}] Finally there is extra code % (normally empty) that is used on the next invocation of the hook % (and then deleted). This can be used to define some special @@ -1890,15 +2027,16 @@ % \begin{macro}{\@@_declare:n} % This function declares the basic data structures for a hook without % actually declaring the hook itself. This is needed to allow adding -% to undeclared hooks. Here it is unnecessary to check whether both -% variables exist, since both are declared at the same time (either -% both exist, or neither). +% to undeclared hooks. Here it is unnecessary to check whether all +% variables exist, since all three are declared at the same time +% (either all of them exist, or none). % \begin{macrocode} \cs_new_protected:Npn \@@_declare:n #1 { \@@_if_exist:nF {#1} { \prop_new:c { g_@@_#1_code_prop } + \tl_new:c { @@_toplevel~#1 } \tl_new:c { @@_next~#1 } } } @@ -1951,13 +2089,6 @@ \cs_new_protected:Npn \@@_include_legacy_code_chunk:n #1 { % \end{macrocode} -% If the \pkg{expl3} code is run with checking on then assigning or -% using non L3 names such as \cs{@enddocumenthook} with \pkg{expl3} -% functions will trigger warnings so we run this code with -% debugging explicitly suspended. -% \begin{macrocode} - \debug_suspend: -% \end{macrocode} % If the macro doesn't exist (which is the usual case) then nothing % needs to be done. % \begin{macrocode} @@ -1975,10 +2106,9 @@ % Once added to the hook, we need to clear it otherwise it might % get added again later if the hook data gets updated. % \begin{macrocode} - \tl_gclear:c { @#1hook } + \@@_tl_gclear:c { @#1hook } } } - \debug_resume: } % \end{macrocode} % \end{macro} @@ -1990,79 +2120,76 @@ % \begin{macro}[EXP]{\@@_parse_label_default:n} % This macro checks if a label was given (not \cs{c_novalue_tl}), and % if so, tries to parse the label looking for a leading \verb|.| to -% replace for \cs{@currname}. Otherwise \cs{@@_currname_or_default:n} -% is used to pick \cs{@currname} or the fallback value. -% -% The default |top-level| is hard-coded here. It once was an -% argument, but it's no longer needed. \pho{can't remember why} +% replace by \cs{@@_currname_or_default:}. % \begin{macrocode} \cs_new:Npn \@@_parse_label_default:n #1 { \tl_if_novalue:nTF {#1} - { \@@_currname_or_default:n { top-level } } - { - \tl_trim_spaces_apply:nN {#1} - \@@_parse_dot_label:nn { top-level } - } + { \@@_currname_or_default: } + { \tl_trim_spaces_apply:nN {#1} \@@_parse_dot_label:n } } % \end{macrocode} % \end{macro} % -% \begin{macro}[EXP]{\@@_parse_dot_label:nn} +% \begin{macro}[EXP]{\@@_parse_dot_label:n} % \begin{macro}[EXP]{ -% \@@_parse_dot_label:nw, +% \@@_parse_dot_label:w, % \@@_parse_dot_label_cleanup:w, -% \@@_parse_dot_label_aux:nw +% \@@_parse_dot_label_aux:w % } % Start by checking if the label is empty, which raises an error, and % uses the fallback value. If not, % split the label at a \verb|./|, if any, and check if no tokens are % before the \verb|./|, or if the only character is a \verb|.|. % If these requirements are fulfilled, the leading -% \verb|.| is replaced with \cs{@@_currname_or_default:n}. Otherwise +% \verb|.| is replaced with \cs{@@_currname_or_default:}. Otherwise % the label is returned unchanged. % \begin{macrocode} -\cs_new:Npn \@@_parse_dot_label:nn #1 #2 +\cs_new:Npn \@@_parse_dot_label:n #1 { \tl_if_empty:nTF {#1} { - \msg_expandable_error:nnn { hooks } { empty-label } {#2} - #2 + \msg_expandable_error:nn { hooks } { empty-label } + \@@_currname_or_default: } { \str_if_eq:nnTF {#1} { . } - { \@@_currname_or_default:n {#2} } - { \@@_parse_dot_label:nw {#2} #1 ./ \s_@@_mark } + { \@@_currname_or_default: } + { \@@_parse_dot_label:w #1 ./ \s_@@_mark } } } -\cs_new:Npn \@@_parse_dot_label:nw #1 #2 ./ #3 \s_@@_mark +\cs_new:Npn \@@_parse_dot_label:w #1 ./ #2 \s_@@_mark { - \tl_if_empty:nTF {#2} - { \@@_parse_dot_label_aux:nw {#1} #3 \s_@@_mark } + \tl_if_empty:nTF {#1} + { \@@_parse_dot_label_aux:w #2 \s_@@_mark } { - \tl_if_empty:nTF {#3} - { \@@_make_name:n {#2} } - { \@@_parse_dot_label_cleanup:w #2 ./ #3 \s_@@_mark } + \tl_if_empty:nTF {#2} + { \@@_make_name:n {#1} } + { \@@_parse_dot_label_cleanup:w #1 ./ #2 \s_@@_mark } } } \cs_new:Npn \@@_parse_dot_label_cleanup:w #1 ./ \s_@@_mark {#1} -\cs_new:Npn \@@_parse_dot_label_aux:nw #1 #2 ./ \s_@@_mark - { \@@_currname_or_default:n {#1} / \@@_make_name:n {#2} } +\cs_new:Npn \@@_parse_dot_label_aux:w #1 ./ \s_@@_mark + { \@@_currname_or_default: / \@@_make_name:n {#1} } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[EXP]{\@@_currname_or_default:n} +% \begin{macro}[EXP]{\@@_currname_or_default:} % Uses \cs{g_@@_hook_curr_name_tl} if it is set, otherwise tries -% \cs{@currname}. If neither is set, uses the fallback value -% \verb|#1| (usually \texttt{top-level}). +% \cs{@currname}. If neither is set, raises an error and uses the +% fallback value \verb|label-missing|. % \begin{macrocode} -\cs_new:Npn \@@_currname_or_default:n #1 +\cs_new:Npn \@@_currname_or_default: { \tl_if_empty:NTF \g_@@_hook_curr_name_tl { \tl_if_empty:NTF \@currname - { \@@_make_name:n {#1} } + { + \msg_expandable_error:nnn { hooks } { should-not-happen } + { Empty~default~label. } + \@@_make_name:n { label-missing } + } { \@currname } } { \g_@@_hook_curr_name_tl } @@ -2213,14 +2340,33 @@ % \end{macrocode} % Then try to get the code chunk labeled \verb=#2= from the hook. % If there's code already there, then append \verb=#3= to that, -% otherwise just put \verb=#3=. +% otherwise just put \verb=#3=. If the current label is |top-level|, +% the code is added to a dedicated token list +% \cs[no-index]{@@_toplevel~\meta{hook}} that goes at the end of the +% hook (or at the beginning, for a reversed hook), just before +% \cs[no-index]{@@_next~\meta{hook}}. +% \begin{macrocode} + \str_if_eq:nnTF {#2} { top-level } + { + \str_if_eq:eeTF { top-level } { \@@_currname_or_default: } + { +% \end{macrocode} +% If the hook's basic structure does not exist, we need to declare it +% with \cs{@@_declare:n}. % \begin{macrocode} - \prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl + \@@_declare:n {#1} + \@@_tl_gput_right:cn { @@_toplevel~#1 } {#3} + } + { \msg_error:nnn { hooks } { misused-top-level } {#1} } + } { - \prop_gput:cno { g_@@_#1_code_prop } {#2} - { \l_@@_return_tl #3 } + \prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl + { + \prop_gput:cno { g_@@_#1_code_prop } {#2} + { \l_@@_return_tl #3 } + } + { \prop_gput:cnn { g_@@_#1_code_prop } {#2} {#3} } } - { \prop_gput:cnn { g_@@_#1_code_prop } {#2} {#3} } } % \end{macrocode} % \end{macro} @@ -2434,24 +2580,48 @@ % hook before its defined (see section~\ref{sec:querying}). % \begin{macrocode} \@@_if_exist:nTF {#1} + { % \end{macrocode} % Then remove the chunk and run \cs{@@_update_hook_code:n} so % that the execution token list reflects the change if we are after % \verb=\begin{document}=. +% +% If all code is to be removed, clear the code pool +% \cs[no-index]{g_@@_\meta{hook}_code_prop}, the top-level code +% \cs[no-index]{@@_toplevel~\meta{hook}}, and the next-execution code +% \cs[no-index]{@@_next~\meta{hook}}. % \begin{macrocode} - { \str_if_eq:nnTF {#2} {*} - { \prop_gclear:c { g_@@_#1_code_prop } } { + \prop_gclear:c { g_@@_#1_code_prop } + \@@_tl_gclear:c { @@_toplevel~#1 } + \@@_tl_gclear:c { @@_next~#1 } + } + { +% \end{macrocode} +% If the label is |top-level| then clear the token list, as all code +% there is under the same label. Marked removal is not implemented +% for |top-level| because it is hard to reliably know that no code +% was added to \cs[no-index]{@@_toplevel~\meta{hook}} (granted that +% an empty code could be interpreted as that, but then it differs in +% behaviour from other labels, in which an empty chunk is still valid +% for removal). Besides, it doesn't make much (if any) sense for +% packages to remove |top-level| code. So here the chunk is just +% cleared unconditionally. +% \begin{macrocode} + \str_if_eq:nnTF {#2} { top-level } + { \@@_tl_gclear:c { @@_toplevel~#1 } } + { % \end{macrocode} -% Check if the label being removed exists in the code pool. If it does, -% just call \cs{@@_gremove_code_do:nn} to do the removal, otherwise mark it -% to be removed. +% Otherwise check if the label being removed exists in the code pool. +% If it does, just call \cs{@@_gremove_code_do:nn} to do the removal, +% otherwise mark it to be removed. % \begin{macrocode} - \prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl - { \@@_gremove_code_do:nn } - { \@@_mark_removal:nn } - {#1} {#2} + \prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl + { \@@_gremove_code_do:nn } + { \@@_mark_removal:nn } + {#1} {#2} + } } % \end{macrocode} % Finally update the code, if the hook exists. @@ -2470,6 +2640,7 @@ % \end{macrocode} % % \begin{macro}{\@@_gremove_code_do:nn} +% Remove code for a given label. % \begin{macrocode} \cs_new_protected:Npn \@@_gremove_code_do:nn #1 #2 { \prop_gremove:cn { g_@@_#1_code_prop } {#2} } @@ -2605,7 +2776,6 @@ % Then we call the function to handle the given rule. Throw an error if the % rule is invalid. % \begin{macrocode} - \debug_suspend: \cs_if_exist_use:cTF { @@_rule_#3_gset:nnn } { {#1} {#2} {#4} @@ -2613,7 +2783,6 @@ } { \msg_error:nnnnnn { hooks } { unknown-rule } {#1} {#2} {#3} {#4} } - \debug_resume: } % \end{macrocode} % \end{macro} @@ -2639,7 +2808,7 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_rule_before_gset:nnn #1#2#3 { - \tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } + \@@_tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } { \@@_label_ordered:nnTF {#2} {#3} { < } { > } } } \cs_new_eq:cN { @@_rule_<_gset:nnn } \@@_rule_before_gset:nnn @@ -2648,7 +2817,7 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_rule_after_gset:nnn #1#2#3 { - \tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#3} {#2} _tl } + \@@_tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#3} {#2} _tl } { \@@_label_ordered:nnTF {#3} {#2} { < } { > } } } \cs_new_eq:cN { @@_rule_>_gset:nnn } \@@_rule_after_gset:nnn @@ -2661,7 +2830,7 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_rule_voids_gset:nnn #1#2#3 { - \tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } + \@@_tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } { \@@_label_ordered:nnTF {#2} {#3} { -> } { <- } } } % \end{macrocode} @@ -2675,9 +2844,9 @@ % together in hook |#1|. % \begin{macrocode} \cs_new_protected:cpn { @@_rule_incompatible-error_gset:nnn } #1#2#3 - { \tl_gset:cn { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } { xE } } + { \@@_tl_gset:cn { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } { xE } } \cs_new_protected:cpn { @@_rule_incompatible-warning_gset:nnn } #1#2#3 - { \tl_gset:cn { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } { xW } } + { \@@_tl_gset:cn { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } { xW } } % \end{macrocode} % \end{macro} % @@ -2722,7 +2891,7 @@ % \end{macro} % % \begin{macro}[EXP]{\@@_if_label_case:nnnnn} -% To avoid doing the string comparison twice in \cs{@@_initialize_single:NNNn} +% To avoid doing the string comparison twice in \cs{@@_initialize_single:NNn} % (once with \cs{str_if_eq:nn} and again with \cs{@@_label_ordered:nn}), % we use a three-way branching macro that will compare |#1| and |#2| % and expand to \cs{use_i:nnn} if they are equal, \cs{use_ii:nn} if @@ -2800,7 +2969,6 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_initialize_hook_code:n #1 { - \debug_suspend: \@@_debug:n{ \iow_term:x{^^JUpdate~ code~ for~ hook~ '#1' \on@line :^^J} } % \end{macrocode} @@ -2815,17 +2983,22 @@ % If there aren't any code % chunks for the current hook, there is no point in even starting % the sorting routine so we make a quick test for that and in that -% case just update \cs{@@~\meta{hook}} to hold the next -% code. If there are code chunks we call -% \cs{@@_initialize_single:NNNn} and pass to it ready made csnames +% case just update \cs{@@~\meta{hook}} to hold the |top-level| and +% |next| code chunks. If there are code chunks we call +% \cs{@@_initialize_single:NNn} and pass to it ready made csnames % as they are needed several times inside. This way we save a bit % on processing time if we do that up front. % \begin{macrocode} \hook_if_exist:nT {#1} { \prop_if_empty:cTF {g_@@_#1_code_prop} - { \tl_gset:co { @@~#1 } - { \cs:w @@_next~#1 \cs_end: } } + { + \@@_tl_gset:co { @@~#1 } + { + \cs:w @@_toplevel~#1 \exp_after:wN \cs_end: + \cs:w @@_next~#1 \cs_end: + } + } { % \end{macrocode} % By default the algorithm sorts the code chunks and then saves the @@ -2836,9 +3009,9 @@ % in preparation is to change two definitions used later on. % \begin{macrocode} \@@_if_reversed:nTF {#1} - { \cs_set_eq:NN \@@_tl_gput:NV \tl_gput_left:NV + { \cs_set_eq:NN \@@_tl_gput:Nn \@@_tl_gput_left:Nn \cs_set_eq:NN \@@_clist_gput:NV \clist_gput_left:NV } - { \cs_set_eq:NN \@@_tl_gput:NV \tl_gput_right:NV + { \cs_set_eq:NN \@@_tl_gput:Nn \@@_tl_gput_right:Nn \cs_set_eq:NN \@@_clist_gput:NV \clist_gput_right:NV } % \end{macrocode} % @@ -2848,9 +3021,8 @@ % save the old code property list so that it can be restored later. % \begin{macrocode} \prop_set_eq:Nc \l_@@_work_prop { g_@@_#1_code_prop } - \@@_initialize_single:cccn - { @@~#1 } { @@_next~#1 } - { g_@@_#1_labels_clist } {#1} + \@@_initialize_single:ccn + { @@~#1 } { g_@@_#1_labels_clist } {#1} % \end{macrocode} % For debug display we want to keep track of those hooks that % actually got code added to them, so we record that in plist. We @@ -2862,7 +3034,6 @@ \g_@@_used_prop {#1}{} } } } - \debug_resume: } % \end{macrocode} % \end{macro} @@ -2918,12 +3089,13 @@ % \end{macro} % % -% \begin{macro}{\@@_initialize_single:NNNn,\@@_initialize_single:cccn} +% \begin{macro}{\@@_initialize_single:NNn,\@@_initialize_single:ccn} % -% \cs{@@_initialize_single:NNNn} implements the sorting of the code +% \cs{@@_initialize_single:NNn} implements the sorting of the code % chunks for a hook and saves the result in the token list for fast -% execution (\verb=#3=). The arguments are \meta{hook-code-plist}, -% \meta{hook-code-tl}, \meta{hook-next-code-tl}, +% execution (\verb=#4=). The arguments are \meta{hook-code-plist}, +% \meta{hook-code-tl}, \meta{hook-top-level-code-tl}, +% \meta{hook-next-code-tl}, % \meta{hook-ordered-labels-clist} and \meta{hook-name} (the latter % is only used for debugging---the \meta{hook-rule-plist} is accessed % using the \meta{hook-name}). @@ -2935,8 +3107,12 @@ % far as possible. The result is a restriction I do not test for at % the moment: a label can't be equal to the number 0! \fmi{Needs % checking for, just in case} +% +% ^^A #1 <- \@@~#1 +% ^^A #2 <- \g_@@_#1_labels_clist +% ^^A #3 <- #1 % \begin{macrocode} -\cs_new_protected:Npn \@@_initialize_single:NNNn #1#2#3#4 +\cs_new_protected:Npn \@@_initialize_single:NNn #1#2#3 { % \end{macrocode} % Step T1: Initialize the data structure \ldots @@ -2947,7 +3123,7 @@ % % Store the name of the hook: % \begin{macrocode} - \tl_set:Nn \l_@@_cur_hook_tl {#4} + \tl_set:Nn \l_@@_cur_hook_tl {#3} % \end{macrocode} % % We loop over the property list holding the code and record all @@ -2961,7 +3137,7 @@ { \int_incr:N \l_@@_labels_int \seq_put_right:Nn \l_@@_labels_seq {##1} - \tl_set:cn { \@@_tl_csname:n {##1} }{0} + \@@_tl_set:cn { \@@_tl_csname:n {##1} } { 0 } \seq_clear_new:c { \@@_seq_csname:n {##1} } } % \end{macrocode} @@ -2987,7 +3163,7 @@ { \prop_map_break: } { \@@_apply_label_pair:nnn {##1} {####1} } { \@@_apply_label_pair:nnn {####1} {##1} } - {#4} + {#3} } } % \end{macrocode} @@ -3014,8 +3190,8 @@ % \end{macrocode} % % \begin{macrocode} - \tl_gclear:N #1 - \clist_gclear:N #3 + \@@_tl_gclear:N #1 + \clist_gclear:N #2 % \end{macrocode} % % The whole loop combines steps T5--T7: @@ -3027,11 +3203,11 @@ % \begin{macrocode} \int_decr:N \l_@@_labels_int \prop_get:NVN \l_@@_work_prop \l_@@_front_tl \l_@@_return_tl - \@@_tl_gput:NV #1 \l_@@_return_tl + \exp_args:NNV \@@_tl_gput:Nn #1 \l_@@_return_tl % \end{macrocode} % % \begin{macrocode} - \@@_clist_gput:NV #3 \l_@@_front_tl + \@@_clist_gput:NV #2 \l_@@_front_tl \@@_debug:n{ \iow_term:x{Handled~ code~ for~ \l_@@_front_tl} } % \end{macrocode} % @@ -3078,27 +3254,31 @@ } % \end{macrocode} % After we have added all hook code to \verb=#1= we finish it off -% with adding extra code for a one time execution. That is stored -% in \verb=#2= but is normally empty. -% \begin{macrocode} - \tl_gput_right:Nn #1 {#2} +% with adding extra code for the |top-level| (\verb=#2=) and for one +% time execution (\verb=#3=). These should normally be empty. The +% |top-level| code is added with \cs{@@_tl_gput:Nn} as that might +% change for a reversed hook (then |top-level| is the very first code +% chunk added). The |next| code is always added last. +% \begin{macrocode} + \exp_args:NNo \@@_tl_gput:Nn #1 { \cs:w @@_toplevel~#3 \cs_end: } + \@@_tl_gput_right:No #1 { \cs:w @@_next~#3 \cs_end: } } % \end{macrocode} -% +% % \begin{macrocode} -\cs_generate_variant:Nn \@@_initialize_single:NNNn {ccc} +\cs_generate_variant:Nn \@@_initialize_single:NNn { cc } % \end{macrocode} % \end{macro} % % % -% \begin{macro}{\@@_tl_gput:NV,\@@_clist_gput:NV} +% \begin{macro}{\@@_tl_gput:Nn,\@@_clist_gput:NV} % These append either on the right (normal hook) or on the left % (reversed hook). This is setup up in % \cs{@@_initialize_hook_code:n}, elsewhere their behavior is undefined. % \begin{macrocode} -\cs_new:Npn \@@_tl_gput:NV {\ERROR} -\cs_new:Npn \@@_clist_gput:NV {\ERROR} +\cs_new:Npn \@@_tl_gput:Nn { \ERROR } +\cs_new:Npn \@@_clist_gput:NV { \ERROR } % \end{macrocode} % \end{macro} % @@ -3347,7 +3527,8 @@ % \begin{macrocode} \hook_if_exist:nF {#1} { \@@_log_line:x { is~not~declared! } } - \@@_if_exist:nTF {#1} + \hook_if_empty:nTF {#1} + { #2 { The~hook~is~empty } } { \@@_log_line:x { Code~chunks: } \prop_if_empty:cTF { g_@@_#1_code_prop } @@ -3357,9 +3538,25 @@ { \@@_log_line_indent:x { ##1~->~\tl_to_str:n {##2} } } } % \end{macrocode} -% +% +% If there is code in the |top-level| token list, print it: % \begin{macrocode} - \@@_log_line:x { Extra~code~for~next~invocation:} + \@@_log_line:x + { + Document-level~(top-level)~code + \hook_if_exist:nT {#1} + { ~(executed~\@@_if_reversed:nTF {#1} {first} {last} ) } : + } + \@@_log_line_indent:x + { + \tl_if_empty:cTF { @@_toplevel~#1 } + { --- } + { -> ~ \exp_args:Nv \tl_to_str:n { @@_toplevel~#1 } } + } +% \end{macrocode} +% +% \begin{macrocode} + \@@_log_line:x { Extra~code~for~next~invocation: } \@@_log_line_indent:x { \tl_if_empty:cTF { @@_next~#1 } @@ -3427,7 +3624,6 @@ } } } - { #2 { The~hook~is~empty. } } } % \end{macrocode} % @@ -3478,7 +3674,7 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_list_one_rule:nnn #1#2#3 { - \@@_list_if_rule_exists:nnnF {#1} {#2} {#3} { } + \@@_list_if_rule_exists:nnnF {#1} {#2} {#3} { \@@_list_if_rule_exists:nnnF {#1} {#2} { ?? } { } } } \cs_new_protected:Npn \@@_list_if_rule_exists:nnnF #1#2#3 @@ -3486,7 +3682,9 @@ \if_cs_exist:w g_@@_ #3 _rule_ #1 | #2 _tl \cs_end: \exp_args:Nv \@@_tmp:w { g_@@_ #3 _rule_ #1 | #2 _tl } { #1 | #2 } {#3} + \exp_after:wN \use_none:nn \fi: + \use:n } % \end{macrocode} % \end{macro} @@ -3528,12 +3726,10 @@ { \@@_normalize_hook_args:Nn \@@_gput_next_code:nn {#1} } \cs_new_protected:Npn \@@_gput_next_code:nn #1 #2 { - \debug_suspend: \@@_declare:n {#1} \hook_if_exist:nTF {#1} { \@@_gput_next_do:nn {#1} {#2} } { \@@_try_declaring_generic_next_hook:nn {#1} {#2} } - \debug_resume: } \cs_new_protected:Npn \@@_gput_next_do:nn #1 { @@ -3556,8 +3752,8 @@ \tl_if_empty:cT { @@~#2 } { \@@_update_hook_code:n {#2} } \tl_if_empty:NT #1 - { \tl_gset:Nn #1 { \@@_clear_next:n {#2} } } - \tl_gput_right:Nn #1 + { \@@_tl_gset:Nn #1 { \@@_clear_next:n {#2} } } + \@@_tl_gput_right:Nn #1 } \cs_new_protected:Npn \@@_clear_next:n #1 { \cs_gset_eq:cN { @@_next~#1 } \c_empty_tl } @@ -3565,7 +3761,6 @@ % \end{macro} % \end{macro} % -% % \subsection{Using the hook} % % \begin{macro}{\hook_use:n} @@ -3720,8 +3915,9 @@ % % \begin{macro}[pTF]{\hook_if_empty:n} % Test if a hook is empty (that is, no code was added to that hook). -% A hook being empty means that \emph{both} its -% \cs[no-index]{g_@@_\meta{hook}_code_prop} and its +% A \meta{hook} being empty means that all three of its +% \cs[no-index]{g_@@_\meta{hook}_code_prop}, its +% \cs[no-index]{@@_toplevel~\meta{hook}} and its % \cs[no-index]{@@_next~\meta{hook}} are empty. % \begin{macrocode} \prg_new_conditional:Npnn \hook_if_empty:n #1 { p , T , F , TF } @@ -3730,7 +3926,11 @@ { \bool_lazy_and:nnTF { \prop_if_empty_p:c { g_@@_#1_code_prop } } - { \tl_if_empty_p:c { @@_next~#1 } } + { + \bool_lazy_and_p:nn + { \tl_if_empty_p:c { @@_toplevel~#1 } } + { \tl_if_empty_p:c { @@_next~#1 } } + } { \prg_return_true: } { \prg_return_false: } } @@ -3812,9 +4012,20 @@ % % \begin{macrocode} \msg_new:nnn { hooks } { empty-label } - { Empty~code~label~\msg_line_context:.~Using~`#1'~instead. } + { + Empty~code~label~\msg_line_context:.~ + Using~`\@@_currname_or_default:'~instead. + } % \end{macrocode} -% +% +% \begin{macrocode} +\msg_new:nnn { hooks } { no-default-label } + { + Missing~(empty)~default~label~\msg_line_context:. \\ + This~command~was~ignored. + } +% \end{macrocode} +% % \begin{macrocode} \msg_new:nnnn { hooks } { unknown-rule } { Unknown~ relationship~ `#3'~ @@ -3834,6 +4045,51 @@ % \end{macrocode} % % \begin{macrocode} +\msg_new:nnnn { hooks } { misused-top-level } + { + Illegal~\iow_char:N \\AddToHook{#1}[top-level]{...}.\\ + 'top-level'~is~reserved~for~the~user's~document. + } + { + The~'top-level'~label~is~meant~for~user~code~only,~and~should~only~ + be~used~(sparingly)~in~the~main~document.~Use~the~default~label~ + '\@@_currname_or_default:'~for~this~\@cls@pkg,~or~another~ + suitable~label. + } +% \end{macrocode} +% +% \begin{macrocode} +\msg_new:nnn { hooks } { set-top-level } + { + You~cannot~change~the~default~label~#1~`top-level'.~Illegal \\ + \use:nn { ~ } { ~ } \iow_char:N \\#2{#3} \\ + \msg_line_context:. + } +% \end{macrocode} +% +% \begin{macrocode} +\msg_new:nnn { hooks } { ddhl-deprecated } + { + \iow_char:N \\DeclareDefaultHookLabel~is~deprecated.\\ + Use~\iow_char:N \\SetDefaultHookLabel~instead.\\ \\ + The~deprecated~name~will~be~removed~in~the~next~release. + } +% \end{macrocode} +% +% \begin{macrocode} +\msg_new:nnn { hooks } { extra-pop-label } + { + Extra~\iow_char:N \\PopDefaultHookLabel. \\ + This~command~will~be~ignored. + } +\msg_new:nnn { hooks } { missing-pop-label } + { + Missing~\iow_char:N \\PopDefaultHookLabel. \\ + The~label~`#1'~was~pushed~but~never~popped.~Something~is~wrong. + } +% \end{macrocode} +% +% \begin{macrocode} \msg_new:nnn { hooks } { should-not-happen } { ERROR!~This~should~not~happen.~#1 \\ @@ -3879,39 +4135,77 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\SetDefaultHookLabel} +% \begin{macro}{\PushDefaultHookLabel} +% \begin{macro}{\PopDefaultHookLabel} % \begin{macro}{\DeclareDefaultHookLabel} -% \begin{macro}{\@@_curr_name_push:n,\@@_curr_name_pop:} +% \begin{macro}{\@@_curr_name_push:n,\@@_curr_name_push_aux:n} +% \begin{macro}{\@@_curr_name_pop:} +% \begin{macro}{\@@_end_document_label_check:} % The token list \cs{g_@@_hook_curr_name_tl} stores the name of the % current package/file to be used as label for hooks. % Providing a consistent interface is tricky, because packages can % be loaded within packages, and some packages may not use -% \cs{DeclareDefaultHookLabel} to change the default label (in which case -% \cs{@currname} is used, if set). +% \cs{SetDefaultHookLabel} to change the default label (in which +% case \cs{@currname} is used). % -% To pull that off, we keep a stack that contains the default label -% for each level of input. The bottom of the stack contains the -% default label for the top-level. Since the string \verb|top-level| -% is hardcoded, here this item of the stack is empty. Also, since -% we're in an input level, add \verb|lthooks| to the stack as well. -% This stack should never go empty. An empty entry is added to the -% stack to account for the \verb|top-level|. The item is empty so -% that the hard-coded default is used, but a call to -% \cs{DeclareDefaultHookLabel} will change it if needed. +% To pull that one off, we keep a stack that contains the default +% label for each level of input. The bottom of the stack contains the +% default label for the |top-level| (this stack should never go +% empty). If we're building the format, set the default label to be +% |top-level|: % \begin{macrocode} -\seq_gpush:Nn \g_@@_name_stack_seq { } +\tl_gset:Nn \g_@@_hook_curr_name_tl { top-level } % \end{macrocode} % +% Then, in case we're in \pkg{latexrelease} we push something on +% the stack to support roll forward. But in some rare cases, +% \pkg{latexrelease} may be loaded inside another package (notably +% \pkg{platexrelease}), so we'll first push the |top-level| entry: +% \begin{macrocode} +%<latexrelease>\seq_gput_right:Nn \g_@@_name_stack_seq { top-level } +% \end{macrocode} +% then we dissect the \cs{@currnamestack}, adding \cs{@currname} to +% the stack: +% \changes{v1.0f}{2020/11/24}{Support for roll forward (gh/434)} +% \begin{macrocode} +%<latexrelease>\cs_set_protected:Npn \@@_tmp:w #1 #2 #3 +%<latexrelease> { +%<latexrelease> \quark_if_recursion_tail_stop:n {#1} +%<latexrelease> \seq_gput_right:Nn \g_@@_name_stack_seq {#1} +%<latexrelease> \@@_tmp:w +%<latexrelease> } +%<latexrelease>\exp_after:wN \@@_tmp:w \@currnamestack +%<latexrelease> \q_recursion_tail \q_recursion_tail +%<latexrelease> \q_recursion_tail \q_recursion_stop +% \end{macrocode} +% and finalle set the default label to be the \cs{@currname}: +% \begin{macrocode} +%<latexrelease>\tl_gset:Nx \g_@@_hook_curr_name_tl { \@currname } +% \end{macrocode} % % Two commands keep track of the stack: when a file is input, -% \cs{@@_curr_name_push:n} pushes an (empty by default) label to the -% stack: +% \cs{@@_curr_name_push:n} pushes the current default label to the +% stack, and sets the new default label in one go: % \begin{macrocode} \cs_new_protected:Npn \@@_curr_name_push:n #1 + { \exp_args:Nx \@@_curr_name_push_aux:n { \@@_make_name:n {#1} } } +\cs_new_protected:Npn \@@_curr_name_push_aux:n #1 { - \seq_gpush:Nn \g_@@_name_stack_seq {#1} - \tl_gset:Nn \g_@@_hook_curr_name_tl {#1} + \tl_if_blank:nTF {#1} + { \msg_error:nn { hooks } { no-default-label } } + { + \str_if_eq:nnTF {#1} { top-level } + { + \msg_error:nnnnn { hooks } { set-top-level } + { to } { PushDefaultHookLabel } {#1} + } + { + \seq_gpush:NV \g_@@_name_stack_seq \g_@@_hook_curr_name_tl + \tl_gset:Nn \g_@@_hook_curr_name_tl {#1} + } + } } -% % \end{macrocode} % and when an input is over, the topmost item of the stack is popped, % since the label will not be used again, and \cs{g_@@_hook_curr_name_tl} @@ -3919,12 +4213,27 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_curr_name_pop: { - \seq_gpop:NN \g_@@_name_stack_seq \l_@@_return_tl - \seq_get:NNTF \g_@@_name_stack_seq \l_@@_return_tl + \seq_gpop:NNTF \g_@@_name_stack_seq \l_@@_return_tl { \tl_gset_eq:NN \g_@@_hook_curr_name_tl \l_@@_return_tl } + { \msg_error:nn { hooks } { extra-pop-label } } + } +% \end{macrocode} +% +% At the end of the document we want to check if there was no +% \cs{@@_curr_name_push:} without a matching \cs{@@_curr_name_pop:} +% (not a critical error, but it might indicate that something else is +% not quite right): +% \begin{macrocode} +\tl_gput_right:Nn \@kernel@after@enddocument@afterlastpage + { \@@_end_document_label_check: } +\cs_new_protected:Npn \@@_end_document_label_check: + { + \seq_gpop:NNT \g_@@_name_stack_seq \l_@@_return_tl { - \msg_error:nnn { hooks } { should-not-happen } - { Tried~to~pop~from~an~empty~default~label~stack. } + \msg_error:nnx { hooks } { missing-pop-label } + { \g_@@_hook_curr_name_tl } + \tl_gset_eq:NN \g_@@_hook_curr_name_tl \l_@@_return_tl + \@@_end_document_label_check: } } % \end{macrocode} @@ -3935,14 +4244,69 @@ % Now define a wrapper that replaces the top of the stack with the % argument, and updates \cs{g_@@_hook_curr_name_tl} accordingly. % \begin{macrocode} +\NewDocumentCommand \SetDefaultHookLabel { m } + { + \seq_if_empty:NTF \g_@@_name_stack_seq + { + \msg_error:nnnnn { hooks } { set-top-level } + { for } { SetDefaultHookLabel } {#1} + } + { \exp_args:Nx \@@_set_default_label:n { \@@_make_name:n {#1} } } + } +\cs_new_protected:Npn \@@_set_default_label:n #1 + { + \str_if_eq:nnTF {#1} { top-level } + { + \msg_error:nnnnn { hooks } { set-top-level } + { to } { SetDefaultHookLabel } {#1} + } + { \tl_gset:Nn \g_@@_hook_curr_name_tl {#1} } + } \NewDocumentCommand \DeclareDefaultHookLabel { m } { - \seq_gpop:NN \g_@@_name_stack_seq \l_@@_return_tl - \@@_curr_name_push:n {#1} + \msg_error:nn { hooks } { ddhl-deprecated } + \SetDefaultHookLabel {#1} + } +% \end{macrocode} +% +% The label is only automatically updated with \cs{@onefilewithoptions} +% (\cs{usepackage} and \cs{documentclass}), but some packages, like +% Ti\emph{k}Z, define package-like interfaces, like +% \cs{usetikzlibrary} that are wrappers around \cs{input}, so they +% inherit the default label currently in force (usually |top-level|, +% but it may change if loaded in another package). To provide a +% package-like behaviour also for hooks in these files, we provide +% high-level access to the default label stack. +% \begin{macrocode} +\NewDocumentCommand \PushDefaultHookLabel { m } + { \@@_curr_name_push:n {#1} } +\NewDocumentCommand \PopDefaultHookLabel { } + { \@@_curr_name_pop: } +% \end{macrocode} +% +% The current label stack holds the labels for all files but the +% current one (more or less like \cs{@currnamestack}), and the current +% label token list, \cs{g_@@_hook_curr_name_tl}, holds the label for +% the current file. However \cs{@pushfilename} happens before +% \cs{@currname} is set, so we need to look ahead to get the +% \cs{@currname} for the label. \pkg{expl3} also requires the current +% file in \cs{@pushfilename}, so here we abuse +% \cs{@expl@push@filename@aux@@@@} to do \cs{@@_curr_name_push:n}. +% \begin{macrocode} +\cs_gset_protected:Npn \@expl@push@filename@aux@@@@ #1#2#3 + { + \@@_curr_name_push:n {#3} + \str_gset:Nx \g_file_curr_name_str {#3} + #1 #2 {#3} } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % % @@ -4029,20 +4393,14 @@ % \end{macrocode} % % \begin{macro}{\@expl@@@initialize@all@@, -% \@expl@@@hook@curr@name@push@@n, % \@expl@@@hook@curr@name@pop@@} -% +% % \begin{macrocode} \cs_new_eq:NN \@expl@@@initialize@all@@ \__hook_initialize_all: % \end{macrocode} % % \begin{macrocode} -\cs_new_eq:NN \@expl@@@hook@curr@name@push@@n - \__hook_curr_name_push:n -% \end{macrocode} -% -% \begin{macrocode} \cs_new_eq:NN \@expl@@@hook@curr@name@pop@@ \__hook_curr_name_pop: % \end{macrocode} diff --git a/macros/latex/base/ltluatex.pdf b/macros/latex/base/ltluatex.pdf Binary files differindex e20118360c..7e559ecf45 100644 --- a/macros/latex/base/ltluatex.pdf +++ b/macros/latex/base/ltluatex.pdf diff --git a/macros/latex/base/ltmath.dtx b/macros/latex/base/ltmath.dtx index 36b8bb7ec4..770367c8a3 100644 --- a/macros/latex/base/ltmath.dtx +++ b/macros/latex/base/ltmath.dtx @@ -38,7 +38,7 @@ %<*driver> % \fi \ProvidesFile{ltmath.dtx} - [2020/07/27 v1.2g LaTeX Kernel (Math Setup)] + [2020/11/09 v1.2h LaTeX Kernel (Math Setup)] % \iffalse %</driver> % @@ -593,6 +593,13 @@ %<latexrelease>\def\;{\mskip\thickmuskip} %<latexrelease>\def\!{\mskip-\thinmuskip} %<latexrelease> +% \end{macrocode} +% \changes{v1.2h}{2020/11/09}{\cs{negmedspace} and \cs{negthickspace} +% have been only in amsmath, so we need to undefine for rollback (gh/423)} +% \begin{macrocode} +%<latexrelease>\let\negmedspace\@undefined +%<latexrelease>\let\negthickspace\@undefined +%<latexrelease> %<latexrelease>\EndIncludeInRelease %<*2ekernel> % \end{macrocode} diff --git a/macros/latex/base/ltmiscen.dtx b/macros/latex/base/ltmiscen.dtx index 9acbcccd68..cf7f3c836b 100644 --- a/macros/latex/base/ltmiscen.dtx +++ b/macros/latex/base/ltmiscen.dtx @@ -32,7 +32,7 @@ %<*driver> % \fi \ProvidesFile{ltmiscen.dtx} - [2020/10/23 v1.1w LaTeX Kernel (Misc. Environments)] + [2020/12/18 v1.1x LaTeX Kernel (Misc. Environments)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltmiscen.dtx} @@ -277,17 +277,6 @@ % \end{macro} % \end{environment} % -% -% \begin{macro}{\@kernel@after@enddocument, -% \@kernel@after@enddocument@afterlastpage} -% -% The two kernel hooks above are used by the shipout code. -% \begin{macrocode} -\let\@kernel@after@enddocument\@empty -\let\@kernel@after@enddocument@afterlastpage\@empty -% \end{macrocode} -% \end{macro} -% % \begin{macro}{\@enddocument@kernel@warnings} % % \begin{macrocode} @@ -395,8 +384,6 @@ %<latexrelease> \endgroup %<latexrelease> \deadcycles\z@\@@end} %<latexrelease> -%<latexrelease>\let\@kernel@after@enddocument\@undefined -%<latexrelease>\let\@kernel@after@enddocument@afterlastpage\@undefined %<latexrelease>\let\@enddocument@kernel@warnings\@undefined %<latexrelease> %<latexrelease>\EndIncludeInRelease diff --git a/macros/latex/base/ltnews.pdf b/macros/latex/base/ltnews.pdf Binary files differindex 902ff811d9..7da22f913b 100644 --- a/macros/latex/base/ltnews.pdf +++ b/macros/latex/base/ltnews.pdf diff --git a/macros/latex/base/ltnews01.pdf b/macros/latex/base/ltnews01.pdf Binary files differindex 8752885008..54c09ea91b 100644 --- a/macros/latex/base/ltnews01.pdf +++ b/macros/latex/base/ltnews01.pdf diff --git a/macros/latex/base/ltnews02.pdf b/macros/latex/base/ltnews02.pdf Binary files differindex a4dff175fa..cfbebec582 100644 --- a/macros/latex/base/ltnews02.pdf +++ b/macros/latex/base/ltnews02.pdf diff --git a/macros/latex/base/ltnews03.pdf b/macros/latex/base/ltnews03.pdf Binary files differindex b5cfd1312b..83b8cba6a6 100644 --- a/macros/latex/base/ltnews03.pdf +++ b/macros/latex/base/ltnews03.pdf diff --git a/macros/latex/base/ltnews04.pdf b/macros/latex/base/ltnews04.pdf Binary files differindex eff5873f9a..82f78370d2 100644 --- a/macros/latex/base/ltnews04.pdf +++ b/macros/latex/base/ltnews04.pdf diff --git a/macros/latex/base/ltnews05.pdf b/macros/latex/base/ltnews05.pdf Binary files differindex f963a2945a..a3a3ba2608 100644 --- a/macros/latex/base/ltnews05.pdf +++ b/macros/latex/base/ltnews05.pdf diff --git a/macros/latex/base/ltnews06.pdf b/macros/latex/base/ltnews06.pdf Binary files differindex ce4e6027fd..f08f189840 100644 --- a/macros/latex/base/ltnews06.pdf +++ b/macros/latex/base/ltnews06.pdf diff --git a/macros/latex/base/ltnews07.pdf b/macros/latex/base/ltnews07.pdf Binary files differindex 29e99ec882..c44afe8b77 100644 --- a/macros/latex/base/ltnews07.pdf +++ b/macros/latex/base/ltnews07.pdf diff --git a/macros/latex/base/ltnews08.pdf b/macros/latex/base/ltnews08.pdf Binary files differindex 9a29dfdc01..575c90644e 100644 --- a/macros/latex/base/ltnews08.pdf +++ b/macros/latex/base/ltnews08.pdf diff --git a/macros/latex/base/ltnews09.pdf b/macros/latex/base/ltnews09.pdf Binary files differindex 3792d6944e..938671e92b 100644 --- a/macros/latex/base/ltnews09.pdf +++ b/macros/latex/base/ltnews09.pdf diff --git a/macros/latex/base/ltnews10.pdf b/macros/latex/base/ltnews10.pdf Binary files differindex 08f4794fb0..1b065aff91 100644 --- a/macros/latex/base/ltnews10.pdf +++ b/macros/latex/base/ltnews10.pdf diff --git a/macros/latex/base/ltnews11.pdf b/macros/latex/base/ltnews11.pdf Binary files differindex 47d305bb00..b5dbd3f722 100644 --- a/macros/latex/base/ltnews11.pdf +++ b/macros/latex/base/ltnews11.pdf diff --git a/macros/latex/base/ltnews12.pdf b/macros/latex/base/ltnews12.pdf Binary files differindex 353e08f72f..103e8b18e3 100644 --- a/macros/latex/base/ltnews12.pdf +++ b/macros/latex/base/ltnews12.pdf diff --git a/macros/latex/base/ltnews13.pdf b/macros/latex/base/ltnews13.pdf Binary files differindex 9f04262286..0041691329 100644 --- a/macros/latex/base/ltnews13.pdf +++ b/macros/latex/base/ltnews13.pdf diff --git a/macros/latex/base/ltnews14.pdf b/macros/latex/base/ltnews14.pdf Binary files differindex 07bf87f377..2bc925c555 100644 --- a/macros/latex/base/ltnews14.pdf +++ b/macros/latex/base/ltnews14.pdf diff --git a/macros/latex/base/ltnews15.pdf b/macros/latex/base/ltnews15.pdf Binary files differindex 48d7b278e4..820600a8df 100644 --- a/macros/latex/base/ltnews15.pdf +++ b/macros/latex/base/ltnews15.pdf diff --git a/macros/latex/base/ltnews16.pdf b/macros/latex/base/ltnews16.pdf Binary files differindex 86bce9ff9b..3c4336dd45 100644 --- a/macros/latex/base/ltnews16.pdf +++ b/macros/latex/base/ltnews16.pdf diff --git a/macros/latex/base/ltnews17.pdf b/macros/latex/base/ltnews17.pdf Binary files differindex 4c4edcce1d..cecb7a07dc 100644 --- a/macros/latex/base/ltnews17.pdf +++ b/macros/latex/base/ltnews17.pdf diff --git a/macros/latex/base/ltnews18.pdf b/macros/latex/base/ltnews18.pdf Binary files differindex dbad7935b3..494f0fa0ec 100644 --- a/macros/latex/base/ltnews18.pdf +++ b/macros/latex/base/ltnews18.pdf diff --git a/macros/latex/base/ltnews19.pdf b/macros/latex/base/ltnews19.pdf Binary files differindex 254e795808..2c4a3b518a 100644 --- a/macros/latex/base/ltnews19.pdf +++ b/macros/latex/base/ltnews19.pdf diff --git a/macros/latex/base/ltnews20.pdf b/macros/latex/base/ltnews20.pdf Binary files differindex 96ec4b6137..b1e5c67560 100644 --- a/macros/latex/base/ltnews20.pdf +++ b/macros/latex/base/ltnews20.pdf diff --git a/macros/latex/base/ltnews21.pdf b/macros/latex/base/ltnews21.pdf Binary files differindex 5829c7a022..eb0264792c 100644 --- a/macros/latex/base/ltnews21.pdf +++ b/macros/latex/base/ltnews21.pdf diff --git a/macros/latex/base/ltnews22.pdf b/macros/latex/base/ltnews22.pdf Binary files differindex 8a6b871ce8..ddfb6d3d3a 100644 --- a/macros/latex/base/ltnews22.pdf +++ b/macros/latex/base/ltnews22.pdf diff --git a/macros/latex/base/ltnews23.pdf b/macros/latex/base/ltnews23.pdf Binary files differindex 518555e784..a32e1efbb4 100644 --- a/macros/latex/base/ltnews23.pdf +++ b/macros/latex/base/ltnews23.pdf diff --git a/macros/latex/base/ltnews24.pdf b/macros/latex/base/ltnews24.pdf Binary files differindex 11210010a2..6dc47bb3de 100644 --- a/macros/latex/base/ltnews24.pdf +++ b/macros/latex/base/ltnews24.pdf diff --git a/macros/latex/base/ltnews25.pdf b/macros/latex/base/ltnews25.pdf Binary files differindex 4965241eec..82908a28f2 100644 --- a/macros/latex/base/ltnews25.pdf +++ b/macros/latex/base/ltnews25.pdf diff --git a/macros/latex/base/ltnews26.pdf b/macros/latex/base/ltnews26.pdf Binary files differindex 9af3fd445a..604db55709 100644 --- a/macros/latex/base/ltnews26.pdf +++ b/macros/latex/base/ltnews26.pdf diff --git a/macros/latex/base/ltnews27.pdf b/macros/latex/base/ltnews27.pdf Binary files differindex 1359bc7efc..472ea7679f 100644 --- a/macros/latex/base/ltnews27.pdf +++ b/macros/latex/base/ltnews27.pdf diff --git a/macros/latex/base/ltnews28.pdf b/macros/latex/base/ltnews28.pdf Binary files differindex f5cb87308b..14ef2d02dd 100644 --- a/macros/latex/base/ltnews28.pdf +++ b/macros/latex/base/ltnews28.pdf diff --git a/macros/latex/base/ltnews29.pdf b/macros/latex/base/ltnews29.pdf Binary files differindex 5d618bc87e..e8197be1b3 100644 --- a/macros/latex/base/ltnews29.pdf +++ b/macros/latex/base/ltnews29.pdf diff --git a/macros/latex/base/ltnews30.pdf b/macros/latex/base/ltnews30.pdf Binary files differindex 35846d4fc9..920d022e99 100644 --- a/macros/latex/base/ltnews30.pdf +++ b/macros/latex/base/ltnews30.pdf diff --git a/macros/latex/base/ltnews31.pdf b/macros/latex/base/ltnews31.pdf Binary files differindex f0778f9d30..6a62e97123 100644 --- a/macros/latex/base/ltnews31.pdf +++ b/macros/latex/base/ltnews31.pdf diff --git a/macros/latex/base/ltnews32.pdf b/macros/latex/base/ltnews32.pdf Binary files differindex aed46fe573..93536d352a 100644 --- a/macros/latex/base/ltnews32.pdf +++ b/macros/latex/base/ltnews32.pdf diff --git a/macros/latex/base/ltshipout-code.pdf b/macros/latex/base/ltshipout-code.pdf Binary files differindex c5cfd30a88..f95e0ebf75 100644 --- a/macros/latex/base/ltshipout-code.pdf +++ b/macros/latex/base/ltshipout-code.pdf diff --git a/macros/latex/base/ltshipout-doc.pdf b/macros/latex/base/ltshipout-doc.pdf Binary files differindex 6a4b41f60e..074774312a 100644 --- a/macros/latex/base/ltshipout-doc.pdf +++ b/macros/latex/base/ltshipout-doc.pdf diff --git a/macros/latex/base/ltshipout.dtx b/macros/latex/base/ltshipout.dtx index 8f0422c887..e226f753f3 100644 --- a/macros/latex/base/ltshipout.dtx +++ b/macros/latex/base/ltshipout.dtx @@ -31,8 +31,8 @@ %%% From File: ltshipout.dtx % % \begin{macrocode} -\providecommand\ltshipoutversion{v1.0c} -\providecommand\ltshipoutdate{2020/09/27} +\providecommand\ltshipoutversion{v1.0d} +\providecommand\ltshipoutdate{2020/11/24} % \end{macrocode} % %<*driver> @@ -1376,9 +1376,11 @@ % % % \begin{macro}{\AtBeginDvi} -% +% If we roll forward from an earlier kernel \cs{AtBeginDvi} is +% defined so we better not use \cs{cs_new_protected:Npn} here. +% \changes{v1.0d}{2020/11/24}{Support for roll forward (gh/434)} % \begin{macrocode} -\cs_new_protected:Npn \AtBeginDvi {\@@_add_firstpage_material:Nn \AtBeginDvi} +\cs_set_protected:Npn \AtBeginDvi {\@@_add_firstpage_material:Nn \AtBeginDvi} % \end{macrocode} % \end{macro} % @@ -1448,7 +1450,17 @@ % \begin{macrocode} %<latexrelease>\IncludeInRelease{0000/00/00}% %<latexrelease> {\shipout}{The hook management (shipout)}% -%<latexrelease>\expandafter\let\expandafter\shipout\csname tex_shipout:D\endcsname +%<latexrelease> +% \end{macrocode} +% If we roll forward then \cs{tex\_shipout:D} may not be defined in +% which case \cs{shipout} does have it original definition and so +% we must not \cs{let} it to something else which is \cs{relax}! +% \changes{v1.0d}{2020/11/24}{Support for roll forward (gh/434)} +% \begin{macrocode} +%<latexrelease>\ifcsname tex_shipout:D\endcsname +%<latexrelease>\expandafter\let\expandafter\shipout +%<latexrelease> \csname tex_shipout:D\endcsname +%<latexrelease>\fi %<latexrelease> %<latexrelease>\let \ShipoutBox\@undefined %<latexrelease>\let \ReadonlyShipoutCounter \@undefined diff --git a/macros/latex/base/ltvers.dtx b/macros/latex/base/ltvers.dtx index dd69d5a6e3..c2ec2ffde3 100644 --- a/macros/latex/base/ltvers.dtx +++ b/macros/latex/base/ltvers.dtx @@ -115,7 +115,7 @@ {2020-10-01} %</2ekernel|latexrelease> %<*2ekernel> -\def\patch@level{2} +\def\patch@level{3} % \end{macrocode} % % \begin{macro}{\development@branch@name} diff --git a/macros/latex/base/ltx3info.pdf b/macros/latex/base/ltx3info.pdf Binary files differindex 620a9b2c6f..070c822a17 100644 --- a/macros/latex/base/ltx3info.pdf +++ b/macros/latex/base/ltx3info.pdf diff --git a/macros/latex/base/ltxdoc.pdf b/macros/latex/base/ltxdoc.pdf Binary files differindex 5080c0e0bc..e5d6fb99cf 100644 --- a/macros/latex/base/ltxdoc.pdf +++ b/macros/latex/base/ltxdoc.pdf diff --git a/macros/latex/base/makeindx.pdf b/macros/latex/base/makeindx.pdf Binary files differindex 97b26b4e72..7993372c01 100644 --- a/macros/latex/base/makeindx.pdf +++ b/macros/latex/base/makeindx.pdf diff --git a/macros/latex/base/manual.pdf b/macros/latex/base/manual.pdf Binary files differindex 0958c15eb6..50811f5d4c 100644 --- a/macros/latex/base/manual.pdf +++ b/macros/latex/base/manual.pdf diff --git a/macros/latex/base/modguide.pdf b/macros/latex/base/modguide.pdf Binary files differindex 7dafc9125a..5f51237557 100644 --- a/macros/latex/base/modguide.pdf +++ b/macros/latex/base/modguide.pdf diff --git a/macros/latex/base/nfssfont.pdf b/macros/latex/base/nfssfont.pdf Binary files differindex 8292894e71..8f189189d9 100644 --- a/macros/latex/base/nfssfont.pdf +++ b/macros/latex/base/nfssfont.pdf diff --git a/macros/latex/base/proc.pdf b/macros/latex/base/proc.pdf Binary files differindex a046c4fbfa..35ba9262e0 100644 --- a/macros/latex/base/proc.pdf +++ b/macros/latex/base/proc.pdf diff --git a/macros/latex/base/slides.pdf b/macros/latex/base/slides.pdf Binary files differindex 37779f807a..b4d275289c 100644 --- a/macros/latex/base/slides.pdf +++ b/macros/latex/base/slides.pdf diff --git a/macros/latex/base/slifonts.pdf b/macros/latex/base/slifonts.pdf Binary files differindex 67f44b6017..39952e8a88 100644 --- a/macros/latex/base/slifonts.pdf +++ b/macros/latex/base/slifonts.pdf diff --git a/macros/latex/base/source2e.pdf b/macros/latex/base/source2e.pdf Binary files differindex bc06f27f18..106d83f723 100644 --- a/macros/latex/base/source2e.pdf +++ b/macros/latex/base/source2e.pdf diff --git a/macros/latex/base/source2edoc.cls b/macros/latex/base/source2edoc.cls index 5b6700039c..e06108230d 100644 --- a/macros/latex/base/source2edoc.cls +++ b/macros/latex/base/source2edoc.cls @@ -2,7 +2,7 @@ % This class is buggy and needs fixing \ProvidesClass{source2edoc} - [2020/08/16 v0.1 Quick hack to typeset source2.tex + [2020/12/02 v0.2 Quick hack to typeset source2.tex (not usable for anything else and buggy -- will vanish again)!] \LoadClass{l3doc} @@ -14,8 +14,43 @@ -% l3doc's def are buggy (already fixed there but not distributed yet) + \ExplSyntaxOn + +% in 2e we have a lot of functions that have no ``user-level'' documentation so we disable +% a bogus backref in that case. Over time the sources should be clean up to have such documentation. + +\cs_set_protected:Npn \__codedoc_print_documented: + { + \seq_gset_filter:NNn \g__codedoc_nested_names_seq + \g__codedoc_nested_names_seq + { ! \__codedoc_if_macro_internal_p:n {##1} } + \seq_if_empty:NF \g__codedoc_nested_names_seq + { +% This is a crude change: we grab the first name + \__codedoc_get_hyper_target:xN + { \seq_item:Nn \g__codedoc_nested_names_seq { 1 } } + \l__codedoc_tmpa_tl +% ... and check if it has a reference + \cs_if_exist:cT{ r@\l__codedoc_tmpa_tl } +% If it does we show it, if not we don't. + { + \int_set:Nn \l__codedoc_tmpa_int + { \seq_count:N \g__codedoc_nested_names_seq } + \int_compare:nNnTF \l__codedoc_tmpa_int = 1 {~This~} {~These~} + \bool_if:NTF \l__codedoc_macro_var_bool {variable} {function} + \int_compare:nNnTF \l__codedoc_tmpa_int = 1 {~is~} {s~are~} + documented~on~page~ + \exp_args:Nx \pageref { \l__codedoc_tmpa_tl } . + } + } + \seq_gclear:N \g__codedoc_nested_names_seq + } + + + +% some l3doc's def are buggy (already fixed there but not distributed yet) + \RenewDocumentCommand \DocInclude { m } { \relax\clearpage diff --git a/macros/latex/base/syntonly.pdf b/macros/latex/base/syntonly.pdf Binary files differindex c13cc82d80..1493490c91 100644 --- a/macros/latex/base/syntonly.pdf +++ b/macros/latex/base/syntonly.pdf diff --git a/macros/latex/base/tlc2.pdf b/macros/latex/base/tlc2.pdf Binary files differindex 03eec97dc7..0c08e372a3 100644 --- a/macros/latex/base/tlc2.pdf +++ b/macros/latex/base/tlc2.pdf diff --git a/macros/latex/base/tulm.pdf b/macros/latex/base/tulm.pdf Binary files differindex e67d8d3522..d480c33dff 100644 --- a/macros/latex/base/tulm.pdf +++ b/macros/latex/base/tulm.pdf diff --git a/macros/latex/base/usrguide.pdf b/macros/latex/base/usrguide.pdf Binary files differindex 96de459ec3..51412a147a 100644 --- a/macros/latex/base/usrguide.pdf +++ b/macros/latex/base/usrguide.pdf diff --git a/macros/latex/base/utf8ienc.pdf b/macros/latex/base/utf8ienc.pdf Binary files differindex e97c6a4527..00da2138cd 100644 --- a/macros/latex/base/utf8ienc.pdf +++ b/macros/latex/base/utf8ienc.pdf diff --git a/macros/latex/base/webcomp.pdf b/macros/latex/base/webcomp.pdf Binary files differindex a6b1e79980..1c36db0c61 100644 --- a/macros/latex/base/webcomp.pdf +++ b/macros/latex/base/webcomp.pdf diff --git a/macros/latex/contrib/biblatex/CHANGES.md b/macros/latex/contrib/biblatex/CHANGES.md index 5de6bc5994..7a035b5a3e 100644 --- a/macros/latex/contrib/biblatex/CHANGES.md +++ b/macros/latex/contrib/biblatex/CHANGES.md @@ -1,3 +1,23 @@ +# RELEASE NOTES FOR VERSION 3.16 +- Fixed an infinite loop caused by excessive aliasing of the `volcitepages` + format. + Reverted the alias `\DeclareFieldAlias{volcitepages}{postnote}` + and again define + ``` + \DeclareFieldFormat{volcitepages}{\mkpageprefix[pagination][\mknormrange]{#1}} + ``` + explicitly. +- Fixed `.lbx` file loading behaviour. All `.lbx` files are now loaded + `\AtBeginDocument`. Languages that were not requested explicitly by packages + are recorded in the `.aux` file and loaded on the next run. + This may require a further LaTeX run in some situations, but now we can be + sure when `.lbx` files are read. +- Added `label` option to `\printbibliography`. +- Added more name wrapper aliases to make name aliasing smoother. +- Deprecate `\mainlang` switch in favour of the text macro `\textmainlang`. +- Deprecate `\mkrelatedstring` (which is defined as `\mainlang`) + in favour of `\mkrelatestringtext` (defined as `\textmainlang`). + # RELEASE NOTES FOR VERSION 3.15a - Fixed bug with long argument for `\DeclareFieldFormat` and friends. @@ -35,6 +55,10 @@ \DeclareFieldFormat{multiprenote}{#1\isdot} \DeclareFieldFormat{multipostnote}{\mkpageprefix[pagination][\mknormrange]{#1}} ``` + + **NB** The definition of `volcitepages` caused an infinite loop and was + reverted in v3.15b. + This means that only `multiprenote` and `multipostnote` are aliased. - Unified DOI, eprint and URL printing across all entry types. The fields `doi`, `eprint`, `eprintclass`, `eprinttype` and `url` are now valid for all entry types. @@ -453,7 +477,7 @@ Since `\mknormrange` acts only on page ranges as detected by `\ifpages`, this does not affect text other than page ranges. Hyphens and dashes in page ranges will be transformed to - `\bibrangedash`, commas and semi-colons to `\bibrangesep`. + `\bibrangedash`, commas and semicolons to `\bibrangesep`. This is analogous to Biber's treatment of page-like fields. If you always separated page ranges with `--` or `\bibrangedash` anyway, this should not change the output you get. diff --git a/macros/latex/contrib/biblatex/bibtex/bst/biblatex.bst b/macros/latex/contrib/biblatex/bibtex/bst/biblatex.bst index dc1837f941..8e5103a458 100644 --- a/macros/latex/contrib/biblatex/bibtex/bst/biblatex.bst +++ b/macros/latex/contrib/biblatex/bibtex/bst/biblatex.bst @@ -184,7 +184,7 @@ STRINGS { ctrl.alphaothers ctrl.sortalphaothers ctrl.sortstr last.name last.hash last.year last.extra } FUNCTION {initialize} { - "$Revision: 3.15 $" + "$Revision: 3.16 $" #12 entry.max$ substring$ #-3 entry.max$ substring$ "Biblatex version: " swap$ * top$ diff --git a/macros/latex/contrib/biblatex/doc/biblatex.pdf b/macros/latex/contrib/biblatex/doc/biblatex.pdf Binary files differindex c50f7bb304..3944dda3ff 100644 --- a/macros/latex/contrib/biblatex/doc/biblatex.pdf +++ b/macros/latex/contrib/biblatex/doc/biblatex.pdf diff --git a/macros/latex/contrib/biblatex/doc/biblatex.tex b/macros/latex/contrib/biblatex/doc/biblatex.tex index 87e406158a..618c5ac60f 100644 --- a/macros/latex/contrib/biblatex/doc/biblatex.tex +++ b/macros/latex/contrib/biblatex/doc/biblatex.tex @@ -64,7 +64,7 @@ url={\biblatexhome}, author={Philip Kime, Moritz Wemheuer, Philipp Lehman}, email={}, - revision={3.15a}, + revision={3.16}, date={\today}} \hypersetup{% @@ -200,6 +200,7 @@ Boruvka and Joseph Wright who helped with the transition of ownership in 2012 and following years. The language modules of this package are made possible thanks to the following contributors:\\ +Ander Zarketa-Astigarraga (Basque); Augusto Ritter Stoffel, Mateus Araújo, Gustavo Barros (Brazilian); Kaloyan Ganev (Bulgarian); Sebastià Vila-Marta (Catalan); @@ -1252,6 +1253,7 @@ The gender of the author or the gender of the editor, if there is no author. The \multicolumn{1}{@{}H}{Region/Dialect} & \multicolumn{1}{@{}H}{Identifiers} \\ \cmidrule(r){1-1}\cmidrule(r){2-2}\cmidrule{3-3} +Basque & France, Spain & \opt{basque} \\ Bulgarian & Bulgaria & \opt{bulgarian} \\ Catalan & Spain, France, Andorra, Italy & \opt{catalan} \\ Croatian & Croatia, Bosnia and Herzegovina, Serbia & \opt{croatian} \\ @@ -2076,7 +2078,7 @@ Loads a citation module which provides \sty{mcite}\slash\sty{mciteplus}-like cit \optitem[auto]{casechanger}{\opt{auto}, \opt{latex2e}, \opt{expl3}} -This option selects the implementation of \biblatex's case changing functions, most prominently \cmd{MakeSentenceCase*}. \opt{expl3} selects the new implementation based on the \latex3 module \sty{l3text}. \opt{latex2e} selects the original implementation, which has tricky brace protection behaviour and some shortcomings when dealing with non-ASCII characters. The default \opt{auto} selects the case changing code based on the available \sty{expl3} version (\opt{expl3} is selected if \sty{expl3} is at least version 2020-04-06). +This option selects the implementation of \biblatex's case changing functions, most prominently \cmd{MakeSentenceCase*}. \opt{expl3} selects the new implementation based on the \latex3 module \sty{l3text}. Note that the \sty{l3text} module assumes \utf input and that your \sty{expl3} version should be new enough (at least version 2020-04-06). \opt{latex2e} selects the original implementation, which has tricky brace protection behaviour and some shortcomings when dealing with non-ASCII characters. The default \opt{auto} selects the case changing code based on the available \sty{expl3} version and detected document encoding (\opt{expl3} is selected if \sty{expl3} is at least version 2020-04-06 and the document encoding is detected as \utf). \end{optionlist} @@ -3098,7 +3100,7 @@ Whether the default data model name part <prefix> (von, van, of, da, de, della, \end{itemize} % For example, if this option is enabled, \biblatex precedes the family name with the prefix---Ludwig van Beethoven would be cited as «van Beethoven» and alphabetized as «Van Beethoven, Ludwig». If this option is disabled (the default), he is cited as «Beethoven» and alphabetized as «Beethoven, Ludwig van» instead. -This option is also settable on a per-type scope. With \biblatexml datasources and the \bibtex extended name format supported by \biber, this is also settable on per-namelist and per-name scopes. +This option is also settable on a per-type scope. With \biblatexml datasources and the \bibtex extended name format supported by \biber (see \secref{use:enf}), this is also settable on per-namelist and per-name scopes. \optitem{indexing}{\opt{true}, \opt{false}, \opt{cite}, \opt{bib}} @@ -3309,6 +3311,64 @@ This style prints all bibliographic data in tabular format. It is intended for d \end{marglist} +\subsection{Extended Name Format} +\label{use:enf} +The parsing rules for \bibtex names are rather archaic and not suited to +many international name formats. \biber supports an extended name format +which allows explicit specification of the parts of names. This allows the +use of custom name parts apart from the four standard \bibtex parts. Extended +name formats are supported in all name fields and can be used along with +the usual \bibtex name format. Recognition of extended name format can be +disabled with the \biber option \opt{--noxname} in case you do not need the +extended format and the auto-detection causes problems with normal name +parsing. The separator \verb+=+ which comes between the namepart names and +values is customisable with the \biber option \opt{--xnamesep}. Here is an +example: + +\begin{lstlisting}[style=bibtex]{} +AUTHOR = {Hans Harman and Simon de Beumont} +AUTHOR = {given=Hans, family=Harman and given=Simon, prefix=de, family=Beumont} +\end{lstlisting} +% +These two name specifications are equivalent but the extended format +explicitly names the parts. The supported parts are those specified by the +\biblatex data mode constant \opt{nameparts}, see \secref{aut:bbx:drv}. As +with traditional \bibtex name parsing, initials are automatically generated +but it is also possible to specify these explicitly: + +\begin{lstlisting}[style=bibtex]{} +AUTHOR = {given=Jean, prefix=de la, prefix-i=d, family=Rousse} +AUTHOR = {given={Jean Pierre Simon}, given-i=JPS} +\end{lstlisting} +% +Initials are specified by adding the suffix \verb+-i+ to the namepart name. +Compound parts may be protected with braces: + +\begin{lstlisting}[style=bibtex]{} +AUTHOR = {given={Jean Pierre}} +\end{lstlisting} +% +If a namepart contains a comma, the whole namepart should be protected with +quotes: + +\begin{lstlisting}[style=bibtex]{} +AUTHOR = {"family={Robert and Sons, Inc.}"} +\end{lstlisting} +% +Traditional \bibtex name formats and the extended form may be used together: + +\begin{lstlisting}[style=bibtex]{} +AUTHOR = {Hans Harman and given=Simon, prefix=de, family=Beumont} +\end{lstlisting} +% +Per-namelist and per-name options may be specified in the extended name +format, see \secref{use:opt:bib:hyb}: + +\begin{lstlisting}[style=bibtex]{} +AUTHOR = {nosortothers=true and Hans Harman and + given=Simon, family=Beumont, prefix=de, useprefix=true} +\end{lstlisting} + \subsection{Related Entries} \label{use:rel} @@ -3444,7 +3504,7 @@ The format of annotation fields in \bibtex data sources is is as follows: <annotation> ::= ["] (string) ["] \end{lstlisting} % -That is, one or more specifications separated by semi-colons. Each specification is an equals sign followed by a comma"=separated list of annotation keywords or a string enclosed in double-quotes (a <literal> annotation, see below). To annotate a specific item in a list, put the number of the list item before the equals sign (lists start at 1). If you need to annotate a specific part of the list item, give its name after the list item number, preceded by a colon. Name part names are defined in the data model, see \secref{aut:bbx:drv}. Some further examples: +That is, one or more specifications separated by semicolons. Each specification is an equals sign followed by a comma"=separated list of annotation keywords or a string enclosed in double-quotes (a <literal> annotation, see below). To annotate a specific item in a list, put the number of the list item before the equals sign (lists start at 1). If you need to annotate a specific part of the list item, give its name after the list item number, preceded by a colon. Name part names are defined in the data model, see \secref{aut:bbx:drv}. Some further examples: \begin{lstlisting}[style=bibtex]{} AUTHOR = {Last1, First1 and Last2, First2 and Last3, First3}, @@ -3616,7 +3676,7 @@ Adds a \prm{resource}, such as a \file{.bib} file, to the default resource list. \addbibresource[glob]{bibfiles/bibfile*.bib} \addbibresource[glob]{bibfile-num?.bib} \addbibresource[glob]{bibfile{1,2,3}.bib} -\addbibresource[location=remote]{http://www.citeulike.org/bibtex/group/9517} +\addbibresource[location=remote]{https://raw.githubusercontent.com/plk/biblatex/master/bibtex/bib/biblatex/biblatex-examples.bib} \addbibresource[location=remote,label=lan]{ftp://192.168.1.57/~user/file.bib} \end{ltxexample} % @@ -3696,6 +3756,10 @@ The bibliography and the list of shorthands typically have a chapter or section This option overrides the default title provided by the heading selected with the \opt{heading} option, if supported by the heading definition. See \secref{use:bib:hdg} for details. +\valitem{label}{label} + +If \prm{label} is nonempty, issue \texttt{\textbackslash label\{\prm{label}\}} after typesetting the heading. No sanity checking is done whether or not it is useful to set a label after the heading (\eg if the heading is not numbered a \texttt{\textbackslash ref} to the label might not result in useful output). + \optitem[\normalfont\emph{global setting} (\opt{none})]{block}{\opt{none}, \opt{space}, \opt{par}, \opt{nbpar}, \opt{ragged}} This option overrides the global \opt{block} option (see \secref{use:opt:pre:gen}, the meaning of the settings is explained there as well). @@ -3786,7 +3850,7 @@ This command loops over all bibliography categories. This is equivalent to givin \cmditem{printbibheading}[key=value, \dots] -This command prints a bibliography heading defined with \cmd{defbibheading}. It takes one optional argument, which is a list of options given in \keyval notation. The options are a small subset of those supported by \cmd{printbibliography}. Valid options are \opt{heading} and \opt{title}. By default, this command uses the heading \texttt{bibliography}. See \secref{use:bib:hdg} for details. Also see \secref{use:use:mlt,use:use:div} for usage examples. +This command prints a bibliography heading defined with \cmd{defbibheading}. It takes one optional argument, which is a list of options given in \keyval notation. The options are a small subset of those supported by \cmd{printbibliography}. Valid options are \opt{heading}, \opt{title} and \opt{label}. By default, this command uses the heading \texttt{bibliography}. See \secref{use:bib:hdg} for details. Also see \secref{use:use:mlt,use:use:div} for usage examples. \cmditem{DeclarePrintbibliographyDefaults}{key=value, \dots} @@ -4330,7 +4394,7 @@ At the beginning of the document, there is always a global context containing gl \cmditem{assignrefcontextentries*}[key=value, \dots]{*} \end{ltxsyntax} -These commands automate putting citations into refcontexts when the default behaviour is not sufficient. The \prm{key=value} options are as for \cmd{DeclareRefcontext}. The default behaviour is that the data for a citation is drawn from the refcontext of the most recently processed bibliography in which it was printed\footnote{This does not always mean what one might think. In a document containing multiple bibliographies, the last bibliography will be the context for any citations \emph{before} the first bibliography because all bibliographies are processed when the \file{.bbl} is read.}. For citations that are used in some way but not printed in a bibliography or bibliography list, they default to drawing their data from the global refcontext established at the beginning of the document. To override this behaviour, instead of manually wrapping citation commands in \env{refcontext} environments, which might be error-prone and tedious, you can register a comma"=separated list of \prm{keywords}, \prm{categories} or \prm{entrykeys} which, respectively, make the entries with any of the specified keywords, entries in any of the specified categories (see \secref{use:use:div}) or entries with any of the specified citation keys draw their data from a particular refcontext specified by the \prm{refcontext key/values} which are parsed as the per the corresponding \env{refcontext} options. Such refcontext auto-assignments are specific to the current refsection. You may specify the same citation key in any of these commands but be aware that assignment is done in the order \prm{keywords}, \prm{categories}, \prm{entrykeys} with the later specifications overriding the earlier. \cmd{assignrefcontextentries} accepts a single asterisk instead of a list of entrykeys which allows the assignment of all keys in a refsection to a refcontext with having to explicitly list them. An example: +These commands automate putting citations into refcontexts when the default behaviour is not sufficient. The \prm{key=value} options are as for \cmd{DeclareRefcontext} with the addition of the \kvopt{name}{refcontextname} option which sets all options from those defined for the named refcontext \prm{refcontextname}. Use \kvopt{name}{default} to use the global default refcontext options. The specific \keyval options override those set by any named \prm{refcontextname}. The default behaviour is that the data for a citation is drawn from the refcontext of the most recently processed bibliography in which it was printed\footnote{This does not always mean what one might think. In a document containing multiple bibliographies, the last bibliography will be the context for any citations \emph{before} the first bibliography because all bibliographies are processed when the \file{.bbl} is read.}. For citations that are used in some way but not printed in a bibliography or bibliography list, they default to drawing their data from the global refcontext established at the beginning of the document. To override this behaviour, instead of manually wrapping citation commands in \env{refcontext} environments, which might be error-prone and tedious, you can register a comma"=separated list of \prm{keywords}, \prm{categories} or \prm{entrykeys} which, respectively, make the entries with any of the specified keywords, entries in any of the specified categories (see \secref{use:use:div}) or entries with any of the specified citation keys draw their data from a particular named refcontext and/or specified \prm{refcontext key/values}. Such refcontext auto-assignments are specific to the current refsection. You may specify the same citation key in any of these commands but be aware that assignment is done in the order \prm{keywords}, \prm{categories}, \prm{entrykeys} with the later specifications overriding the earlier. \cmd{assignrefcontextentries} accepts a single asterisk instead of a list of entrykeys which allows the assignment of all keys in a refsection to a refcontext with having to explicitly list them. An example: \begin{ltxexample}[style=latex] \assignrefcontextentries[labelprefix=A]{key2} @@ -4353,6 +4417,28 @@ The starred versions do not override a local refcontext and so with: % the data for the citation of \bibfield{key2} will be drawn from refcontext \opt{labelprefix=B}. Note that these commands are rarely necessary unless you have multiple bibliographies in which the same citations occur and \biblatex\ cannot by default tell which bibliography list a citation should refer to. See the example file \file{94-labelprefix.tex} for more details. +\begin{ltxexample}[style=latex] +\DeclareRefcontext{testrc}{labelprefix=A} +\assignrefcontextentries[name=testrc]{key2} +\cite{key1} +\begin{refcontext}[labelprefix=B] +\cite{key2} +\end{refcontext} +\end{ltxexample} +% +Here, the data for the citation of \bibfield{key2} will be drawn from the refcontext named <testrc> which has \opt{labelprefix=A} and not \opt{labelprefix=B} (resulting in a label with prefix <A> and not <B>). + +\begin{ltxexample}[style=latex] +\DeclareRefcontext{testrc}{labelprefix=A} +\assignrefcontextentries[name=testrc,labelprefix=C]{key2} +\cite{key1} +\begin{refcontext}[labelprefix=B] +\cite{key2} +\end{refcontext} +\end{ltxexample} +% +Here, the data for the citation of \bibfield{key2} will be drawn from refcontext with \opt{labelprefix=C} and not \opt{labelprefix=A} since the explicit options override the named refcontext (resulting in a label with prefix <C> and not <A> or <B>). + \subsubsection{Dynamic Entry Sets} \label{use:bib:set} @@ -4727,7 +4813,7 @@ Similar to \cmd{psq} but indicates an open-ended page range. See \secref{use:cav \cmditem{pnfmt}{text} -This command formats is argument \prm{text} in the same format as \bibfield{postnote}. The command can be used to format a page range while adding additional text in the postnote argument of a cite command. +This command formats its argument \prm{text} in the same format as \bibfield{postnote}. The command can be used to format a page range while adding additional text in the postnote argument of a cite command. \begin{ltxexample} \autocite[\pnfmt{378-381, 383} and more]{sigfridsson} @@ -6732,7 +6818,7 @@ Names depend on the datamodel constant <nameparts> which has the default definit {prefix,family,suffix,given} \end{ltxexample} % -This can be customised to add more name parts to deal with things like patronymics (see the example file \file{93-nameparts.tex}). This needs an extended name format for data sources since the standard \bibtex name format is very limited. \biblatexml (\secref{apx:biblatexml}) handles this natively and there is an extended name format which can handle custom nameparts when using \biber (see \biber documentation). +This can be customised to add more name parts to deal with things like patronymics (see the example file \file{93-nameparts.tex}). This needs an extended name format for data sources since the standard \bibtex name format is very limited. \biblatexml (\secref{apx:biblatexml}) handles this natively and there is an extended name format which can handle custom nameparts when using \biber (see \secref{use:enf}). Inside name formats, the <nameparts> constant declaration makes available two or three macros for each name part defined in the datamodel: @@ -9355,7 +9441,7 @@ or just a name list by using the option as a pseudo-name which will be ignored: \end{lstlisting} % or just a single name by passing the option as part of the extended name information -format which \biber supports (see \biber doc): +format which \biber supports (see \secref{use:enf}): \begin{lstlisting}[style=bibtex]{} @BOOK{key, @@ -10811,7 +10897,7 @@ The pagination strings are taken from \texttt{$<$pagination$>$total} and \texttt \cmditem{mkcomprange}[postpro][itempostpro]{text} \cmditem*{mkcomprange*}[postpro][itempostpro]{text} -This command, which is intended for use in field formatting directives, will parse its \prm{text} argument for page ranges and compress them. For example, «125--129» may be formatted as «125--9». You may configure the behavior of \cmd{mkcomprange} by adjusting the \latex counters \cnt{mincomprange}, \cnt{maxcomprange}, and \cnt{mincompwidth}, as illustrated in \tabref{aut:aux:tab1}. The default settings are \texttt{10}, \texttt{100000}, and \texttt{1}, respectively. This means that the command tries to compress as much as possible by default. Use \cmd{setcounter} to adjust the parameters. The scanner recognises \cmd{bibrangedash} and hyphens as range dashes. It will normalize the dash by replacing any number of consecutive hyphens with \cmd{bibrangedash}. Lists of ranges delimited with \cmd{bibrangessep} are also supported. The scanner will normalise any comma or semi-colons surrounded by optional space by replacing them with \cmd{bibrangessep}. If you want to hide a character from the list/range scanner for some reason, wrap the character or the entire string in curly braces. The optional \prm{postpro} argument specifies a macro to be used for post-processing the \prm{text}. This is important if you want to combine \cmd{mkcomprange} with other formatting macros which also need to parse their \prm{text} argument, such as \cmd{mkpageprefix}. Simply nesting these commands will not work as expected. Use the \prm{postpro} argument to set up the processing chain as follows: +This command, which is intended for use in field formatting directives, will parse its \prm{text} argument for page ranges and compress them. For example, «125--129» may be formatted as «125--9». You may configure the behavior of \cmd{mkcomprange} by adjusting the \latex counters \cnt{mincomprange}, \cnt{maxcomprange}, and \cnt{mincompwidth}, as illustrated in \tabref{aut:aux:tab1}. The default settings are \texttt{10}, \texttt{100000}, and \texttt{1}, respectively. This means that the command tries to compress as much as possible by default. Use \cmd{setcounter} to adjust the parameters. The scanner recognises \cmd{bibrangedash} and hyphens as range dashes. It will normalize the dash by replacing any number of consecutive hyphens with \cmd{bibrangedash}. Lists of ranges delimited with \cmd{bibrangessep} are also supported. The scanner will normalise any comma or semicolons surrounded by optional space by replacing them with \cmd{bibrangessep}. If you want to hide a character from the list/range scanner for some reason, wrap the character or the entire string in curly braces. The optional \prm{postpro} argument specifies a macro to be used for post-processing the \prm{text}. This is important if you want to combine \cmd{mkcomprange} with other formatting macros which also need to parse their \prm{text} argument, such as \cmd{mkpageprefix}. Simply nesting these commands will not work as expected. Use the \prm{postpro} argument to set up the processing chain as follows: \begin{ltxexample} \DeclareFieldFormat{postnote}{\mkcomprange[<<{>>\mkpageprefix[pagination]<<}>>]{#1}} @@ -10836,7 +10922,7 @@ The second optional argument \prm{itempostpro} is used to post-process each indi \cmditem{mknormrange}[postpro][itempostpro]{text} \cmditem*{mknormrange*}[postpro][itempostpro]{text} -This command, which is intended for use in field formatting directives, will parse its \prm{text} argument for page ranges and will normalise them. The command is similar to \cmd{mkcomprange} except that the page ranges will not be compressed. The scanner recognises \cmd{bibrangedash} and hyphens as range dashes. It will normalize the dash by replacing any number of consecutive hyphens with \cmd{bibrangedash}. Lists of ranges delimited with \cmd{bibrangessep} are also supported. The scanner will normalise any comma or semi-colons surrounded by optional space by replacing them with \cmd{bibrangessep}. If you want to hide a character from the list/range scanner for some reason, wrap the character or the entire string in curly braces. The optional \prm{postpro} argument specifies a macro to be used for post-processing the \prm{text}. See \cmd{mkcomprange} on how to use this argument. The starred version of this command differs from the regular one in the way the \prm{postpro} argument is applied to a list of values. The second optional argument \prm{itempostpro} is used to post-process each individual number item in the formatted list. It can be used to convert numbers from cardinals to ordinals. If only one optional argument is present, it is treated as \prm{postpro}. +This command, which is intended for use in field formatting directives, will parse its \prm{text} argument for page ranges and will normalise them. The command is similar to \cmd{mkcomprange} except that the page ranges will not be compressed. The scanner recognises \cmd{bibrangedash} and hyphens as range dashes. It will normalize the dash by replacing any number of consecutive hyphens with \cmd{bibrangedash}. Lists of ranges delimited with \cmd{bibrangessep} are also supported. The scanner will normalise any comma or semicolons surrounded by optional space by replacing them with \cmd{bibrangessep}. If you want to hide a character from the list/range scanner for some reason, wrap the character or the entire string in curly braces. The optional \prm{postpro} argument specifies a macro to be used for post-processing the \prm{text}. See \cmd{mkcomprange} on how to use this argument. The starred version of this command differs from the regular one in the way the \prm{postpro} argument is applied to a list of values. The second optional argument \prm{itempostpro} is used to post-process each individual number item in the formatted list. It can be used to convert numbers from cardinals to ordinals. If only one optional argument is present, it is treated as \prm{postpro}. \cmditem{mkfirstpage}[postpro][itempostpro]{text} \cmditem*{mkfirstpage*}[postpro][itempostpro]{text} @@ -11361,9 +11447,13 @@ Similar to \cmd{bibxstring} but always uses the long string, ignoring the \opt{a Similar to \cmd{bibxstring} but always uses the short string, ignoring the \opt{abbreviate} option. -\cmditem{mainlang} +\cmditem{mainlang}\DeprecatedMark + +Switches from the current language to the main document language. This command is deprecated. Use the text-macro \cmd{textmainlang} instead. With \sty{babel} this command will need to be wrapped into \emph{two} groups to have purely local effect. -Switches from the current language to the main document language. This can be used the \prm{wrapper} argument in the localisation string commands above. +\cmditem{textmainlang}{text} + +Locally switches from the current language to the main document language to typeset \prm{text}. This can be used the \prm{wrapper} argument in the localisation string commands above. \end{ltxsyntax} @@ -11944,6 +12034,7 @@ Other expressions frequently used in citations: \begin{keymarglist} \item[langamerican] The language <American> or <American English>. +\item[langbasque] The language <Basque>. \item[langbrazilian] The language <Brazilian> or <Brazilian Portuguese>. \item[langbulgarian] The language <Bulgarian>. \item[langcatalan] The language <Catalan>. @@ -11980,6 +12071,7 @@ The following strings are intended for use in phrases like <translated from [the \begin{keymarglist} \item[fromamerican] The expression <from [the] American> or <from [the] American English>. +\item[frombasque] The expression <from [the] Basque>. \item[frombrazilian] The expression <from [the] Brazilian> or <from [the] Brazilian Portuguese>. \item[frombulgarian] The expression <from [the] Bulgarian>. \item[fromcatalan] The expression <from [the] Catalan>. @@ -14428,6 +14520,14 @@ use$<$name$>$ &\+&\+&\_&\+&\+&\_&\_\\ This revision history is a list of changes relevant to users of this package. Changes of a more technical nature which do not affect the user interface or the behavior of the package are not included in the list. More technical details are to be found in the \file{CHANGES.md} file. The numbers on the right indicate the relevant section of this manual. \begin{changelog} +\begin{release}{3.16}{2020-12} +\item Added named refcontext support to \cmd{assignrefcontext*}\see{use:bib:context} +\item Fixed infinite loop with \bibfield{volcitepages} field format +\item Added Extended Name Format documentation\see{use:enf} +\item Added \opt{label} option to \cmd{printbibliography}\see{use:bib:bib} +\item Deprecate \cmd{mainlang} in favour of \cmd{textmainlang}\see{aut:str} +\item Added Basque localisation (Ander Zarketa-Astigarraga) +\end{release} \begin{release}{3.15a}{2020-08-23} \item Fixed bug with long arguments in \cmd{DeclareFieldFormat} and friends \end{release} diff --git a/macros/latex/contrib/biblatex/doc/examples/03-localization-keys-biber.pdf b/macros/latex/contrib/biblatex/doc/examples/03-localization-keys-biber.pdf Binary files differindex 6b221f760d..141a79e6a7 100644 --- a/macros/latex/contrib/biblatex/doc/examples/03-localization-keys-biber.pdf +++ b/macros/latex/contrib/biblatex/doc/examples/03-localization-keys-biber.pdf diff --git a/macros/latex/contrib/biblatex/doc/examples/03-localization-keys-bibtex.pdf b/macros/latex/contrib/biblatex/doc/examples/03-localization-keys-bibtex.pdf Binary files differindex 2d5254f846..b10bb33409 100644 --- a/macros/latex/contrib/biblatex/doc/examples/03-localization-keys-bibtex.pdf +++ b/macros/latex/contrib/biblatex/doc/examples/03-localization-keys-bibtex.pdf diff --git a/macros/latex/contrib/biblatex/doc/examples/03-localization-keys.tex b/macros/latex/contrib/biblatex/doc/examples/03-localization-keys.tex index 84f46d5a6c..445c000498 100644 --- a/macros/latex/contrib/biblatex/doc/examples/03-localization-keys.tex +++ b/macros/latex/contrib/biblatex/doc/examples/03-localization-keys.tex @@ -584,6 +584,7 @@ Other expressions frequently used in citations: \begin{keylist} \keyitem{langamerican} The language <American> or <American English>. +\keyitem{langbasque} The language <Basque>. \keyitem{langbrazilian} The language <Brazilian> or <Brazilian Portuguese>. \keyitem{langbulgarian} The language <Bulgarian>. \keyitem{langcatalan} The language <Catalan>. @@ -620,6 +621,7 @@ The following strings are intended for use in phrases like <translated from [the \begin{keylist} \keyitem{fromamerican} The expression <from [the] American> or <from [the] American English>. +\keyitem{frombasque} The expression <from [the] Basque>. \keyitem{frombrazilian} The expression <from [the] Brazilian> or <from [the] Brazilian Portuguese>. \keyitem{frombulgarian} The expression <from [the] Bulgarian>. \keyitem{fromcatalan} The expression <from [the] Catalan>. diff --git a/macros/latex/contrib/biblatex/doc/examples/16-numeric-prefixed-1-bibtex.pdf b/macros/latex/contrib/biblatex/doc/examples/16-numeric-prefixed-1-bibtex.pdf Binary files differindex 127d8ca0d7..64db9af5a6 100644 --- a/macros/latex/contrib/biblatex/doc/examples/16-numeric-prefixed-1-bibtex.pdf +++ b/macros/latex/contrib/biblatex/doc/examples/16-numeric-prefixed-1-bibtex.pdf diff --git a/macros/latex/contrib/biblatex/doc/examples/16-numeric-prefixed-1-bibtex.tex b/macros/latex/contrib/biblatex/doc/examples/16-numeric-prefixed-1-bibtex.tex deleted file mode 100644 index 2ba9fa7417..0000000000 --- a/macros/latex/contrib/biblatex/doc/examples/16-numeric-prefixed-1-bibtex.tex +++ /dev/null @@ -1,53 +0,0 @@ -% -% This file demonstrates how to configure biblatex to prefix -% numerical citations with a letter or a string. This will work with -% all numerical styles which ship with biblatex. Note that you must -% set defernumbers=true globally when using prefixes. -% -% Since the prefixes are assigned as the bibliography is generated, -% you may use any filter supported by biblatex to subdivide the -% references (by type, by category, by keyword, etc.). -% -\documentclass[a4paper,oneside]{article} -\usepackage[T1]{fontenc} -\usepackage[american]{babel} -\usepackage{csquotes} -% When using prefixed numerical labels, the labels must be assigned -% as the bibliography is generated. That's why we set -% defernumbers=true here: -\usepackage[style=numeric,defernumbers,backend=bibtex]{biblatex} -\usepackage{hyperref} -\usepackage{nameref} -\addbibresource{biblatex-examples.bib} -% A catch-all filter for all items which are not assigned to a -% dedicated sub-bibliography: -\defbibfilter{other}{ - not type=article - and - not type=book - and - not type=collection -} - -\begin{document} - -\section*{Prefixed numerical citations} - -% Some citations: -\cite{angenendt, kastenholz, augustine, companion, jaffe, ctan} - -\nocite{*} - -% Let's print the overall heading of the bibliography first: -\printbibheading - -% And now the sub-bibliographies: we use three of them (based on the -% entry type). Each sub-bibliography assigns a different prefix: -\printbibliography[heading=subbibliography,title={Articles},type=article, prefixnumbers={A}] -\printbibliography[heading=subbibliography,title={Books},type=book, prefixnumbers={B}] -\printbibliography[heading=subbibliography,title={Collections},type=collection, prefixnumbers={C}] - -% The catch-all sub-bibliography for all remaining types: -\printbibliography[heading=subbibliography,title={Other Sources},filter=other, prefixnumbers={O}] - -\end{document} diff --git a/macros/latex/contrib/biblatex/doc/examples/17-numeric-prefixed-2-bibtex.pdf b/macros/latex/contrib/biblatex/doc/examples/17-numeric-prefixed-2-bibtex.pdf Binary files differindex 5c29ad4479..1660f1fa12 100644 --- a/macros/latex/contrib/biblatex/doc/examples/17-numeric-prefixed-2-bibtex.pdf +++ b/macros/latex/contrib/biblatex/doc/examples/17-numeric-prefixed-2-bibtex.pdf diff --git a/macros/latex/contrib/biblatex/doc/examples/17-numeric-prefixed-2-bibtex.tex b/macros/latex/contrib/biblatex/doc/examples/17-numeric-prefixed-2-bibtex.tex deleted file mode 100644 index c0952bab42..0000000000 --- a/macros/latex/contrib/biblatex/doc/examples/17-numeric-prefixed-2-bibtex.tex +++ /dev/null @@ -1,40 +0,0 @@ -% -% This example is almost the same as the previous one except that -% the catch-all sub-bibliography does not assign any prefix. -% -\documentclass[a4paper,oneside]{article} -\usepackage[T1]{fontenc} -\usepackage[american]{babel} -\usepackage{csquotes} -\usepackage[style=numeric,defernumbers,backend=bibtex]{biblatex} -\usepackage{hyperref} -\usepackage{nameref} -\addbibresource{biblatex-examples.bib} -\defbibfilter{other}{ - not type=article - and - not type=book - and - not type=collection -} -\begin{document} - -\section*{Prefixed numerical citations} - -% Some citations: -\cite{angenendt, kastenholz, augustine, companion, jaffe, ctan} - -\nocite{*} - -\printbibheading - -\printbibliography[heading=subbibliography,title={Articles},type=article, prefixnumbers={A}] -\printbibliography[heading=subbibliography,title={Books},type=book, prefixnumbers={A}] -\printbibliography[heading=subbibliography,title={Collections},type=collection, prefixnumbers={C}] - -% The catch-all sub-bibliography for all remaining types. We don't -% use a prefix but we still need to set resetnumbers=true to restart -% the item numbering: -\printbibliography[heading=subbibliography,title={Other Sources},filter=other,resetnumbers] - -\end{document} diff --git a/macros/latex/contrib/biblatex/doc/examples/19-alphabetic-prefixed-bibtex.pdf b/macros/latex/contrib/biblatex/doc/examples/19-alphabetic-prefixed-bibtex.pdf Binary files differindex 12ee886cf2..fd02d3ee77 100644 --- a/macros/latex/contrib/biblatex/doc/examples/19-alphabetic-prefixed-bibtex.pdf +++ b/macros/latex/contrib/biblatex/doc/examples/19-alphabetic-prefixed-bibtex.pdf diff --git a/macros/latex/contrib/biblatex/doc/examples/19-alphabetic-prefixed-bibtex.tex b/macros/latex/contrib/biblatex/doc/examples/19-alphabetic-prefixed-bibtex.tex deleted file mode 100644 index 31cac5de0b..0000000000 --- a/macros/latex/contrib/biblatex/doc/examples/19-alphabetic-prefixed-bibtex.tex +++ /dev/null @@ -1,44 +0,0 @@ -% -% Prefixes also work with alphabetic the styles. -% -\documentclass[a4paper,oneside]{article} -\usepackage[T1]{fontenc} -\usepackage[american]{babel} -\usepackage{csquotes} -\usepackage[style=alphabetic,backend=bibtex]{biblatex} -\usepackage{hyperref} -\usepackage{nameref} -\addbibresource{biblatex-examples.bib} -% A catch-all filter for all items which are not assigned to a -% dedicated sub-bibliography: -\defbibfilter{other}{ - not type=article - and - not type=book - and - not type=collection -} -\begin{document} - -\section*{Prefixed alphabetic citations} - -% Some citations: -\cite{angenendt, kastenholz, augustine, companion, jaffe, ctan} - -\nocite{*} - -% Let's print the overall heading of the bibliography first: -\printbibheading - -% And now the sub-bibliographies: we use three of them (based on the -% entry type). Each sub-bibliography assigns a different prefix. The -% option is called 'prefixnumbers' because it was originally intended -% for numeric citations only. It also works with alphabetic labels: -\printbibliography[heading=subbibliography,title={Articles},type=article,prefixnumbers={A-}] -\printbibliography[heading=subbibliography,title={Books},type=book,prefixnumbers={B-}] -\printbibliography[heading=subbibliography,title={Collections},type=collection,prefixnumbers={C-}] - -% The catch-all sub-bibliography for all remaining types: -\printbibliography[heading=subbibliography,title={Other Sources},filter=other,prefixnumbers={O-}] - -\end{document} diff --git a/macros/latex/contrib/biblatex/doc/examples/82-style-debug-biber.pdf b/macros/latex/contrib/biblatex/doc/examples/82-style-debug-biber.pdf Binary files differindex eb9d127563..d737632db1 100644 --- a/macros/latex/contrib/biblatex/doc/examples/82-style-debug-biber.pdf +++ b/macros/latex/contrib/biblatex/doc/examples/82-style-debug-biber.pdf diff --git a/macros/latex/contrib/biblatex/doc/examples/93-nameparts-biber.pdf b/macros/latex/contrib/biblatex/doc/examples/93-nameparts-biber.pdf Binary files differindex 3b422be09e..e9368e5e45 100644 --- a/macros/latex/contrib/biblatex/doc/examples/93-nameparts-biber.pdf +++ b/macros/latex/contrib/biblatex/doc/examples/93-nameparts-biber.pdf diff --git a/macros/latex/contrib/biblatex/doc/examples/93-nameparts.tex b/macros/latex/contrib/biblatex/doc/examples/93-nameparts.tex index 71b6a5b219..44115b6acd 100644 --- a/macros/latex/contrib/biblatex/doc/examples/93-nameparts.tex +++ b/macros/latex/contrib/biblatex/doc/examples/93-nameparts.tex @@ -1,15 +1,10 @@ \documentclass[a4paper]{article} \usepackage{fontspec} -\setmainfont{Linux Libertine O} -\setsansfont{Linux Biolinum O} +\usepackage{libertine} \usepackage[fallback]{xeCJK} -%\setCJKmainfont{Malgun Gothic} -\setCJKmainfont{PingFang TC}% OSX - \usepackage[british]{babel} \usepackage{csquotes} -\usepackage{filecontents} -\begin{filecontents}{\jobname.bib} +\begin{filecontents}[force]{\jobname.bib} @book{tolstoy, author = {given=Лев, patronymic=Николаевич, family=Толстой, nametemplates=russian}, title = {Война и мир}, @@ -84,14 +79,6 @@ publisher = {Shangwu Yinshuguan}, date = {2016}, } -@book{zhangh, - title = {Sŏmyŏng}, - titleaddon = {書名}, - author = {family=Zhang, cjk=장학성, given=Haksŏng, nametemplates=cjk}, - location = {Shanghai}, - publisher = {Shangwu Yinshuguan}, - date = {2016}, -} @book{bronte:c, author = {Charlotte Brontë}, @@ -433,7 +420,7 @@ \textcite{bronte:c,bronte:e,austen:jane,austen:john} -\textcite{zhangx1,zhangx2,zhangh} +\textcite{zhangx1,zhangx2} \printbibliography \end{document} diff --git a/macros/latex/contrib/biblatex/doc/examples/96-dates.tex b/macros/latex/contrib/biblatex/doc/examples/96-dates.tex index e4e1863934..d1e88e2f53 100644 --- a/macros/latex/contrib/biblatex/doc/examples/96-dates.tex +++ b/macros/latex/contrib/biblatex/doc/examples/96-dates.tex @@ -6,8 +6,7 @@ \usepackage{fontspec} \usepackage[american]{babel} \usepackage{csquotes} -\usepackage{filecontents} -\begin{filecontents}{\jobname.bib} +\begin{filecontents}[force]{\jobname.bib} @misc{date1, note = {Years with implicit era}, author = {Author1}, diff --git a/macros/latex/contrib/biblatex/doc/examples/97-annotations.tex b/macros/latex/contrib/biblatex/doc/examples/97-annotations.tex index 03be50f142..a756b7ce00 100644 --- a/macros/latex/contrib/biblatex/doc/examples/97-annotations.tex +++ b/macros/latex/contrib/biblatex/doc/examples/97-annotations.tex @@ -5,8 +5,7 @@ \usepackage{fontspec} \usepackage[american]{babel} \usepackage{csquotes} -\usepackage{filecontents} -\begin{filecontents}{\jobname.bib} +\begin{filecontents}[force]{\jobname.bib} @MISC{ann1, AUTHOR = {Last1, First1 and Last2, First2 and Last3, First3}, AUTHOR+an = {1:family=student;2=corresponding}, diff --git a/macros/latex/contrib/biblatex/latex/bbx/draft.bbx b/macros/latex/contrib/biblatex/latex/bbx/draft.bbx index 1c57325157..0896a6d963 100644 --- a/macros/latex/contrib/biblatex/latex/bbx/draft.bbx +++ b/macros/latex/contrib/biblatex/latex/bbx/draft.bbx @@ -8,6 +8,10 @@ \DeclareNameAlias{editor}{default} \DeclareNameAlias{translator}{default} +\DeclareNameWrapperAlias{author}{default} +\DeclareNameWrapperAlias{editor}{default} +\DeclareNameWrapperAlias{translator}{default} + \DeclareFieldFormat{shorthandwidth}{#1} \defbibenvironment{bibliography} diff --git a/macros/latex/contrib/biblatex/latex/bbx/numeric.bbx b/macros/latex/contrib/biblatex/latex/bbx/numeric.bbx index 4bf46c3ff8..909b806fd1 100644 --- a/macros/latex/contrib/biblatex/latex/bbx/numeric.bbx +++ b/macros/latex/contrib/biblatex/latex/bbx/numeric.bbx @@ -13,6 +13,10 @@ \DeclareNameAlias{editor}{default} \DeclareNameAlias{translator}{default} +\DeclareNameWrapperAlias{author}{default} +\DeclareNameWrapperAlias{editor}{default} +\DeclareNameWrapperAlias{translator}{default} + \DeclareFieldFormat{bibentrysetcount}{\mkbibparens{\mknumalph{#1}}} \DeclareFieldFormat{labelnumberwidth}{\mkbibbrackets{#1}} \DeclareFieldFormat{shorthandwidth}{\mkbibbrackets{#1}} diff --git a/macros/latex/contrib/biblatex/latex/bbx/reading.bbx b/macros/latex/contrib/biblatex/latex/bbx/reading.bbx index 547510c37d..3eb35c3909 100644 --- a/macros/latex/contrib/biblatex/latex/bbx/reading.bbx +++ b/macros/latex/contrib/biblatex/latex/bbx/reading.bbx @@ -7,6 +7,10 @@ \DeclareNameAlias{editor}{default} \DeclareNameAlias{translator}{default} +\DeclareNameWrapperAlias{author}{default} +\DeclareNameWrapperAlias{editor}{default} +\DeclareNameWrapperAlias{translator}{default} + \DeclareFieldFormat{entrykey}{\mbox{\bfseries#1}} \DeclareFieldFormat{annotation}{\bibstring{annotation}\addcolon\space #1} \DeclareFieldFormat{abstract}{\bibstring{abstract}\addcolon\space #1} diff --git a/macros/latex/contrib/biblatex/latex/bbx/standard.bbx b/macros/latex/contrib/biblatex/latex/bbx/standard.bbx index 810c8584c9..f53eb722d5 100644 --- a/macros/latex/contrib/biblatex/latex/bbx/standard.bbx +++ b/macros/latex/contrib/biblatex/latex/bbx/standard.bbx @@ -983,14 +983,14 @@ test {\ifbibxstring{\thefield{relatedtype}s}} } {\printtext[\bbx@tempb]{% - \bibstring[\mkrelatedstring]{\thefield{relatedtype}s}}} + \bibstring[\mkrelatedstringtext]{\thefield{relatedtype}s}}} {\iffieldbibstring{relatedtype} {\printtext[\bbx@tempb]{% - \bibstring[\mkrelatedstring]{\thefield{relatedtype}}}} + \bibstring[\mkrelatedstringtext]{\thefield{relatedtype}}}} {}}} {\iffieldbibstring{relatedstring} {\printtext[\bbx@tempb]{% - \bibstring[\mkrelatedstring]{\thefield{relatedstring}}}} + \bibstring[\mkrelatedstringtext]{\thefield{relatedstring}}}} {\printfield[\bbx@tempb]{relatedstring}}}% \docsvfield{related}% \usebibmacro{endrelatedloop}}}% diff --git a/macros/latex/contrib/biblatex/latex/biblatex.def b/macros/latex/contrib/biblatex/latex/biblatex.def index 10f4144dab..c4ac8d0169 100644 --- a/macros/latex/contrib/biblatex/latex/biblatex.def +++ b/macros/latex/contrib/biblatex/latex/biblatex.def @@ -194,7 +194,7 @@ % Examples of use, uncommenting these would break backwards compatibility %\newcommand*{\begrelateddelimorigpubin}{\addspace} %\newcommand*{\begrelateddelimorigpubas}{\addspace} -\newcommand{\mkrelatedstring}{\mainlang} +\newcommand{\mkrelatedstringtext}{\textmainlang} % Used for indexing @@ -476,7 +476,7 @@ \DeclareFieldFormat{prenote}{#1\isdot} \DeclareFieldFormat{postnote}{\mkpageprefix[pagination][\mknormrange]{#1}} \DeclareFieldFormat{volcitevolume}{\bibstring{volume}\ppspace#1} -\DeclareFieldAlias{volcitepages}{postnote} +\DeclareFieldFormat{volcitepages}{\mkpageprefix[pagination][\mknormrange]{#1}} \DeclareFieldFormat{volcitenote}{\mkvolcitenote#1} \newrobustcmd*{\mkvolcitenote}[2]{% \printtext[volcitevolume]{#1}% @@ -624,6 +624,7 @@ % The default used by \citelist \DeclareListAlias{citelist}{default} +\DeclareListWrapperAlias{citelist}{default} % Used in the bibliography @@ -724,6 +725,11 @@ \DeclareListAlias{institution}{default} \DeclareListAlias{organization}{default} +\DeclareListWrapperAlias{origlocation}{location} +\DeclareListWrapperAlias{origpublisher}{publisher} +\DeclareListWrapperAlias{institution}{default} +\DeclareListWrapperAlias{organization}{default} + % Auxiliary macros for list formatting directives % ------------------------------------------------------------------ @@ -943,6 +949,7 @@ % Default used by \citename \DeclareNameAlias{citename}{default} +\DeclareNameWrapperAlias{citename}{default} % Used in some citations \DeclareNameFormat{labelname}{% @@ -998,6 +1005,28 @@ \DeclareNameAlias{withforeword}{default} \DeclareNameAlias{withafterword}{default} +\DeclareNameWrapperAlias{author}{default} +\DeclareNameWrapperAlias{bookauthor}{author} +\DeclareNameWrapperAlias{editor}{default} +\DeclareNameWrapperAlias{editora}{editor} +\DeclareNameWrapperAlias{editorb}{editor} +\DeclareNameWrapperAlias{editorc}{editor} +\DeclareNameWrapperAlias{translator}{default} + +\DeclareNameWrapperAlias{byauthor}{default} +\DeclareNameWrapperAlias{bybookauthor}{byauthor} +\DeclareNameWrapperAlias{byeditor}{default} +\DeclareNameWrapperAlias{byeditora}{byeditor} +\DeclareNameWrapperAlias{byeditorb}{byeditor} +\DeclareNameWrapperAlias{byeditorc}{byeditor} +\DeclareNameWrapperAlias{bytranslator}{default} + +\DeclareNameWrapperAlias{withcommentator}{default} +\DeclareNameWrapperAlias{withannotator}{default} +\DeclareNameWrapperAlias{withintroduction}{default} +\DeclareNameWrapperAlias{withforeword}{default} +\DeclareNameWrapperAlias{withafterword}{default} + \DeclareFieldFormat{authortype}{#1} \DeclareFieldFormat{editortype}{#1} \DeclareFieldFormat{translatortype}{#1} @@ -2963,13 +2992,10 @@ \entrydata{#1}{% \renewbibmacro*{name:hook}[1]{% \ifnumequal{\value{listcount}}{1} - {\begingroup - \mkrelatedstring% - \lbx@initnamehook{#1}% - \endgroup} + {\mkrelatedstringtext{\lbx@initnamehook{##1}}} {}}% \printnames[bytranslator]{translator}% - \setunit*{\addspace\bibstring[\mkrelatedstring]{astitle}\space}% + \setunit*{\addspace\bibstring[\mkrelatedstringtext]{astitle}\space}% \usebibmacro{title}% \setunit{\addspace}% \printtext[parens]{% @@ -3017,7 +3043,7 @@ test {\iflistundef{publisher}} } {} - {\setunit{\addspace\bibstring[\mkrelatedstring]{bypublisher}\space}% + {\setunit{\addspace\bibstring[\mkrelatedstringtext]{bypublisher}\space}% \printlist{publisher}% \setunit{\addcomma\space}% \iflistsequal{location}{savedlocation} @@ -3033,7 +3059,7 @@ test {\iflistundef{publisher}} } {} - {\setunit{\addspace\bibstring[\mkrelatedstring]{bypublisher}\space}% + {\setunit{\addspace\bibstring[\mkrelatedstringtext]{bypublisher}\space}% \printlist{publisher}% \setunit{\addcomma\space}% \iflistsequal{location}{savedlocation} @@ -3041,10 +3067,7 @@ {\printlist{location}}}}} \DeclareFieldFormat{title:hook}{% - \begingroup - \mkrelatedstring% - \lbx@inittitlehook{#1}% - \endgroup + \mkrelatedstringtext{\lbx@inittitlehook{#1}}% \mkbibemph{#1}} \newbibmacro*{related:reprintfrom}[1]{% diff --git a/macros/latex/contrib/biblatex/latex/biblatex.sty b/macros/latex/contrib/biblatex/latex/biblatex.sty index 22da31e261..e24c735007 100644 --- a/macros/latex/contrib/biblatex/latex/biblatex.sty +++ b/macros/latex/contrib/biblatex/latex/biblatex.sty @@ -12,8 +12,8 @@ % particular purpose. % Set up the version strings here -\def\abx@date{2020/08/23} -\def\abx@version{3.15a} +\def\abx@date{2020/12/31} +\def\abx@version{3.16} \def\abx@bbxid{\abx@date\space v\abx@version\space biblatex bibliography style (PK/MW)} \def\abx@cbxid{\abx@date\space v\abx@version\space biblatex citation style (PK/MW)} \def\abx@lbxid{\abx@date\space v\abx@version\space biblatex localization (PK/MW)} @@ -52,6 +52,20 @@ This is a fatal error. I'm aborting now}% \endinput} +% The new hook management system in LaTeX 2020-10-01 and above +% no longer guarantees that \AtBeginDocument/AfterPreamble +% are executed in order of use. +% Instead each use of those commands gets a 'label' +% and code for the same label is chunked together. +% We give our \AfterPreamble invocations a new label and set up a rule to +% have it executed after all normal biblatex \AtBeginDocument stuff. +% Note that begindocument is a one-time hook, so we are guaranteed +% immediate execution when inside \begin{document}...\end{document}. +\providecommand\IfFormatAtLeastTF{\@ifl@t@r\fmtversion} +\IfFormatAtLeastTF{2020/10/01} + {\def\blx@AfterPreamble{\AddToHook{begindocument}[biblatex/afterpreamble]}% + \DeclareHookRule{begindocument}{biblatex/afterpreamble}{after}{biblatex}} + {\def\blx@AfterPreamble{\AfterPreamble}} % generalised keyval interface % define a new key (possibly with a default value) @@ -509,8 +523,10 @@ {\let\xpg@bloaded\xpg@loaded}} {}% \global\let\blx@maplang\blx@maplang@polyglossia - \def\do#1{\blx@langsetup{#1}}% + \def\do#1{\blx@langsetup@from@pkglist{#1}}% \expandafter\docsvlist\expandafter{\xpg@bloaded}% + \def\do#1{\blx@langsetup@from@auxlist{#1}}% + \dolistloop\blx@lbx@auxloadlist \ifboolexpr{ not togl {blx@autolangbib} and @@ -521,8 +537,10 @@ {\global\let\blx@maplang\blx@maplang@babel \@ifpackageloaded{babel} {% This is required for languages which are never explicitly selected - \def\do#1{\blx@langsetup{#1}}% + \def\do#1{\blx@langsetup@from@pkglist{#1}}% \expandafter\docsvlist\expandafter{\bbl@loaded}% + \def\do#1{\blx@langsetup@from@auxlist{#1}}% + \dolistloop\blx@lbx@auxloadlist \ifboolexpr{ not togl {blx@autolangbib} and @@ -545,7 +563,10 @@ % babel/polyglossia has loaded the (main document) language already, % so we need to explicitly enable our captions (abx@strings@) % and extras (abx@extras@) now - \toggletrue{blx@lang@captions@\blx@languagename}% + \ifdefstring{\blx@langhook}{captions} + {\blx@etb@inittoggle{blx@lang@captions@\blx@languagename}% + \toggletrue{blx@lang@captions@\blx@languagename}} + {}% \csuse{abx@extras@\blx@languagename}% \csuse{abx@strings@\blx@languagename}% % avoid accidental re-initialization @@ -637,35 +658,44 @@ in recent versions of pdfTeX, LuaTeX and XeTeX}} {\let\blx@mdfivesum\pdf@mdfivesum} +\newtoggle{blx@bbl@rerun@requested} \ifundef\pdf@filemdfivesum {\blx@warning@noline{Command '\string\pdf@filemdfivesum' undefined.\MessageBreak Biber rerun detection may not work as expected.\MessageBreak The command is available (via 'pdftexcmds')\MessageBreak in recent versions of pdfTeX, LuaTeX and XeTeX}% - \let\blx@generate@bbl@mdfivesum@found\relax + \let\blx@generate@bbl@mdfivesum@found\@gobble \let\blx@generate@bbl@mdfivesum@notfound\relax - \let\blx@aux@read@bbl@mdfivesum\@gobble + \let\abx@aux@read@bblrerun\relax + \let\abx@aux@read@bbl@mdfivesum\@gobble \let\blx@aux@write@bbl@mdfivesum\relax \let\blx@check@bbl@rerun@mdfivesum\relax} {\let\blx@filemdfivesum\pdf@filemdfivesum - \def\blx@generate@bbl@mdfivesum@found{% - \xdef\blx@bbl@mdfivesum@new{\blx@filemdfivesum{\jobname.bbl}}} + \def\blx@generate@bbl@mdfivesum@found#1{% + \xdef\blx@bbl@mdfivesum@new{\blx@filemdfivesum{#1}}} + % 'nobblfile' can never be equal to any md5 hash \def\blx@generate@bbl@mdfivesum@notfound{% \gdef\blx@bbl@mdfivesum@new{nobblfile}} - \def\blx@aux@read@bbl@mdfivesum{% + \def\abx@aux@read@bblrerun{\global\toggletrue{blx@bbl@rerun@requested}} + + \def\abx@aux@read@bbl@mdfivesum{% \gdef\blx@bbl@mdfivesum@old} % If we need Biber to rerun, save the hash of the current .bbl. % That way we can detect if the Biber rerun really happened when % we run LaTeX the next time. \def\blx@aux@write@bbl@mdfivesum{% + \blx@auxwrite\@mainaux{}{% + \string\abx@aux@read@bbl@mdfivesum{% + \ifundef\blx@bbl@mdfivesum@old + {nohash} + {\blx@bbl@mdfivesum@new}}}% \iftoggle{blx@runbiber} - {\blx@auxwrite\@mainaux{}{% - \string\blx@aux@read@bbl@mdfivesum{\blx@bbl@mdfivesum@new}}} + {\blx@auxwrite\@mainaux{}{\string\abx@aux@read@bblrerun}} {}} % There was a Biber rerun request last time (\blx@bbl@mdfivesum@old), @@ -673,9 +703,11 @@ % that means *no* Biber rerun happened. % So we need to re-request a rerun. \def\blx@check@bbl@rerun@mdfivesum{% - \ifdefstrequal\blx@bbl@mdfivesum@old\blx@bbl@mdfivesum@new - {\blx@logreq@active{}} - {}}} + \iftoggle{blx@bbl@rerun@requested} + {\ifdefstrequal\blx@bbl@mdfivesum@old\blx@bbl@mdfivesum@new} + {\@secondoftwo} + {\blx@logreq@active{}} + {}}} % xstring replacements @@ -923,6 +955,9 @@ \cslet{blx@defaultrefcontexts@0}\@empty \listadd\blx@allrefsections{0} +% Used to track defernumbers from .aux +\global\let\blx@localnumbers\@empty + % Used to track sorting name key specifications \global\let\blx@sortingnamekeytemplates\@empty @@ -2164,15 +2199,15 @@ \providerobustcmd*{\nohyphenation}{% \language\blx@langwohyphens} -% work around odd XeTeX/babel-french behaviour +% First part of workaround for odd XeTeX/babel-french behaviour % https://github.com/plk/biblatex/issues/979 % fix by Ulrike Fischer -% https://tex.stackexchange.com/a/544914/ +% https://tex.stackexchange.com/a/544914/. +% The second bit lives in blx-unicode.def. \ifundef\XeTeXrevision {\providerobustcmd*{\textnohyphenation}[1]{% \bgroup\nohyphenation#1\egroup}} - {\providerobustcmd*{\textnohyphenation}[1]{% - \bgroup\nohyphenation#1\egroup^^^^200b}} + {} \blx@regimcs{% \setpunctfont \resetpunctfont \ifcapital \autocap \ifpunctmark @@ -5203,6 +5238,7 @@ \do{november}% \do{december}% \do{langamerican}% + \do{langbasque}% \do{langbrazilian}% \do{langbulgarian}% \do{langcatalan}% @@ -5235,6 +5271,7 @@ \do{langturkish}% \do{langukrainian}% \do{fromamerican}% + \do{frombasque}% \do{frombrazilian}% \do{frombulgarian}% \do{fromcatalan}% @@ -5499,7 +5536,9 @@ \IfFileExists{#1} {\blx@info@noline{... file '#1' found}% \csuse{blx@lbxfilehook@simple@preload@#1}% - #3\@@input\@filef@und#4% + #3% + \@@input\@filef@und + #4% \csuse{blx@lbxfilehook@simple@postload@#1}% #5% \ifcsundef{blx@file@lbx@simple@#1} @@ -5518,7 +5557,9 @@ \IfFileExists{#1} {\blx@info@noline{... file '#1' found}% \csuse{blx@lbxfilehook@once@preload@#1}% - #3\@@input\@filef@und#4% + #3% + \@@input\@filef@und + #4% \csuse{blx@lbxfilehook@once@postload@#1}% #5% \ifcsundef{blx@file@lbx@simple@#1} @@ -5588,13 +5629,49 @@ \endgroup} % {<language>} -\def\blx@langsetup#1{% +\protected\def\blx@langsetup#1{% \blx@lbxinput{#1} {\edef\blx@languagename{#1}} {\blx@warning {Language '#1' not supported.\MessageBreak Using dummy definitions}}} +\protected\def\blx@langsetup@from@pkglist#1{% + \global\cslet{blx@lbx@loaded@from@pkglist@#1}\@empty + \blx@langsetup{#1}} + +\protected\def\blx@langsetup@from@auxlist#1{% + \global\cslet{blx@lbx@loaded@from@auxlist@#1}\@empty + \blx@langsetup{#1}} + +\newcommand*{\blx@lbx@loadlist}{} + +\protected\def\blx@langsetup@indoc#1{% + \ifcsundef{blx@lbx@loaded@from@pkglist@#1} + {\xifinlist{#1}\blx@lbx@loadlist + {} + {\listxadd\blx@lbx@loadlist{#1}}% + \ifcsundef{blx@lbx@loaded@from@auxlist@#1} + {\ifcsundef{blx@lbx@loaded@nolistload@#1} + {\blx@warning@noline{% + No localisation for language '#1' loaded.\MessageBreak + Please rerun LaTeX to ensure languages can\MessageBreak + be requested properly}% + \global\cslet{blx@lbx@loaded@nolistload@#1}\@empty} + {}} + {\edef\blx@languagename{#1}}} + {\edef\blx@languagename{#1}}% +} + +\newcommand*{\blx@lbx@auxloadlist}{} + +\def\abx@aux@lbx@loadrequest{% + \listgadd\blx@lbx@auxloadlist} + +\protected\def\blx@lbx@writeloaderequest#1{% + \blx@auxwrite\@mainaux{}{% + \string\abx@aux@lbx@loadrequest{#1}}} + % auxiliary macros % {<field base name>} @@ -6377,6 +6454,7 @@ \let\blx@hook@endlang\@empty \let\blx@hook@initlang\@empty \let\blx@imc@mainlang\@empty +\let\blx@imc@textmainlang\@firstofone \def\blx@hyphenreset{% \blx@ifhyphenationundef{\blx@languagename} {} @@ -6403,7 +6481,7 @@ % afterreset was added in 3.9i (~2014-03-16) % way before 3.9r (2016-04-23), which we require \AddBabelHook{biblatex@langsetup}{afterreset}{% - \expandafter\blx@langsetup\expandafter{\languagename}}% + \expandafter\blx@langsetup@indoc\expandafter{\languagename}}% \ifdef\blx@thelangenv {\def\blx@beglang{% \blx@clearlang @@ -6437,8 +6515,20 @@ {}}} {}% \def\blx@imc@mainlang{% + \ifundef\blx@warn@mainlang + {\blx@warning@noline{% + '\string\mainlang' is deprecated in favour of\MessageBreak + '\string\textmainlang'.% + \MessageBreak + Please consider using the new command,\MessageBreak + but note that the syntax is different.\MessageBreak + Using the old, problematic definition}% + \global\let\blx@warn@mainlang\@empty} + {}% \expandafter\selectlanguage\expandafter{\blx@main@language}}% - \expandafter\blx@langsetup\expandafter{\blx@main@language}% + \def\blx@imc@textmainlang##1{% + {{\expandafter\selectlanguage\expandafter{\blx@main@language}##1}}}% + \expandafter\blx@langsetup@from@pkglist\expandafter{\blx@main@language}% } \def\blx@beglang@spacefactors{\frenchspacing} @@ -6453,12 +6543,12 @@ {\let\blx@main@language\mainbabelname}% \ifundef\polyglossia@language@switched {\apptocmd\select@language - {\expandafter\blx@langsetup\expandafter{\babelname}} + {\expandafter\blx@langsetup@indoc\expandafter{\babelname}} {} {\blx@err@patch{'polyglossia' package}% \blx@mknoautolang}} {\appto\polyglossia@language@switched{% - \expandafter\blx@langsetup\expandafter{\babelname}}}% + \expandafter\blx@langsetup@indoc\expandafter{\babelname}}}% \ifdef\blx@thelangenv {\def\blx@beglang{% \blx@clearlang @@ -6500,15 +6590,27 @@ \blx@beglang@spacefactors}} {}}} {}% - \def\blx@imc@mainlang{\select@language{\blx@main@language}}% - \expandafter\blx@langsetup\expandafter{\blx@main@language}} + \def\blx@imc@mainlang{% + \ifundef\blx@warn@mainlang + {\blx@warning@noline{% + '\string\mainlang' is deprecated in favour of\MessageBreak + '\string\textmainlang'.% + \MessageBreak + Please consider using the new command,\MessageBreak + but note that the syntax is different.\MessageBreak + Using the old, problematic definition}% + \global\let\blx@warn@mainlang\@empty} + {}% + \select@language{\blx@main@language}}% + \def\blx@imc@textmainlang##1{{{\select@language{\blx@main@language}##1}}}% + \expandafter\blx@langsetup@from@pkglist\expandafter{\blx@main@language}} \def\blx@mknoautolang{% \blx@lbxinput{\blx@languagename} {} {\blx@err@nolang{\blx@languagename}}} -\blx@regimcs{\mainlang} +\blx@regimcs{\mainlang \textmainlang} \newrobustcmd*{\DeclareRedundantLanguages}[2]{% \begingroup @@ -8302,14 +8404,14 @@ \abx@flfw@getfieldformat{abx@flfw@labelnumberwidth}{labelnumberwidth}{}% \abx@flfw@getfieldformat{abx@flfw@labelprefix}{labelprefix}{}% \abx@flfw@getfieldformat{abx@flfw@labelnumber}{labelnumber}{}% - \iftoggle{blx@defernumbers} - {\ifundef\abx@field@localnumber - {\numdef\abx@field@localnumber{0}}% - {}} - {\ifundef\abx@field@localnumber - {\edef\abx@field@localnumber{% - \csuse{blx@labelnumber@\the\c@refsection}}} - {}}% + \iftoggle{blx@defernumbers} + {\ifundef\abx@field@localnumber + {\numdef\abx@field@localnumber{0}}% + {}} + {\ifundef\abx@field@localnumber + {\edef\abx@field@localnumber{% + \csuse{blx@labelnumber@\the\c@refsection}}} + {}}% \blx@setlabwidth{\csname #1labelnumberwidth\endcsname}{% \csuse{abx@flfw@labelnumberwidth}{% \ifdef\abx@field@labelprefix @@ -8549,13 +8651,18 @@ % any citations or add/remove any sorting templates, we need to re-run % biber. Also, if we have to re-run biber, we need to defer writing % the defernumbers .aux information because it will not yet be correct. - + \begingroup + % Test to see if there are any .aux entries with defernums (localnum) + % information which are no longer in the .bbl. This is to catch + % when .bib entries are removed when using \nocite{*}. In this case, + % We need another run to remove the .aux localnumber info + \def\do#1{\xifinlist{#1}\blx@entries{}{\blx@rerun@latex}}% + \dolistloop\blx@localnumbers % Test to see if we *removed* any citations since last run % (adding citations is dealt with naturally in \blx@citation@entry) % If so, give a rerun biber message. This also sets the % rerun biber toggle so defernums doesn't consume the localnumbers % in the .aux but instead, re-writes them, which is what we need. - \begingroup \def\do#1{\ifinlist{#1}\blx@cites{}{\blx@logreq@active{}}\relax}% \dolistloop\blx@lastcites % Special case - if we are using sortingtemplate with \citeorder anywhere, @@ -8603,9 +8710,16 @@ {\def\do#1{\blx@auxwrite\@mainaux{}{#1}} \dolistloop\blx@localnumaux}} {}% - % Wite md5 hash of .bbl to .aux if we need a Biber rerun. + % Write out missing languages we still need to load + \forlistloop{\blx@lbx@writeloaderequest}{\blx@lbx@loadlist}% + % Issue rerun warning if we need to load a language babel/polyglossia + % hasn't told us about and that we are not loading it already from previous + % runs. + \def\do#1{\xifinlist{#1}{\blx@lbx@auxloadlist}{}{\blx@rerun@latex\listbreak}}% + \dolistloop\blx@lbx@loadlist + % Write md5 hash of .bbl to .aux if we need a Biber rerun. % This needs to happen here and not in \blx@check@rerun together with - % the other rerun stuff, because \AfterEndBibliography would be too + % the other rerun stuff, because \AfterEndDocument would be too % late for .aux file writing. \blx@aux@write@bbl@mdfivesum \endgroup} @@ -8614,6 +8728,8 @@ \protected\def\blx@aux@number#1#2#3#4#5{% \blx@bbl@addentryfield{\detokenize{#2}}{#3}{localnumber}{#4}{#5}% \blx@bbl@addentryfield{\detokenize{#2}}{#3}{labelnumber}{#4}{#5}% + \csgdef{blx@localnumber@#3@\detokenize{#2}}{#5}% + \xifinlist{\detokenize{#2}}\blx@localnumbers{}{\listxadd\blx@localnumbers{\detokenize{#2}}}% \global\toggletrue{blx@localnumber}% \ifblank{#5} {} @@ -8632,9 +8748,14 @@ % Also, don't want to regenerate localnumber for any key in a % refsection which we've already seen because this has the nasty % side-effect of incrementing the localnum counter - {\ifboolexpr { not togl {blx@localnumber} - and - not test {\ifcsdef{blx@defer@\the\c@refsection @\blx@refcontext@context @\abx@field@entrykey}} } + % Also, have to create localnumber again if \nocite{*} as items + % could have been added to the .bib file without changing the cite + % information in the .tex + {\ifboolexpr { (not togl {blx@localnumber} + or + test {\ifinlist{*}\blx@nocites}) + and + not test {\ifcsdef{blx@defer@\the\c@refsection @\blx@refcontext@context @\abx@field@entrykey}} } {\iftoggle{blx@omitnumbers} {\let\abx@field@localnumber\@empty} {\csnumgdef{blx@labelnumber@\the\c@refsection}{% @@ -8642,7 +8763,17 @@ \edef\abx@field@localnumber{% \csuse{blx@labelnumber@\the\c@refsection}}% \blx@bbl@addentryfield{\abx@field@entrykey}{\the\c@refsection}% - {localnumber}{\blx@refcontext@context}{\abx@field@localnumber}}} + {localnumber}{\blx@refcontext@context}{\abx@field@localnumber}}} + {}% + % Issue re-run message if there was no localnumber in the .aux and + % \nocite{*} was used because this means that an entry was added to the .bib + % and was not yet recorded in the .aux. We will have generated a localnumber + % for such a case above and now we need to re-run to make sure it's in the .aux + % for the next run + \ifboolexpr { test {\ifinlist{*}\blx@nocites} + and + not test {\ifcsdef{blx@localnumber@\the\c@refsection @\abx@field@entrykey}} } + {\blx@rerun@latex} {}% % If localnumbers were already in the .aux, add them % again from the .aux. This prevents some cycling @@ -8653,8 +8784,8 @@ \ifcsundef{blx@defer@\the\c@refsection @\blx@refcontext@context @\abx@field@entrykey} {\ifundef\abx@field@localnumber {} - {\listxadd\blx@localnumaux{% - \string\abx@aux@number% + {\listxadd\blx@localnumaux{% + \string\abx@aux@number% {\the\c@instcount}% {\abx@field@entrykey}% {\the\c@refsection}% @@ -8707,10 +8838,9 @@ {\InputIfFileExists{\jobname.bbl} {\blx@info@noline{... file '\jobname.bbl' found}% \global\toggletrue{blx@bbldone}% - \blx@generate@bbl@mdfivesum@found} + \blx@generate@bbl@mdfivesum@found{\jobname.bbl}} {\blx@info@noline{... file '\jobname.bbl' not found}% \typeout{No file \jobname.bbl.}% - % 'nobblfile' can never be equal to any mdfivehash \blx@generate@bbl@mdfivesum@notfound}} {\blx@generate@bbl@mdfivesum@notfound}% \blx@bblend @@ -8848,6 +8978,7 @@ \blx@kv@defkey{blx@bib1}{heading}{} \blx@kv@defkey{blx@bib1}{env}{} \blx@kv@defkey{blx@bib1}{title}{} +\blx@kv@defkey{blx@bib1}{label}{} \blx@kv@defkey{blx@bib1}{prenote}{} \blx@kv@defkey{blx@bib1}{postnote}{} \blx@kv@defkey{blx@bib1}{omitnumbers}[]{} @@ -8874,6 +9005,7 @@ \blx@kv@defkey{blx@biblist1}{heading}{} \blx@kv@defkey{blx@biblist1}{env}{} \blx@kv@defkey{blx@biblist1}{title}{} +\blx@kv@defkey{blx@biblist1}{label}{} \blx@kv@defkey{blx@biblist1}{prenote}{} \blx@kv@defkey{blx@biblist1}{postnote}{} @@ -9079,6 +9211,10 @@ \blx@kv@defkey{blx@bib2}{title}{\def\blx@thetitle{#1}} \blx@kv@defkey{blx@biblist2}{title}{\def\blx@thetitle{#1}} +\blx@kv@defkey{blx@bhd}{label}{\def\blx@thelabel{#1}} +\blx@kv@defkey{blx@bib2}{label}{\def\blx@thelabel{#1}} +\blx@kv@defkey{blx@biblist2}{label}{\def\blx@thelabel{#1}} + \cslet{blx@note@}\@empty \def\blx@key@bibnote#1#2{% \ifcsundef{blx@note@#2} @@ -9168,10 +9304,12 @@ \def\blx@printbibheading[#1]{% \let\blx@theheading\blx@default@theheading \let\blx@thetitle\blx@default@thetitle + \undef\blx@thelabel \blx@safe@actives \blx@kv@setkeys{blx@bhd}{#1}% \blx@rest@actives \blx@bibheading\blx@theheading\blx@thetitle + \blx@biblabel\blx@thelabel \endgroup} % We use this to determine whether an explicit value for resetnumbers is passed to @@ -9196,6 +9334,7 @@ \let\blx@theprenote\blx@default@theprenote \let\blx@thepostnote\blx@default@thepostnote \let\blx@thetitle\blx@default@thetitle + \undef\blx@thelabel % defaults \let\blx@tempa\@empty% before there is a .bbl, this must not be undef \edef\blx@tempe{\the\c@refsection}% default refsection is current @@ -9250,6 +9389,7 @@ \let\blx@theprenote\blx@default@theprenote \let\blx@thepostnote\blx@default@thepostnote \let\blx@thetitle\blx@default@thetitle + \undef\blx@thelabel \c@refsection\z@ \blx@safe@actives \blx@kv@setkeys{blx@bbs}{#1}% @@ -9289,6 +9429,7 @@ \let\blx@theprenote\blx@default@theprenote \let\blx@thepostnote\blx@default@thepostnote \let\blx@thetitle\blx@default@thetitle + \undef\blx@thelabel \c@refsegment\@ne \blx@safe@actives \blx@kv@setkeys{blx@bbg}{#1}% @@ -9333,6 +9474,7 @@ \let\blx@theprenote\blx@default@theprenote \let\blx@thepostnote\blx@default@thepostnote \let\blx@thetitle\blx@default@thetitle + \undef\blx@thelabel \c@refsection\z@ \blx@safe@actives \blx@kv@setkeys{blx@bbc}{#1}% @@ -9361,6 +9503,7 @@ % {<entrykey>,...} \def\blx@bibliography{% \blx@bibheading\blx@theheading\blx@thetitle + \blx@biblabel\blx@thelabel \blx@bibnote\blx@theprenote \begingroup \blx@bibinit @@ -9403,6 +9546,11 @@ \let\newrefsection\blx@newrefsection \let\newrefsegment\blx@newrefsegment} +\def\blx@biblabel#1{% + \ifdefvoid#1 + {} + {\expandafter\label\expandafter{#1}}} + \def\blx@bibnote#1{% \ifdefempty#1 {} @@ -9631,6 +9779,7 @@ \let\blx@theprenote\@empty \let\blx@thepostnote\@empty \let\blx@thetitle\@empty + \undef\blx@thelabel % defaults \let\blx@tempa\@empty% before there is a .bbl, this must not be undef % default sorting template and template name for list is same name as list @@ -9713,6 +9862,7 @@ \@restonecolfalse \fi \blx@bibheading\blx@theheading\blx@thetitle + \blx@biblabel\blx@thelabel \blx@bibnote\blx@theprenote \begingroup \blx@bibinit @@ -9900,6 +10050,7 @@ \let\blx@tempc\@empty% \def\blx@tempd{global}% \def\blx@tempe{global}% + \blx@kv@setkeys{blx@assignrefcontextmeta}{#2}% \blx@kv@setkeys{blx@assignrefcontext}{#2}% \def\do##1{% \listxadd\blx@assignedrefcontextkeywlist{##1}% @@ -9919,6 +10070,7 @@ \let\blx@tempc\@empty% \def\blx@tempd{global}% \def\blx@tempe{global}% + \blx@kv@setkeys{blx@assignrefcontextmeta}{#2}% \blx@kv@setkeys{blx@assignrefcontext}{#2}% \def\do##1{% \listxadd\blx@assignedrefcontextcatlist{##1}% @@ -9938,22 +10090,38 @@ \let\blx@tempc\@empty% \def\blx@tempd{global}% \def\blx@tempe{global}% + \blx@kv@setkeys{blx@assignrefcontextmeta}{#2}% \blx@kv@setkeys{blx@assignrefcontext}{#2}% \def\do##1{% \csxdef{blx@assignedrefcontextkeys#1@\the\c@refsection @##1}% {\blx@tempa/\blx@tempb/\blx@tempc/\blx@tempd/\blx@tempe}}% \docsvlist{#3}} +% This makes sure that named refcontexts set options first +% Note that the docs say that "name=default" selects the global default +% refcontext and this is because this won't set anything and the defaults +% in the above macros will take effect. +\blx@kv@defkey{blx@assignrefcontextmeta}{name}{% + \begingroup + \edef\blx@tempf{\endgroup% + \noexpand\blx@kv@setkeys{blx@assignrefcontext}{\csuse{blx@refcontext@name@#1}}}% + \blx@tempf} +\blx@kv@defkey{blx@assignrefcontextmeta}{nametemplates}{} +\blx@kv@defkey{blx@assignrefcontextmeta}{sorting}{} +\blx@kv@defkey{blx@assignrefcontextmeta}{sortingnamekeytemplatename}{} +\blx@kv@defkey{blx@assignrefcontextmeta}{labelprefix}{} +\blx@kv@defkey{blx@assignrefcontextmeta}{uniquenametemplatename}{} +\blx@kv@defkey{blx@assignrefcontextmeta}{labelalphanametemplatename}{} + % Meta option to set all name template options +\blx@kv@defkey{blx@assignrefcontext}{name}{} \blx@kv@defkey{blx@assignrefcontext}{nametemplates}{% \def\blx@tempb{#1}% \def\blx@tempd{#1}% \def\blx@tempe{#1}} - \blx@kv@defkey{blx@assignrefcontext}{sorting}{\def\blx@tempa{#1}} \blx@kv@defkey{blx@assignrefcontext}{sortingnamekeytemplatename}{\def\blx@tempb{#1}} -\blx@kv@defkey{blx@assignrefcontext}{labelprefix}{% - \edef\blx@tempc{\blx@mdfivesum{#1}}} +\blx@kv@defkey{blx@assignrefcontext}{labelprefix}{\edef\blx@tempc{\blx@mdfivesum{#1}}} \blx@kv@defkey{blx@assignrefcontext}{uniquenametemplatename}{\def\blx@tempd{#1}} \blx@kv@defkey{blx@assignrefcontext}{labelalphanametemplatename}{\def\blx@tempe{#1}} @@ -10408,7 +10576,7 @@ {\blx@error {Category '#1' not declared} {Use \string\DeclareBibliographyCategory\space to declare}} - {\AfterPreamble{% + {\blx@AfterPreamble{% \blx@xsanitizeafter{\forcsvlist{\blx@addtocategory{#1}}}{#2}}}} % {<category>}{<entrykey>,...} @@ -10692,6 +10860,7 @@ \blx@citation@all} \def\blx@citation@all{% + \blx@auxwrite\@mainaux{}{\string\abx@aux@nociteall}% \ifbool{citerequest} {\blx@bibreq{*}% \global\csletcs @@ -10702,6 +10871,9 @@ {}} {}} +\def\abx@aux@nociteall{% + \listgadd\blx@nocites{*}} + \protected\def\blx@bibreq#1{% \begingroup \blx@xmlsanitizeafter{\def\blx@tempa}{#1}% @@ -10746,7 +10918,7 @@ I'm ignoring the new definition}}} {\global\cslet{blx@set@\the\c@refsection @\blx@tempa}\blx@tempb \edef\blx@tempa{% - \AfterPreamble{\blx@setreq{\blx@tempa}{\blx@tempb}}}% + \blx@AfterPreamble{\blx@setreq{\blx@tempa}{\blx@tempb}}}% \blx@tempa}% \endgroup \@esphack} @@ -11468,7 +11640,7 @@ \def\blx@nocite#1{% \@bsphack - \AfterPreamble{% + \blx@AfterPreamble{% \ifstrequal{*}{#1} {\blx@nocitation@all} {\blx@xsanitizeafter{\forcsvlist\blx@nocite@do}{#1}}}% @@ -15272,34 +15444,75 @@ \csdef{blx@opt@casechanger@auto}{% - \RequirePackage{expl3}[2020/04/06]% - \@ifpackagelater{expl3}{2020/04/06} - {\blx@info{expl3\MessageBreak\csuse{ver@expl3.sty}\MessageBreak - is new enough (at least 2020/04/06),\MessageBreak - setting 'casechanger=expl3'}% - \csuse{blx@opt@casechanger@expl3}} - {\blx@info{expl3\MessageBreak\csuse{ver@expl3.sty}\MessageBreak - is too old (older than 2020/04/06),\MessageBreak - setting 'casechanger=latex2e'}% + \ifdefstring{\blx@texencoding}{utf8} + {\blx@info@noline{Document encoding is UTF8 ...}% + \RequirePackage{expl3}[2020/04/06]% + \@ifpackagelater{expl3}{2020/04/06} + {\blx@info@noline{... and expl3\MessageBreak\csuse{ver@expl3.sty}\MessageBreak + is new enough (at least 2020/04/06),\MessageBreak + setting 'casechanger=expl3'}% + \csuse{blx@opt@casechanger@expl3}} + {\blx@info@noline{... but expl3\MessageBreak\csuse{ver@expl3.sty}\MessageBreak + is too old (older than 2020/04/06),\MessageBreak + setting 'casechanger=latex2e'}% + \csuse{blx@opt@casechanger@latex2e}}} + {\blx@info@noline{% + Document encoding not detected as UTF8.\MessageBreak + Setting 'casechanger=latex2e'}% \csuse{blx@opt@casechanger@latex2e}}} \csdef{blx@opt@casechanger@latex2e}{% - \blx@inputonce{blx-case-latex2e.def} - {LaTeX2e (legacy) case changing code} - {}{}{}{}} + \RequirePackage{blx-case-latex2e}} \csletcs{blx@opt@casechanger@2e}{blx@opt@casechanger@latex2e} -% Apparently neither \input nor \blx@inputonce ever pops the -% \ExplSyntaxOff from \ProvidesExplFile, so we do that ourselves. \csdef{blx@opt@casechanger@expl3}{% - \blx@inputonce{blx-case-expl3.def} - {expl3 case changing code} - {}{\ExplSyntaxOff}{}{}} + \ifdefstring{\blx@texencoding}{utf8} + {} + {\blx@warning@noline{% + The expl3 case changer code should only be used\MessageBreak + with UTF-8 encoding.\MessageBreak + But the document encoding was detected as + '\blx@texencoding'.\MessageBreak + Case changing macros may break\MessageBreak + if used with non-ASCII characters}}% + \RequirePackage{blx-case-expl3}} \csletcs{blx@opt@casechanger@3}{blx@opt@casechanger@expl3} % default to auto \csletcs{blx@deferoption@casechanger}{blx@opt@casechanger@auto} +% This is a bit unfortunate, but we need some more definitions after +% loading the case changing code. +\def\blx@casechange@postload{% + % Language fallback, in order: + % * explicit option language=<lang>, which overrides everything + % * langid field of entry + % * babel/polyglossia lang + % * main document lang (we should never reach this) + % * <empty> (we should *definitely* never reach this) + % Everything here is expandable so that + % \blx@mksc@lang expands to the language name. + \def\blx@mksc@lang{% + \ifundef\blx@forcelanguagename + {\ifundef\abx@field@langid + {\ifundef\blx@languagename + {\ifundef\blx@main@language + {} + {\blx@main@language}} + {\blx@languagename}} + {\abx@field@langid}} + {\blx@forcelanguagename}}% + % + \DeclareCaseLangs{% + american,british,canadian, + english,USenglish,UKenglish, + australian,newzealand}% + % Textcase defines \NoCaseChange as \let\NoCaseChange\@firstofone + \ifundef\NoCaseChange + {\let\NoCaseChange\@firstofone} + {}} +% That's it for the case change code + % Set defaults \blx@kv@setkeys{blx@opt@ldt}{style=numeric} \blx@kv@setkeys{blx@opt@pre}{% @@ -15340,43 +15553,6 @@ % Process load-time options \ProcessOptions* -% this ultimately loads either -% blx-case-expl3.def or blx-case-latex2e.def -\blx@deferoption@casechanger - -% This is a bit unfortunate, but we need some more definitions here. - -% Language fallback, in order: -% * explicit option language=<lang>, which overrides everything -% * langid field of entry -% * babel/polyglossia lang -% * main document lang (we should never reach this) -% * <empty> (we should *definitely* never reach this) -% Everything here is expandable so that -% \blx@mksc@lang expands to the language name. -\def\blx@mksc@lang{% - \ifundef\blx@forcelanguagename - {\ifundef\abx@field@langid - {\ifundef\blx@languagename - {\ifundef\blx@main@language - {} - {\blx@main@language}} - {\blx@languagename}} - {\abx@field@langid}} - {\blx@forcelanguagename}} - -\DeclareCaseLangs{% - american,british,canadian, - english,USenglish,UKenglish, - australian,newzealand} - - -% Textcase defines \NoCaseChange as \let\NoCaseChange\@firstofone -\ifundef\NoCaseChange - {\let\NoCaseChange\@firstofone} - {} - -% That's it for the case change code % Switch to BibTeX support if requested \iftoggle{blx@bibtex} @@ -15542,6 +15718,10 @@ \AtBeginDocument{% \blx@auxwrite\@mainaux{}{\string\abx@aux@refcontext{\blx@refcontext@context}} \blx@checkencoding + % this ultimately loads either + % blx-case-expl3.def or blx-case-latex2e.def + \blx@deferoption@casechanger + \blx@casechange@postload \if@filesw \blx@ctrlwrite \fi diff --git a/macros/latex/contrib/biblatex/latex/blx-bibtex.def b/macros/latex/contrib/biblatex/latex/blx-bibtex.def index 03d6781131..956b4708c5 100644 --- a/macros/latex/contrib/biblatex/latex/blx-bibtex.def +++ b/macros/latex/contrib/biblatex/latex/blx-bibtex.def @@ -215,6 +215,7 @@ \patchcmd{\blx@bblinput}{\blx@bblfile}{\blx@bblfile\blx@bblsecs}{}{} + \def\blx@bblfile{% \blx@secinit \begingroup @@ -227,13 +228,18 @@ \blx@ifsigned{\blx@auxfile}{bbl} {\InputIfFileExists{\blx@auxfile.bbl} {\blx@info@noline{... file '\blx@auxfile.bbl' found}% - \global\toggletrue{blx@bbldone}} + \global\toggletrue{blx@bbldone}% + \blx@generate@bbl@mdfivesum@found{\blx@auxfile.bbl}} {\blx@info@noline{... file '\blx@auxfile.bbl' not found}% \typeout{No file \blx@auxfile.bbl.}% - \global\togglefalse{blx@bbldone}}} + \global\togglefalse{blx@bbldone}% + \blx@generate@bbl@mdfivesum@notfound}} {}% \blx@bblend \endgroup + % Check if Biber rerun was not carried out. + % If so, ask for it again. + \blx@check@bbl@rerun@mdfivesum \csnumgdef{blx@labelnumber@\the\c@refsection}{0}} \def\blx@bblsecs{% diff --git a/macros/latex/contrib/biblatex/latex/blx-case-expl3.def b/macros/latex/contrib/biblatex/latex/blx-case-expl3.sty index e9b7f23289..e90a4a7c11 100644 --- a/macros/latex/contrib/biblatex/latex/blx-case-expl3.def +++ b/macros/latex/contrib/biblatex/latex/blx-case-expl3.sty @@ -1,8 +1,29 @@ \RequirePackage{expl3}[2020/04/06] \RequirePackage{xparse} -\ProvidesExplFile {blx-case-expl3} {\abx@date} {\abx@version} +\ProvidesExplPackage {blx-case-expl3} {\abx@date} {\abx@version} {expl3 case changing code for biblatex} + +% helper macros to work around babel \languagename catcode weirdness +\cs_new:Npn \__biblatex_clist_put_detokenized_left:Nn #1 #2 + { + \clist_put_left:No #1 { \detokenize{#2} } + } + +\cs_generate_variant:Nn \__biblatex_clist_put_detokenized_left:Nn { Ne } + + +\prg_new_conditional:Npnn \__biblatex_clist_if_detokenized_in:Nn #1#2 { TF } + { + \clist_if_in:NoTF #1 { \detokenize{#2} } + {\prg_return_true:} + {\prg_return_false:} + } + +\prg_generate_conditional_variant:Nnn \__biblatex_clist_if_detokenized_in:Nn {Ne} {TF} + + + % Map for babel/polyglossia names % to BCP-47-like l3text names. % We only need maps for l3text names that do something @@ -209,8 +230,6 @@ } -\cs_generate_variant:Nn \clist_if_in:NnTF { NxTF } - \cs_generate_variant:Nn \biblatex_text_sentencecase:nn { Vo, xo } % If \DeclareCaseLangs says we should apply sentence casing, @@ -222,7 +241,7 @@ { \IfBooleanTF {#1} { - \clist_if_in:NxTF + \__biblatex_clist_if_detokenized_in:NeTF \l__biblatex_caselangs_clist { \blx@mksc@lang } { \biblatex_text_sentencecase:xo { \blx@mksc@lang } @@ -244,19 +263,18 @@ { \IfBooleanF {#1} { \clist_clear:N \l__biblatex_caselangs_clist } - \clist_put_left:Nn \l__biblatex_caselangs_clist {#2} + \__biblatex_clist_put_detokenized_left:Ne + \l__biblatex_caselangs_clist {#2} } % \DeclareCaseLangs invocation is in biblatex.sty - \NewDocumentCommand \ifcaselang {O{\blx@languagename}} { - \clist_if_in:NxTF \l__biblatex_caselangs_clist {#1} + \__biblatex_clist_if_detokenized_in:NeTF \l__biblatex_caselangs_clist {#1} } - \msg_new:nnnn { biblatex } { invalid-value-bibtexcaseprotection } { Invalid~value~'#1'~for~option~'bibtexcaseprotection'. } { Valid~values~for~'bibtexcaseprotection'~are~'true'~and~'false'. } diff --git a/macros/latex/contrib/biblatex/latex/blx-case-latex2e.def b/macros/latex/contrib/biblatex/latex/blx-case-latex2e.sty index 85641d2e66..5aede0c0bb 100644 --- a/macros/latex/contrib/biblatex/latex/blx-case-latex2e.def +++ b/macros/latex/contrib/biblatex/latex/blx-case-latex2e.sty @@ -1,6 +1,41 @@ -\ProvidesFile{blx-case-latex2e.def} +\ProvidesPackage{blx-case-latex2e} [\abx@cptid] +% auxiliary macros +% babel's \languagename has weird catcodes, +% so we \detokenize our language names + +\def\blx@listgadd@switched#1#2{\listgadd{#2}{#1}} + +\ifundef\expanded + {\protected\def\blx@deifinlist#1{% + \begingroup + \edef\blx@tempa{\endgroup + \blx@deifinlist@i{#1}}% + \blx@tempa}% + \protected\def\blx@deifinlist@i#1{% + \expandafter\ifinlist\expandafter{\detokenize{#1}}}% + % + \protected\def\blx@listdxadd@switched#1{% + \begingroup + \edef\blx@tempa{\endgroup + \blx@listdxadd@switched@i{#1}}% + \blx@tempa}% + \protected\def\blx@listdxadd@switched@i#1{% + \expandafter\blx@listgadd@switched\expandafter{\detokenize{#1}}}} + {\def\blx@deifinlist#1{% + \expandafter\expandafter\expandafter\ifinlist + \expandafter\expandafter\expandafter{% + \expandafter\detokenize\expandafter{\expanded{#1}}}}% + % + \def\blx@listdxadd@switched#1{% + \expandafter\expandafter\expandafter\blx@listgadd@switched + \expandafter\expandafter\expandafter{% + \expandafter\detokenize\expandafter{\expanded{#1}}}}} + +\def\blx@listdxadd#1#2{\blx@listdxadd@switched{#2}{#1}} + + % we don't have l3text's (pseudo)BCP47 language codes here \newrobustcmd*{\DeclareBabelToExplLanguageMapping}[2]{% \blx@warning{The command '\string\DeclareBabelToExplLanguageMapping'% @@ -108,10 +143,11 @@ \newrobustcmd*{\MakeSentenceCase}{% \@ifstar\blx@mksc@i\blx@mksc@ii} + % \blx@cmksc@lang is defined in biblatex.sty % it expands to the applicable language for the title field \def\blx@mksc@i{% - \xifinlist\blx@mksc@lang\blx@cmksc@lang + \blx@deifinlist\blx@mksc@lang\blx@cmksc@lang {\blx@mksc@ii} {\@firstofone}} @@ -280,11 +316,11 @@ \def\blx@defcaselangs#1{% \ifblank{#1} {} - {\forcsvlist{\listgadd\blx@cmksc@lang}{#1}}} + {\forcsvlist{\blx@listdxadd\blx@cmksc@lang}{#1}}} % \DeclareCaseLangs invocation is in biblatex.sty \newrobustcmd*{\ifcaselang}[1][\blx@languagename]{% - \xifinlist{#1}\blx@cmksc@lang} + \blx@deifinlist{#1}\blx@cmksc@lang} \endinput diff --git a/macros/latex/contrib/biblatex/latex/blx-compat.def b/macros/latex/contrib/biblatex/latex/blx-compat.def index 546f16af43..46272f181f 100644 --- a/macros/latex/contrib/biblatex/latex/blx-compat.def +++ b/macros/latex/contrib/biblatex/latex/blx-compat.def @@ -351,5 +351,9 @@ Please use '\string\mkdaterangeisoextra'}% \mkdaterangeisoextra} +% 3.16 +% deprecate \mainlang for \textmainlang +% and \mkrelatedstring for \mkrelatedstringtext +\newcommand{\mkrelatedstring}{\mainlang} \endinput diff --git a/macros/latex/contrib/biblatex/latex/blx-dm.def b/macros/latex/contrib/biblatex/latex/blx-dm.def index 0667b577ae..cb23e20c5f 100644 --- a/macros/latex/contrib/biblatex/latex/blx-dm.def +++ b/macros/latex/contrib/biblatex/latex/blx-dm.def @@ -1464,7 +1464,7 @@ } } -\DeclareDatamodelConstraints[book,mvbook,mvcollection,mvreference]{ +\DeclareDatamodelConstraints[book,mvbook]{ \constraint[type=mandatory]{ \constraintfield{author} \constraintfield{title} @@ -1489,7 +1489,7 @@ } } -\DeclareDatamodelConstraints[collection,reference]{ +\DeclareDatamodelConstraints[collection,reference,mvcollection,mvreference]{ \constraint[type=mandatory]{ \constraintfield{editor} \constraintfield{title} @@ -1598,12 +1598,6 @@ \constraint[type=data, datatype=ismn]{ \constraintfield{ismn} } - \constraint[type=data, datatype=date]{ - \constraintfield{date} - \constraintfield{eventdate} - \constraintfield{origdate} - \constraintfield{urldate} - } \constraint[type=data, datatype=pattern, pattern=\regexp{(?:sf|sm|sn|pf|pm|pn|pp)}]{ \constraintfield{gender} } diff --git a/macros/latex/contrib/biblatex/latex/blx-unicode.def b/macros/latex/contrib/biblatex/latex/blx-unicode.def index 01009c028c..12eabfe98b 100644 --- a/macros/latex/contrib/biblatex/latex/blx-unicode.def +++ b/macros/latex/contrib/biblatex/latex/blx-unicode.def @@ -32,6 +32,20 @@ \closein\blx@bcfin \endgroup +% Second part of workaround for odd XeTeX/babel-french behaviour +% https://github.com/plk/biblatex/issues/979 +% fix by Ulrike Fischer +% https://tex.stackexchange.com/a/544914/. +% The first bit lives in biblatex.sty. +% At some point we may want to consider providing a +% blx-unicode-xetex and a blx-unicode-lualatex +% both loading a blx-unicode-generic. +% For now this test is enough. +\ifundef\XeTeXrevision + {} + {\providerobustcmd*{\textnohyphenation}[1]{% + \bgroup\nohyphenation#1\egroup^^^^200b}} + \appto\blx@setfrcodes{% % … should probably have dot spacefactor, but pdfLaTeX % makes it a period, so we have this here for consistency diff --git a/macros/latex/contrib/biblatex/latex/lbx/basque.lbx b/macros/latex/contrib/biblatex/latex/lbx/basque.lbx new file mode 100644 index 0000000000..6263081e97 --- /dev/null +++ b/macros/latex/contrib/biblatex/latex/lbx/basque.lbx @@ -0,0 +1,480 @@ +\ProvidesFile{basque.lbx} +[\abx@lbxid] + +\DeclareRedundantLanguages{basque}{basque} + +\DeclareBibliographyExtras{% + \protected\def\bibrangedash{\mbox{-}}% non-breaking hyphen + \let\finalandcomma=\empty + \let\finalandsemicolon=\empty + \def\mkbibordinal{\mkbibmascord}% + \providecommand*{\sptext}{\textsuperscript}% \sptext -> spanish.ldf (babel) + %\protected\def\mkbibmascord#1{\stripzeros{#1}\sptext{o}}% + \protected\def\mkbibmascord#1{\stripzeros{#1}\adddot}% + %\protected\def\mkbibfemord#1{\stripzeros{#1}\sptext{a}}% + \protected\def\mkbibfemord#1{\stripzeros{#1}\adddot}% + \protected\def\mkbibneutord{\mkbibmascord}% + \protected\def\mkbibdatelong#1#2#3{% + \iffieldundef{#3} + {} + {\stripzeros{\thefield{#3}}% + \iffieldundef{#2}{}{\nobreakspace de\space}}% + \iffieldundef{#2} + {} + {\mkbibmonth{\thefield{#2}}% + \iffieldundef{#1}{}{\nobreakspace de\space}}% + \iffieldbibstring{#1} + {\bibstring{\thefield{#1}}} + {\dateeraprintpre{#1}\mkyearzeros{\thefield{#1}}}}% + \protected\def\mkbibdateshort#1#2#3{% + \iffieldundef{#1} + {} + {\mkdayzeros{\thefield{#1}}% + \iffieldundef{#2}{}{\mbox{-}}}% + \iffieldundef{#2} + {} + {\mkmonthzeros{\thefield{#2}}% + \iffieldundef{#1}{}{\mbox{-}}}% + \iffieldbibstring{#3} + {\bibstring{\thefield{#3}}} + \stripzeros{\thefield{#3}}}% + \savecommand\mkdaterangeterse + \protected\def\mkdaterangeterse{% + \BibliographyWarning{% + Date format 'terse' not applicable to\MessageBreak + Spanish dates. Using format 'short' instead}% + \mkdaterangefull{short}}% + \savecommand\mkbibordedition + \savecommand\mkbibordseries + \def\mkbibordedition{\mkbibfemord}% + \def\mkbibordseries{\mkbibfemord}% + \expandafter\protected\expandafter\def\csname mkbibtime24h\endcsname#1#2#3#4{% + \iffieldundef{#1}{} + {\printtext{\mktimezeros{\thefield{#1}}}\setunit{\bibtimesep}}% + \iffieldundef{#2}{} + {\printtext{\mktimezeros{\thefield{#2}}}\setunit{\bibtimesep}}% + \iffieldundef{#3}{} + {\printtext{\mktimezeros{\thefield{#3}}}}% + \setunit{}% + \iffieldundef{#4}{} + {\bibtimezonesep + \mkbibtimezone{\thefield{#4}}}}% + \expandafter\protected\expandafter\def\csname mkbibtime12h\endcsname#1#2#3#4{% + \stripzeros{\mktimehh{\thefield{#1}}}\bibtimesep + \forcezerosmdt{\thefield{#2}}% + \iffieldundef{#3}{} + {\bibtimesep + \forcezerosmdt{\thefield{#3}}}% + \space + \ifnumless{\thefield{#1}}{12} + {\bibstring{am}} + {\bibstring{pm}}% + \iffieldundef{#4}{} + {\space\bibtimezonesep + \parentext{\mkbibtimezone{\thefield{#4}}}}}% + \protected\def\mkbibseasondateshort#1#2{% + \mkbibseason{\thefield{#2}}% + \iffieldundef{#1}{}{\space}% + \dateeraprintpre{#1}\mkyearzeros{\thefield{#1}}}% + \protected\def\mkbibseasondatelong#1#2{% + \mkbibseason{\thefield{#2}}% + \iffieldundef{#1}{}{\space}% + \dateeraprintpre{#1}\mkyearzeros{\thefield{#1}}}% +} + +\UndeclareBibliographyExtras{% + \restorecommand\mkdaterangeterse + \restorecommand\lbx@finalnamedelim + \restorecommand\lbx@finallistdelim + \restorecommand\mkbibordedition + \restorecommand\mkbibordseries +} + +\DeclareBibliographyStrings{% + bibliography = {{Bibliografia}{Bibliografia}},% + references = {{Erreferentziak}{Erreferentziak}},% + shorthands = {{Laburduren zerrenda}{Laburdurak}},% + editor = {{editorea}{ed\adddot}},% + editors = {{editoreak}{edk\adddot}},% + compiler = {{biltzailea}{biltz\adddot}},% + compilers = {{biltzaileak}{biltzk\adddot}},% + redactor = {{erredaktorea}{err\adddot}},% + redactors = {{erredakotreak}{errk\adddot}},% + reviser = {{orraztailea}{orr\adddot}},% + revisers = {{orraztaileak}{orrk\adddot}},% + founder = {{sortzailea}{sor\adddot}},% + founders = {{sortzaileak}{sork\adddot}},% + continuator = {{jarraitzailea}{jarr\adddot}},% + continuators = {{jarraitzaileak}{jarrk\adddot}},% + collaborator = {{kolaboratzailea}{kolab\adddot}},% + collaborators = {{kolaboratzaileak}{kolabk\adddot}},% + translator = {{itzulpena}{itz\adddot}},% + translators = {{itzulpena}{itz\adddot}},% + commentator = {{iruzkingilea}{irzgl\adddot}},% + commentators = {{iruzkingileak}{irzglk\adddot}},% + annotator = {{ohargilea}{ohr\adddot}},% + annotators = {{ohargileak}{ohrk\adddot}},% + commentary = {{iruzkina}{ir\adddot}},% + annotations = {{oharrak}{ohk\adddot}},% + introduction = {{sarrera}{sar\adddot}},% + foreword = {{hitzaurrea}{hitzaur\adddot}},% + afterword = {{hitzatzea}{hitzatz\adddot}},% + editortr = {{edizioa eta \lbx@sfromlang\ itzulpena}{ed\adddotspace eta \lbx@sfromlang\ itz\adddot}},% + editorstr = {{edizioa eta \lbx@sfromlang\ itzulpena}{ed\adddotspace eta \lbx@sfromlang\ itz\adddot}},% + editorco = {{edizioa eta iruzkinak}{ed\adddotspace eta irk\adddot}},% + editorsco = {{edizioa eta iruzkinak}{ed\adddotspace eta irk\adddot}},% + editoran = {{edizioa eta oharrak}{ed\adddotspace eta ohk\adddot}},% + editorsan = {{edizioa eta oharrak}{ed\adddotspace eta ohk\adddot}},% + editorin = {{edizioa eta sarrera}{ed\adddotspace eta sar\adddot}},% + editorsin = {{edizioa eta sarrera}{ed\adddotspace eta sar\adddot}},% + editorfo = {{edizioa eta hitzaurrea}{ed\adddotspace eta hitzaur\adddot}},% + editorsfo = {{edizioa eta hitzaurrea}{ed\adddotspace eta hitzaur\adddot}},% + editoraf = {{edizioa eta hitzatzea}{ed\adddotspace eta hitzatz\adddot}},% + editorsaf = {{edizioa eta hitzatzea}{ed\adddotspace eta hitzatz\adddot}},% + editortrco = {{edizioa, \lbx@sfromlang\ itzulpena eta iruzkinak}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddotspace eta irzk\adddot}},% + editorstrco = {{edizioa, \lbx@sfromlang\ itzulpena eta iruzkinak}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddotspace eta irzk\adddot}},% + editortran = {{edizioa, \lbx@sfromlang\ itzulpena eta oharrak}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddotspace eta ohk\adddot}},% + editorstran = {{edizioa, \lbx@sfromlang\ itzulpena eta oharrak}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddotspace eta ohk\adddot}},% + editortrin = {{edizioa, \lbx@sfromlang\ itzulpena eta sarrera}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddotspace eta sar\adddot}},% + editorstrin = {{edizioa, \lbx@sfromlang\ itzulpena eta sarrera}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddotspace eta sar\adddot}},% + editortrfo = {{edizioa, \lbx@sfromlang\ itzulpena eta hitzaurrea}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddotspace eta hitzaur\adddot}},% + editorstrfo = {{edizioak, \lbx@sfromlang\ itzulpenak eta hitzaurrea}{edk.,\addabbrvspace \lbx@sfromlang\ itzk\adddotspace eta hitzaur\adddot}},% + editortraf = {{edizioa, \lbx@sfromlang\ itzulpena eta hitzatzea}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddotspace eta hitzatz\adddot}},% + editorstraf = {{edizioak, \lbx@sfromlang\ itzulpenak eta hitzatzea}{edk.,\addabbrvspace \lbx@sfromlang\ itzk\adddotspace eta hitzatz\adddot}},% + editorcoin = {{edizioa, iruzkinak eta sarrera}{ed.,\addabbrvspace irzk\adddotspace eta sar\adddot}},% + editorscoin = {{edizioak, iruzkinak eta sarrera}{edk.,\addabbrvspace irzk\adddotspace eta sar\adddot}},% + editorcofo = {{edizioa, iruzkinak eta hitzaurrea}{ed.,\addabbrvspace irzk\adddotspace eta hitzaur\adddot}},% + editorscofo = {{edizioak, iruzkinak eta hitzaurrea}{edk.,\addabbrvspace irzk\adddotspace eta hitzaur\adddot}},% + editorcoaf = {{edizioa, iruzkinak eta hitzatzea}{ed.,\addabbrvspace irzk\adddotspace eta hitzatz\adddot}},% + editorscoaf = {{edizioak, iruzkinak eta hitzatzea}{edk.,\addabbrvspace irzk\adddotspace eta hitzatz\adddot}},% + editoranin = {{edizioa, oharrak eta sarrera}{ed.,\addabbrvspace ohk\adddotspace eta sar\adddot}},% + editorsanin = {{edizioak, oharrak eta sarrera}{edk.,\addabbrvspace ohk\adddotspace eta sar\adddot}},% + editoranfo = {{edizioa, oharrak eta hitzaurrea}{ed.,\addabbrvspace ohk\adddotspace eta hitzatz\adddot}},% + editorsanfo = {{edizioak, oharrak eta hitzaurrea}{edk.,\addabbrvspace ohk\adddotspace eta hitzatz\adddot}},% + editoranaf = {{edizioa, oharrak eta hitzatzea}{ed.,\addabbrvspace ohk\adddotspace eta hitzatz\adddot}},% + editorsanaf = {{edizioak, oharrak eta hitzatzea}{edk.,\addabbrvspace ohk\adddotspace eta hitzatz\adddot}},% + editortrcoin = {{edizioa, \lbx@sfromlang\ itzulpena, iruzkinak eta sarrera}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot,\addabbrvspace irzk\adddotspace eta sar\adddot}},% + editorstrcoin = {{edizioak, \lbx@sfromlang\ itzulpenak, iruzkinak eta sarrera}{edk.,\addabbrvspace \lbx@sfromlang\ itzk\adddot,\addabbrvspace irzk\adddotspace eta sar\adddot}},% + editortrcofo = {{edizioa, \lbx@sfromlang\ itzulpena, iruzkinak eta hitzaurrea}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot,\addabbrvspace irzk\adddotspace eta hitzaur\adddot}},% + editorstrcofo = {{edizioak, \lbx@sfromlang\ itzulpenak, iruzkinak eta hitzaurrea}{edk.,\addabbrvspace \lbx@sfromlang\ itzk\adddot,\addabbrvspace irzk\adddotspace eta hitzaur\adddot}},% + editortrcoaf = {{edizioa, \lbx@sfromlang\ itzulpena, iruzkinak eta hitzatzea}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot,\addabbrvspace irzk\adddotspace eta hitzatz\adddot}},% + editorstrcoaf = {{edizioak, \lbx@sfromlang\ itzulpenak, iruzkinak eta hitzatzea}{edk.,\addabbrvspace \lbx@sfromlang\ itzk\adddot,\addabbrvspace irzk\adddotspace eta hitzatz\adddot}},% + editortranin = {{edizioa, \lbx@sfromlang\ itzulpena, sarrera eta oharrak}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot,\addabbrvspace sar\adddotspace eta ohk\adddot}},% + editorstranin = {{edizioak, \lbx@sfromlang\ itzulpenak, sarrera eta oharrak}{edk.,\addabbrvspace \lbx@sfromlang\ itzk\adddot,\addabbrvspace sar\adddotspace eta ohk\adddot}},% + editortranfo = {{edizioa, \lbx@sfromlang\ itzulpena, hitzaurrea eta oharrak}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot,\addabbrvspace hitzaur\adddotspace eta ohk\adddot}},% + editorstranfo = {{edizioak, \lbx@sfromlang\ itzulpenak, hitzaurrea eta oharrak}{edk.,\addabbrvspace \lbx@sfromlang\ itzk\adddot,\addabbrvspace hitzaur\adddotspace eta ohk\adddot}},% + editortranaf = {{edizioa, \lbx@sfromlang\ itzulpena, hitzatzea eta oharrak}{ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot,\addabbrvspace hitzatz\adddotspace eta ohk\adddot}},% + editorstranaf = {{edizioak, \lbx@sfromlang\ itzulpenak, hitzatzea eta oharrak}{edk.,\addabbrvspace \lbx@sfromlang\ itzk\adddot,\addabbrvspace hitzatz\adddotspace eta ohk\adddot}},% + translatorco = {{\lbx@sfromlang\ itzulpena eta iruzkinak}{\lbx@sfromlang\ itz\adddot\ eta irzk\adddot}},% + translatorsco = {{\lbx@sfromlang\ itzulpenak eta iruzkinak}{\lbx@sfromlang\ itzk\adddot\ eta irzk\adddot}},% + translatoran = {{\lbx@sfromlang\ itzulpena eta oharrak}{\lbx@sfromlang\ itz\adddot\ eta ohk\adddot}},% + translatorsan = {{\lbx@sfromlang\ itzulpenak eta oharrak}{\lbx@sfromlang\ itzk\adddot\ eta ohks\adddot}},% + translatorin = {{\lbx@sfromlang\ itzulpena eta sarrera}{\lbx@sfromlang\ itz\adddot\ eta sar\adddot}},% + translatorsin = {{\lbx@sfromlang\ itzulpenak eta sarrera}{\lbx@sfromlang\ itzk\adddot\ eta sar\adddot}},% + translatorfo = {{\lbx@sfromlang\ itzulpena eta hitzaurrea}{\lbx@sfromlang\ itz\adddot\ eta hitzaur\adddot}},% + translatorsfo = {{\lbx@sfromlang\ itzulpenak eta hitzaurrea}{\lbx@sfromlang\ itzk\adddot\ eta hitzaur\adddot}},% + translatoraf = {{\lbx@sfromlang\ itzulpena eta hitzatzea}{\lbx@sfromlang\ itz\adddot\ eta hitzatz\adddot}},% + translatorsaf = {{\lbx@sfromlang\ itzulpenak eta hitzatzea}{\lbx@sfromlang\ itzk\adddot\ eta hitzatz\adddot}},% + translatorcoin = {{\lbx@sfromlang\ itzulpena, sarrera eta iruzkinak}{\lbx@sfromlang\ itz\adddot, sar\adddotspace eta irzk\adddot}},% + translatorscoin = {{\lbx@sfromlang\ itzulpenak, sarrera eta iruzkinak}{\lbx@sfromlang\ itzk\adddot, sar\adddotspace eta irzk\adddot}},% + translatorcofo = {{\lbx@sfromlang\ itzulpena, hitzaurrea eta iruzkinak}{\lbx@sfromlang\ itz\adddot, hitzaur\adddotspace eta irzk\adddot}},% + translatorscofo = {{\lbx@sfromlang\ itzulpenak, hitzaurrea eta iruzkinak}{\lbx@sfromlang\ itzk\adddot, hitzaur\adddotspace eta irzk\adddot}},% + translatorcoaf = {{\lbx@sfromlang\ itzulpena, hitzatzea eta iruzkinak}{\lbx@sfromlang\ itz\adddot, hitzatz\adddotspace eta irzk\adddot}},% + translatorscoaf = {{\lbx@sfromlang\ itzulpenak, hitzatzea eta iruzkinak}{\lbx@sfromlang\ itzk\adddot, hitzatz\adddotspace eta irzk\adddot}},% + translatoranin = {{\lbx@sfromlang\ itzulpena, sarrera eta oharrak}{\lbx@sfromlang\ itz\adddot, sar\adddotspace eta ohk\adddot}},% + translatorsanin = {{\lbx@sfromlang\ itzulpenak, sarrera eta oharrak}{\lbx@sfromlang\ itzk\adddot, sar\adddotspace eta ohk\adddot}},% + translatoranfo = {{\lbx@sfromlang\ itzulpena, hitzaurrea eta oharrak}{\lbx@sfromlang\ itz\adddot, hitzaur\adddotspace eta ohk\adddot}},% + translatorsanfo = {{\lbx@sfromlang\ itzulpenak, hitzaurrea eta oharrak}{\lbx@sfromlang\ itzk\adddot, hitzaur\adddotspace eta ohk\adddot}},% + translatoranaf = {{\lbx@sfromlang\ itzulpena, hitzatzea eta oharrak}{\lbx@sfromlang\ itz\adddot, hitzatz\adddotspace eta ohk\adddot}},% + translatorsanaf = {{\lbx@sfromlang\ itzulpenak, hitzatzea eta oharrak}{\lbx@sfromlang\ itzk\adddot, hitzatz\adddotspace eta ohk\adddot}},% + organizer = {{antolatzailea(k)}{antltz(k)\adddot}},% + organizers = {{antolatzailea(k)}{antltz(k)\adddot}},% + byorganizer = {{antolatzailea(k)}{antltz(k)\adddot}},% + byauthor = {{egilea(k)}{eg(k)}},% + byeditor = {{editorea(k)}{ed(k)}},% + bycompiler = {{biltzailea(k)}{biltz(k)}},% + byredactor = {{erredaktorea(k)}{err(k)}},% + byreviser = {{orraztailea(k)}{orrz(k)}},% + byreviewer = {{berrikustzailea(k)}{berr(k)}},% + byfounder = {{sortzailea(k)}{sortz(k)}},% + bycontinuator = {{jarraitzailea(k)}{jarr(k)}},% + bycollaborator = {{kolaboratzailea(k)}{kolab(k)}},% + bytranslator = {{\lbx@lfromlang\ itzulpena}{\lbx@sfromlang\ itz\adddot}},% + bycommentator = {{iruzkinak}{irzk\adddotspace}},% + byannotator = {{oharrak}{ohk\adddot}},% + withcommentator = {{iruzkinak}{irzk\adddot}},% + withannotator = {{oharrak}{ohk\adddot}},% + withintroduction = {{sarrera}{sar\adddot}},% + withforeword = {{hitzaurrea}{hitzaur\adddot}},% + withafterword = {{hitzatzea}{hitzatz\adddot}},% + byeditortr = {{edizioa eta \lbx@lfromlang\ itzulpena}% + {ed\adddotspace eta \lbx@sfromlang\ itz\adddot}},% + byeditorco = {{edizioa eta iruzkinak}% + {ed\adddotspace eta irzk\adddot}},% + byeditoran = {{edizioa eta oharrak}% + {ed\adddotspace eta ohk\adddot}},% + byeditorin = {{edizioa eta sarrera}% + {ed\adddotspace eta sar\adddot}},% + byeditorfo = {{edizioa eta hitzaurrea}% + {ed\adddotspace eta hitzaur\adddot}},% + byeditoraf = {{edizioa eta hitzatzea}% + {ed\adddotspace eta hitzatz\adddot}},% + byeditortrco = {{edizioa, \lbx@lfromlang\ itzulpena eta iruzkinak}% + {ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot\ eta irzk\adddot}},% + byeditortran = {{edizioa, \lbx@lfromlang\ itzulpena eta oharrak}% + {ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot\ eta ohk\adddot}},% + byeditortrin = {{edizioa, \lbx@lfromlang\ itzulpena eta sarrera}% + {ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot\ eta sar\adddot}},% + byeditortrfo = {{edizioa, \lbx@lfromlang\ itzulpena eta hitzaurrea}% + {ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot\ eta hitzaur\adddot}},% + byeditortraf = {{edizioa, \lbx@lfromlang\ itzulpena eta hitzatzea}% + {ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot\ eta hitzatz\adddot}},% + byeditorcoin = {{edizioa, iruzkinak eta sarrera}% + {ed.,\addabbrvspace irzk\adddotspace eta sar\adddot}},% + byeditorcofo = {{edizioa, iruzkinak eta hitzaurrea}% + {ed.,\addabbrvspace irzk\adddotspace eta hitzaur\adddot}},% + byeditorcoaf = {{edizioa, iruzkinak eta hitzatzea}% + {ed.,\addabbrvspace irzk\adddotspace eta hitzatz\adddot}},% + byeditoranin = {{edizioa, oharrak eta sarrera}% + {ed.,\addabbrvspace ohk\adddotspace eta sar\adddot}},% + byeditoranfo = {{edizioa, oharrak eta hitzaurrea}% + {ed.,\addabbrvspace ohk\adddotspace eta hitzaur\adddot}},% + byeditoranaf = {{edizioa, oharrak eta hitzatzea}% + {ed.,\addabbrvspace ohk\adddotspace eta hitzatz\adddot}},% + byeditortrcoin = {{edizioa, \lbx@lfromlang itzulpena, iruzkinak eta sarrera}% + {ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot, irzk\adddotspace eta sar\adddot}},% + byeditortrcofo = {{edizioa, \lbx@lfromlang itzulpena, iruzkinak eta hitzaurrea}% + {ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot, irzk\adddotspace eta hitzaur\adddot}},% + byeditortrcoaf = {{edizioa, \lbx@lfromlang itzulpena, iruzkinak eta hitzatzea}% + {ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot, irzk\adddotspace eta hitzatz\adddot}},% + byeditortranin = {{edizioa, \lbx@lfromlang itzulpena, oharrak eta sarrera}% + {ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot, ohk\adddotspace eta sar\adddot}},% + byeditortranfo = {{edizioa, \lbx@lfromlang itzulpena, oharrak eta hitzaurrea}% + {ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot, ohk\adddotspace eta hitzaur\adddot}},% + byeditortranaf = {{edizioa, \lbx@lfromlang itzulpena, oharrak eta hitzatzea}% + {ed.,\addabbrvspace \lbx@sfromlang\ itz\adddot, ohk\adddotspace eta hitzatz\adddot}},% + bytranslatorco = {{\lbx@lfromlang\ itzulpena eta iruzkinak}% + {\lbx@sfromlang\ itz\adddot\ eta irzk\adddot}},% + bytranslatoran = {{\lbx@lfromlang\ itzulpena eta oharrak}% + {\lbx@sfromlang\ itz\adddot\ eta ohk\adddot}},% + bytranslatorin = {{\lbx@lfromlang\ itzulpena eta sarrera}% + {\lbx@sfromlang\ itz\adddot\ eta sarod\adddot}},% + bytranslatorfo = {{\lbx@lfromlang\ itzulpena eta hitzaurrea}% + {\lbx@sfromlang\ itz\adddot\ eta hitzaur\adddot}},% + bytranslatoraf = {{\lbx@lfromlang\ itzulpena eta hitzatzea}% + {\lbx@sfromlang\ itz\adddot\ eta hitzatz\adddot}},% + bytranslatorcoin = {{\lbx@lfromlang itzulpena, iruzkinak eta sarrera}% + {\lbx@sfromlang itz\adddot, irzk\adddotspace eta sar\adddot}},% + bytranslatorcofo = {{\lbx@lfromlang itzulpena, iruzkinak eta hitzaurrea}% + {\lbx@sfromlang itz\adddot, irzk\adddotspace eta pr\'ol\adddot}},% + bytranslatorcoaf = {{\lbx@lfromlang itzulpena, iruzkinak eta hitzatzea}% + {\lbx@sfromlang itz\adddot, irzk\adddotspace eta hitzatz\adddot}},% + bytranslatoranin = {{\lbx@lfromlang itzulpena, oharrak eta sarrera}% + {\lbx@sfromlang itz\adddot, ohk\adddotspace eta sar\adddot}},% + bytranslatoranfo = {{\lbx@lfromlang itzulpena, oharrak eta hitzaurrea}% + {\lbx@sfromlang itz\adddot, ohk\adddotspace eta pr\'ol\adddot}},% + bytranslatoranaf = {{\lbx@lfromlang itzulpena, oharrak eta hitzatzea}% + {\lbx@sfromlang itz\adddot, ohk\adddotspace eta hitzatz\adddot}},% + and = {{eta}{eta}},% + andothers = {{et\adddotspace al\adddot}{et\adddotspace al\adddot}},% + andmore = {{et\adddotspace al\adddot}{et\adddotspace al\adddot}},% + volume = {{bolumena}{bol\adddot}},% + volumes = {{bolumeank}{bolk\adddot}},% + involumes = {{non}{non}},% + jourvol = {{bolumena}{bol\adddot}},% + jourser = {{serie-zenbaki}{ser-zb\adddot}},% + book = {{liburua}{liburua}},% + part = {{atala}{atala}},% + issue = {{zenbakia}{zk\adddot}},% + newseries = {{serie-zenbaki berria}{ser-zb ber\adddot}},% + oldseries = {{serie-zenbaki zaharra}{ser-zb zah\adddot}},% + edition = {{edizioa}{ed\adddot}},% + reprint = {{berrinprimatzea}{berrinp\adddot}},% + reprintof = {{berrinprimatzea}{berrinp\adddot}},% + reprintas = {{berrinprimitua}{berrinp\adddot}},% + reprintfrom = {{berrinprimitua}{berrinp\adddot}},% + reviewof = {{erreseina}{erres\adddot}},% + translationof = {{itzulpena}{itz\adddot}},% + translationas = {{zein hizkuntzara itzulia}{zein hizk\adddot -ra itz\adddot}},% + translationfrom = {{zein hizkuntzatik itzulia}{zein hizk\adddotspace itz\adddot}},% + origpubas = {{originalki argitaratua}{orig\adddotspace argit\adddotspace}},% + origpubin = {{originalki argitaratua}{orig\adddot argit\adddot}},% + astitle = {{izenburua}{izenb\adddot}},% + bypublisher = {{argitaletxea}{argit\adddot}},% + nodate = {{datarik gabe}{dat\adddot gabe}},% + page = {{orria}{orr\adddot}},% + pages = {{orriak}{orrk\adddot}},% + column = {{zutabea}{ztb\adddot}},% + columns = {{zutabeak}{ztbk\adddot}},% + line = {{lerroa}{lerr\adddot}},% + lines = {{lerroak}{lerrk\adddot}},% + verse = {{lerroa}{lerr\adddot}},% + verses = {{lerroak}{lerrk\adddot}},% + section = {{atala}{at\adddot}},% + sections = {{atalak}{atk\adddot}},% + paragraph = {{parrafoa}{parr\adddot}},% + paragraphs = {{parrafoak}{parrk\adddot}},% + pagetotal = {{orria}{orr\adddot}},% + pagetotals = {{orriak}{orrk\adddot}},% + columntotal = {{zutabea}{ztb\adddot}},% + columntotals = {{zutabeak}{ztbk\adddot}},% + linetotal = {{lerroa}{lerr\adddot}},% + linetotals = {{lerroak}{lerrk\adddot}},% + versetotal = {{verso}{v\adddot}}, + versetotals = {{versos}{vv\adddot}}, + sectiontotal = {{atala}{at\adddot}},% + sectiontotals = {{atalak}{atk\adddot}},% + paragraphtotal = {{parrafoa}{parr\adddot}},% + paragraphtotals = {{parrafoak}{parrk\adddot}},% + in = {{non}{non}},% + inseries = {{non}{non}},% + ofseries = {{nongo}{nongo}},% + number = {{zenbakia}{zb\adddot}},% + chapter = {{kapitulua}{kap\adddot}},% + bathesis = {{Lizentziatura tesia}{Liz\adddotspace tesia}},% + mathesis = {{Maisutza tesia}{Mais\adddotspace tesia}},% + phdthesis = {{Tesi doktorala}{Tesi dokt\adddot}},% + candthesis = {{Doktoretzarako hautagaitza tesia}{Dokt\adddotspace haut\adddotspace tesia}},% + resreport = {{ikerketa txostena}{ik\adddotspace txos\adddot}},% + techreport = {{txosten teknikoa}{txos\adddotspace tek\adddot}},% + software = {{programa}{prog\adddot}},% + datacd = {{datu CD-a}{datu CD-a}},% + audiocd = {{audio CD-a}{audio CD-a}},% + version = {{bertsioa}{ber\adddot}},% + url = {{esteka}{esteka}},% + urlfrom = {{noiztik erabilgarri}{erabilg\adddot}},% + urlseen = {{azkenekoz ikusia}{azkenekoz ikusia}},% + inpreparation = {{prestaketa prozesuan}{prest\adddot proz\adddot}},% + submitted = {{bidalia}{bidalia}},% + forthcoming = {{laster}{laster}},% + inpress = {{inprentan}{inprentan}},% + prepublished = {{aurrez argitaratua}{aur\adddot argit\adddot}},% + citedas = {{aurrerantzean aipatua}{aur\adddot aip\adddot}},% + thiscite = {{bereziki}{berez\adddot}},% + seenote = {{ikus oharra}{ik\adddot oh\adddot}},% + quotedin = {{aipatua}{aip\adddot}},% + idem = {{idem}{id\adddot}},% + idemsf = {{idem}{id\adddot}},% + idemsm = {{idem}{id\adddot}},% + idemsn = {{idem}{id\adddot}},% + idempf = {{idem}{id\adddot}},% + idempm = {{idem}{id\adddot}},% + idempn = {{idem}{id\adddot}},% + idempp = {{idem}{id\adddot}},% + ibidem = {{ibidem}{ibid\adddot}},% + opcit = {{op\adddotspace cit\adddot}{o\adddot cit\adddot}},% + loccit = {{loc\adddotspace cit\adddot}{loc\adddot cit\adddot}},% + confer = {{cf\adddot}{cf\adddot}},% + sequens = {{hurr\adddot}{hurr\adddot}},% + sequentes = {{hurrk\adddot}{hurrk\adddot}},% + passim = {{passim}{passim}},% + see = {{ikus}{ik\adddot}},% + seealso = {{ikus ere}{ik\adddotspace ere}},% + backrefpage = {{ikus orria}{ik\adddotspace orr\adddot}},% + backrefpages = {{ikus orriak}{ik\adddotspace orrk\adddot}},% + january = {{urtarrila}{urt\adddot}},% + february = {{otsaila}{ots\adddot}},% + march = {{martxoa}{mar\adddot}},% + april = {{apirila}{ap\adddot}},% + may = {{maiatza}{mai\adddot}},% + june = {{ekaina}{ek\adddot}},% + july = {{uztaila}{uz\adddot}},% + august = {{abuztua}{abu\adddot}},% + september = {{iraila}{ir\adddot}},% + october = {{urria}{urr\adddot}},% + november = {{azaroa}{az\adddot}},% + december = {{abendua}{abe\adddot}},% + langamerican = {{ingleles amerikarra}{ingeles amerikarra}},% + langbrazilian = {{portugesa}{portugesa}},% + langbulgarian = {{bulgariera}{bulgariera}},% + langcatalan = {{katalana}{katalana}},% + langcroatian = {{kroaziera}{kroaziera}},% + langczech = {{txekiera}{txekiera}},% + langdanish = {{daniera}{daniera}},% + langdutch = {{nederlandera}{nederlandera}},% + langenglish = {{ingelesa}{ingelesa}},% + langestonian = {{estoniera}{estoniera}},% + langfinnish = {{finlandiera}{finlandiera}},% + langfrench = {{frantsesa}{frantsesa}},% + langgalician = {{galiziera}{galiziera}},% + langgerman = {{alemana}{alemana}},% + langgreek = {{greziera}{greziera}},% + langhungarian = {{hungariera}{hungariera}},% + langitalian = {{italiera}{italiera}},% + langjapanese = {{japoniera}{japoniera}},% + langlatin = {{latina}{latina}},% + langlatvian = {{lituaniera}{lituaniera}},% + langnorwegian = {{norvegiera}{norvegiera}},% + langpolish = {{poloniera}{poloniera}},% + langportuguese = {{portugesa}{portugesa}},% + langrussian = {{errusiera}{errusiera}},% + langslovak = {{eslovakiera}{eslovakiera}},% + langslovene = {{esloveniera}{esloveniera}},% + langspanish = {{gaztelera}{gaztelera}},% + langswedish = {{suediera}{suediera}},% + langukrainian = {{ukrainera}{ukrainera}},% + fromamerican = {{ingeles amerikarretik}{ingeles amerikarretik}},% + frombrazilian = {{portugesetik}{portugesetik}},% + frombulgarian = {{bulgarieratik}{bulgarieratik}},% + fromcatalan = {{katalanetik}{katalanetik}},% + fromcroatian = {{kroazieratik}{kroazieratik}},% + fromczech = {{txekieratik}{txekieratik}},% + fromdanish = {{danieratik}{danieratik}},% + fromdutch = {{nederlanderatik}{nederlanderatik}},% + fromenglish = {{ingelesetik}{ingelesetik}},% + fromestonian = {{estonieratik}{estonieratik}},% + fromfinnish = {{finlandieratik}{finlandieratik}},% + fromfrench = {{frantsesetik}{frantsesetik}},% + fromgalician = {{galizieratik}{galizieratik}},% + fromgerman = {{alemanetik}{alemanetik}},% + fromgreek = {{grezieratik}{grezieratik}},% + fromhungarian = {{hungarieratik}{hungarieratik}},% + fromitalian = {{italieratik}{italieratik}},% + fromjapanese = {{japonieratik}{japonieratik}},% + fromlatin = {{latinetik}{latinetik}},% + fromlatvian = {{lituanieratik}{lituanieratik}},% + fromnorwegian = {{norvegieratik}{norvegieratik}},% + frompolish = {{polonieratik}{polonieratik}},% + fromportuguese = {{portugesetik}{portugesetik}},% + fromrussian = {{errusieratik}{errusieratik}},% + fromslovak = {{eslovakieratik}{eslovakieratik}},% + fromslovene = {{eslovenieratik}{eslovenieratik}},% + fromspanish = {{gazteleratik}{gazteleratik}},% + fromswedish = {{suedieratik}{suedieratik}},% + fromukrainian = {{ukraineratik}{ukraineratik}},% + countryde = {{Alemania}{DE}},% + countryeu = {{Europar Batasuna}{EU}},% + countryep = {{Europar Batasuna}{EP}},% + countryfr = {{Frantzia}{FR}},% + countryuk = {{Britainia Handia}{GB}},% + countryus = {{Ameriketako Estatu Batuak}{US}},% + patent = {{patentea}{pat\adddot}},% + patentde = {{patente alemana}{pat\adddotspace alemana}},% + patenteu = {{patente europarra}{pat\adddotspace europarra}},% + patentfr = {{patente frantsesa}{pat\adddotspace frantsesa}},% + patentuk = {{patente britainiarra}{pat\adddotspace britainiarra}},% + patentus = {{patente estatubatuarra}{pat\adddotspace estatubatuarra}},% + patreq = {{patente eskakizuna}{pat\adddotspace esk\adddot}},% + patreqde = {{patente alemanaaren eskakizuna}{pat\adddotspace alem\adddotspace esk\adddot}},% + patreqeu = {{patente europarraren eskakizuna}{pat\adddotspace europ\adddotspace esk\adddot}},% + patreqfr = {{patente frantsesaren eskakizuna}{pat\adddotspace frants\adddotspace esk\adddot}},% + patrequk = {{patente britainiarraren eskakizuna}{pat\adddotspace brit\adddotspace esk\adddot}},% + patrequs = {{patente estatubatuarraren eskakizuna}{pat\adddotspace estat\adddotspace esk\adddot}},% + file = {{fitxategia}{fitxategia}},% + library = {{biblioteka}{bibl\adddot}},% + abstract = {{laburpena}{laburpena}},% + annotation = {{oharra}{oh\adddot}},% + commonera = {{oraingo aroa}{o\adddotspace a\adddot}},% + beforecommonera = {{oraingo aroaren aurretik}{o\adddotspace a\adddotspace a\adddot}},% + annodomini = {{Kristo ondoren}{K\adddotspace o\adddot}},% + beforechrist = {{Kristo aurretik}{K\adddotspace a\adddot}},% + circa = {{circa}{ca\adddot}},% + spring = {{udaberria}{udab\adddot}},% + summer = {{uda}{uda}},% + autumn = {{udazkena}{udaz\adddot}},% + winter = {{negua}{neg\adddot}},% + am = {{a\adddotspace m\adddot}{a\adddot m\adddot}},% + pm = {{p\adddotspace m\adddot}{p\adddot m\adddot}},% +} + +\endinput diff --git a/macros/latex/contrib/biblatex/latex/lbx/catalan.lbx b/macros/latex/contrib/biblatex/latex/lbx/catalan.lbx index 4f1878ac4d..abf7f8522c 100644 --- a/macros/latex/contrib/biblatex/latex/lbx/catalan.lbx +++ b/macros/latex/contrib/biblatex/latex/lbx/catalan.lbx @@ -274,90 +274,90 @@ organizers = {{organitzadors}{org\adddot}}, byorganizer = {{organitzat per}{org\adddotspace per}}, byauthor = {{per}{per}}, - byeditor = {{edici\'o a cura \smartof}{ed\adddotspace\smartof}}, - bycompiler = {{compilaci\'o a cura \smartof}{comp\adddotspace\smartof}}, - byredactor = {{redacci\'o a cura \smartof}{red\adddotspace\smartof}}, - byreviser = {{revisi\'o a cura \smartof}{rev\adddotspace\smartof}}, - byreviewer = {{ressenya a cura \smartof}{ress\adddotspace\smartof}}, + byeditor = {{edici\'o a cura\smartof}{ed\adddot\smartof}}, + bycompiler = {{compilaci\'o a cura\smartof}{comp\adddot\smartof}}, + byredactor = {{redacci\'o a cura\smartof}{red\adddot\smartof}}, + byreviser = {{revisi\'o a cura\smartof}{rev\adddot\smartof}}, + byreviewer = {{ressenya a cura\smartof}{ress\adddot\smartof}}, byfounder = {{fundat per}{fund\adddotspace per}}, bycontinuator = {{continuat per}{cont\adddotspace per}}, - bycollaborator = {{amb la co\l.laboraci\'o \smartof}{amb la co\l.l\adddotspace\smartof}}, - bytranslator = {{traducci\'o \lbx@fromlang\ a cura \smartof}{trad\adddotspace\lbx@fromlang\ \smartof}}, - bycommentator = {{comentari a cura \smartof}{com\adddotspace\smartof}}, - byannotator = {{notes a cura \smartof}{n\adddotspace\smartof}}, - withcommentator = {{amb un comentari a cura \smartof}{amb un com\adddotspace\smartof}}, - withannotator = {{amb notes a cura \smartof}{amb n\adddotspace\smartof}}, - withintroduction = {{amb una introducci\'o a cura \smartof}{amb una intr\adddotspace\smartof}}, - withforeword = {{amb un pr\`oleg a cura \smartof}{amb un pr\`ol\adddotspace\smartof}}, - withafterword = {{amb un ep\'{\i}leg a cura \smartof}{amb un ep\adddotspace\smartof}}, - byeditortr = {{edici\'o i traducci\'o \lbx@fromlang\ a cura \smartof}% - {ed\adddotspace i trad\adddotspace\lbx@fromlang\ \smartof}}, - byeditorco = {{edici\'o i comentari a cura \smartof}% - {ed\adddotspace i com\adddotspace\smartof}}, - byeditoran = {{edici\'o i notes a cura \smartof}% - {ed\adddotspace i n\adddotspace\smartof}}, - byeditorin = {{edici\'o i introducci\'o a cura \smartof}% - {ed\adddotspace i intr\adddotspace\smartof}}, - byeditorfo = {{edici\'o i pr\`oleg a cura \smartof}% - {ed\adddotspace i pr\`ol\adddotspace\smartof}}, - byeditoraf = {{edici\'o i ep\'{\i}leg a cura \smartof}% - {ed\adddotspace i ep\adddotspace\smartof}}, - byeditortrco = {{edici\'o, traducci\'o \lbx@fromlang\ i comentari a cura \smartof}% - {ed.,\addabbrvspace trad\adddotspace\lbx@fromlang\ i com\adddotspace\smartof}}, - byeditortran = {{edici\'o, traducci\'o \lbx@fromlang\ i notes a cura \smartof}% - {ed.,\addabbrvspace trad\adddotspace\lbx@fromlang\ i n\adddotspace\smartof}}, - byeditortrin = {{edici\'o, traducci\'o \lbx@fromlang\ i introducci\'o a cura \smartof}% - {ed.,\addabbrvspace trad\adddotspace\lbx@fromlang\ i intr\adddotspace\smartof}}, - byeditortrfo = {{edici\'o, traducci\'o \lbx@fromlang\ i pr\`oleg a cura \smartof}% - {ed.,\addabbrvspace trad\adddotspace\lbx@fromlang\ i pr\`ol\adddotspace\smartof}}, - byeditortraf = {{edici\'o, traducci\'o \lbx@fromlang\ i ep\'{\i}leg a cura \smartof}% - {ed.,\addabbrvspace trad\adddotspace\lbx@fromlang\ i ep\adddotspace\smartof}}, - byeditorcoin = {{edici\'o, comentari i introducci\'o a cura \smartof} - {ed.,\addabbrvspace com\adddotspace i intr\adddotspace\smartof}}, - byeditorcofo = {{edici\'o, comentari i pr\`oleg a cura \smartof} - {ed.,\addabbrvspace com\adddotspace i pr\`ol\adddotspace\smartof}}, - byeditorcoaf = {{edici\'o, comentari i ep\'{\i}leg a cura \smartof}% - {ed.,\addabbrvspace com\adddotspace i ep\adddotspace\smartof}}, - byeditoranin = {{edici\'o, notes i introducci\'o a cura \smartof}% - {ed.,\addabbrvspace n\adddotspace i intr\adddotspace\smartof}}, - byeditoranfo = {{edici\'o, notes i pr\`oleg a cura \smartof}% - {ed.,\addabbrvspace n\adddotspace i pr\`ol\adddotspace\smartof}}, - byeditoranaf = {{edici\'o, notes i ep\'{\i}leg a cura \smartof}% - {ed.,\addabbrvspace n\adddotspace i ep\adddotspace\smartof}}, - byeditortrcoin = {{edici\'o, traducci\'o \lbx@fromlang, comentari i introducci\'o a cura \smartof}% - {ed.,\addabbrvspace trad\adddotspace \lbx@fromlang, com\adddotspace i intr\adddotspace\smartof}}, - byeditortrcofo = {{edici\'o, traducci\'o \lbx@fromlang, comentari i pr\`oleg a cura \smartof}% - {ed.,\addabbrvspace trad\adddotspace \lbx@fromlang, com\adddotspace i pr\`ol\adddotspace\smartof}}, - byeditortrcoaf = {{edici\'o, traducci\'o \lbx@fromlang, comentari i ep\'{\i}leg a cura \smartof}% - {ed.,\addabbrvspace trad\adddot\ \lbx@fromlang, com\adddot\ i ep\adddot\ \smartof}}, - byeditortranin = {{edici\'o, traducci\'o \lbx@fromlang, notes i introducci\'o a cura \smartof}% - {ed.,\addabbrvspace trad\adddot\ \lbx@fromlang, n\adddot\ i intr\adddot\ \smartof}}, - byeditortranfo = {{edici\'o, traducci\'o \lbx@fromlang, notes i pr\`oleg a cura \smartof}% - {ed.,\addabbrvspace trad\adddot\ \lbx@fromlang, n\adddot\ i pr\`ol\adddot\ \smartof}}, - byeditortranaf = {{edici\'o, traducci\'o \lbx@fromlang, notes i ep\'{\i}leg a cura \smartof}% - {ed.,\addabbrvspace trad\adddot\ \lbx@fromlang, n\adddot\ i ep\adddot\ \smartof}}, - bytranslatorco = {{traducci\'o \lbx@fromlang\ i comentari a cura \smartof}% - {trad\adddot\ \lbx@fromlang\ i com\adddot\ \smartof}}, - bytranslatoran = {{traducci\'o \lbx@fromlang\ i notes a cura \smartof}% - {trad\adddot\ \lbx@fromlang\ i n\adddot\ \smartof}}, - bytranslatorin = {{traducci\'o \lbx@fromlang\ i introducci\'o a cura \smartof}% - {trad\adddot\ \lbx@fromlang\ i intr\adddot\ \smartof}}, - bytranslatorfo = {{traducci\'o \lbx@fromlang\ i pr\`oleg a cura \smartof}% - {trad\adddot\ \lbx@fromlang\ i pr\`ol\adddot\ \smartof}}, - bytranslatoraf = {{traducci\'o \lbx@fromlang\ i ep\'{\i}leg a cura \smartof}% - {trad\adddot\ \lbx@fromlang\ i ep\adddot\ \smartof}}, - bytranslatorcoin = {{traducci\'o \lbx@fromlang, comentari i introducci\'o a cura \smartof}% - {trad\adddot\ \lbx@fromlang, com\adddot\ i intr\adddot\ \smartof}}, - bytranslatorcofo = {{traducci\'o \lbx@fromlang, comentari i pr\`oleg a cura \smartof}% - {trad\adddot\ \lbx@fromlang, com\adddot\ i pr\`ol\adddot\ \smartof}}, - bytranslatorcoaf = {{traducci\'o \lbx@fromlang, comentari i ep\'{\i}leg a cura \smartof}% - {trad\adddot\ \lbx@fromlang, com\adddot\ i ep\adddot\ \smartof}}, - bytranslatoranin = {{traducci\'o \lbx@fromlang, notes i introducci\'o a cura \smartof}% - {trad\adddot\ \lbx@fromlang, n\adddot\ i intr\adddot\ \smartof}}, - bytranslatoranfo = {{traducci\'o \lbx@fromlang, notes i pr\`oleg a cura \smartof}% - {trad\adddot\ \lbx@fromlang, n\adddot\ i pr\`ol\adddot\ \smartof}}, - bytranslatoranaf = {{traducci\'o \lbx@fromlang, notes i ep\'{\i}leg a cura \smartof}% - {trad\adddot\ \lbx@fromlang, n\adddot\ i ep\adddot\ \smartof}}, + bycollaborator = {{amb la co\l.laboraci\'o\smartof}{amb la co\l.l\adddot\smartof}}, + bytranslator = {{traducci\'o \lbx@fromlang\ a cura\smartof}{trad\adddotspace\lbx@fromlang\smartof}}, + bycommentator = {{comentari a cura\smartof}{com\adddot\smartof}}, + byannotator = {{notes a cura\smartof}{n\adddot\smartof}}, + withcommentator = {{amb un comentari a cura\smartof}{amb un com\adddot\smartof}}, + withannotator = {{amb notes a cura\smartof}{amb n\adddot\smartof}}, + withintroduction = {{amb una introducci\'o a cura\smartof}{amb una intr\adddot\smartof}}, + withforeword = {{amb un pr\`oleg a cura\smartof}{amb un pr\`ol\adddot\smartof}}, + withafterword = {{amb un ep\'{\i}leg a cura\smartof}{amb un ep\adddot\smartof}}, + byeditortr = {{edici\'o i traducci\'o \lbx@fromlang\ a cura\smartof}% + {ed\adddotspace i trad\adddotspace\lbx@fromlang\smartof}}, + byeditorco = {{edici\'o i comentari a cura\smartof}% + {ed\adddotspace i com\adddot\smartof}}, + byeditoran = {{edici\'o i notes a cura\smartof}% + {ed\adddotspace i n\adddot\smartof}}, + byeditorin = {{edici\'o i introducci\'o a cura\smartof}% + {ed\adddotspace i intr\adddot\smartof}}, + byeditorfo = {{edici\'o i pr\`oleg a cura\smartof}% + {ed\adddotspace i pr\`ol\adddot\smartof}}, + byeditoraf = {{edici\'o i ep\'{\i}leg a cura\smartof}% + {ed\adddotspace i ep\adddot\smartof}}, + byeditortrco = {{edici\'o, traducci\'o \lbx@fromlang\ i comentari a cura\smartof}% + {ed.,\addabbrvspace trad\adddotspace\lbx@fromlang\ i com\adddot\smartof}}, + byeditortran = {{edici\'o, traducci\'o \lbx@fromlang\ i notes a cura\smartof}% + {ed.,\addabbrvspace trad\adddotspace\lbx@fromlang\ i n\adddot\smartof}}, + byeditortrin = {{edici\'o, traducci\'o \lbx@fromlang\ i introducci\'o a cura\smartof}% + {ed.,\addabbrvspace trad\adddotspace\lbx@fromlang\ i intr\adddot\smartof}}, + byeditortrfo = {{edici\'o, traducci\'o \lbx@fromlang\ i pr\`oleg a cura\smartof}% + {ed.,\addabbrvspace trad\adddotspace\lbx@fromlang\ i pr\`ol\adddot\smartof}}, + byeditortraf = {{edici\'o, traducci\'o \lbx@fromlang\ i ep\'{\i}leg a cura\smartof}% + {ed.,\addabbrvspace trad\adddotspace\lbx@fromlang\ i ep\adddot\smartof}}, + byeditorcoin = {{edici\'o, comentari i introducci\'o a cura\smartof} + {ed.,\addabbrvspace com\adddotspace i intr\adddot\smartof}}, + byeditorcofo = {{edici\'o, comentari i pr\`oleg a cura\smartof} + {ed.,\addabbrvspace com\adddotspace i pr\`ol\adddot\smartof}}, + byeditorcoaf = {{edici\'o, comentari i ep\'{\i}leg a cura\smartof}% + {ed.,\addabbrvspace com\adddotspace i ep\adddot\smartof}}, + byeditoranin = {{edici\'o, notes i introducci\'o a cura\smartof}% + {ed.,\addabbrvspace n\adddotspace i intr\adddot\smartof}}, + byeditoranfo = {{edici\'o, notes i pr\`oleg a cura\smartof}% + {ed.,\addabbrvspace n\adddotspace i pr\`ol\adddot\smartof}}, + byeditoranaf = {{edici\'o, notes i ep\'{\i}leg a cura\smartof}% + {ed.,\addabbrvspace n\adddotspace i ep\adddot\smartof}}, + byeditortrcoin = {{edici\'o, traducci\'o \lbx@fromlang, comentari i introducci\'o a cura\smartof}% + {ed.,\addabbrvspace trad\adddotspace \lbx@fromlang, com\adddotspace i intr\adddot\smartof}}, + byeditortrcofo = {{edici\'o, traducci\'o \lbx@fromlang, comentari i pr\`oleg a cura\smartof}% + {ed.,\addabbrvspace trad\adddotspace \lbx@fromlang, com\adddotspace i pr\`ol\adddot\smartof}}, + byeditortrcoaf = {{edici\'o, traducci\'o \lbx@fromlang, comentari i ep\'{\i}leg a cura\smartof}% + {ed.,\addabbrvspace trad\adddot\ \lbx@fromlang, com\adddot\ i ep\adddot\smartof}}, + byeditortranin = {{edici\'o, traducci\'o \lbx@fromlang, notes i introducci\'o a cura\smartof}% + {ed.,\addabbrvspace trad\adddot\ \lbx@fromlang, n\adddot\ i intr\adddot\smartof}}, + byeditortranfo = {{edici\'o, traducci\'o \lbx@fromlang, notes i pr\`oleg a cura\smartof}% + {ed.,\addabbrvspace trad\adddot\ \lbx@fromlang, n\adddot\ i pr\`ol\adddot\smartof}}, + byeditortranaf = {{edici\'o, traducci\'o \lbx@fromlang, notes i ep\'{\i}leg a cura\smartof}% + {ed.,\addabbrvspace trad\adddot\ \lbx@fromlang, n\adddot\ i ep\adddot\smartof}}, + bytranslatorco = {{traducci\'o \lbx@fromlang\ i comentari a cura\smartof}% + {trad\adddot\ \lbx@fromlang\ i com\adddot\smartof}}, + bytranslatoran = {{traducci\'o \lbx@fromlang\ i notes a cura\smartof}% + {trad\adddot\ \lbx@fromlang\ i n\adddot\smartof}}, + bytranslatorin = {{traducci\'o \lbx@fromlang\ i introducci\'o a cura\smartof}% + {trad\adddot\ \lbx@fromlang\ i intr\adddot\smartof}}, + bytranslatorfo = {{traducci\'o \lbx@fromlang\ i pr\`oleg a cura\smartof}% + {trad\adddot\ \lbx@fromlang\ i pr\`ol\adddot\smartof}}, + bytranslatoraf = {{traducci\'o \lbx@fromlang\ i ep\'{\i}leg a cura\smartof}% + {trad\adddot\ \lbx@fromlang\ i ep\adddot\smartof}}, + bytranslatorcoin = {{traducci\'o \lbx@fromlang, comentari i introducci\'o a cura\smartof}% + {trad\adddot\ \lbx@fromlang, com\adddot\ i intr\adddot\smartof}}, + bytranslatorcofo = {{traducci\'o \lbx@fromlang, comentari i pr\`oleg a cura\smartof}% + {trad\adddot\ \lbx@fromlang, com\adddot\ i pr\`ol\adddot\smartof}}, + bytranslatorcoaf = {{traducci\'o \lbx@fromlang, comentari i ep\'{\i}leg a cura\smartof}% + {trad\adddot\ \lbx@fromlang, com\adddot\ i ep\adddot\smartof}}, + bytranslatoranin = {{traducci\'o \lbx@fromlang, notes i introducci\'o a cura\smartof}% + {trad\adddot\ \lbx@fromlang, n\adddot\ i intr\adddot\smartof}}, + bytranslatoranfo = {{traducci\'o \lbx@fromlang, notes i pr\`oleg a cura\smartof}% + {trad\adddot\ \lbx@fromlang, n\adddot\ i pr\`ol\adddot\smartof}}, + bytranslatoranaf = {{traducci\'o \lbx@fromlang, notes i ep\'{\i}leg a cura\smartof}% + {trad\adddot\ \lbx@fromlang, n\adddot\ i ep\adddot\smartof}}, and = {{i}{i}}, andothers = {{et al\adddot}{et al\adddot}}, andmore = {{i m\'es}{i m\'es}}, @@ -373,11 +373,11 @@ oldseries = {{s\`erie antiga}{s\`erie ant\adddot}}, edition = {{edici\'o}{ed\adddot}}, reprint = {{reimpressi\'o}{reimpr\adddot}}, - reprintof = {{reimpressi\'o \smartof}{reimpr\adddotspace\smartof}}, + reprintof = {{reimpressi\'o\smartof}{reimpr\adddot\smartof}}, reprintas = {{reimpr\`es com}{reimpr\adddotspace com}}, - reprintfrom = {{reimpr\`es \smartof}{reimpr\adddotspace\smartof}}, - reviewof = {{ressenya \smartof}{ress\adddotspace\smartof}}, - translationof = {{traducci\'o \smartof}{trad\adddotspace\smartof}}, + reprintfrom = {{reimpr\`es\smartof}{reimpr\adddot\smartof}}, + reviewof = {{ressenya\smartof}{ress\adddot\smartof}}, + translationof = {{traducci\'o\smartof}{trad\adddot\smartof}}, translationas = {{tradu\"{\i}t com}{trad\adddotspace com}}, translationfrom = {{tradu\"{\i}t del}{trad\adddotspace del}}, % Unsure of 'del' origpubas = {{publicat origin\`ariament com}{pub\adddotspace orig\adddotspace com}}, diff --git a/macros/latex/contrib/biblatex/latex/lbx/english.lbx b/macros/latex/contrib/biblatex/latex/lbx/english.lbx index 1ade8c7f81..d13bd0fd42 100644 --- a/macros/latex/contrib/biblatex/latex/lbx/english.lbx +++ b/macros/latex/contrib/biblatex/latex/lbx/english.lbx @@ -470,6 +470,7 @@ canadian,australian,newzealand,USenglish,UKenglish} november = {{November}{Nov\adddot}}, december = {{December}{Dec\adddot}}, langamerican = {{American}{American}}, + langbasque = {{Basque}{Basque}}, langbrazilian = {{Brazilian}{Brazilian}}, langbulgarian = {{Bulgarian}{Bulgarian}}, langcatalan = {{Catalan}{Catalan}}, @@ -502,6 +503,7 @@ canadian,australian,newzealand,USenglish,UKenglish} langturkish = {{Turkish}{Turkish}}, langukrainian = {{Ukrainian}{Ukrainian}}, fromamerican = {{from the American}{from the American}}, + frombasque = {{from the Basque}{from the Basque}}, frombrazilian = {{from the Brazilian}{from the Brazilian}}, frombulgarian = {{from the Bulgarian}{from the Bulgarian}}, fromcatalan = {{from the Catalan}{from the Catalan}}, diff --git a/macros/latex/contrib/biblatex/latex/lbx/french.lbx b/macros/latex/contrib/biblatex/latex/lbx/french.lbx index d2e441b66e..8b3f7f194b 100644 --- a/macros/latex/contrib/biblatex/latex/lbx/french.lbx +++ b/macros/latex/contrib/biblatex/latex/lbx/french.lbx @@ -276,23 +276,23 @@ organizers = {{organisateurs}{org\adddot}},% byorganizer = {{organis\'e par}{org\adddotspace par}},% byauthor = {{par}{par}}, - byeditor = {{sous la direction \smartof}{sous la dir\adddotspace\smartof}}, + byeditor = {{sous la direction\smartof}{sous la dir\adddot\smartof}}, bycompiler = {{compil\'e par}{comp\adddotspace par}}, byredactor = {{r\'edig\'e par}{r\'ed\adddotspace par}}, byreviser = {{r\'evis\'e par}{r\'ev\adddotspace par}}, byreviewer = {{examin\'e par}{ex\adddotspace par}}, byfounder = {{d\'ecouvert par}{d\'ecouv\adddotspace par}}, bycontinuator = {{continu\'e par}{cont\adddotspace par}}, - bycollaborator = {{avec la collaboration \smartof}{avec la - coll\adddotspace\smartof}}, + bycollaborator = {{avec la collaboration\smartof}{avec la + coll\adddot\smartof}}, bytranslator = {{traduit \lbx@lfromlang\ par}{trad\adddotspace \lbx@sfromlang\ par}}, bycommentator = {{comment\'e par}{comm\adddotspace par}}, byannotator = {{annot\'e par}{annot\adddotspace par}}, - withcommentator = {{avec des commentaires \smartof}{avec des comment\adddotspace\smartof}}, - withannotator = {{avec des annotations \smartof}{avec des annot\adddotspace\smartof}}, - withintroduction = {{avec une introduction \smartof}{avec une introd\adddotspace\smartof}}, - withforeword = {{avec une pr\'eface \smartof}{avec une pr\'ef\adddotspace\smartof}}, - withafterword = {{avec une postface \smartof}{avec une postf\adddotspace\smartof}}, + withcommentator = {{avec des commentaires\smartof}{avec des comment\adddot\smartof}}, + withannotator = {{avec des annotations\smartof}{avec des annot\adddot\smartof}}, + withintroduction = {{avec une introduction\smartof}{avec une introd\adddot\smartof}}, + withforeword = {{avec une pr\'eface\smartof}{avec une pr\'ef\adddot\smartof}}, + withafterword = {{avec une postface\smartof}{avec une postf\adddot\smartof}}, byeditortr = {{\'edition \'etablie et traduite \lbx@lfromlang\ par}% {\'ed\adddotspace \'etablie et trad\adddotspace \lbx@sfromlang\ par}}, byeditorco = {{\'edition \'etablie et comment\'ee par}% @@ -378,7 +378,7 @@ reprint = {{r\'eimpression}{r\'eimpr\adddot}}, reprintof = {{r\'eimpression de}{r\'eimpr\adddotspace de}}, reprintas = {{r\'eimpression sous le titre}{r\'eimpr\adddotspace sous le titre}}, - reprintfrom = {{r\'eimpression \`a partir \smartof}{r\'eimpr\adddotspace \`a part\adddotspace\smartof}}, + reprintfrom = {{r\'eimpression \`a partir\smartof}{r\'eimpr\adddotspace \`a part\adddot\smartof}}, translationof = {{traduction de}{trad\adddotspace de}}, translationas = {{traduit sous le titre}{trad\adddotspace sous le titre}}, translationfrom = {{traduit de}{trad\adddotspace de}}, diff --git a/macros/latex/contrib/biblatex/latex/lbx/german.lbx b/macros/latex/contrib/biblatex/latex/lbx/german.lbx index 3aba7d6739..d09bee3a76 100644 --- a/macros/latex/contrib/biblatex/latex/lbx/german.lbx +++ b/macros/latex/contrib/biblatex/latex/lbx/german.lbx @@ -455,6 +455,7 @@ november = {{November}{Nov\adddot}}, december = {{Dezember}{Dez\adddot}}, langamerican = {{Amerikanisch}{Amerikanisch}}, + langbasque = {{Baskisch}{Baskisch}}, langbrazilian = {{Brasilianisch}{Brasilianisch}}, langbulgarian = {{Bulgarisch}{Bulgarisch}}, langcatalan = {{Katalanisch}{Katalanisch}}, @@ -487,6 +488,7 @@ langturkish = {{T\"urkisch}{T\"urkisch}}, langukrainian = {{Ukrainisch}{Ukrainisch}}, fromamerican = {{aus dem Amerikanischen}{aus dem Amerikanischen}}, + frombasque = {{aus dem Baskischen}{aus dem Baskischen}}, frombrazilian = {{aus dem Brasilianischen}{aus dem Brasilianischen}}, frombulgarian = {{aus dem Bulgarischen}{aus dem Bulgarischen}}, fromcatalan = {{aus dem Katalanischen}{aus dem Katalanischen}}, diff --git a/macros/luatex/generic/lualibs/NEWS b/macros/luatex/generic/lualibs/NEWS index af54318e6e..4c80d06987 100644 --- a/macros/luatex/generic/lualibs/NEWS +++ b/macros/luatex/generic/lualibs/NEWS @@ -1,4 +1,7 @@ History of the lualibs package +2020/12/30 v2.73/ + * sync with Context current as of 2020/12/30. + 2020/08/31 v2.72/ * sync with Context current as of 2020/08/31. diff --git a/macros/luatex/generic/lualibs/README.md b/macros/luatex/generic/lualibs/README.md index 351930040c..cf330df159 100644 --- a/macros/luatex/generic/lualibs/README.md +++ b/macros/luatex/generic/lualibs/README.md @@ -1,10 +1,10 @@ # The Lualibs Package -VERSION: 2.72 +VERSION: 2.73 -DATE: 2020-08-31 +DATE: 2020-12-30 -FONTLOADERDATE: 2020-08-31 +FONTLOADERDATE: 2020-12-30 Lualibs is a collection of Lua modules useful for general programming. diff --git a/macros/luatex/generic/lualibs/lualibs-basic-merged.lua b/macros/luatex/generic/lualibs/lualibs-basic-merged.lua index 147cc33fa9..92e571a7cc 100644 --- a/macros/luatex/generic/lualibs/lualibs-basic-merged.lua +++ b/macros/luatex/generic/lualibs/lualibs-basic-merged.lua @@ -1,6 +1,6 @@ -- merged file : lualibs-basic-merged.lua -- parent file : lualibs-basic.lua --- merge date : Mon Aug 31 23:16:26 2020 +-- merge date : Wed Dec 30 17:55:54 2020 do -- begin closure to overcome local limits and interference @@ -358,7 +358,10 @@ methods["already loaded"]=function(name) return package.loaded[name] end methods["preload table"]=function(name) - return builtin["preload table"](name) + local f=builtin["preload table"] + if f then + return f(name) + end end methods["qualified path"]=function(name) return loadedbyname(addsuffix(lualibfile(name),"lua"),name) @@ -370,15 +373,24 @@ methods["lib extra list"]=function(name) return loadedbypath(addsuffix(lualibfile(name),os.libsuffix),name,getextralibpaths(),true,"lib") end methods["path specification"]=function(name) - getluapaths() - return builtin["path specification"](name) + local f=builtin["path specification"] + if f then + getluapaths() + return f(name) + end end methods["cpath specification"]=function(name) - getlibpaths() - return builtin["cpath specification"](name) + local f=builtin["cpath specification"] + if f then + getlibpaths() + return f(name) + end end methods["all in one fallback"]=function(name) - return builtin["all in one fallback"](name) + local f=builtin["all in one fallback"] + if f then + return f(name) + end end methods["not loaded"]=function(name) if helpers.trace then @@ -3358,6 +3370,8 @@ elseif name=="macosx" then platform="osx-intel" elseif find(architecture,"x86_64",1,true) then platform="osx-64" + elseif find(architecture,"arm64",1,true) then + platform="osx-64" else platform="osx-ppc" end @@ -4684,6 +4698,7 @@ if not modules then modules={} end modules ['l-unicode']={ license="see context related readme files" } utf=utf or {} +-- unicode=nil if not string.utfcharacters then local gmatch=string.gmatch function string.characters(str) diff --git a/macros/luatex/generic/lualibs/lualibs-extended-merged.lua b/macros/luatex/generic/lualibs/lualibs-extended-merged.lua index 89d384ac8a..cac8889ca3 100644 --- a/macros/luatex/generic/lualibs/lualibs-extended-merged.lua +++ b/macros/luatex/generic/lualibs/lualibs-extended-merged.lua @@ -1,6 +1,6 @@ -- merged file : lualibs-extended-merged.lua -- parent file : lualibs-extended.lua --- merge date : Mon Aug 31 23:16:16 2020 +-- merge date : Wed Dec 30 17:55:44 2020 do -- begin closure to overcome local limits and interference @@ -2700,8 +2700,6 @@ local dimenfactors=allocate { ["pc"]=(1/12)/65536, ["dd"]=(1157/1238)/65536, ["cc"]=(1157/14856)/65536, - ["nd"]=(20320/21681)/65536, - ["nc"]=(5080/65043)/65536 } local f_none=formatters["%s%s"] local f_true=formatters["%0.5F%s"] @@ -2733,8 +2731,6 @@ function number.tobasepoints (n,fmt) return numbertodimen(n,"bp",fmt) end function number.topicas (n,fmt) return numbertodimen(n "pc",fmt) end function number.todidots (n,fmt) return numbertodimen(n,"dd",fmt) end function number.tociceros (n,fmt) return numbertodimen(n,"cc",fmt) end -function number.tonewdidots (n,fmt) return numbertodimen(n,"nd",fmt) end -function number.tonewciceros (n,fmt) return numbertodimen(n,"nc",fmt) end local amount=(S("+-")^0*R("09")^0*P(".")^0*R("09")^0)+Cc("0") local unit=R("az")^1+P("%") local dimenpair=amount/tonumber*(unit^1/dimenfactors+Cc(1)) diff --git a/macros/luatex/generic/lualibs/lualibs-os.lua b/macros/luatex/generic/lualibs/lualibs-os.lua index 1e01350947..73841074c4 100644 --- a/macros/luatex/generic/lualibs/lualibs-os.lua +++ b/macros/luatex/generic/lualibs/lualibs-os.lua @@ -358,6 +358,8 @@ elseif name == "macosx" then platform = "osx-intel" elseif find(architecture,"x86_64",1,true) then platform = "osx-64" + elseif find(architecture,"arm64",1,true) then + platform = "osx-64" else platform = "osx-ppc" end diff --git a/macros/luatex/generic/lualibs/lualibs-package.lua b/macros/luatex/generic/lualibs/lualibs-package.lua index 94607d4368..a35ec3e2a9 100644 --- a/macros/luatex/generic/lualibs/lualibs-package.lua +++ b/macros/luatex/generic/lualibs/lualibs-package.lua @@ -300,7 +300,10 @@ methods["already loaded"] = function(name) end methods["preload table"] = function(name) - return builtin["preload table"](name) + local f = builtin["preload table"] + if f then + return f(name) + end end methods["qualified path"]=function(name) @@ -316,17 +319,26 @@ methods["lib extra list"] = function(name) end methods["path specification"] = function(name) - getluapaths() -- triggers list building and tracing - return builtin["path specification"](name) + local f = builtin["path specification"] + if f then + getluapaths() -- triggers list building and tracing + return f(name) + end end methods["cpath specification"] = function(name) - getlibpaths() -- triggers list building and tracing - return builtin["cpath specification"](name) + local f = builtin["cpath specification"] + if f then + getlibpaths() -- triggers list building and tracing + return f(name) + end end methods["all in one fallback"] = function(name) - return builtin["all in one fallback"](name) + local f = builtin["all in one fallback"] + if f then + return f(name) + end end methods["not loaded"] = function(name) diff --git a/macros/luatex/generic/lualibs/lualibs-util-dim.lua b/macros/luatex/generic/lualibs/lualibs-util-dim.lua index 76b5fd20bb..bb9eca9668 100644 --- a/macros/luatex/generic/lualibs/lualibs-util-dim.lua +++ b/macros/luatex/generic/lualibs/lualibs-util-dim.lua @@ -44,8 +44,8 @@ local dimenfactors = allocate { ["pc"] = ( 1/ 12)/65536, ["dd"] = ( 1157/ 1238)/65536, ["cc"] = ( 1157/14856)/65536, - ["nd"] = (20320/21681)/65536, - ["nc"] = ( 5080/65043)/65536 + -- ["nd"] = (20320/21681)/65536, + -- ["nc"] = ( 5080/65043)/65536 } -- print(table.serialize(dimenfactors)) @@ -61,9 +61,9 @@ local dimenfactors = allocate { -- ["ex"]=6.103515625e-005, -- ["in"]=2.1113586636917117e-007, -- ["mm"]=5.3628510057769473e-008, --- ["nc"]=1.1917446679504327e-006, --- ["nd"]=1.4300936015405194e-005, --- ["pc"]=1.2715657552083333e-006, +-- --["nc"]=1.1917446679504327e-006, +-- --["nd"]=1.4300936015405194e-005, +-- --["pc"]=1.2715657552083333e-006, -- ["pt"]=1.52587890625e-005, -- ["sp"]=1, -- } @@ -79,8 +79,8 @@ local dimenfactors = allocate { -- ["ex"]=0.00006103515625, -- ["in"]=0.00000021113587, -- ["mm"]=0.00000005362851, --- ["nc"]=0.00000119174467, --- ["nd"]=0.00001430093602, +-- --["nc"]=0.00000119174467, +-- --["nd"]=0.00001430093602, -- ["pc"]=0.00000127156576, -- ["pt"]=0.00001525878906, -- ["sp"]=1, @@ -128,8 +128,8 @@ function number.tobasepoints (n,fmt) return numbertodimen(n,"bp",fmt) end function number.topicas (n,fmt) return numbertodimen(n "pc",fmt) end function number.todidots (n,fmt) return numbertodimen(n,"dd",fmt) end function number.tociceros (n,fmt) return numbertodimen(n,"cc",fmt) end -function number.tonewdidots (n,fmt) return numbertodimen(n,"nd",fmt) end -function number.tonewciceros (n,fmt) return numbertodimen(n,"nc",fmt) end +-------- number.tonewdidots (n,fmt) return numbertodimen(n,"nd",fmt) end +-------- number.tonewciceros (n,fmt) return numbertodimen(n,"nc",fmt) end --[[ldx-- <p>More interesting it to implement a (sort of) dimen datatype, one diff --git a/macros/luatex/generic/lualibs/lualibs.dtx b/macros/luatex/generic/lualibs/lualibs.dtx index c98c752765..7246e8541e 100644 --- a/macros/luatex/generic/lualibs/lualibs.dtx +++ b/macros/luatex/generic/lualibs/lualibs.dtx @@ -37,7 +37,7 @@ \input docstrip.tex \Msg{************************************************************************} \Msg{* Installation} -\Msg{* Package: lualibs 2020-08-31 v2.72 Lua additional functions.} +\Msg{* Package: lualibs 2020-12-30 v2.73 Lua additional functions.} \Msg{************************************************************************} \keepsilent @@ -107,7 +107,7 @@ and lualibs-extended.lua. %<*driver> \NeedsTeXFormat{LaTeX2e} \ProvidesFile{lualibs.drv} - [2020/08/31 v2.72 Lua Libraries.] + [2020/12/30 v2.73 Lua Libraries.] \documentclass{ltxdoc} \usepackage{fancyvrb,xspace} \usepackage[x11names]{xcolor} @@ -208,7 +208,7 @@ and lualibs-extended.lua. % \GetFileInfo{lualibs.drv} % % \title{The \identifier{lualibs} package} -% \date{2020/08/31 v2.72} +% \date{2020/12/30 v2.73} % \author{Élie Roux · \email{elie.roux@telecom-bretagne.eu}\\ % Philipp Gesang · \email{phg@phi-gamma.net}\\ % The \LaTeX3 Project · \email{https://github.com/latex3/lualibs/}\\ @@ -429,8 +429,8 @@ lualibs = lualibs or { } lualibs.module_info = { name = "lualibs", - version = "2.72", --TAGVERSION - date = "2020-08-31", --TAGDATE + version = "2.73", --TAGVERSION + date = "2020-12-30", --TAGDATE description = "ConTeXt Lua standard libraries.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", @@ -583,8 +583,8 @@ local loadmodule = lualibs.loadmodule local lualibs_basic_module = { name = "lualibs-basic", - version = "2.72", --TAGVERSION - date = "2020-08-31", --TAGDATE + version = "2.73", --TAGVERSION + date = "2020-12-30", --TAGDATE description = "ConTeXt Lua libraries -- basic collection.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", @@ -665,8 +665,8 @@ lualibs = lualibs or { } local lualibs_extended_module = { name = "lualibs-extended", - version = "2.72", --TAGVERSION - date = "2020-08-31", --TAGDATE + version = "2.73", --TAGVERSION + date = "2020-12-30", --TAGDATE description = "ConTeXt Lua libraries -- extended collection.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", diff --git a/macros/luatex/generic/lualibs/lualibs.pdf b/macros/luatex/generic/lualibs/lualibs.pdf Binary files differindex 031fc8158e..10274b447b 100644 --- a/macros/luatex/generic/lualibs/lualibs.pdf +++ b/macros/luatex/generic/lualibs/lualibs.pdf diff --git a/macros/luatex/generic/luaotfload/NEWS b/macros/luatex/generic/luaotfload/NEWS index 658c5d420e..b0a7f124c1 100644 --- a/macros/luatex/generic/luaotfload/NEWS +++ b/macros/luatex/generic/luaotfload/NEWS @@ -1,6 +1,32 @@ Change History -------------- -2020-08-31 luaotfload v3.15 +2020-12-31 luaotfload v3.16 + + * The fontloader has been synced with the context code from 2020-12-30 + * The entry point is called luaotfload.lua instead of + luaotfload-main.lua (but the old name is still provided for + compatibility). + * pre/post_shaping_filter callbacks has been added. + * The number of lua-files and submodules shown in the log-file + has been reduced. But it is extended again by setting the environment + variable LUAOTFLOAD_TRACE_SUBMODULES=1. + * The HarfBuzz based shaper will in some situations drop hyphenation + points. This happens less frequently now since the new version uses + first/second discretionaries (the mechanism described in the LuaTeX manual, + section 5.6 for the of-f-ice example) to support a limited amount of + nesting. + * When the node shaper is used, experimental support for + OpenType variable fonts has been added. To use them, set the font + feature axis to a comma separated list of axis names and values. + (E.g. axis={weight=600}) The supported axis names and value + range depend on the font. + * The font features upper and lower can be used to map + the text of a font to upper or lowercase before displaying it. Currently + this implements the untailored Unicode case mapping algorithm, but it is + planned to add tailoring later. + * A number of small bugfixes. + +2020-09-02 luaotfload v3.15 * The font database is updated more reliably if fonts get deleted. * In multiple error cases, error messages are shown instead of silently generating bad output. diff --git a/macros/luatex/generic/luaotfload/README.md b/macros/luatex/generic/luaotfload/README.md index 626e1c9b8b..f19c4c5563 100644 --- a/macros/luatex/generic/luaotfload/README.md +++ b/macros/luatex/generic/luaotfload/README.md @@ -1,8 +1,8 @@ # The Luaotfload Package -VERSION: 3.15 +VERSION: 3.16 -DATE: 2020-09-02 +DATE: 2020-12-31 ## Description diff --git a/macros/luatex/generic/luaotfload/filegraph.pdf b/macros/luatex/generic/luaotfload/filegraph.pdf Binary files differindex 5e90db1544..ac40ce55f9 100644 --- a/macros/luatex/generic/luaotfload/filegraph.pdf +++ b/macros/luatex/generic/luaotfload/filegraph.pdf diff --git a/macros/luatex/generic/luaotfload/filegraph.tex b/macros/luatex/generic/luaotfload/filegraph.tex index ee76912b78..1301319880 100644 --- a/macros/luatex/generic/luaotfload/filegraph.tex +++ b/macros/luatex/generic/luaotfload/filegraph.tex @@ -103,7 +103,7 @@ label={[name=mL3,font=\itshape,anchor=south]above:Lualibs -- Lua Libraries from %>>>>>>>>>>>>>>>> }; % m4 -\node[left=2cm of m3,fill=gray!20,draw=gray!30,thick,basic,inner sep=6mm] (m4) {luaotfload-main.lua}; +\node[left=2cm of m3,fill=gray!20,draw=gray!30,thick,basic,inner sep=6mm] (m4) {luaotfload.lua}; % m5 \node[fill=gray!20,draw=gray!30,dashed,basic,inner sep=6mm,anchor=south west] at (m3.south -| m2.west)(m5){% diff --git a/macros/luatex/generic/luaotfload/fontloader-2020-08-31.lua b/macros/luatex/generic/luaotfload/fontloader-2020-12-30.lua index 01e1f8300c..835eca6695 100644 --- a/macros/luatex/generic/luaotfload/fontloader-2020-08-31.lua +++ b/macros/luatex/generic/luaotfload/fontloader-2020-12-30.lua @@ -1,6 +1,6 @@ --[[info----------------------------------------------------------------------- Luaotfload fontloader package - build 2020-08-31 23:33:48 + build 2020-12-30 17:29:34 ------------------------------------------------------------------------------- © 2020 PRAGMA ADE / ConTeXt Development Team @@ -63,7 +63,7 @@ --info]]----------------------------------------------------------------------- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “data-con” de6ae0997b0e70a23bcc9afff5d8b072] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “data-con” 23a0f5386d46a1c157ae82a373e35fa0] --- if not modules then modules={} end modules ['data-con']={ version=1.100, @@ -184,10 +184,10 @@ function containers.cleanname(name) return (gsub(lower(name),"[^%w\128-\255]+","-")) end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “data-con”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “data-con”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “basics-nod” e296bfb03d5654a596b43612348c4191] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “basics-nod” 4b5c3c63e19df1b3f37fae7f87c25bda] --- if not modules then modules={} end modules ['luatex-fonts-nod']={ version=1.001, @@ -265,6 +265,7 @@ nuts.getkern=direct.getkern nuts.getlist=direct.getlist nuts.getnext=direct.getnext nuts.getoffsets=direct.getoffsets +nuts.getoptions=direct.getoptions or function() return 0 end nuts.getprev=direct.getprev nuts.getsubtype=direct.getsubtype nuts.getwidth=direct.getwidth @@ -348,6 +349,15 @@ local traverse_id=nuts.traverse_id local copy_node=nuts.copy_node local glyph_code=nodes.nodecodes.glyph local ligature_code=nodes.glyphcodes.ligature +do + local p=nodecodes.localpar or nodecodes.local_par + if p then + nodecodes.par=p + nodecodes[p]="par" + nodecodes.localpar=p + nodecodes.local_par=p + end +end do local get_components=node.direct.getcomponents local set_components=node.direct.setcomponents @@ -400,11 +410,14 @@ do end return 0 end + local function flush_components() + end nuts.set_components=set_components nuts.get_components=get_components nuts.copy_only_glyphs=copy_only_glyphs nuts.copy_no_components=copy_no_components nuts.count_components=count_components + nuts.flush_components=flush_components end nuts.uses_font=direct.uses_font do @@ -437,10 +450,10 @@ do end end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “basics-nod”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “basics-nod”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “basics-chr” 58b7ef0c486e06090b362971b9f85e27] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “basics-chr” 64fafe4eaf55d64aead6513c1e74a024] --- characters=characters or {} @@ -4050,10 +4063,10 @@ characters.indicgroups={ }, } -end --- [luaotfload, fontloader-2020-08-31.lua scope for “basics-chr”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “basics-chr”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ini” 4dee96e1e1474d324dd126bd5d375df8] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-ini” 5343de60613adb24cdd7a8d2ee1d153c] --- if not modules then modules={} end modules ['font-ini']={ version=1.001, @@ -4094,10 +4107,10 @@ if node and not tex.getfontoffamily then tex.getfontoffamily=node.family_font end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ini”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-ini”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-mis” bc9eb43c27f63ce9d0fff67e104fe1c6] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-mis” 17e967c9ec4d001deefd43ddf25e98f7] --- if not modules then modules={} end modules ['luatex-font-mis']={ version=1.001, @@ -4129,10 +4142,10 @@ function font.each() return table.sortedhash(fonts.hashes.identifiers) end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-mis”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-mis”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-con” cbccccc4a5016196d62332a365aa8b72] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-con” a3eb543fa5946fa1faf0e1e50d5b3b91] --- if not modules then modules={} end modules ['font-con']={ version=1.001, @@ -5497,10 +5510,10 @@ function constructors.addcoreunicodes(unicodes) return unicodes end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-con”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-con”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-enc” 3e71a54297e8f85a1ac438bb0f20dd79] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-enc” 5ff4ca50493d7c4ecea0e15c203099f0] --- if not modules then modules={} end modules ['luatex-font-enc']={ version=1.001, @@ -5569,10 +5582,10 @@ function encodings.load(filename) return containers.write(encodings.cache,name,data) end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-enc”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-enc”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-cid” 4d87988efa86020a14708ee03c23415f] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-cid” 22b0367742fb253deef84ef7ccf5e8de] --- if not modules then modules={} end modules ['font-cid']={ version=1.001, @@ -5723,10 +5736,10 @@ function cid.getmap(specification) return found end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-cid”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-cid”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-map” a03653ea3c5f042b457d54ed678d6df3] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-map” c4a39db5ad822b348aa61bca5f4a599a] --- if not modules then modules={} end modules ['font-map']={ version=1.001, @@ -6134,10 +6147,10 @@ function mappings.addtounicode(data,filename,checklookups,forceligatures) end end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-map”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-map”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-vfc” 04fa0ffad5c51198c7c19462949f54ed] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-vfc” a81c29eda98cd62cbebdb6c93544b50d] --- if not modules then modules={} end modules ['font-vfc']={ version=1.001, @@ -6234,10 +6247,10 @@ helpers.commands=utilities.storage.allocate { dummy=dummy, } -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-vfc”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-vfc”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otr” 7a2f7a9e9627b29158e1822ea3c650ab] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-otr” 64dcbbc7107538723990e1119a80a9f8] --- if not modules then modules={} end modules ['font-otr']={ version=1.001, @@ -8081,10 +8094,10 @@ function readers.extend(fontdata) end end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otr”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-otr”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-oti” dbae7722baae24d917a17176553825cf] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-oti” 309a75f9c14b77d87e94eba827dc4e71] --- if not modules then modules={} end modules ['font-oti']={ version=1.001, @@ -8227,10 +8240,10 @@ function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages) end end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-oti”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-oti”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ott” 1249b7018dba80e080fc478a38aa6756] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-ott” 673ed11e1d159997f535bfec5fa73808] --- if not modules then modules={} end modules ["font-ott"]={ version=1.001, @@ -9346,10 +9359,10 @@ function otffeatures.normalize(features,wrap) end end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ott”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-ott”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-cff” aa9038651d9fedd2b76cacd1f69fd742] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-cff” 802a10ad12ac32329f540881f940e3f2] --- if not modules then modules={} end modules ['font-cff']={ version=1.001, @@ -11544,10 +11557,10 @@ function readers.cffcheck(filename) end end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-cff”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-cff”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ttf” 807599f6d56c775d53cf6f358d741f34] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-ttf” ffffc827e1bcddc33a2b615340ecff7f] --- if not modules then modules={} end modules ['font-ttf']={ version=1.001, @@ -11672,7 +11685,7 @@ local function mergecomposites(glyphs,shapes) shape.components=nil return contours,points end - for index=0,#glyphs-1 do + for index=0,#glyphs do local shape=shapes[index] if shape then local components=shape.components @@ -12102,7 +12115,7 @@ local function repackpoints(glyphs,shapes) local result={} local xpoints={} local ypoints={} - for index=0,#glyphs-1 do + for index=0,#glyphs do local shape=shapes[index] if shape then local r=0 @@ -12718,10 +12731,10 @@ function readers.gvar(f,fontdata,specification,glyphdata,shapedata) end end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ttf”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-ttf”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-dsp” e1c275ded4770aa6cbe0b1afbdfd0dde] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-dsp” 18c85a4857f45c31a3555bf1faac434a] --- if not modules then modules={} end modules ['font-dsp']={ version=1.001, @@ -13366,7 +13379,7 @@ local function readfirst(f,offset) end return { readushort(f) } end -function readarray(f,offset) +local function readarray(f,offset) if offset then setposition(f,offset) end @@ -15999,10 +16012,10 @@ function readers.mvar(f,fontdata,specification) end end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-dsp”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-dsp”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-oup” 1700a2dac4f8b105c187d4e5b84cecdf] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-oup” 6f46aa00ae1c20c43f8ffaf329dc8695] --- if not modules then modules={} end modules ['font-oup']={ version=1.001, @@ -18643,10 +18656,10 @@ function readers.expand(data) expandlookups(sublookups) end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-oup”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-oup”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otl” f111f9ac18d24049fadeb8883e4e8da5] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-otl” 6c4b718ceacfb0cbeb2c03c423f97aec] --- if not modules then modules={} end modules ['font-otl']={ version=1.001, @@ -18674,7 +18687,7 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_d local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf -otf.version=3.111 +otf.version=3.112 otf.cache=containers.define("fonts","otl",otf.version,true) otf.svgcache=containers.define("fonts","svg",otf.version,true) otf.pngcache=containers.define("fonts","png",otf.version,true) @@ -19039,7 +19052,6 @@ local function copytotfm(data,cache_id) parameters.units=units parameters.vheight=metadata.defaultvheight properties.space=spacer - properties.encodingbytes=2 properties.format=data.format or formats.otf properties.filename=filename properties.fontname=fontname @@ -19047,6 +19059,9 @@ local function copytotfm(data,cache_id) properties.psname=psname properties.name=filename or fullname properties.subfont=subfont +if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then + properties.encodingbytes=2 +end properties.private=properties.private or data.private or privateoffset return { characters=characters, @@ -19350,10 +19365,10 @@ otf.coverup={ end } -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otl”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-otl”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-oto” 24238a7c600d090a8ee88312321dd9b3] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-oto” 2b1d6bc63b2ebf8f2655a15e1cda6541] --- if not modules then modules={} end modules ['font-oto']={ version=1.001, @@ -19811,10 +19826,10 @@ registerotffeature { } otf.basemodeinitializer=featuresinitializer -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-oto”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-oto”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otj” a37a1007b8a92c9e7d24064180c2a772] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-otj” 8de59cb9b043e5f73c6b9f7cc8f6978e] --- if not modules then modules={} end modules ['font-otj']={ version=1.001, @@ -21309,10 +21324,10 @@ function injections.handler(head,where) end end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otj”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-otj”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ota” f31232af3a694ae3d50380a5a92f88d3] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-ota” ad1d5de06400f88829509e1f3ff2b473] --- if not modules then modules={} end modules ['font-ota']={ version=1.001, @@ -21806,10 +21821,10 @@ directives.register("otf.analyze.useunicodemarks",function(v) analyzers.useunicodemarks=v end) -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ota”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-ota”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ots” c507280651dcbc549f1d8a5622da8667] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-ots” 91c79619c386e4a96954f3115f398b94] --- if not modules then modules={} end modules ['font-ots']={ version=1.001, @@ -21893,6 +21908,7 @@ local copy_only_glyphs=nuts.copy_only_glyphs local count_components=nuts.count_components local set_components=nuts.set_components local get_components=nuts.get_components +local flush_components=nuts.flush_components local ischar=nuts.ischar local usesfont=nuts.uses_font local insert_node_after=nuts.insert_after @@ -21915,7 +21931,7 @@ local glue_code=nodecodes.glue local disc_code=nodecodes.disc local math_code=nodecodes.math local dir_code=nodecodes.dir -local localpar_code=nodecodes.localpar +local par_code=nodecodes.par local lefttoright_code=nodes.dirvalues.lefttoright local righttoleft_code=nodes.dirvalues.righttoleft local discretionarydisc_code=disccodes.discretionary @@ -22097,11 +22113,23 @@ local function markstoligature(head,start,stop,char) setsubtype(base,ligatureglyph_code) set_components(base,start) setlink(prev,base,next) + flush_components(start) return head,base end end +local no_left_ligature_code=1 +local no_right_ligature_code=2 +local no_left_kern_code=4 +local no_right_kern_code=8 +local has_glyph_option=node.direct.has_glyph_option or function(n,c) + if c==no_left_ligature_code or c==no_right_ligature_code then + return getattr(n,a_noligature)==1 + else + return false + end +end local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfound,hasmarks) - if getattr(start,a_noligature)==1 then + if has_glyph_option(start,no_right_ligature_code) then return head,start end if start==stop and getchar(start)==char then @@ -22165,6 +22193,7 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou break end end + flush_components(components) else local discprev,discnext=getboth(discfound) if discprev and discnext then @@ -22451,78 +22480,86 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip return head,start,false,false end function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection) - local startchar=getchar(start) - local format=step.format - if format=="single" or type(kerns)=="table" then - local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %s xy (%p,%p) and wh (%p,%p)",pref(dataset,sequence),gref(startchar),format,dx,dy,w,h) - end + if has_glyph_option(start,no_right_kern_code) then + return head,start,false else - local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %s %p",pref(dataset,sequence),gref(startchar),format,k) + local startchar=getchar(start) + local format=step.format + if format=="single" or type(kerns)=="table" then + local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %s xy (%p,%p) and wh (%p,%p)",pref(dataset,sequence),gref(startchar),format,dx,dy,w,h) + end + else + local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %s %p",pref(dataset,sequence),gref(startchar),format,k) + end end + return head,start,true end - return head,start,true end function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection) - local snext=getnext(start) - if not snext then + if has_glyph_option(start,no_right_kern_code) then return head,start,false else - local prev=start - while snext do - local nextchar=ischar(snext,currentfont) - if nextchar then - if skiphash and skiphash[nextchar] then - prev=snext - snext=getnext(snext) - else - local krn=kerns[nextchar] - if not krn then - break - end - local format=step.format - if format=="pair" then - local a=krn[1] - local b=krn[2] - if a==true then - elseif a then - local x,y,w,h=setposition(1,start,factor,rlmode,a,injection) - if trace_kerns then - local startchar=getchar(start) - logprocess("%s: shifting first of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") - end + local snext=getnext(start) + if not snext then + return head,start,false + else + local prev=start + while snext do + local nextchar=ischar(snext,currentfont) + if nextchar then + if skiphash and skiphash[nextchar] then + prev=snext + snext=getnext(snext) + else + local krn=kerns[nextchar] + if not krn then + break end - if b==true then - start=snext - elseif b then - local x,y,w,h=setposition(2,snext,factor,rlmode,b,injection) + local format=step.format + if format=="pair" then + local a=krn[1] + local b=krn[2] + if a==true then + elseif a then + local x,y,w,h=setposition(1,start,factor,rlmode,a,injection) + if trace_kerns then + local startchar=getchar(start) + logprocess("%s: shifting first of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + end + end + if b==true then + start=snext + elseif b then + local x,y,w,h=setposition(2,snext,factor,rlmode,b,injection) + if trace_kerns then + local startchar=getchar(start) + logprocess("%s: shifting second of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + end + start=snext + elseif forcepairadvance then + start=snext + end + return head,start,true + elseif krn~=0 then + local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn,injection) if trace_kerns then - local startchar=getchar(start) - logprocess("%s: shifting second of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + logprocess("%s: inserting %s %p between %s and %s as %s",pref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar),injection or "injections") end - start=snext - elseif forcepairadvance then - start=snext - end - return head,start,true - elseif krn~=0 then - local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn,injection) - if trace_kerns then - logprocess("%s: inserting %s %p between %s and %s as %s",pref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar),injection or "injections") + return head,start,true + else + break end - return head,start,true - else - break end + else + break end - else - break end + return head,start,false end - return head,start,false end end function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode,skiphash) @@ -22952,89 +22989,93 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup return head,start,false,0,false end function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) - local mapping=currentlookup.mapping - if mapping==nil then - mapping=getmapping(dataset,sequence,currentlookup) - end - if mapping then - local startchar=getchar(start) - local kerns=mapping[startchar] - if kerns then - local format=currentlookup.format - if format=="single" then - local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns) - if trace_kerns then - logprocess("%s: shifting single %s by %s (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),format,dx,dy,w,h) - end - else - local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %s %p",cref(dataset,sequence),gref(startchar),format,k) + if not has_glyph_option(start,no_right_kern_code) then + local mapping=currentlookup.mapping + if mapping==nil then + mapping=getmapping(dataset,sequence,currentlookup) + end + if mapping then + local startchar=getchar(start) + local kerns=mapping[startchar] + if kerns then + local format=currentlookup.format + if format=="single" then + local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns) + if trace_kerns then + logprocess("%s: shifting single %s by %s (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),format,dx,dy,w,h) + end + else + local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %s %p",cref(dataset,sequence),gref(startchar),format,k) + end end + return head,start,true end - return head,start,true end end return head,start,false end -function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) - local mapping=currentlookup.mapping - if mapping==nil then - mapping=getmapping(dataset,sequence,currentlookup) - end - if mapping then - local snext=getnext(start) - if snext then - local startchar=getchar(start) - local kerns=mapping[startchar] - if kerns then - local prev=start - while snext do - local nextchar=ischar(snext,currentfont) - if not nextchar then - break - end - if skiphash and skiphash[nextchar] then - prev=snext - snext=getnext(snext) - else - local krn=kerns[nextchar] - if not krn then +function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) + if not has_glyph_option(start,no_right_kern_code) then + local mapping=currentlookup.mapping + if mapping==nil then + mapping=getmapping(dataset,sequence,currentlookup) + end + if mapping then + local snext=getnext(start) + if snext then + local startchar=getchar(start) + local kerns=mapping[startchar] + if kerns then + local prev=start + while snext do + local nextchar=ischar(snext,currentfont) + if not nextchar then break end - local format=currentlookup.format - if format=="pair" then - local a=krn[1] - local b=krn[2] - if a==true then - elseif a then - local x,y,w,h=setposition(1,start,factor,rlmode,a,"injections") - if trace_kerns then - local startchar=getchar(start) - logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) - end + if skiphash and skiphash[nextchar] then + prev=snext + snext=getnext(snext) + else + local krn=kerns[nextchar] + if not krn then + break end - if b==true then - start=snext - elseif b then - local x,y,w,h=setposition(2,snext,factor,rlmode,b,"injections") + local format=currentlookup.format + if format=="pair" then + local a=krn[1] + local b=krn[2] + if a==true then + elseif a then + local x,y,w,h=setposition(1,start,factor,rlmode,a,"injections") + if trace_kerns then + local startchar=getchar(start) + logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + end + end + if b==true then + start=snext + elseif b then + local x,y,w,h=setposition(2,snext,factor,rlmode,b,"injections") + if trace_kerns then + local startchar=getchar(start) + logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + end + start=snext + elseif forcepairadvance then + start=snext + end + return head,start,true + elseif krn~=0 then + local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn) if trace_kerns then - local startchar=getchar(start) - logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + logprocess("%s: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar)) end - start=snext - elseif forcepairadvance then - start=snext - end - return head,start,true - elseif krn~=0 then - local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn) - if trace_kerns then - logprocess("%s: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar)) + return head,start,true + else + break end - return head,start,true - else - break end end end @@ -24856,7 +24897,7 @@ do checkstep(head) end local initialrl=0 - if getid(head)==localpar_code and start_of_par(head) then + if getid(head)==par_code and start_of_par(head) then initialrl=pardirstate(head) elseif direction==righttoleft_code then initialrl=-1 @@ -25401,10 +25442,10 @@ registerotffeature { }, } -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ots”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-ots”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-osd” 61f05fcf91add1aa5dac9bc8b235adc9] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-osd” 73c9531c79df5ada320cb20777f7ed49] --- if not modules then modules={} end modules ['font-osd']={ version=1.001, @@ -27837,10 +27878,10 @@ for i=1,nofscripts do methods[scripts_two[i]]=method_two end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-osd”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-osd”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ocl” ab81576f20e2d37bc8707e1dbd3decf2] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-ocl” 797b5c71bf819c5f4fb314a4d646e9a7] --- if not modules then modules={} end modules ['font-ocl']={ version=1.001, @@ -28383,10 +28424,10 @@ if context then } end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-ocl”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-ocl”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otc” 1204a2fdc436e644127c0aa38ab69607] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-otc” 0f12230ea07b5151f75d52726977e91f] --- if not modules then modules={} end modules ['font-otc']={ version=1.001, @@ -29143,10 +29184,10 @@ end otf.enhancers.enhance=enhance otf.enhancers.register("check extra features",enhance) -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-otc”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-otc”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-onr” 7a9ece7bf3e36b5f0adf295a9a2a2989] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-onr” 6d161533f3437435e12a0ad64866df44] --- if not modules then modules={} end modules ['font-onr']={ version=1.001, @@ -29519,10 +29560,10 @@ function readers.getinfo(filename) end end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-onr”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-onr”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-one” 1402ae8e4e96186c848fa2742388fb24] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-one” 53cd565030e919da984b50471cc3be37] --- if not modules then modules={} end modules ['font-one']={ version=1.001, @@ -30021,7 +30062,6 @@ local function copytotfm(data) parameters.descender=abs(metadata.descender or 0) parameters.units=1000 properties.spacer=spacer - properties.encodingbytes=2 properties.format=fonts.formats[filename] or "type1" properties.filename=filename properties.fontname=fontname @@ -30029,6 +30069,9 @@ local function copytotfm(data) properties.psname=fullname properties.name=filename or fullname or fontname properties.private=properties.private or data.private or privateoffset +if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then + properties.encodingbytes=2 +end if next(characters) then return { characters=characters, @@ -30234,10 +30277,10 @@ registerafmenhancer("normalize features",enhance_normalize_features) registerafmenhancer("check extra features",otfenhancers.enhance) registerafmenhancer("fix names",enhance_fix_names) -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-one”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-one”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-afk” 54d554530e75c57c56ee76234724e26d] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-afk” 9da14e0fb22129c053acc599d1312544] --- if not modules then modules={} end modules ['font-afk']={ version=1.001, @@ -30404,10 +30447,10 @@ fonts.handlers.afm.helpdata={ } } -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-afk”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-afk”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-tfm” 3bbba3214fd0b8c6f35ad85592fc2917] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-tfm” f0eb5e2a8068b17ad401bb7efdba1630] --- if not modules then modules={} end modules ['luatex-fonts-tfm']={ version=1.001, @@ -30922,10 +30965,10 @@ registertfmfeature { } } -end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-tfm”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-tfm”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-lua” 55b281fb98f7bd848fc19928f376f647] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-lua” 1fbfdf7b689b2bdfd0e3bb9bf74ce136] --- if not modules then modules={} end modules ['font-lua']={ version=1.001, @@ -30965,10 +31008,10 @@ function readers.lua(specification) return check_lua(specification,fullname) end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-lua”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-lua”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-def” 226b4d26ede7fa7be8e45b7f0d93e781] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-def” b9d908c2338b7dc443ce9d1e9fcb7139] --- if not modules then modules={} end modules ['font-def']={ version=1.001, @@ -31368,10 +31411,10 @@ if not context then callbacks.register('define_font',definers.read,"definition of fonts (tfmdata preparation)") end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-def”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-def”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-shp” c4a8c14513597ce3579d3ad4c580fe51] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-shp” 5ff497c993112d4fef4c148348d964eb] --- if not modules then modules={} end modules ['font-shp']={ version=1.001, @@ -31382,7 +31425,7 @@ if not modules then modules={} end modules ['font-shp']={ } local tonumber,next=tonumber,next local concat=table.concat -local formatters=string.formatters +local formatters,lower=string.formatters,string.lower local otf=fonts.handlers.otf local afm=fonts.handlers.afm local pfb=fonts.handlers.pfb @@ -31575,7 +31618,7 @@ end local function loadstreams(cache,filename,sub,instance) local base=file.basename(filename) local name=file.removesuffix(base) - local kind=file.suffix(filename) + local kind=lower(file.suffix(filename)) local attr=lfs.attributes(filename) local size=attr and attr.size or 0 local time=attr and attr.modification or 0 @@ -31736,10 +31779,10 @@ callback.register("glyph_stream_provider",function(id,index,mode) return "" end) -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-shp”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-shp”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-def” 5ad79120ebc5e60f4d322fb3ee13bffe] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-def” f435e0875f203f343157baeff876ec9c] --- if not modules then modules={} end modules ['luatex-fonts-def']={ version=1.001, @@ -31820,10 +31863,10 @@ function fonts.definers.applypostprocessors(tfmdata) return tfmdata end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-def”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-def”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-ext” 01015ab3758cdc2af29394e6d502a91a] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-ext” 32013cbc5d5d336be8b1d1e5879d86c4] --- if not modules then modules={} end modules ['luatex-fonts-ext']={ version=1.001, @@ -32009,10 +32052,10 @@ registerotffeature { } } -end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-ext”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-ext”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-tex” 77c374b0ef00c2fb12188ec42beb4257] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-imp-tex” ceb087ef6fa2f89aed7179f60ddf8f35] --- if not modules then modules={} end modules ['font-imp-tex']={ version=1.001, @@ -32111,10 +32154,10 @@ registerotffeature { description="arabic digits", } -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-tex”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-imp-tex”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-ligatures” 043daa4fcccf2560868da359d71d3a4a] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-imp-ligatures” 26ffcf089391445f7af59536c8814364] --- if not modules then modules={} end modules ['font-imp-ligatures']={ version=1.001, @@ -32228,10 +32271,10 @@ if context then } end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-ligatures”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-imp-ligatures”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-italics” 058fb834c11c6ac30c280b29e496966e] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-imp-italics” ae563638fa29a4ff3e8e4d1e81fd35ae] --- if not modules then modules={} end modules ['font-imp-italics']={ version=1.001, @@ -32335,10 +32378,10 @@ if context then registerafmfeature(dimensions_specification) end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-italics”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-imp-italics”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-effects” 582f9dd5031e9d67fff389efd16a874f] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “font-imp-effects” a2dde5e071fcb3fc7b90f2bcd5aa4f22] --- if not modules then modules={} end modules ['font-imp-effects']={ version=1.001, @@ -32522,56 +32565,74 @@ local rules={ "FractionRuleThickness", "UnderbarRuleThickness", } -local function setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze) - if delta~=0 then - for i=1,#rules do - local name=rules[i] - local value=mathparameters[name] - if value then - mathparameters[name]=(squeeze or 1)*(value+dx) +local setmathparameters +local setmathcharacters +if CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 then + setmathparameters=function(tfmdata,characters,mathparameters,dx,dy,squeeze,multiplier) + if delta~=0 then + for i=1,#rules do + local name=rules[i] + local value=mathparameters[name] + if value then + mathparameters[name]=(squeeze or 1)*(value+dy) + end end end end -end -local function setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta) - local function wdpatch(char) - if wsnap~=0 then - char.width=char.width+wdelta/2 - end + setmathcharacters=function() end - local function htpatch(char) - if hsnap~=0 then - local height=char.height - if height then - char.height=char.height+2*dy +else + setmathparameters=function(tfmdata,characters,mathparameters,dx,dy,squeeze,multiplier) + if delta~=0 then + for i=1,#rules do + local name=rules[i] + local value=mathparameters[name] + if value then + mathparameters[name]=(squeeze or 1)*(value+dy) + end end end end - local character=characters[0x221A] - if character and character.next then - local char=character - local next=character.next - wdpatch(char) - htpatch(char) - while next do - char=characters[next] + setmathcharacters=function(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta) + local function wdpatch(char) + if wsnap~=0 then + char.width=char.width+wdelta/2 + end + end + local function htpatch(char) + if hsnap~=0 then + local height=char.height + if height then + char.height=char.height+2*dy + end + end + end + local character=characters[0x221A] + if character and character.next then + local char=character + local next=character.next wdpatch(char) htpatch(char) - next=char.next - end - if char then - local v=char.vert_variants - if v then - local top=v[#v] - if top then - local char=characters[top.glyph] - htpatch(char) + while next do + char=characters[next] + wdpatch(char) + htpatch(char) + next=char.next + end + if char then + local v=char.vert_variants + if v then + local top=v[#v] + if top then + local char=characters[top.glyph] + htpatch(char) + end end end end end end -local shiftmode=CONTEXTLMTXMODE>0 +local shiftmode=CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 local function manipulateeffect(tfmdata) local effect=tfmdata.properties.effect if effect then @@ -32643,7 +32704,7 @@ local function manipulateeffect(tfmdata) end end if mathparameters then - setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze) + setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze,multiplier) setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta) end parameters.factor=factor @@ -32703,10 +32764,10 @@ local specification={ registerotffeature(specification) registerafmfeature(specification) -end --- [luaotfload, fontloader-2020-08-31.lua scope for “font-imp-effects”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “font-imp-effects”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-lig” b9dbe77ce747d4c35bb2a20ffbe5aa51] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-lig” fbd251eea3810a43a8d5542319361d68] --- fonts.handlers.otf.addfeature { @@ -34775,10 +34836,10 @@ fonts.handlers.otf.addfeature { ["type"]="ligature", } -end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-lig”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-lig”] --- -do --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-gbn” d25472d54c4841db43a745764a63533e] --- +do --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-gbn” 10ecdf01e7c926e5128ad8a9dff4d677] --- if not modules then modules={} end modules ['luatex-fonts-gbn']={ version=1.001, @@ -35043,7 +35104,7 @@ function nodes.simple_font_handler(head,groupcode,size,packtype,direction) return head end -end --- [luaotfload, fontloader-2020-08-31.lua scope for “fonts-gbn”] --- +end --- [luaotfload, fontloader-2020-12-30.lua scope for “fonts-gbn”] --- --- vim:ft=lua:sw=2:ts=8:et:tw=79 diff --git a/macros/luatex/generic/luaotfload/fontloader-basics-nod.lua b/macros/luatex/generic/luaotfload/fontloader-basics-nod.lua index 67abf707b1..25f5473a5a 100644 --- a/macros/luatex/generic/luaotfload/fontloader-basics-nod.lua +++ b/macros/luatex/generic/luaotfload/fontloader-basics-nod.lua @@ -107,6 +107,7 @@ nuts.getkern = direct.getkern nuts.getlist = direct.getlist nuts.getnext = direct.getnext nuts.getoffsets = direct.getoffsets +nuts.getoptions = direct.getoptions or function() return 0 end nuts.getprev = direct.getprev nuts.getsubtype = direct.getsubtype nuts.getwidth = direct.getwidth @@ -206,6 +207,19 @@ local copy_node = nuts.copy_node local glyph_code = nodes.nodecodes.glyph local ligature_code = nodes.glyphcodes.ligature +do -- this is consistent with the rest of context, not that we need it + + local p = nodecodes.localpar or nodecodes.local_par + + if p then + nodecodes.par = p + nodecodes[p] = "par" + nodecodes.localpar = p -- for old times sake + nodecodes.local_par = p -- for old times sake + end + +end + do local get_components = node.direct.getcomponents @@ -264,11 +278,16 @@ do return 0 end + local function flush_components() + -- this is a no-op in mkiv / generic + end + nuts.set_components = set_components nuts.get_components = get_components nuts.copy_only_glyphs = copy_only_glyphs nuts.copy_no_components = copy_no_components nuts.count_components = count_components + nuts.flush_components = flush_components end diff --git a/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua b/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua index 0cff896e8d..91ee83b19b 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-dsp.lua @@ -823,7 +823,7 @@ end -- quite often 0, 1, 2 -function readarray(f,offset) +local function readarray(f,offset) if offset then setposition(f,offset) end diff --git a/macros/luatex/generic/luaotfload/fontloader-font-imp-effects.lua b/macros/luatex/generic/luaotfload/fontloader-font-imp-effects.lua index bd6cce8795..43ce82b71a 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-imp-effects.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-imp-effects.lua @@ -215,62 +215,88 @@ local rules = { -- end -- end -local function setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze) - if delta ~= 0 then - for i=1,#rules do - local name = rules[i] - local value = mathparameters[name] - if value then - mathparameters[name] = (squeeze or 1) * (value + dx) +-- radicals are not yet ok + +local setmathparameters +local setmathcharacters + +if CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 then + + setmathparameters = function(tfmdata,characters,mathparameters,dx,dy,squeeze,multiplier) + if delta ~= 0 then + for i=1,#rules do + local name = rules[i] + local value = mathparameters[name] + if value then + mathparameters[name] = (squeeze or 1) * (value + dy) + end end end end -end -local function setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta) + setmathcharacters = function() + end - local function wdpatch(char) - if wsnap ~= 0 then - char.width = char.width + wdelta/2 +else + + setmathparameters = function(tfmdata,characters,mathparameters,dx,dy,squeeze,multiplier) + if delta ~= 0 then + for i=1,#rules do + local name = rules[i] + local value = mathparameters[name] + if value then + mathparameters[name] = (squeeze or 1) * (value + dy) + end + end end end - local function htpatch(char) - if hsnap ~= 0 then - local height = char.height - if height then - char.height = char.height + 2 * dy + setmathcharacters = function(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta) + + -- still not the perfect rule + + local function wdpatch(char) + if wsnap ~= 0 then + char.width = char.width + wdelta/2 + end + end + + local function htpatch(char) + if hsnap ~= 0 then + local height = char.height + if height then + char.height = char.height + 2 * dy + end end end - end - local character = characters[0x221A] + local character = characters[0x221A] - if character and character.next then --- print("base char",0x221A,table.sequenced(character)) - local char = character - local next = character.next - wdpatch(char) - htpatch(char) - while next do - char = characters[next] + if character and character.next then + local char = character + local next = character.next wdpatch(char) htpatch(char) --- print("next char",next,table.sequenced(char)) - next = char.next - end - if char then - local v = char.vert_variants - if v then - local top = v[#v] - if top then - local char = characters[top.glyph] --- print("top char",top.glyph,table.sequenced(char)) - htpatch(char) + while next do + char = characters[next] + wdpatch(char) + htpatch(char) + next = char.next + end + if char then + local v = char.vert_variants + if v then + local top = v[#v] + if top then + local char = characters[top.glyph] + htpatch(char) + end end end end + end + end -- local show_effect = { "lua", function(f,c) @@ -278,10 +304,7 @@ end -- inspect(fonts.hashes.characters[f][c]) -- end } --- local show_effect = { "lua", "print('!')" } - ------ shiftmode = false -- test in mkiv and lmtx -local shiftmode = CONTEXTLMTXMODE > 0 +local shiftmode = CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 local function manipulateeffect(tfmdata) local effect = tfmdata.properties.effect @@ -358,7 +381,7 @@ local function manipulateeffect(tfmdata) end end if mathparameters then - setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze) + setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze,multiplier) setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta) end parameters.factor = factor diff --git a/macros/luatex/generic/luaotfload/fontloader-font-one.lua b/macros/luatex/generic/luaotfload/fontloader-font-one.lua index a76c929859..5ef6e47497 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-one.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-one.lua @@ -592,15 +592,18 @@ local function copytotfm(data) parameters.descender = abs(metadata.descender or 0) parameters.units = 1000 -- - properties.spacer = spacer + properties.spacer = spacer + properties.format = fonts.formats[filename] or "type1" + properties.filename = filename + properties.fontname = fontname + properties.fullname = fullname + properties.psname = fullname + properties.name = filename or fullname or fontname + properties.private = properties.private or data.private or privateoffset + -- +if not CONTEXTLMTXMODE or CONTEXTLMTXMODE == 0 then properties.encodingbytes = 2 - properties.format = fonts.formats[filename] or "type1" - properties.filename = filename - properties.fontname = fontname - properties.fullname = fullname - properties.psname = fullname - properties.name = filename or fullname or fontname - properties.private = properties.private or data.private or privateoffset +end -- if next(characters) then return { diff --git a/macros/luatex/generic/luaotfload/fontloader-font-otl.lua b/macros/luatex/generic/luaotfload/fontloader-font-otl.lua index aff4cc8c8d..b8e13f1070 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-otl.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-otl.lua @@ -52,7 +52,7 @@ local report_otf = logs.reporter("fonts","otf loading") local fonts = fonts local otf = fonts.handlers.otf -otf.version = 3.111 -- beware: also sync font-mis.lua and in mtx-fonts +otf.version = 3.112 -- beware: also sync font-mis.lua and in mtx-fonts otf.cache = containers.define("fonts", "otl", otf.version, true) otf.svgcache = containers.define("fonts", "svg", otf.version, true) otf.pngcache = containers.define("fonts", "png", otf.version, true) @@ -486,23 +486,26 @@ local function copytotfm(data,cache_id) end end -- - parameters.designsize = (designsize/10)*65536 - parameters.minsize = (minsize /10)*65536 - parameters.maxsize = (maxsize /10)*65536 - parameters.ascender = abs(metadata.ascender or 0) - parameters.descender = abs(metadata.descender or 0) - parameters.units = units - parameters.vheight = metadata.defaultvheight + parameters.designsize = (designsize/10)*65536 + parameters.minsize = (minsize /10)*65536 + parameters.maxsize = (maxsize /10)*65536 + parameters.ascender = abs(metadata.ascender or 0) + parameters.descender = abs(metadata.descender or 0) + parameters.units = units + parameters.vheight = metadata.defaultvheight -- - properties.space = spacer + properties.space = spacer + properties.format = data.format or formats.otf + properties.filename = filename + properties.fontname = fontname + properties.fullname = fullname + properties.psname = psname + properties.name = filename or fullname + properties.subfont = subfont + -- +if not CONTEXTLMTXMODE or CONTEXTLMTXMODE == 0 then properties.encodingbytes = 2 - properties.format = data.format or formats.otf - properties.filename = filename - properties.fontname = fontname - properties.fullname = fullname - properties.psname = psname - properties.name = filename or fullname - properties.subfont = subfont +end -- -- properties.name = specification.name -- properties.sub = specification.sub diff --git a/macros/luatex/generic/luaotfload/fontloader-font-ots.lua b/macros/luatex/generic/luaotfload/fontloader-font-ots.lua index 490f28de69..1f4806ee25 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-ots.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-ots.lua @@ -13,7 +13,7 @@ with plain <l n='tex'/> it has to be so. This module is part of <l n='context'/> and discussion about improvements and functionality mostly happens on the <l n='context'/> mailing list.</p> -<p>The specification of OpenType is (or at least a decade ago was) kind of vague. +<p>The specification of OpenType is (or at least decades ago was) kind of vague. Apart from a lack of a proper free specifications there's also the problem that Microsoft and Adobe may have their own interpretation of how and in what order to apply features. In general the Microsoft website has more detailed specifications @@ -218,6 +218,7 @@ local copy_only_glyphs = nuts.copy_only_glyphs local count_components = nuts.count_components local set_components = nuts.set_components local get_components = nuts.get_components +local flush_components = nuts.flush_components --------------------------------------------------------------------------------------- @@ -251,7 +252,7 @@ local glue_code = nodecodes.glue local disc_code = nodecodes.disc local math_code = nodecodes.math local dir_code = nodecodes.dir -local localpar_code = nodecodes.localpar +local par_code = nodecodes.par local lefttoright_code = nodes.dirvalues.lefttoright local righttoleft_code = nodes.dirvalues.righttoleft @@ -488,6 +489,7 @@ local function markstoligature(head,start,stop,char) setsubtype(base,ligatureglyph_code) set_components(base,start) setlink(prev,base,next) + flush_components(start) return head, base end end @@ -500,9 +502,25 @@ end -- in the not discfound branch then. We now have skiphash too so we can be more -- selective if needed (todo). +-- we can have more granularity here but for now we only do a simple check + +local no_left_ligature_code = 1 +local no_right_ligature_code = 2 +local no_left_kern_code = 4 +local no_right_kern_code = 8 + +local has_glyph_option = node.direct.has_glyph_option or function(n,c) + if c == no_left_ligature_code or c == no_right_ligature_code then + return getattr(n,a_noligature) == 1 + else + return false + end +end + +-- in lmtx we need to check the components and can be slightly more clever + local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfound,hasmarks) -- brr head - if getattr(start,a_noligature) == 1 then - -- so we can do: e\noligature{ff}e e\noligature{f}fie (we only look at the first) + if has_glyph_option(start,no_right_ligature_code) then return head, start end if start == stop and getchar(start) == char then @@ -572,6 +590,7 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou break end end + flush_components(components) else -- discfound ... forget about marks .. probably no scripts that hyphenate and have marks local discprev, discnext = getboth(discfound) @@ -902,81 +921,89 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip end function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection) - local startchar = getchar(start) - local format = step.format - if format == "single" or type(kerns) == "table" then -- the table check can go - local dx, dy, w, h = setposition(0,start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %s xy (%p,%p) and wh (%p,%p)",pref(dataset,sequence),gref(startchar),format,dx,dy,w,h) - end + if has_glyph_option(start,no_right_kern_code) then + return head, start, false else - local k = (format == "move" and setmove or setkern)(start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %s %p",pref(dataset,sequence),gref(startchar),format,k) + local startchar = getchar(start) + local format = step.format + if format == "single" or type(kerns) == "table" then -- the table check can go + local dx, dy, w, h = setposition(0,start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %s xy (%p,%p) and wh (%p,%p)",pref(dataset,sequence),gref(startchar),format,dx,dy,w,h) + end + else + local k = (format == "move" and setmove or setkern)(start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %s %p",pref(dataset,sequence),gref(startchar),format,k) + end end + return head, start, true end - return head, start, true end function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection) - local snext = getnext(start) - if not snext then + if has_glyph_option(start,no_right_kern_code) then return head, start, false else - local prev = start - while snext do - local nextchar = ischar(snext,currentfont) - if nextchar then - if skiphash and skiphash[nextchar] then -- includes marks too when flag - prev = snext - snext = getnext(snext) - else - local krn = kerns[nextchar] - if not krn then - break - end - local format = step.format - if format == "pair" then - local a = krn[1] - local b = krn[2] - if a == true then - -- zero - elseif a then -- #a > 0 - local x, y, w, h = setposition(1,start,factor,rlmode,a,injection) - if trace_kerns then - local startchar = getchar(start) - logprocess("%s: shifting first of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") - end + local snext = getnext(start) + if not snext then + return head, start, false + else + local prev = start + while snext do + local nextchar = ischar(snext,currentfont) + if nextchar then + if skiphash and skiphash[nextchar] then -- includes marks too when flag + prev = snext + snext = getnext(snext) + else + local krn = kerns[nextchar] + if not krn then + break end - if b == true then - -- zero - start = snext -- cf spec - elseif b then -- #b > 0 - local x, y, w, h = setposition(2,snext,factor,rlmode,b,injection) + local format = step.format + if format == "pair" then + local a = krn[1] + local b = krn[2] + if a == true then + -- zero + elseif a then -- #a > 0 + local x, y, w, h = setposition(1,start,factor,rlmode,a,injection) + if trace_kerns then + local startchar = getchar(start) + logprocess("%s: shifting first of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + end + end + if b == true then + -- zero + start = snext -- cf spec + elseif b then -- #b > 0 + local x, y, w, h = setposition(2,snext,factor,rlmode,b,injection) + if trace_kerns then + local startchar = getchar(start) + logprocess("%s: shifting second of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + end + start = snext -- cf spec + elseif forcepairadvance then + start = snext -- for testing, not cf spec + end + return head, start, true + elseif krn ~= 0 then + local k = (format == "move" and setmove or setkern)(snext,factor,rlmode,krn,injection) if trace_kerns then - local startchar = getchar(start) - logprocess("%s: shifting second of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + logprocess("%s: inserting %s %p between %s and %s as %s",pref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar),injection or "injections") end - start = snext -- cf spec - elseif forcepairadvance then - start = snext -- for testing, not cf spec - end - return head, start, true - elseif krn ~= 0 then - local k = (format == "move" and setmove or setkern)(snext,factor,rlmode,krn,injection) - if trace_kerns then - logprocess("%s: inserting %s %p between %s and %s as %s",pref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar),injection or "injections") + return head, start, true + else -- can't happen + break end - return head, start, true - else -- can't happen - break end + else + break end - else - break end + return head, start, false end - return head, start, false end end @@ -1505,92 +1532,98 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup end function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) - local mapping = currentlookup.mapping - if mapping == nil then - mapping = getmapping(dataset,sequence,currentlookup) - end - if mapping then - local startchar = getchar(start) - local kerns = mapping[startchar] - if kerns then - local format = currentlookup.format - if format == "single" then - local dx, dy, w, h = setposition(0,start,factor,rlmode,kerns) -- currentlookup.flags ? - if trace_kerns then - logprocess("%s: shifting single %s by %s (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),format,dx,dy,w,h) - end - else -- needs checking .. maybe no kerns format for single - local k = (format == "move" and setmove or setkern)(start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %s %p",cref(dataset,sequence),gref(startchar),format,k) + -- we actually should check no_left_kern_code with next + if not has_glyph_option(start,no_right_kern_code) then + local mapping = currentlookup.mapping + if mapping == nil then + mapping = getmapping(dataset,sequence,currentlookup) + end + if mapping then + local startchar = getchar(start) + local kerns = mapping[startchar] + if kerns then + local format = currentlookup.format + if format == "single" then + local dx, dy, w, h = setposition(0,start,factor,rlmode,kerns) -- currentlookup.flags ? + if trace_kerns then + logprocess("%s: shifting single %s by %s (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),format,dx,dy,w,h) + end + else -- needs checking .. maybe no kerns format for single + local k = (format == "move" and setmove or setkern)(start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %s %p",cref(dataset,sequence),gref(startchar),format,k) + end end + return head, start, true end - return head, start, true end end return head, start, false end function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) -- todo: injections ? - local mapping = currentlookup.mapping - if mapping == nil then - mapping = getmapping(dataset,sequence,currentlookup) - end - if mapping then - local snext = getnext(start) - if snext then - local startchar = getchar(start) - local kerns = mapping[startchar] -- always 1 step - if kerns then - local prev = start - while snext do - local nextchar = ischar(snext,currentfont) - if not nextchar then - break - end - if skiphash and skiphash[nextchar] then - prev = snext - snext = getnext(snext) - else - local krn = kerns[nextchar] - if not krn then + -- we actually should check no_left_kern_code with next + if not has_glyph_option(start,no_right_kern_code) then + local mapping = currentlookup.mapping + if mapping == nil then + mapping = getmapping(dataset,sequence,currentlookup) + end + if mapping then + local snext = getnext(start) + if snext then + local startchar = getchar(start) + local kerns = mapping[startchar] -- always 1 step + if kerns then + local prev = start + while snext do + local nextchar = ischar(snext,currentfont) + if not nextchar then break end - local format = currentlookup.format - if format == "pair" then - local a = krn[1] - local b = krn[2] - if a == true then - -- zero - elseif a then - local x, y, w, h = setposition(1,start,factor,rlmode,a,"injections") -- currentlookups flags? - if trace_kerns then - local startchar = getchar(start) - logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) - end + if skiphash and skiphash[nextchar] then + prev = snext + snext = getnext(snext) + else + local krn = kerns[nextchar] + if not krn then + break end - if b == true then - -- zero - start = snext -- cf spec - elseif b then -- #b > 0 - local x, y, w, h = setposition(2,snext,factor,rlmode,b,"injections") + local format = currentlookup.format + if format == "pair" then + local a = krn[1] + local b = krn[2] + if a == true then + -- zero + elseif a then + local x, y, w, h = setposition(1,start,factor,rlmode,a,"injections") -- currentlookups flags? + if trace_kerns then + local startchar = getchar(start) + logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + end + end + if b == true then + -- zero + start = snext -- cf spec + elseif b then -- #b > 0 + local x, y, w, h = setposition(2,snext,factor,rlmode,b,"injections") + if trace_kerns then + local startchar = getchar(start) + logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + end + start = snext -- cf spec + elseif forcepairadvance then + start = snext -- for testing, not cf spec + end + return head, start, true + elseif krn ~= 0 then + local k = (format == "move" and setmove or setkern)(snext,factor,rlmode,krn) if trace_kerns then - local startchar = getchar(start) - logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + logprocess("%s: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar)) end - start = snext -- cf spec - elseif forcepairadvance then - start = snext -- for testing, not cf spec - end - return head, start, true - elseif krn ~= 0 then - local k = (format == "move" and setmove or setkern)(snext,factor,rlmode,krn) - if trace_kerns then - logprocess("%s: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar)) + return head, start, true + else + break end - return head, start, true - else - break end end end @@ -3759,7 +3792,7 @@ do local initialrl = 0 - if getid(head) == localpar_code and start_of_par(head) then + if getid(head) == par_code and start_of_par(head) then initialrl = pardirstate(head) elseif direction == righttoleft_code then initialrl = -1 @@ -3913,7 +3946,7 @@ do elseif id == dir_code then topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode) start = getnext(start) - -- elseif id == localpar_code and start_of_par(start) then + -- elseif id == par_code and start_of_par(start) then -- rlparmode, rlmode = pardirstate(start) -- start = getnext(start) else @@ -3997,7 +4030,7 @@ do elseif id == dir_code then topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode) start = getnext(start) - -- elseif id == localpar_code and start_of_par(start) then + -- elseif id == par_code and start_of_par(start) then -- rlparmode, rlmode = pardirstate(start) -- start = getnext(start) else @@ -4108,7 +4141,7 @@ do elseif id == dir_code then topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode) start = getnext(start) - -- elseif id == localpar_code and start_of_par(start) then + -- elseif id == par_code and start_of_par(start) then -- rlparmode, rlmode = pardirstate(start) -- start = getnext(start) else diff --git a/macros/luatex/generic/luaotfload/fontloader-font-shp.lua b/macros/luatex/generic/luaotfload/fontloader-font-shp.lua index c3fea6d460..78e8597b93 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-shp.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-shp.lua @@ -8,7 +8,7 @@ if not modules then modules = { } end modules ['font-shp'] = { local tonumber, next = tonumber, next local concat = table.concat -local formatters = string.formatters +local formatters, lower = string.formatters, string.lower local otf = fonts.handlers.otf local afm = fonts.handlers.afm @@ -221,7 +221,7 @@ end local function loadstreams(cache,filename,sub,instance) local base = file.basename(filename) local name = file.removesuffix(base) - local kind = file.suffix(filename) + local kind = lower(file.suffix(filename)) local attr = lfs.attributes(filename) local size = attr and attr.size or 0 local time = attr and attr.modification or 0 diff --git a/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua b/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua index 865f8e6e30..a2732aa5f2 100644 --- a/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua +++ b/macros/luatex/generic/luaotfload/fontloader-font-ttf.lua @@ -163,8 +163,7 @@ local function mergecomposites(glyphs,shapes) return contours, points end --- for index=1,#glyphs do - for index=0,#glyphs-1 do + for index=0,#glyphs do local shape = shapes[index] if shape then local components = shape.components @@ -659,7 +658,7 @@ local function repackpoints(glyphs,shapes) local result = { } -- reused local xpoints = { } -- reused local ypoints = { } -- reused - for index=0,#glyphs-1 do + for index=0,#glyphs do local shape = shapes[index] if shape then local r = 0 diff --git a/macros/luatex/generic/luaotfload/fontloader-reference.lua b/macros/luatex/generic/luaotfload/fontloader-reference.lua index df4f3593c2..0b220327c3 100644 --- a/macros/luatex/generic/luaotfload/fontloader-reference.lua +++ b/macros/luatex/generic/luaotfload/fontloader-reference.lua @@ -1,6 +1,6 @@ -- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua -- parent file : c:/data/develop/context/sources/luatex-fonts.lua --- merge date : 2020-08-31 22:01 +-- merge date : 2020-12-30 16:42 do -- begin closure to overcome local limits and interference @@ -4939,6 +4939,7 @@ nuts.getkern=direct.getkern nuts.getlist=direct.getlist nuts.getnext=direct.getnext nuts.getoffsets=direct.getoffsets +nuts.getoptions=direct.getoptions or function() return 0 end nuts.getprev=direct.getprev nuts.getsubtype=direct.getsubtype nuts.getwidth=direct.getwidth @@ -5022,6 +5023,15 @@ local traverse_id=nuts.traverse_id local copy_node=nuts.copy_node local glyph_code=nodes.nodecodes.glyph local ligature_code=nodes.glyphcodes.ligature +do + local p=nodecodes.localpar or nodecodes.local_par + if p then + nodecodes.par=p + nodecodes[p]="par" + nodecodes.localpar=p + nodecodes.local_par=p + end +end do local get_components=node.direct.getcomponents local set_components=node.direct.setcomponents @@ -5074,11 +5084,14 @@ do end return 0 end + local function flush_components() + end nuts.set_components=set_components nuts.get_components=get_components nuts.copy_only_glyphs=copy_only_glyphs nuts.copy_no_components=copy_no_components nuts.count_components=count_components + nuts.flush_components=flush_components end nuts.uses_font=direct.uses_font do @@ -15147,7 +15160,7 @@ local function mergecomposites(glyphs,shapes) shape.components=nil return contours,points end - for index=0,#glyphs-1 do + for index=0,#glyphs do local shape=shapes[index] if shape then local components=shape.components @@ -15577,7 +15590,7 @@ local function repackpoints(glyphs,shapes) local result={} local xpoints={} local ypoints={} - for index=0,#glyphs-1 do + for index=0,#glyphs do local shape=shapes[index] if shape then local r=0 @@ -16840,7 +16853,7 @@ local function readfirst(f,offset) end return { readushort(f) } end -function readarray(f,offset) +local function readarray(f,offset) if offset then setposition(f,offset) end @@ -20766,7 +20779,7 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_d local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf -otf.version=3.111 +otf.version=3.112 otf.cache=containers.define("fonts","otl",otf.version,true) otf.svgcache=containers.define("fonts","svg",otf.version,true) otf.pngcache=containers.define("fonts","png",otf.version,true) @@ -21131,7 +21144,6 @@ local function copytotfm(data,cache_id) parameters.units=units parameters.vheight=metadata.defaultvheight properties.space=spacer - properties.encodingbytes=2 properties.format=data.format or formats.otf properties.filename=filename properties.fontname=fontname @@ -21139,6 +21151,9 @@ local function copytotfm(data,cache_id) properties.psname=psname properties.name=filename or fullname properties.subfont=subfont +if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then + properties.encodingbytes=2 +end properties.private=properties.private or data.private or privateoffset return { characters=characters, @@ -26617,6 +26632,7 @@ local copy_only_glyphs=nuts.copy_only_glyphs local count_components=nuts.count_components local set_components=nuts.set_components local get_components=nuts.get_components +local flush_components=nuts.flush_components local ischar=nuts.ischar local usesfont=nuts.uses_font local insert_node_after=nuts.insert_after @@ -26639,7 +26655,7 @@ local glue_code=nodecodes.glue local disc_code=nodecodes.disc local math_code=nodecodes.math local dir_code=nodecodes.dir -local localpar_code=nodecodes.localpar +local par_code=nodecodes.par local lefttoright_code=nodes.dirvalues.lefttoright local righttoleft_code=nodes.dirvalues.righttoleft local discretionarydisc_code=disccodes.discretionary @@ -26821,11 +26837,23 @@ local function markstoligature(head,start,stop,char) setsubtype(base,ligatureglyph_code) set_components(base,start) setlink(prev,base,next) + flush_components(start) return head,base end end +local no_left_ligature_code=1 +local no_right_ligature_code=2 +local no_left_kern_code=4 +local no_right_kern_code=8 +local has_glyph_option=node.direct.has_glyph_option or function(n,c) + if c==no_left_ligature_code or c==no_right_ligature_code then + return getattr(n,a_noligature)==1 + else + return false + end +end local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfound,hasmarks) - if getattr(start,a_noligature)==1 then + if has_glyph_option(start,no_right_ligature_code) then return head,start end if start==stop and getchar(start)==char then @@ -26889,6 +26917,7 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou break end end + flush_components(components) else local discprev,discnext=getboth(discfound) if discprev and discnext then @@ -27175,78 +27204,86 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip return head,start,false,false end function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection) - local startchar=getchar(start) - local format=step.format - if format=="single" or type(kerns)=="table" then - local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %s xy (%p,%p) and wh (%p,%p)",pref(dataset,sequence),gref(startchar),format,dx,dy,w,h) - end + if has_glyph_option(start,no_right_kern_code) then + return head,start,false else - local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %s %p",pref(dataset,sequence),gref(startchar),format,k) + local startchar=getchar(start) + local format=step.format + if format=="single" or type(kerns)=="table" then + local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %s xy (%p,%p) and wh (%p,%p)",pref(dataset,sequence),gref(startchar),format,dx,dy,w,h) + end + else + local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %s %p",pref(dataset,sequence),gref(startchar),format,k) + end end + return head,start,true end - return head,start,true end function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection) - local snext=getnext(start) - if not snext then + if has_glyph_option(start,no_right_kern_code) then return head,start,false else - local prev=start - while snext do - local nextchar=ischar(snext,currentfont) - if nextchar then - if skiphash and skiphash[nextchar] then - prev=snext - snext=getnext(snext) - else - local krn=kerns[nextchar] - if not krn then - break - end - local format=step.format - if format=="pair" then - local a=krn[1] - local b=krn[2] - if a==true then - elseif a then - local x,y,w,h=setposition(1,start,factor,rlmode,a,injection) - if trace_kerns then - local startchar=getchar(start) - logprocess("%s: shifting first of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") - end + local snext=getnext(start) + if not snext then + return head,start,false + else + local prev=start + while snext do + local nextchar=ischar(snext,currentfont) + if nextchar then + if skiphash and skiphash[nextchar] then + prev=snext + snext=getnext(snext) + else + local krn=kerns[nextchar] + if not krn then + break end - if b==true then - start=snext - elseif b then - local x,y,w,h=setposition(2,snext,factor,rlmode,b,injection) + local format=step.format + if format=="pair" then + local a=krn[1] + local b=krn[2] + if a==true then + elseif a then + local x,y,w,h=setposition(1,start,factor,rlmode,a,injection) + if trace_kerns then + local startchar=getchar(start) + logprocess("%s: shifting first of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + end + end + if b==true then + start=snext + elseif b then + local x,y,w,h=setposition(2,snext,factor,rlmode,b,injection) + if trace_kerns then + local startchar=getchar(start) + logprocess("%s: shifting second of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + end + start=snext + elseif forcepairadvance then + start=snext + end + return head,start,true + elseif krn~=0 then + local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn,injection) if trace_kerns then - local startchar=getchar(start) - logprocess("%s: shifting second of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") + logprocess("%s: inserting %s %p between %s and %s as %s",pref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar),injection or "injections") end - start=snext - elseif forcepairadvance then - start=snext - end - return head,start,true - elseif krn~=0 then - local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn,injection) - if trace_kerns then - logprocess("%s: inserting %s %p between %s and %s as %s",pref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar),injection or "injections") + return head,start,true + else + break end - return head,start,true - else - break end + else + break end - else - break end + return head,start,false end - return head,start,false end end function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode,skiphash) @@ -27676,89 +27713,93 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup return head,start,false,0,false end function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) - local mapping=currentlookup.mapping - if mapping==nil then - mapping=getmapping(dataset,sequence,currentlookup) - end - if mapping then - local startchar=getchar(start) - local kerns=mapping[startchar] - if kerns then - local format=currentlookup.format - if format=="single" then - local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns) - if trace_kerns then - logprocess("%s: shifting single %s by %s (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),format,dx,dy,w,h) - end - else - local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection) - if trace_kerns then - logprocess("%s: shifting single %s by %s %p",cref(dataset,sequence),gref(startchar),format,k) + if not has_glyph_option(start,no_right_kern_code) then + local mapping=currentlookup.mapping + if mapping==nil then + mapping=getmapping(dataset,sequence,currentlookup) + end + if mapping then + local startchar=getchar(start) + local kerns=mapping[startchar] + if kerns then + local format=currentlookup.format + if format=="single" then + local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns) + if trace_kerns then + logprocess("%s: shifting single %s by %s (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),format,dx,dy,w,h) + end + else + local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by %s %p",cref(dataset,sequence),gref(startchar),format,k) + end end + return head,start,true end - return head,start,true end end return head,start,false end -function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) - local mapping=currentlookup.mapping - if mapping==nil then - mapping=getmapping(dataset,sequence,currentlookup) - end - if mapping then - local snext=getnext(start) - if snext then - local startchar=getchar(start) - local kerns=mapping[startchar] - if kerns then - local prev=start - while snext do - local nextchar=ischar(snext,currentfont) - if not nextchar then - break - end - if skiphash and skiphash[nextchar] then - prev=snext - snext=getnext(snext) - else - local krn=kerns[nextchar] - if not krn then +function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) + if not has_glyph_option(start,no_right_kern_code) then + local mapping=currentlookup.mapping + if mapping==nil then + mapping=getmapping(dataset,sequence,currentlookup) + end + if mapping then + local snext=getnext(start) + if snext then + local startchar=getchar(start) + local kerns=mapping[startchar] + if kerns then + local prev=start + while snext do + local nextchar=ischar(snext,currentfont) + if not nextchar then break end - local format=currentlookup.format - if format=="pair" then - local a=krn[1] - local b=krn[2] - if a==true then - elseif a then - local x,y,w,h=setposition(1,start,factor,rlmode,a,"injections") - if trace_kerns then - local startchar=getchar(start) - logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) - end + if skiphash and skiphash[nextchar] then + prev=snext + snext=getnext(snext) + else + local krn=kerns[nextchar] + if not krn then + break end - if b==true then - start=snext - elseif b then - local x,y,w,h=setposition(2,snext,factor,rlmode,b,"injections") + local format=currentlookup.format + if format=="pair" then + local a=krn[1] + local b=krn[2] + if a==true then + elseif a then + local x,y,w,h=setposition(1,start,factor,rlmode,a,"injections") + if trace_kerns then + local startchar=getchar(start) + logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + end + end + if b==true then + start=snext + elseif b then + local x,y,w,h=setposition(2,snext,factor,rlmode,b,"injections") + if trace_kerns then + local startchar=getchar(start) + logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + end + start=snext + elseif forcepairadvance then + start=snext + end + return head,start,true + elseif krn~=0 then + local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn) if trace_kerns then - local startchar=getchar(start) - logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) + logprocess("%s: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar)) end - start=snext - elseif forcepairadvance then - start=snext - end - return head,start,true - elseif krn~=0 then - local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn) - if trace_kerns then - logprocess("%s: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar)) + return head,start,true + else + break end - return head,start,true - else - break end end end @@ -29580,7 +29621,7 @@ do checkstep(head) end local initialrl=0 - if getid(head)==localpar_code and start_of_par(head) then + if getid(head)==par_code and start_of_par(head) then initialrl=pardirstate(head) elseif direction==righttoleft_code then initialrl=-1 @@ -34675,7 +34716,6 @@ local function copytotfm(data) parameters.descender=abs(metadata.descender or 0) parameters.units=1000 properties.spacer=spacer - properties.encodingbytes=2 properties.format=fonts.formats[filename] or "type1" properties.filename=filename properties.fontname=fontname @@ -34683,6 +34723,9 @@ local function copytotfm(data) properties.psname=fullname properties.name=filename or fullname or fontname properties.private=properties.private or data.private or privateoffset +if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then + properties.encodingbytes=2 +end if next(characters) then return { characters=characters, @@ -35993,7 +36036,7 @@ if not modules then modules={} end modules ['font-shp']={ } local tonumber,next=tonumber,next local concat=table.concat -local formatters=string.formatters +local formatters,lower=string.formatters,string.lower local otf=fonts.handlers.otf local afm=fonts.handlers.afm local pfb=fonts.handlers.pfb @@ -36186,7 +36229,7 @@ end local function loadstreams(cache,filename,sub,instance) local base=file.basename(filename) local name=file.removesuffix(base) - local kind=file.suffix(filename) + local kind=lower(file.suffix(filename)) local attr=lfs.attributes(filename) local size=attr and attr.size or 0 local time=attr and attr.modification or 0 @@ -37084,56 +37127,74 @@ local rules={ "FractionRuleThickness", "UnderbarRuleThickness", } -local function setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze) - if delta~=0 then - for i=1,#rules do - local name=rules[i] - local value=mathparameters[name] - if value then - mathparameters[name]=(squeeze or 1)*(value+dx) +local setmathparameters +local setmathcharacters +if CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 then + setmathparameters=function(tfmdata,characters,mathparameters,dx,dy,squeeze,multiplier) + if delta~=0 then + for i=1,#rules do + local name=rules[i] + local value=mathparameters[name] + if value then + mathparameters[name]=(squeeze or 1)*(value+dy) + end end end end -end -local function setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta) - local function wdpatch(char) - if wsnap~=0 then - char.width=char.width+wdelta/2 - end + setmathcharacters=function() end - local function htpatch(char) - if hsnap~=0 then - local height=char.height - if height then - char.height=char.height+2*dy +else + setmathparameters=function(tfmdata,characters,mathparameters,dx,dy,squeeze,multiplier) + if delta~=0 then + for i=1,#rules do + local name=rules[i] + local value=mathparameters[name] + if value then + mathparameters[name]=(squeeze or 1)*(value+dy) + end end end end - local character=characters[0x221A] - if character and character.next then - local char=character - local next=character.next - wdpatch(char) - htpatch(char) - while next do - char=characters[next] + setmathcharacters=function(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta) + local function wdpatch(char) + if wsnap~=0 then + char.width=char.width+wdelta/2 + end + end + local function htpatch(char) + if hsnap~=0 then + local height=char.height + if height then + char.height=char.height+2*dy + end + end + end + local character=characters[0x221A] + if character and character.next then + local char=character + local next=character.next wdpatch(char) htpatch(char) - next=char.next - end - if char then - local v=char.vert_variants - if v then - local top=v[#v] - if top then - local char=characters[top.glyph] - htpatch(char) + while next do + char=characters[next] + wdpatch(char) + htpatch(char) + next=char.next + end + if char then + local v=char.vert_variants + if v then + local top=v[#v] + if top then + local char=characters[top.glyph] + htpatch(char) + end end end end end end -local shiftmode=CONTEXTLMTXMODE>0 +local shiftmode=CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 local function manipulateeffect(tfmdata) local effect=tfmdata.properties.effect if effect then @@ -37205,7 +37266,7 @@ local function manipulateeffect(tfmdata) end end if mathparameters then - setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze) + setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze,multiplier) setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta) end parameters.factor=factor diff --git a/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua b/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua index 14a66da359..2d4e757bc0 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-auxiliary.lua @@ -4,19 +4,14 @@ -- AUTHOR: Khaled Hosny, Élie Roux, Philipp Gesang ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-auxiliary", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / auxiliary functions", license = "GPL v2.0" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - - luaotfload = luaotfload or { } local log = luaotfload.log local logreport = log.report @@ -912,6 +907,53 @@ function aux.get_quad(font_id) end ----------------------------------------------------------------------- +--- Script/language fixup +----------------------------------------------------------------------- +local otftables = fonts.constructors.handlers.otf.tables +local function setscript(tfmdata, value) + if value then + local cleanvalue = string.lower(value) + local scripts = otftables and otftables.scripts + local properties = tfmdata.properties + if not scripts then + properties.script = cleanvalue + elseif scripts[value] then + properties.script = cleanvalue + else + properties.script = "dflt" + end + end + local resources = tfmdata.resources + local features = resources and resources.features + if features then + local properties = tfmdata.properties + local script, language = properties.script, properties.language + local script_found, language_found = false, false + for _, data in next, features do for _, feature_data in next, data do + local scr = feature_data[script] + if scr then + script_found = true + if scr[language] then + language_found = true + goto double_break + end + end + end end + ::double_break:: + if not script_found then properties.script = "dflt" end + if not language_found then properties.language = "dflt" end + end +end +fonts.constructors.features.otf.register { + name = "script", + initializers = { + base = setscript, + node = setscript, + plug = setscript, + }, +} + +----------------------------------------------------------------------- --- initialization ----------------------------------------------------------------------- diff --git a/macros/luatex/generic/luaotfload/luaotfload-case.lua b/macros/luatex/generic/luaotfload/luaotfload-case.lua new file mode 100644 index 0000000000..33bb1bc924 --- /dev/null +++ b/macros/luatex/generic/luaotfload/luaotfload-case.lua @@ -0,0 +1,239 @@ +local unicode_data = require'luaotfload-unicode' + +local mapping_tables = unicode_data.casemapping +local soft_dotted = unicode_data.soft_dotted +local ccc = unicode_data.ccc + +local uppercase = mapping_tables.uppercase +local lowercase = mapping_tables.lowercase +local cased = mapping_tables.cased +local case_ignorable = mapping_tables.case_ignorable + +local otfregister = fonts.constructors.features.otf.register + +local direct = node.direct +local is_char = direct.is_char +local has_glyph = direct.has_glyph +local uses_font = direct.uses_font +local getnext = direct.getnext +local setchar = direct.setchar +local setdisc = direct.setdisc +local getdisc = direct.getdisc +local getfield = direct.getfield +local remove = direct.remove +local copy = direct.copy +local insert_after = direct.insert_after +local traverse = direct.traverse + +local disc = node.id'disc' + +--[[ We make some implicit assumptions about contexts in SpecialCasing.txt here which happened to be true when I wrote the code: +-- +-- * Before_Dot only appears as Not_Before_Dot +-- * No other context appears with Not_ +-- * Final_Sigma is never language dependent +-- * Other contexts are always language dependent +-- * The only languages with special mappings are Lithuanian (lt/"LTH "/lit), Turkish (tr/"TRK "/tur), and Azeri/Azerbaijani (az/"AZE "/aze) +]] + +local font_lang = setmetatable({}, {__index = function(t, fid) + local f = font.getfont(fid) + local lang = f.specification.features.normal.language + lang = lang == 'lth' and 'lt' or lang == 'trk' and 'tr' or lang == 'aze' and 'az' or false + t[fid] = lang + return lang +end}) + +local function is_Final_Sigma(font, mapping, n, after) + mapping = mapping.Final_Sigma + if not mapping then return false end + mapping = mapping._ + if not mapping then return false end + n = getnext(n) + repeat + while n do + local char, id = is_char(n, font) + if id == disc then + after = getnext(n) + n = getfield(n, 'replace') + char, id = is_char(n, font) + elseif char then + if not case_ignorable[char] then + return not cased[char] and mapping + end + n = getnext(n) + else + return mapping + end + end + n, after = after + until not n + return mapping +end + +local function is_More_Above(font, mapping, n, after) + mapping = mapping.More_Above + if not mapping then return false end + mapping = mapping._ + if not mapping then return false end + n = getnext(n) + repeat + while n do + local char, id = is_char(n, font) + if id == disc then + after = getnext(n) + n = getfield(n, 'replace') + char, id = is_char(n, font) + elseif char then + local char_ccc = ccc[char] + if not char_ccc then + return false + elseif char_ccc == 230 then + return mapping + end + n = getnext(n) + else + return false + end + end + n, after = after + until not n + return false +end + +local function is_Not_Before_Dot(font, mapping, n, after) + mapping = mapping.Not_Before_Dot + if not mapping then return false end + mapping = mapping._ + if not mapping then return false end + n = getnext(n) + repeat + while n do + local char, id = is_char(n, font) + if id == disc then + after = getnext(n) + n = getfield(n, 'replace') + char, id = is_char(n, font) + elseif char then + local char_ccc = ccc[char] + if not char_ccc then + return mapping + elseif char_ccc == 230 then + return char ~= 0x0307 and mapping + end + n = getnext(n) + else + return mapping + end + end + n, after = after + until not n + return mapping +end + +local function is_Language_Mapping(font, mapping, n, after, seen_soft_dotted, seen_I) + if not mapping then return false end + if seen_soft_dotted then + local mapping = mapping.After_Soft_Dotted + mapping = mapping and mapping._ + if mapping then + return mapping + end + end + if seen_I then + local mapping = mapping.After_I + mapping = mapping and mapping._ + if mapping then + return mapping + end + end + return is_More_Above(font, mapping, n, after) or is_Not_Before_Dot(font, mapping, n, after) or mapping._ -- Might be nil +end + +local function process(table) + local function processor(head, font, after, seen_cased, seen_soft_dotted, seen_I) + local lang = font_lang[font] + local n = head + while n do + do + local new = has_glyph(n) + if n ~= new then + seen_cased, seen_soft_dotted, seen_I = nil + end + n = new + end + if not n then break end + local char, id = is_char(n, font) + if char then + local mapping = table[char] + if mapping then + if tonumber(mapping) then + setchar(n, mapping) + else + mapping = seen_cased and is_Final_Sigma(font, mapping, n, after) + or lang and is_Language_Mapping(font, mapping[lang], n, after, seen_soft_dotted, seen_I) + or mapping._ + if #mapping == 0 then + head, n = remove(head, n) + goto continue + else + setchar(n, mapping[1]) + for i=2, #mapping do + head, n = insert_after(head, n, copy(n)) + setchar(n, mapping[i]) + end + end + end + end + if not case_ignorable[char] then + seen_cased = cased[char] or nil + end + local char_ccc = ccc[char] + if not char_ccc or char_ccc == 230 then + seen_I = char == 0x49 or nil + seen_soft_dotted = soft_dotted[char] + end + elseif id == disc and uses_font(n, font) then + local pre, post, rep = getdisc(n) + local after = getnext(n) + pre, post, rep, seen_cased, seen_soft_dotted, seen_I = + processor(pre, font, nil, seen_cased, seen_soft_dotted, seen_I), + processor(post, font, after), + processor(rep, font, after, seen_cased, seen_soft_dotted, seen_I) + setdisc(n, pre, post, rep) + else + seen_cased, seen_soft_dotted, seen_I = nil + end + n = getnext(n) + ::continue:: + end + return head, seen_cased, seen_soft_dotted, seen_I + end + return function(head, font) return (processor(head, font)) end +end + +local upper_process = process(uppercase) +otfregister { + name = 'upper', + description = 'Map to uppercase', + default = false, + processors = { + position = 1, + plug = upper_process, + node = upper_process, + base = upper_process, + }, +} + +local lower_process = process(lowercase) +otfregister { + name = 'lower', + description = 'Map to lowercase', + default = false, + processors = { + position = 1, + plug = lower_process, + node = lower_process, + base = lower_process, + }, +} diff --git a/macros/luatex/generic/luaotfload/luaotfload-colors.lua b/macros/luatex/generic/luaotfload/luaotfload-colors.lua index e8a8e996a8..c1f8a63a8e 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-colors.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-colors.lua @@ -3,21 +3,16 @@ -- DESCRIPTION: part of luaotfload / font colors ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-colors", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / color", license = "GPL v2.0", author = "Khaled Hosny, Elie Roux, Philipp Gesang, Dohyun Kim, David Carlisle", copyright = "Luaotfload Development Team" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - - --[[doc-- buggy coloring with the pre_output_filter when expansion is enabled diff --git a/macros/luatex/generic/luaotfload/luaotfload-conf.pdf b/macros/luatex/generic/luaotfload/luaotfload-conf.pdf Binary files differindex 85768faf2f..52137882d4 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-conf.pdf +++ b/macros/luatex/generic/luaotfload/luaotfload-conf.pdf diff --git a/macros/luatex/generic/luaotfload/luaotfload-configuration.lua b/macros/luatex/generic/luaotfload/luaotfload-configuration.lua index 8f04190a43..e5e1ed24f0 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-configuration.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-configuration.lua @@ -5,18 +5,14 @@ -- AUTHOR: Dohyun Kim <nomosnomos@gmail.com> ------------------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-configuration", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / config file reader", license = "GPL v2.0" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - ------------------------------ local status_file = "luaotfload-status" diff --git a/macros/luatex/generic/luaotfload/luaotfload-database.lua b/macros/luatex/generic/luaotfload/luaotfload-database.lua index 6d0bcff414..da2d9965a3 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-database.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-database.lua @@ -3,19 +3,15 @@ -- DESCRIPTION: part of luaotfload / luaotfload-tool / font database ----------------------------------------------------------------------- do -- block to avoid to many local variables error - local ProvidesLuaModule = { + assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-database", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / database", license = "GPL v2.0", author = "Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger", copyright = "Luaotfload Development Team", } - - if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) - end end --[[doc-- @@ -2335,8 +2331,7 @@ local path_separator = os.type == "windows" and ";" or ":" --[[doc-- collect_font_filenames_texmf -- Scan texmf tree for font files - relying on the kpathsea variables $OPENTYPEFONTS and $TTFONTS of - texmf.cnf. + relying on kpathsea search paths for the respective file types. The current working directory comes as “.” (texlive) or absolute path (miktex) and will always be filtered out. @@ -2362,16 +2357,20 @@ local function collect_font_filenames_texmf () end end - fontdirs = kpseexpand_path "$OPENTYPEFONTS" - fontdirs = fontdirs .. path_separator .. kpseexpand_path "$TTFONTS" - fontdirs = fontdirs .. path_separator .. kpseexpand_path "$T1FONTS" - fontdirs = fontdirs .. path_separator .. kpseexpand_path "$AFMFONTS" + local show_path = kpse.show_path - if stringis_empty (fontdirs) then - return { } + local function expanded_path (file_type) + return kpseexpand_path (show_path (file_type)) end - local tasks = filter_out_pwd (filesplitpath (fontdirs)) + local fontdirs = expanded_path "opentype fonts" + fontdirs = fontdirs .. path_separator .. expanded_path "truetype fonts" + fontdirs = fontdirs .. path_separator .. expanded_path "type1 fonts" + fontdirs = fontdirs .. path_separator .. expanded_path "afm" + + fontdirs = filesplitpath (fontdirs) or { } + + local tasks = filter_out_pwd (fontdirs) logreport ("both", 3, "db", "Initiating scan of %d directories.", #tasks) diff --git a/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua b/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua index be3183cf65..366c7c98ec 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-diagnostics.lua @@ -5,19 +5,14 @@ -- AUTHOR: Philipp Gesang <phg@phi-gamma.net> ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-diagnostics", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload-tool submodule / diagnostics", license = "GPL v2.0" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - - local names = fonts.names local kpse = require "kpse" diff --git a/macros/luatex/generic/luaotfload/luaotfload-dvi.lua b/macros/luatex/generic/luaotfload/luaotfload-dvi.lua index b57934fdb6..33083045d4 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-dvi.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-dvi.lua @@ -4,20 +4,16 @@ ------------------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-dvi", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / DVI", license = "GPL v2.0", author = "Marcel Krüger", copyright = "Luaotfload Development Team", } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - local getfont = font.getfont local setfont = node.direct.setfont local getdisc = node.direct.getdisc diff --git a/macros/luatex/generic/luaotfload/luaotfload-embolden.lua b/macros/luatex/generic/luaotfload/luaotfload-embolden.lua index d1d4e478c8..73993eead8 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-embolden.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-embolden.lua @@ -3,19 +3,15 @@ -- DESCRIPTION: part of luaotfload / embolden ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-embolden", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / embolden", license = "GPL v2.0", author = "Marcel Krüger" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - local otffeatures = fonts.constructors.newfeatures "otf" local function enableembolden(tfmdata, _, embolden) diff --git a/macros/luatex/generic/luaotfload/luaotfload-fallback.lua b/macros/luatex/generic/luaotfload/luaotfload-fallback.lua index eee107c709..17bd7ca404 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-fallback.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-fallback.lua @@ -3,19 +3,15 @@ -- DESCRIPTION: part of luaotfload / fallback ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-fallback", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / fallback", license = "GPL v2.0", author = "Marcel Krüger" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - local nodenew = node.direct.new local getfont = font.getfont local setfont = node.direct.setfont diff --git a/macros/luatex/generic/luaotfload/luaotfload-features.lua b/macros/luatex/generic/luaotfload/luaotfload-features.lua index 2d83df10ff..67c9f93565 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-features.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-features.lua @@ -3,21 +3,16 @@ -- DESCRIPTION: part of luaotfload / font features ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-features", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / features", license = "GPL v2.0", author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger", copyright = "PRAGMA ADE / ConTeXt Development Team", } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - - local type = type local next = next local tonumber = tonumber @@ -45,12 +40,18 @@ local otf = handlers.otf local config = config or { luaotfload = { run = { } } } -local as_script = true -local normalize = function () end +local as_script = config.luaotfload.run.live +local normalize -if config.luaotfload.run.live ~= false then +if as_script then + function normalize(features) + return { + axis = features and features.axis, + instance = features and features.instance, + } + end +else normalize = otf.features.normalize - as_script = false end --[[HH (font-xtx) -- @@ -663,7 +664,7 @@ end do local function mathfontdimen(tfmdata, _, value) - if not next(tfmdata.mathparameters) then return end + if not (tfmdata.mathparameters and next(tfmdata.mathparameters)) then return end local parameters = tfmdata.parameters local mathparameters = tfmdata.mathparameters if value == 'xetex' then diff --git a/macros/luatex/generic/luaotfload/luaotfload-filelist.lua b/macros/luatex/generic/luaotfload/luaotfload-filelist.lua index b8ab343402..69195603ed 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-filelist.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-filelist.lua @@ -4,19 +4,13 @@ -- AUTHOR: Ulrike Fischer, <fischer@troubleshooting-tex.de> ----------------------------------------------------------------------- -local ProvidesLuaModule = { +if luaotfload_module then luaotfload_module { name = "luaotfload-filelist", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / filelist", license = "GPL v2.0" -} - -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - - +} end --[[doc-- diff --git a/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua b/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua index 19f5c2082b..aefc8369c6 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-glyphlist.lua @@ -1,12 +1,14 @@ -local ProvidesLuaModule = { +if luaotfload_module then + luaotfload_module { name = "luaotfload-glyphlist", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / autogenerated glyphlist", copyright = "derived from https://raw.githubusercontent.com/adobe-type-tools/agl-aglfn/master/glyphlist.txt", original = "Adobe Glyph List, version 2.0, September 20, 2002", dataonly = true -} + } +end if context then logs.report("fatal error","this module is not for context") diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua index 37ada59d00..5be4acfa65 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-harf-define.lua @@ -3,19 +3,15 @@ -- DESCRIPTION: part of luaotfload / HarfBuzz / font definition ----------------------------------------------------------------------- do -- block to avoid to many local variables error - local ProvidesLuaModule = { + assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-harf-define", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / HarfBuzz font loading", license = "GPL v2.0", author = "Khaled Hosny, Marcel Krüger", copyright = "Luaotfload Development Team", } - - if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) - end end local unpack = string.unpack diff --git a/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua b/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua index 6759747fbf..c40aa3b72e 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-harf-plug.lua @@ -3,19 +3,15 @@ -- DESCRIPTION: part of luaotfload / HarfBuzz / fontloader plugin ----------------------------------------------------------------------- do -- block to avoid to many local variables error - local ProvidesLuaModule = { + assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-harf-plug", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / HarfBuzz shaping", license = "GPL v2.0", author = "Khaled Hosny, Marcel Krüger", copyright = "Luaotfload Development Team", } - - if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) - end end local hb = luaotfload.harfbuzz @@ -36,6 +32,7 @@ local direct = node.direct local tonode = direct.tonode local todirect = direct.todirect local traverse = direct.traverse +local traverse_list = direct.traverse_list local insertbefore = direct.insert_before local insertafter = direct.insert_after local protectglyph = direct.protect_glyph @@ -46,6 +43,7 @@ local removenode = direct.remove local copynodelist = direct.copy_list local ischar = direct.is_char local uses_font = direct.uses_font +local length = direct.length local getattrs = direct.getattributelist local setattrs = direct.setattributelist @@ -78,13 +76,15 @@ local getsubtype = direct.getsubtype local setsubtype = direct.setsubtype local getwidth = direct.getwidth local setwidth = direct.setwidth +local setlist = direct.setlist local is_char = direct.is_char local tail = direct.tail +local getboth = direct.getboth +local setlink = direct.setlink local properties = direct.get_properties_table() -local imgnode = img.node - +local hlist_t = node.id("hlist") local disc_t = node.id("disc") local glue_t = node.id("glue") local glyph_t = node.id("glyph") @@ -94,7 +94,10 @@ local localpar_t = node.id("local_par") local whatsit_t = node.id("whatsit") local pdfliteral_t = node.subtype("pdf_literal") +local line_t = 1 local explicitdisc_t = 1 +local firstdisc_t = 4 +local seconddisc_t = 5 local fontkern_t = 0 local italiccorr_t = 3 local regulardisc_t = 3 @@ -179,8 +182,12 @@ local function itemize(head, fontid, direction) local currdir = direction or 0 local lastskip, lastdir = true local lastrun = {} + local lastdisc + local in_disc - for n, id, subtype in direct.traverse(head) do + for n, id, subtype in traverse(head) do + if in_disc == n then in_disc = nil end + local disc local code = 0xFFFC -- OBJECT REPLACEMENT CHARACTER local skip = lastskip local props = properties[n] @@ -189,8 +196,9 @@ local function itemize(head, fontid, direction) code = 0x200C -- skip = false -- Not sure about this, but lastskip should be a bit faster elseif id == glyph_t then - if is_char(n) and getfont(n) == fontid then - code = getchar(n) + local char = is_char(n, fontid) + if char then + code = char skip = false else skip = true @@ -199,8 +207,28 @@ local function itemize(head, fontid, direction) code = 0x0020 -- SPACE elseif id == disc_t then if uses_font(n, fontid) then - code = 0x00AD -- SOFT HYPHEN + local _, _, rep, _, _, rep_tail = getdisc(n, true) + setfield(n, 'replace', nil) + local prev, next = getboth(n) + in_disc = next + disc = { + disc = n, + anchor_cluster = #codes - (lastrun.start or 0) + 1, + after_cluster = #codes - (lastrun.start or 0) + 1 + length(rep), + } + if rep then + setlink(rep_tail, next) + setnext(n, rep) -- This one is just to keep the loop going + n = rep + else + n = next + end + setlink(prev, n) + code = nil skip = false + if not prev then + head = n + end else skip = true end @@ -220,26 +248,39 @@ local function itemize(head, fontid, direction) currdir = getdirection(n) end - codes[#codes + 1] = code + local ncodes = #codes -- Necessary to count discs correctly + codes[ncodes + 1] = code - if lastdir ~= currdir or lastskip ~= skip then + if (disc or not in_disc) and (lastdir ~= currdir or lastskip ~= skip) then + if disc then + disc.after_cluster = disc.after_cluster - disc.anchor_cluster + disc.anchor_cluster = 0 + end lastrun.after = n lastrun = { - start = #codes, - len = 1, + start = ncodes + 1, + len = code and 1 or 0, font = fontid, dir = currdir == 1 and dir_rtl or dir_ltr, skip = skip, codes = codes, + discs = disc, } runs[#runs + 1] = lastrun - lastdir, lastskip = currdir, skip - else + lastdir, lastskip, lastdisc = currdir, skip, disc + elseif code then lastrun.len = lastrun.len + 1 + elseif disc then + if lastdisc then + lastdisc.next = disc + lastdisc = disc + else + lastrun.discs, lastdisc = disc, disc + end end end - return runs + return head, runs end @@ -260,7 +301,6 @@ local function makesub(run, codes, nodelist) font = run.font, dir = run.dir, fordisc = true, - node = nodelist, codes = codes, } local glyphs @@ -294,14 +334,12 @@ end function shape(head, firstnode, run) local node = firstnode local codes = run.codes - local offset = run.start - local nodeindex = offset - run.start = offset + local offset = run.start - 1 -- -1 because we want the cluster local len = run.len local fontid = run.font local dir = run.dir - local fordisc = run.fordisc - local cluster = offset - 2 + local cluster + local discs = (not run.fordisc) and run.discs local fontdata = font.getfont(fontid) local hbdata = fontdata.hb @@ -323,7 +361,7 @@ function shape(head, firstnode, run) buf:set_script(script) buf:set_language(lang) buf:set_cluster_level(buf.CLUSTER_LEVEL_MONOTONE_CHARACTERS) - buf:add_codepoints(codes, offset - 1, len) + buf:add_codepoints(codes, offset, len) local hscale = hbdata.hscale local vscale = hbdata.vscale @@ -333,7 +371,7 @@ function shape(head, firstnode, run) features = table.merged(features) -- We don't want to modify the global features local current_features = {} local n = node - for i = offset-1, offset+len-2 do + for i = offset, offset+len-1 do local props = properties[n] or empty_table if props then local local_feat = props.glyph_features or empty_table @@ -371,187 +409,260 @@ function shape(head, firstnode, run) local glyphs = buf:get_glyphs() + local break_glyph, break_cluster, break_node = 1, offset, node + local disc_glyph, disc_cluster, disc_node + local disc_cluster local i = 0 - while i < #glyphs do - i = i + 1 - local glyph = glyphs[i] - - -- Calculate the Unicode code points of this glyph. If cluster did not - -- change then this is a glyph inside a complex cluster and will be - -- handled with the start of its cluster. - if cluster ~= glyph.cluster then - cluster = glyph.cluster - for i = nodeindex, cluster do node = getnext(node) end - nodeindex = cluster + 1 - local hex = "" - local str = "" - local nextcluster - for j = i+1, #glyphs do - nextcluster = glyphs[j].cluster - if cluster ~= nextcluster then - glyph.nglyphs = j - i - goto NEXTCLUSTERFOUND -- break - end - end -- else -- only executed if the loop reached the end without - -- finding another cluster - nextcluster = offset + len - 1 - glyph.nglyphs = #glyphs + 1 - i - ::NEXTCLUSTERFOUND:: -- end - glyph.nextcluster = nextcluster - do - local node = node - for j = cluster,nextcluster-1 do - local id = getid(node) - if id == glyph_t or (id == glue_t and getsubtype(node) == spaceskip_t) then - local code = codes[j + 1] - hex = hex..to_utf16_hex(code) - str = str..utf8.char(code) - end + local glyph + -- The following is a repeat {...} while glyph {...} loop. + while true do + repeat + i = i+1 + glyph = glyphs[i] + until not glyph or glyph.cluster ~= cluster + do + local oldcluster = cluster + cluster = glyph and glyph.cluster or offset + len + if oldcluster then + for _ = oldcluster+1, cluster do + node = getnext(node) end - glyph.tounicode = hex - glyph.string = str end - if not fordisc then - local discindex = nil - local disc = node - for j = cluster + 1, nextcluster do - local props = properties[disc] - if (not (props and props.zwnj)) and getid(disc) == disc_t then - discindex = j - break + end + + -- Is this a safe breakpoint? + if discs and ((not glyph) or codes[cluster] == 0x20 or codes[cluster+1] == 0x20 or codes[cluster+1] == 0xFFFC + or not unsafetobreak(glyph)) then + -- Should we change the discretionary state? + local anchor_cluster, after_cluster = offset + discs.anchor_cluster, offset + discs.after_cluster + local saved_anchor, saved_after = (discs.next and discs.next.anchor_cluster or math.huge) + offset + while disc_cluster and after_cluster <= cluster + or not disc_cluster and anchor_cluster <= cluster do + if disc_cluster then + if not saved_after and saved_anchor < cluster then + saved_after = discs.next.after_cluster + offset + if saved_after > cluster then + saved_after, after_cluster = after_cluster, saved_after + break + end + elseif saved_after then + saved_after, after_cluster = after_cluster, saved_after end - disc = getnext(disc) - end - if discindex then - -- Discretionary found. - local startindex, stopindex = nil, nil - local startglyph, stopglyph = nil, nil - - -- Find the previous glyph that is safe to break at. - local startglyph = i - while startglyph > 1 - and codes[glyphs[startglyph - 1].cluster + 1] ~= 0x20 - and codes[glyphs[startglyph - 1].cluster + 1] ~= 0xFFFC - and (unsafetobreak(glyphs[startglyph]) - or glyphs[startglyph].cluster == glyphs[startglyph-1].cluster) do - startglyph = startglyph - 1 + local rep_glyphs = table.move(glyphs, disc_glyph, i - 1, 1, {}) + for j = 1, #rep_glyphs do + local glyph = rep_glyphs[j] + glyph.cluster = glyph.cluster - disc_cluster + glyph.nextcluster = glyph.nextcluster - disc_cluster end - -- Get the corresponding character index. - startindex = glyphs[startglyph].cluster + 1 - - -- Find the next glyph that is safe to break at. - stopglyph = i + 1 - local lastcluster = glyphs[i].cluster - while stopglyph <= #glyphs - and codes[glyphs[stopglyph].cluster + 1] ~= 0x20 - and codes[glyphs[stopglyph].cluster + 1] ~= 0xFFFC - and (unsafetobreak(glyphs[stopglyph]) - or lastcluster == glyphs[stopglyph].cluster) do - lastcluster = glyphs[stopglyph].cluster - stopglyph = stopglyph + 1 + do + local cluster_offset = disc_cluster - cluster + (saved_after and 2 or 1) -- The offset the glyph indices will move + for j = i, #glyphs do + local glyph = glyphs[j] + glyph.cluster = glyph.cluster + cluster_offset + end + len = len + cluster_offset + table.move(glyphs, i, #glyphs + i - disc_glyph, disc_glyph + (saved_after and 2 or 1)) + + local discs = discs.next + while discs do + discs.anchor_cluster = discs.anchor_cluster + cluster_offset + discs.after_cluster = discs.after_cluster + cluster_offset + discs = discs.next + end end - stopindex = stopglyph <= #glyphs and glyphs[stopglyph].cluster + 1 - or offset + len - - local startnode, stopnode = node, node - for j=nodeindex - 1, startindex, -1 do - startnode = getprev(startnode) + local pre, post, _, _, lastpost, _ = getdisc(discs.disc, true) + local precodes, postcodes, repcodes = {}, {} + table.move(codes, disc_cluster + 1, anchor_cluster, 1, precodes) + for n in traverse(pre) do + precodes[#precodes + 1] = is_char(n, fontid) or 0xFFFC end - for j=nodeindex + 1, stopindex do - stopnode = getnext(stopnode) + for n in traverse(post) do + postcodes[#postcodes + 1] = is_char(n, fontid) or 0xFFFC end + table.move(codes, after_cluster + 1, cluster, #postcodes + 1, postcodes) - glyphs[startglyph] = glyph - glyph.cluster = startindex - 1 - glyph.nextcluster = startindex - for j = stopglyph, #glyphs do - local glyph = glyphs[j] - glyph.cluster = glyph.cluster - (stopindex - startindex) + 1 + if saved_after then + repcodes = table.move(codes, disc_cluster + 1, cluster, 1, {}) + table.move(codes, cluster + 1, #codes + cluster - disc_cluster, disc_cluster + 3) + codes[disc_cluster + 1], codes[disc_cluster + 2] = 0xFFFC, 0xFFFC + else + table.move(codes, cluster + 1, #codes + cluster - disc_cluster, disc_cluster + 2) + codes[disc_cluster + 1] = 0xFFFC end - len = len - (stopindex - startindex) + 1 - table.move(glyphs, stopglyph, #glyphs + stopglyph - startglyph - 1, startglyph + 1) - local subcodes, subindex = {} do - local node = startnode - while node ~= stopnode do - if node == disc then - subindex = #subcodes - startindex = startindex + 1 - node = getnext(node) - elseif getid(node) == disc_t then - local oldnode = node - startnode, node = removenode(startnode, node) - freenode(oldnode) - tableremove(codes, startindex) - else - subcodes[#subcodes + 1] = tableremove(codes, startindex) - node = getnext(node) - end + local iter = disc_node + for _ = disc_cluster, anchor_cluster-1 do iter = getnext(iter) end + if iter ~= disc_node then + local newpre = copynodelist(disc_node, iter) + setlink(tail(newpre), pre) + pre = newpre + end + for _ = anchor_cluster, after_cluster-1 do iter = getnext(iter) end + if post then + setlink(lastpost, copynodelist(iter, node)) + else + post = copynodelist(iter, node) end end - - local pre, post, rep, lastpre, lastpost, lastrep = getdisc(disc, true) - local precodes, postcodes, repcodes = {}, {}, {} - table.move(subcodes, 1, subindex, 1, repcodes) - for n, id, subtype in traverse(rep) do - repcodes[#repcodes + 1] = getfont(n) == fontid and getchar(n) or 0xFFFC - end - table.move(subcodes, subindex + 1, #subcodes, #repcodes + 1, repcodes) - table.move(subcodes, 1, subindex, 1, precodes) - for n, id, subtype in traverse(pre) do - precodes[#precodes + 1] = getfont(n) == fontid and getchar(n) or 0xFFFC - end - for n, id, subtype in traverse(post) do - postcodes[#postcodes + 1] = getfont(n) == fontid and getchar(n) or 0xFFFC - end - table.move(subcodes, subindex + 1, #subcodes, #postcodes + 1, postcodes) - if startnode ~= disc then - local newpre = copynodelist(startnode, disc) - setnext(tail(newpre), pre) - pre = newpre + local prev = getprev(disc_node) + if disc_cluster ~= cluster then + setprev(disc_node, nil) + setnext(getprev(node), nil) end - if post then - setnext(lastpost, copynodelist(getnext(disc), stopnode)) - else - post = copynodelist(getnext(disc), stopnode) + setlink(prev, discs.disc, node) + if disc_node == firstnode then + firstnode = discs.disc + if head == disc_node then + head = firstnode + end end - if startnode ~= disc then - local predisc = getprev(disc) - setnext(predisc, rep) - setprev(rep, predisc) - if firstnode == startnode then - firstnode = disc + glyphs[disc_glyph] = { + replace = { + glyphs = rep_glyphs, + head = disc_node ~= node and disc_node or nil, + run = { + start = 1, + font = run.font, + dir = run.dir, + }, + }, + pre = makesub(run, precodes, pre), + post = makesub(run, postcodes, post), + cluster = disc_cluster, + nextcluster = disc_cluster + 1, + codepoint = 0xFFFC, + } + if saved_after then + local next_disc = discs.next + setlink(discs.disc, next_disc.disc, node) + local next_pre, next_post, _, _, next_lastpost, _ = getdisc(next_disc.disc, true) + local next_rep = copynodelist(next_pre) + -- Let's play the game again. We need three parts: + -- The pre and post branches in the outer post branch + local next_precodes, next_postcodes, next_repcodes = {}, {}, {} + do + local saved_offset = length(post) - cluster + local saved_anchor, saved_after = saved_anchor + saved_offset, saved_after + saved_offset + table.move(postcodes, 1, saved_anchor, 1, next_precodes) + for n in traverse(next_pre) do + next_precodes[#next_precodes + 1] = is_char(n, fontid) or 0xFFFC + end + for n in traverse(next_post) do + next_postcodes[#next_postcodes + 1] = is_char(n, fontid) or 0xFFFC + end + table.move(postcodes, saved_after + 1, #postcodes, #next_postcodes + 1, next_postcodes) + + local iter = post + for _ = 1, saved_anchor do iter = getnext(iter) end + if iter ~= post then + local newpre = copynodelist(post, iter) + setlink(tail(newpre), next_pre) + next_pre = newpre + end + for _ = saved_anchor, saved_after - 1 do iter = getnext(iter) end + if next_post then + setlink(next_lastpost, copynodelist(iter)) + else + next_post = copynodelist(iter) + end end - if startnode == head then - head = disc - else - local before = getprev(startnode) - setnext(before, disc) - setprev(disc, before) + -- The pre branch in the outer replace branch. The post branch is implicitly the same as the previous one + do + local saved_anchor = saved_anchor - disc_cluster + table.move(repcodes, 1, saved_anchor, 1, next_repcodes) + for n in traverse(next_rep) do + next_repcodes[#next_repcodes + 1] = is_char(n, fontid) or 0xFFFC + end + + local rep = glyphs[disc_glyph].replace.head + local iter = rep + for _ = 1, saved_anchor do iter = getnext(iter) end + if iter ~= rep then + local newpre = copynodelist(rep, iter) + setlink(tail(newpre), next_rep) + next_rep = newpre + end end - setprev(startnode, nil) - rep = startnode - lastrep = lastrep or predisc + setsubtype(discs.disc, firstdisc_t) + setsubtype(next_disc.disc, seconddisc_t) + discs = discs.next + disc_glyph = disc_glyph + 1 + disc_cluster = disc_cluster + 1 + glyphs[disc_glyph] = { + replace = makesub(run, next_repcodes, next_rep), + pre = makesub(run, next_precodes, next_pre), + post = makesub(run, next_postcodes, next_post), + cluster = disc_cluster, + nextcluster = disc_cluster + 1, + codepoint = 0xFFFC, + } + end + i = disc_glyph + 1 + assert(node == getnext(discs.disc)) + cluster = disc_cluster + 1 + + disc_cluster = nil + discs = discs.next + while discs and discs.anchor_cluster + offset < cluster do + freenode(discs.disc) + discs = discs.next end - if getnext(disc) ~= stopnode then - setnext(getprev(stopnode), nil) - setprev(stopnode, disc) - setprev(getnext(disc), lastrep) - setnext(lastrep, getnext(disc)) - rep = rep or getnext(disc) - setnext(disc, stopnode) + if not discs then break end + anchor_cluster, after_cluster = offset + discs.anchor_cluster, offset + discs.after_cluster + saved_anchor, saved_after = (discs.next and discs.next.anchor_cluster or math.huge) + offset + elseif anchor_cluster == cluster then + disc_glyph, disc_cluster, disc_node = i, cluster, node + else + disc_glyph, disc_cluster, disc_node = break_glyph, break_cluster, break_node + end + end + break_glyph, break_cluster, break_node = i, cluster, node + end + + if not glyph then break end + + local nextcluster + for j = i+1, #glyphs do + nextcluster = glyphs[j].cluster + if cluster ~= nextcluster then + glyph.nglyphs = j - i + goto NEXTCLUSTERFOUND -- break + end + end -- else -- only executed if the loop reached the end without + -- finding another cluster + nextcluster = offset + len + glyph.nglyphs = #glyphs + 1 - i + ::NEXTCLUSTERFOUND:: -- end + glyph.nextcluster = nextcluster + + local disc, discindex + -- Calculate the Unicode code points of this glyph. If cluster did not + -- change then this is a glyph inside a complex cluster and will be + -- handled with the start of its cluster. + do + local hex = "" + local str = "" + local node = node + for j = cluster+1,nextcluster do + local char, id = is_char(node, fontid) + if char then + -- assert(char == codes[j]) + hex = hex .. to_utf16_hex(char) + str = str .. utf8.char(char) + elseif not discindex and id == disc_t then + local props = properties[disc] + if not (props and props.zwnj) then + disc, discindex = node, j end - glyph.replace = makesub(run, repcodes, rep) - glyph.pre = makesub(run, precodes, pre) - glyph.post = makesub(run, postcodes, post) - i = startglyph - node = disc - cluster = glyph.cluster - nodeindex = cluster + 1 end + node = getnext(node) end + glyph.tounicode = hex + glyph.string = str + end + if not fordisc and discindex then end end return head, firstnode, glyphs, run.len - len @@ -587,7 +698,7 @@ local function color_to_rgba(color) end end --- Cache of color glyph PNG data for bookkeeping, only because I couldn’t +-- Cache of color glyph PNG data for bookkeeping, only because I couldn't -- figure how to make the engine load the image from the binary data directly. local pngcache = {} local pngcachefiles = {} @@ -672,7 +783,7 @@ local function tonodes(head, node, run, glyphs) end local gid = glyph.codepoint local char = nominals[gid] or gid_offset + gid - local id = getid(node) + local orig_char, id = is_char(node, fontid) if glyph.replace then -- For discretionary the glyph itself is skipped and a discretionary node @@ -681,17 +792,12 @@ local function tonodes(head, node, run, glyphs) setdisc(node, tonodes(pre.head, pre.head, pre.run, pre.glyphs), tonodes(post.head, post.head, post.run, post.glyphs), - tonodes(rep.head, rep.head, rep.run, rep.glyphs)) + (tonodes(rep.head, rep.head, rep.run, rep.glyphs))) node = getnext(node) nodeindex = nodeindex + 1 - elseif glyph.skip then - local oldnode = node - head, node = removenode(head, node) - freenode(oldnode) - nodeindex = nodeindex + 1 else if lastprops and lastprops.zwnj and nodeindex == glyph.cluster + 1 then - elseif id == glyph_t then + elseif orig_char then local done local fontglyph = fontglyphs[gid] local character = characters[char] @@ -717,7 +823,7 @@ local function tonodes(head, node, run, glyphs) character.depth = layerchar.depth end -- color_index has a special value, 0x10000, that mean use text - -- color, we don’t check for it here explicitly since we will + -- color, we don't check for it here explicitly since we will -- get nil anyway. local color = palette[layer.color_index] if not color or color.alpha ~= 0 then @@ -787,7 +893,7 @@ local function tonodes(head, node, run, glyphs) -- Color bitmap font with no glyph outlines (like Noto -- Color Emoji) but has no bitmap for current glyph (most likely -- `.notdef` glyph). The engine does not know how to embed such - -- fonts, so we don’t want them to reach the backend as it will cause + -- fonts, so we don't want them to reach the backend as it will cause -- a fatal error. We use `nullfont` instead. That is a hack, but I -- think it is good enough for now. We could make the glyph virtual -- with empty commands suh that LuaTeX ignores it, but we still want @@ -799,7 +905,7 @@ local function tonodes(head, node, run, glyphs) end end if not done then - local oldcharacter = characters[getchar(node)] + local oldcharacter = characters[orig_char] -- If the glyph index of current font character is the same as shaped -- glyph, keep the node char unchanged. Helps with primitives that -- take characters as input but actually work on glyphs, like @@ -824,7 +930,7 @@ local function tonodes(head, node, run, glyphs) -- overfull messages, otherwise it will be trying to print our -- invalid pseudo Unicode code points. -- If the string is empty it means this glyph is part of a larger - -- cluster and we don’t to print anything for it as the first glyph + -- cluster and we don't to print anything for it as the first glyph -- in the cluster will have the string of the whole cluster. local props = properties[node] if not props then @@ -837,7 +943,7 @@ local function tonodes(head, node, run, glyphs) -- * Find how many characters in this cluster and how many glyphs, -- * If there is more than 0 characters -- * One glyph: one to one or one to many mapping, can be - -- represented by font’s /ToUnicode + -- represented by font's /ToUnicode -- * More than one: many to one or many to many mapping, can be -- represented by /ActualText spans. -- * If there are zero characters, then this glyph is part of complex @@ -883,7 +989,7 @@ local function tonodes(head, node, run, glyphs) end elseif id == kern_t and getsubtype(node) == italiccorr_t then -- If this is an italic correction node and the previous node is a - -- glyph, update its kern value with the glyph’s italic correction. + -- glyph, update its kern value with the glyph's italic correction. local prevchar, prevfontid = ischar(getprev(node)) if prevfontid == fontid and prevchar and prevchar > 0 then local italic = characters[prevchar].italic @@ -919,8 +1025,8 @@ local function shape_run(head, current, run) end function process(head, font, _attr, direction) - local newhead, current = head, head - local runs = itemize(head, font, direction) + local newhead, runs = itemize(head, font, direction) + local current = newhead local offset = 0 for i = 1,#runs do @@ -954,29 +1060,39 @@ local function post_process(head) if startactual then local actualtext = "/Span<</ActualText<FEFF"..startactual..">>>BDC" head = insertbefore(head, n, pageliteral(actualtext)) + props[startactual_p] = nil end if endactual then head = insertafter(head, n, pageliteral("EMC")) + props[endactual_p] = nil end local replace = getfield(n, "replace") if replace then setfield(n, "replace", post_process(replace)) end + end + return head +end - local subhead = getfield(n, "head") - if subhead then - setfield(n, "head", post_process(subhead)) +local function post_process_vlist(head) + for n, id, subtype, list in traverse_list(head) do + if id == hlist_t and subtype == line_t then + setlist(n, post_process(list)) end end - return head + return true end -local function post_process_nodes(head, groupcode) +local function post_process_nodes(head) return tonode(post_process(todirect(head))) end +local function post_process_vlist_nodes(head) + return tonode(post_process_vlist(todirect(head))) +end + local function run_cleanup() -- Remove temporary PNG files that we created, if any. -- FIXME: It would be nice if we wouldn't need this @@ -1032,29 +1148,10 @@ end fonts.handlers.otf.registerplugin('harf', process) --- luatexbase does not know how to handle `wrapup_run` callback, teach it. --- TODO: Move these into ltluatex -luatexbase.callbacktypes.wrapup_run = 1 -- simple -luatexbase.callbacktypes.glyph_info = 1 -- simple - -local base_callback_descriptions = luatexbase.callback_descriptions -local base_add_to_callback = luatexbase.add_to_callback -local base_remove_from_callback = luatexbase.remove_from_callback - --- Remove all existing functions from given callback, insert ours, then --- reinsert the removed ones, so ours takes a priority. -local function add_to_callback(name, func) - local saved_callbacks = {}, ff, dd - for k, v in next, base_callback_descriptions(name) do - saved_callbacks[k] = { base_remove_from_callback(name, v) } - end - base_add_to_callback(name, func, "Harf "..name.." callback") - for _, v in next, saved_callbacks do - base_add_to_callback(name, v[1], v[2]) - end -end +local add_to_callback = luatexbase.add_to_callback -add_to_callback('pre_output_filter', post_process_nodes) -- FIXME: Wrong callback, but I want to get rid of the whole function anyway -add_to_callback('wrapup_run', run_cleanup) -add_to_callback('finish_pdffile', set_tounicode) -add_to_callback('glyph_info', get_glyph_info) +add_to_callback('post_linebreak_filter', post_process_vlist_nodes, 'luaotfload.harf.finalize_vlist') +add_to_callback('hpack_filter', post_process_nodes, 'luaotfload.harf.finalize_hlist') +add_to_callback('wrapup_run', run_cleanup, 'luaotfload.cleanup_files') +add_to_callback('finish_pdffile', set_tounicode, 'luaotfload.harf.finalize_unicode') +add_to_callback('glyph_info', get_glyph_info, 'luaotfload.glyphinfo') diff --git a/macros/luatex/generic/luaotfload/luaotfload-init.lua b/macros/luatex/generic/luaotfload/luaotfload-init.lua index cfbcb68eab..3b67738fe5 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-init.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-init.lua @@ -5,17 +5,13 @@ -- AUTHOR: Philipp Gesang (Phg), <phg@phi-gamma.net>, Marcel Krüger ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-init", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / initialization", license = "GPL v2.0" } - -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end ----------------------------------------------------------------------- @@ -299,7 +295,6 @@ local function init_main(early_hook) local saved_exit = os.exit local errmsg function texio.reporter(msg, ...) - print(...) errmsg = msg end function os.exit() @@ -407,6 +402,11 @@ local function init_main(early_hook) -- fontloader end --- [init_main] +if not luatexbase.callbacktypes.pre_shaping_filter then + luatexbase.create_callback('pre_shaping_filter', 'list') + luatexbase.create_callback('post_shaping_filter', 'reverselist') +end + local init_post_install_callbacks = function () --[[doc-- @@ -423,17 +423,42 @@ local init_post_install_callbacks = function () local fallback = luaotfload.loaders.luaotfload "fallback".process local multiscript = luaotfload.loaders.luaotfload "multiscript".process - -- MK Pass current text direction to simple_font_handler + local call_callback = luatexbase.call_callback + local tex_get = tex.get + local flush_list = node.flush_list local handler = luaotfload.fontloader.nodes.simple_font_handler - local callback = function(head, groupcode, _, _, direction) + local function callback(head, groupcode, _, _, direction) if not direction then - direction = tex.get'textdirection' + direction = tex_get'textdirection' else direction = direction == "TRT" and 1 or 0 end + local result = call_callback("pre_shaping_filter", head, groupcode, direction) + if result == false then + return false + elseif result ~= true then + head = result + end multiscript(head, nil, nil, nil, direction) fallback(head, nil, nil, nil, direction) - return handler(head, groupcode, nil, nil, direction) + result = handler(head, groupcode, nil, nil, direction) + -- handler never returns a boolean and only returns nil if it was passed in + -- We keep it general though for consistency + if result == false then + flush_list(head) + return nil + elseif result ~= true then + head = result + end + result = call_callback("post_shaping_filter", head, groupcode, direction) + if result == false then + flush_list(head) + return nil + elseif result == true then + return head + else + return result + end end luatexbase.add_to_callback("pre_linebreak_filter", callback, @@ -443,7 +468,6 @@ local init_post_install_callbacks = function () callback, "luaotfload.node_processor", 1) - -- /MK local streams = fonts.hashes.streams luatexbase.add_to_callback("glyph_stream_provider",function(id,index,mode) diff --git a/macros/luatex/generic/luaotfload/luaotfload-latex.pdf b/macros/luatex/generic/luaotfload/luaotfload-latex.pdf Binary files differindex df1a8e0e86..299ff211aa 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-latex.pdf +++ b/macros/luatex/generic/luaotfload/luaotfload-latex.pdf diff --git a/macros/luatex/generic/luaotfload/luaotfload-latex.tex b/macros/luatex/generic/luaotfload/luaotfload-latex.tex index dcf6507881..40b01af0de 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-latex.tex +++ b/macros/luatex/generic/luaotfload/luaotfload-latex.tex @@ -260,7 +260,7 @@ local stringsub = string.sub local stringgsub = string.gsub %local backslash = unicode.utf8.char (0x200c) - local backslash = unicode.utf8.char (0x5c) + local backslash = string.char(0x5c) local escaped = [[\string\string\string\]] document.printlines = function (buffer) local lines = string.explode (buffer, "\noexpand\n") diff --git a/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua b/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua index f9c24a1335..c1a3d6f1b7 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-letterspace.lua @@ -3,20 +3,16 @@ -- DESCRIPTION: part of luaotfload / letterspacing ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-letterspace", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / letterspacing", license = "GPL v2.0", copyright = "PRAGMA ADE / ConTeXt Development Team", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL; adapted by Philipp Gesang, Ulrike Fischer, Marcel Krüger" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - --- This code diverged quite a bit from its origin in Context. Please --- do *not* report bugs on the Context list. diff --git a/macros/luatex/generic/luaotfload/luaotfload-loaders.lua b/macros/luatex/generic/luaotfload/luaotfload-loaders.lua index a63506237a..84c5555f5d 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-loaders.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-loaders.lua @@ -6,17 +6,13 @@ -- AUTHOR: Hans Hagen, Khaled Hosny, Elie Roux, David Carlisle ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-loaders", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / callback handling", license = "GPL v2.0" } - -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end ----------------------------------------------------------------------- diff --git a/macros/luatex/generic/luaotfload/luaotfload-log.lua b/macros/luatex/generic/luaotfload/luaotfload-log.lua index b102da65bf..58fc403e62 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-log.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-log.lua @@ -4,21 +4,16 @@ ------------------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-log", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / logging", license = "GPL v2.0", author = "Khaled Hosny, Elie Roux, Philipp Gesang", copyright = "Luaotfload Development Team", } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - - --[[doc-- The logging system is slow in general, as we always have the function call overhead even if we aren’t going to output anything. On the other diff --git a/macros/luatex/generic/luaotfload/luaotfload-main.lua b/macros/luatex/generic/luaotfload/luaotfload-main.lua index 5fa8c54ad3..1b029bd514 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-main.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-main.lua @@ -1,341 +1,6 @@ ----------------------------------------------------------------------- -- FILE: luaotfload-main.lua --- DESCRIPTION: OpenType layout system / luaotfload entry point --- REQUIREMENTS: luatex v.0.95.0 or later; package lualibs --- AUTHOR: Élie Roux, Khaled Hosny, Philipp Gesang, Ulrike Fischer, Marcel Krüger +-- DESCRIPTION: OpenType layout system / compatibility wrapper ----------------------------------------------------------------------- -local authors = "\z - Hans Hagen,\z - Khaled Hosny,\z - Elie Roux,\z - Will Robertson,\z - Philipp Gesang,\z - Dohyun Kim,\z - Reuben Thomas,\z - David Carlisle,\ - Ulrike Fischer,\z - Marcel Krüger\z -" --- version number is used below! -local ProvidesLuaModule = { - name = "luaotfload-main", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE - description = "luaotfload entry point", - author = authors, - copyright = authors, - license = "GPL v2.0" -} - -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - -local osgettimeofday = os.gettimeofday -config = config or { } -luaotfload = luaotfload or { } -local luaotfload = luaotfload -luaotfload.log = luaotfload.log or { } -local logreport -luaotfload.version = ProvidesLuaModule.version -luaotfload.loaders = { } -luaotfload.fontloader_package = "reference" --- default: from current Context - -if not tex or not tex.luatexversion then - error "this program must be run in TeX mode" --- or call tex.initialize() =) -end - ---- version check -local revno = tonumber(tex.luatexrevision) -local minimum = { 110, 0 } -if tex.luatexversion < minimum[1] or tex.luatexversion == minimum[1] and revno < minimum[2] then - texio.write_nl ("term and log", - string.format ("\tFATAL ERROR\n\z - \tLuaotfload requires a Luatex version >= %d.%d.%d.\n\z - \tPlease update your TeX distribution!\n\n", - math.floor(minimum[1] / 100), minimum[1] % 100, minimum[2])) - error "version check failed" -end - -if not utf8 then - texio.write_nl("term and log", string.format("\z - \tluaotfload: module utf8 is unavailable\n\z - \tutf8 is available in Lua 5.3+; engine\'s _VERSION is %q\n\z - \tThis probably means that the engine is not supported\n\z - \n", - _VERSION)) - error "module utf8 is unavailable" -end - -if status.safer_option ~= 0 then - texio.write_nl("term and log","luaotfload can't run with option --safer. Aborting") - error("safer_option used") -end - - - - ---[[doc-- - - This file initializes the system and loads the font loader. To - minimize potential conflicts between other packages and the code - imported from \CONTEXT, several precautions are in order. Some of - the functionality that the font loader expects to be present, like - raw access to callbacks, are assumed to have been disabled by - \identifier{luatexbase} when this file is processed. In some cases - it is possible to trick it by putting dummies into place and - restoring the behavior from \identifier{luatexbase} after - initilization. Other cases such as attribute allocation require - that we hook the functionality from \identifier{luatexbase} into - locations where they normally wouldn’t be. - - Anyways we can import the code base without modifications, which is - due mostly to the extra effort by Hans Hagen to make \LUATEX-Fonts - self-contained and encapsulate it, and especially due to his - willingness to incorporate our suggestions. - ---doc]]-- - -local luatexbase = luatexbase -local require = require -local type = type - - ---[[doc-- - - \subsection{Module loading} - We load the files imported from \CONTEXT with function derived this way. It - automatically prepends a prefix to its argument, so we can refer to the - files with their actual \CONTEXT name. - ---doc]]-- - -local function make_loader_name (prefix, name) - local msg = luaotfload.log and luaotfload.log.report - or function (stream, lvl, cat, ...) - if lvl > 1 then --[[not pressing]] return end - texio.write_nl ("log", - string.format ("luaotfload | %s : ", - tostring (cat))) - texio.write (string.format (...)) - end - if not name then - msg ("both", 0, "load", - "Fatal error: make_loader_name (%q, %q).", - tostring (prefix), tostring (name)) - return "dummy-name" - end - name = tostring (name) - if prefix == false then - msg ("log", 9, "load", - "No prefix requested, passing module name %q unmodified.", - name) - return tostring (name) .. ".lua" - end - prefix = tostring (prefix) - msg ("log", 9, "load", - "Composing module name from constituents %s, %s.", - prefix, name) - return prefix .. "-" .. name .. ".lua" -end - -local timing_info = { - t_load = { }, - t_init = { }, -} - -local function make_loader (prefix, load_helper) - return function (name) - local t_0 = osgettimeofday () - local modname = make_loader_name (prefix, name) - --- We don’t want the stack info from inside, so just pcall(). - local ok, data = pcall (load_helper or require, modname) - local t_end = osgettimeofday () - timing_info.t_load [name] = t_end - t_0 - if not ok then - io.write "\n" - local msg = luaotfload.log and luaotfload.log.report or print - msg ("both", 0, "load", "FATAL ERROR") - msg ("both", 0, "load", " × Failed to load %q module %q.", - tostring (prefix), tostring (name)) - local lines = string.split (data, "\n\t") - if not lines then - msg ("both", 0, "load", " × Error message: %q", data) - else - msg ("both", 0, "load", " × Error message:") - for i = 1, #lines do - msg ("both", 0, "load", " × %q.", lines [i]) - end - end - io.write "\n\n" - local debug = debug - if debug then - io.write (debug.traceback()) - io.write "\n\n" - end - os.exit(-1) - end - return data - end -end - ---[[doc-- - Certain files are kept around that aren’t loaded because they are part of - the imported fontloader. In order to keep the initialization structure - intact we also provide a no-op version of the module loader that can be - called in the expected places. ---doc]]-- - -local function dummy_loader (name) - luaotfload.log.report ("log", 3, "load", - "Skipping module %q on purpose.", - name) -end - -local context_environment = setmetatable({}, {__index = _G}) -luaotfload.fontloader = context_environment -local function context_isolated_load(name) - local fullname = kpse.find_file(name, 'lua') - if not fullname then - error(string.format('Fontloader module %q could not be found.', name)) - end - return assert(loadfile(fullname, nil, context_environment))(name) -end - -local function context_loader (name, path) - luaotfload.log.report ("log", 3, "load", - "Loading module %q from Context.", - name) - local t_0 = osgettimeofday () - local modname = make_loader_name (false, name) - local modpath = modname - if path then - if lfs.isdir (path) then - luaotfload.log.report ("log", 3, "load", - "Prepending path %q.", - path) - modpath = file.join (path, modname) - else - luaotfload.log.report ("both", 0, "load", - "Non-existant path %q specified, ignoring.", - path) - end - end - local ret = context_isolated_load (modpath) - local t_end = osgettimeofday () - timing_info.t_load [name] = t_end - t_0 - - if ret ~= nil then - --- require () returns “true” upon success unless the loaded file - --- yields a non-zero exit code. This isn’t per se indicating that - --- something isn’t right, but against HH’s coding practices. We’ll - --- silently ignore this ever happening on lower log levels. - luaotfload.log.report ("log", 4, "load", - "Module %q returned %q.", modname, ret) - end - return ret -end - -local function install_loaders () - local loaders = { } - local loadmodule = make_loader "luaotfload" - loaders.luaotfload = loadmodule - loaders.fontloader = make_loader ("fontloader", context_isolated_load) - loaders.context = context_loader - loaders.ignore = dummy_loader -----loaders.plaintex = make_loader "luatex" --=> for Luatex-Plain - - function loaders.initialize (name) - local tmp = loadmodule (name) - local init = type(tmp) == "table" and tmp.init or tmp - if init and type (init) == "function" then - local t_0 = osgettimeofday () - if not init () then - logreport ("log", 0, "load", - "Failed to load module %q.", name) - return - end - local t_end = osgettimeofday () - local d_t = t_end - t_0 - logreport ("log", 4, "load", - "Module %q loaded in %g ms.", - name, d_t * 1000) - timing_info.t_init [name] = d_t - end - end - - return loaders -end - -local luaotfload_initialized = false --- prevent multiple invocations - -luaotfload.main = function () - - if luaotfload_initialized then - logreport ("log", 0, "load", - "Luaotfload initialization requested but is already \z - loaded, ignoring.") - return - end - luaotfload_initialized = true - - luaotfload.loaders = install_loaders () - local loaders = luaotfload.loaders - local loadmodule = loaders.luaotfload - local initialize = loaders.initialize - - local starttime = osgettimeofday () - - -- Feature detect HarfBuzz. This is done early to allow easy HarfBuzz - -- detection in other modules - local harfstatus, harfbuzz = pcall(require, 'luaharfbuzz') - if harfstatus then - luaotfload.harfbuzz = harfbuzz - end - - local init = loadmodule "init" --- fontloader initialization - init (function () - - logreport = luaotfload.log.report - initialize "parsers" --- fonts.conf and syntax - initialize "configuration" --- configuration options - end) - - initialize "loaders" --- Font loading; callbacks - initialize "database" --- Font management. - initialize "colors" --- Per-font colors. - - local init_resolvers = loadmodule "resolvers" --- Font lookup - init_resolvers () - - if not config.actions.reconfigure () then - logreport ("log", 0, "load", "Post-configuration hooks failed.") - end - - initialize "features" --- font request and feature handling - - if harfstatus then - loadmodule "harf-define" - loadmodule "harf-plug" - end - loadmodule "letterspace" --- extra character kerning - loadmodule "embolden" --- fake bold - loadmodule "notdef" --- missing glyph handling - loadmodule "suppress" --- suppress ligatures by adding ZWNJ - loadmodule "szss" --- missing glyph handling - initialize "auxiliary" --- additional high-level functionality - loadmodule "tounicode" - if tex.outputmode == 0 then - loadmodule "dvi" --- allow writing fonts to DVI files - end - - luaotfload.aux.start_rewrite_fontname () --- to be migrated to fontspec - - logreport ("log", 1, "main", - "initialization completed in %0.3f seconds\n", - osgettimeofday() - starttime) -----inspect (timing_info) -end - --- vim:tw=79:sw=4:ts=4:et +return require'luaotfload' diff --git a/macros/luatex/generic/luaotfload/luaotfload-main.tex b/macros/luatex/generic/luaotfload/luaotfload-main.tex index a1f79b7da4..d1f698f684 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-main.tex +++ b/macros/luatex/generic/luaotfload/luaotfload-main.tex @@ -32,7 +32,7 @@ \beginfrontmatter \setdocumenttitle {The \identifier{luaotfload} package} - \setdocumentdate {2020-09-02 v3.15} + \setdocumentdate {2020-12-31 v3.16} \setdocumentauthor {LaTeX3 Project\\ Elie Roux · Khaled Hosny · Philipp Gesang · Ulrike Fischer · Marcel Krüger\\ Home: \hyperlink {https://github.com/latex3/luaotfload}} @@ -62,6 +62,30 @@ Supported is the \identifier{luatex} versions of a current TeXLive 2019 (and a c \endsection \beginsection{Changes} +\beginsubsection {New in version 3.16 (by Ulrike Fischer/Marcel Krüger)} +\begin{itemize} + \item The entry point is called \identifier{luaotfload.lua} instead of + \identifier{luaotfload-main.lua} (but the old name is still provided for compatibility). + \item \inlinecode{pre/post_shaping_filter} callbacks has been added. + \item The number of \abbrev{lua}-files and submodules shown in the \abbrev{log}-file has been reduced. But it + is extended again by setting the environment variable \inlinecode{LUAOTFLOAD_TRACE_SUBMODULES=1}. + \item The HarfBuzz based shaper will in some situations drop hyphenation + points. This happens less frequently now since the new version uses + first/second discretionaries (the mechanism described in the LuaTeX manual, + section 5.6 for the of-f-ice example) to support a limited amount of + nesting. + \item When the \texttt{node} shaper is used, experimental support for OpenType variable + fonts has been added. To use them, set the font feature \texttt{axis} to + a comma separated list of axis names and values. (E.g. \texttt{axis={weight=600}}) + The supported axis names and value range depend on the font (see~page~\pageref{variablefonts}). + \item The font features \texttt{upper} and \texttt{lower} can be used to map + the text of a font to upper or lowercase before displaying it. Currently + this implements the untailored Unicode case mapping algorithm, but it is + planned to add tailoring later (see~page~\pageref{upperlower}). + \item A number of small bugfixes. + \end{itemize} +\endsubsection + \beginsubsection {New in version 3.15 (by Ulrike Fischer/Marcel Krüger)} \begin{itemize} \item The font database is updated more reliably if fonts get deleted. @@ -1166,8 +1190,8 @@ obviously, \inlinecode{random}. \endaltitem - \beginaltitem {multiscript}\phantomsection\label{multiscript} - In\marginpar{New in 3.12 -- experimental} fonts many shaping rules are implemented only for specific scripts and so you get correct typesetting only if the \identifier{script} feature is correctly set. This means that to write a text which uses more than one script you have to declare a font for each script and switch fonts even if the font contains glyphs for all scripts. + \beginaltitem {multiscript} + In\phantomsection\label{multiscript}\marginpar{New in 3.12 -- experimental} fonts many shaping rules are implemented only for specific scripts and so you get correct typesetting only if the \identifier{script} feature is correctly set. This means that to write a text which uses more than one script you have to declare a font for each script and switch fonts even if the font contains glyphs for all scripts. \identifier{multiscript} tries to help here. The feature is experimental and bound to change. Feedback is welcome but you use it at your risk. \identifier{multiscript} allows you to declare fonts for various script. The value is either \identifier{auto} described below, or a name which has been previously declared or a combination of both. An example for such a named multiscript could look like this (the colors are only for demonstration): @@ -1221,8 +1245,10 @@ obviously, \inlinecode{random}. \endaltitem - \beginaltitem {fallback}\label{fallback} - This\marginpar{New in 3.12 -- experimental} allows you to define a chain of fonts which are used if glyphs are missing in the main font. It works only for text fonts, not for math fonts set with the \identifier{unicode-math} package. + \beginaltitem {fallback} + This\label{fallback}\marginpar{New in 3.12 -- experimental} + allows you to define a chain of fonts which are used if glyphs are missing in the main font. + It works only for text fonts, not for math fonts set with the \identifier{unicode-math} package. The feature is experimental and bound to change. Feedback is welcome but you use it at your risk. For example @@ -1276,7 +1302,69 @@ obviously, \inlinecode{random}. As with the \identifier{multiscript} key more control over the used glyph and script in edge cases will be needed. \endaltitem -\enddescriptions + + \beginaltitem {upper/lower} + The\phantomsection\label{upperlower}\marginpar{New in 3.16} + font features \texttt{upper} and \texttt{lower} can be used to map + the text of a font to upper or lowercase before displaying it. Currently + this implements the untailored Unicode case mapping algorithm, but it is + planned to add tailoring later. For example + + \beginlisting + \font\test={name:LatinModernRoman:mode=node;+upper;} + \test Grüße + \endlisting + + {\Large\font\test={name:LatinModernRoman:mode=node;+upper;}\test Grüße} + + \endaltitem + + \beginaltitem {Variable fonts} + When\phantomsection\label{variablefonts}\marginpar{New in 3.16} + the \texttt{node} shaper is used, + experimental support for OpenType variable + fonts has been added. To use them, set the font feature \texttt{axis} to + a comma separated list of axis names and values. (E.g. \texttt{axis={weight=600}}) + The supported axis names and value range depend on the font (see~page~\pageref{variablefonts}). + The following listing shows an example with the Source Code Variable font: + + \begin{lstlisting}[columns=fullflexible] +\documentclass{article} + \DeclareFontFamily{TU}{sourcecode-variable}{} + \newcommand\DeclareSourceVariable[2]{% + \DeclareFontShape{TU}{sourcecode-variable}{#1}{n}{% + <-> \UnicodeFontFile{SourceCodeVariable-Roman.otf} + {\UnicodeFontTeXLigatures axis={weight=#2};}% + }{}% + \DeclareFontShape{TU}{sourcecode-variable}{#1}{it}{% + <-> \UnicodeFontFile{SourceCodeVariable-Italic.otf} + {\UnicodeFontTeXLigatures axis={weight=#2};}% + }{}% + } + \DeclareSourceVariable{ul}{200} + \DeclareSourceVariable{el}{250} + \DeclareSourceVariable{l}{300} + \DeclareSourceVariable{sl}{350} + \DeclareSourceVariable{m}{400} + \DeclareSourceVariable{sb}{500} + \DeclareSourceVariable{b}{600} + \DeclareSourceVariable{eb}{700} + \DeclareSourceVariable{ub}{900} + \begin{document} + \fontfamily{sourcecode-variable}\selectfont + \fontseries{ul}\selectfont a\textit{b} + \fontseries{el}\selectfont c\textit{d} + \fontseries{l}\selectfont e\textit{f} + \fontseries{sl}\selectfont g\textit{h} + \fontseries{m}\selectfont i\textit{j} + \fontseries{sb}\selectfont k\textit{l} + \fontseries{b}\selectfont m\textit{n} + \fontseries{eb}\selectfont o\textit{p} + \fontseries{ub}\selectfont q\textit{r} + \end{document} +\end{lstlisting} + + \enddescriptions \endsubsection @@ -1339,6 +1427,7 @@ Currently (2014) there are three of them: \enddescriptions \endsubsection + \endsection %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua b/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua index aae924c9de..a632ab4c6a 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-multiscript.lua @@ -3,19 +3,15 @@ -- DESCRIPTION: part of luaotfload / multiscript ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-multiscript", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / multiscript", license = "GPL v2.0", author = "Marcel Krüger" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - local nodenew = node.direct.new local getfont = font.getfont local setfont = node.direct.setfont diff --git a/macros/luatex/generic/luaotfload/luaotfload-notdef.lua b/macros/luatex/generic/luaotfload/luaotfload-notdef.lua index f2043a7ad7..7b9664fa7e 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-notdef.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-notdef.lua @@ -3,19 +3,15 @@ -- DESCRIPTION: part of luaotfload / notdef ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-notdef", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / notdef", license = "GPL v2.0", author = "Marcel Krüger" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - local harfbuzz = luaotfload.harfbuzz local flush_node = node.direct.flush_node local getfont = font.getfont diff --git a/macros/luatex/generic/luaotfload/luaotfload-parsers.lua b/macros/luatex/generic/luaotfload/luaotfload-parsers.lua index f321e9733f..7810c3a49e 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-parsers.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-parsers.lua @@ -5,19 +5,14 @@ -- AUTHOR: Philipp Gesang (Phg), <phg@phi-gamma.net>, Marcel Krüger ------------------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-parsers", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / parsers", license = "GPL v2.0" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - - local traversal_maxdepth = 42 --- prevent stack overflows local rawset = rawset diff --git a/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua b/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua index b7ca21ec87..2ea85de781 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-resolvers.lua @@ -9,19 +9,14 @@ --- The bare fontloader uses a set of simplistic file name resolvers --- that must be overloaded by the user (i. e. us). -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-resolvers", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / resolvers", license = "GPL v2.0" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - - if not lualibs then error "this module requires Luaotfload" end if not luaotfload then error "this module requires Luaotfload" end diff --git a/macros/luatex/generic/luaotfload/luaotfload-scripts.lua b/macros/luatex/generic/luaotfload/luaotfload-scripts.lua index 6ac19f14d5..b6c34b9e3e 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-scripts.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-scripts.lua @@ -3,19 +3,15 @@ -- DESCRIPTION: part of luaotfload / script ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-script", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / Script helpers", license = "CC0 1.0 Universal", author = "Marcel Krüger" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - local canonical_name = { dflt = "DFLT", hira = "kana", diff --git a/macros/luatex/generic/luaotfload/luaotfload-status.lua b/macros/luatex/generic/luaotfload/luaotfload-status.lua index dd38631cc8..0ad3c01ead 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-status.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-status.lua @@ -1,97 +1,99 @@ return { ["hashes"]={ - { "fontloader-2020-08-31.lua", "70a72561e3869bcaa8554921083b3872" }, - { "fontloader-util-fil.lua", "aae2a2add764144bb58dd8216fd59260" }, - { "fontloader-util-str.lua", "c975ff7bbd178163cf47d9e9296c8b4b" }, - { "fontloader-l-unicode.lua", "f368874f11f3c525de5864fd413e4b24" }, - { "fontloader-l-math.lua", "082add08e0bb79f39191ae9534a79849" }, - { "fontloader-l-boolean.lua", "abe28515dd33e8f6c416c09bca351cf8" }, - { "fontloader-l-file.lua", "352b42b8360ada02ceb26a41f0bd2a76" }, - { "fontloader-l-io.lua", "bbcc4824d0ded30b415d7d2d5763028a" }, - { "fontloader-l-table.lua", "0330da8b3a08d39876def70df8d9c0e5" }, - { "fontloader-l-string.lua", "9457f2af85723e0e6c46d0b5122e9000" }, - { "fontloader-l-function.lua", "a7e68a9703c35238729da41a474e951b" }, - { "fontloader-l-lpeg.lua", "10bdaef44175902917691835010ae5f5" }, - { "fontloader-l-lua.lua", "420bc442e6d81f4624728a6c56fcd175" }, - { "fontloader-fonts-gbn.lua", "10ecdf01e7c926e5128ad8a9dff4d677" }, - { "fontloader-fonts-lig.lua", "fbd251eea3810a43a8d5542319361d68" }, - { "fontloader-fonts-ext.lua", "32013cbc5d5d336be8b1d1e5879d86c4" }, - { "fontloader-fonts-def.lua", "f435e0875f203f343157baeff876ec9c" }, - { "fontloader-fonts-tfm.lua", "f0eb5e2a8068b17ad401bb7efdba1630" }, - { "fontloader-fonts-enc.lua", "5ff4ca50493d7c4ecea0e15c203099f0" }, - { "fontloader-fonts-mis.lua", "17e967c9ec4d001deefd43ddf25e98f7" }, - { "fontloader-basics-chr.lua", "64fafe4eaf55d64aead6513c1e74a024" }, - { "fontloader-basics-nod.lua", "335e61ffb6dec00f88f737854a2d9ab4" }, - { "fontloader-font-imp-effects.lua", "d9b935e9b73f250a175ddd71a226b8e9" }, - { "fontloader-font-imp-italics.lua", "ae563638fa29a4ff3e8e4d1e81fd35ae" }, - { "fontloader-font-imp-ligatures.lua", "26ffcf089391445f7af59536c8814364" }, - { "fontloader-font-imp-tex.lua", "ceb087ef6fa2f89aed7179f60ddf8f35" }, - { "fontloader-font-def.lua", "b9d908c2338b7dc443ce9d1e9fcb7139" }, - { "fontloader-font-lua.lua", "1fbfdf7b689b2bdfd0e3bb9bf74ce136" }, - { "fontloader-font-afk.lua", "9da14e0fb22129c053acc599d1312544" }, - { "fontloader-font-one.lua", "5a2f244c88c8178e997c16a9b628bb6f" }, - { "fontloader-font-onr.lua", "6d161533f3437435e12a0ad64866df44" }, - { "fontloader-font-otc.lua", "0f12230ea07b5151f75d52726977e91f" }, - { "fontloader-font-ocl.lua", "797b5c71bf819c5f4fb314a4d646e9a7" }, - { "fontloader-font-osd.lua", "73c9531c79df5ada320cb20777f7ed49" }, - { "fontloader-font-ots.lua", "f018ae1f355a8ef5c8d403cc5489e3d3" }, - { "fontloader-font-ota.lua", "ad1d5de06400f88829509e1f3ff2b473" }, - { "fontloader-font-otj.lua", "8de59cb9b043e5f73c6b9f7cc8f6978e" }, - { "fontloader-font-oto.lua", "2b1d6bc63b2ebf8f2655a15e1cda6541" }, - { "fontloader-font-otl.lua", "b168cf69300873d6668203bc7afe1f56" }, - { "fontloader-font-oup.lua", "6f46aa00ae1c20c43f8ffaf329dc8695" }, - { "fontloader-font-dsp.lua", "5d6528c0673b7651600ca6b763b51df5" }, - { "fontloader-font-ttf.lua", "786a535ba0385446b7015260388bc415" }, - { "fontloader-font-cff.lua", "802a10ad12ac32329f540881f940e3f2" }, - { "fontloader-font-ott.lua", "673ed11e1d159997f535bfec5fa73808" }, - { "fontloader-font-oti.lua", "309a75f9c14b77d87e94eba827dc4e71" }, - { "fontloader-font-otr.lua", "64dcbbc7107538723990e1119a80a9f8" }, - { "fontloader-font-vfc.lua", "a81c29eda98cd62cbebdb6c93544b50d" }, - { "fontloader-font-map.lua", "c4a39db5ad822b348aa61bca5f4a599a" }, - { "fontloader-font-cid.lua", "22b0367742fb253deef84ef7ccf5e8de" }, - { "fontloader-font-con.lua", "a3eb543fa5946fa1faf0e1e50d5b3b91" }, - { "fontloader-font-ini.lua", "5343de60613adb24cdd7a8d2ee1d153c" }, - { "fontloader-data-con.lua", "23a0f5386d46a1c157ae82a373e35fa0" }, - { "fontloader-reference.lua", "c10086745bc0b8b2303572fdea86d61c" }, - { "fontloader-basics-gen.lua", "4bc43036e9796fccb0b8869f4b05bf2e" }, - { "mktests", "918cb50be9ee8bd645ac1a27dc501e8c" }, - { "mkstatus", "49692433db8a578cf3a03fbedfb2ea9c" }, - { "mkcharacters", "bfca0e96e1e351afe7077502f9595af9" }, - { "mkglyphlist", "7a8a8fdc0eac7fac2f13ec8f4e8e7aa9" }, - { "mkimport", "7d62f1042e548f8b9368f26b9ba4be5c" }, - { "luaotfload-glyphlist.lua", "af60521c7ea3f5828c83ed1d1fa23b45" }, - { "luaotfload-characters.lua", "76415ca3ede312cad6e09038323489ae" }, - { "luaotfload-tounicode.lua", "24601f0255c35508eddbb427a6e18873" }, - { "luaotfload-unicode.lua", "c7d3f282db7a0f9588cc57d8f079a3cb" }, - { "luaotfload-resolvers.lua", "ac9e134e0614ab7ab69122ec0fd99e54" }, - { "luaotfload-parsers.lua", "10afafb81544840cb0fd0ecaac3c3344" }, - { "luaotfload-fallback.lua", "9d70a346c2584834f40d83be25d53a6a" }, - { "luaotfload-szss.lua", "0e29a05f35bbd05388e5af674059c242" }, - { "luaotfload-scripts.lua", "9a1e50e55ddef481ca3863004f33703e" }, - { "luaotfload-multiscript.lua", "8a828bf429dc73742ea78ad73332d219" }, - { "luaotfload-loaders.lua", "f13bafee1dca48db5073fe4390dc8ec4" }, - { "luaotfload-harf-plug.lua", "f43e0d894cf9ca3f31ff405d1684a5ff" }, - { "luaotfload-harf-define.lua", "0aecef4ea82a6edc305be2eed7b8e9c9" }, - { "luaotfload-notdef.lua", "73762a6d7662aa090f8f950a34d55835" }, - { "luaotfload-embolden.lua", "3444350537a12803b8e255f56b33b50d" }, - { "luaotfload-letterspace.lua", "6ac6c8d6f54107984ad338a94f0acd86" }, - { "luaotfload-features.lua", "b42fbc57c4fb1306dc23bf4e3bf6cd98" }, - { "luaotfload-database.lua", "8e11e69cf6a83bc1723c95e4788cdc70" }, - { "luaotfload-configuration.lua", "d1f4d64caa58bfc5feb524ea7cd365f6" }, - { "luaotfload-colors.lua", "5d1e7e10b5a8dda7ccf3742ae90f002e" }, - { "luaotfload-auxiliary.lua", "6d4e31212b8852e5f1425dc0ea49e016" }, - { "luaotfload-filelist.lua", "5e4c15ea6e5aafc19a533289b6ac2709" }, - { "luaotfload-tool.lua", "9caf618c38bf58cf9a29f2b2d4449346" }, - { "luaotfload-diagnostics.lua", "797176921da30591e6112831ed7459a7" }, - { "luaotfload-log.lua", "932117045a6abfe303314a295c24d338" }, - { "luaotfload-init.lua", "eb1bfca3833688aba31521032ed38883" }, - { "luaotfload-main.lua", "133ee97a73e07f3116d0417c9373398b" }, + { "fontloader-2020-12-30.lua", "68ad807e7fdc2161801a16d1d404e1c4" }, + { "fontloader-util-fil.lua", "a617cad49fc028e99f0f30bce8b2b623" }, + { "fontloader-util-str.lua", "a2041dad54b982ad124cbc764f5de43b" }, + { "fontloader-l-unicode.lua", "a4464b61c123f0454bea92c1cf502891" }, + { "fontloader-l-math.lua", "a373be3ed2db0d5f98588fa81abca48f" }, + { "fontloader-l-boolean.lua", "18ed6c4b2c40dd87224ea33229548d20" }, + { "fontloader-l-file.lua", "60ddd3948d9de7bde8b4a0f5c51ff9f5" }, + { "fontloader-l-io.lua", "a4042e9d6bce71c61fdd94e6e17f2bf4" }, + { "fontloader-l-table.lua", "20c03ae1b81e902217f3f76995b9d294" }, + { "fontloader-l-string.lua", "e1347bef0eeeff9f098df83b30b32df9" }, + { "fontloader-l-function.lua", "f771cc91839ebcdfc094083434fbe00f" }, + { "fontloader-l-lpeg.lua", "c3407de16bcedd73652250b000b39e98" }, + { "fontloader-l-lua.lua", "c8dbb33df962e1b945b91b906b3c15c4" }, + { "fontloader-fonts-gbn.lua", "d25472d54c4841db43a745764a63533e" }, + { "fontloader-fonts-lig.lua", "b9dbe77ce747d4c35bb2a20ffbe5aa51" }, + { "fontloader-fonts-ext.lua", "01015ab3758cdc2af29394e6d502a91a" }, + { "fontloader-fonts-def.lua", "5ad79120ebc5e60f4d322fb3ee13bffe" }, + { "fontloader-fonts-tfm.lua", "3bbba3214fd0b8c6f35ad85592fc2917" }, + { "fontloader-fonts-enc.lua", "3e71a54297e8f85a1ac438bb0f20dd79" }, + { "fontloader-fonts-mis.lua", "bc9eb43c27f63ce9d0fff67e104fe1c6" }, + { "fontloader-basics-chr.lua", "58b7ef0c486e06090b362971b9f85e27" }, + { "fontloader-basics-nod.lua", "6549c88db8cf4c6ae005a2e08f223d4b" }, + { "fontloader-font-imp-effects.lua", "231cda056b88f6dc282fab9d7643d380" }, + { "fontloader-font-imp-italics.lua", "058fb834c11c6ac30c280b29e496966e" }, + { "fontloader-font-imp-ligatures.lua", "043daa4fcccf2560868da359d71d3a4a" }, + { "fontloader-font-imp-tex.lua", "77c374b0ef00c2fb12188ec42beb4257" }, + { "fontloader-font-shp.lua", "72de6029980ac796ec6ec76fa3ec8684" }, + { "fontloader-font-def.lua", "226b4d26ede7fa7be8e45b7f0d93e781" }, + { "fontloader-font-lua.lua", "55b281fb98f7bd848fc19928f376f647" }, + { "fontloader-font-afk.lua", "54d554530e75c57c56ee76234724e26d" }, + { "fontloader-font-one.lua", "2e52d1e42764f68b779522bda9569480" }, + { "fontloader-font-onr.lua", "7a9ece7bf3e36b5f0adf295a9a2a2989" }, + { "fontloader-font-ocl.lua", "ab81576f20e2d37bc8707e1dbd3decf2" }, + { "fontloader-font-osd.lua", "61f05fcf91add1aa5dac9bc8b235adc9" }, + { "fontloader-font-otc.lua", "1204a2fdc436e644127c0aa38ab69607" }, + { "fontloader-font-ots.lua", "a83d5992a82b706c0ffdb5c2778534f1" }, + { "fontloader-font-ota.lua", "f31232af3a694ae3d50380a5a92f88d3" }, + { "fontloader-font-oup.lua", "1700a2dac4f8b105c187d4e5b84cecdf" }, + { "fontloader-font-otj.lua", "a37a1007b8a92c9e7d24064180c2a772" }, + { "fontloader-font-oto.lua", "24238a7c600d090a8ee88312321dd9b3" }, + { "fontloader-font-otl.lua", "70237f19b76c4bc75f0c6e89038fb49a" }, + { "fontloader-font-ott.lua", "1249b7018dba80e080fc478a38aa6756" }, + { "fontloader-font-oti.lua", "dbae7722baae24d917a17176553825cf" }, + { "fontloader-font-dsp.lua", "10eb256f4bcb9c5eabd48048e2da5eab" }, + { "fontloader-font-ttf.lua", "ebef049a169c04edd19902fd66ddea44" }, + { "fontloader-font-cff.lua", "aa9038651d9fedd2b76cacd1f69fd742" }, + { "fontloader-font-otr.lua", "7a2f7a9e9627b29158e1822ea3c650ab" }, + { "fontloader-font-vfc.lua", "04fa0ffad5c51198c7c19462949f54ed" }, + { "fontloader-font-map.lua", "a03653ea3c5f042b457d54ed678d6df3" }, + { "fontloader-font-cid.lua", "4d87988efa86020a14708ee03c23415f" }, + { "fontloader-font-con.lua", "cbccccc4a5016196d62332a365aa8b72" }, + { "fontloader-font-ini.lua", "4dee96e1e1474d324dd126bd5d375df8" }, + { "fontloader-data-con.lua", "de6ae0997b0e70a23bcc9afff5d8b072" }, + { "fontloader-reference.lua", "957f358a48ea6fcbc78a8701f947d7e5" }, + { "fontloader-basics-gen.lua", "7bcfb5e4f48a1a34be6ddfcee2b1e49d" }, + { "mktests", "c7cff7025962922944376acc1ffa9c47" }, + { "mkstatus", "f3b00b5999440afce64bdc448f3fda9a" }, + { "mkcharacters", "92c24bb582fc84c0365634f29eb89863" }, + { "mkglyphlist", "95bbf91338214d40b2102114285ccd3f" }, + { "mkimport", "5dacc09f3358ba9b90cf3a804f9a535c" }, + { "luaotfload-glyphlist.lua", "bb6a9912a0944b3b21a61fce247dd728" }, + { "luaotfload-characters.lua", "6a46f4749368e4f56a863da9c61b7bd6" }, + { "luaotfload-dvi.lua", "34e1550905555da63304e07797168c69" }, + { "luaotfload-tounicode.lua", "09fa475eeb7b160d3eb124e9107d4e03" }, + { "luaotfload-unicode.lua", "153f97b086fd38dcb7f4850d95a41016" }, + { "luaotfload-resolvers.lua", "2441b9624775fbcea6617e6cc72b424d" }, + { "luaotfload-parsers.lua", "623d33f43813eda562cbfef5528753de" }, + { "luaotfload-fallback.lua", "ec702c1c9407eba7bfe80b59c36f3f67" }, + { "luaotfload-szss.lua", "ee4c0c070dcacf4d3e43f52948611392" }, + { "luaotfload-scripts.lua", "14a19085cd5288592ebd5e24acf8514a" }, + { "luaotfload-multiscript.lua", "4a283df608be713b0b666515fb6b9789" }, + { "luaotfload-loaders.lua", "f0eeb293d8f448413631b1ffff554e39" }, + { "luaotfload-harf-plug.lua", "34182344e7985d1267dacde37f387433" }, + { "luaotfload-harf-define.lua", "252c36178f4f9ab066bdc15adfe809f1" }, + { "luaotfload-notdef.lua", "06278786a6f2f8ddd3749b5d75f611db" }, + { "luaotfload-embolden.lua", "8bdfebc528d078086c7fd0747815df74" }, + { "luaotfload-letterspace.lua", "57d6026196fa62f9891d7a7a7300f63f" }, + { "luaotfload-features.lua", "2219adcecef7362bbbe46da2e5ed005b" }, + { "luaotfload-database.lua", "e2bea14191641d3a18b04064752d0fd4" }, + { "luaotfload-configuration.lua", "dfa0521ef327c68573ea587ed7b989c8" }, + { "luaotfload-colors.lua", "32bf6714aa19f6c291922cd1be01b629" }, + { "luaotfload-auxiliary.lua", "4c18ffcc0d1cbef3ad4db2b6440a863e" }, + { "luaotfload-filelist.lua", "8bb0a321254e6f04a1fa776d2f67747f" }, + { "luaotfload-tool.lua", "ac7b0adfd9d0096228bed8ae61540a70" }, + { "luaotfload-diagnostics.lua", "21bca70ad0b6f7dd1d9d57c7b1513809" }, + { "luaotfload-log.lua", "d9c45eff233d71c3824f3a579694d737" }, + { "luaotfload-init.lua", "265f1bfe8789fbb0cc3bff3a780f5494" }, + { "luaotfload-main.lua", "f5f771d1cf5c8c4a2519a8d46aed1241" }, }, ["notes"]={ - ["committer"]="Marcel Fabian Krüger <tex@2krueger.de>", - ["description"]="v3.15/2020-09-02", - ["loader"]="fontloader-2020-08-31.lua", - ["revision"]="77eede02640bef0cb596d24aa79661328a68b448", - ["timestamp"]="2020-09-02 21:02:40 +0200", + ["committer"]="Ulrike Fischer <fischer@troubleshooting-tex.de>", + ["description"]="v3.16/2020-12-31", + ["loader"]="fontloader-2020-12-30.lua", + ["revision"]="d1423b56efe2649e2881657747cee8d54cf64e12", + ["timestamp"]="2020-12-31 12:35:44 +0100", }, }
\ No newline at end of file diff --git a/macros/luatex/generic/luaotfload/luaotfload-suppress.lua b/macros/luatex/generic/luaotfload/luaotfload-suppress.lua index 768cf81402..c4c0c1010e 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-suppress.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-suppress.lua @@ -3,19 +3,15 @@ -- DESCRIPTION: part of luaotfload / suppress ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-suppress", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / suppress", license = "GPL v2.0", author = "Marcel Krüger" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - local direct = node.direct local otfregister = fonts.constructors.features.otf.register diff --git a/macros/luatex/generic/luaotfload/luaotfload-szss.lua b/macros/luatex/generic/luaotfload/luaotfload-szss.lua index 751964cdd1..4c7de4d11b 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-szss.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-szss.lua @@ -3,19 +3,15 @@ -- DESCRIPTION: part of luaotfload / szss ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-szss", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / Special feature handling", license = "GPL v2.0", author = "Marcel Krüger" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - local direct = node.direct local otfregister = fonts.constructors.features.otf.register diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.1 b/macros/luatex/generic/luaotfload/luaotfload-tool.1 index ea2d12e9eb..7cd4934ab0 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-tool.1 +++ b/macros/luatex/generic/luaotfload/luaotfload-tool.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH LUAOTFLOAD-TOOL 1 "2020-09-02" "3.15" "text processing" +.TH LUAOTFLOAD-TOOL 1 "2020-12-31" "3.16" "text processing" .SH NAME luaotfload-tool \- generate and query the Luaotfload font names database . @@ -327,7 +327,7 @@ state. .SS miscellaneous .INDENT 0.0 .TP -.BI \-\-verbose\fB= N\fP,\fB \ \-v +.BI \-\-verbose\fB= N\fR,\fB \ \-v Set verbosity level to \fIn\fP or the number of repetitions of \fB\-v\fP\&. .TP diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.lua b/macros/luatex/generic/luaotfload/luaotfload-tool.lua index 18334d5ab3..fd66a9f79c 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-tool.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-tool.lua @@ -9,15 +9,13 @@ local ProvidesLuaModule = { name = "luaotfload-tool", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload-tool / database functionality", license = "GPL v2.0" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end +function luaotfload_module(module) end -- We don't log module loading here luaotfload = luaotfload or { } @@ -70,7 +68,7 @@ do local revn = tonumber (status.luatex_revision) or 0 --[[ : string ]] if status.luatex_version < minimum[1] - or status.luatex_version == minimum[1] and status.luatex_revision < minimum[2] then + or status.luatex_version == minimum[1] and tonumber(status.luatex_revision) < minimum[2] then texio.write_nl ("term and log", string.format ("\tFATAL ERROR\n\z \tLuaotfload requires a Luatex version >= %d.%d.%d.\n\z diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.pdf b/macros/luatex/generic/luaotfload/luaotfload-tool.pdf Binary files differindex 6697476a0e..e35752ab17 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-tool.pdf +++ b/macros/luatex/generic/luaotfload/luaotfload-tool.pdf diff --git a/macros/luatex/generic/luaotfload/luaotfload-tool.rst b/macros/luatex/generic/luaotfload/luaotfload-tool.rst index c030ab81f2..c4c15d916f 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-tool.rst +++ b/macros/luatex/generic/luaotfload/luaotfload-tool.rst @@ -6,9 +6,9 @@ generate and query the Luaotfload font names database ----------------------------------------------------------------------- -:Date: 2020-09-02 +:Date: 2020-12-31 :Copyright: GPL v2.0 -:Version: 3.15 +:Version: 3.16 :Manual section: 1 :Manual group: text processing diff --git a/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua b/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua index 028aef9d12..f4eeec1125 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-tounicode.lua @@ -3,20 +3,16 @@ -- DESCRIPTION: part of luaotfload / tounicode overwrites ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-tounicode", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / tounicode", license = "GPL v2.0", author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger", copyright = "PRAGMA ADE / ConTeXt Development Team", } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - local overloads = { -- rougly based on texglyphlist-g2u.txt diff --git a/macros/luatex/generic/luaotfload/luaotfload-unicode.lua b/macros/luatex/generic/luaotfload/luaotfload-unicode.lua index 2e9b28cf79..a05c660a36 100644 --- a/macros/luatex/generic/luaotfload/luaotfload-unicode.lua +++ b/macros/luatex/generic/luaotfload/luaotfload-unicode.lua @@ -3,19 +3,15 @@ -- DESCRIPTION: part of luaotfload / unicode ----------------------------------------------------------------------- -local ProvidesLuaModule = { +assert(luaotfload_module, "This is a part of luaotfload and should not be loaded independently") { name = "luaotfload-unicode", - version = "3.15", --TAGVERSION - date = "2020-09-02", --TAGDATE + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE description = "luaotfload submodule / Unicode helpers", license = "CC0 1.0 Universal", author = "Marcel Krüger" } -if luatexbase and luatexbase.provides_module then - luatexbase.provides_module (ProvidesLuaModule) -end - local utf8codes = utf8.codes local utf8char = utf8.char local sub = string.sub @@ -103,7 +99,149 @@ local alphnum_only do end end +local uppercase, lowercase, ccc, cased, case_ignorable, titlecase = {}, {}, {}, {}, {}, nil do + titlecase = nil -- Not implemented yet(?) + local ignored_field = (1-lpeg.P';')^0 * ';' + local cased_category = lpeg.P'Ll;' + 'Lu;' + 'Lt;' + local case_ignore_category = lpeg.P'Mn;' + 'Me;' + 'Cf;' + 'Lm;' + 'Sk;' + + local simple_entry = + codepoint/0 * ';' + * ignored_field -- Name + * (ignored_field - cased_category - case_ignore_category) -- General_Category + * '0;' -- ccc + * ignored_field -- Bidi + * ignored_field -- Decomp + * ignored_field -- Numeric + * ignored_field -- Numeric + * ignored_field -- Numeric + * ignored_field -- Mirrored + * ignored_field -- Obsolete + * ignored_field -- Obsolete + * ';;\n' + local entry = simple_entry + + codepoint * ';' + * ignored_field -- Name + * (cased_category * lpeg.Cc(cased) + case_ignore_category * lpeg.Cc(case_ignorable) + ignored_field * lpeg.Cc(nil)) -- General_Category + * ('0;' * lpeg.Cc(nil) + lpeg.R'09'^1/tonumber * ';') -- ccc + * ignored_field -- Bidi + * ignored_field -- Decomp + * ignored_field -- Numeric + * ignored_field -- Numeric + * ignored_field -- Numeric + * ignored_field -- Mirrored + * ignored_field -- Obsolete + * ignored_field -- Obsolete + * (codepoint + lpeg.Cc(nil)) * ';' -- uppercase + * (codepoint + lpeg.Cc(nil)) * ';' -- lowercase + * (codepoint + lpeg.Cc(nil)) * '\n' -- titlecase + / function(codepoint, cased_flag, ccc_val, upper, lower, title) + if cased_flag then cased_flag[codepoint] = true end + ccc[codepoint] = ccc_val + uppercase[codepoint] = upper + lowercase[codepoint] = lower + -- if title then titlecase[codepoint] = title end -- Not implemented yet(?) + end + local file = entry^0 * -1 + + local f = io.open(kpse.find_file"UnicodeData.txt") + assert(file:match(f:read'*a')) + f:close() +end + +local props do + local ws = lpeg.P' '^0 + local nl = ws * ('#' * (1-lpeg.P'\n')^0)^-1 * '\n' + local entry = codepoint * (".." * codepoint + lpeg.Cc(false)) * ws * ";" * ws * lpeg.C(lpeg.R("AZ", "az", "__")^1) * nl + local file = lpeg.Cf( + lpeg.Ct( + lpeg.Cg(lpeg.Ct"", "Soft_Dotted") + * lpeg.Cg(lpeg.Cc(cased), "Other_Lowercase") + * lpeg.Cg(lpeg.Cc(cased), "Other_Uppercase")) + * (lpeg.Cg(entry) + nl)^0 + , function(t, cp_start, cp_end, prop) + local prop_table = t[prop] + if prop_table then + for cp = cp_start, cp_end or cp_start do + prop_table[cp] = true + end + end + return t + end) * -1 + + local f = io.open(kpse.find_file"PropList.txt") + props = file:match(f:read'*a') + f:close() +end + +do + local ws = lpeg.P' '^0 + local nl = ws * ('#' * (1-lpeg.P'\n')^0)^-1 * '\n' + local file = (codepoint * (".." * codepoint + lpeg.Cc(false)) * ws * ";" * ws * (lpeg.P'Single_Quote' + 'MidLetter' + 'MidNumLet') * nl / function(cp_start, cp_end) + for cp = cp_start, cp_end or cp_start do + case_ignorable[cp] = true + end + end + (1-lpeg.P'\n')^0 * '\n')^0 * -1 + + local f = io.open(kpse.find_file"WordBreakProperty.txt") + assert(file:match(f:read'*a')) + f:close() +end + +do + local ws = lpeg.P' '^0 + local nl = ws * ('#' * (1-lpeg.P'\n')^0)^-1 * '\n' + local empty = {} + local function set(t, cp, condition, value) + local old = t[cp] or cp + if not condition then + if #value == 1 and tonumber(old) then + t[cp] = value[1] + return + end + condition = empty + end + if tonumber(old or cp) then + old = {_ = {old}} + t[cp] = old + end + for i=1, #condition do + local cond = condition[i] + local step = old[cond] + if not step then + step = {} + old[cond] = step + end + old = step + end + old._ = value + end + local entry = codepoint * ";" + * lpeg.Ct((ws * codepoint)^1 + ws) * ";" + * lpeg.Ct((ws * codepoint)^1 + ws) * ";" + * lpeg.Ct((ws * codepoint)^1 + ws) * ";" + * (lpeg.Ct((ws * lpeg.C(lpeg.R('AZ', 'az', '__')^1))^1) * ";")^-1 + * ws * nl / function(cp, lower, title, upper, condition) + set(lowercase, cp, condition, lower) + set(uppercase, cp, condition, upper) + end + local file = (entry + nl)^0 * -1 + + local f = io.open(kpse.find_file"SpecialCasing.txt") + assert(file:match(f:read'*a')) + f:close() +end + return { casefold = casefold, alphnum_only = alphnum_only, + casemapping = { + uppercase = uppercase, + lowercase = lowercase, + cased = cased, + case_ignorable = case_ignorable, + -- titlecase = titlecase, + }, + ccc = ccc, + soft_dotted = props.Soft_Dotted, } diff --git a/macros/luatex/generic/luaotfload/luaotfload.conf.5 b/macros/luatex/generic/luaotfload/luaotfload.conf.5 index 0035ce834f..4620ef0f2f 100644 --- a/macros/luatex/generic/luaotfload/luaotfload.conf.5 +++ b/macros/luatex/generic/luaotfload/luaotfload.conf.5 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH LUAOTFLOAD.CONF 5 "2020-09-02" "3.15" "text processing" +.TH LUAOTFLOAD.CONF 5 "2020-12-31" "3.16" "text processing" .SH NAME luaotfload.conf \- Luaotfload configuration file . diff --git a/macros/luatex/generic/luaotfload/luaotfload.conf.rst b/macros/luatex/generic/luaotfload/luaotfload.conf.rst index d40cb3a967..5905eb3811 100644 --- a/macros/luatex/generic/luaotfload/luaotfload.conf.rst +++ b/macros/luatex/generic/luaotfload/luaotfload.conf.rst @@ -6,9 +6,9 @@ Luaotfload configuration file ----------------------------------------------------------------------- -:Date: 2020-09-02 +:Date: 2020-12-31 :Copyright: GPL v2.0 -:Version: 3.15 +:Version: 3.16 :Manual section: 5 :Manual group: text processing diff --git a/macros/luatex/generic/luaotfload/luaotfload.lua b/macros/luatex/generic/luaotfload/luaotfload.lua new file mode 100644 index 0000000000..843c84a3bf --- /dev/null +++ b/macros/luatex/generic/luaotfload/luaotfload.lua @@ -0,0 +1,375 @@ +----------------------------------------------------------------------- +-- FILE: luaotfload.lua +-- DESCRIPTION: OpenType layout system / luaotfload entry point +-- REQUIREMENTS: luatex v.0.95.0 or later; package lualibs +-- AUTHOR: Élie Roux, Khaled Hosny, Philipp Gesang, Ulrike Fischer, Marcel Krüger +----------------------------------------------------------------------- + +local authors = "\z + Hans Hagen,\z + Khaled Hosny,\z + Elie Roux,\z + Will Robertson,\z + Philipp Gesang,\z + Dohyun Kim,\z + Reuben Thomas,\z + David Carlisle,\ + Ulrike Fischer,\z + Marcel Krüger\z +" +-- version number is used below! +local ProvidesLuaModule = { + name = "luaotfload", + version = "3.16", --TAGVERSION + date = "2020-12-31", --TAGDATE + description = "Lua based OpenType font support", + author = authors, + copyright = authors, + license = "GPL v2.0" +} + +if luatexbase and luatexbase.provides_module then + luatexbase.provides_module (ProvidesLuaModule) +end + +if luaotfload_module == nil then + local print_warning = luatexbase and luatexbase.module_warning or function(module, text) + return texio.write_nl("%s WARNING: %s", module, text) + end + local saved_version = ProvidesLuaModule.version + local trace_submodules = tonumber(os.getenv'LUAOTFLOAD_TRACE_SUBMODULES') + if luatexbase and luatexbase.provides_module and trace_submodules and trace_submodules ~= 0 then + luaotfload_module = luatexbase.provides_module + else + function luaotfload_module(module) + local module_version = module.version + if module_version ~= saved_version then + local filenames + if debug then + filenames = string.format("luaotfload.lua is found at\n%q\n%s.lua is found at\n%q\n", + debug.getinfo(1, "S").source:sub(2), + module.name, + debug.getinfo(2, "S").source:sub(2)) + else + filenames = "" + end + print_warning("luaotfload", string.format("Version inconsistency detected.\n\z + luaotfload is loaded in version %s, while %q is loaded \z + in version %s.\n%sI will try to continue anyway.\nHIC SUNT DRACONES", + saved_version, module.name, module_version, filenames)) + end + end + end +else + error[[luaotfload is reloading itself nested. This can't happen.]] +end + +local osgettimeofday = os.gettimeofday +config = config or { } +luaotfload = luaotfload or { } +local luaotfload = luaotfload +luaotfload.log = luaotfload.log or { } +local logreport +luaotfload.version = ProvidesLuaModule.version +luaotfload.loaders = { } +luaotfload.fontloader_package = "reference" --- default: from current Context + +if not tex or not tex.luatexversion then + error "this program must be run in TeX mode" --- or call tex.initialize() =) +end + +--- version check +local revno = tonumber(tex.luatexrevision) +local minimum = { 110, 0 } +if tex.luatexversion < minimum[1] or tex.luatexversion == minimum[1] and revno < minimum[2] then + texio.write_nl ("term and log", + string.format ("\tFATAL ERROR\n\z + \tLuaotfload requires a Luatex version >= %d.%d.%d.\n\z + \tPlease update your TeX distribution!\n\n", + math.floor(minimum[1] / 100), minimum[1] % 100, minimum[2])) + error "version check failed" +end + +if not utf8 then + texio.write_nl("term and log", string.format("\z + \tluaotfload: module utf8 is unavailable\n\z + \tutf8 is available in Lua 5.3+; engine\'s _VERSION is %q\n\z + \tThis probably means that the engine is not supported\n\z + \n", + _VERSION)) + error "module utf8 is unavailable" +end + +if status.safer_option ~= 0 then + texio.write_nl("term and log","luaotfload can't run with option --safer. Aborting") + error("safer_option used") +end + + + + +--[[doc-- + + This file initializes the system and loads the font loader. To + minimize potential conflicts between other packages and the code + imported from \CONTEXT, several precautions are in order. Some of + the functionality that the font loader expects to be present, like + raw access to callbacks, are assumed to have been disabled by + \identifier{luatexbase} when this file is processed. In some cases + it is possible to trick it by putting dummies into place and + restoring the behavior from \identifier{luatexbase} after + initilization. Other cases such as attribute allocation require + that we hook the functionality from \identifier{luatexbase} into + locations where they normally wouldn’t be. + + Anyways we can import the code base without modifications, which is + due mostly to the extra effort by Hans Hagen to make \LUATEX-Fonts + self-contained and encapsulate it, and especially due to his + willingness to incorporate our suggestions. + +--doc]]-- + +local luatexbase = luatexbase +local require = require +local type = type + + +--[[doc-- + + \subsection{Module loading} + We load the files imported from \CONTEXT with function derived this way. It + automatically prepends a prefix to its argument, so we can refer to the + files with their actual \CONTEXT name. + +--doc]]-- + +local function make_loader_name (prefix, name) + local msg = luaotfload.log and luaotfload.log.report + or function (stream, lvl, cat, ...) + if lvl > 1 then --[[not pressing]] return end + texio.write_nl ("log", + string.format ("luaotfload | %s : ", + tostring (cat))) + texio.write (string.format (...)) + end + if not name then + msg ("both", 0, "load", + "Fatal error: make_loader_name (%q, %q).", + tostring (prefix), tostring (name)) + return "dummy-name" + end + name = tostring (name) + if prefix == false then + msg ("log", 9, "load", + "No prefix requested, passing module name %q unmodified.", + name) + return tostring (name) .. ".lua" + end + prefix = tostring (prefix) + msg ("log", 9, "load", + "Composing module name from constituents %s, %s.", + prefix, name) + return prefix .. "-" .. name .. ".lua" +end + +local timing_info = { + t_load = { }, + t_init = { }, +} + +local function make_loader (prefix, load_helper) + return function (name) + local t_0 = osgettimeofday () + local modname = make_loader_name (prefix, name) + --- We don’t want the stack info from inside, so just pcall(). + local ok, data = pcall (load_helper or require, modname) + local t_end = osgettimeofday () + timing_info.t_load [name] = t_end - t_0 + if not ok then + io.write "\n" + local msg = luaotfload.log and luaotfload.log.report or print + msg ("both", 0, "load", "FATAL ERROR") + msg ("both", 0, "load", " × Failed to load %q module %q.", + tostring (prefix), tostring (name)) + local lines = string.split (data, "\n\t") + if not lines then + msg ("both", 0, "load", " × Error message: %q", data) + else + msg ("both", 0, "load", " × Error message:") + for i = 1, #lines do + msg ("both", 0, "load", " × %q.", lines [i]) + end + end + io.write "\n\n" + local debug = debug + if debug then + io.write (debug.traceback()) + io.write "\n\n" + end + os.exit(-1) + end + return data + end +end + +--[[doc-- + Certain files are kept around that aren’t loaded because they are part of + the imported fontloader. In order to keep the initialization structure + intact we also provide a no-op version of the module loader that can be + called in the expected places. +--doc]]-- + +local function dummy_loader (name) + luaotfload.log.report ("log", 3, "load", + "Skipping module %q on purpose.", + name) +end + +local context_environment = setmetatable({}, {__index = _G}) +luaotfload.fontloader = context_environment +local function context_isolated_load(name) + local fullname = kpse.find_file(name, 'lua') + if not fullname then + error(string.format('Fontloader module %q could not be found.', name)) + end + return assert(loadfile(fullname, nil, context_environment))(name) +end + +local function context_loader (name, path) + luaotfload.log.report ("log", 3, "load", + "Loading module %q from Context.", + name) + local t_0 = osgettimeofday () + local modname = make_loader_name (false, name) + local modpath = modname + if path then + if lfs.isdir (path) then + luaotfload.log.report ("log", 3, "load", + "Prepending path %q.", + path) + modpath = file.join (path, modname) + else + luaotfload.log.report ("both", 0, "load", + "Non-existant path %q specified, ignoring.", + path) + end + end + local ret = context_isolated_load (modpath) + local t_end = osgettimeofday () + timing_info.t_load [name] = t_end - t_0 + + if ret ~= nil then + --- require () returns “true” upon success unless the loaded file + --- yields a non-zero exit code. This isn’t per se indicating that + --- something isn’t right, but against HH’s coding practices. We’ll + --- silently ignore this ever happening on lower log levels. + luaotfload.log.report ("log", 4, "load", + "Module %q returned %q.", modname, ret) + end + return ret +end + +local function install_loaders () + local loaders = { } + local loadmodule = make_loader "luaotfload" + loaders.luaotfload = loadmodule + loaders.fontloader = make_loader ("fontloader", context_isolated_load) + loaders.context = context_loader + loaders.ignore = dummy_loader +----loaders.plaintex = make_loader "luatex" --=> for Luatex-Plain + + function loaders.initialize (name) + local tmp = loadmodule (name) + local init = type(tmp) == "table" and tmp.init or tmp + if init and type (init) == "function" then + local t_0 = osgettimeofday () + if not init () then + logreport ("log", 0, "load", + "Failed to load module %q.", name) + return + end + local t_end = osgettimeofday () + local d_t = t_end - t_0 + logreport ("log", 4, "load", + "Module %q loaded in %g ms.", + name, d_t * 1000) + timing_info.t_init [name] = d_t + end + end + + return loaders +end + +local luaotfload_initialized = false --- prevent multiple invocations + +luaotfload.main = function () + + if luaotfload_initialized then + logreport ("log", 0, "load", + "Luaotfload initialization requested but is already \z + loaded, ignoring.") + return + end + luaotfload_initialized = true + + luaotfload.loaders = install_loaders () + local loaders = luaotfload.loaders + local loadmodule = loaders.luaotfload + local initialize = loaders.initialize + + local starttime = osgettimeofday () + + -- Feature detect HarfBuzz. This is done early to allow easy HarfBuzz + -- detection in other modules + local harfstatus, harfbuzz = pcall(require, 'luaharfbuzz') + if harfstatus then + luaotfload.harfbuzz = harfbuzz + end + + local init = loadmodule "init" --- fontloader initialization + init (function () + + logreport = luaotfload.log.report + initialize "parsers" --- fonts.conf and syntax + initialize "configuration" --- configuration options + end) + + initialize "loaders" --- Font loading; callbacks + initialize "database" --- Font management. + initialize "colors" --- Per-font colors. + + local init_resolvers = loadmodule "resolvers" --- Font lookup + init_resolvers () + + if not config.actions.reconfigure () then + logreport ("log", 0, "load", "Post-configuration hooks failed.") + end + + initialize "features" --- font request and feature handling + + if harfstatus then + loadmodule "harf-define" + loadmodule "harf-plug" + end + loadmodule "letterspace" --- extra character kerning + loadmodule "embolden" --- fake bold + loadmodule "notdef" --- missing glyph handling + loadmodule "suppress" --- suppress ligatures by adding ZWNJ + loadmodule "szss" --- missing glyph handling + initialize "auxiliary" --- additional high-level functionality + loadmodule "tounicode" + loadmodule "case" + if tex.outputmode == 0 then + loadmodule "dvi" --- allow writing fonts to DVI files + end + + luaotfload.aux.start_rewrite_fontname () --- to be migrated to fontspec + + logreport ("log", 1, "main", + "initialization completed in %0.3f seconds\n", + osgettimeofday() - starttime) +----inspect (timing_info) + luaotfload_module = nil +end + +-- vim:tw=79:sw=4:ts=4:et diff --git a/macros/luatex/generic/luaotfload/luaotfload.sty b/macros/luatex/generic/luaotfload/luaotfload.sty index 33e15ba7c3..d9a3397d14 100644 --- a/macros/luatex/generic/luaotfload/luaotfload.sty +++ b/macros/luatex/generic/luaotfload/luaotfload.sty @@ -39,11 +39,11 @@ \fi \ifdefined\ProvidesPackage \ProvidesPackage{luaotfload}% - [2020/09/02 v3.15 OpenType layout system] + [2020/12/31 v3.16 OpenType layout system] \fi \directlua{ if xpcall(function ()% - require('luaotfload-main')% + require('luaotfload')% end,texio.write_nl) then % local _void = luaotfload.main ()% else % diff --git a/macros/luatex/generic/luaotfload/scripts-demo.pdf b/macros/luatex/generic/luaotfload/scripts-demo.pdf Binary files differindex 60b7e524de..5c00e2f4a6 100644 --- a/macros/luatex/generic/luaotfload/scripts-demo.pdf +++ b/macros/luatex/generic/luaotfload/scripts-demo.pdf diff --git a/macros/luatex/generic/luaotfload/shaper-demo-graphite.pdf b/macros/luatex/generic/luaotfload/shaper-demo-graphite.pdf Binary files differindex 8eb287e081..fa1bda41bb 100644 --- a/macros/luatex/generic/luaotfload/shaper-demo-graphite.pdf +++ b/macros/luatex/generic/luaotfload/shaper-demo-graphite.pdf diff --git a/macros/luatex/generic/luaotfload/shaper-demo.pdf b/macros/luatex/generic/luaotfload/shaper-demo.pdf Binary files differindex 77a7463630..b19632bbc7 100644 --- a/macros/luatex/generic/luaotfload/shaper-demo.pdf +++ b/macros/luatex/generic/luaotfload/shaper-demo.pdf |