From 18270d5b800b9c4f6e47613bef99e5a27812ea54 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sat, 4 Feb 2023 21:14:15 +0000 Subject: lua-typo (4feb23) git-svn-id: svn://tug.org/texlive/trunk@65734 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/lualatex/lua-typo/README.md | 20 +- .../doc/lualatex/lua-typo/lua-typo-demo.pdf | Bin 16794 -> 16859 bytes .../doc/lualatex/lua-typo/lua-typo-fr.ltx | 5 +- .../doc/lualatex/lua-typo/lua-typo-fr.pdf | Bin 64171 -> 80360 bytes .../texmf-dist/doc/lualatex/lua-typo/lua-typo.ltx | 5 +- .../texmf-dist/doc/lualatex/lua-typo/lua-typo.pdf | Bin 138442 -> 169623 bytes .../source/lualatex/lua-typo/lua-typo.dtx | 998 ++++++++++++++------- .../texmf-dist/tex/lualatex/lua-typo/lua-typo.sty | 234 ++--- 8 files changed, 846 insertions(+), 416 deletions(-) diff --git a/Master/texmf-dist/doc/lualatex/lua-typo/README.md b/Master/texmf-dist/doc/lualatex/lua-typo/README.md index 64373e69135..a9c6c7a2aa2 100644 --- a/Master/texmf-dist/doc/lualatex/lua-typo/README.md +++ b/Master/texmf-dist/doc/lualatex/lua-typo/README.md @@ -28,15 +28,15 @@ Installation ------------ This bundle is meant to be included in most TeX distributions, -but if you need to install it by yourself +but if you really need to install it by yourself 1. run "luatex lua-typo.dtx" to strip the comments and create lua-typo.sty, lua-typo.cfg, lua-typo.ltx and lua-typo-fr.ltx; 2. run "lualatex lua-typo.ltx" to get the full documentation (lua-typo.pdf) in English; -2. run "lualatex lua-typo-fr.ltx" to get the French documentation - (lua-typo-fr.pdf, code not included). +3. run "lualatex lua-typo-fr.ltx" to get the French documentation + (lua-typo-fr.pdf, without documented code). -Recommended loactions for installation: +Recommended locations for installation: - TDS:tex/lualatex/lua-typo/lua-typo.sty - TDS:tex/lualatex/lua-typo/lua-typo.cfg - TDS:doc/lualatex/lua-typo/lua-typo.pdf @@ -45,6 +45,9 @@ Recommended loactions for installation: - TDS:doc/lualatex/lua-typo/README.md - TDS:source/lualatex/lua-typo/lua-typo.dtx +On Debian based systems, the "TDS:" prefix can be replaced by "$HOME/texmf/" +for a single user installation. + Changes ------- @@ -69,6 +72,13 @@ Changes - coloration of faulty lines improved; - all flaws found are now recorded into file "`\jobname`.typo". +* v.0.51 (not released): bug fix + - in some cases orphans were not detected. + +* v.0.60: new implementation, Feb. 2023 + - this version should do a better job on two columns documents; + - debugging stuff added. + -- -Copyright 2020--2021 Daniel Flipo +Copyright 2020--2023 Daniel Flipo E-mail: daniel (dot) flipo (at) free (dot) fr diff --git a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-demo.pdf b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-demo.pdf index 89951bdf862..9b4721716e8 100644 Binary files a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-demo.pdf and b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-demo.pdf differ diff --git a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.ltx b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.ltx index e99c7b92124..3e580ef3147 100644 --- a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.ltx +++ b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.ltx @@ -6,10 +6,10 @@ \setmainfont{erewhon} \setsansfont{Cabin}[Scale=MatchLowercase] \setmonofont{VeraMono.ttf}[ + Scale = MatchLowercase, ItalicFont = VeraMoIt.ttf, BoldFont = VeraMoBd.ttf, BoldItalicFont = VeraMoBI.ttf, - Scale = MatchLowercase, HyphenChar=None, Color=Sepia, ] \usepackage[expansion=true, protrusion=true]{microtype} @@ -26,10 +26,13 @@ \hypersetup{colorlinks,urlcolor=blue,unicode} \OnlyDescription \let\FrenchDoc\begingroup\let\endFrenchDoc\endgroup +\let\Debugging\comment\let\endDebugging\endcomment +\newcommand*\texdir[1]{\textsc{#1}} \newcommand*\file[1]{\texttt{#1}} \newcommand*\pkg[1]{\texttt{#1}} \newcommand*\opt[1]{\texttt{#1}} \renewcommand\meta[1]{\texttt{\textsl{\color{Sepia}<#1>}}} +\newcommand*\node[1]{\textsc{#1}} \setlength{\parindent}{0pt} \setlength{\parskip}{.3\baselineskip plus 0.3pt minus 0.3pt} \begin{document} diff --git a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.pdf b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.pdf index 315c8306e10..0b96add63d3 100644 Binary files a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.pdf and b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.pdf differ diff --git a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.ltx b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.ltx index 5e94a0075df..46244feb110 100644 --- a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.ltx +++ b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.ltx @@ -6,10 +6,10 @@ \setmainfont{erewhon} \setsansfont{Cabin}[Scale=MatchLowercase] \setmonofont{VeraMono.ttf}[ + Scale = MatchLowercase, ItalicFont = VeraMoIt.ttf, BoldFont = VeraMoBd.ttf, BoldItalicFont = VeraMoBI.ttf, - Scale = MatchLowercase, HyphenChar=None, Color=Sepia, ] \usepackage[expansion=true, protrusion=true]{microtype} @@ -23,6 +23,7 @@ \usepackage{array,url,verbatim} \usepackage[numbered]{hypdoc} \hypersetup{colorlinks,urlcolor=blue,unicode} +\let\Debugging\comment\let\endDebugging\endcomment \let\FrenchDoc\comment\let\endFrenchDoc\endcomment \RecordChanges \AtEndDocument{% @@ -33,10 +34,12 @@ from version~0.30. \PrintChanges } +\newcommand*\texdir[1]{\textsc{#1}} \newcommand*\file[1]{\texttt{#1}} \newcommand*\pkg[1]{\texttt{#1}} \newcommand*\opt[1]{\texttt{#1}} \renewcommand\meta[1]{\texttt{\textsl{\color{Sepia}<#1>}}} +\newcommand*\node[1]{\textsc{#1}} \setlength{\parindent}{0pt} \setlength{\parskip}{.3\baselineskip plus 0.3pt minus 0.3pt} \begin{document} diff --git a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.pdf b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.pdf index 5b2b2dcbdf7..4f50db55294 100644 Binary files a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.pdf and b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.pdf differ diff --git a/Master/texmf-dist/source/lualatex/lua-typo/lua-typo.dtx b/Master/texmf-dist/source/lualatex/lua-typo/lua-typo.dtx index ebcd727a67b..29e087ccb13 100644 --- a/Master/texmf-dist/source/lualatex/lua-typo/lua-typo.dtx +++ b/Master/texmf-dist/source/lualatex/lua-typo/lua-typo.dtx @@ -1,9 +1,5 @@ -% \CheckSum{373} -% % \iffalse meta-comment % -% Copyright © 2020-2021 Daniel Flipo. -% % This program can be distributed and/or modified under the terms % of the LaTeX Project Public License either version 1.3c of this % license or (at your option) any later version. @@ -16,7 +12,7 @@ % % Lua-Typo package for LaTeX version 2e % -% Copyright © 2020-2021 by Daniel Flipo +% Copyright © 2020-2023 by Daniel Flipo % % Please report errors to: daniel (dot) flipo (at) free (dot) fr % @@ -36,12 +32,18 @@ \let\MetaPrefix\DoubleperCent \askforoverwritefalse \generate{% - \file{lua-typo.sty}{\from{lua-typo.dtx}{sty}}% {sty,dbg} - \nopreamble - \file{lua-typo.cfg}{\from{lua-typo.dtx}{cfg}}% - \file{lua-typo-fr.ltx}{\from{lua-typo.dtx}{driver,docfr}}% - \file{lua-typo.ltx}{\from{lua-typo.dtx}{driver,doc}}% -} + \file{lua-typo.sty}{\from{lua-typo.dtx}{sty}}% + \nopreamble + \file{lua-typo.cfg}{\from{lua-typo.dtx}{cfg}}% + \file{lua-typo-fr.ltx}{\from{lua-typo.dtx}{driver,docfr}}% + \file{lua-typo.ltx}{\from{lua-typo.dtx}{driver,doc}}% + } +\iffalse + \generate{% + \file{lua-typo.sty}{\from{lua-typo.dtx}{sty,dbg}}% + \file{scan-page.sty}{\from{lua-typo.dtx}{scan}}% + } +\fi \endbatchfile % %<*gobble> @@ -51,24 +53,24 @@ % %<*driver> \RequirePackage{pdfmanagement-testphase} -%<-docfr>\DeclareDocumentMetadata{pdfstandard=A-2b, lang=en-GB} -%<-doc>\DeclareDocumentMetadata{pdfstandard=A-2b, lang=fr-FR} +%<+doc>\DeclareDocumentMetadata{pdfstandard=A-2b, lang=en-GB} +%<+docfr>\DeclareDocumentMetadata{pdfstandard=A-2b, lang=fr-FR} \documentclass[a4paper]{ltxdoc} \usepackage[dvipsnames]{xcolor} \usepackage{fontspec} \setmainfont{erewhon} \setsansfont{Cabin}[Scale=MatchLowercase] \setmonofont{VeraMono.ttf}[ + Scale = MatchLowercase, ItalicFont = VeraMoIt.ttf, BoldFont = VeraMoBd.ttf, BoldItalicFont = VeraMoBI.ttf, - Scale = MatchLowercase, HyphenChar=None, Color=Sepia, ] \usepackage[expansion=true, protrusion=true]{microtype} -%<-docfr>\usepackage[british]{babel} -%<-doc>\usepackage[french]{babel} -%<-doc>\frenchsetup{og=«, fg=»} +%<+doc>\usepackage[british]{babel} +%<+docfr>\usepackage[french]{babel} +%<+docfr>\frenchsetup{og=«, fg=»} \usepackage[ShortPages, OverfullLines, UnderfullLines, Widows, Orphans, EOPHyphens, RepeatedHyphens ]{lua-typo} @@ -79,24 +81,27 @@ \usepackage[numbered]{hypdoc} \hypersetup{colorlinks,urlcolor=blue,unicode} % -%<-doc>\OnlyDescription -%<-doc>\let\FrenchDoc\begingroup\let\endFrenchDoc\endgroup -% -%<-docfr>\let\FrenchDoc\comment\let\endFrenchDoc\endcomment -%<-docfr>\RecordChanges -%<-docfr>\AtEndDocument{% -%<-docfr> \clearpage -%<-docfr> \section{Change History}% -%<-docfr> \GlossaryPrologue{}% -%<-docfr> Changes are listed in reverse order (latest first) -%<-docfr> from version~0.30. -%<-docfr> \PrintChanges -%<-docfr>} -% +%<+docfr>\OnlyDescription +%<+docfr>\let\FrenchDoc\begingroup\let\endFrenchDoc\endgroup +%<+doc|docfr>\let\Debugging\comment\let\endDebugging\endcomment +%<*doc> +\let\FrenchDoc\comment\let\endFrenchDoc\endcomment +\RecordChanges +\AtEndDocument{% + \clearpage + \section{Change History}% + \GlossaryPrologue{}% + Changes are listed in reverse order (latest first) + from version~0.30. + \PrintChanges +} +% +\newcommand*\texdir[1]{\textsc{#1}} \newcommand*\file[1]{\texttt{#1}} \newcommand*\pkg[1]{\texttt{#1}} \newcommand*\opt[1]{\texttt{#1}} \renewcommand\meta[1]{\texttt{\textsl{\color{Sepia}<#1>}}} +\newcommand*\node[1]{\textsc{#1}} % \setlength{\parindent}{0pt} \setlength{\parskip}{.3\baselineskip plus 0.3pt minus 0.3pt} @@ -155,6 +160,16 @@ % d’une coupure malvenue ne va pas provoquer des désordres plus % graves encore. % +% Un outil potentiellement utile est la commande TeX |\spaceskip| +% qui, utilisée dans un groupe, permet de modifier localement +% l’espace inter-mots. Un léger accroissement de celui-ci dans un +% paragraphe peut rendre acceptable la dernière ligne de celui-ci +% alors qu’elle était trop courte ou, si elle était presque pleine, +% lui ajouter une ligne, supprimant ainsi une orpheline éventuelle. +% De même une légère réduction de l’espace inter-mots peut supprimer +% la dernière ligne (courte) d’un paragraphe et éviter une veuve en +% début de la page suivante. +% % Je conseille de n’appliquer \pkg{lua-typo} que sur des textes % « presque au point », d’améliorer ce qui peut l’être puis de % \emph{supprimer} l’appel à \pkg{lua-typo} afin de ne pas risquer @@ -163,7 +178,7 @@ % \pkg{lua-typo}, il suffit d’ajouter dans le préambule la ligne\\ % |\usepackage[All]{lua-typo}| % -% La version courante (0.50) nécessite un noyau LaTeX très récent, +% La version courante (0.60) nécessite un noyau LaTeX récent, % 2021/06/01 ou ultérieur. Ceux qui ne disposent que d’un noyau plus % ancient reçoivent un message d’avertissement et un message d’erreur % «\texttt{Unable to register callback}» ; une version «rollback » @@ -173,6 +188,7 @@ % Les fichiers \file{demo.tex} et \file{demo.pdf} fournissent un % exemple du traitement opéré par \pkg{lua-typo}. % +% \pagebreak[4] % Un grand merci à Jacques André et Thomas Savary pour avoir accepté % de tester les pré-versions et pour leurs retours riches et toujours % pertinents ; leurs suggestions et leurs encouragements ont @@ -286,10 +302,10 @@ % % Le fichier \file{lua-typo.cfg} fourni avec la distribution reprend % exactement les réglages internes, il se trouve normalement dans le -% répertoire \textsc{texmfdist} des distributions TeXLive, MikTeX, etc. +% répertoire \texdir{texmfdist} des distributions TeXLive, MikTeX, etc. % L’utilisateur a la possibilité de recopier ce fichier soit dans son % répertoire de travail pour un document particulier, soit dans son -% répertoire \textsc{texmfhome} ou \textsc{texmflocal} et de le +% répertoire \texdir{texmfhome} ou \texdir{texmflocal} et de le % personnaliser comme il l’entend. % % Voici la liste complète des paramètres personnalisables avec leur @@ -379,8 +395,8 @@ % \luatypoSetColor4{cyan} % Veuve % \luatypoSetColor5{cyan} % Orpheline % \luatypoSetColor6{cyan} % Dernière ligne d’alinéa trop courte -% \luatypoSetColor7{mygrey} % Ligne trop pleine -% \luatypoSetColor8{mygrey} % Ligne creuse +% \luatypoSetColor7{blue} % Ligne trop pleine +% \luatypoSetColor8{blue} % Ligne creuse % \luatypoSetColor9{red} % Page presque vide (qq. lignes) % \luatypoSetColor{10}{myred} % Répétitions en début de ligne % \luatypoSetColor{11}{myred} % Répétitions en fin de ligne @@ -424,17 +440,26 @@ % issues (underflow/overfull lines) when fixing one of the flaws % mentionned above, human correction providing much better results. % For completeness, overfull and underfull lines are also coloured -% (in grey by default) and mentionned in the summary provided at the +% (in blue by default) and mentionned in the summary provided at the % end of the \file{.log} file. % +% The TeX commands |\spaceskip| and |\xspaceskip| which alter the +% inter-word spacing (locally when used in a group) should be +% considered: slightly enlarging the inter-word space may be +% sufficient to make a paragraph’s last line acceptable when it was +% originally too short or add a line to a paragraph when its last +% line was nearly full, thus possibly removing an orphan. +% Conversely, slightly reducing it may remove a paragraph’s last line +% (when it was short) and get rid of a widow on top of next page. +% % I suggest to add a call |\usepackage[All]{lua-typo}| to the % preamble of a document which is ``nearly finished’’ % \emph{and to remove it} once all possible corrections have been % made: if some flaws remain, getting them printed in colour in % the final document would be a shame! % -% This version (0.50) requires the latest LaTeX kernel (dated -% 2021/06/01). Users running an older kernel will get a warning +% Starting with version 0.50 a recent LaTeX kernel (dated 2021/06/01) +% is reiquired. Users running an older kernel will get a warning % and an error message ``\texttt{Unable to register callback}’’; % for them, a ``rollback’’ version of \pkg{lua-typo} is provided, % it can be loaded this way: |\usepackage[All]{lua-typo}[=v0.4]|. @@ -461,7 +486,6 @@ % or to enable just a few checks, then do it this way:\\ % |\usepackage[|\meta{OptX}|, |\meta{OptY}|, |\meta{OptZ}|]{lua-typo}| % -% \pagebreak % Here is the full list of possible checks (name and purpose):\\[12pt] % \begin{tabular}{>{\ttfamily}ll} % \multicolumn{1}{l}{Name} & Glitch to highlight\\ \hline @@ -537,16 +561,16 @@ % % A default configuration file \file{lua-typo.cfg} is provided % with all parameters set to their defaults; it is located under -% the \textsc{texmfdist} directory. It is up to the users to copy -% this file into their working directory (or \textsc{texmfhome} or -% \textsc{texmflocal}) and tune the defaults according to their own +% the \texdir{texmfdist} directory. It is up to the users to copy +% this file into their working directory (or \texdir{texmfhome} or +% \texdir{texmflocal}) and tune the defaults according to their own % taste. % % It is also possible to provide defaults directly in the % document’s preamble (this overwrites the corresponding settings % done in the configuration file found on TeX’s search path: current -% directory, then \textsc{texmfhome}, \textsc{texmflocal} and -% finally \textsc{texmfdist}. +% directory, then \texdir{texmfhome}, \texdir{texmflocal} and +% finally \texdir{texmfdist}. % % Here are the parameters names (all prefixed by |luatypo| in order % to avoid conflicts with other packages) and their default values: @@ -626,8 +650,8 @@ % \luatypoSetColor4{cyan} % Widow % \luatypoSetColor5{cyan} % Orphan % \luatypoSetColor6{cyan} % Paragraph ending on a short line -% \luatypoSetColor7{mygrey} % Overfull lines -% \luatypoSetColor8{mygrey} % Underfull lines +% \luatypoSetColor7{blue} % Overfull lines +% \luatypoSetColor8{blue} % Underfull lines % \luatypoSetColor9{red} % Nearly empty page (a few lines) % \luatypoSetColor{10}{myred} % First word matches % \luatypoSetColor{11}{myred} % Last word matches @@ -645,18 +669,18 @@ % \section{\TeX{}nical details} % % \iffalse -%<*sty> +%<*sty|scan> %% IMPORTANT NOTICE: %% For the copyright see the source file `lua-typo.dtx’. %% -\ProvidesPackage{lua-typo} -% -%<*dtx> -\ProvidesFile{lua-typo.dtx} -% -%<*dtx|sty> - [2021/05/13 v.0.50 Daniel Flipo] -% +\NeedsTeXFormat{LaTeX2e}[2021/06/01] +% +%<+sty>\ProvidesPackage{lua-typo} +%<+scan>\ProvidesPackage{scan-page} +%<+dtx>\ProvidesFile{lua-typo.dtx} +%<*dtx|sty|scan> + [2023-02-04 v.0.60 Daniel Flipo] +% %<*sty> % \fi % @@ -671,10 +695,10 @@ % \begin{macrocode} \ifdefined\DeclareRelease \DeclareRelease{v0.4}{2021-01-01}{lua-typo-2021-04-18.sty} - \DeclareCurrentRelease{}{2021-05-13} + \DeclareCurrentRelease{}{2023-02-04} \else \PackageWarning{lua-typo}{Your LaTeX kernel is too old to provide - access\MessageBreak to former versions of the lettrine package.% + access\MessageBreak to former versions of the lua-typo package.% \MessageBreak Anyway, lua-typo requires a LaTeX kernel dated% \MessageBreak 2020-01-01 or newer; reported} \fi @@ -927,11 +951,11 @@ luatypo = { } \directlua{ texio.write_nl(' ') texio.write_nl('*************************************') - if luatypo.pagelist == "" then + if luatypo.pagelist == " " then texio.write_nl('*** lua-typo: No Typo Flaws found.') else texio.write_nl('*** lua-typo: WARNING *************') - texio.write_nl('The following pages need attention: ') + texio.write_nl('The following pages need attention:') texio.write(luatypo.pagelist) end texio.write_nl('***********************************') @@ -965,8 +989,8 @@ luatypo = { } local s = string.char(c) luatypo.single[langno] = luatypo.single[langno] .. s end -% texio.write_nl("SINGLE=" .. luatypo.single[langno]) -% texio.write_nl(' ') +% texio.write_nl("SINGLE=" .. luatypo.single[langno]) +% texio.write_nl(' ') }% \else \PackageWarning{luatypo}{Unknown language "\luatypo@LANG", @@ -984,8 +1008,8 @@ luatypo = { } local s = string.char(c) luatypo.double[langno] = luatypo.double[langno] .. s end -% texio.write_nl("DOUBLE=" .. luatypo.double[langno]) -% texio.write_nl(' ') +% texio.write_nl("DOUBLE=" .. luatypo.double[langno]) +% texio.write_nl(' ') }% \else \PackageWarning{luatypo}{Unknown language "\luatypo@LANG", @@ -1020,7 +1044,7 @@ luatypo = { } luatypo.single = { } luatypo.double = { } luatypo.colortbl = { } -luatypo.pagelist = "" +luatypo.pagelist = " " luatypo.buffer = "List of typographic flaws found for " .. tex.jobname .. ".tex:\string\n\string\n" @@ -1112,7 +1136,7 @@ local color_node = function (node, color) local repl = node.replace if pre then set_attribute(pre,attr,color) -% texio.write_nl('PRE=' .. tostring(pre.char)) +% texio.write_nl('PRE=' .. tostring(pre.char)) end if post then set_attribute(post,attr,color) @@ -1193,7 +1217,7 @@ end % % This function appends a line to a buffer which will be written % to file `\cs{jobname.typo}’; it takes four arguments: -% a string, two numbers (which can be \texttt{nil}) and a flag. +% a string, two numbers (which can be \node{nil}) and a flag. % % \changes{v0.50}{2021/05/13}{Summary of flaws written to file % `\cs{jobname.typo}’.} @@ -1374,8 +1398,8 @@ local check_last_word = function (old, node, line, flag) until not n or n.id == GLUE end new = string.reverse(new) -% texio.write_nl('EOLsigold=' .. old) -% texio.write(' EOLsig=' .. new) +% texio.write_nl('EOLsigold=' .. old) +% texio.write(' EOLsig=' .. new) local MinFull = luatypo.MinFull local MinPart = luatypo.MinPart MinFull = math.min(MinPart,MinFull) @@ -1390,10 +1414,10 @@ local check_last_word = function (old, node, line, flag) local newsub = string.sub(new,-k) local l = string.len(new) if oldsub == newsub and l >= k then -% texio.write_nl('EOLnewsub=' .. newsub) +% texio.write_nl('EOLnewsub=' .. newsub) match = true elseif oldlast == newlast and string.len(newlast) >= MinFull then -% texio.write_nl('EOLnewlast=' .. newlast) +% texio.write_nl('EOLnewlast=' .. newlast) match = true oldsub = oldlast newsub = newlast @@ -1415,7 +1439,7 @@ local check_last_word = function (old, node, line, flag) end pageflag = true newsub = string.gsub(newsub, '^_', '') -% texio.write_nl('EOLfullmatch=' .. newsub) +% texio.write_nl('EOLfullmatch=' .. newsub) local msg = "E.O.L. MATCH=" .. newsub log_flaw(msg, line, colno, footnote) % \end{macrocode} @@ -1512,10 +1536,10 @@ local check_first_word = function (old, node, line, flag) local newsub = string.sub(new,1,k) local l = string.len(newsub) if oldsub == newsub and l >= k then -% texio.write_nl('BOLnewsub=' .. newsub) +% texio.write_nl('BOLnewsub=' .. newsub) match = true elseif oldfirst == newfirst and string.len(newfirst) >= MinFull then -% texio.write_nl('BOLnewfirst=' .. newfirst) +% texio.write_nl('BOLnewfirst=' .. newfirst) match = true oldsub = oldfirst newsub = newfirst @@ -1537,7 +1561,7 @@ local check_first_word = function (old, node, line, flag) end pageflag = true newsub = string.gsub(newsub, '_$', '') --$ -% texio.write_nl('BOLfullmatch=' .. newsub) +% texio.write_nl('BOLfullmatch=' .. newsub) local msg = "B.O.L. MATCH=" .. newsub log_flaw(msg, line, colno, footnote) % \end{macrocode} @@ -1569,7 +1593,7 @@ end % This auxillary function looks for a short word (one or two chars) % at end of lines, compares it to a given list and colours it if % matches. The first argument must be a node of type |GLYPH|, -% usually the last line’s node, the second one is the line number.\\ +% usually the last line’s node, the second one is the line number.\par % TODO: where does ``out of range’’ starts? U+0100? U+0180? % % \begin{macrocode} @@ -1646,7 +1670,7 @@ end % % This auxillary function prints the first part of an hyphenated word % up to the discretionary, with a supplied colour. -% It requires two arguments: a |DISC| node and a (named) colour. +% It requires two arguments: a \node{disc} node and a (named) colour. % % \begin{macrocode} local show_pre_disc = function (disc, color) @@ -1659,7 +1683,58 @@ local show_pre_disc = function (disc, color) end % \end{macrocode} % -% This auxillary function scans the `vlists’ in search of the page body. +% \begin{macro}{footnoterule-ahead} +% This auxillary function scans the current \node{vlist} in search +% of a |\footnoterule|; it returns |true| if found, false otherwise. +% The \node{rule} node above footnotes is normaly surrounded by +% two (vertical) \node{kern} nodes, the total height is either +% 0 (standard and koma classes) or equals the rule’s height +% (memoir class). +% +% \changes{v0.50}{2021/05/02}{New function `footnoterule\_ahead’.} +% +% \begin{macrocode} +local footnoterule_ahead = function (head) + local n = head + local flag = false + local totalht, ruleht, ht1, ht2, ht3 + if n and n.id == KERN and n.subtype == 1 then + totalht = n.kern + n = n.next +% ht1 = string.format("%.2fpt", totalht/65536) +% \end{macrocode} +% \changes{v0.51}{2023/01/17}{In some cases glue nodes might preceed +% the footnote rule; next line added} +% \begin{macrocode} + while n and n.id == GLUE do n = n.next end + if n and n.id == RULE and n.subtype == 0 then + ruleht = n.height +% ht2 = string.format("%.2fpt", ruleht/65536) + totalht = totalht + ruleht + n = n.next + if n and n.id == KERN and n.subtype == 1 then +% ht3 = string.format("%.2fpt", n.kern/65536) + totalht = totalht + n.kern + if totalht == 0 or totalht == ruleht then + flag = true + else +% texio.write_nl(' ') +% texio.write_nl('Not a footnoterule:') +% texio.write(' KERN height=' .. ht1) +% texio.write(' RULE height=' .. ht2) +% texio.write(' KERN height=' .. ht3) + end + end + end + end + return flag +end +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{get-pagebody} +% This auxillary function scans the \node{vlist}s on the current +% page in search of the page body. % It returns the corresponding node or nil in case of failure. % % \changes{v0.50}{2021/05/02}{New function `get\_pagebody’ required for @@ -1673,21 +1748,29 @@ local get_pagebody = function (head) repeat fn = fn.next until fn.id == VLIST and fn.height > 0 -% texio.write_nl(' ht=' .. fn.height/65536 .. 'pt') -% texio.write(' dp=' .. fn.depth/65536 .. 'pt') +% texio.write_nl(' ') +% local ht = string.format("%.1fpt", fn.height/65536) +% local dp = string.format("%.1fpt", fn.depth/65536) +% texio.write_nl('get_pagebody: TOP VLIST') +% texio.write(' ht=' .. ht .. ' dp=' .. dp) first = fn.list for n in traverse_id(VLIST,first) do if n.subtype == 0 and n.height == textht then -% texio.write_nl(' BODY: ' .. n.height/65536 .. 'pt') +% local ht = string.format("%.1fpt", n.height/65536) +% texio.write_nl('BODY found: ht=' .. ht) +% texio.write_nl(' ') body = n break else -% texio.write_nl(' ht=' .. n.height/65536 .. 'pt') -% texio.write_nl(' dp=' .. n.depth/65536 .. 'pt') +% texio.write_nl('Skip short VLIST:') +% local ht = string.format("%.1fpt", n.height/65536) +% local dp = string.format("%.1fpt", n.depth/65536) +% texio.write(' ht=' .. ht .. ' dp=' .. dp) first = n.list for n in traverse_id(VLIST,first) do if n.subtype == 0 and n.height == textht then -% texio.write_nl(' BODY: ' .. n.height/65536 .. 'pt') +% local ht = string.format("%.1fpt", n.height/65536) +% texio.write_nl(' BODY: ht=' .. ht) body = n break end @@ -1700,61 +1783,26 @@ local get_pagebody = function (head) return body end % \end{macrocode} +% \end{macro} % -% This auxillary function scans the current `vlist’ in search -% of a |\footnoterule| (kern, rule, kern, totalheight=0). -% It returns |true| if found, false othewise. +% \begin{macro}{check-vtop} +% This function is called repeatedly by |check_page| (see below); +% it scans the boxes found in the page body (f.i. columns) +% in search of typographical flaws and logs them if it finds any. % -% \changes{v0.50}{2021/05/02}{New function `footnoterule\_ahead’.} +% \changes{v0.40}{2021/04/18}{Title pages, pages with figures and/or +% tables may not be empty pages: check `vpos’ last line’s position.} % -% \begin{macrocode} -local footnoterule_ahead = function (head, debug) - local n = head - local flag = false - if n and n.id == KERN and n.subtype == 1 then - local htr = n.kern - local ht1, ht2, ht3 -% if debug then -% ht1 = string.format("%.2fpt", n.kern/65536) -% end - n = n.next - if n and n.id == RULE and n.subtype == 0 then - htr = htr + n.height -% if debug then -% ht2 = string.format("%.2fpt", n.height/65536) -% end - n = n.next - if n and n.id == KERN and n.subtype == 1 then - htr = htr + n.kern -% if debug then -% ht3 = string.format("%.2fpt", n.kern/65536) -% texio.write_nl(' ') -% texio.write_nl('KERN height: ' .. ht1) -% texio.write(' RULE height: ' .. ht2) -% texio.write(' KERN height: ' .. ht3) -% texio.write_nl('TOTAL height: ' .. htr .. 'sp') -% end - if htr == 0 then - flag = true -% if debug then -% texio.write(' => footnoterule found!') -% end - end - end - end - end - return flag -end -% \end{macrocode} +% \changes{v0.60}{2023/01/28}{Loop redesigned.} % -% This function scans the page body (or each column) in search of -% typographical flaws. +% \changes{v0.60}{2023/01/29}{Typographical flaws are recorded here +% (formerly in check\_page).} % -% \changes{v0.40}{2021/04/18}{Title pages, pages with figures and/or -% tables may not be empty pages: check `vpos’ last line’s position.} +% \changes{v0.60}{2023/01/29}{Break `check\_vtop’ loop +% if a two columns box starts.} % % \begin{macrocode} -check_vtop = function (head, colno) +check_vtop = function (head, colno, vpos) local PAGEmin = luatypo.PAGEmin local HYPHmax = luatypo.HYPHmax local LLminWD = luatypo.LLminWD @@ -1776,13 +1824,9 @@ check_vtop = function (head, colno) local FootnoteSplit = luatypo.FootnoteSplit local Stretch = math.max(luatypo.Stretch/100,1) local blskip = tex.getglue("baselineskip") - local pageno = tex.getcount("c@page") local vpos_min = PAGEmin * blskip vpos_min = vpos_min * 1.5 - local vpos = 0 - local pageflag = false - local body_bottom = false - local page_bottom = false + local linewd = tex.getdimen("textwidth") local first_bot = true local footnote = false local ftnsplit = false @@ -1796,37 +1840,31 @@ check_vtop = function (head, colno) local pageline = 0 local ftnline = 0 local line = 0 + local body_bottom = false + local page_bottom = false + local pageflag = false + local plist = luatypo.pagelist + local lastp = tonumber(string.match(plist, "%s(%d+),%s$")) + local pageno = tex.getcount("c@page") % \end{macrocode} % The main loop scans the content of the |\vtop| holding the page % (or column) body, footnotes included. -% The vertical position of the current node is stored in the |vpos| -% dimension (integer in `sp’ units). % \begin{macrocode} while head do local nextnode = head.next % \end{macrocode} -% If a |\footnoterule| is found, set the |footnote| flag and reset -% some counters and flags for the coming footnotes. +% Let's scan the top nodes of this vbox: expected are \node{hlist} +% (text lines or vboxes), \node{rule}, \node{kern}, \node{glue}… % \begin{macrocode} - if not footnote and head.id == KERN and head.subtype == 1 then - if footnoterule_ahead(head, true) then - footnote = true - ftnline = 0 - body_bottom = false - orphanflag = false - lwhyphflag = false - hyphcount = 0 - firstwd = "" - lastwd = "" - else - vpos = vpos + head.kern - end - elseif head.id == HLIST and head.subtype == LINE and + if head.id == HLIST and head.subtype == LINE and (head.height > 0 or head.depth > 0) then % \end{macrocode} -% This is a text line, increment counters |pageline| or -% |ftnline| and |line| (for |log_flaw|). +% This is a text line, store the line width, increment counters +% |pageline| or |ftnline| and |line| (for |log_flaw|). +% Let’s update |vpos| (vertical position in `sp' units) too. % \begin{macrocode} + vpos = vpos + head.height + head.depth + linewd = head.width if footnote then ftnline = ftnline + 1 line = ftnline @@ -1835,12 +1873,30 @@ check_vtop = function (head, colno) line = pageline end % \end{macrocode} -% Is it overfull or underfull? +% Is this line the last one on the page or before footnotes?\par +% This has to be known early (orphanflag, lwhyphflag, ftnsplit). +% \begin{macrocode} + local n = nextnode + while n and (n.id == GLUE or n.id == PENALTY or + n.id == WHATSIT ) do + n = n.next + end + if not n then + page_bottom = true + body_bottom = true + elseif footnoterule_ahead(n) then + body_bottom = true +% texio.write_nl('=> FOOTNOTE RULE ahead') +% texio.write_nl('check_vtop: last line before footnotes') +% texio.write_nl(' ') + end +% \end{macrocode} +% Is the current line overfull or underfull? % \changes{v0.50}{2021/05/13}{Detection of overfull boxes fixed: the % former code didn’t work for typewriter fonts.} % \begin{macrocode} local first = head.head - local hmax = head.width + tex.hfuzz + local hmax = linewd + tex.hfuzz local w,h,d = dimensions(1,2,0, first) if w > hmax and OverfullLines then pageflag = true @@ -1859,34 +1915,6 @@ check_vtop = function (head, colno) color_line (head, COLOR) end % \end{macrocode} -% Let’s update |vpos| and check if the current line is the last one -% of the page body; this requires to look ahead \emph{now} for the -% next nodes in the `vlist’ as this information is needed to decide -% about orphans, last page’s word hyphenated, etc. -% \begin{macrocode} - vpos = vpos + head.height + head.depth - local n = head.next - while n and - (n.id == GLUE or n.id == PENALTY or n.id == WHATSIT) do - n = n.next - end -% \end{macrocode} -% Is this line the last one on the current page? … -% \begin{macrocode} - if not n then - if footnote then - page_bottom = true - else - page_bottom = true - body_bottom = true - end -% \end{macrocode} -% or the last one before |\footnoterule|? -% \begin{macrocode} - elseif footnoterule_ahead(n, false) then - body_bottom = true - end -% \end{macrocode} % Set flag |ftnsplit| to |true| on every page’s last line. % This flag will be reset to false if the current line ends a % paragraph. @@ -1922,14 +1950,14 @@ check_vtop = function (head, colno) hyphcount = 0 if not footnote then parline = 1 - end - if body_bottom then + if body_bottom then % \end{macrocode} % We are at the page bottom (footnotes excluded), this ligne is % an orphan (unless it is the unique line of the paragraph, this % will be checked later when scanning the end of line). % \begin{macrocode} - orphanflag = true + orphanflag = true + end end % \end{macrocode} % List items begin with |LPAR| followed by an hbox. @@ -1964,7 +1992,7 @@ check_vtop = function (head, colno) orphanflag = false % \end{macrocode} % but it is a widow if it is the page’s first line and it does’nt -% start a new paragraph.\\ Orphans and widows will be colored later. +% start a new paragraph.\par Orphans and widows will be colored later. % \begin{macrocode} if pageline == 1 and parline > 1 then widowflag = true @@ -1974,11 +2002,11 @@ check_vtop = function (head, colno) % \begin{macrocode} local PFskip = effective_glue(pn,head) if ShortLines then - local llwd = tex.hsize - PFskip -% local PFskip_pt = string.format("%.1fpt", PFskip/65536) -% local llwd_pt = string.format("%.1fpt", llwd/65536) -% texio.write_nl('PFskip= ' .. PFskip_pt) -% texio.write(' llwd= ' .. llwd_pt) + local llwd = linewd - PFskip +% local PFskip_pt = string.format("%.1fpt", PFskip/65536) +% local llwd_pt = string.format("%.1fpt", llwd/65536) +% texio.write_nl('PFskip= ' .. PFskip_pt) +% texio.write(' llwd= ' .. llwd_pt) % \end{macrocode} % |llwd| is the line’s length. Is it too short? % \begin{macrocode} @@ -2042,7 +2070,8 @@ check_vtop = function (head, colno) % \end{macrocode} % Does the next line end the current paragraph? If so, |nextnode| is % a `linebreak penalty’, the next one is a `baseline skip’ and the -% node after a `hlist of subtype line’ with |glue_order=2|. +% node after a \node{hlist} of subtype \node{line} with +% |glue_order=2|. % \begin{macrocode} local nn = nextnode.next local nnn = nil @@ -2059,9 +2088,9 @@ check_vtop = function (head, colno) end end % \end{macrocode} -% CASE 3: the current line ends with anything else (|MKERN|, -% |GLYPH|, |HLIST|, etc.), reset |hyphcount|, perform checks -% for `LastWordMatch’ and for `EOLShortWords’. +% CASE 3: the current line ends with anything else (\node{mkern}, +% \node{glyph}, \node{hlist}, etc.), reset |hyphcount|, perform +% checks for `LastWordMatch’ and for `EOLShortWords’. % \begin{macrocode} else hyphcount = 0 @@ -2089,7 +2118,7 @@ check_vtop = function (head, colno) color_line (head, COLOR) end % \end{macrocode} -% Colour the whole line if is is a orphan or footenote continuing +% Colour the whole line if is is a orphan or footnote continuing % on the next page. % \begin{macrocode} if orphanflag and Orphans then @@ -2116,16 +2145,19 @@ check_vtop = function (head, colno) local COLOR = luatypo.colortbl[1] local pg = show_pre_disc (pn,COLOR) end +% \end{macrocode} +% End of scanning for the main type of node (text lines). +% \begin{macrocode} elseif head.id == HLIST and (head.subtype == EQN or head.subtype == ALIGN) and (head.height > 0 or head.depth > 0) then % \end{macrocode} +% This line is a displayed or aligned equation. +% Let’s update |vpos| and the line number. % % \changes{v0.50}{2021/05/05}{Consider displayed and aligned equations % too for overfull boxes.} % -% This line is a displayed or aligned equation. -% Let’s update |vpos| and the line number. % \begin{macrocode} vpos = vpos + head.height + head.depth if footnote then @@ -2139,7 +2171,8 @@ check_vtop = function (head, colno) % Let’s check for an ``Overfull box''. For a displayed equation % it is straightforward. A set of aligned equations all have the % same (maximal) width; in order to avoid highlighting the whole -% set, we have to look for glues at the end of embedded `hlists’. +% set, we have to look for glues at the end of embedded +% \node{hlist}s. % \begin{macrocode} local fl = true local wd = 0 @@ -2173,49 +2206,53 @@ check_vtop = function (head, colno) color_line (head, COLOR) end end + elseif head and head.id == RULE and head.subtype == 0 then % \end{macrocode} -% We also need to set flag |body_bottom| and to increment the -% |pageline| counter to track empty pages. +% This is a \node{rule}, possibly a footnote rule. % \begin{macrocode} - local n = head.next - while n and (n.id == GLUE or n.id == PENALTY or - n.id == WHATSIT or n.id == VLIST) do - n = n.next - end - if not n then - page_bottom = true - body_bottom = true - elseif footnoterule_ahead(n, false) then - body_bottom = true - end + vpos = vpos + head.height + head.depth + if body_bottom then % \end{macrocode} -% This is a |\vbox|, let’s update |vpos|. +% If a |\footnoterule| has been detected on the previous run, +% set the |footnote| flag and reset some counters and flags +% for the coming footnote lines. % \begin{macrocode} - elseif head.id == VLIST then - vpos = vpos + head.height + head.depth +% texio.write_nl('check_vtop: footnotes start') +% texio.write_nl(' ') + footnote = true + ftnline = 0 + body_bottom = false + ftnrule_ahead = false + orphanflag = false + lwhyphflag = false + hyphcount = 0 + firstwd = "" + lastwd = "" + end % \end{macrocode} -% Track empty pages: check the number of lines at end of page, +% Track short pages: check the number of lines at end of page, % in case this number is low, \emph{and} |vpos| is less than -% |vpos_min|, fetch the last line and colour it.\\ +% |vpos_min|, fetch the last line and colour it.\par % NOTE1: |effective_glue| requires a `parent’ node, as pointed out by % Marcel Krüger on S.E., this implies using |pre_shipout_filter| -% instead of |pre_output_filter|.\\ +% instead of |pre_output_filter|.\par % NOTE2: Widows are already detected, skip them here; there are -% usually two consecutive nodes of type 12-0 at end of pages… +% usually two consecutive nodes of type \node{glue}-0 at end of +% pages… % \begin{macrocode} elseif body_bottom and head.id == GLUE and head.subtype == 0 then if first_bot then -% local vpos_pt = string.format("%.1fpt", vpos/65536) -% local vmin_pt = string.format("%.1fpt", vpos_min/65536) -% texio.write_nl('pageline=' .. pageline) -% texio.write_nl('vpos=' .. vpos_pt) -% texio.write(' vpos_min=' .. vmin_pt) -% if page_bottom then -% local tht = tex.getdimen("textheight") -% local tht_pt = string.format("%.1fpt", tht/65536) -% texio.write(' textheight=' .. tht_pt) -% end -% texio.write_nl(' ') +% local vpos_pt = string.format("%.1fpt", vpos/65536) +% local vmin_pt = string.format("%.1fpt", vpos_min/65536) +% texio.write_nl('pageline=' .. pageline) +% texio.write_nl('vpos=' .. vpos_pt) +% texio.write(' vpos_min=' .. vmin_pt) +% if page_bottom then +% local tht = tex.getdimen("textheight") +% local tht_pt = string.format("%.1fpt", tht/65536) +% texio.write(' textheight=' .. tht_pt) +% end +% texio.write_nl(' ') if pageline > 1 and pageline < PAGEmin and ShortPages then pageshort = true end @@ -2232,85 +2269,176 @@ check_vtop = function (head, colno) end first_bot = false end + elseif head.id == GLUE then % \end{macrocode} % Increment |vpos| on other vertical glues. % \begin{macrocode} - elseif head.id == GLUE then vpos = vpos + effective_glue(head,body) + elseif head.id == KERN and head.subtype == 1 then +% \end{macrocode} +% This is a vertical kern, let’s update |vpos|. +% \begin{macrocode} + vpos = vpos + head.kern + elseif head.id == VLIST then +% \end{macrocode} +% This is a vertical a |\vbox|, let’s update |vpos|. +% \begin{macrocode} + vpos = vpos + head.height + head.depth +% \end{macrocode} +% Leave |check_vtop| if a two columns box starts. +% \begin{macrocode} + elseif head.id == HLIST and head.subtype == BOX then + local hf = head.list + if hf and hf.id == VLIST and hf.subtype == 0 then +% texio.write_nl('check_vtop: BREAK => multicol') +% texio.write_nl(' ') + break + end end head = nextnode end - return pageflag +% if nextnode then +% texio.write('Exit check_vtop, next=') +% texio.write(tostring(node.type(nextnode.id))) +% texio.write('-'.. nextnode.subtype) +% else +% texio.write_nl('Exit check_vtop, next=nil') +% end +% texio.write_nl('') +% \end{macrocode} +% Record flaws: +% \begin{macrocode} + if pageflag then + if not lastp or pageno > lastp then + luatypo.pagelist = luatypo.pagelist .. tostring(pageno) .. ", " + end + end + return head +% \end{macrocode} +% head is nil unless |check_vtop| exited on a two column start. +% \begin{macrocode} end % \end{macrocode} +% \end{macro} % +% \begin{macro}{check-page} % This is the main function which will be added to the % |pre_shipout_filter| callback unless option |None| is selected. -% It executes |get_pagebody|, then scans the page body for possible -% columns (multi column page). +% It executes |get_pagebody| which returns a node of type +% \node{vlist}-0, then scans this \node{vlist}: expected are +% \node{vlist}-0 (full width block) or \node{hlist}-2 (multi +% column block). +% The vertical position of the current node is stored in the |vpos| +% dimension (integer in `sp’ units, 1\,pt~=~65536\,sp). It is used to +% detect short pages. +% +% \changes{v0.60}{2023/01/29}{Loop redesigned to properly handle +% two colums.} % % \begin{macrocode} luatypo.check_page = function (head) - local pageno = tex.getcount("c@page") - local pageflag = false + local textwd = tex.getdimen("textwidth") + local vpos = 0 local n2, n3, col, colno local body = get_pagebody(head) + local footnote = false + local top = body local first = body.list -% texio.write_nl('body.id=' .. tostring(node.type(body.id))) -% texio.write('-' .. body.subtype) -% texio.write_nl(' ') -% texio.write_nl('first.id=' .. tostring(node.type(first.id))) -% texio.write('-' .. first.subtype) -% texio.write_nl(' ') - if first.id == HLIST and first.subtype == 2 then + if (first and first.id == HLIST and first.subtype == BOX) or + (first and first.id == VLIST and first.subtype == 0) then % \end{macrocode} -% Two or more columns, each one is boxed in an hlist. -% Run |check_vtop| on every column. +% Some classes (\cls{memoir}, \cls{tugboat} …) use one more level +% of bowing, let’s step down one level. % \begin{macrocode} - n2 = first.list - colno = 0 - for n in traverse_id(HLIST, n2) do -% texio.write_nl('n.id=' .. tostring(node.type(n.id))) -% texio.write('-' .. n.subtype) -% texio.write(' ht=' .. n.height) -% texio.write_nl(' ') - if n.id == HLIST and n.subtype == 2 then - n3 = n.list -% texio.write_nl('n3.id=' .. tostring(node.type(n3.id))) -% texio.write('-' .. n3.subtype) -% texio.write(' ht=' .. n3.height) -% texio.write_nl(' ') - col = n3.list - colno = colno + 1 - pageflag = check_vtop(col,colno) - end - end - elseif body.id == VLIST and body.subtype == 0 then +% local boxwd = string.format("%.1fpt", first.width/65536) +% texio.write_nl('One step down: boxwd=' .. boxwd) +% texio.write_nl(' ') + top = body.list + first = top.list + end + while top do + first = top.list +% texio.write_nl('Page loop: top=' .. tostring(node.type(top.id))) +% texio.write('-' .. top.subtype) +% texio.write_nl(' ') + if top and top.id == VLIST and top.subtype == 0 and + top.width > textwd/2 then % \end{macrocode} % Single column, run |check_vtop| on the top vlist. % \begin{macrocode} - col = body.list - pageflag = check_vtop(col,colno) - end +% local boxht = string.format("%.1fpt", top.height/65536) +% local boxwd = string.format("%.1fpt", top.width/65536) +% texio.write_nl('**VLIST: ') +% texio.write(tostring(node.type(top.id))) +% texio.write('-' .. top.subtype) +% texio.write(' wd=' .. boxwd .. ' ht=' .. boxht) +% texio.write_nl(' ') + local next = check_vtop(first,colno,vpos) + if next then + top = next + elseif top then + top = top.next + end + elseif (top and top.id == HLIST and top.subtype == BOX) and + (first and first.id == VLIST and first.subtype == 0) and + (first.height > 0 and first.width > 0) then % \end{macrocode} -% Add this page number to the summary if any flaw has been found on it. -% Skip duplicates. -% -% \changes{v0.32}{2021/03/14}{Remove duplicates in the summary of pages.} -% +% Two or more columns, each one is boxed in a vlist.\par +% Run |check_vtop| on every column. % \begin{macrocode} - if pageflag then - local pl = luatypo.pagelist - local p = tonumber(string.match(pl, "%s(%d+),%s$")) - if not p or pageno > p then - luatypo.pagelist = luatypo.pagelist .. tostring(pageno) .. ", " - end +% texio.write_nl('**MULTICOL type1:') +% texio.write_nl(' ') + colno = 0 + for n in traverse_id(VLIST, first) do + colno = colno + 1 + col = n.list +% texio.write_nl('Start of col.' .. colno) +% texio.write_nl(' ') + check_vtop(col,colno,vpos) +% texio.write_nl('End of col.' .. colno) +% texio.write_nl(' ') + end + colno = nil + top = top.next +% texio.write_nl('MULTICOL type1 END: next=') +% texio.write(tostring(node.type(top.id))) +% texio.write('-' .. top.subtype) +% texio.write_nl(' ') + elseif (top and top.id == HLIST and top.subtype == BOX) and + (first and first.id == HLIST and first.subtype == BOX) and + (first.height > 0 and first.width > 0) then +% \end{macrocode} +% Two or more columns, each one is boxed in an hlist which +% holds a vlist.\par +% Run |check_vtop| on every column. +% \begin{macrocode} +% texio.write_nl('**MULTICOL type2:') +% texio.write_nl(' ') + colno = 0 + for n in traverse_id(HLIST, first) do + colno = colno + 1 + local nn = n.list + if nn and nn.list then + col = nn.list +% texio.write_nl('Start of col.' .. colno) +% texio.write_nl(' ') + check_vtop(col,colno,vpos) +% texio.write_nl('End of col.' .. colno) +% texio.write_nl(' ') + end + end + colno = nil + top = top.next + else + top = top.next + end end return true end return luatypo.check_page \end{luacode} % \end{macrocode} +% \end{macro} % % Add the |luatypo.check_page| function to the |pre_shipout_filter| % callback (with priority 1 for color attributes to be effective), @@ -2318,7 +2446,7 @@ return luatypo.check_page % boolean’s value is forwarded to Lua `AtEndOfPackage’… % % \changes{v0.50}{2021/05/02}{Callback `pre\_output\_filter’ replaced -% by `pre\_shipout\_filter’, in the later the material is not boxed +% by `pre\_shipout\_filter’, in the former the material is not boxed % yet and footnotes are not visible.} % % \begin{macrocode} @@ -2328,11 +2456,11 @@ return luatypo.check_page luatexbase.add_to_callback ("pre_shipout_filter",luatypo.check_page,"check_page",1) end - } + }% } % \end{macrocode} % -% Load a local config file if present in LaTeX’s search path.\\ +% Load a local config file if present in LaTeX’s search path.\par % Otherwise, set reasonnable defaults. % \enlargethispage*{\baselineskip} % \begin{macrocode} @@ -2429,32 +2557,290 @@ return luatypo.check_page %%\luatypoTwoChars{french}{'Je Tu Il On'} % \end{macrocode} % -%\iffalse +% \iffalse % % \fi % +% \changes{v0.60}{2023/02/02}{Debugging stuff added.} +% +% \section{Debugging lua-typo} +% +% Personal stuff useful \emph{only} for maintaining the +% \pkg{lua-typo} package has been added at the end of +% \file{lua-typo.dtx} in version~0.60. +% It is not extracted unless a) both `|\iffalse|’ and `|\fi|’ on +% lines 41 and 46 at the beginning of \file{lua-typo.dtx} are +% commented out and b) all files are generated again by a +% |luatex lua-typo.dtx| command; then a (very) verbose version of +% \file{lua-typo.sty} is generated together with +% a \file{scan-page.sty} file which can be used instead of +% \file{lua-typo.sty} to show the structured list of nodes +% found in a document. +% % \iffalse -%<*dtx> +%<*scan> % \fi -%% -%% \CharacterTable -%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z -%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z -%% Digits \0\1\2\3\4\5\6\7\8\9 -%% Exclamation \! Double quote \" Hash (number) \# -%% Dollar \$ Percent \% Ampersand \& -%% Acute accent \' Left paren \( Right paren \) -%% Asterisk \* Plus \+ Comma \, -%% Minus \- Point \. Solidus \/ -%% Colon \: Semicolon \; Less than \< -%% Equals \= Greater than \> Question mark \? -%% Commercial at \@ Left bracket \[ Backslash \\ -%% Right bracket \] Circumflex \^ Underscore \_ -%% Grave accent \` Left brace \{ Vertical bar \| -%% Right brace \} Tilde \~} -%% +% +% \begin{Debugging} +% \begin{macrocode} +\ifdefined\directlua + \RequirePackage{luatexbase,luacode,luacolor} + \RequirePackage{kvoptions,atveryend} +\else + \PackageError{This package is meant for LuaTeX only! Aborting} + {No more information available, sorry!} +\fi + +\newdimen\luatypoLLminWD +\newdimen\luatypoBackPI +\newdimen\luatypoBackFuzz +\newcount\luatypoStretchMax +\newcount\luatypoHyphMax +\newcount\luatypoPageMin +\newcount\luatypoMinFull +\newcount\luatypoMinPart +\newcount\luatypo@LANGno +\newcount\luatypo@options +\newtoks\luatypo@single +\newtoks\luatypo@double + +\AtBeginDocument{% + \directlua{ + luatypo.HYPHmax = tex.count.luatypoHyphMax + luatypo.PAGEmin = tex.count.luatypoPageMin + luatypo.Stretch = tex.count.luatypoStretchMax + luatypo.MinFull = tex.count.luatypoMinFull + luatypo.MinPart = tex.count.luatypoMinPart + luatypo.LLminWD = tex.dimen.luatypoLLminWD + luatypo.BackPI = tex.dimen.luatypoBackPI + luatypo.BackFuzz = tex.dimen.luatypoBackFuzz + }% +} + +\AtVeryEndDocument{% + \directlua{ + texio.write_nl(' ') + texio.write_nl('***************************') + texio.write_nl('*** PAGE SCANNING ONLY: ***') + texio.write_nl('*** NO CHECK PERFORMED! ***') + texio.write_nl('***************************') + texio.write_nl(' ') + }% +} + +\newcommand*{\luatypoOneChar}[2]{} +\newcommand*{\luatypoTwoChars}[2]{} +\newcommand*{\luatypoSetColor}[2]{} + +\begin{luacode} +luatypo = { } +luatypo.single = { } +luatypo.double = { } +luatypo.colortbl = { } +luatypo.pagelist = " " + +local hyphcount = 0 +local parlines = 0 +local pagelines = 0 +local pageno = 0 +local prevno = 0 +local pageflag = false + +local char_to_discard = { } +char_to_discard[string.byte(",")] = true +char_to_discard[string.byte(".")] = true +char_to_discard[string.byte("!")] = true +char_to_discard[string.byte("?")] = true +char_to_discard[string.byte(":")] = true +char_to_discard[string.byte(";")] = true +char_to_discard[string.byte("-")] = true + +local DISC = node.id("disc") +local GLYPH = node.id("glyph") +local GLUE = node.id("glue") +local KERN = node.id("kern") +local HLIST = node.id("hlist") +local VLIST = node.id("vlist") +local LPAR = node.id("local_par") +local MKERN = node.id("margin_kern") +local PENALTY = node.id("penalty") +local USRSKIP = 0 +local PARSKIP = 3 +local LEFTSKIP = 8 +local TOPSKIP = 10 +local PARFILL = 15 +local LINE = 1 +local BOX = 2 +local USER = 0 + +local dimensions = node.dimensions +local rangedimensions = node.rangedimensions +local effective_glue = node.effective_glue +local set_attribute = node.set_attribute +local slide = node.slide +local traverse = node.traverse +local traverse_id = node.traverse_id +local has_field = node.has_field +local uses_font = node.uses_font +local is_glyph = node.is_glyph + +% \end{macrocode} +% Some helpers functions. +% \begin{macrocode} +local get_pagebody = function (head) + local textht = tex.getdimen("textheight") + local fn = head.list + local body = nil + repeat + fn = fn.next + until fn.id == VLIST and fn.height > 0 + first = fn.list + local ht = string.format("%.1fpt", fn.height/65536) + local dp = string.format("%.1fpt", fn.depth/65536) + texio.write_nl('SKIP vlist: ht=' .. ht .. ' dp=' .. dp) + for n in traverse_id(VLIST,first) do + if n.subtype == 0 and n.height == textht then + local ht = string.format("%.1fpt", n.height/65536) + texio.write_nl(' BODY: ' .. ht) + texio.write_nl(' ') + body = n + break + else + local ht = string.format("%.1fpt", n.height/65536) + local dp = string.format("%.1fpt", n.depth/65536) + texio.write_nl(' SKIP vlist: ht=' .. ht .. ' dp=' .. dp) + first = n.list + for n in traverse_id(VLIST,first) do + if n.subtype == 0 and n.height == textht then + ht = string.format("%.1fpt", n.height/65536) + texio.write_nl(' BODY: ' .. ht) + texio.write_nl(' ') + body = n + break + end + end + end + end + if not body then + texio.write_nl('***lua-typo ERROR: PAGE BODY *NOT* FOUND!***') + end + return body +end + +local print_subtype = function (node,parent) + local n = node + if n.id == GLYPH and n.subtype == 256 and n.char < 0x100 then + texio.write(string.char(n.char)) + else + if n.subtype then + texio.write(n.subtype) + else + texio.write(' ') + end + end + if n.id == GLUE then + real_pt = string.format("%.1fpt", effective_glue(n,parent)/65536) + texio.write(' realwd=' .. real_pt) + elseif n.id == DISC then + texio.write(' pre=' .. tostring(n.pre)) + texio.write(' post=' .. tostring(n.post)) + texio.write(' repl=' .. tostring(n.replace)) + elseif n.subtype and n.subtype < 256 and n.height and n.depth then + ht_pt = string.format("%.1fpt", n.height/65536) + dp_pt = string.format("%.1fpt", n.depth/65536) + texio.write(' ht=' .. ht_pt .. ' dp=' .. dp_pt) + if n.width then + wd_pt = string.format("%.1fpt", n.width/65536) + texio.write(' wd=' .. wd_pt) + end + end +end + +% \end{macrocode} +% Main function. It prints a structured list of nodes found on the +% page body (header and footer excluded, footnotes included). +% \begin{macrocode} +local scanvlist = function (head) + local textht = tex.getdimen("textheight") + local textwd = tex.getdimen("textwidth") + local pageno = tex.getcount("c@page") + texio.write_nl('PAGE ' .. pageno) + texio.write(' textheight='.. string.format("%.1fpt", textht/65536)) + texio.write(' textwidth=' .. string.format("%.1fpt", textwd/65536)) + local linecount = 0 + local body, parent, ht_pt, dp_pt, real_pt + body = get_pagebody(head) + if body then + parent = body + head = body.head + end + while (head) do + texio.write_nl(tostring(node.type(head.id))) + texio.write('-') + print_subtype(head,body) + if head.kern then + ht_pt = string.format("%.1fpt", head.kern/65536) + texio.write(' KERN ht/wd=' .. ht_pt) + end + local next = head.next + local first = head.head + for n in traverse(first) do + parent = head + texio.write_nl(' ' .. tostring(node.type(n.id))) + texio.write('-') + print_subtype(n,head) + if n.id == VLIST or n.id == HLIST then + local ff = n.head + for nn in traverse(ff) do + parent = n + texio.write_nl(' ' .. tostring(node.type(nn.id))) + texio.write('-') + print_subtype(nn,n) + if nn.id == VLIST or nn.id == HLIST then + local f3 = nn.head + for n3 in traverse(f3) do + parent = nn + texio.write_nl(' ' .. tostring(node.type(n3.id))) + texio.write('-') + print_subtype(n3,nn) + if n3.id == VLIST or n3.id == HLIST then + local f4 = n3.head + for n4 in traverse(f4) do + parent = n3 + texio.write_nl(' ' .. tostring(node.type(n4.id))) + texio.write('-') + print_subtype(n4,n3) + if n4.id == VLIST or n4.id == HLIST then + local f5 = n4.head + for n5 in traverse(f5) do + parent = n4 + texio.write_nl(' ' .. tostring(node.type(n4.id))) + texio.write('-') + print_subtype(n5,n4) + end + end + end + end + end + end + end + end + end + head = next + end + return true +end + +% \end{macrocode} +% Add the main function to callback "pre\_shipout\_filter". +% \begin{macrocode} +luatexbase.add_to_callback("pre_shipout_filter",scanvlist,"check_vlists") +% \end{macrocode} +\end{luacode} +% \end{Debugging} +% % \iffalse -% +% % \fi % % \Finale diff --git a/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.sty b/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.sty index 5110fb0e605..4d64e57f297 100644 --- a/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.sty +++ b/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.sty @@ -9,14 +9,15 @@ %% IMPORTANT NOTICE: %% For the copyright see the source file `lua-typo.dtx’. %% +\NeedsTeXFormat{LaTeX2e}[2021/06/01] \ProvidesPackage{lua-typo} - [2021/05/13 v.0.50 Daniel Flipo] + [2023-02-04 v.0.60 Daniel Flipo] \ifdefined\DeclareRelease \DeclareRelease{v0.4}{2021-01-01}{lua-typo-2021-04-18.sty} - \DeclareCurrentRelease{}{2021-05-13} + \DeclareCurrentRelease{}{2023-02-04} \else \PackageWarning{lua-typo}{Your LaTeX kernel is too old to provide - access\MessageBreak to former versions of the lettrine package.% + access\MessageBreak to former versions of the lua-typo package.% \MessageBreak Anyway, lua-typo requires a LaTeX kernel dated% \MessageBreak 2020-01-01 or newer; reported} \fi @@ -218,11 +219,11 @@ luatypo = { } \directlua{ texio.write_nl(' ') texio.write_nl('*************************************') - if luatypo.pagelist == "" then + if luatypo.pagelist == " " then texio.write_nl('*** lua-typo: No Typo Flaws found.') else texio.write_nl('*** lua-typo: WARNING *************') - texio.write_nl('The following pages need attention: ') + texio.write_nl('The following pages need attention:') texio.write(luatypo.pagelist) end texio.write_nl('***********************************') @@ -277,7 +278,7 @@ luatypo = { } luatypo.single = { } luatypo.double = { } luatypo.colortbl = { } -luatypo.pagelist = "" +luatypo.pagelist = " " luatypo.buffer = "List of typographic flaws found for " .. tex.jobname .. ".tex:\string\n\string\n" @@ -730,6 +731,29 @@ local show_pre_disc = function (disc, color) end return n end +local footnoterule_ahead = function (head) + local n = head + local flag = false + local totalht, ruleht, ht1, ht2, ht3 + if n and n.id == KERN and n.subtype == 1 then + totalht = n.kern + n = n.next + while n and n.id == GLUE do n = n.next end + if n and n.id == RULE and n.subtype == 0 then + ruleht = n.height + totalht = totalht + ruleht + n = n.next + if n and n.id == KERN and n.subtype == 1 then + totalht = totalht + n.kern + if totalht == 0 or totalht == ruleht then + flag = true + else + end + end + end + end + return flag +end local get_pagebody = function (head) local textht = tex.getdimen("textheight") local fn = head.list @@ -757,27 +781,7 @@ local get_pagebody = function (head) end return body end -local footnoterule_ahead = function (head, debug) - local n = head - local flag = false - if n and n.id == KERN and n.subtype == 1 then - local htr = n.kern - local ht1, ht2, ht3 - n = n.next - if n and n.id == RULE and n.subtype == 0 then - htr = htr + n.height - n = n.next - if n and n.id == KERN and n.subtype == 1 then - htr = htr + n.kern - if htr == 0 then - flag = true - end - end - end - end - return flag -end -check_vtop = function (head, colno) +check_vtop = function (head, colno, vpos) local PAGEmin = luatypo.PAGEmin local HYPHmax = luatypo.HYPHmax local LLminWD = luatypo.LLminWD @@ -799,13 +803,9 @@ check_vtop = function (head, colno) local FootnoteSplit = luatypo.FootnoteSplit local Stretch = math.max(luatypo.Stretch/100,1) local blskip = tex.getglue("baselineskip") - local pageno = tex.getcount("c@page") local vpos_min = PAGEmin * blskip vpos_min = vpos_min * 1.5 - local vpos = 0 - local pageflag = false - local body_bottom = false - local page_bottom = false + local linewd = tex.getdimen("textwidth") local first_bot = true local footnote = false local ftnsplit = false @@ -819,23 +819,18 @@ check_vtop = function (head, colno) local pageline = 0 local ftnline = 0 local line = 0 + local body_bottom = false + local page_bottom = false + local pageflag = false + local plist = luatypo.pagelist + local lastp = tonumber(string.match(plist, "%s(%d+),%s$")) + local pageno = tex.getcount("c@page") while head do local nextnode = head.next - if not footnote and head.id == KERN and head.subtype == 1 then - if footnoterule_ahead(head, true) then - footnote = true - ftnline = 0 - body_bottom = false - orphanflag = false - lwhyphflag = false - hyphcount = 0 - firstwd = "" - lastwd = "" - else - vpos = vpos + head.kern - end - elseif head.id == HLIST and head.subtype == LINE and + if head.id == HLIST and head.subtype == LINE and (head.height > 0 or head.depth > 0) then + vpos = vpos + head.height + head.depth + linewd = head.width if footnote then ftnline = ftnline + 1 line = ftnline @@ -843,8 +838,19 @@ check_vtop = function (head, colno) pageline = pageline + 1 line = pageline end + local n = nextnode + while n and (n.id == GLUE or n.id == PENALTY or + n.id == WHATSIT ) do + n = n.next + end + if not n then + page_bottom = true + body_bottom = true + elseif footnoterule_ahead(n) then + body_bottom = true + end local first = head.head - local hmax = head.width + tex.hfuzz + local hmax = linewd + tex.hfuzz local w,h,d = dimensions(1,2,0, first) if w > hmax and OverfullLines then pageflag = true @@ -862,22 +868,6 @@ check_vtop = function (head, colno) local COLOR = luatypo.colortbl[8] color_line (head, COLOR) end - vpos = vpos + head.height + head.depth - local n = head.next - while n and - (n.id == GLUE or n.id == PENALTY or n.id == WHATSIT) do - n = n.next - end - if not n then - if footnote then - page_bottom = true - else - page_bottom = true - body_bottom = true - end - elseif footnoterule_ahead(n, false) then - body_bottom = true - end if footnote and page_bottom then ftnsplit = true end @@ -890,9 +880,9 @@ check_vtop = function (head, colno) hyphcount = 0 if not footnote then parline = 1 - end - if body_bottom then - orphanflag = true + if body_bottom then + orphanflag = true + end end local nn = first.next if nn and nn.id == HLIST and nn.subtype == BOX then @@ -916,7 +906,7 @@ check_vtop = function (head, colno) end local PFskip = effective_glue(pn,head) if ShortLines then - local llwd = tex.hsize - PFskip + local llwd = linewd - PFskip if llwd < LLminWD then pageflag = true local msg = "SHORT LINE: " .. @@ -1059,19 +1049,19 @@ check_vtop = function (head, colno) color_line (head, COLOR) end end - local n = head.next - while n and (n.id == GLUE or n.id == PENALTY or - n.id == WHATSIT or n.id == VLIST) do - n = n.next - end - if not n then - page_bottom = true - body_bottom = true - elseif footnoterule_ahead(n, false) then - body_bottom = true - end - elseif head.id == VLIST then + elseif head and head.id == RULE and head.subtype == 0 then vpos = vpos + head.height + head.depth + if body_bottom then + footnote = true + ftnline = 0 + body_bottom = false + ftnrule_ahead = false + orphanflag = false + lwhyphflag = false + hyphcount = 0 + firstwd = "" + lastwd = "" + end elseif body_bottom and head.id == GLUE and head.subtype == 0 then if first_bot then if pageline > 1 and pageline < PAGEmin and ShortPages then @@ -1092,38 +1082,76 @@ check_vtop = function (head, colno) end elseif head.id == GLUE then vpos = vpos + effective_glue(head,body) + elseif head.id == KERN and head.subtype == 1 then + vpos = vpos + head.kern + elseif head.id == VLIST then + vpos = vpos + head.height + head.depth + elseif head.id == HLIST and head.subtype == BOX then + local hf = head.list + if hf and hf.id == VLIST and hf.subtype == 0 then + break + end end head = nextnode end - return pageflag + if pageflag then + if not lastp or pageno > lastp then + luatypo.pagelist = luatypo.pagelist .. tostring(pageno) .. ", " + end + end + return head end luatypo.check_page = function (head) - local pageno = tex.getcount("c@page") - local pageflag = false + local textwd = tex.getdimen("textwidth") + local vpos = 0 local n2, n3, col, colno local body = get_pagebody(head) + local footnote = false + local top = body local first = body.list - if first.id == HLIST and first.subtype == 2 then - n2 = first.list - colno = 0 - for n in traverse_id(HLIST, n2) do - if n.id == HLIST and n.subtype == 2 then - n3 = n.list - col = n3.list - colno = colno + 1 - pageflag = check_vtop(col,colno) - end - end - elseif body.id == VLIST and body.subtype == 0 then - col = body.list - pageflag = check_vtop(col,colno) + if (first and first.id == HLIST and first.subtype == BOX) or + (first and first.id == VLIST and first.subtype == 0) then + top = body.list + first = top.list end - if pageflag then - local pl = luatypo.pagelist - local p = tonumber(string.match(pl, "%s(%d+),%s$")) - if not p or pageno > p then - luatypo.pagelist = luatypo.pagelist .. tostring(pageno) .. ", " - end + while top do + first = top.list + if top and top.id == VLIST and top.subtype == 0 and + top.width > textwd/2 then + local next = check_vtop(first,colno,vpos) + if next then + top = next + elseif top then + top = top.next + end + elseif (top and top.id == HLIST and top.subtype == BOX) and + (first and first.id == VLIST and first.subtype == 0) and + (first.height > 0 and first.width > 0) then + colno = 0 + for n in traverse_id(VLIST, first) do + colno = colno + 1 + col = n.list + check_vtop(col,colno,vpos) + end + colno = nil + top = top.next + elseif (top and top.id == HLIST and top.subtype == BOX) and + (first and first.id == HLIST and first.subtype == BOX) and + (first.height > 0 and first.width > 0) then + colno = 0 + for n in traverse_id(HLIST, first) do + colno = colno + 1 + local nn = n.list + if nn and nn.list then + col = nn.list + check_vtop(col,colno,vpos) + end + end + colno = nil + top = top.next + else + top = top.next + end end return true end @@ -1135,7 +1163,7 @@ return luatypo.check_page luatexbase.add_to_callback ("pre_shipout_filter",luatypo.check_page,"check_page",1) end - } + }% } \InputIfFileExists{lua-typo.cfg}% -- cgit v1.2.3