summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex')
-rw-r--r--Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkiv72
-rw-r--r--Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkxl72
-rw-r--r--Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control-2022-02-22.sty94
-rw-r--r--Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control.sty262
-rw-r--r--Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.lua390
-rw-r--r--Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.tex9
-rw-r--r--Master/texmf-dist/tex/optex/lua-widow-control/lua-widow-control.opm9
7 files changed, 698 insertions, 210 deletions
diff --git a/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkiv b/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkiv
index 6eff5c9b00c..e24f972d577 100644
--- a/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkiv
+++ b/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkiv
@@ -1,10 +1,10 @@
%D \module
%D [ file=t-lua-widow-control,
-%D version=1.1.6, %%version
+%D version=2.0.0, %%version
%D title=lua-widow-control,
%D subtitle=\ConTeXt module for lua-widow-control,
%D author=Max Chernoff,
-%D date=2022-02-22, %%date
+%D date=2022-03-07, %%dashdate
%D copyright=Max Chernoff,
%D license=MPL-2.0+,
%D url=https://github.com/gucci-on-fleek/lua-widow-control]
@@ -15,9 +15,9 @@
\installcommandhandler \????lwc {lwc} \????lwc
-\newdimen\lwcemergencystretch
+\newdimen\lwc_emergency_stretch
\appendtoks
- \lwcemergencystretch=\lwcparameter{emergencystretch}
+ \lwc_emergency_stretch=\lwcparameter{emergencystretch}
\to\everysetuplwc
\appendtoks
@@ -28,23 +28,49 @@
}
\to\everysetuplwc
+\appendtoks
+ \doifelse{\lwcparameter{debug}}\v!start{
+ \ctxlua{lwc.debug = true}
+ }{
+ \ctxlua{lwc.debug = false}
+ }
+\to\everysetuplwc
+
+\appendtoks
+ \ctxlua{lwc.nobreak_behaviour = "\lwcparameter{nobreak}"}
+\to\everysetuplwc
+
+\newcount\lwc_max_cost
+\appendtoks
+ \lwc_max_cost=\lwcparameter{maxcost}
+\to\everysetuplwc
+
+\appendtoks
+ % We can't just set the penalties because they will be reset automatically
+ % at \\starttext.
+ \startsetups[*default]
+ \clubpenalty=\lwcparameter{orphanpenalty}
+ \widowpenalty=\lwcparameter{widowpenalty}
+ \displaywidowpenalty=\lwcparameter{widowpenalty}
+ \stopsetups
+
+ \setups[*default]
+\to\everysetuplwc
+
\define\iflwc{\ctxlua{lwc.if_lwc_enabled()}}
\ctxloadluafile{lua-widow-control}
-\setuplwc[emergencystretch=3em, \c!state=\v!start]
-
-% We can't just set the penalties because they will be reset automatically
-% at \\starttext.
-\startsetups[*default]
- \clubpenalty=1
- \widowpenalty=1
- \displaywidowpenalty=0
- \interlinepenalty=0
- \brokenpenalty=0
-\stopsetups
+\setuplwc[
+ emergencystretch=3em,
+ \c!state=\v!start,
+ debug=\v!stop,
+ orphanpenalty=1,
+ widowpenalty=1,
+ nobreak=keep,
+ maxcost=2147483647,
+]
-\setups[*default]
% Here, we enable font expansion/contraction. It isn't strictly necessary for
% \lwc/'s functionality; however, it is required for the
@@ -55,23 +81,23 @@
% Expansion of some parts of the document, such as section headings, is quite
% undesirable, so we'll disable \lwc/ for certain commands.
% We should only reenable \lwc/ at the end if it was already enabled.
-\newif\iflwc@should@reenable
+\newif\iflwc_should_reenable
-\define\lwc@patch@pre{%
+\define\lwc_patch_pre{%
\iflwc%
- \lwc@should@reenabletrue%
+ \lwc_should_reenabletrue%
\setuplwc[state=stop]%
\else%
- \lwc@should@reenablefalse
+ \lwc_should_reenablefalse
\fi%
}
-\define\lwc@patch@post{\iflwc@should@reenable%
+\define\lwc_patch_post{\iflwc_should_reenable%
\setuplwc[state=start]%
\fi}
-\prependtoks\lwc@patch@pre\to\everybeforesectionheadhandle % Sectioning
-\prependtoks\lwc@patch@post\to\everyaftersectionheadhandle
+\prependtoks\lwc_patch_pre\to\everybeforesectionheadhandle % Sectioning
+\prependtoks\lwc_patch_post\to\everyaftersectionheadhandle
\protect
\stopmodule
diff --git a/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkxl b/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkxl
index 6eff5c9b00c..e24f972d577 100644
--- a/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkxl
+++ b/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkxl
@@ -1,10 +1,10 @@
%D \module
%D [ file=t-lua-widow-control,
-%D version=1.1.6, %%version
+%D version=2.0.0, %%version
%D title=lua-widow-control,
%D subtitle=\ConTeXt module for lua-widow-control,
%D author=Max Chernoff,
-%D date=2022-02-22, %%date
+%D date=2022-03-07, %%dashdate
%D copyright=Max Chernoff,
%D license=MPL-2.0+,
%D url=https://github.com/gucci-on-fleek/lua-widow-control]
@@ -15,9 +15,9 @@
\installcommandhandler \????lwc {lwc} \????lwc
-\newdimen\lwcemergencystretch
+\newdimen\lwc_emergency_stretch
\appendtoks
- \lwcemergencystretch=\lwcparameter{emergencystretch}
+ \lwc_emergency_stretch=\lwcparameter{emergencystretch}
\to\everysetuplwc
\appendtoks
@@ -28,23 +28,49 @@
}
\to\everysetuplwc
+\appendtoks
+ \doifelse{\lwcparameter{debug}}\v!start{
+ \ctxlua{lwc.debug = true}
+ }{
+ \ctxlua{lwc.debug = false}
+ }
+\to\everysetuplwc
+
+\appendtoks
+ \ctxlua{lwc.nobreak_behaviour = "\lwcparameter{nobreak}"}
+\to\everysetuplwc
+
+\newcount\lwc_max_cost
+\appendtoks
+ \lwc_max_cost=\lwcparameter{maxcost}
+\to\everysetuplwc
+
+\appendtoks
+ % We can't just set the penalties because they will be reset automatically
+ % at \\starttext.
+ \startsetups[*default]
+ \clubpenalty=\lwcparameter{orphanpenalty}
+ \widowpenalty=\lwcparameter{widowpenalty}
+ \displaywidowpenalty=\lwcparameter{widowpenalty}
+ \stopsetups
+
+ \setups[*default]
+\to\everysetuplwc
+
\define\iflwc{\ctxlua{lwc.if_lwc_enabled()}}
\ctxloadluafile{lua-widow-control}
-\setuplwc[emergencystretch=3em, \c!state=\v!start]
-
-% We can't just set the penalties because they will be reset automatically
-% at \\starttext.
-\startsetups[*default]
- \clubpenalty=1
- \widowpenalty=1
- \displaywidowpenalty=0
- \interlinepenalty=0
- \brokenpenalty=0
-\stopsetups
+\setuplwc[
+ emergencystretch=3em,
+ \c!state=\v!start,
+ debug=\v!stop,
+ orphanpenalty=1,
+ widowpenalty=1,
+ nobreak=keep,
+ maxcost=2147483647,
+]
-\setups[*default]
% Here, we enable font expansion/contraction. It isn't strictly necessary for
% \lwc/'s functionality; however, it is required for the
@@ -55,23 +81,23 @@
% Expansion of some parts of the document, such as section headings, is quite
% undesirable, so we'll disable \lwc/ for certain commands.
% We should only reenable \lwc/ at the end if it was already enabled.
-\newif\iflwc@should@reenable
+\newif\iflwc_should_reenable
-\define\lwc@patch@pre{%
+\define\lwc_patch_pre{%
\iflwc%
- \lwc@should@reenabletrue%
+ \lwc_should_reenabletrue%
\setuplwc[state=stop]%
\else%
- \lwc@should@reenablefalse
+ \lwc_should_reenablefalse
\fi%
}
-\define\lwc@patch@post{\iflwc@should@reenable%
+\define\lwc_patch_post{\iflwc_should_reenable%
\setuplwc[state=start]%
\fi}
-\prependtoks\lwc@patch@pre\to\everybeforesectionheadhandle % Sectioning
-\prependtoks\lwc@patch@post\to\everyaftersectionheadhandle
+\prependtoks\lwc_patch_pre\to\everybeforesectionheadhandle % Sectioning
+\prependtoks\lwc_patch_post\to\everyaftersectionheadhandle
\protect
\stopmodule
diff --git a/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control-2022-02-22.sty b/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control-2022-02-22.sty
new file mode 100644
index 00000000000..783db59ed22
--- /dev/null
+++ b/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control-2022-02-22.sty
@@ -0,0 +1,94 @@
+% lua-widow-control
+% https://github.com/gucci-on-fleek/lua-widow-control
+% SPDX-License-Identifier: MPL-2.0+
+% SPDX-FileCopyrightText: 2022 Max Chernoff
+
+\NeedsTeXFormat{LaTeX2e}[2015/01/01] % Formats built after 2015 include \LuaTeX{}Base
+\ProvidesPackage{lua-widow-control}%
+ [2022/02/22 v1.1.6]
+
+\PackageWarning{lua-widow-control}{%
+ Old LaTeX format detected!\MessageBreak\MessageBreak
+ Lua-widow-control prefers a LaTeX format\MessageBreak
+ newer than November 2020. I'll still run\MessageBreak
+ the latest Lua code, but I'm using an older\MessageBreak
+ version of the LaTeX code. This means that\MessageBreak
+ the key-value interface is *UNSUPPORTED*.\MessageBreak
+}
+
+\ifdefined\directlua\else
+ \PackageError{lua-widow-control}{%
+ LuaTeX is required for this package.\MessageBreak
+ Make sure to compile with `lualatex'%
+ }{}
+\fi
+
+\clubpenalty=1
+\widowpenalty=1
+\displaywidowpenalty=1
+
+% We can't use \\newlength since that makes a \TeX{} "skip", not a "dimen"
+\newdimen\lwcemergencystretch
+\lwcemergencystretch=3em
+
+\newcount\lwcmaxcost
+\lwcmaxcost=2147483647
+
+\directlua{require "lua-widow-control"}
+
+% Here, we enable font expansion/contraction. It isn't strictly necessary for
+% \lwc/'s functionality; however, it is required for the
+% lengthened paragraphs to not have terrible spacing.
+\RequirePackage{etoolbox}
+\AtEndPreamble{
+ \@ifpackageloaded{microtype}{}{ % Only load if not already loaded
+ \RequirePackage[
+ final,
+ activate={true,nocompatibility}
+ ]{microtype}
+ }
+}
+
+% Define \TeX{} wrappers for Lua functions
+\newcommand{\lwcenable}{\directlua{lwc.enable_callbacks()}}
+\newcommand{\lwcdisable}{\directlua{lwc.disable_callbacks()}}
+\newcommand{\iflwc}{\directlua{lwc.if_lwc_enabled()}}
+
+% Enable \lwc/ by default when the package is loaded.
+\lwcenable
+
+% Expansion of some parts of the document, such as section headings, is quite
+% undesirable, so we'll disable \lwc/ for certain commands.
+\newcommand{\lwc@patch@warning}[1]{\PackageWarning{lua-widow-control}{%
+ Patching the \protect#1 command failed%
+}}
+
+% We should only reenable \lwc/ at the end if it was already enabled.
+\newif\iflwc@should@reenable
+
+\newcommand{\lwc@patch@pre}{%
+ \iflwc%
+ \lwc@should@reenabletrue%
+ \lwcdisable%
+ \else%
+ \lwc@should@reenablefalse%
+ \fi%
+}
+
+\newcommand{\lwc@patch@post}{%
+ \iflwc@should@reenable%
+ \lwcenable%
+ \fi%
+}
+
+\newcommand{\lwcdisablecmd}[1]{%
+ \ifdefined#1
+ \pretocmd{#1}{\lwc@patch@pre}{}{\lwc@patch@warning{#1}}%
+ \apptocmd{#1}{\lwc@patch@post}{}{\lwc@patch@warning{#1}}%
+ \fi
+}
+
+\lwcdisablecmd{\@sect} % Sectioning
+
+
+\endinput
diff --git a/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control.sty b/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control.sty
index 9ef5a76de56..56462e40d87 100644
--- a/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control.sty
+++ b/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control.sty
@@ -3,82 +3,232 @@
% SPDX-License-Identifier: MPL-2.0+
% SPDX-FileCopyrightText: 2022 Max Chernoff
-\NeedsTeXFormat{LaTeX2e}[2015/01/01] % Formats built after 2015 include \LuaTeX{}Base
-\ProvidesPackage{lua-widow-control}%
- [2022/02/22 v1.1.6] %%version %%date
+% Formats built after 2015 include \LuaTeX{}Base, so this is the absolute
+% minimum version that we will run under.
+\NeedsTeXFormat{LaTeX2e}[2015/01/01]
+
+% For _really_ old formats
+\providecommand\DeclareRelease[3]{}
+\providecommand\DeclareCurrentRelease[2]{}
+
+\DeclareRelease{}{0000-00-00}{lua-widow-control-2022-02-22.sty}
+\DeclareRelease{v1.1.6}{2022-02-22}{lua-widow-control-2022-02-22.sty}
+\DeclareCurrentRelease{v2.0.0}{2022-03-07} %%version %%dashdate
+
+% If this version of LaTeX doesn't support command hooks, then we load
+% the last v1.1.X version of the package.
+\providecommand\IfFormatAtLeastTF{\@ifl@t@r\fmtversion}
+\IfFormatAtLeastTF{2020/10/01}{}{\input{lua-widow-control-2022-02-22.sty}}
+\IfFormatAtLeastTF{2020/10/01}{}{\endinput}
+
+\ProvidesExplPackage
+ {lua-widow-control}
+ {2022/03/07} %%slashdate
+ {v2.0.0} %%version
+ {Use Lua to remove widows and orphans}
+
+% Unconditional Package Loads
+\RequirePackage { l3keys2e }
+
+% Message and String Constants
+\str_const:Nn \c__lwc_name_str { lua-widow-control }
+
+\msg_new:nnn
+ { \c__lwc_name_str }
+ { no-luatex }
+ {
+ LuaTeX~ is~ REQUIRED! \\
+ Make~ sure~ to~ compile~ your~ document~ with~ `lualatex'.
+ }
-\ifdefined\directlua\else
- \PackageError{lua-widow-control}{%
- LuaTeX is required for this package.\MessageBreak
- Make sure to compile with `lualatex'%
- }{}
-\fi
+\msg_new:nnn
+ { \c__lwc_name_str }
+ { patch-failed }
+ {
+ Patching~ \c_backslash_str #1~ failed. \\
+ Please~ ensure~ that~ \c_backslash_str #1~ exists.
+ }
-\clubpenalty=1
-\widowpenalty=1
-\displaywidowpenalty=0
-\interlinepenalty=0
-\brokenpenalty=0
+\msg_new:nnn
+ { \c__lwc_name_str }
+ { old-format-patch }
+ {
+ Patching~ not~ supported~ with~ old~ LaTeX. \\
+ Please~ use~ a~ LaTeX~ format~ >=~ 2021/06/01.
+ }
-% We can't use \\newlength since that makes a \TeX{} "skip", not a "dimen"
-\newdimen\lwcemergencystretch
-\lwcemergencystretch=3em
+\msg_new:nnn
+ { \c__lwc_name_str }
+ { old-command }
+ {
+ \c_backslash_str #1~ has~ been~ REMOVED! \\
+ Please~ use~ \c_backslash_str setuplwc \c_left_brace_str #2
+ \c_right_brace_str\ instead.
+ }
-\directlua{require "lua-widow-control"}
+% Don't let the user proceed unless they are using \LuaTeX{}.
+\sys_if_engine_luatex:F {
+ \msg_critical:nn { \c__lwc_name_str } { no-luatex }
+}
+
+% Define (most of) the keys
+\keys_define:nn { \c__lwc_name_str } {
+ emergencystretch .dim_gset:N = \g__lwc_emergencystretch_dim,
+ emergencystretch .value_required:n = true,
+ emergencystretch .initial:x = \dim_max:nn { 3em } { 30pt },
+
+ max-cost .int_gset:N = \g__lwc_maxcost_int,
+ max-cost .value_required:n = true,
+ max-cost .initial:x = \c_max_int,
+
+ widowpenalty .code:n = \int_gset:Nn \tex_widowpenalty:D { #1 }
+ \int_gset:Nn \tex_displaywidowpenalty:D { #1 },
+ widowpenalty .value_required:n = true,
+ widowpenalty .initial:n = 1,
+
+ orphanpenalty .code:n = \int_gset:Nn \tex_clubpenalty:D { #1 }
+ \int_gset:Nn \@clubpenalty { #1 },
+ orphanpenalty .value_required:n = true,
+ orphanpenalty .initial:n = 1,
+
+ microtype .bool_gset:N = \g__lwc_use_microtype_bool,
+ microtype .value_required:n = true,
+ microtype .initial:n = true,
+ microtype .usage:n = preamble,
+
+ disablecmds .clist_gset:N = \g__lwc_disablecmds_cl,
+ disablecmds .value_required:n = false,
+ disablecmds .initial:n = { \@sect },
+ disablecmds .usage:n = preamble,
+
+ nobreak .choice:,
+ nobreak / keep .code:n = \lua_now:n { lwc.nobreak_behaviour = "keep" },
+ nobreak / split .code:n = \lua_now:n { lwc.nobreak_behaviour = "split" },
+ nobreak / warn .code:n = \lua_now:n { lwc.nobreak_behaviour = "warn" },
+}
+
+% Load the Lua code
+\lua_now:n { require "lua-widow-control" }
% Here, we enable font expansion/contraction. It isn't strictly necessary for
% \lwc/'s functionality; however, it is required for the
-% lengthened paragraphs to not have terrible spacing.
-\RequirePackage{etoolbox}
-\AtEndPreamble{
- \@ifpackageloaded{microtype}{}{ % Only load if not already loaded
- \RequirePackage[
- final,
- activate={true,nocompatibility}
- ]{microtype}
+% lengthened paragraphs to not have terrible spacing.
+\bool_if:NT \g__lwc_use_microtype_bool {
+ \hook_gput_code:nnn { begindocument / before } { \c__lwc_name_str } {
+ \@ifpackageloaded { microtype } {} {
+ \RequirePackage[
+ final,
+ activate = { true, nocompatibility }
+ ]
+ { microtype }
+ }
}
}
-% Define \TeX{} wrappers for Lua functions
-\newcommand{\lwcenable}{\directlua{lwc.enable_callbacks()}}
-\newcommand{\lwcdisable}{\directlua{lwc.disable_callbacks()}}
-\newcommand{\iflwc}{\directlua{lwc.if_lwc_enabled()}}
+% Core Function Definitions
+\cs_new:Npn \__lwc_enable: {
+ \lua_now:n { lwc.enable_callbacks() }
+}
+
+\cs_new:Npn \__lwc_disable: {
+ \lua_now:n { lwc.disable_callbacks() }
+}
-% Enable \lwc/ by default when the package is loaded.
-\lwcenable
+\prg_set_conditional:Nnn \__lwc_if_enabled: { T, F, TF } {
+ \lua_now:n { lwc.if_lwc_enabled() }
+ \prg_return_true:
+ \else
+ \prg_return_false:
+ \fi
+}
% Expansion of some parts of the document, such as section headings, is quite
% undesirable, so we'll disable \lwc/ for certain commands.
-\newcommand{\lwc@patch@warning}[1]{\PackageWarning{lua-widow-control}{%
- Patching the \protect#1 command failed%
-}}
-
-% We should only reenable \lwc/ at the end if it was already enabled.
-\newif\iflwc@should@reenable
-
-\newcommand{\lwc@patch@pre}{%
- \iflwc%
- \lwc@should@reenabletrue%
- \lwcdisable%
- \else%
- \lwc@should@reenablefalse%
- \fi%
+\bool_new:N \g__lwc_should_reenable_bool
+
+\cs_new:Npn \__lwc_patch_cmd:c #1 {
+ \IfFormatAtLeastTF {2021/06/01 } {
+ \hook_gput_code:nnn { cmd / #1 / before } { \c__lwc_name_str } {
+ % We should only reenable \lwc/ at the end if it was already enabled.
+ \__lwc_if_enabled:TF {
+ \bool_gset_true:N \g__lwc_should_reenable_bool
+ \__lwc_disable:
+ } {
+ \bool_gset_false:N \g__lwc_should_reenable_bool
+ }
+ }
+ \hook_gput_code:nnn { cmd / #1 / after } { \c__lwc_name_str } {
+ \bool_if:NT { \g__lwc_should_reenable_bool } {
+ \__lwc_enable:
+ }
+ }
+ } {
+ \msg_warning:nn
+ { \c__lwc_name_str }
+ { old-format-patch }
+ }
}
-\newcommand{\lwc@patch@post}{%
- \iflwc@should@reenable%
- \lwcenable%
- \fi%
+\cs_new:Npn \__lwc_patch_cmd:N #1 {
+ \__lwc_patch_cmd:c { \cs_to_str:N #1 }
}
-\newcommand{\lwcdisablecmd}[1]{%
- \ifdefined#1
- \pretocmd{#1}{\lwc@patch@pre}{}{\lwc@patch@warning{#1}}%
- \apptocmd{#1}{\lwc@patch@post}{}{\lwc@patch@warning{#1}}%
- \fi
+\hook_gput_code:nnn { begindocument / before } { \c__lwc_name_str } {
+ \clist_map_function:NN \g__lwc_disablecmds_cl \__lwc_patch_cmd:N
+}
+
+% Define some final keys
+\keys_define:nn { \c__lwc_name_str } {
+ enable .choice:,
+ enable / true .code:n = \__lwc_enable:,
+ enable / false .code:n = \__lwc_disable:,
+ enable .initial:n = true,
+ enable .default:n = true,
+ enable .value_required:n = false,
+
+ disable .code:n = \__lwc_disable:,
+ disable .value_forbidden:n = true,
+
+ debug .choice:,
+ debug / true .code:n = \lua_now:n { lwc.debug = true },
+ debug / false .code:n = \lua_now:n { lwc.debug = false },
+
+ strict .meta:n = { emergencystretch = 0pt,
+ max-cost = 2500,
+ nobreak = warn,
+ },
+ strict .value_forbidden:n = true,
+
+ default .meta:n = { emergencystretch = 3em,
+ max-cost = \c_max_int,
+ nobreak = keep,
+ },
+ default .value_forbidden:n = true,
}
-\lwcdisablecmd{\@sect} % Sectioning
+% Add the user interface for the keys
+\ProcessKeysPackageOptions{ \c__lwc_name_str }
+
+\NewDocumentCommand \lwcsetup {m} { \keys_set:nn{\c__lwc_name_str}{#1} }
+
+% Legacy Commands
+\NewDocumentCommand \lwcemergencystretch { } {
+ \msg_error:nnnnn
+ { \c__lwc_name_str }
+ { old-command }
+ { lwcemergencystretch }
+ { emergencystretch=XXXpt }
+}
+
+\NewDocumentCommand \lwcdisablecmd { m } {
+ \msg_error:nnxx
+ { \c__lwc_name_str }
+ { old-command }
+ { lwcdisablecmd }
+ { disablecmds={\c_backslash_str aaa,~ \c_backslash_str bbb} }
+}
+\cs_new_eq:NN \lwcenable \__lwc_enable:
+\cs_new_eq:NN \lwcdisable \__lwc_disable:
\endinput
diff --git a/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.lua b/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.lua
index f1ecb54c65f..5801feef129 100644
--- a/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.lua
+++ b/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.lua
@@ -5,8 +5,24 @@
SPDX-FileCopyrightText: 2022 Max Chernoff
]]
-lwc = {}
+lwc = lwc or {}
lwc.name = "lua-widow-control"
+lwc.nobreak_behaviour = "keep"
+
+local write_nl = texio.write_nl
+local string_rep = string.rep
+local function debug_print(title, text)
+ if not lwc.debug then return end
+
+ local filler = 15 - #title
+
+ if text then
+ write_nl("log", "LWC (" .. title .. string_rep(" ", filler) .. "): " .. text)
+ else
+ write_nl("log", "LWC: " .. string_rep(" ", 18) .. title)
+ end
+end
+
--[[
\lwc/ is intended to be format-agonistic. It only runs on Lua\TeX{},
@@ -37,70 +53,90 @@ local last = node.slide
local copy = node.copy_list
local par_id = node.id("par") or node.id("local_par")
local glue_id = node.id("glue")
-local set_attribute = node.set_attribute
-local has_attribute = node.has_attribute
+local glyph_id = node.id("glyph")
+local penalty_id = node.id("penalty")
+local hlist_id = node.id("hlist")
+local traverse = node.traverse
+local set_attribute = node.set_attribute or node.setattribute
+local find_attribute = node.find_attribute or node.findattribute
local flush_list = node.flush_list or node.flushlist
local free = node.free
-local min_col_width = tex.sp("25em")
-local maxdimen = 1073741823 -- \\maxdimen in sp
+local min_col_width = tex.sp("250pt")
--[[
Package/module initialization
]]
-local warning, info, attribute, contrib_head, stretch_order, pagenum
-
-if context and lmtx then
- warning = logs.reporter("module", lwc.name)
- info = logs.reporter("module", lwc.name)
- attribute = attributes.public(lwc.name)
- contrib_head = 'contributehead' -- For \LuaMetaTeX{}
+local warning,
+ info,
+ attribute,
+ contrib_head,
+ stretch_order,
+ pagenum,
+ emergencystretch,
+ max_cost
+
+if lmtx then
+ debug_print("LMTX")
+ contrib_head = 'contributehead'
stretch_order = "stretchorder"
- pagenum = function() return tex.count["realpageno"] end
-elseif context and not lmtx then
+else
+ contrib_head = 'contrib_head'
+ stretch_order = "stretch_order"
+end
+
+if context then
+ debug_print("ConTeXt")
warning = logs.reporter("module", lwc.name)
info = logs.reporter("module", lwc.name)
attribute = attributes.public(lwc.name)
- contrib_head = 'contrib_head'
- stretch_order = "stretch_order"
pagenum = function() return tex.count["realpageno"] end
-elseif plain or latex then
- luatexbase.provides_module {
- name = lwc.name,
- date = "2022/02/22", --%%date
- version = "1.1.6", --%%version
- description = [[
-
- This module provides a LuaTeX-based solution to prevent
- widows and orphans from appearing in a document. It does
- so by increasing or decreasing the lengths of previous
- paragraphs.
- ]],
- }
- warning = function(str) luatexbase.module_warning(lwc.name, str) end
- info = function(str) luatexbase.module_info(lwc.name, str) end
- attribute = luatexbase.new_attribute(lwc.name)
- contrib_head = 'contrib_head' -- For \LuaTeX{}
- stretch_order = "stretch_order"
- pagenum = function() return tex.count[0] end
-elseif optex then
- local write_nl = texio.write_nl
- warning = function(str) write_nl(lwc.name .. " Warning: " .. str) end
- info = function(str) write_nl("log", lwc.name .. " Info: " .. str) end
- attribute = alloc.new_attribute(lwc.name)
- contrib_head = 'contrib_head'
- stretch_order = "stretch_order"
+ emergencystretch = "lwc_emergency_stretch"
+ max_cost = "lwc_max_cost"
+elseif plain or latex or optex then
pagenum = function() return tex.count[0] end
+
+ if tex.isdimen("g__lwc_emergencystretch_dim") then
+ emergencystretch = "g__lwc_emergencystretch_dim"
+ max_cost = "g__lwc_maxcost_int"
+ else
+ emergencystretch = "lwcemergencystretch"
+ max_cost = "lwcmaxcost"
+ end
+
+ if plain or latex then
+ debug_print("Plain/LaTeX")
+ luatexbase.provides_module {
+ name = lwc.name,
+ date = "2022/03/07", --%%slashdate
+ version = "2.0.0", --%%version
+ description = [[
+
+This module provides a LuaTeX-based solution to prevent
+widows and orphans from appearing in a document. It does
+so by increasing or decreasing the lengths of previous
+paragraphs.]],
+ }
+ warning = function(str) luatexbase.module_warning(lwc.name, str) end
+ info = function(str) luatexbase.module_info(lwc.name, str) end
+ attribute = luatexbase.new_attribute(lwc.name)
+ elseif optex then
+ debug_print("OpTeX")
+ warning = function(str) write_nl(lwc.name .. " Warning: " .. str) end
+ info = function(str) write_nl("log", lwc.name .. " Info: " .. str) end
+ attribute = alloc.new_attribute(lwc.name)
+ end
else -- uh oh
- error [[
- Unsupported format.
+ error [[Unsupported format.
- Please use (Lua)LaTeX, Plain (Lua)TeX, ConTeXt (MKXL/LMTX),
- or OpTeX.
- ]]
+Please use LaTeX, Plain TeX, ConTeXt or OpTeX.]]
end
local paragraphs = {} -- List to hold the alternate paragraph versions
+local function get_location()
+ return "At " .. pagenum() .. "/" .. #paragraphs
+end
+
--[[
Function definitions
@@ -165,11 +201,39 @@ local function register_callback(t)
end
end
+local function get_chars(head)
+ if not lwc.debug then return end
+
+ local chars = ""
+ for n in traverse(head) do
+ if n.id == glyph_id then
+ if n.char < 127 then
+ chars = chars .. string.char(n.char)
+ else
+ chars = chars .. "#"
+ end
+ elseif n.id == glue_id then
+ chars = chars .. " "
+ end
+ if #chars > 25 then
+ break
+ end
+ end
+
+ debug_print(get_location(), chars)
+end
+
+
+function lwc.paragraph_cost(demerits, lines)
+ return demerits / (2 * math.sqrt(lines))
+end
+
+
--- Saves each paragraph, but lengthened by 1 line
function lwc.save_paragraphs(head)
-- Prevent the "underfull hbox" warnings when we store a potential paragraph
local renable_box_warnings
- if (latex or plain) and
+ if (context or optex) or
#luatexbase.callback_descriptions("hpack_quality") == 0
then -- See #18 and michal-h21/linebreaker#3
renable_box_warnings = true
@@ -194,7 +258,7 @@ function lwc.save_paragraphs(head)
-- Break the paragraph 1 line longer than natural
local long_node, long_info = tex.linebreak(new_head, {
looseness = 1,
- emergencystretch = tex.dimen.lwcemergencystretch,
+ emergencystretch = tex.getdimen(emergencystretch),
})
-- Break the natural paragraph so we know how long it was
@@ -205,20 +269,31 @@ function lwc.save_paragraphs(head)
lwc.callbacks.disable_box_warnings.disable()
end
- -- If we can't lengthen the paragraph, assign a \emph{very} large demerit value
- local long_demerits
- if long_info.prevgraf == natural_info.prevgraf then
- long_demerits = maxdimen
- else
- long_demerits = long_info.demerits
- end
-
-- Offset the accumulated \\prevdepth
local prevdepth = node.new("glue")
prevdepth.width = natural_info.prevdepth - long_info.prevdepth
last(long_node).next = prevdepth
- table.insert(paragraphs, { demerits = long_demerits, node = long_node })
+ if long_info.prevgraf == natural_info.prevgraf + 1 then
+ table.insert(paragraphs, {
+ cost = lwc.paragraph_cost(long_info.demerits, long_info.prevgraf),
+ node = long_node
+ })
+ end
+
+ get_chars(head)
+ debug_print(get_location(), "nat lines " .. natural_info.prevgraf)
+ debug_print(
+ get_location(),
+ "nat cost " ..
+ lwc.paragraph_cost(natural_info.demerits, natural_info.prevgraf)
+ )
+ debug_print(get_location(), "long lines " .. long_info.prevgraf)
+ debug_print(
+ get_location(),
+ "long cost " ..
+ lwc.paragraph_cost(long_info.demerits, long_info.prevgraf)
+ )
-- \LuaMetaTeX{} crashes if we return `true`
return head
@@ -251,11 +326,12 @@ local function safe_last(head)
if ids[id] then
warning [[Circular node list detected!
-This should never happen. I'll try and recover, but your output may be
-corrupted. As a workaround, disable lua-widow-control for the
-affected paragraph or change the page breaks in your document.]]
-
+This should never happen. I'll try and
+recover, but your output may be corrupted.
+(Internal Error)]]
prev.next = nil
+ debug_print("safe_last", node.type(head.id) .. " " .. node.type(prev.id))
+
return prev
end
@@ -276,12 +352,16 @@ end
--- replace one paragraph with the same paragraph, but lengthened by one line.
--- Then, we can push the bottom line of the page to the next page.
function lwc.remove_widows(head)
+ local head_save = head -- Save the start of the `head` linked-list
+
local penalty = tex.outputpenalty - tex.interlinepenalty
local widowpenalty = tex.widowpenalty
local clubpenalty = tex.clubpenalty
local displaywidowpenalty = tex.displaywidowpenalty
local brokenpenalty = tex.brokenpenalty
+ debug_print("outputpenalty", tex.outputpenalty .. " " .. #paragraphs)
+
--[[
We only need to process pages that have orphans or widows. If `paragraphs`
is empty, then there is nothing that we can do.
@@ -289,7 +369,9 @@ function lwc.remove_widows(head)
The list of penalties is from:
https://tug.org/TUGboat/tb39-3/tb123mitt-widows-code.pdf#subsection.0.2.1
]]
- if (penalty == widowpenalty or
+ if penalty ~= 0 and
+ penalty < 10000 and
+ (penalty == widowpenalty or
penalty == displaywidowpenalty or
penalty == clubpenalty or
penalty == clubpenalty + widowpenalty or
@@ -302,28 +384,26 @@ function lwc.remove_widows(head)
penalty == brokenpenalty + clubpenalty + displaywidowpenalty) and
#paragraphs >= 1 then
else
+ paragraphs = {}
return head
end
info("Widow/orphan detected. Attempting to remove.")
- local head_save = head -- Save the start of the `head` linked-list
-
--[[
- Find the paragraph on the page with the minimum penalty.
-
- This would be a 1-liner in Python or JavaScript, but Lua is pretty low-level,
- so there's quite a bit of code here.
+ Find the paragraph on the page with the least cost.
]]
local paragraph_index = 1
- local minimum_demerits = paragraphs[paragraph_index].demerits
+ local best_cost = paragraphs[paragraph_index].cost
-- We find the current "best" replacement, then free the unused ones
for i, paragraph in pairs(paragraphs) do
- if paragraph.demerits < minimum_demerits and i <= #paragraphs - 1 then
+ if paragraph.cost < best_cost and i <= #paragraphs - 1 then
+ -- Clear the old best paragraph
flush_list(paragraphs[paragraph_index].node)
paragraphs[paragraph_index].node = nil
- paragraph_index, minimum_demerits = i, paragraph.demerits
+ -- Set the new best paragraph
+ paragraph_index, best_cost = i, paragraph.cost
elseif i > 1 then
-- Not sure why `i > 1` is required?
flush_list(paragraph.node)
@@ -331,50 +411,113 @@ function lwc.remove_widows(head)
end
end
+ debug_print(
+ "selected para",
+ pagenum() ..
+ "/" ..
+ paragraph_index ..
+ " (" ..
+ best_cost ..
+ ")"
+ )
+
+ if best_cost > tex.getcount(max_cost) then
+ -- If the best replacement is too bad, we can't do anything
+ warning("Widow/Orphan NOT removed on page " .. pagenum())
+ paragraphs = {}
+ return head_save
+ end
+
local target_node = paragraphs[paragraph_index].node
- local clear_flag = false
- -- Loop through all of the nodes on the page
+ -- Start of final paragraph
+ debug_print("remove_widows", "moving last line")
+
+ head = last(head_save).prev
+ local big_penalty_found, last_line, hlist_head
+ while head do
+ if head.id == glue_id then
+ -- Ignore any glue nodes
+ elseif head.id == penalty_id and head.penalty >= 10000 then
+ -- Infinite break penalty
+ big_penalty_found = true
+ elseif big_penalty_found and head.id == hlist_id then
+ -- Line before the penalty
+ if lwc.nobreak_behaviour == "keep" then
+ hlist_head = head
+ big_penalty_found = false
+ elseif lwc.nobreak_behaviour == "split" then
+ head = last(head_save)
+ break
+ elseif lwc.nobreak_behaviour == "warn" then
+ warning("Widow/Orphan NOT removed on page " .. pagenum())
+ paragraphs = {}
+ return head_save
+ end
+ else
+ -- Not found
+ if hlist_head then
+ head = hlist_head
+ else
+ head = last(head_save)
+ end
+ break
+ end
+ head = head.prev
+ end
+
+ last_line = copy(head)
+ last(last_line).next = copy(tex.lists[contrib_head])
+
+ head.prev.prev.next = nil
+ -- Move the last line to the next page
+ tex.lists[contrib_head] = last_line
+
+ local free_next_nodes = false
+
+ -- Loop through all of the nodes on the page with the lwc attribute
+ head = head_save
while head do
+ local value
+ value, head = find_attribute(head, attribute)
+
+ if not head then
+ break
+ end
+
+ debug_print("remove_widows", "found " .. value)
+
-- Insert the start of the replacement paragraph
- if has_attribute(head, attribute, paragraph_index) then
+ if value == paragraph_index then
+ debug_print("remove_widows", "replacement start")
safe_last(target_node) -- Remove any loops
head.prev.next = target_node
- clear_flag = true
+ free_next_nodes = true
end
-- Insert the end of the replacement paragraph
- if has_attribute(head, attribute, -1 * paragraph_index) then
+ if value == -1 * paragraph_index then
+ debug_print("remove_widows", "replacement end")
safe_last(target_node).next = head.next
- clear_flag = false
+ break
end
- -- Start of final paragraph
- if has_attribute(head, attribute, #paragraphs) then
- local last_line = copy(last(head))
-
- last(last_line).next = copy(tex.lists[contrib_head])
-
- last(head).prev.prev.next = nil
- -- Move the last line to the next page
- tex.lists[contrib_head] = last_line
- info(
- "Widow/orphan successfully removed at paragraph "
- .. paragraph_index
- .. " on page "
- .. pagenum()
- .. "."
- )
- end
-
- if clear_flag then
+ if free_next_nodes then
head = free(head)
else
head = head.next
end
end
+ info(
+ "Widow/orphan successfully removed at paragraph "
+ .. paragraph_index
+ .. " on page "
+ .. pagenum()
+ .. "."
+ )
+
paragraphs = {} -- Clear paragraphs array at the end of the page
return head_save
@@ -413,18 +556,19 @@ lwc.callbacks = {
local enabled = false
function lwc.enable_callbacks()
+ debug_print("callbacks", "enabling")
if not enabled then
- lwc.callbacks.remove_widows.enable()
lwc.callbacks.save_paragraphs.enable()
lwc.callbacks.mark_paragraphs.enable()
enabled = true
else
- warning("Already enabled")
+ info("Already enabled")
end
end
function lwc.disable_callbacks()
+ debug_print("callbacks", "disabling")
if enabled then
lwc.callbacks.save_paragraphs.disable()
lwc.callbacks.mark_paragraphs.disable()
@@ -436,11 +580,12 @@ function lwc.disable_callbacks()
enabled = false
else
- warning("Already disabled")
+ info("Already disabled")
end
end
function lwc.if_lwc_enabled()
+ debug_print("iflwc")
if enabled then
tex.sprint("\\iftrue")
else
@@ -448,4 +593,49 @@ function lwc.if_lwc_enabled()
end
end
+--- Silence the luatexbase "Enabling/Removing <callback>" info messages
+---
+--- Every time that a paragraph is typeset, \lwc/ hooks in
+--- and typesets the paragraph 1 line longer. Some of these longer paragraphs
+--- will have pretty bad badness values, so TeX will issue an over/underfull
+--- hbox warning. To block these warnings, we hook into the `hpack_quality`
+--- callback and disable it so that no warning is generated.
+---
+--- However, each time that we enable/disable the null `hpack_quality` callback,
+--- luatexbase puts an info message in the log. This completely fills the log file
+--- with useless error messages, so we disable it here.
+---
+--- This uses the Lua `debug` library to internally modify the log upvalue in the
+--- `add_to_callback` function. This is almost certainly a terrible idea, but I don't
+--- know of a better way.
+local function silence_luatexbase()
+ local nups = debug.getinfo(luatexbase.add_to_callback).nups
+
+ for x = 1, nups do
+ local name, func = debug.getupvalue(luatexbase.add_to_callback, x)
+ if name == "luatexbase_log" then
+ debug.setupvalue(
+ luatexbase.add_to_callback,
+ x,
+ function(text)
+ if text:match("^Inserting") or text:match("^Removing") then
+ return
+ else
+ func(text)
+ end
+ end
+ )
+ return
+ end
+ end
+end
+
+
+-- Activate \lwc/
+if plain or latex then
+ silence_luatexbase()
+end
+
+lwc.callbacks.remove_widows.enable()
+
return lwc
diff --git a/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.tex b/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.tex
index d83e6114f4f..7a75e52132f 100644
--- a/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.tex
+++ b/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.tex
@@ -3,7 +3,7 @@
% SPDX-License-Identifier: MPL-2.0+
% SPDX-FileCopyrightText: 2022 Max Chernoff
-\wlog{lua-widow-control v1.1.6} %%version
+\wlog{lua-widow-control v2.0.0} %%version
\ifx\directlua\undefined
\errmessage{%
@@ -16,13 +16,14 @@
\clubpenalty=1
\widowpenalty=1
-\displaywidowpenalty=0
-\interlinepenalty=0
-\brokenpenalty=0
+\displaywidowpenalty=1
\newdimen\lwcemergencystretch
\lwcemergencystretch=3em
+\newcount\lwcmaxcost
+\lwcmaxcost=2147483647
+
\directlua{require "lua-widow-control"}
% Here, we enable font expansion/contraction. It isn't strictly necessary for
diff --git a/Master/texmf-dist/tex/optex/lua-widow-control/lua-widow-control.opm b/Master/texmf-dist/tex/optex/lua-widow-control/lua-widow-control.opm
index 4b8837cfec9..992d817a5c8 100644
--- a/Master/texmf-dist/tex/optex/lua-widow-control/lua-widow-control.opm
+++ b/Master/texmf-dist/tex/optex/lua-widow-control/lua-widow-control.opm
@@ -3,17 +3,18 @@
% SPDX-License-Identifier: MPL-2.0+
% SPDX-FileCopyrightText: 2022 Max Chernoff
-\_codedecl\lwcenable{lua-widow-control <v1.1.6>} %%version
+\_codedecl\lwcenable{lua-widow-control <v2.0.0>} %%version
\_clubpenalty=1
\_widowpenalty=1
-\_displaywidowpenalty=0
-\_interlinepenalty=0
-\_brokenpenalty=0
+\_displaywidowpenalty=1
\_newdimen\lwcemergencystretch
\lwcemergencystretch=3em
+\_newcount\lwcmaxcost
+\lwcmaxcost=2147483647
+
\_directlua{require "lua-widow-control"}
% Define \TeX{} wrappers for Lua functions