summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2023-03-09 21:13:22 +0000
committerKarl Berry <karl@freefriends.org>2023-03-09 21:13:22 +0000
commit3cc082dbb3a6dc55461c335bf82b41fa693aa433 (patch)
tree1ab32c61c817d39f8377a34d920ce1128609119c
parentf15b22a2d2fcca2502bb3dda7d2750fa9b9460b4 (diff)
lua-typo (9mar23) (branch)
git-svn-id: svn://tug.org/texlive/branches/branch2022.final@66498 c570f23f-e606-0410-a88d-b1316a301751
-rw-r--r--Master/texmf-dist/doc/lualatex/lua-typo/README.md7
-rw-r--r--Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-demo.pdfbin16859 -> 16859 bytes
-rw-r--r--Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.ltx21
-rw-r--r--Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.pdfbin105225 -> 106404 bytes
-rw-r--r--Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.ltx21
-rw-r--r--Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.pdfbin173735 -> 179022 bytes
-rw-r--r--Master/texmf-dist/source/lualatex/lua-typo/lua-typo.dtx957
-rw-r--r--Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.cfg9
-rw-r--r--Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.sty432
9 files changed, 849 insertions, 598 deletions
diff --git a/Master/texmf-dist/doc/lualatex/lua-typo/README.md b/Master/texmf-dist/doc/lualatex/lua-typo/README.md
index 0930ac70cff..9577fee1cf0 100644
--- a/Master/texmf-dist/doc/lualatex/lua-typo/README.md
+++ b/Master/texmf-dist/doc/lualatex/lua-typo/README.md
@@ -81,7 +81,12 @@ Changes
* v.0.61:
- bug fixes and documentation enhanced.
- - colours `mygrey` and `myred` renamed `LTgrey` and `LTred`.
+ - colours `mygrey` and `myred` renamed as `LTgrey` and `LTred`.
+
+* v.0.65:
+ - new option `ShortFinalWord` to detect short end-of-sentence word
+ on top of next page.
+ - code cleaning.
--
Copyright 2020--2023 Daniel Flipo
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 f5ea36a35e5..35fe6bc9070 100644
--- a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-demo.pdf
+++ b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-demo.pdf
Binary files 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 3e580ef3147..6a4abf1f8a9 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
@@ -1,24 +1,23 @@
-\RequirePackage{pdfmanagement-testphase}
-\DeclareDocumentMetadata{pdfstandard=A-2b, lang=fr-FR}
-\documentclass[a4paper]{ltxdoc}
-\usepackage[dvipsnames]{xcolor}
+\DocumentMetadata{pdfstandard=A-2b, lang=fr-FR}
+\documentclass[a4paper,french]{ltxdoc}
\usepackage{fontspec}
\setmainfont{erewhon}
\setsansfont{Cabin}[Scale=MatchLowercase]
\setmonofont{VeraMono.ttf}[
Scale = MatchLowercase,
- ItalicFont = VeraMoIt.ttf,
- BoldFont = VeraMoBd.ttf,
- BoldItalicFont = VeraMoBI.ttf,
- HyphenChar=None, Color=Sepia,
+ ItalicFont = VeraMoIt.ttf,
+ BoldFont = VeraMoBd.ttf,
+ BoldItalicFont = VeraMoBI.ttf,
+ HyphenChar=None,
+ Color=5D1D00,
]
\usepackage[expansion=true, protrusion=true]{microtype}
-\usepackage[french]{babel}
+\usepackage{babel,varioref}
\frenchsetup{og=«, fg=»}
+
\usepackage[ShortPages, OverfullLines, UnderfullLines,
Widows, Orphans, EOPHyphens, RepeatedHyphens
]{lua-typo}
-\luatypoLLminWD=3em
\renewcommand*\descriptionlabel[1]{%
\hspace{\labelsep}\texttt{#1}}
\usepackage{array,url,verbatim}
@@ -31,7 +30,7 @@
\newcommand*\file[1]{\texttt{#1}}
\newcommand*\pkg[1]{\texttt{#1}}
\newcommand*\opt[1]{\texttt{#1}}
-\renewcommand\meta[1]{\texttt{\textsl{\color{Sepia}<#1>}}}
+\renewcommand\meta[1]{\texttt{\textsl{<#1>}}}
\newcommand*\node[1]{\textsc{#1}}
\setlength{\parindent}{0pt}
\setlength{\parskip}{.3\baselineskip plus 0.3pt minus 0.3pt}
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 287b2660b57..ed50a38d11e 100644
--- a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.pdf
+++ b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo-fr.pdf
Binary files 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 46244feb110..94d5ad0b56e 100644
--- a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.ltx
+++ b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.ltx
@@ -1,23 +1,22 @@
-\RequirePackage{pdfmanagement-testphase}
-\DeclareDocumentMetadata{pdfstandard=A-2b, lang=en-GB}
-\documentclass[a4paper]{ltxdoc}
-\usepackage[dvipsnames]{xcolor}
+\DocumentMetadata{pdfstandard=A-2b, lang=en-GB}
+\documentclass[a4paper,british]{ltxdoc}
\usepackage{fontspec}
\setmainfont{erewhon}
\setsansfont{Cabin}[Scale=MatchLowercase]
\setmonofont{VeraMono.ttf}[
Scale = MatchLowercase,
- ItalicFont = VeraMoIt.ttf,
- BoldFont = VeraMoBd.ttf,
- BoldItalicFont = VeraMoBI.ttf,
- HyphenChar=None, Color=Sepia,
+ ItalicFont = VeraMoIt.ttf,
+ BoldFont = VeraMoBd.ttf,
+ BoldItalicFont = VeraMoBI.ttf,
+ HyphenChar=None,
+ Color=5D1D00,
]
\usepackage[expansion=true, protrusion=true]{microtype}
-\usepackage[british]{babel}
+\usepackage{babel,varioref}
+
\usepackage[ShortPages, OverfullLines, UnderfullLines,
Widows, Orphans, EOPHyphens, RepeatedHyphens
]{lua-typo}
-\luatypoLLminWD=3em
\renewcommand*\descriptionlabel[1]{%
\hspace{\labelsep}\texttt{#1}}
\usepackage{array,url,verbatim}
@@ -38,7 +37,7 @@
\newcommand*\file[1]{\texttt{#1}}
\newcommand*\pkg[1]{\texttt{#1}}
\newcommand*\opt[1]{\texttt{#1}}
-\renewcommand\meta[1]{\texttt{\textsl{\color{Sepia}<#1>}}}
+\renewcommand\meta[1]{\texttt{\textsl{<#1>}}}
\newcommand*\node[1]{\textsc{#1}}
\setlength{\parindent}{0pt}
\setlength{\parskip}{.3\baselineskip plus 0.3pt minus 0.3pt}
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 55acdc97b8e..6990971202e 100644
--- a/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.pdf
+++ b/Master/texmf-dist/doc/lualatex/lua-typo/lua-typo.pdf
Binary files 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 9929679bc21..41a9966280c 100644
--- a/Master/texmf-dist/source/lualatex/lua-typo/lua-typo.dtx
+++ b/Master/texmf-dist/source/lualatex/lua-typo/lua-typo.dtx
@@ -52,29 +52,28 @@
\csname fi\endcsname
%</gobble>
%<*driver>
-\RequirePackage{pdfmanagement-testphase}
-%<+doc>\DeclareDocumentMetadata{pdfstandard=A-2b, lang=en-GB}
-%<+docfr>\DeclareDocumentMetadata{pdfstandard=A-2b, lang=fr-FR}
-\documentclass[a4paper]{ltxdoc}
-\usepackage[dvipsnames]{xcolor}
+%<+doc>\DocumentMetadata{pdfstandard=A-2b, lang=en-GB}
+%<+doc>\documentclass[a4paper,british]{ltxdoc}
+%<+docfr>\DocumentMetadata{pdfstandard=A-2b, lang=fr-FR}
+%<+docfr>\documentclass[a4paper,french]{ltxdoc}
\usepackage{fontspec}
\setmainfont{erewhon}
\setsansfont{Cabin}[Scale=MatchLowercase]
\setmonofont{VeraMono.ttf}[
Scale = MatchLowercase,
- ItalicFont = VeraMoIt.ttf,
- BoldFont = VeraMoBd.ttf,
- BoldItalicFont = VeraMoBI.ttf,
- HyphenChar=None, Color=Sepia,
+ ItalicFont = VeraMoIt.ttf,
+ BoldFont = VeraMoBd.ttf,
+ BoldItalicFont = VeraMoBI.ttf,
+ HyphenChar=None,
+ Color=5D1D00,
]
\usepackage[expansion=true, protrusion=true]{microtype}
-%<+doc>\usepackage[british]{babel}
-%<+docfr>\usepackage[french]{babel}
+\usepackage{babel,varioref}
%<+docfr>\frenchsetup{og=«, fg=»}
+
\usepackage[ShortPages, OverfullLines, UnderfullLines,
Widows, Orphans, EOPHyphens, RepeatedHyphens
]{lua-typo}
-\luatypoLLminWD=3em
\renewcommand*\descriptionlabel[1]{%
\hspace{\labelsep}\texttt{#1}}
\usepackage{array,url,verbatim}
@@ -100,7 +99,7 @@
\newcommand*\file[1]{\texttt{#1}}
\newcommand*\pkg[1]{\texttt{#1}}
\newcommand*\opt[1]{\texttt{#1}}
-\renewcommand\meta[1]{\texttt{\textsl{\color{Sepia}<#1>}}}
+\renewcommand\meta[1]{\texttt{\textsl{<#1>}}}
\newcommand*\node[1]{\textsc{#1}}
%
\setlength{\parindent}{0pt}
@@ -205,7 +204,7 @@
% \pkg{lua-typo}, il suffit d’ajouter dans le préambule la ligne %\\
% |\usepackage[All]{lua-typo}|
%
-% La version courante (0.61) nécessite un noyau LaTeX récent,
+% La version courante (0.65) 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 »
@@ -235,10 +234,20 @@
% ou pour se limiter aux tests \meta{OptX} et \meta{OptY} :\\
% |\usepackage[|\meta{OptX}|, |\meta{OptY}|]{lua-typo}|
%
-% \pagebreak[4]
-% Le tableau suivant donne le nom des options et le type des
-% vérifications proposées :
+% La liste des options et le type des vérifications proposées sont
+% présentés dans le tableau \vpageref{options-fr}.
+% Par exemple, pour limiter les vérifications aux lignes trop pleines
+% ou creuses, il suffit de coder :\\
+% |\usepackage[OverfullLines, UnderfullLines]{lua-typo}|\\
+% Pour tout vérifier sauf les coupures répétées en fin de ligne on
+% codera :\\
+% |\usepackage[All, RepeatedHyphens=false]{lua-typo}|\\
+% Notez que l’option that \opt{All} doit être la première de la
+% liste, les suivantes étant rétirées de la liste complète définie
+% par~\opt{All}.
%
+% \begin{table}[ht]
+% \centering\label{options-fr}
% \begin{tabular}{>{\ttfamily}ll}
% \multicolumn{1}{l}{Nom} & Imperfection à signaler\\ \hline
% All & Active toutes les options ci-dessous\\
@@ -258,18 +267,10 @@
% LastWordMatch & Même (partie de) mot en fin de lignes
% consécutives ?\\
% FootnoteSplit & Fin de note de bas de page sur page suivante?\\
+% ShortFinalWord & Mot de fin de phrase court en haut de page\\
% \hline
% \end{tabular}
-%
-% Par exemple, pour limiter les vérifications aux lignes trop pleines
-% ou creuses, il suffit de coder :\\
-% |\usepackage[OverfullLines, UnderfullLines]{lua-typo}|\\
-% Pour tout vérifier sauf les coupures répétées en fin de ligne on
-% codera :\\
-% |\usepackage[All, RepeatedHyphens=false]{lua-typo}|\\
-% Notez que l’option that \opt{All} doit être la première de la
-% liste, les suivantes étant rétirées de la liste complète définie
-% par~\opt{All}.
+% \end{table}
%
% Le nom des différentes options n’étant pas facile à mémoriser, il
% est possible de les retrouver sans devoir consulter la
@@ -299,6 +300,9 @@
% \item[RepeatedHyphens :] de même, lorsque le nombre de lignes
% consécutives affectées par des coupures dépasse le seuil fixé
% (voir ci-dessous), ne sont coloriées que les coupures en excès.
+% \item[ShortFinalWord :] lorsque le premier mot de la première ligne
+% d’une page termine une phrase et qu’il est court (au plus
+% |\luatypoMinLen=4| lettres), on le signale.
% \end{description}
%
% \section{Paramétrage personnalisé}
@@ -374,7 +378,7 @@
% commun), ainsi que la présence de « mon » en début ou fin de
% deux lignes consécutives (trois lettres en commun).
%
-% \item[EOLShortWords:] cette option signale la présence en fin de
+% \item[EOLShortWords:] cette option signale la présence en fin de
% ligne de mots très courts (une ou deux lettres)
% qui sont répertoriés dans une des listes
% suivantes (elles dépendent de la langue courante) :\\
@@ -423,14 +427,16 @@
% \luatypoSetColor{11}{LTred} % Répétitions en fin de ligne
% \luatypoSetColor{12}{LTgrey}% Dernière ligne d’alinéa presque pleine
% \luatypoSetColor{13}{cyan} % Note de bas de page éclatée
+% \luatypoSetColor{14}{red} % Mot de fin de phrase en haut de page
% \end{verbatim}
-% \pkg{lua-typo} charge l’extension graphique \pkg{color}.
-% Seules les couleurs portant un nom (\emph{named colors}) peuvent
-% être utilisées ; pour en définir de nouvelles, il faut donc soit
-% utiliser la commande |\definecolor| de l’extension \pkg{color}
-% (comme ci-dessus pour |LTgrey| ou |LTred|), soit charger l’extension
-% \pkg{xcolor} package qui donne accès à une kyrielle de noms de
-% couleurs.
+% \pkg{lua-typo} charge les extensions \pkg{luacolor} et donc
+% \pkg{color}. Seules les couleurs portant un nom (\emph{named
+% colors}) peuvent être utilisées dans la commande
+% |\luatypoSetColor| ; pour en définir de nouvelles il faut donc,
+% soit utiliser la commande |\definecolor| de l’extension
+% \pkg{color} (comme ci-dessus pour |LTgrey| ou |LTred|), soit
+% charger l’extension \pkg{xcolor} qui donne accès à une
+% kyrielle de noms de couleurs.
% \end{FrenchDoc}
%
% \StopEventually{}
@@ -449,9 +455,9 @@
% \filedate.}, is meant for careful writers and proofreaders who do
% not feel totally satisfied with LaTeX output, the most frequent
% issues being overfull or underfull lines, widows and orphans,
-% hyphenated words split across two pages, consecutive lines ending
-% with hyphens, paragraphs ending on too short or nearly full lines,
-% homeoarchy, etc.
+% hyphenated words split across two pages, two many consecutive lines
+% ending with hyphens, paragraphs ending on too short or nearly full
+% lines, homeoarchy, etc.
%
% This package, which works with LuaLaTeX only,
% \emph{does not try to correct anything} but just highlights
@@ -469,7 +475,7 @@
% may be acceptable in some conditions (multi-columns, technical
% papers) and unbearable in others (literary works f.i.).
% Moreover, correcting a potential issue somewhere may result in
-% other much more serious flaws elsewhere…\\
+% other much more serious flaws somewhere else …\\
% b) Conversely, possible bugs in \pkg{lua-typo} might hide issues
% that should normally be highlighted.
%
@@ -543,6 +549,7 @@
% FirstWordMatch & same (part of) word starting two consecutive lines?\\
% LastWordMatch & same (part of) word ending two consecutive lines?\\
% FootnoteSplit & footnotes spread over two pages or more?\\
+% ShortFinalWord & Short word ending a sentence on the next page\\
% \hline
% \end{tabular}\\[12pt]
% For example, if you want \pkg{lua-typo} to only warn about overfull
@@ -559,7 +566,6 @@
% this option provides an easy way to get their names without having
% to look into the documentation.
%
-% \enlargethispage*{\baselineskip}
% With option \opt{None}, \pkg{lua-typo} \emph{does absolutely
% nothing}, all checks are disabled as the main function is not added
% to any LuaTeX callback. It not quite equivalent to commenting out
@@ -577,6 +583,9 @@
% \item[RepeatedHyphens:] ditto, when the number of consecutives
% hyphenated lines is too high, only the hyphenated words in
% excess (the last ones) are hightlighted.
+% \item[ShortFinalWord :] the first word on a page is highlighted
+% if it ends a sentence and is short (up to |\luatypoMinLen=4|
+% letters).
% \end{description}
%
% \section{Customisation}
@@ -685,17 +694,18 @@
% \luatypoSetColor9{red} % Nearly empty page (a few lines)
% \luatypoSetColor{10}{LTred} % First word matches
% \luatypoSetColor{11}{LTred} % Last word matches
-% \luatypoSetColor{12}{LTgrey}% paragraph’s last line nearly full
-% \luatypoSetColor{13}{cyan} % footnotes spread over two pages
+% \luatypoSetColor{12}{LTgrey}% Paragraph’s last line nearly full
+% \luatypoSetColor{13}{cyan} % Footnotes spread over two pages
+% \luatypoSetColor{14}{red} % Short final word on top of the page
% \end{verbatim}
%
-% \pkg{lua-typo} loads the \pkg{color} package from the LaTeX graphic
-% bundle. Only named colours can be used by \pkg{lua-typo}, so you
-% can either use the |\definecolor| from \pkg{color} package to
-% define yours (as done in the config file for `LTgrey’) or load the
+% \pkg{lua-typo} loads the \pkg{luacolor} package which loads the
+% \pkg{color} package from the LaTeX graphic bundle.
+% |\luatypoSetColor| requires named colours, so you can either use
+% the |\definecolor| from \pkg{color} package to define yours
+% (as done in the config file for `LTgrey’ and `LTred’) or load the
% \pkg{xcolor} package which provides a bunch of named colours.
%
-% \clearpage
% \section{\TeX{}nical details}
%
% \iffalse
@@ -709,7 +719,7 @@
%<+scan>\ProvidesPackage{scan-page}
%<+dtx>\ProvidesFile{lua-typo.dtx}
%<*dtx|sty|scan>
- [2023-02-10 v.0.61 Daniel Flipo]
+ [2023-03-08 v.0.65 Daniel Flipo]
%</dtx|sty|scan>
%<*sty>
% \fi
@@ -725,7 +735,7 @@
% \begin{macrocode}
\ifdefined\DeclareRelease
\DeclareRelease{v0.4}{2021-01-01}{lua-typo-2021-04-18.sty}
- \DeclareCurrentRelease{}{2023-02-04}
+ \DeclareCurrentRelease{}{2023-03-08}
\else
\PackageWarning{lua-typo}{Your LaTeX kernel is too old to provide
access\MessageBreak to former versions of the lua-typo package.%
@@ -761,6 +771,7 @@
\newcount\luatypoPageMin
\newcount\luatypoMinFull
\newcount\luatypoMinPart
+\newcount\luatypoMinLen
\newcount\luatypo@LANGno
\newcount\luatypo@options
\newtoks\luatypo@single
@@ -797,6 +808,7 @@ luatypo = { }
\DeclareBoolOption[false]{FirstWordMatch}
\DeclareBoolOption[false]{LastWordMatch}
\DeclareBoolOption[false]{FootnoteSplit}
+\DeclareBoolOption[false]{ShortFinalWord}
% \end{macrocode}
% Option \opt{All} resets all booleans relative to specific
% typographic checks to \opt{true}.
@@ -809,6 +821,7 @@ luatypo = { }
\LT@ParLastHyphentrue \LT@EOLShortWordstrue
\LT@FirstWordMatchtrue \LT@LastWordMatchtrue
\LT@BackParindenttrue \LT@FootnoteSplittrue
+ \LT@ShortFinalWordtrue
}
\ProcessKeyvalOptions{luatypo}
% \end{macrocode}
@@ -909,6 +922,12 @@ luatypo = { }
\else
\directlua{ luatypo.FootnoteSplit = false }%
\fi
+ \ifLT@ShortFinalWord
+ \advance\luatypo@options by 1
+ \directlua{ luatypo.ShortFinalWord = true }%
+ \else
+ \directlua{ luatypo.ShortFinalWord = false }%
+ \fi
}
% \end{macrocode}
%
@@ -936,6 +955,7 @@ luatypo = { }
FirstWordMatch [false]\MessageBreak
LastWordMatch [false]\MessageBreak
FootnoteSplit [false]\MessageBreak
+ ShortFinalWord [false]\MessageBreak
\MessageBreak
*********************************************%
\MessageBreak Lua-typo [ShowOptions]
@@ -954,6 +974,7 @@ luatypo = { }
luatypo.Stretch = tex.count.luatypoStretchMax
luatypo.MinFull = tex.count.luatypoMinFull
luatypo.MinPart = tex.count.luatypoMinPart
+ luatypo.MinLen = tex.count.luatypoMinLen
luatypo.LLminWD = tex.dimen.luatypoLLminWD
luatypo.BackPI = tex.dimen.luatypoBackPI
luatypo.BackFuzz = tex.dimen.luatypoBackFuzz
@@ -1004,8 +1025,8 @@ luatypo = { }
% lines. The first argument is a language name, say \opt{french},
% which is turned into a command |\l@french| expanding to a number
% known by luatex, otherwise an error message occurs.
-% The UTF8 string entered as second argument has to be converted
-% into the font internal coding.
+% The utf-8 string entered as second argument has to be
+% converted into the font internal coding.
% \begin{macrocode}
\newcommand*{\luatypoOneChar}[2]{%
\def\luatypo@LANG{#1}\luatypo@single={#2}%
@@ -1016,7 +1037,7 @@ luatypo = { }
local string = \the\luatypo@single
luatypo.single[langno] = " "
for p, c in utf8.codes(string) do
- local s = string.char(c)
+ local s = utf8.char(c)
luatypo.single[langno] = luatypo.single[langno] .. s
end
%<dbg> texio.write_nl("SINGLE=" .. luatypo.single[langno])
@@ -1035,7 +1056,7 @@ luatypo = { }
local string = \the\luatypo@double
luatypo.double[langno] = " "
for p, c in utf8.codes(string) do
- local s = string.char(c)
+ local s = utf8.char(c)
luatypo.double[langno] = luatypo.double[langno] .. s
end
%<dbg> texio.write_nl("DOUBLE=" .. luatypo.double[langno])
@@ -1087,14 +1108,11 @@ char_to_discard[string.byte(":")] = true
char_to_discard[string.byte(";")] = true
char_to_discard[string.byte("-")] = true
-local split_lig = { }
-split_lig[0xFB00] = "ff"
-split_lig[0xFB01] = "fi"
-split_lig[0xFB02] = "fl"
-split_lig[0xFB03] = "ffi"
-split_lig[0xFB04] = "ffl"
-split_lig[0xFB05] = "st"
-split_lig[0xFB06] = "st"
+local eow_char = { }
+eow_char[string.byte(".")] = true
+eow_char[string.byte("!")] = true
+eow_char[string.byte("?")] = true
+eow_char[utf8.codepoint("…")] = true
local DISC = node.id("disc")
local GLYPH = node.id("glyph")
@@ -1134,10 +1152,13 @@ local HYPH = 0x2D
% \begin{macrocode}
local LIGA = 0x102
% \end{macrocode}
-% |parline| (current paragraph) must not be reset on every new page!
+% Counter |parline| (current paragraph) \emph{must not be reset}
+% on every new page!
% \begin{macrocode}
local parline = 0
-
+% \end{macrocode}
+% Local definitions for the `node’ library:
+% \begin{macrocode}
local dimensions = node.dimensions
local rangedimensions = node.rangedimensions
local effective_glue = node.effective_glue
@@ -1148,13 +1169,44 @@ 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}
+% Local definitions from the `unicode.utf8’ library: replacements are
+% needed for functions |string.gsub()|, |string.find()| and
+% |string.reverse()| which are meant for one-byte characters only.
+%
+% \changes{v0.65}{2023/03/02}{Three new functions for utf-8 strings’
+% manipulations.}
%
-% \changes{v0.32}{2021/03/14}{Better protection against unexpected
+% |utf8_find| requires an utf-8 string and a `pattern’ (also utf-8),
+% it returns |nil| if pattern is not found, or the \emph{byte}
+% position of the first match otherwise [not an issue as we only
+% care for true/false].
+% \begin{macrocode}
+local utf8_find = unicode.utf8.find
+% \end{macrocode}
+% |utf8_gsub| mimics |string.gsub| for utf-8 strings.
+% \begin{macrocode}
+local utf8_gsub = unicode.utf8.gsub
+% \end{macrocode}
+% |utf8_reverse| returns the reversed string (utf-8 chars read from
+% end to beginning) [same as |string.reverse| but for utf-8 strings].
+% \begin{macrocode}
+local utf8_reverse = function (s)
+ if utf8.len(s) > 1 then
+ local so = ""
+ for p, c in utf8.codes(s) do
+ so = utf8.char(c) .. so
+ end
+ s = so
+ end
+ return s
+end
+% \end{macrocode}
+%
+%\changes{v0.32}{2021/03/14}{Better protection against unexpected
% nil nodes.}
%
-% This auxillary function colours glyphs and discretionaries.
+% The next function colours glyphs and discretionaries.
% It requires two arguments: a node and a (named) colour.
%
% \begin{macrocode}
@@ -1166,34 +1218,20 @@ local color_node = function (node, color)
local repl = node.replace
if pre then
set_attribute(pre,attr,color)
-%<dbg> texio.write_nl('PRE=' .. tostring(pre.char))
end
if post then
set_attribute(post,attr,color)
-%<dbg> if pre then
-%<dbg> texio.write(' POST=' .. tostring(post.char))
-%<dbg> else
-%<dbg> texio.write_nl('POST=' .. tostring(post.char))
-%<dbg> end
end
if repl then
set_attribute(repl,attr,color)
-%<dbg> if pre or post then
-%<dbg> texio.write(' REPL=' .. tostring(repl.char))
-%<dbg> else
-%<dbg> texio.write_nl('REPL=' .. tostring(repl.char))
-%<dbg> end
end
-%<dbg> if pre or post or repl then
-%<dbg> texio.write_nl(' ')
-%<dbg> end
elseif node then
set_attribute(node,attr,color)
end
end
% \end{macrocode}
%
-% This auxillary function colours a whole line. It requires two
+% The nextfunction colours a whole line. It requires two
% arguments: a line’s node and a (named) colour.\par
% Digging into nested hlists and vlists is needed f.i.\ to colour
% aligned equations.
@@ -1245,9 +1283,9 @@ local color_line = function (head, color)
end
% \end{macrocode}
%
-% 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 \node{nil}) and a flag.
+% The next function takes four arguments: a string, two numbers
+% (which can be \node{nil}) and a flag. It appends a line to
+% a buffer which will be written to file `\cs{jobname.typo}’.
%
% \changes{v0.50}{2021/05/13}{Summary of flaws written to file
% `\cs{jobname.typo}’.}
@@ -1277,77 +1315,72 @@ end
% While comparing two words, the only significant nodes are glyphs
% and ligatures, dicretionnaries other than ligatures, kerns
% (letterspacing) should be discarded.
-% For each word to be compared we build a ``signature'' made of
+% For each word to be compared we build a ``signature’’ made of
% glyphs and split ligatures.
%
-% \changes{v0.32}{2021/03/14}{Experimental code to deal with non
-% standard ligatures.}
+% \changes{v0.65}{2023/03/02}{All ligatures are now split using the
+% node’s `components’ field rather than a table.}
%
% The first function adds a node to a signature of type string.
% It returns the augmented string and its length.
% The last argument is a boolean needed when building a signature
-% backwards (see |check_last_word|).
+% backwards (see |check_line_last_word|).
% \begin{macrocode}
local signature = function (node, string, swap)
local n = node
local str = string
if n and n.id == GLYPH then
- local b, id = is_glyph(n)
- if b and not char_to_discard[b] then
-% \end{macrocode}
-% Punctuation has to be discarded; the French apostrophe
-% (right quote U+2019) has a char code ``out of range'',
-% we replace it with U+0027;
-% Other glyphs should have char codes less than 0x100 (or 0x180?) or
-% be ligatures… standard ones (U+FB00 to U+FB06) are converted using
-% table |split_lig|.
-% \begin{macrocode}
- if b == 0x2019 then b = 0x27 end
- if b < 0x100 then
- str = str .. string.char(b)
- elseif split_lig[b] then
- local c = split_lig[b]
- if swap then
- c = string.reverse(c)
- end
- str = str .. c
+ local b = n.char
+ if b and not char_to_discard[b] then
% \end{macrocode}
-% Experimental: store other ligatures as the last two digits of their
-% decimal code…
+% Punctuation has to be discarded; other glyphs may be ligatures,
+% then they have a |components| field which holds the list of glyphs
+% which compose the ligature.
% \begin{macrocode}
- elseif n.subtype == LIGA and b > 0xE000 then
- local c = string.sub(b,-2)
- if swap then
- c = string.reverse(c)
- end
- str = str .. c
- end
- end
+ if n.components then
+ local c = ""
+ for nn in traverse_id(GLYPH, n.components) do
+ c = c .. utf8.char(nn.char)
+ end
+ if swap then
+ str = str .. utf8_reverse(c)
+ else
+ str = str .. c
+ end
+ else
+ str = str .. utf8.char(b)
+ end
+ end
elseif n and n.id == DISC then
% \end{macrocode}
-% Ligatures are split into |pre| and |post| and both parts are
-% stored. In case of \emph{ffl, ffi}, the post part is also
-% a ligature…
+% Discretionaries are split into |pre| and |post| and both parts
+% are stored. They might be ligatures (\emph{ffl, ffi})…
% \begin{macrocode}
local pre = n.pre
local post = n.post
local c1 = ""
local c2 = ""
- if pre and pre.char and pre.char ~= HYPH and pre.char < 0x100 then
- c1 = string.char(pre.char)
+ if pre and pre.char then
+ if pre.components then
+ for nn in traverse_id(GLYPH, post.components) do
+ c1 = c1 .. utf8.char(nn.char)
+ end
+ else
+ c1 = utf8.char(pre.char)
+ end
+ c1 = utf8_gsub(c1, "-", "")
end
if post and post.char then
- if post.char < 0x100 then
- c2 = string.char(post.char)
- elseif split_lig[post.char] then
- c2 = split_lig[post.char]
- if swap then
- c2 = string.reverse(c2)
+ if post.components then
+ for nn in traverse_id(GLYPH, post.components) do
+ c2 = c2 .. utf8.char(nn.char)
end
+ else
+ c2 = utf8.char(post.char)
end
end
if swap then
- str = str .. c2 .. c1
+ str = str .. utf8_reverse(c2) .. c1
else
str = str .. c1 .. c2
end
@@ -1355,39 +1388,39 @@ local signature = function (node, string, swap)
% \end{macrocode}
% The returned length is the number of \emph{letters}.
% \begin{macrocode}
- local len = string.len(str)
- if string.find(str, "_") then
+ local len = utf8.len(str)
+ if utf8_find(str, "_") then
len = len - 1
end
return len, str
end
% \end{macrocode}
%
-% This auxillary function looks for consecutive lines ending with the
-% same letters.\par
+% The next function looks for consecutive lines ending with
+% the same letters.\par
% It requires five arguments: a string (previous line’s signature),
% a node (the last one on the current line), a line number, a column
% number (possibly |nil|) and a boolean to cancel checking in some
-% cases (end of paragraphs).\par
+% cases (end of paragraphs).
% It prints the matching part at end of linewith with the supplied
% colour and returns the current line’s last word and a boolean (match).
%
-% \changes{v0.32}{2021/03/14}{Functions `check\_first\_word’ and
-% `check\_last\_word’ rewritten.}
+% \changes{v0.32}{2021/03/14}{Functions `check\_line\_first\_word’ and
+% `check\_line\_last\_word’ rewritten.}
%
% \changes{v0.50}{2021/05/13}{Homeoarchy detection added for lines
% starting or ending on \cs{mbox}.}
%
-% \changes{v0.61}{2023/02/06}{`check\_last\_word’ returns a flag
+% \changes{v0.61}{2023/02/06}{`check\_line\_last\_word’ returns a flag
% to set pageflag.}
%
% \begin{macrocode}
-local check_last_word = function (old, node, line, colno, flag)
+local check_line_last_word = function (old, node, line, colno, flag)
local COLOR = luatypo.colortbl[11]
local match = false
local new = ""
local maxlen = 0
- if flag and node then
+ if node then
local swap = true
local box, go
% \end{macrocode}
@@ -1431,69 +1464,91 @@ local check_last_word = function (old, node, line, colno, flag)
maxlen, new = signature (n, new, swap)
until not n or n.id == GLUE
end
- new = string.reverse(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)
- local k = MinPart
- local oldlast = string.gsub (old, '.*_', '')
- local newlast = string.gsub (new, '.*_', '')
- local i = string.find(new, "_")
- if i and i > maxlen - MinPart + 1 then
- k = MinPart + 1
- end
- local oldsub = string.sub(old,-k)
- local newsub = string.sub(new,-k)
- local l = string.len(new)
- if oldsub == newsub and l >= k then
-%<dbg> texio.write_nl('EOLnewsub=' .. newsub)
- match = true
- elseif oldlast == newlast and string.len(newlast) >= MinFull then
-%<dbg> texio.write_nl('EOLnewlast=' .. newlast)
- match = true
- oldsub = oldlast
- newsub = newlast
- k = string.len(newlast)
- end
- if match then
+ new = utf8_reverse(new)
+%<dbg> texio.write_nl("EOLsigold=" .. old)
+%<dbg> texio.write(" EOLsig=" .. new)
% \end{macrocode}
-% Minimal partial match; any more glyphs matching?
+% When called with flag |false|, |check_line_last_word| returns
+% the last word’s signature, but doesn’t compare it with the
+% previous line’s.
% \begin{macrocode}
- local osub = oldsub
- local nsub = newsub
- while osub == nsub and k <= maxlen do
- k = k +1
- osub = string.sub(old,-k)
- nsub = string.sub(new,-k)
- if osub == nsub then
- newsub = nsub
+ if flag then
+ local MinFull = luatypo.MinFull
+ local MinPart = luatypo.MinPart
+ MinFull = math.min(MinPart,MinFull)
+ local k = MinPart
+ local dlo = utf8_reverse(old)
+ local wen = utf8_reverse(new)
+ local oldlast = utf8_gsub (old, ".*_", "_")
+ local newlast = utf8_gsub (new, ".*_", "_")
+ local i
+ if utf8_find(newlast, "_") then
+ i = utf8.len(newlast)
+ end
+ if i and i > maxlen - MinPart + 1 then
+ k = MinPart + 1
+ end
+ local oldsub = ""
+ local newsub = ""
+ for p, c in utf8.codes(dlo) do
+ if utf8.len(oldsub) < k then
+ oldsub = utf8.char(c) .. oldsub
end
end
- newsub = string.gsub(newsub, '^_', '')
-%<dbg> texio.write_nl('EOLfullmatch=' .. newsub)
- local msg = "E.O.L. MATCH=" .. newsub
- log_flaw(msg, line, colno, footnote)
+ for p, c in utf8.codes(wen) do
+ if utf8.len(newsub) < k then
+ newsub = utf8.char(c) .. newsub
+ end
+ end
+ local l = utf8.len(new)
+ if oldsub == newsub and l >= k then
+%<dbg> texio.write_nl("EOLnewsub=" .. newsub)
+ match = true
+ elseif oldlast == newlast and utf8.len(newlast) > MinFull then
+%<dbg> texio.write_nl("EOLnewlast=" .. newlast)
+ match = true
+ oldsub = oldlast
+ newsub = newlast
+ k = utf8.len(newlast)
+ end
+ if match then
+% \end{macrocode}
+% Minimal partial match; any more glyphs matching?
+% \begin{macrocode}
+ local osub = oldsub
+ local nsub = newsub
+ while osub == nsub and k <= maxlen do
+ k = k +1
+ osub = string.sub(old,-k)
+ nsub = string.sub(new,-k)
+ if osub == nsub then
+ newsub = nsub
+ end
+ end
+ newsub = utf8_gsub(newsub, "^_", "")
+%<dbg> texio.write_nl("EOLfullmatch=" .. newsub)
+ local msg = "E.O.L. MATCH=" .. newsub
+ log_flaw(msg, line, colno, footnote)
% \end{macrocode}
% Lest’s colour the matching string.
% \begin{macrocode}
- oldsub = string.reverse(newsub)
- local newsub = ""
- local n = lastn
- repeat
- if n and n.id ~= GLUE then
- color_node(n, COLOR)
- l, newsub = signature(n, newsub, swap)
- elseif n and n.id == GLUE then
- newsub = newsub .. "_"
- elseif not n and box then
- n = box
- else
- break
- end
- n = n.prev
- until newsub == oldsub or l >= k
+ oldsub = utf8_reverse(newsub)
+ local newsub = ""
+ local n = lastn
+ repeat
+ if n and n.id ~= GLUE then
+ color_node(n, COLOR)
+ l, newsub = signature(n, newsub, swap)
+ elseif n and n.id == GLUE then
+ newsub = newsub .. "_"
+ elseif not n and box then
+ n = box
+ else
+ break
+ end
+ n = n.prev
+ until newsub == oldsub or l >= k
+ end
end
end
return new, match
@@ -1503,11 +1558,11 @@ end
% Same thing for beginning of lines: check the first two words
% and compare their signature with the previous line’s.
%
-% \changes{v0.61}{2023/02/06}{`check\_first\_word’ returns a flag
+% \changes{v0.61}{2023/02/06}{`check\_line\_first\_word’ returns a flag
% to set pageflag.}
%
% \begin{macrocode}
-local check_first_word = function (old, node, line, colno, flag)
+local check_line_first_word = function (old, node, line, colno, flag)
local COLOR = luatypo.colortbl[10]
local match = false
local swap = false
@@ -1548,10 +1603,10 @@ local check_first_word = function (old, node, line, colno, flag)
maxlen, new = signature (n, new, swap)
until not n or n.id == GLUE
end
-%<dbg> texio.write_nl('BOLsigold=' .. old)
-%<dbg> texio.write(' BOLsig=' .. new)
+%<dbg> texio.write_nl("BOLsigold=" .. old)
+%<dbg> texio.write(" BOLsig=" .. new)
% \end{macrocode}
-% When called with flag |false|, |check_first_word| returns
+% When called with flag |false|, |check_line_first_word| returns
% the first word’s signature, but doesn’t compare it with the
% previous line’s.
% \begin{macrocode}
@@ -1560,26 +1615,33 @@ local check_first_word = function (old, node, line, colno, flag)
local MinPart = luatypo.MinPart
MinFull = math.min(MinPart,MinFull)
local k = MinPart
- local oldsub = ""
- local newsub = ""
- local oldfirst = string.gsub (old, '_.*', '')
- local newfirst = string.gsub (new, '_.*', '')
- local i = string.find(new, "_")
+ local oldfirst = utf8_gsub (old, "_.*", "_")
+ local newfirst = utf8_gsub (new, "_.*", "_")
+ local i
+ if utf8_find(newfirst, "_") then
+ i = utf8.len(newfirst)
+ end
if i and i <= MinPart then
k = MinPart + 1
end
- local oldsub = string.sub(old,1,k)
- local newsub = string.sub(new,1,k)
- local l = string.len(newsub)
+ local oldsub = ""
+ local newsub = ""
+ for p, c in utf8.codes(old) do
+ if utf8.len(oldsub) < k then oldsub = oldsub .. utf8.char(c) end
+ end
+ for p, c in utf8.codes(new) do
+ if utf8.len(newsub) < k then newsub = newsub .. utf8.char(c) end
+ end
+ local l = utf8.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)
+ elseif oldfirst == newfirst and utf8.len(newfirst) > MinFull then
+%<dbg> texio.write_nl("BOLnewfirst=" .. newfirst)
match = true
oldsub = oldfirst
newsub = newfirst
- k = string.len(newfirst)
+ k = utf8.len(newfirst)
end
if match then
% \end{macrocode}
@@ -1595,8 +1657,8 @@ local check_first_word = function (old, node, line, colno, flag)
newsub = nsub
end
end
- newsub = string.gsub(newsub, '_$', '') --$
-%<dbg> texio.write_nl('BOLfullmatch=' .. newsub)
+ newsub = utf8_gsub(newsub, "_$", "") --$
+%<dbg> texio.write_nl("BOLfullmatch=" .. newsub)
local msg = "B.O.L. MATCH=" .. newsub
log_flaw(msg, line, colno, footnote)
% \end{macrocode}
@@ -1604,7 +1666,7 @@ local check_first_word = function (old, node, line, colno, flag)
% \begin{macrocode}
oldsub = newsub
local newsub = ""
- local k = string.len(oldsub)
+ local k = utf8.len(oldsub)
local n = start
repeat
if n and n.id ~= GLUE then
@@ -1625,13 +1687,79 @@ local check_first_word = function (old, node, line, colno, flag)
end
% \end{macrocode}
%
-% \pagebreak[4]
-% 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|,
+% \changes{v0.65}{2023/03/02}{New `check\_page\_first\_word’ function.}
+%
+% The next function checks the first word on a new page: if
+% it ends a sentence and is short (up to |luatypoMinLen| characters),
+% the function returns |true| and colors the offending word.
+% Otherwise it just retrurs |false|.
+% The function requires two arguments: the line’s first node and
+% a column number (possibly |nil|).
+%
+% \begin{macrocode}
+local check_page_first_word = function (node, colno)
+ local COLOR = luatypo.colortbl[14]
+ local match = false
+ local swap = false
+ local new = ""
+ local maxlen = luatypo.MinLen
+ local len = 0
+ local n = node
+ local pn
+ while n and n.id ~= GLYPH and n.id ~= DISC and
+ (n.id ~= HLIST or n.subtype == INDENT) do
+ n = n.next
+ end
+ local start = n
+ if n and n.id == HLIST then
+ start = n.head
+ n = n.head
+ end
+ repeat
+ len, new = signature (n, new, swap)
+ n = n.next
+ until len > maxlen or (n and n.id == GLYPH and eow_char[n.char]) or
+ (n and n.id == GLUE) or
+ (n and n.id == KERN and n.subtype == 1)
+% \end{macrocode}
+% In French `?’ and `!’ are preceded by a glue (babel) or a kern
+% (polyglossia).
+% \begin{macrocode}
+ if n and (n.id == GLUE or n.id == KERN) then
+ pn = n
+ n = n.next
+ end
+ if len <= maxlen and n and n.id == GLYPH and eow_char[n.char] then
+ match =true
+ if pn and (pn.id == GLUE or pn.id == KERN) then
+ new = new .. " "
+ len = len + 1
+ end
+ len = len + 1
+ end
+%<dbg> texio.write_nl("FinalWord=" .. new)
+ if match then
+ local msg = "ShortFinalWord=" .. new
+ log_flaw(msg, 1, colno, false)
+% \end{macrocode}
+% Lest’s colour the final word and punctuation sign.
+% \begin{macrocode}
+ local n = start
+ repeat
+ color_node(n, COLOR)
+ n = n.next
+ until eow_char[n.char]
+ color_node(n, COLOR)
+ end
+ return match
+end
+% \end{macrocode}
+%
+% The next 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 next two are the line and
-% column number.\par
-% TODO: where does ``out of range’’ starts? U+0100? U+0180?
+% column number.
%
% \changes{v0.61}{2023/02/06}{`check\_regexpr’ returns a flag
% to set pageflag in `check\_vtop’.}
@@ -1651,11 +1779,11 @@ local check_regexpr = function (glyph, line, colno)
% \end{macrocode}
% For single char words, the previous node is a glue.
% \begin{macrocode}
- if lchar and lchar < 0x100 and previous and previous.id == GLUE then
- match = string.find(luatypo.single[lang], string.char(lchar))
+ if lchar and previous and previous.id == GLUE then
+ match = utf8_find(luatypo.single[lang], utf8.char(lchar))
if match then
retflag = true
- local msg = "RGX MATCH=" .. string.char(lchar)
+ local msg = "RGX MATCH=" .. utf8.char(lchar)
log_flaw(msg, line, colno, footnote)
color_node(glyph,COLOR)
end
@@ -1671,9 +1799,9 @@ local check_regexpr = function (glyph, line, colno)
% \end{macrocode}
% For two chars words, the previous node is a glue…
% \begin{macrocode}
- if pchar and pchar < 0x100 and pprev and pprev.id == GLUE then
- local pattern = string.char(pchar) .. string.char(lchar)
- match = string.find(luatypo.double[lang], pattern)
+ if pchar and pprev and pprev.id == GLUE then
+ local pattern = utf8.char(pchar) .. utf8.char(lchar)
+ match = utf8_find(luatypo.double[lang], pattern)
if match then
retflag = true
local msg = "RGX MATCH=" .. pattern
@@ -1690,10 +1818,9 @@ local check_regexpr = function (glyph, line, colno)
if pprev and pprev.id == GLYPH then
local pchar, id = is_glyph(pprev)
local ppprev = pprev.prev
- if pchar and pchar < 0x100 and
- ppprev and ppprev.id == GLUE then
- local pattern = string.char(pchar) .. string.char(lchar)
- match = string.find(luatypo.double[lang], pattern)
+ if pchar and ppprev and ppprev.id == GLUE then
+ local pattern = utf8.char(pchar) .. utf8.char(lchar)
+ match = utf8_find(luatypo.double[lang], pattern)
if match then
retflag = true
local msg = "REGEXP MATCH=" .. pattern
@@ -1709,8 +1836,8 @@ return retflag
end
% \end{macrocode}
%
-% This auxillary function prints the first part of an hyphenated word
-% up to the discretionary, with a supplied colour.
+% The next function prints the first part of an hyphenated
+% word up to the discretionary, with a supplied colour.
% It requires two arguments: a \node{disc} node and a (named) colour.
%
% \begin{macrocode}
@@ -1725,7 +1852,7 @@ local show_pre_disc = function (disc, color)
% \end{macrocode}
%
% \begin{macro}{footnoterule-ahead}
-% This auxillary function scans the current \node{vlist} in search
+% The next 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
@@ -1759,11 +1886,11 @@ local footnoterule_ahead = function (head)
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)
+%<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
@@ -1774,7 +1901,7 @@ end
% \end{macro}
%
% \begin{macro}{get-pagebody}
-% This auxillary function scans the \node{vlist}s on the current
+% The next 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.
%
@@ -1789,29 +1916,29 @@ local get_pagebody = function (head)
repeat
fn = fn.next
until fn.id == VLIST and fn.height > 0
-%<dbg> texio.write_nl(' ')
+%<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)
+%<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> local ht = string.format("%.1fpt", n.height/65536)
-%<dbg> texio.write_nl('BODY found: ht=' .. ht)
-%<dbg> texio.write_nl(' ')
+%<dbg> texio.write_nl("BODY found: ht=" .. ht)
+%<dbg> texio.write_nl(" ")
body = n
break
else
-%<dbg> texio.write_nl('Skip short VLIST:')
+%<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)
+%<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> local ht = string.format("%.1fpt", n.height/65536)
-%<dbg> texio.write_nl(' BODY: ht=' .. ht)
+%<dbg> texio.write_nl(" BODY: ht=" .. ht)
body = n
break
end
@@ -1819,7 +1946,7 @@ local get_pagebody = function (head)
end
end
if not body then
- texio.write_nl('***lua-typo ERROR: PAGE BODY *NOT* FOUND!***')
+ texio.write_nl("***lua-typo ERROR: PAGE BODY *NOT* FOUND!***")
end
return body
end
@@ -1827,7 +1954,7 @@ end
% \end{macro}
%
% \begin{macro}{check-vtop}
-% This function is called repeatedly by |check_page| (see below);
+% The next 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.
%
@@ -1863,6 +1990,7 @@ check_vtop = function (head, colno, vpos)
local EOLShortWords = luatypo.EOLShortWords
local LastWordMatch = luatypo.LastWordMatch
local FootnoteSplit = luatypo.FootnoteSplit
+ local ShortFinalWord = luatypo.ShortFinalWord
local Stretch = math.max(luatypo.Stretch/100,1)
local blskip = tex.getglue("baselineskip")
local vpos_min = PAGEmin * blskip
@@ -1904,6 +2032,7 @@ check_vtop = function (head, colno, vpos)
vpos = vpos + head.height + head.depth
local linewd = head.width
local first = head.head
+ local ListItem = false
if footnote then
ftnline = ftnline + 1
line = ftnline
@@ -1926,9 +2055,9 @@ check_vtop = function (head, colno, vpos)
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(' ')
+%<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?
@@ -1954,6 +2083,7 @@ check_vtop = function (head, colno, vpos)
color_line (head, COLOR)
end
% \end{macrocode}
+% \enlargethispage*{2\baselineskip}
% 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.
@@ -1976,7 +2106,6 @@ check_vtop = function (head, colno, vpos)
(first.id == GLUE and first.subtype == LFTSKIP) do
first = first.next
end
- local ListItem = false
% \end{macrocode}
% Now let’s analyse the beginning of the current line.
% \begin{macrocode}
@@ -1987,6 +2116,8 @@ check_vtop = function (head, colno, vpos)
% they are frozen in footnotes).
% \begin{macrocode}
hyphcount = 0
+ firstwd = ""
+ lastwd = ""
if not footnote then
parline = 1
if body_bottom then
@@ -2043,8 +2174,8 @@ check_vtop = function (head, colno, vpos)
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)
+%<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}
@@ -2095,7 +2226,7 @@ check_vtop = function (head, colno, vpos)
if FirstWordMatch then
local flag = not ListItem
firstwd, flag =
- check_first_word(firstwd, first, line, colno, flag)
+ check_line_first_word(firstwd, first, line, colno, flag)
if flag then
pageflag = true
end
@@ -2109,7 +2240,7 @@ check_vtop = function (head, colno, vpos)
flag = false
end
lastwd, flag =
- check_last_word(lastwd, pn, line, colno, flag)
+ check_line_last_word(lastwd, pn, line, colno, flag)
if flag then
pageflag = true
end
@@ -2123,46 +2254,46 @@ check_vtop = function (head, colno, vpos)
% Colour the whole line now if it is a orphan or a footnote
% continuing on the next page.
% \begin{macrocode}
- if orphanflag and Orphans then
- pageflag = true
- local msg = "ORPHAN"
- log_flaw(msg, line, colno, footnote)
- local COLOR = luatypo.colortbl[5]
- color_line (head, COLOR)
- end
- if ftnsplit and FootnoteSplit then
- pageflag = true
- local msg = "FOOTNOTE SPLIT"
- log_flaw(msg, line, colno, footnote)
- local COLOR = luatypo.colortbl[13]
- color_line (head, COLOR)
- end
- if (page_bottom or body_bottom) and EOPHyphens then
+ if orphanflag and Orphans then
+ pageflag = true
+ local msg = "ORPHAN"
+ log_flaw(msg, line, colno, footnote)
+ local COLOR = luatypo.colortbl[5]
+ color_line (head, COLOR)
+ end
+ if ftnsplit and FootnoteSplit then
+ pageflag = true
+ local msg = "FOOTNOTE SPLIT"
+ log_flaw(msg, line, colno, footnote)
+ local COLOR = luatypo.colortbl[13]
+ color_line (head, COLOR)
+ end
+ if (page_bottom or body_bottom) and EOPHyphens then
% \end{macrocode}
% This hyphen occurs on the page’s last line (body or footnote),
% colour (differently) the last word.
% \begin{macrocode}
- pageflag = true
- local msg = "LAST WORD SPLIT"
- log_flaw(msg, line, colno, footnote)
- local COLOR = luatypo.colortbl[1]
- local pg = show_pre_disc (pn,COLOR)
- end
+ pageflag = true
+ local msg = "LAST WORD SPLIT"
+ log_flaw(msg, line, colno, footnote)
+ local COLOR = luatypo.colortbl[1]
+ local pg = show_pre_disc (pn,COLOR)
+ end
% \end{macrocode}
% Track matching words at the beginning and end of line.
% \begin{macrocode}
if FirstWordMatch then
local flag = not ListItem
firstwd, flag =
- check_first_word(firstwd, first, line, colno, flag)
+ check_line_first_word(firstwd, first, line, colno, flag)
if flag then
pageflag = true
end
end
if LastWordMatch then
- local flag = false
+ local flag = true
lastwd, flag =
- check_last_word(lastwd, ln, line, colno, true)
+ check_line_last_word(lastwd, ln, line, colno, flag)
if flag then
pageflag = true
end
@@ -2206,36 +2337,36 @@ check_vtop = function (head, colno, vpos)
% Colour the whole line now if it is a orphan or a footnote
% continuing on the next page.
% \begin{macrocode}
- if orphanflag and Orphans then
- pageflag = true
- local msg = "ORPHAN"
- log_flaw(msg, line, colno, footnote)
- local COLOR = luatypo.colortbl[5]
- color_line (head, COLOR)
- end
- if ftnsplit and FootnoteSplit then
- pageflag = true
- local msg = "FOOTNOTE SPLIT"
- log_flaw(msg, line, colno, footnote)
- local COLOR = luatypo.colortbl[13]
- color_line (head, COLOR)
- end
+ if orphanflag and Orphans then
+ pageflag = true
+ local msg = "ORPHAN"
+ log_flaw(msg, line, colno, footnote)
+ local COLOR = luatypo.colortbl[5]
+ color_line (head, COLOR)
+ end
+ if ftnsplit and FootnoteSplit then
+ pageflag = true
+ local msg = "FOOTNOTE SPLIT"
+ log_flaw(msg, line, colno, footnote)
+ local COLOR = luatypo.colortbl[13]
+ color_line (head, COLOR)
+ end
% \end{macrocode}
-% Track matching words at the beginning and end of line and shot
+% Track matching words at the beginning and end of line and short
% words.
% \begin{macrocode}
if FirstWordMatch then
local flag = not ListItem
firstwd, flag =
- check_first_word(firstwd, first, line, colno, flag)
+ check_line_first_word(firstwd, first, line, colno, flag)
if flag then
pageflag = true
end
end
if LastWordMatch and pn then
- local flag
+ local flag = true
lastwd, flag =
- check_last_word(lastwd, pn, line, colno, true)
+ check_line_last_word(lastwd, pn, line, colno, flag)
if flag then
pageflag = true
end
@@ -2252,6 +2383,13 @@ check_vtop = function (head, colno, vpos)
end
end
% \end{macrocode}
+% Check the page’s first word (end of sentence?).
+% \begin{macrocode}
+ if ShortFinalWord and pageline == 1 and parline > 1 and
+ check_page_first_word(first,colno) then
+ pageflag = true
+ end
+% \end{macrocode}
% End of scanning for the main type of node (text lines).
% \begin{macrocode}
elseif head.id == HLIST and
@@ -2323,8 +2461,8 @@ check_vtop = function (head, colno, vpos)
% set the |footnote| flag and reset some counters and flags
% for the coming footnote lines.
% \begin{macrocode}
-%<dbg> texio.write_nl('check_vtop: footnotes start')
-%<dbg> texio.write_nl(' ')
+%<dbg> texio.write_nl("check_vtop: footnotes start")
+%<dbg> texio.write_nl(" ")
footnote = true
ftnline = 0
body_bottom = false
@@ -2342,15 +2480,15 @@ check_vtop = function (head, colno, vpos)
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> 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> texio.write(" textheight=" .. tht_pt)
%<dbg> end
-%<dbg> texio.write_nl(' ')
+%<dbg> texio.write_nl(" ")
if pageline > 1 and pageline < PAGEmin and ShortPages then
pageshort = true
end
@@ -2388,21 +2526,21 @@ check_vtop = function (head, colno, vpos)
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(' ')
+%<dbg> texio.write_nl("check_vtop: BREAK => multicol")
+%<dbg> texio.write_nl(" ")
break
end
end
head = nextnode
end
%<dbg> if nextnode then
-%<dbg> texio.write('Exit check_vtop, next=')
+%<dbg> texio.write("Exit check_vtop, next=")
%<dbg> texio.write(tostring(node.type(nextnode.id)))
-%<dbg> texio.write('-'.. nextnode.subtype)
+%<dbg> texio.write("-".. nextnode.subtype)
%<dbg> else
-%<dbg> texio.write_nl('Exit check_vtop, next=nil')
+%<dbg> texio.write_nl("Exit check_vtop, next=nil")
%<dbg> end
-%<dbg> texio.write_nl('')
+%<dbg> texio.write_nl("")
% \end{macrocode}
% Update the list of flagged pages avoiding duplicates:
% \begin{macrocode}
@@ -2451,8 +2589,8 @@ luatypo.check_page = function (head)
% of bowing, let’s step down one level.
% \begin{macrocode}
%<dbg> local boxwd = string.format("%.1fpt", first.width/65536)
-%<dbg> texio.write_nl('One step down: boxwd=' .. boxwd)
-%<dbg> texio.write_nl(' ')
+%<dbg> texio.write_nl("One step down: boxwd=" .. boxwd)
+%<dbg> texio.write_nl(" ")
top = body.list
first = top.list
end
@@ -2461,9 +2599,9 @@ luatypo.check_page = function (head)
% \begin{macrocode}
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(' ')
+%<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}
@@ -2471,11 +2609,11 @@ luatypo.check_page = function (head)
% \begin{macrocode}
%<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_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(' ')
+%<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
@@ -2489,24 +2627,24 @@ luatypo.check_page = function (head)
% Two or more columns, each one is boxed in a vlist.\par
% Run |check_vtop| on every column.
% \begin{macrocode}
-%<dbg> texio.write_nl('**MULTICOL type1:')
-%<dbg> texio.write_nl(' ')
+%<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(' ')
+%<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(' ')
+%<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_nl("MULTICOL type1 END: next=")
%<dbg> texio.write(tostring(node.type(top.id)))
-%<dbg> texio.write('-' .. top.subtype)
-%<dbg> texio.write_nl(' ')
+%<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
@@ -2515,19 +2653,19 @@ luatypo.check_page = function (head)
% holds a vlist.\par
% Run |check_vtop| on every column.
% \begin{macrocode}
-%<dbg> texio.write_nl('**MULTICOL type2:')
-%<dbg> texio.write_nl(' ')
+%<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(' ')
+%<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(' ')
+%<dbg> texio.write_nl("End of col." .. colno)
+%<dbg> texio.write_nl(" ")
end
end
colno = nil
@@ -2543,18 +2681,17 @@ return luatypo.check_page
% \end{macrocode}
% \end{macro}
%
+% \changes{v0.50}{2021/05/02}{Callback `pre\_output\_filter’ replaced
+% by `pre\_shipout\_filter’, in the former the material is not boxed
+% yet and footnotes are not visible.}
+%
% NOTE: |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|.
%
% Add the |luatypo.check_page| function to the |pre_shipout_filter|
% callback (with priority 1 for colour attributes to be effective),
-% unless option |None| is selected ; remember that the |None|
-% 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 former the material is not boxed
-% yet and footnotes are not visible.}
+% unless option |None| is selected.
%
% \begin{macrocode}
\AtEndOfPackage{%
@@ -2567,17 +2704,16 @@ return luatypo.check_page
}
% \end{macrocode}
%
-% Load a local config file if present in LaTeX’s search path.\par
-% Otherwise, set reasonnable defaults.
+% Load a config file if present in LaTeX’s search path or
+% set reasonnable defaults.
%
-% \changes{v0.61}{2023/02/07}{Colours mygrey, myred renamed
+% \changes{v0.61}{2023/02/07}{Colours mygrey, myred renamed as
% LTgrey, LTred.}
%
% \begin{macrocode}
-
\InputIfFileExists{lua-typo.cfg}%
- {\PackageInfo{lua-typo.sty}{'lua-typo.cfg' file loaded}}%
- {\PackageInfo{lua-typo.sty}{'lua-typo.cfg' file not found.
+ {\PackageInfo{lua-typo.sty}{"lua-typo.cfg" file loaded}}%
+ {\PackageInfo{lua-typo.sty}{"lua-typo.cfg" file not found.
\MessageBreak Providing default values.}%
\definecolor{LTgrey}{gray}{0.6}%
\definecolor{LTred}{rgb}{1,0.55,0}
@@ -2595,6 +2731,7 @@ return luatypo.check_page
\luatypoSetColor{11}{LTred}% Last word matches
\luatypoSetColor{12}{LTgrey}% Paragraph ending on a nearly full line
\luatypoSetColor{13}{cyan}% Footnote split
+ \luatypoSetColor{14}{red}% Too short first (final) word on the page
\luatypoBackPI=1em\relax
\luatypoBackFuzz=2pt\relax
\ifdim\parindent=0pt \luatypoLLminWD=20pt\relax
@@ -2604,6 +2741,7 @@ return luatypo.check_page
\luatypoPageMin=5\relax
\luatypoMinFull=4\relax
\luatypoMinPART=4\relax
+ \luatypoMinLen=4\relax
}%
% \end{macrocode}
% \iffalse
@@ -2643,6 +2781,10 @@ return luatypo.check_page
\luatypoMinFull=3\relax
\luatypoMinPart=4\relax
+%% Minimum number of characters for the first word on a page if it ends
+%% a sentence.
+\luatypoMinLen=4\relax
+
%% Default colours = red, cyan, LTgrey
\definecolor{LTgrey}{gray}{0.6}
\definecolor{LTred}{rgb}{1,0.55,0}
@@ -2660,11 +2802,12 @@ return luatypo.check_page
\luatypoSetColor{11}{LTred} % Last word matches
\luatypoSetColor{12}{LTgrey}% Paragraph ending on a nearly full line
\luatypoSetColor{13}{cyan} % Footnote split
+\luatypoSetColor{14}{red} % Too short first (final) word on the page
%% Language specific settings (example for French):
%% short words (two letters max) to be avoided at end of lines.
-%%\luatypoOneChar{french}{'À Ô Y'}
-%%\luatypoTwoChars{french}{'Je Tu Il On Au De'}
+%%\luatypoOneChar{french}{"À Ô Y"}
+%%\luatypoTwoChars{french}{"Je Tu Il On Au De"}
% \end{macrocode}
%
% \iffalse
@@ -2729,12 +2872,12 @@ return luatypo.check_page
\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(' ')
+ texio.write_nl(" ")
+ texio.write_nl("***************************")
+ texio.write_nl("*** PAGE SCANNING ONLY: ***")
+ texio.write_nl("*** NO CHECK PERFORMED! ***")
+ texio.write_nl("***************************")
+ texio.write_nl(" ")
}%
}
@@ -2750,21 +2893,10 @@ 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")
@@ -2807,24 +2939,24 @@ local get_pagebody = function (head)
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)
+ 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(' ')
+ 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)
+ 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(' ')
+ texio.write_nl(" BODY: " .. ht)
+ texio.write_nl(" ")
body = n
break
end
@@ -2832,37 +2964,48 @@ local get_pagebody = function (head)
end
end
if not body then
- texio.write_nl('***lua-typo ERROR: PAGE BODY *NOT* FOUND!***')
+ 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
+ if n.id == GLYPH then
+ texio.write(utf8.char(n.char))
+ elseif n.id == GLUE then
real_pt = string.format("%.1fpt", effective_glue(n,parent)/65536)
- texio.write(' realwd=' .. real_pt)
+ 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))
+ local c = ""
+ if n.replace then
+ for nn in traverse_id(GLYPH, n.replace) do
+ c = c .. utf8.char(nn.char)
+ end
+ texio.write(c)
+ end
+ if n.pre then
+ c = ""
+ for nn in traverse_id(GLYPH, n.pre) do
+ c = c .. utf8.char(nn.char)
+ end
+ texio.write(" pre=" .. c)
+ end
+ if n.post then
+ c = ""
+ for nn in traverse_id(GLYPH, n.post) do
+ c = c .. utf8.char(nn.char)
+ end
+ texio.write(" post=" .. c)
+ end
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)
+ 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
+ texio.write(" wd=" .. wd_pt)
+ end
end
end
@@ -2874,9 +3017,9 @@ 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))
+ 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)
@@ -2886,46 +3029,46 @@ local scanvlist = function (head)
end
while (head) do
texio.write_nl(tostring(node.type(head.id)))
- texio.write('-')
+ 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)
+ 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('-')
+ 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('-')
+ 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('-')
+ 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('-')
+ 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('-')
+ texio.write_nl(" " .. tostring(node.type(n4.id)))
+ texio.write("-")
print_subtype(n5,n4)
end
end
diff --git a/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.cfg b/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.cfg
index 9a3a27405a6..a3d826f54a5 100644
--- a/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.cfg
+++ b/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.cfg
@@ -23,6 +23,10 @@
\luatypoMinFull=3\relax
\luatypoMinPart=4\relax
+%% Minimum number of characters for the first word on a page if it ends
+%% a sentence.
+\luatypoMinLen=4\relax
+
%% Default colours = red, cyan, LTgrey
\definecolor{LTgrey}{gray}{0.6}
\definecolor{LTred}{rgb}{1,0.55,0}
@@ -40,11 +44,12 @@
\luatypoSetColor{11}{LTred} % Last word matches
\luatypoSetColor{12}{LTgrey}% Paragraph ending on a nearly full line
\luatypoSetColor{13}{cyan} % Footnote split
+\luatypoSetColor{14}{red} % Too short first (final) word on the page
%% Language specific settings (example for French):
%% short words (two letters max) to be avoided at end of lines.
-%%\luatypoOneChar{french}{'À Ô Y'}
-%%\luatypoTwoChars{french}{'Je Tu Il On Au De'}
+%%\luatypoOneChar{french}{"À Ô Y"}
+%%\luatypoTwoChars{french}{"Je Tu Il On Au De"}
%%
%%
%% End of file `lua-typo.cfg'.
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 fd7e4a1e5da..aa876b82fa9 100644
--- a/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.sty
+++ b/Master/texmf-dist/tex/lualatex/lua-typo/lua-typo.sty
@@ -11,10 +11,10 @@
%%
\NeedsTeXFormat{LaTeX2e}[2021/06/01]
\ProvidesPackage{lua-typo}
- [2023-02-10 v.0.61 Daniel Flipo]
+ [2023-03-08 v.0.65 Daniel Flipo]
\ifdefined\DeclareRelease
\DeclareRelease{v0.4}{2021-01-01}{lua-typo-2021-04-18.sty}
- \DeclareCurrentRelease{}{2023-02-04}
+ \DeclareCurrentRelease{}{2023-03-08}
\else
\PackageWarning{lua-typo}{Your LaTeX kernel is too old to provide
access\MessageBreak to former versions of the lua-typo package.%
@@ -37,6 +37,7 @@
\newcount\luatypoPageMin
\newcount\luatypoMinFull
\newcount\luatypoMinPart
+\newcount\luatypoMinLen
\newcount\luatypo@LANGno
\newcount\luatypo@options
\newtoks\luatypo@single
@@ -65,6 +66,7 @@ luatypo = { }
\DeclareBoolOption[false]{FirstWordMatch}
\DeclareBoolOption[false]{LastWordMatch}
\DeclareBoolOption[false]{FootnoteSplit}
+\DeclareBoolOption[false]{ShortFinalWord}
\AddToKeyvalOption{luatypo}{All}{%
\LT@ShortLinestrue \LT@ShortPagestrue
\LT@OverfullLinestrue \LT@UnderfullLinestrue
@@ -73,6 +75,7 @@ luatypo = { }
\LT@ParLastHyphentrue \LT@EOLShortWordstrue
\LT@FirstWordMatchtrue \LT@LastWordMatchtrue
\LT@BackParindenttrue \LT@FootnoteSplittrue
+ \LT@ShortFinalWordtrue
}
\ProcessKeyvalOptions{luatypo}
\AtEndOfPackage{%
@@ -165,6 +168,12 @@ luatypo = { }
\else
\directlua{ luatypo.FootnoteSplit = false }%
\fi
+ \ifLT@ShortFinalWord
+ \advance\luatypo@options by 1
+ \directlua{ luatypo.ShortFinalWord = true }%
+ \else
+ \directlua{ luatypo.ShortFinalWord = false }%
+ \fi
}
\ifLT@ShowOptions
\GenericWarning{* }{%
@@ -187,6 +196,7 @@ luatypo = { }
FirstWordMatch [false]\MessageBreak
LastWordMatch [false]\MessageBreak
FootnoteSplit [false]\MessageBreak
+ ShortFinalWord [false]\MessageBreak
\MessageBreak
*********************************************%
\MessageBreak Lua-typo [ShowOptions]
@@ -199,6 +209,7 @@ luatypo = { }
luatypo.Stretch = tex.count.luatypoStretchMax
luatypo.MinFull = tex.count.luatypoMinFull
luatypo.MinPart = tex.count.luatypoMinPart
+ luatypo.MinLen = tex.count.luatypoMinLen
luatypo.LLminWD = tex.dimen.luatypoLLminWD
luatypo.BackPI = tex.dimen.luatypoBackPI
luatypo.BackFuzz = tex.dimen.luatypoBackFuzz
@@ -243,7 +254,7 @@ luatypo = { }
local string = \the\luatypo@single
luatypo.single[langno] = " "
for p, c in utf8.codes(string) do
- local s = string.char(c)
+ local s = utf8.char(c)
luatypo.single[langno] = luatypo.single[langno] .. s
end
}%
@@ -260,7 +271,7 @@ luatypo = { }
local string = \the\luatypo@double
luatypo.double[langno] = " "
for p, c in utf8.codes(string) do
- local s = string.char(c)
+ local s = utf8.char(c)
luatypo.double[langno] = luatypo.double[langno] .. s
end
}%
@@ -291,14 +302,11 @@ char_to_discard[string.byte(":")] = true
char_to_discard[string.byte(";")] = true
char_to_discard[string.byte("-")] = true
-local split_lig = { }
-split_lig[0xFB00] = "ff"
-split_lig[0xFB01] = "fi"
-split_lig[0xFB02] = "fl"
-split_lig[0xFB03] = "ffi"
-split_lig[0xFB04] = "ffl"
-split_lig[0xFB05] = "st"
-split_lig[0xFB06] = "st"
+local eow_char = { }
+eow_char[string.byte(".")] = true
+eow_char[string.byte("!")] = true
+eow_char[string.byte("?")] = true
+eow_char[utf8.codepoint("…")] = true
local DISC = node.id("disc")
local GLYPH = node.id("glyph")
@@ -326,7 +334,6 @@ local USER = 0
local HYPH = 0x2D
local LIGA = 0x102
local parline = 0
-
local dimensions = node.dimensions
local rangedimensions = node.rangedimensions
local effective_glue = node.effective_glue
@@ -337,7 +344,18 @@ local traverse_id = node.traverse_id
local has_field = node.has_field
local uses_font = node.uses_font
local is_glyph = node.is_glyph
-
+local utf8_find = unicode.utf8.find
+local utf8_gsub = unicode.utf8.gsub
+local utf8_reverse = function (s)
+ if utf8.len(s) > 1 then
+ local so = ""
+ for p, c in utf8.codes(s) do
+ so = utf8.char(c) .. so
+ end
+ s = so
+ end
+ return s
+end
local color_node = function (node, color)
local attr = oberdiek.luacolor.getattribute()
if node and node.id == DISC then
@@ -419,61 +437,64 @@ local signature = function (node, string, swap)
local n = node
local str = string
if n and n.id == GLYPH then
- local b, id = is_glyph(n)
- if b and not char_to_discard[b] then
- if b == 0x2019 then b = 0x27 end
- if b < 0x100 then
- str = str .. string.char(b)
- elseif split_lig[b] then
- local c = split_lig[b]
- if swap then
- c = string.reverse(c)
- end
- str = str .. c
- elseif n.subtype == LIGA and b > 0xE000 then
- local c = string.sub(b,-2)
- if swap then
- c = string.reverse(c)
- end
- str = str .. c
- end
- end
+ local b = n.char
+ if b and not char_to_discard[b] then
+ if n.components then
+ local c = ""
+ for nn in traverse_id(GLYPH, n.components) do
+ c = c .. utf8.char(nn.char)
+ end
+ if swap then
+ str = str .. utf8_reverse(c)
+ else
+ str = str .. c
+ end
+ else
+ str = str .. utf8.char(b)
+ end
+ end
elseif n and n.id == DISC then
local pre = n.pre
local post = n.post
local c1 = ""
local c2 = ""
- if pre and pre.char and pre.char ~= HYPH and pre.char < 0x100 then
- c1 = string.char(pre.char)
+ if pre and pre.char then
+ if pre.components then
+ for nn in traverse_id(GLYPH, post.components) do
+ c1 = c1 .. utf8.char(nn.char)
+ end
+ else
+ c1 = utf8.char(pre.char)
+ end
+ c1 = utf8_gsub(c1, "-", "")
end
if post and post.char then
- if post.char < 0x100 then
- c2 = string.char(post.char)
- elseif split_lig[post.char] then
- c2 = split_lig[post.char]
- if swap then
- c2 = string.reverse(c2)
+ if post.components then
+ for nn in traverse_id(GLYPH, post.components) do
+ c2 = c2 .. utf8.char(nn.char)
end
+ else
+ c2 = utf8.char(post.char)
end
end
if swap then
- str = str .. c2 .. c1
+ str = str .. utf8_reverse(c2) .. c1
else
str = str .. c1 .. c2
end
end
- local len = string.len(str)
- if string.find(str, "_") then
+ local len = utf8.len(str)
+ if utf8_find(str, "_") then
len = len - 1
end
return len, str
end
-local check_last_word = function (old, node, line, colno, flag)
+local check_line_last_word = function (old, node, line, colno, flag)
local COLOR = luatypo.colortbl[11]
local match = false
local new = ""
local maxlen = 0
- if flag and node then
+ if node then
local swap = true
local box, go
local lastn = node
@@ -511,63 +532,80 @@ local check_last_word = function (old, node, line, colno, flag)
maxlen, new = signature (n, new, swap)
until not n or n.id == GLUE
end
- new = string.reverse(new)
- local MinFull = luatypo.MinFull
- local MinPart = luatypo.MinPart
- MinFull = math.min(MinPart,MinFull)
- local k = MinPart
- local oldlast = string.gsub (old, '.*_', '')
- local newlast = string.gsub (new, '.*_', '')
- local i = string.find(new, "_")
- if i and i > maxlen - MinPart + 1 then
- k = MinPart + 1
- end
- local oldsub = string.sub(old,-k)
- local newsub = string.sub(new,-k)
- local l = string.len(new)
- if oldsub == newsub and l >= k then
- match = true
- elseif oldlast == newlast and string.len(newlast) >= MinFull then
- match = true
- oldsub = oldlast
- newsub = newlast
- k = string.len(newlast)
- end
- if match then
- local osub = oldsub
- local nsub = newsub
- while osub == nsub and k <= maxlen do
- k = k +1
- osub = string.sub(old,-k)
- nsub = string.sub(new,-k)
- if osub == nsub then
- newsub = nsub
- end
+ new = utf8_reverse(new)
+ if flag then
+ local MinFull = luatypo.MinFull
+ local MinPart = luatypo.MinPart
+ MinFull = math.min(MinPart,MinFull)
+ local k = MinPart
+ local dlo = utf8_reverse(old)
+ local wen = utf8_reverse(new)
+ local oldlast = utf8_gsub (old, ".*_", "_")
+ local newlast = utf8_gsub (new, ".*_", "_")
+ local i
+ if utf8_find(newlast, "_") then
+ i = utf8.len(newlast)
end
- newsub = string.gsub(newsub, '^_', '')
- local msg = "E.O.L. MATCH=" .. newsub
- log_flaw(msg, line, colno, footnote)
- oldsub = string.reverse(newsub)
+ if i and i > maxlen - MinPart + 1 then
+ k = MinPart + 1
+ end
+ local oldsub = ""
local newsub = ""
- local n = lastn
- repeat
- if n and n.id ~= GLUE then
- color_node(n, COLOR)
- l, newsub = signature(n, newsub, swap)
- elseif n and n.id == GLUE then
- newsub = newsub .. "_"
- elseif not n and box then
- n = box
- else
- break
+ for p, c in utf8.codes(dlo) do
+ if utf8.len(oldsub) < k then
+ oldsub = utf8.char(c) .. oldsub
end
- n = n.prev
- until newsub == oldsub or l >= k
+ end
+ for p, c in utf8.codes(wen) do
+ if utf8.len(newsub) < k then
+ newsub = utf8.char(c) .. newsub
+ end
+ end
+ local l = utf8.len(new)
+ if oldsub == newsub and l >= k then
+ match = true
+ elseif oldlast == newlast and utf8.len(newlast) > MinFull then
+ match = true
+ oldsub = oldlast
+ newsub = newlast
+ k = utf8.len(newlast)
+ end
+ if match then
+ local osub = oldsub
+ local nsub = newsub
+ while osub == nsub and k <= maxlen do
+ k = k +1
+ osub = string.sub(old,-k)
+ nsub = string.sub(new,-k)
+ if osub == nsub then
+ newsub = nsub
+ end
+ end
+ newsub = utf8_gsub(newsub, "^_", "")
+ local msg = "E.O.L. MATCH=" .. newsub
+ log_flaw(msg, line, colno, footnote)
+ oldsub = utf8_reverse(newsub)
+ local newsub = ""
+ local n = lastn
+ repeat
+ if n and n.id ~= GLUE then
+ color_node(n, COLOR)
+ l, newsub = signature(n, newsub, swap)
+ elseif n and n.id == GLUE then
+ newsub = newsub .. "_"
+ elseif not n and box then
+ n = box
+ else
+ break
+ end
+ n = n.prev
+ until newsub == oldsub or l >= k
+ end
end
end
return new, match
end
-local check_first_word = function (old, node, line, colno, flag)
+local check_line_first_word = function (old, node, line, colno, flag)
local COLOR = luatypo.colortbl[10]
local match = false
local swap = false
@@ -613,24 +651,31 @@ local check_first_word = function (old, node, line, colno, flag)
local MinPart = luatypo.MinPart
MinFull = math.min(MinPart,MinFull)
local k = MinPart
- local oldsub = ""
- local newsub = ""
- local oldfirst = string.gsub (old, '_.*', '')
- local newfirst = string.gsub (new, '_.*', '')
- local i = string.find(new, "_")
+ local oldfirst = utf8_gsub (old, "_.*", "_")
+ local newfirst = utf8_gsub (new, "_.*", "_")
+ local i
+ if utf8_find(newfirst, "_") then
+ i = utf8.len(newfirst)
+ end
if i and i <= MinPart then
k = MinPart + 1
end
- local oldsub = string.sub(old,1,k)
- local newsub = string.sub(new,1,k)
- local l = string.len(newsub)
+ local oldsub = ""
+ local newsub = ""
+ for p, c in utf8.codes(old) do
+ if utf8.len(oldsub) < k then oldsub = oldsub .. utf8.char(c) end
+ end
+ for p, c in utf8.codes(new) do
+ if utf8.len(newsub) < k then newsub = newsub .. utf8.char(c) end
+ end
+ local l = utf8.len(newsub)
if oldsub == newsub and l >= k then
match = true
- elseif oldfirst == newfirst and string.len(newfirst) >= MinFull then
+ elseif oldfirst == newfirst and utf8.len(newfirst) > MinFull then
match = true
oldsub = oldfirst
newsub = newfirst
- k = string.len(newfirst)
+ k = utf8.len(newfirst)
end
if match then
local osub = oldsub
@@ -643,12 +688,12 @@ local check_first_word = function (old, node, line, colno, flag)
newsub = nsub
end
end
- newsub = string.gsub(newsub, '_$', '') --$
+ newsub = utf8_gsub(newsub, "_$", "") --$
local msg = "B.O.L. MATCH=" .. newsub
log_flaw(msg, line, colno, footnote)
oldsub = newsub
local newsub = ""
- local k = string.len(oldsub)
+ local k = utf8.len(oldsub)
local n = start
repeat
if n and n.id ~= GLUE then
@@ -667,6 +712,54 @@ local check_first_word = function (old, node, line, colno, flag)
end
return new, match
end
+local check_page_first_word = function (node, colno)
+ local COLOR = luatypo.colortbl[14]
+ local match = false
+ local swap = false
+ local new = ""
+ local maxlen = luatypo.MinLen
+ local len = 0
+ local n = node
+ local pn
+ while n and n.id ~= GLYPH and n.id ~= DISC and
+ (n.id ~= HLIST or n.subtype == INDENT) do
+ n = n.next
+ end
+ local start = n
+ if n and n.id == HLIST then
+ start = n.head
+ n = n.head
+ end
+ repeat
+ len, new = signature (n, new, swap)
+ n = n.next
+ until len > maxlen or (n and n.id == GLYPH and eow_char[n.char]) or
+ (n and n.id == GLUE) or
+ (n and n.id == KERN and n.subtype == 1)
+ if n and (n.id == GLUE or n.id == KERN) then
+ pn = n
+ n = n.next
+ end
+ if len <= maxlen and n and n.id == GLYPH and eow_char[n.char] then
+ match =true
+ if pn and (pn.id == GLUE or pn.id == KERN) then
+ new = new .. " "
+ len = len + 1
+ end
+ len = len + 1
+ end
+ if match then
+ local msg = "ShortFinalWord=" .. new
+ log_flaw(msg, 1, colno, false)
+ local n = start
+ repeat
+ color_node(n, COLOR)
+ n = n.next
+ until eow_char[n.char]
+ color_node(n, COLOR)
+ end
+ return match
+end
local check_regexpr = function (glyph, line, colno)
local COLOR = luatypo.colortbl[3]
local lang = glyph.lang
@@ -675,11 +768,11 @@ local check_regexpr = function (glyph, line, colno)
local lchar, id = is_glyph(glyph)
local previous = glyph.prev
if lang and luatypo.single[lang] then
- if lchar and lchar < 0x100 and previous and previous.id == GLUE then
- match = string.find(luatypo.single[lang], string.char(lchar))
+ if lchar and previous and previous.id == GLUE then
+ match = utf8_find(luatypo.single[lang], utf8.char(lchar))
if match then
retflag = true
- local msg = "RGX MATCH=" .. string.char(lchar)
+ local msg = "RGX MATCH=" .. utf8.char(lchar)
log_flaw(msg, line, colno, footnote)
color_node(glyph,COLOR)
end
@@ -689,9 +782,9 @@ local check_regexpr = function (glyph, line, colno)
if lchar and previous and previous.id == GLYPH then
local pchar, id = is_glyph(previous)
local pprev = previous.prev
- if pchar and pchar < 0x100 and pprev and pprev.id == GLUE then
- local pattern = string.char(pchar) .. string.char(lchar)
- match = string.find(luatypo.double[lang], pattern)
+ if pchar and pprev and pprev.id == GLUE then
+ local pattern = utf8.char(pchar) .. utf8.char(lchar)
+ match = utf8_find(luatypo.double[lang], pattern)
if match then
retflag = true
local msg = "RGX MATCH=" .. pattern
@@ -705,10 +798,9 @@ local check_regexpr = function (glyph, line, colno)
if pprev and pprev.id == GLYPH then
local pchar, id = is_glyph(pprev)
local ppprev = pprev.prev
- if pchar and pchar < 0x100 and
- ppprev and ppprev.id == GLUE then
- local pattern = string.char(pchar) .. string.char(lchar)
- match = string.find(luatypo.double[lang], pattern)
+ if pchar and ppprev and ppprev.id == GLUE then
+ local pattern = utf8.char(pchar) .. utf8.char(lchar)
+ match = utf8_find(luatypo.double[lang], pattern)
if match then
retflag = true
local msg = "REGEXP MATCH=" .. pattern
@@ -776,7 +868,7 @@ local get_pagebody = function (head)
end
end
if not body then
- texio.write_nl('***lua-typo ERROR: PAGE BODY *NOT* FOUND!***')
+ texio.write_nl("***lua-typo ERROR: PAGE BODY *NOT* FOUND!***")
end
return body
end
@@ -800,6 +892,7 @@ check_vtop = function (head, colno, vpos)
local EOLShortWords = luatypo.EOLShortWords
local LastWordMatch = luatypo.LastWordMatch
local FootnoteSplit = luatypo.FootnoteSplit
+ local ShortFinalWord = luatypo.ShortFinalWord
local Stretch = math.max(luatypo.Stretch/100,1)
local blskip = tex.getglue("baselineskip")
local vpos_min = PAGEmin * blskip
@@ -828,6 +921,7 @@ check_vtop = function (head, colno, vpos)
vpos = vpos + head.height + head.depth
local linewd = head.width
local first = head.head
+ local ListItem = false
if footnote then
ftnline = ftnline + 1
line = ftnline
@@ -871,9 +965,10 @@ check_vtop = function (head, colno, vpos)
(first.id == GLUE and first.subtype == LFTSKIP) do
first = first.next
end
- local ListItem = false
if first.id == LPAR then
hyphcount = 0
+ firstwd = ""
+ lastwd = ""
if not footnote then
parline = 1
if body_bottom then
@@ -930,7 +1025,7 @@ check_vtop = function (head, colno, vpos)
if FirstWordMatch then
local flag = not ListItem
firstwd, flag =
- check_first_word(firstwd, first, line, colno, flag)
+ check_line_first_word(firstwd, first, line, colno, flag)
if flag then
pageflag = true
end
@@ -941,46 +1036,46 @@ check_vtop = function (head, colno, vpos)
flag = false
end
lastwd, flag =
- check_last_word(lastwd, pn, line, colno, flag)
+ check_line_last_word(lastwd, pn, line, colno, flag)
if flag then
pageflag = true
end
end
elseif pn and pn.id == DISC then
hyphcount = hyphcount + 1
- if orphanflag and Orphans then
- pageflag = true
- local msg = "ORPHAN"
- log_flaw(msg, line, colno, footnote)
- local COLOR = luatypo.colortbl[5]
- color_line (head, COLOR)
- end
- if ftnsplit and FootnoteSplit then
- pageflag = true
- local msg = "FOOTNOTE SPLIT"
- log_flaw(msg, line, colno, footnote)
- local COLOR = luatypo.colortbl[13]
- color_line (head, COLOR)
- end
- if (page_bottom or body_bottom) and EOPHyphens then
- pageflag = true
- local msg = "LAST WORD SPLIT"
- log_flaw(msg, line, colno, footnote)
- local COLOR = luatypo.colortbl[1]
- local pg = show_pre_disc (pn,COLOR)
- end
+ if orphanflag and Orphans then
+ pageflag = true
+ local msg = "ORPHAN"
+ log_flaw(msg, line, colno, footnote)
+ local COLOR = luatypo.colortbl[5]
+ color_line (head, COLOR)
+ end
+ if ftnsplit and FootnoteSplit then
+ pageflag = true
+ local msg = "FOOTNOTE SPLIT"
+ log_flaw(msg, line, colno, footnote)
+ local COLOR = luatypo.colortbl[13]
+ color_line (head, COLOR)
+ end
+ if (page_bottom or body_bottom) and EOPHyphens then
+ pageflag = true
+ local msg = "LAST WORD SPLIT"
+ log_flaw(msg, line, colno, footnote)
+ local COLOR = luatypo.colortbl[1]
+ local pg = show_pre_disc (pn,COLOR)
+ end
if FirstWordMatch then
local flag = not ListItem
firstwd, flag =
- check_first_word(firstwd, first, line, colno, flag)
+ check_line_first_word(firstwd, first, line, colno, flag)
if flag then
pageflag = true
end
end
if LastWordMatch then
- local flag = false
+ local flag = true
lastwd, flag =
- check_last_word(lastwd, ln, line, colno, true)
+ check_line_last_word(lastwd, ln, line, colno, flag)
if flag then
pageflag = true
end
@@ -1009,32 +1104,32 @@ check_vtop = function (head, colno, vpos)
end
else
hyphcount = 0
- if orphanflag and Orphans then
- pageflag = true
- local msg = "ORPHAN"
- log_flaw(msg, line, colno, footnote)
- local COLOR = luatypo.colortbl[5]
- color_line (head, COLOR)
- end
- if ftnsplit and FootnoteSplit then
- pageflag = true
- local msg = "FOOTNOTE SPLIT"
- log_flaw(msg, line, colno, footnote)
- local COLOR = luatypo.colortbl[13]
- color_line (head, COLOR)
- end
+ if orphanflag and Orphans then
+ pageflag = true
+ local msg = "ORPHAN"
+ log_flaw(msg, line, colno, footnote)
+ local COLOR = luatypo.colortbl[5]
+ color_line (head, COLOR)
+ end
+ if ftnsplit and FootnoteSplit then
+ pageflag = true
+ local msg = "FOOTNOTE SPLIT"
+ log_flaw(msg, line, colno, footnote)
+ local COLOR = luatypo.colortbl[13]
+ color_line (head, COLOR)
+ end
if FirstWordMatch then
local flag = not ListItem
firstwd, flag =
- check_first_word(firstwd, first, line, colno, flag)
+ check_line_first_word(firstwd, first, line, colno, flag)
if flag then
pageflag = true
end
end
if LastWordMatch and pn then
- local flag
+ local flag = true
lastwd, flag =
- check_last_word(lastwd, pn, line, colno, true)
+ check_line_last_word(lastwd, pn, line, colno, flag)
if flag then
pageflag = true
end
@@ -1050,6 +1145,10 @@ check_vtop = function (head, colno, vpos)
end
end
end
+ if ShortFinalWord and pageline == 1 and parline > 1 and
+ check_page_first_word(first,colno) then
+ pageflag = true
+ end
elseif head.id == HLIST and
(head.subtype == EQN or head.subtype == ALIGN) and
(head.height > 0 or head.depth > 0) then
@@ -1209,10 +1308,9 @@ return luatypo.check_page
end
}%
}
-
\InputIfFileExists{lua-typo.cfg}%
- {\PackageInfo{lua-typo.sty}{'lua-typo.cfg' file loaded}}%
- {\PackageInfo{lua-typo.sty}{'lua-typo.cfg' file not found.
+ {\PackageInfo{lua-typo.sty}{"lua-typo.cfg" file loaded}}%
+ {\PackageInfo{lua-typo.sty}{"lua-typo.cfg" file not found.
\MessageBreak Providing default values.}%
\definecolor{LTgrey}{gray}{0.6}%
\definecolor{LTred}{rgb}{1,0.55,0}
@@ -1230,6 +1328,7 @@ return luatypo.check_page
\luatypoSetColor{11}{LTred}% Last word matches
\luatypoSetColor{12}{LTgrey}% Paragraph ending on a nearly full line
\luatypoSetColor{13}{cyan}% Footnote split
+ \luatypoSetColor{14}{red}% Too short first (final) word on the page
\luatypoBackPI=1em\relax
\luatypoBackFuzz=2pt\relax
\ifdim\parindent=0pt \luatypoLLminWD=20pt\relax
@@ -1239,6 +1338,7 @@ return luatypo.check_page
\luatypoPageMin=5\relax
\luatypoMinFull=4\relax
\luatypoMinPART=4\relax
+ \luatypoMinLen=4\relax
}%
%%
%%