texlive[65734] Master/texmf-dist: lua-typo (4feb23)

commits+karl at tug.org commits+karl at tug.org
Sat Feb 4 22:14:15 CET 2023


Revision: 65734
          http://tug.org/svn/texlive?view=revision&revision=65734
Author:   karl
Date:     2023-02-04 22:14:15 +0100 (Sat, 04 Feb 2023)
Log Message:
-----------
lua-typo (4feb23)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/lualatex/lua-typo/README.md
    trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-demo.pdf
    trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.ltx
    trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.pdf
    trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.ltx
    trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.pdf
    trunk/Master/texmf-dist/source/lualatex/lua-typo/lua-typo.dtx
    trunk/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.sty

Modified: trunk/Master/texmf-dist/doc/lualatex/lua-typo/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/lua-typo/README.md	2023-02-04 21:13:56 UTC (rev 65733)
+++ trunk/Master/texmf-dist/doc/lualatex/lua-typo/README.md	2023-02-04 21:14:15 UTC (rev 65734)
@@ -28,15 +28,15 @@
 ------------
 
 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 @@
 - 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 @@
   - 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

Modified: trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-demo.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.ltx
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.ltx	2023-02-04 21:13:56 UTC (rev 65733)
+++ trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.ltx	2023-02-04 21:14:15 UTC (rev 65734)
@@ -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}

Modified: trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.ltx
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.ltx	2023-02-04 21:13:56 UTC (rev 65733)
+++ trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.ltx	2023-02-04 21:14:15 UTC (rev 65734)
@@ -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}

Modified: trunk/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/lualatex/lua-typo/lua-typo.dtx
===================================================================
--- trunk/Master/texmf-dist/source/lualatex/lua-typo/lua-typo.dtx	2023-02-04 21:13:56 UTC (rev 65733)
+++ trunk/Master/texmf-dist/source/lualatex/lua-typo/lua-typo.dtx	2023-02-04 21:14:15 UTC (rev 65734)
@@ -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
 %</batch>
 %<*gobble>
@@ -51,8 +53,8 @@
 %</gobble>
 %<*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}
@@ -59,16 +61,16 @@
 \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
+}
+%</doc>
+\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,9 +440,18 @@
 %    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
@@ -433,8 +458,8 @@
 %    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}
-%</sty>
-%<*dtx>
-\ProvidesFile{lua-typo.dtx}
-%</dtx>
-%<*dtx|sty>
-                [2021/05/13 v.0.50 Daniel Flipo]
-%</dtx|sty>
+\NeedsTeXFormat{LaTeX2e}[2021/06/01]
+%</sty|scan>
+%<+sty>\ProvidesPackage{lua-typo}
+%<+scan>\ProvidesPackage{scan-page}
+%<+dtx>\ProvidesFile{lua-typo.dtx}
+%<*dtx|sty|scan>
+                [2023-02-04 v.0.60 Daniel Flipo]
+%</dtx|sty|scan>
 %<*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 @@
   \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 @@
         local s = string.char(c)
         luatypo.single[langno] = luatypo.single[langno] .. s
       end
-%<dbg>     texio.write_nl("SINGLE=" .. luatypo.single[langno])
-%<dbg>     texio.write_nl(' ')
+%<dbg>      texio.write_nl("SINGLE=" .. luatypo.single[langno])
+%<dbg>      texio.write_nl(' ')
      }%
   \else
     \PackageWarning{luatypo}{Unknown language "\luatypo at LANG",
@@ -984,8 +1008,8 @@
         local s = string.char(c)
         luatypo.double[langno] = luatypo.double[langno] .. s
       end
-%<dbg>     texio.write_nl("DOUBLE=" .. luatypo.double[langno])
-%<dbg>     texio.write_nl(' ')
+%<dbg>      texio.write_nl("DOUBLE=" .. luatypo.double[langno])
+%<dbg>      texio.write_nl(' ')
     }%
   \else
     \PackageWarning{luatypo}{Unknown language "\luatypo at LANG",
@@ -1020,7 +1044,7 @@
 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 repl = node.replace
      if pre then
         set_attribute(pre,attr,color)
-%<dbg>  texio.write_nl('PRE=' .. tostring(pre.char))
+%<dbg>        texio.write_nl('PRE=' .. tostring(pre.char))
      end
      if post then
         set_attribute(post,attr,color)
@@ -1193,7 +1217,7 @@
 %
 %    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 @@
         until not n or n.id == GLUE
      end
      new = string.reverse(new)
-%<dbg>  texio.write_nl('EOLsigold=' .. old)
-%<dbg>  texio.write('   EOLsig=' .. new)
+%<dbg>     texio.write_nl('EOLsigold=' .. old)
+%<dbg>     texio.write('   EOLsig=' .. new)
      local MinFull = luatypo.MinFull
      local MinPart = luatypo.MinPart
      MinFull = math.min(MinPart,MinFull)
@@ -1390,10 +1414,10 @@
      local newsub = string.sub(new,-k)
      local l = string.len(new)
      if oldsub == newsub and l >= k then
-%<dbg>  texio.write_nl('EOLnewsub=' .. newsub)
+%<dbg>        texio.write_nl('EOLnewsub=' .. newsub)
         match = true
      elseif oldlast == newlast and string.len(newlast) >= MinFull then
-%<dbg>  texio.write_nl('EOLnewlast=' .. newlast)
+%<dbg>        texio.write_nl('EOLnewlast=' .. newlast)
         match = true
         oldsub = oldlast
         newsub = newlast
@@ -1415,7 +1439,7 @@
         end
         pageflag = true
         newsub = string.gsub(newsub, '^_', '')
-%<dbg>  texio.write_nl('EOLfullmatch=' .. newsub)
+%<dbg>        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 newsub = string.sub(new,1,k)
      local l = string.len(newsub)
      if oldsub == newsub and l >= k then
-%<dbg>  texio.write_nl('BOLnewsub=' .. newsub)
+%<dbg>        texio.write_nl('BOLnewsub=' .. newsub)
         match = true
      elseif oldfirst == newfirst  and string.len(newfirst) >= MinFull then
-%<dbg>  texio.write_nl('BOLnewfirst=' .. newfirst)
+%<dbg>        texio.write_nl('BOLnewfirst=' .. newfirst)
         match = true
         oldsub = oldfirst
         newsub = newfirst
@@ -1537,7 +1561,7 @@
         end
         pageflag = true
         newsub = string.gsub(newsub, '_$', '')   --$
-%<dbg>  texio.write_nl('BOLfullmatch=' .. newsub)
+%<dbg>        texio.write_nl('BOLfullmatch=' .. newsub)
         local msg = "B.O.L. MATCH=" .. newsub
         log_flaw(msg, line, colno, footnote)
 %    \end{macrocode}
@@ -1569,7 +1593,7 @@
 %    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 @@
 %
 %    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 @@
   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
+%<dbg>     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
+%<dbg>  ht2 = string.format("%.2fpt", ruleht/65536)
+        totalht = totalht + ruleht
+        n = n.next
+        if n and n.id == KERN and n.subtype == 1 then
+%<dbg>     ht3 = string.format("%.2fpt", n.kern/65536)
+           totalht = totalht + n.kern
+           if totalht == 0 or totalht == ruleht then
+              flag = true
+           else
+%<dbg>             texio.write_nl(' ')
+%<dbg>             texio.write_nl('Not a footnoterule:')
+%<dbg>             texio.write('  KERN height=' .. ht1)
+%<dbg>             texio.write('  RULE height=' .. ht2)
+%<dbg>             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 @@
   repeat
     fn = fn.next
   until fn.id == VLIST and fn.height > 0
-%<dbg>  texio.write_nl(' ht=' .. fn.height/65536 .. 'pt')
-%<dbg>  texio.write(' dp=' .. fn.depth/65536 .. 'pt')
+%<dbg>  texio.write_nl(' ')
+%<dbg>  local ht = string.format("%.1fpt", fn.height/65536)
+%<dbg>  local dp = string.format("%.1fpt", fn.depth/65536)
+%<dbg>  texio.write_nl('get_pagebody: TOP VLIST')
+%<dbg>  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
-%<dbg>   texio.write_nl('   BODY: ' .. n.height/65536 .. 'pt')
+%<dbg>         local ht = string.format("%.1fpt",  n.height/65536)
+%<dbg>         texio.write_nl('BODY found: ht=' .. ht)
+%<dbg>         texio.write_nl(' ')
          body = n
          break
       else
-%<dbg>   texio.write_nl('   ht=' .. n.height/65536 .. 'pt')
-%<dbg>   texio.write_nl(' dp=' .. n.depth/65536 .. 'pt')
+%<dbg>         texio.write_nl('Skip short VLIST:')
+%<dbg>         local ht = string.format("%.1fpt",  n.height/65536)
+%<dbg>         local dp = string.format("%.1fpt",  n.depth/65536)
+%<dbg>         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
-%<dbg>          texio.write_nl('     BODY: ' .. n.height/65536 .. 'pt')
+%<dbg>                local ht = string.format("%.1fpt",  n.height/65536)
+%<dbg>                texio.write_nl('  BODY: ht=' .. ht)
                 body = n
                 break
              end
@@ -1700,61 +1783,26 @@
   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
-%<dbg>     if debug then
-%<dbg>        ht1 = string.format("%.2fpt", n.kern/65536)
-%<dbg>     end
-     n = n.next
-     if n and n.id == RULE and n.subtype == 0 then
-        htr = htr + n.height
-%<dbg>        if debug then
-%<dbg>           ht2 = string.format("%.2fpt", n.height/65536)
-%<dbg>        end
-        n = n.next
-        if n and n.id == KERN and n.subtype == 1 then
-           htr = htr + n.kern
-%<dbg>     if debug then
-%<dbg>        ht3 = string.format("%.2fpt", n.kern/65536)
-%<dbg>        texio.write_nl(' ')
-%<dbg>        texio.write_nl('KERN height: ' .. ht1)
-%<dbg>        texio.write('  RULE height: ' .. ht2)
-%<dbg>        texio.write('  KERN height: ' .. ht3)
-%<dbg>        texio.write_nl('TOTAL height: ' .. htr .. 'sp')
-%<dbg>     end
-           if htr == 0 then
-              flag = true
-%<dbg>        if debug then
-%<dbg>           texio.write(' =>  footnoterule found!')
-%<dbg>        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 @@
   local FootnoteSplit   = luatypo.FootnoteSplit
   local Stretch  = math.max(luatypo.Stretch/100,1)
   local blskip   = tex.getglue("baselineskip")
-  local pageno   = tex.getcount("c at 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 @@
   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 at 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 @@
           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
+%<dbg>          texio.write_nl('=> FOOTNOTE RULE ahead')
+%<dbg>          texio.write_nl('check_vtop: last line before footnotes')
+%<dbg>          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 @@
           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 @@
           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 @@
           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 @@
 %    \begin{macrocode}
           local PFskip = effective_glue(pn,head)
           if ShortLines then
-             local llwd = tex.hsize - PFskip
-%<dbg>       local PFskip_pt = string.format("%.1fpt", PFskip/65536)
-%<dbg>       local llwd_pt = string.format("%.1fpt", llwd/65536)
-%<dbg>       texio.write_nl('PFskip= ' .. PFskip_pt)
-%<dbg>       texio.write('  llwd= ' .. llwd_pt)
+             local llwd = linewd - PFskip
+%<dbg>             local PFskip_pt = string.format("%.1fpt", PFskip/65536)
+%<dbg>             local llwd_pt = string.format("%.1fpt", llwd/65536)
+%<dbg>             texio.write_nl('PFskip= ' .. PFskip_pt)
+%<dbg>             texio.write('  llwd= ' .. llwd_pt)
 %    \end{macrocode}
 %    |llwd| is the line’s length. Is it too short?
 %    \begin{macrocode}
@@ -2042,7 +2070,8 @@
 %    \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 @@
              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 @@
           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 @@
           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 @@
 %    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 @@
              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
+%<dbg>       texio.write_nl('check_vtop: footnotes start')
+%<dbg>       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
-%<dbg>    local vpos_pt = string.format("%.1fpt", vpos/65536)
-%<dbg>    local vmin_pt = string.format("%.1fpt", vpos_min/65536)
-%<dbg>    texio.write_nl('pageline=' .. pageline)
-%<dbg>    texio.write_nl('vpos=' .. vpos_pt)
-%<dbg>    texio.write('   vpos_min=' .. vmin_pt)
-%<dbg>    if page_bottom then
-%<dbg>       local tht    = tex.getdimen("textheight")
-%<dbg>       local tht_pt = string.format("%.1fpt", tht/65536)
-%<dbg>       texio.write('   textheight=' .. tht_pt)
-%<dbg>    end
-%<dbg>    texio.write_nl(' ')
+%<dbg>          local vpos_pt = string.format("%.1fpt", vpos/65536)
+%<dbg>          local vmin_pt = string.format("%.1fpt", vpos_min/65536)
+%<dbg>          texio.write_nl('pageline=' .. pageline)
+%<dbg>          texio.write_nl('vpos=' .. vpos_pt)
+%<dbg>          texio.write('   vpos_min=' .. vmin_pt)
+%<dbg>          if page_bottom then
+%<dbg>             local tht    = tex.getdimen("textheight")
+%<dbg>             local tht_pt = string.format("%.1fpt", tht/65536)
+%<dbg>             texio.write('   textheight=' .. tht_pt)
+%<dbg>          end
+%<dbg>          texio.write_nl(' ')
           if pageline > 1 and pageline < PAGEmin and ShortPages then
              pageshort = true
           end
@@ -2232,79 +2269,169 @@
           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
+%<dbg>          texio.write_nl('check_vtop: BREAK => multicol')
+%<dbg>          texio.write_nl(' ')
+          break
+       end
     end
   head = nextnode
   end
-  return pageflag
+%<dbg>  if nextnode then
+%<dbg>     texio.write('Exit check_vtop,  next=')
+%<dbg>     texio.write(tostring(node.type(nextnode.id)))
+%<dbg>     texio.write('-'.. nextnode.subtype)
+%<dbg>  else
+%<dbg>     texio.write_nl('Exit check_vtop,  next=nil')
+%<dbg>  end
+%<dbg>  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 at 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
-%<dbg>  texio.write_nl('body.id=' .. tostring(node.type(body.id)))
-%<dbg>  texio.write('-' .. body.subtype)
-%<dbg>  texio.write_nl(' ')
-%<dbg>  texio.write_nl('first.id=' .. tostring(node.type(first.id)))
-%<dbg>  texio.write('-' .. first.subtype)
-%<dbg>  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
-%<dbg>   texio.write_nl('n.id=' .. tostring(node.type(n.id)))
-%<dbg>   texio.write('-' .. n.subtype)
-%<dbg>   texio.write('  ht=' .. n.height)
-%<dbg>   texio.write_nl(' ')
-         if n.id == HLIST and n.subtype == 2 then
-            n3 = n.list
-%<dbg>      texio.write_nl('n3.id=' .. tostring(node.type(n3.id)))
-%<dbg>      texio.write('-' .. n3.subtype)
-%<dbg>      texio.write('  ht=' .. n3.height)
-%<dbg>      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
+%<dbg>     local boxwd = string.format("%.1fpt", first.width/65536)
+%<dbg>     texio.write_nl('One step down: boxwd=' .. boxwd)
+%<dbg>     texio.write_nl(' ')
+     top = body.list
+     first = top.list
+  end
+  while top do
+    first = top.list
+%<dbg>    texio.write_nl('Page loop: top=' .. tostring(node.type(top.id)))
+%<dbg>    texio.write('-' .. top.subtype)
+%<dbg>    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
+%<dbg>       local boxht = string.format("%.1fpt", top.height/65536)
+%<dbg>       local boxwd = string.format("%.1fpt", top.width/65536)
+%<dbg>       texio.write_nl('**VLIST: ')
+%<dbg>       texio.write(tostring(node.type(top.id)))
+%<dbg>       texio.write('-' .. top.subtype)
+%<dbg>       texio.write('  wd=' .. boxwd .. '  ht=' .. boxht)
+%<dbg>       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
+%<dbg>           texio.write_nl('**MULTICOL type1:')
+%<dbg>           texio.write_nl(' ')
+       colno = 0
+       for n in traverse_id(VLIST, first) do
+           colno = colno + 1
+           col = n.list
+%<dbg>           texio.write_nl('Start of col.' .. colno)
+%<dbg>           texio.write_nl(' ')
+           check_vtop(col,colno,vpos)
+%<dbg>           texio.write_nl('End of col.' .. colno)
+%<dbg>           texio.write_nl(' ')
+       end
+       colno = nil
+       top = top.next
+%<dbg>       texio.write_nl('MULTICOL type1 END: next=')
+%<dbg>       texio.write(tostring(node.type(top.id)))
+%<dbg>       texio.write('-' .. top.subtype)
+%<dbg>       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}
+%<dbg>     texio.write_nl('**MULTICOL type2:')
+%<dbg>     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
+%<dbg>              texio.write_nl('Start of col.' .. colno)
+%<dbg>              texio.write_nl(' ')
+              check_vtop(col,colno,vpos)
+%<dbg>              texio.write_nl('End of col.' .. colno)
+%<dbg>              texio.write_nl(' ')
+           end
+       end
+       colno = nil
+       top = top.next
+    else
+       top = top.next
+    end
   end
   return true
 end
@@ -2311,6 +2438,7 @@
 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 @@
 %    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 @@
        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 @@
 %%\luatypoTwoChars{french}{'Je Tu Il On'}
 %    \end{macrocode}
 %
-%\iffalse
+% \iffalse
 %</cfg>
 % \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 at LANGno
+\newcount\luatypo at options
+\newtoks\luatypo at single
+\newtoks\luatypo at 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 at 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
-%</dtx>
+%</scan>
 % \fi
 %
 % \Finale

Modified: trunk/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.sty
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.sty	2023-02-04 21:13:56 UTC (rev 65733)
+++ trunk/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.sty	2023-02-04 21:14:15 UTC (rev 65734)
@@ -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 @@
   \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.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 @@
   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 @@
   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 @@
   local FootnoteSplit   = luatypo.FootnoteSplit
   local Stretch  = math.max(luatypo.Stretch/100,1)
   local blskip   = tex.getglue("baselineskip")
-  local pageno   = tex.getcount("c at 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 @@
   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 at 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 @@
           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 @@
           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,10 +880,10 @@
           hyphcount = 0
           if not footnote then
              parline = 1
+             if body_bottom then
+                orphanflag = true
+             end
           end
-          if body_bottom then
-             orphanflag = true
-          end
           local nn = first.next
           if nn and nn.id == HLIST and nn.subtype == BOX then
              ListItem = true
@@ -916,7 +906,7 @@
           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 @@
              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
+    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
-       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
-       vpos = vpos + head.height + head.depth
     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 @@
        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 at 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 @@
        luatexbase.add_to_callback
            ("pre_shipout_filter",luatypo.check_page,"check_page",1)
     end
-  }
+  }%
 }
 
 \InputIfFileExists{lua-typo.cfg}%



More information about the tex-live-commits mailing list.