texlive[63302] Master/texmf-dist: lua-widow-control (14may22)

commits+karl at tug.org commits+karl at tug.org
Sat May 14 22:33:11 CEST 2022


Revision: 63302
          http://tug.org/svn/texlive?view=revision&revision=63302
Author:   karl
Date:     2022-05-14 22:33:11 +0200 (Sat, 14 May 2022)
Log Message:
-----------
lua-widow-control (14may22)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/luatex/lua-widow-control/README.md
    trunk/Master/texmf-dist/doc/luatex/lua-widow-control/lua-widow-control.pdf
    trunk/Master/texmf-dist/source/luatex/lua-widow-control/lwc-documentation.tex
    trunk/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkiv
    trunk/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkxl
    trunk/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control-2022-02-22.sty
    trunk/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control.sty
    trunk/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.lua
    trunk/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.tex
    trunk/Master/texmf-dist/tex/optex/lua-widow-control/lua-widow-control.opm

Modified: trunk/Master/texmf-dist/doc/luatex/lua-widow-control/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/lua-widow-control/README.md	2022-05-14 20:32:55 UTC (rev 63301)
+++ trunk/Master/texmf-dist/doc/luatex/lua-widow-control/README.md	2022-05-14 20:33:11 UTC (rev 63302)
@@ -48,4 +48,4 @@
 Please note that a compiled document is absolutely **not** considered to be an "Executable Form" as defined by the MPL. The use of lua-widow-control in a document does not place **any** obligations on the document's author or distributors. The MPL and CC-BY-SA licenses **only** apply to you if you distribute the lua-widow-control source code or documentation.
 
 ---
-_v2.0.6 (2022-04-23)_ <!--%%version %%dashdate-->
+_v2.1.0 (2022-05-14)_ <!--%%version %%dashdate-->

Modified: trunk/Master/texmf-dist/doc/luatex/lua-widow-control/lua-widow-control.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/luatex/lua-widow-control/lwc-documentation.tex
===================================================================
--- trunk/Master/texmf-dist/source/luatex/lua-widow-control/lwc-documentation.tex	2022-05-14 20:32:55 UTC (rev 63301)
+++ trunk/Master/texmf-dist/source/luatex/lua-widow-control/lwc-documentation.tex	2022-05-14 20:33:11 UTC (rev 63302)
@@ -5,7 +5,10 @@
 % SPDX-License-Identifier: MPL-2.0+ OR CC-BY-SA-4.0+
 % SPDX-FileCopyrightText: 2022 Max Chernoff
 
-% Warning: Compiles slowly
+\doifnot{\contextmark}{LMTX}{
+    \errhelp{LMTX/MkXL is required to compile this file.}
+    \errmessage{Fatal error, exiting.}
+}
 
 \environment lwc-documentation
 
@@ -37,7 +40,7 @@
 \startdocument[
     title=lua-widow-control,
     author=Max Chernoff,
-    version=2.0.6, %%version
+    version=2.1.0, %%version
     github=https://github.com/gucci-on-fleek/lua-widow-control,
     ctan=https://www.ctan.org/pkg/lua-widow-control,
 ]
@@ -316,7 +319,7 @@
 
 \startTABLE
     \NC \plainop/
-    \NC \inlineTEX{\lwcdisablecmd{$\meta{\backslash macro}$}}
+    \NC \inlineTEX{\lwcdisablecmd $\meta{\backslash macro}$}
     \NC\NR
     \NC \LaTeX{}
     \NC \inlineTEX{\lwcsetup{disablecmds = {$\meta{macronameone}$, $\meta{macronametwo}$}}}
@@ -363,7 +366,7 @@
 
 \startTABLE
     \NC \plainop/
-    \NC\inlineTEX{\directlua{lwc.nobreak_behaviour = "$\meta{value}$"}}
+    \NC\inlineTEX{\lwcnobreak{$\meta{value}$}}
     \NC\NR
     \NC \LaTeX{}
     \NC\inlineTEX{\lwcsetup{nobreak = $\meta{value}$}}
@@ -409,8 +412,8 @@
 
 \startTABLE
     \NC \plainop/
-    \NC\inlineTEX{\directlua{lwc.debug = true}}
-    \NC\NR\NC\NC\inlineTEX{\directlua{lwc.debug = false}}
+    \NC\inlineTEX{\lwcdebug 1}
+    \NC\NR\NC\NC\inlineTEX{\lwcdebug 0}
     \NC\NR
     \NC \LaTeX{}
     \NC\inlineTEX{\lwcsetup{debug = true}}

Modified: trunk/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkiv
===================================================================
--- trunk/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkiv	2022-05-14 20:32:55 UTC (rev 63301)
+++ trunk/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkiv	2022-05-14 20:33:11 UTC (rev 63302)
@@ -1,10 +1,10 @@
 %D \module
 %D   [     file=t-lua-widow-control,
-%D      version=2.0.6, %%version
+%D      version=2.1.0, %%version
 %D        title=lua-widow-control,
 %D     subtitle=\ConTeXt module for lua-widow-control,
 %D       author=Max Chernoff,
-%D         date=2022-04-23, %%dashdate
+%D         date=2022-05-14, %%dashdate
 %D    copyright=Max Chernoff,
 %D      license=MPL-2.0+,
 %D          url=https://github.com/gucci-on-fleek/lua-widow-control]
@@ -16,39 +16,27 @@
 \installcommandhandler \????lwc {lwc} \????lwc
 
 \newdimen\lwc_emergency_stretch
+\newcount\lwc_max_cost
 \appendtoks
     \lwc_emergency_stretch=\lwcparameter{emergencystretch}
-\to\everysetuplwc
 
-\appendtoks
     \doifelse{\lwcparameter{\c!state}}\v!start{
-        \ctxlua{lwc.enable_callbacks()}
+        \lwc_enable
     }{
-        \ctxlua{lwc.disable_callbacks()}
+        \lwc_disable
     }
-\to\everysetuplwc
 
-\appendtoks
-    \doifelse{\lwcparameter{debug}}\v!start{
-        \ctxlua{lwc.debug = true}
-    }{
-        \ctxlua{lwc.debug = false}
-    }
-\to\everysetuplwc
+    \lwc_debug{\lwcparameter{debug}}
 
-\appendtoks
-    \ctxlua{lwc.nobreak_behaviour = "\lwcparameter{nobreak}"}
-\to\everysetuplwc
+    \lwc_nobreak{\lwcparameter{nobreak}}
 
-\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]
+        \directsetup{*reset}
+
         \clubpenalty=\lwcparameter{orphanpenalty}
         \widowpenalty=\lwcparameter{widowpenalty}
         \displaywidowpenalty=\lwcparameter{widowpenalty}
@@ -55,11 +43,18 @@
         \brokenpenalty=\lwcparameter{brokenpenalty}
     \stopsetups
 
+    \startsetups[grid][*default]
+        \directsetup{*reset}
+
+        \clubpenalty=\lwcparameter{orphanpenalty}
+        \widowpenalty=\lwcparameter{widowpenalty}
+        \displaywidowpenalty=\lwcparameter{widowpenalty}
+        \brokenpenalty=\lwcparameter{brokenpenalty}
+    \stopsetups
+
     \setups[*default]
 \to\everysetuplwc
 
-\define\iflwc{\ctxlua{lwc.if_lwc_enabled()}}
-
 \ctxloadluafile{lua-widow-control}
 
 \setuplwc[
@@ -86,7 +81,7 @@
 \newcount\lwc_disable_count
 
 \define\lwc_patch_pre{%
-    \iflwc%
+    \lwc_if_enabled%
         \advance\lwc_disable_count by 1%
         \setuplwc[\c!state=\v!stop]%
     \fi%
@@ -93,7 +88,7 @@
 }
 
 \define\lwc_patch_post{
-    \ifnum\lwc_disable_count>0%
+    \ifnum\lwc_disable_count>0\relax%
         \setuplwc[\c!state=\v!start]%
         \advance\lwc_disable_count by -1%
     \fi%
@@ -102,5 +97,8 @@
 \prependtoks\lwc_patch_pre\to\everybeforesectionheadhandle % Sectioning
 \prependtoks\lwc_patch_post\to\everyaftersectionheadhandle
 
+% Make the commands public
+\let\iflwc=\lwc_if_enabled
+
 \protect
 \stopmodule

Modified: trunk/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkxl
===================================================================
--- trunk/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkxl	2022-05-14 20:32:55 UTC (rev 63301)
+++ trunk/Master/texmf-dist/tex/context/third/lua-widow-control/t-lua-widow-control.mkxl	2022-05-14 20:33:11 UTC (rev 63302)
@@ -1,10 +1,10 @@
 %D \module
 %D   [     file=t-lua-widow-control,
-%D      version=2.0.6, %%version
+%D      version=2.1.0, %%version
 %D        title=lua-widow-control,
 %D     subtitle=\ConTeXt module for lua-widow-control,
 %D       author=Max Chernoff,
-%D         date=2022-04-23, %%dashdate
+%D         date=2022-05-14, %%dashdate
 %D    copyright=Max Chernoff,
 %D      license=MPL-2.0+,
 %D          url=https://github.com/gucci-on-fleek/lua-widow-control]
@@ -16,39 +16,27 @@
 \installcommandhandler \????lwc {lwc} \????lwc
 
 \newdimen\lwc_emergency_stretch
+\newcount\lwc_max_cost
 \appendtoks
     \lwc_emergency_stretch=\lwcparameter{emergencystretch}
-\to\everysetuplwc
 
-\appendtoks
     \doifelse{\lwcparameter{\c!state}}\v!start{
-        \ctxlua{lwc.enable_callbacks()}
+        \lwc_enable
     }{
-        \ctxlua{lwc.disable_callbacks()}
+        \lwc_disable
     }
-\to\everysetuplwc
 
-\appendtoks
-    \doifelse{\lwcparameter{debug}}\v!start{
-        \ctxlua{lwc.debug = true}
-    }{
-        \ctxlua{lwc.debug = false}
-    }
-\to\everysetuplwc
+    \lwc_debug{\lwcparameter{debug}}
 
-\appendtoks
-    \ctxlua{lwc.nobreak_behaviour = "\lwcparameter{nobreak}"}
-\to\everysetuplwc
+    \lwc_nobreak{\lwcparameter{nobreak}}
 
-\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]
+        \directsetup{*reset}
+
         \clubpenalty=\lwcparameter{orphanpenalty}
         \widowpenalty=\lwcparameter{widowpenalty}
         \displaywidowpenalty=\lwcparameter{widowpenalty}
@@ -55,11 +43,18 @@
         \brokenpenalty=\lwcparameter{brokenpenalty}
     \stopsetups
 
+    \startsetups[grid][*default]
+        \directsetup{*reset}
+
+        \clubpenalty=\lwcparameter{orphanpenalty}
+        \widowpenalty=\lwcparameter{widowpenalty}
+        \displaywidowpenalty=\lwcparameter{widowpenalty}
+        \brokenpenalty=\lwcparameter{brokenpenalty}
+    \stopsetups
+
     \setups[*default]
 \to\everysetuplwc
 
-\define\iflwc{\ctxlua{lwc.if_lwc_enabled()}}
-
 \ctxloadluafile{lua-widow-control}
 
 \setuplwc[
@@ -86,7 +81,7 @@
 \newcount\lwc_disable_count
 
 \define\lwc_patch_pre{%
-    \iflwc%
+    \lwc_if_enabled%
         \advance\lwc_disable_count by 1%
         \setuplwc[\c!state=\v!stop]%
     \fi%
@@ -93,7 +88,7 @@
 }
 
 \define\lwc_patch_post{
-    \ifnum\lwc_disable_count>0%
+    \ifnum\lwc_disable_count>0\relax%
         \setuplwc[\c!state=\v!start]%
         \advance\lwc_disable_count by -1%
     \fi%
@@ -102,5 +97,8 @@
 \prependtoks\lwc_patch_pre\to\everybeforesectionheadhandle % Sectioning
 \prependtoks\lwc_patch_post\to\everyaftersectionheadhandle
 
+% Make the commands public
+\let\iflwc=\lwc_if_enabled
+
 \protect
 \stopmodule

Modified: trunk/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control-2022-02-22.sty
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control-2022-02-22.sty	2022-05-14 20:32:55 UTC (rev 63301)
+++ trunk/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control-2022-02-22.sty	2022-05-14 20:33:11 UTC (rev 63302)
@@ -7,6 +7,15 @@
 \ProvidesPackage{lua-widow-control}%
     [2022/02/22 v1.1.6]
 
+% The version number above is somewhat-misleading: I will make bugfixes to this file
+% from time to time, but the core of the file will not change. Therefore, we should
+% report a real version number here for debugging.
+\PackageInfo{lua-widow-control}{%
+    Real version:
+    2022/05/14 %%dashdate
+    v2.1.0 %%version
+}
+
 \PackageWarning{lua-widow-control}{%
     Old LaTeX format detected!\MessageBreak\MessageBreak
     Lua-widow-control prefers a LaTeX format\MessageBreak

Modified: trunk/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control.sty
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control.sty	2022-05-14 20:32:55 UTC (rev 63301)
+++ trunk/Master/texmf-dist/tex/lualatex/lua-widow-control/lua-widow-control.sty	2022-05-14 20:33:11 UTC (rev 63302)
@@ -13,7 +13,7 @@
 
 \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.6}{2022-04-23} %%version %%dashdate
+\DeclareCurrentRelease{v2.1.0}{2022-05-14} %%version %%dashdate
 
 % If this version of LaTeX doesn't support command hooks, then we load
 % the last v1.1.X version of the package.
@@ -23,8 +23,8 @@
 
 \ProvidesExplPackage
     {lua-widow-control}
-    {2022/04/23} %%slashdate
-    {v2.0.6} %%version
+    {2022/05/14} %%dashdate
+    {v2.1.0} %%version
     {Use Lua to remove widows and orphans}
 
 % Unconditional Package Loads
@@ -105,6 +105,7 @@
     disablecmds .clist_gset:N     = \g__lwc_disablecmds_cl,
     disablecmds .value_required:n = false,
     disablecmds .initial:n        = { \@sect,           % LaTeX default
+                                      \@ssect,          % LaTeX starred
                                       \M at sect,          % Memoir
                                       \@mem at old@ssect,  % Memoir Starred
                                       \ttl at straight@ii, % titlesec normal
@@ -112,11 +113,6 @@
                                       \ttl at part@ii,     % titlesec part
                                     },
     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
@@ -138,16 +134,10 @@
 }
 
 % Core Function Definitions
-\cs_new:Npn \__lwc_enable: {
-    \lua_now:n { lwc.enable_callbacks() }
-}
+\cs_new_eq:NN \iflwc \__lwc_iflwc:
 
-\cs_new:Npn \__lwc_disable: {
-    \lua_now:n { lwc.disable_callbacks() }
-}
-
-\prg_set_conditional:Nnn \__lwc_if_enabled: { T, F, TF } {
-    \lua_now:n { lwc.if_lwc_enabled() }
+\prg_new_conditional:Nnn \__lwc_if_enabled: { T, F, TF } {
+    \__lwc_if_enabled:
         \prg_return_true:
     \else
         \prg_return_false:
@@ -230,9 +220,13 @@
     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 },
+    debug / true  .code:n = \__lwc_debug:n { true  },
+    debug / false .code:n = \__lwc_debug:n { false },
 
+    nobreak .code:n           = \__lwc_nobreak:n { #1 },
+    nobreak .value_required:n = true,
+    nobreak .initial:n        = keep,
+
     strict .meta:n = { emergencystretch = 0pt,
                        max-cost         = 5000,
                        nobreak          = warn,

Modified: trunk/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.lua	2022-05-14 20:32:55 UTC (rev 63301)
+++ trunk/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.lua	2022-05-14 20:33:11 UTC (rev 63302)
@@ -5,21 +5,45 @@
     SPDX-FileCopyrightText: 2022 Max Chernoff
   ]]
 
+--- Tell the linter about node attributes
+--- @class node
+--- @field prev node
+--- @field next node
+--- @field id integer
+--- @field subtype integer
+--- @field penalty integer
+--- @field height integer
+--- @field depth integer
+
+-- Set some default variables
 lwc = lwc or {}
 lwc.name = "lua-widow-control"
 lwc.nobreak_behaviour = "keep"
 
+-- Locals for `debug_print`
 local write_nl = texio.write_nl
 local string_rep = string.rep
+local write_log
+if status.luatex_engine == "luametatex" then
+    write_log = "logfile"
+else
+    write_log = "log"
+end
+
+--- Prints debugging messages to the log, only if `debug` is set to `true`.
+--- @param title string The "title" to use
+--- @param text string? The "content" to print
+--- @return nil
 local function debug_print(title, text)
     if not lwc.debug then return end
 
+    -- The number of spaces we need
     local filler = 15 - #title
 
     if text then
-        write_nl("log", "LWC (" .. title .. string_rep(" ", filler) .. "): " .. text)
+        write_nl(write_log, "LWC (" .. title .. string_rep(" ", filler) .. "): " .. text)
     else
-        write_nl("log", "LWC: " .. string_rep(" ", 18) .. title)
+        write_nl(write_log, "LWC: " .. string_rep(" ", 18) .. title)
     end
 end
 
@@ -31,16 +55,16 @@
 local format = tex.formatname
 local context, latex, plain, optex, lmtx
 
-if format:find('cont') then -- cont-en, cont-fr, cont-nl, ...
+if format:find("cont") then -- cont-en, cont-fr, cont-nl, ...
     context = true
     if status.luatex_engine == "luametatex" then
         lmtx = true
     end
-elseif format:find('latex') then -- lualatex, lualatex-dev, ...
+elseif format:find("latex") then -- lualatex, lualatex-dev, ...
     latex = true
-elseif format == 'luatex' then -- Plain
+elseif format == "luatex" then -- Plain
     plain = true
-elseif format == 'optex' then -- OpTeX
+elseif format == "optex" then -- OpTeX
     optex = true
 end
 
@@ -48,46 +72,81 @@
     Save some local copies of the node library to reduce table lookups.
     This is probably a useless micro-optimization, but it can't hurt.
   ]]
-local last = node.slide
-local copy = node.copy_list or node.copylist
-local par_id = node.id("par") or node.id("local_par")
+-- Node ID's
+local baselineskip_subid = 2
 local glue_id = node.id("glue")
 local glyph_id = node.id("glyph")
+local hlist_id = node.id("hlist")
+local line_subid = 1
+local linebreakpenalty_subid = 1
+local par_id = node.id("par") or node.id("local_par")
 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 versions of globals
+local copy = node.copy_list or node.copylist
 local find_attribute = node.find_attribute or node.findattribute
 local flush_list = node.flush_list or node.flushlist
 local free = node.free
+local getattribute = node.get_attribute or node.getattribute
+local insert_token = token.put_next or token.putnext
+local last = node.slide
+local new_node = node.new
 local node_id = node.is_node or node.isnode
+local set_attribute = node.set_attribute or node.setattribute
+local string_char = string.char
+local traverse = node.traverse
+local traverseid = node.traverse_id or node.traverseid
+
+-- Misc. Constants
+local iffalse = token.create("iffalse")
+local iftrue = token.create("iftrue")
+local INFINITY = 10000
 local min_col_width = tex.sp("250pt")
+local SINGLE_LINE = 50
+local PAGE_MULTIPLE = 100
 
 --[[
     Package/module initialization
   ]]
-local warning, info, attribute, contrib_head, stretch_order, pagenum, emergencystretch, max_cost
+local attribute,
+      contrib_head,
+      emergencystretch,
+      info,
+      max_cost,
+      pagenum,
+      stretch_order,
+      warning
 
 if lmtx then
+    -- LMTX has removed underscores from most of the Lua parts
     debug_print("LMTX")
-    contrib_head = 'contributehead'
+    contrib_head = "contributehead"
     stretch_order = "stretchorder"
 else
-    contrib_head = 'contrib_head'
+    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)
+
+    warning = logs.reporter(lwc.name, "warning")
+    local _info = logs.reporter(lwc.name, "info")
+    info = function (text)
+        logs.pushtarget("logfile")
+        _info(text)
+        logs.poptarget()
+    end
     attribute = attributes.public(lwc.name)
     pagenum = function() return tex.count["realpageno"] end
+
+    -- Dimen names
     emergencystretch = "lwc_emergency_stretch"
     max_cost = "lwc_max_cost"
 elseif plain or latex or optex then
     pagenum = function() return tex.count[0] end
 
+    -- Dimen names
     if tex.isdimen("g__lwc_emergencystretch_dim") then
         emergencystretch = "g__lwc_emergencystretch_dim"
         max_cost = "g__lwc_maxcost_int"
@@ -100,8 +159,8 @@
         debug_print("Plain/LaTeX")
         luatexbase.provides_module {
             name = lwc.name,
-            date = "2022/04/23", --%%slashdate
-            version = "2.0.6", --%%version
+            date = "2022/05/14", --%%dashdate
+            version = "2.1.0", --%%version
             description = [[
 
 This module provides a LuaTeX-based solution to prevent
@@ -114,11 +173,12 @@
         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
+else -- This shouldn't ever happen
     error [[Unsupported format.
 
 Please use LaTeX, Plain TeX, ConTeXt or OpTeX.]]
@@ -126,6 +186,8 @@
 
 local paragraphs = {} -- List to hold the alternate paragraph versions
 
+--- Gets the current paragraph and page locations
+--- @return string
 local function get_location()
     return "At " .. pagenum() .. "/" .. #paragraphs
 end
@@ -134,65 +196,9 @@
     Function definitions
   ]]
 
---- Create a table of functions to enable or disable a given callback
---- @param t table Parameters of the callback to create
----     callback: str = The \LuaTeX{} callback name
----     func: function = The function to call
----     name: str = The name/ID of the callback
----     category: str = The category for a \ConTeXt{} "Action"
----     position: str = The "position" for a \ConTeXt{} "Action"
----     lowlevel: bool = If we should use a lowlevel \LuaTeX{} callback instead of a
----                      \ConTeXt{} "Action"
---- @return table t Enablers/Disablers for the callback
----     enable: function = Enable the callback
----     disable: function = Disable the callback
-local function register_callback(t)
-    if plain or latex then -- Both use \LuaTeX{}Base for callbacks
-        return {
-            enable = function()
-                luatexbase.add_to_callback(t.callback, t.func, t.name)
-            end,
-            disable = function()
-                luatexbase.remove_from_callback(t.callback, t.name)
-            end,
-        }
-    elseif context and not t.lowlevel then
-        return {
-            -- Register the callback when the table is created,
-            -- but activate it when `enable()` is called.
-            enable = nodes.tasks.appendaction(t.category, t.position, "lwc." .. t.name)
-                or function()
-                    nodes.tasks.enableaction(t.category, "lwc." .. t.name)
-                end,
-            disable = function()
-                nodes.tasks.disableaction(t.category, "lwc." .. t.name)
-            end,
-        }
-    elseif context and t.lowlevel then
-        --[[
-            Some of the callbacks in \ConTeXt{} have no associated "actions". Unlike
-            with \LuaTeX{}base, \ConTeXt{} leaves some \LuaTeX{} callbacks unregistered
-            and unfrozen. Because of this, we need to register some callbacks at the
-            engine level. This is fragile though, because a future \ConTeXt{} update
-            may decide to register one of these functions, in which case
-            \lwc/ will crash with a cryptic error message.
-          ]]
-        return {
-            enable = function() callback.register(t.callback, t.func) end,
-            disable = function() callback.register(t.callback, nil) end,
-        }
-    elseif optex then
-        return {
-            enable = function()
-                callback.add_to_callback(t.callback, t.func, t.name)
-            end,
-            disable = function()
-                callback.remove_from_callback(t.callback, t.name)
-            end,
-        }
-    end
-end
-
+--- Prints the initial glyphs and glue of an hlist
+--- @param head node
+--- @return nil
 local function get_chars(head)
     if not lwc.debug then return end
 
@@ -199,13 +205,13 @@
     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)
+            if n.char < 127 then -- Only ASCII
+                chars = chars .. string_char(n.char)
             else
-                chars = chars .. "#"
+                chars = chars .. "#"  -- Replacement for an unknown glyph
             end
         elseif n.id == glue_id then
-            chars = chars .. " "
+            chars = chars .. " " -- Any glue goes to a space
         end
         if #chars > 25 then
             break
@@ -215,14 +221,56 @@
     debug_print(get_location(), chars)
 end
 
+--- The "cost function" to use. See the manual.
+--- @param demerits number The demerits of the broken paragraph
+--- @param lines number The number of lines in the broken paragraph
+--- @return number The cost of the broken paragraph
 function lwc.paragraph_cost(demerits, lines)
     return demerits / math.sqrt(lines)
 end
 
+--- Checks if the ConTeXt "grid snapping" is active
+--- @return boolean
+local function grid_mode_enabled()
+    -- Compare the token "mode" to see if `\\ifgridsnapping` is `\\iftrue`
+    return token.create("ifgridsnapping").mode == iftrue.mode
+end
+
+--- Gets the next node of a type/subtype in a node list
+--- @param head node The head of the node list
+--- @param id number The node type
+--- @param args table?
+---     subtype: number = The node subtype
+---     reverse: bool = Whether we should iterate backwards
+--- @return node
+local function next_of_type(head, id, args)
+    args = args or {}
+    if lmtx or not args.reverse then
+        for n, subtype in traverseid(id, head, args.reverse) do
+            if (subtype == args.subtype) or (args.subtype == nil) then
+                return n
+            end
+        end
+    else -- Only LMTX has the built-in backwards traverser
+        while head do
+            if head.id == id and
+               (head.subtype == args.subtype or args.subtype == nil)
+            then
+                return head
+            end
+            head = head.prev
+        end
+    end
+end
+
 --- Saves each paragraph, but lengthened by 1 line
+---
+--- Called by the `pre_linebreak_filter` callback
+---
+--- @param head node
+--- @return node
 function lwc.save_paragraphs(head)
-    -- Ensure that we were actually given a par (only under \ConTeXt{} for some reason)
-    if (head.id ~= par_id and context) or
+    if (head.id ~= par_id and context) or -- Ensure that we were actually given a par
         status.output_active -- Don't run during the output routine
     then
         return head
@@ -231,23 +279,34 @@
     -- Prevent the "underfull hbox" warnings when we store a potential paragraph
     local renable_box_warnings
     if (context or optex) or
-        #luatexbase.callback_descriptions("hpack_quality") == 0
+       #luatexbase.callback_descriptions("hpack_quality") == 0
     then -- See #18 and michal-h21/linebreaker#3
         renable_box_warnings = true
         lwc.callbacks.disable_box_warnings.enable()
     end
 
-
     -- We need to return the unmodified head at the end, so we make a copy here
     local new_head = copy(head)
 
     -- Prevent ultra-short last lines (\TeX{}Book p. 104), except with narrow columns
-    local parfillskip = last(new_head)
-    if parfillskip.id == glue_id and tex.hsize > min_col_width then
+    -- Equivalent to \\parfillskip=0pt plus 0.8\\hsize
+    local parfillskip
+    if lmtx or last(new_head).id ~= glue_id then
+        -- LMTX does not automatically add the \\parfillskip glue
+        parfillskip = new_node("glue", "parfillskip")
+    else
+        parfillskip = last(new_head)
+    end
+
+    if tex.hsize > min_col_width then
         parfillskip[stretch_order] = 0
         parfillskip.stretch = 0.8 * tex.hsize -- Last line must be at least 20% long
     end
 
+    if lmtx or last(new_head).id ~= glue_id then
+        last(new_head).next = parfillskip
+    end
+
     -- Break the paragraph 1 line longer than natural
     local long_node, long_info = tex.linebreak(new_head, {
         looseness = 1,
@@ -255,7 +314,16 @@
     })
 
     -- Break the natural paragraph so we know how long it was
-    local natural_node, natural_info = tex.linebreak(copy(head))
+    nat_head = copy(head)
+
+    if lmtx then
+        parfillskip = new_node("glue", "parfillskip")
+        parfillskip[stretch_order] = 1
+        parfillskip.stretch = 1 -- 0pt plus 1fil
+        last(nat_head).next = parfillskip
+    end
+
+    local natural_node, natural_info = tex.linebreak(nat_head)
     flush_list(natural_node)
 
     if renable_box_warnings then
@@ -262,18 +330,25 @@
         lwc.callbacks.disable_box_warnings.disable()
     end
 
-    -- Offset the accumulated \\prevdepth
-    local prevdepth = node.new("glue")
-    prevdepth.width = natural_info.prevdepth - long_info.prevdepth
-    last(long_node).next = prevdepth
+    if not grid_mode_enabled() then
+        -- Offset the accumulated \\prevdepth
+        local prevdepth = new_node("glue")
+        prevdepth.width = natural_info.prevdepth - long_info.prevdepth
+        last(long_node).next = prevdepth
+    end
 
-    if long_info.prevgraf == natural_info.prevgraf + 1 then
+    local long_cost = lwc.paragraph_cost(long_info.demerits, long_info.prevgraf)
+
+    if long_info.prevgraf == natural_info.prevgraf + 1 and
+       long_cost > 10 -- Any paragraph that is "free" to expand is suspicious
+    then
         table.insert(paragraphs, {
-            cost = lwc.paragraph_cost(long_info.demerits, long_info.prevgraf),
-            node = long_node
+            cost = long_cost,
+            node = next_of_type(long_node, hlist_id, { subtype = line_subid })
         })
     end
 
+    -- Print some debugging information
     get_chars(head)
     debug_print(get_location(), "nat  lines    " .. natural_info.prevgraf)
     debug_print(
@@ -288,21 +363,45 @@
         lwc.paragraph_cost(long_info.demerits, long_info.prevgraf)
     )
 
-    -- \LuaMetaTeX{} crashes if we return `true`
+    -- \ConTeXt{} crashes if we return `true`
     return head
 end
 
-local last_paragraph = 0
 --- Tags the beginning and the end of each paragraph as it is added to the page.
 ---
 --- We add an attribute to the first and last node of each paragraph. The ID is
 --- some arbitrary number for \lwc/, and the value corresponds to the
---- paragraphs index, which is negated for the end of the paragraph.
+--- paragraphs index, which is negated for the end of the paragraph. Called by the
+--- `post_linebreak_filter` callback.
+---
+--- @param head node
+--- @return node
 function lwc.mark_paragraphs(head)
-    if not status.output_active then
-        set_attribute(head, attribute, #paragraphs + (100 * pagenum()))
-        set_attribute(last(head), attribute, -1 * (#paragraphs + (100 * pagenum())))
-        last_paragraph = #paragraphs
+    if not status.output_active then -- Don't run during the output routine
+        -- Get the start and end of the paragraph
+        local top_para = next_of_type(head, hlist_id, { subtype = line_subid })
+        local bottom_para = last(head)
+
+        if top_para ~= bottom_para then
+            set_attribute(
+                top_para,
+                attribute,
+                #paragraphs + (PAGE_MULTIPLE * pagenum())
+            )
+            set_attribute(
+                bottom_para,
+                attribute,
+                -1 * (#paragraphs + (PAGE_MULTIPLE * pagenum()))
+            )
+        else
+            -- We need a special tag for a 1-line paragraph since the node can only
+            -- have one attribute value
+            set_attribute(
+                top_para,
+                attribute,
+                #paragraphs + (PAGE_MULTIPLE * pagenum()) + SINGLE_LINE
+            )
+        end
     end
 
     return head
@@ -313,7 +412,11 @@
 --- Sometimes the node list can form a loop. Since there is no last element
 --- of a looped linked-list, the `last()` function will never terminate. This
 --- function provides a "safe" version of the `last()` function that will break
---- the loop at the end if the list is circular.
+--- the loop at the end if the list is circular. Called by the `pre_output_filter`
+--- callback.
+---
+--- @param head node The start of a node list
+--- @return node The last node in a list
 local function safe_last(head)
     local ids = {}
     local prev
@@ -341,6 +444,40 @@
     return head
 end
 
+--- Checks to see if a penalty matches the widow/orphan/broken penalties
+--- @param penalty number
+--- @return boolean
+function is_matching_penalty(penalty)
+    local widowpenalty = tex.widowpenalty
+    local clubpenalty = tex.clubpenalty
+    local displaywidowpenalty = tex.displaywidowpenalty
+    local brokenpenalty = tex.brokenpenalty
+
+    --[[
+        We only need to process pages that have orphans or widows. If `paragraphs`
+        is empty, then there is nothing that we can do.
+
+        The list of penalties is from:
+        https://tug.org/TUGboat/tb39-3/tb123mitt-widows-code.pdf#subsection.0.2.1
+      ]]
+    penalty = penalty - tex.interlinepenalty
+
+    return penalty ~= 0 and
+           penalty <  INFINITY and (
+               penalty == widowpenalty or
+               penalty == displaywidowpenalty or
+               penalty == clubpenalty or
+               penalty == clubpenalty + widowpenalty or
+               penalty == clubpenalty + displaywidowpenalty or
+               penalty == brokenpenalty or
+               penalty == brokenpenalty + widowpenalty or
+               penalty == brokenpenalty + displaywidowpenalty or
+               penalty == brokenpenalty + clubpenalty or
+               penalty == brokenpenalty + clubpenalty + widowpenalty or
+               penalty == brokenpenalty + clubpenalty + displaywidowpenalty
+           )
+end
+
 --- Remove the widows and orphans from the page, just after the output routine.
 ---
 --- This function holds the "meat" of the module. It is called just after the
@@ -348,44 +485,22 @@
 --- penalty indicates that the page was broken at a widow or an orphan, we
 --- 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.
+---
+--- @param head node
+--- @return node
 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.
-
-        The list of penalties is from:
-        https://tug.org/TUGboat/tb39-3/tb123mitt-widows-code.pdf#subsection.0.2.1
-      ]]
-    if penalty ~= 0 and
-        penalty < 10000 and
-        (penalty == widowpenalty or
-            penalty == displaywidowpenalty or
-            penalty == clubpenalty or
-            penalty == clubpenalty + widowpenalty or
-            penalty == clubpenalty + displaywidowpenalty or
-            penalty == brokenpenalty or
-            penalty == brokenpenalty + widowpenalty or
-            penalty == brokenpenalty + displaywidowpenalty or
-            penalty == brokenpenalty + clubpenalty or
-            penalty == brokenpenalty + clubpenalty + widowpenalty or
-            penalty == brokenpenalty + clubpenalty + displaywidowpenalty) and
-        #paragraphs >= 1 then
-    else
+    if not is_matching_penalty(tex.outputpenalty) or
+       #paragraphs == 0
+    then
         paragraphs = {}
         return head_save
     end
 
-    info("Widow/orphan detected. Attempting to remove.")
+    info("Widow/orphan/broken hyphen detected. Attempting to remove")
 
     --[[
         Find the paragraph on the page with the least cost.
@@ -393,10 +508,38 @@
     local paragraph_index = 1
     local best_cost = paragraphs[paragraph_index].cost
 
+    local last_paragraph
+    local head_last = last(head)
+    -- Find the last paragraph on the page, starting at the end, heading in reverse
+    while head_last do
+        local value = getattribute(head_last, attribute)
+        if value then
+            last_paragraph = value % PAGE_MULTIPLE
+            break
+        end
+
+        head_last = head_last.prev
+    end
+
+    local first_paragraph
+    -- Find the first paragraph on the page, from the top
+    local first_attribute_val, first_attribute_head = find_attribute(head, attribute)
+    if first_attribute_val // 100 == pagenum() - 1 then
+        -- If the first complete paragraph on the page was initially broken on the
+        -- previous page, then we can't expand it here so we need to skip it.
+        first_paragraph = find_attribute(
+            first_attribute_head.next,
+            attribute
+        ) % PAGE_MULTIPLE
+    else
+        first_paragraph = first_attribute_val % PAGE_MULTIPLE
+    end
+
     -- We find the current "best" replacement, then free the unused ones
     for i, paragraph in pairs(paragraphs) do
         if paragraph.cost < best_cost and
-            i ~= last_paragraph
+           i <  last_paragraph and
+           i >= first_paragraph
         then
             -- Clear the old best paragraph
             flush_list(paragraphs[paragraph_index].node)
@@ -421,10 +564,10 @@
     )
 
     if best_cost > tex.getcount(max_cost) or
-        paragraph_index == last_paragraph
+       paragraph_index == last_paragraph
     then
         -- If the best replacement is too bad, we can't do anything
-        warning("Widow/Orphan NOT removed on page " .. pagenum())
+        warning("Widow/Orphan/broken hyphen NOT removed on page " .. pagenum())
         paragraphs = {}
         return head_save
     end
@@ -434,12 +577,13 @@
     -- Start of final paragraph
     debug_print("remove_widows", "moving last line")
 
+    -- Here we check to see if the widow/orphan was preceded by a large penalty
     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
+        elseif head.id == penalty_id and head.penalty >= INFINITY then
             -- Infinite break penalty
             big_penalty_found = true
         elseif big_penalty_found and head.id == hlist_id then
@@ -451,7 +595,7 @@
                 head = last(head_save)
                 break
             elseif lwc.nobreak_behaviour == "warn" then
-                warning("Widow/Orphan NOT removed on page " .. pagenum())
+                warning("Widow/Orphan/broken hyphen NOT removed on page " .. pagenum())
                 paragraphs = {}
                 return head_save
             end
@@ -467,6 +611,17 @@
         head = head.prev
     end
 
+    local potential_penalty = head.prev.prev
+
+    if potential_penalty and
+       potential_penalty.id      == penalty_id and
+       potential_penalty.subtype == linebreakpenalty_subid and
+       is_matching_penalty(potential_penalty.penalty)
+    then
+        warning("Making a new widow/orphan/broken hyphen on page " .. pagenum())
+    end
+
+
     last_line = copy(head)
     last(last_line).next = copy(tex.lists[contrib_head])
 
@@ -489,18 +644,50 @@
         debug_print("remove_widows", "found " .. value)
 
         -- Insert the start of the replacement paragraph
-        if value == paragraph_index + (100 * pagenum()) then
+        if value == paragraph_index + (PAGE_MULTIPLE * pagenum()) or
+           value == paragraph_index + (PAGE_MULTIPLE * pagenum()) + SINGLE_LINE
+        then
             debug_print("remove_widows", "replacement start")
             safe_last(target_node) -- Remove any loops
 
+            -- Fix the `\\baselineskip` glue between paragraphs
+            height_difference = (
+                next_of_type(head, hlist_id, { subtype = line_subid }).height -
+                next_of_type(target_node, hlist_id, { subtype = line_subid }).height
+            )
+
+            local prev_bls = next_of_type(
+                head,
+                glue_id,
+                { subtype = baselineskip_subid, reverse = true }
+            )
+
+            if prev_bls then
+                prev_bls.width = prev_bls.width + height_difference
+            end
+
             head.prev.next = target_node
             free_next_nodes = true
         end
 
         -- Insert the end of the replacement paragraph
-        if value == -1 * (paragraph_index + (100 * pagenum())) then
+        if value == -1 * (paragraph_index + (PAGE_MULTIPLE * pagenum())) or
+           value ==       paragraph_index + (PAGE_MULTIPLE * pagenum()) + SINGLE_LINE
+        then
             debug_print("remove_widows", "replacement end")
-            safe_last(target_node).next = head.next
+            local target_node_last = safe_last(target_node)
+
+            if grid_mode_enabled() then
+                -- Account for the difference in depth
+                local after_glue = new_node("glue")
+                after_glue.width = head.depth - target_node_last.depth
+                target_node_last.next = after_glue
+
+                after_glue.next = head.next
+            else
+                target_node_last.next = head.next
+            end
+
             break
         end
 
@@ -512,11 +699,10 @@
     end
 
     info(
-        "Widow/orphan successfully removed at paragraph "
+        "Widow/orphan/broken hyphen successfully removed at paragraph "
         .. paragraph_index
         .. " on page "
         .. pagenum()
-        .. "."
     )
 
     paragraphs = {} -- Clear paragraphs array at the end of the page
@@ -524,31 +710,90 @@
     return head_save
 end
 
+--- Create a table of functions to enable or disable a given callback
+--- @param t table Parameters of the callback to create
+---     callback: string = The \LuaTeX{} callback name
+---     func: function = The function to call
+---     name: string = The name/ID of the callback
+---     category: string = The category for a \ConTeXt{} "Action"
+---     position: string = The "position" for a \ConTeXt{} "Action"
+---     lowlevel: boolean = If we should use a lowlevel \LuaTeX{} callback instead of a
+---                      \ConTeXt{} "Action"
+--- @return table t Enablers/Disablers for the callback
+---     enable: function = Enable the callback
+---     disable: function = Disable the callback
+local function register_callback(t)
+    if plain or latex then -- Both use \LuaTeX{}Base for callbacks
+        return {
+            enable = function()
+                luatexbase.add_to_callback(t.callback, t.func, t.name)
+            end,
+            disable = function()
+                luatexbase.remove_from_callback(t.callback, t.name)
+            end,
+        }
+    elseif context and not t.lowlevel then
+        return {
+            -- Register the callback when the table is created,
+            -- but activate it when `enable()` is called.
+            enable = nodes.tasks.appendaction(t.category, t.position, "lwc." .. t.name)
+                or function()
+                    nodes.tasks.enableaction(t.category, "lwc." .. t.name)
+                end,
+            disable = function()
+                nodes.tasks.disableaction(t.category, "lwc." .. t.name)
+            end,
+        }
+    elseif context and t.lowlevel then
+        --[[
+            Some of the callbacks in \ConTeXt{} have no associated "actions". Unlike
+            with \LuaTeX{}base, \ConTeXt{} leaves some \LuaTeX{} callbacks unregistered
+            and unfrozen. Because of this, we need to register some callbacks at the
+            engine level. This is fragile though, because a future \ConTeXt{} update
+            may decide to register one of these functions, in which case
+            \lwc/ will crash with a cryptic error message.
+          ]]
+        return {
+            enable = function() callback.register(t.callback, t.func) end,
+            disable = function() callback.register(t.callback, nil) end,
+        }
+    elseif optex then -- Op\TeX{} is very similar to luatexbase
+        return {
+            enable = function()
+                callback.add_to_callback(t.callback, t.func, t.name)
+            end,
+            disable = function()
+                callback.remove_from_callback(t.callback, t.name)
+            end,
+        }
+    end
+end
+
 -- Add all of the callbacks
 lwc.callbacks = {
     disable_box_warnings = register_callback({
         callback = "hpack_quality",
-        func = function() end,
-        name = "disable_box_warnings",
+        func     = function() end,
+        name     = "disable_box_warnings",
         lowlevel = true,
     }),
     remove_widows = register_callback({
         callback = "pre_output_filter",
-        func = lwc.remove_widows,
-        name = "remove_widows",
+        func     = lwc.remove_widows,
+        name     = "remove_widows",
         lowlevel = true,
     }),
     save_paragraphs = register_callback({
         callback = "pre_linebreak_filter",
-        func = lwc.save_paragraphs,
-        name = "save_paragraphs",
+        func     = lwc.save_paragraphs,
+        name     = "save_paragraphs",
         category = "processors",
         position = "after",
     }),
     mark_paragraphs = register_callback({
         callback = "post_linebreak_filter",
-        func = lwc.mark_paragraphs,
-        name = "mark_paragraphs",
+        func     = lwc.mark_paragraphs,
+        name     = "mark_paragraphs",
         category = "finalizers",
         position = "after",
     }),
@@ -556,6 +801,7 @@
 
 
 local enabled = false
+--- Enable the paragraph callbacks
 function lwc.enable_callbacks()
     debug_print("callbacks", "enabling")
     if not enabled then
@@ -568,6 +814,7 @@
     end
 end
 
+--- Disable the paragraph callbacks
 function lwc.disable_callbacks()
     debug_print("callbacks", "disabling")
     if enabled then
@@ -588,12 +835,88 @@
 function lwc.if_lwc_enabled()
     debug_print("iflwc")
     if enabled then
-        tex.sprint("\\iftrue")
+        insert_token(iftrue)
     else
-        tex.sprint("\\iffalse")
+        insert_token(iffalse)
     end
 end
 
+--- Mangles a macro name so that it's suitable for a specific format
+--- @param name string The plain name
+--- @param args table<string> The TeX types of the function arguments
+--- @return string The mangled name
+local function mangle_name(name, args)
+    if plain then
+        return "lwc@" .. name:gsub("_", "@")
+    elseif optex then
+        return "_lwc_" .. name
+    elseif context then
+        return "lwc_" .. name
+    elseif latex then
+        return "__lwc_" .. name .. ":" .. string_rep("n", #args)
+    end
+end
+
+--- Creates a TeX command that evaluates a Lua function
+--- @param name string The name of the csname to define
+--- @param func function
+--- @param args table<string> The TeX types of the function arguments
+--- @return nil
+local function register_tex_cmd(name, func, args)
+    local scanning_func
+    name = mangle_name(name, args)
+
+    if not context then
+        local scanners = {}
+        for _, arg in ipairs(args) do
+            scanners[#scanners+1] = token['scan_' .. arg]
+        end
+
+        scanning_func = function()
+            local values = {}
+            for _, scanner in ipairs(scanners) do
+                values[#values+1] = scanner()
+            end
+
+            func(table.unpack(values))
+        end
+    end
+
+    if optex then
+        define_lua_command(name, scanning_func)
+        return
+    elseif plain or latex then
+        local index = luatexbase.new_luafunction(name)
+        lua.get_functions_table()[index] = scanning_func
+        token.set_lua(name, index)
+    elseif context then
+        interfaces.implement {
+            name = name,
+            public = true,
+            arguments = args,
+            actions = func
+        }
+    end
+end
+
+register_tex_cmd("if_enabled", lwc.if_lwc_enabled, {})
+register_tex_cmd("enable", lwc.enable_callbacks, {})
+register_tex_cmd("disable", lwc.disable_callbacks, {})
+register_tex_cmd(
+    "nobreak",
+    function(str)
+        lwc.nobreak_behaviour = str
+    end,
+    { "string" }
+)
+register_tex_cmd(
+    "debug",
+    function(str)
+        lwc.debug = str ~= "0" and str ~= "false" and str ~= "stop"
+    end,
+    { "string" }
+)
+
 --- Silence the luatexbase "Enabling/Removing <callback>" info messages
 ---
 --- Every time that a paragraph is typeset, \lwc/ hooks in
@@ -612,12 +935,12 @@
 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)
+    for i = 1, nups do
+        local name, func = debug.getupvalue(luatexbase.add_to_callback, i)
         if name == "luatexbase_log" then
             debug.setupvalue(
                 luatexbase.add_to_callback,
-                x,
+                i,
                 function(text)
                     if text:match("^Inserting") or text:match("^Removing") then
                         return

Modified: trunk/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.tex
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.tex	2022-05-14 20:32:55 UTC (rev 63301)
+++ trunk/Master/texmf-dist/tex/luatex/lua-widow-control/lua-widow-control.tex	2022-05-14 20:33:11 UTC (rev 63302)
@@ -3,7 +3,7 @@
 % SPDX-License-Identifier: MPL-2.0+
 % SPDX-FileCopyrightText: 2022 Max Chernoff
 
-\wlog{lua-widow-control v2.0.6} %%version
+\wlog{lua-widow-control v2.1.0} %%version
 
 \ifx\directlua\undefined
     \errmessage{%
@@ -35,13 +35,8 @@
 \expandglyphsinfont\the\font 20 20 5
 \adjustspacing=2
 
-% Define \TeX{} wrappers for Lua functions
-\def\lwcenable{\directlua{lwc.enable_callbacks()}}
-\def\lwcdisable{\directlua{lwc.disable_callbacks()}}
-\def\iflwc{\directlua{lwc.if_lwc_enabled()}}
-
 % Enable \lwc/ by default when the package is loaded.
-\lwcenable
+\lwc at enable
 
 % Expansion of some parts of the document, such as section headings, is quite
 % undesirable, so we'll disable \lwc/ for certain commands.
@@ -50,15 +45,15 @@
 \newcount\lwc at disable@count
 
 \def\lwc at patch@pre{%
-    \iflwc%
+    \lwc at if@enabled%
         \advance\lwc at disable@count by 1%
-        \lwcdisable%
+        \lwc at disable%
     \fi%
 }
 
 \def\lwc at patch@post{
     \ifnum\lwc at disable@count>0%
-        \lwcenable%
+        \lwc at enable%
         \advance\lwc at disable@count by -1%
     \fi
 }
@@ -89,6 +84,13 @@
     \lwcdisablecmd{\beginsection} % Sectioning
 \endgroup
 
+% Make the commands public
+\let\lwcenable=\lwc at enable
+\let\lwcdisable=\lwc at disable
+\let\lwcdebug=\lwc at debug
+\let\iflwc=\lwc at if@enabled
+\let\lwcnobreak=\lwc at nobreak
 
+
 \catcode`@=12
 \endinput

Modified: trunk/Master/texmf-dist/tex/optex/lua-widow-control/lua-widow-control.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/lua-widow-control/lua-widow-control.opm	2022-05-14 20:32:55 UTC (rev 63301)
+++ trunk/Master/texmf-dist/tex/optex/lua-widow-control/lua-widow-control.opm	2022-05-14 20:33:11 UTC (rev 63302)
@@ -3,7 +3,7 @@
 % SPDX-License-Identifier: MPL-2.0+
 % SPDX-FileCopyrightText: 2022 Max Chernoff
 
-\_codedecl\lwcenable{lua-widow-control <v2.0.6>} %%version
+\_codedecl\lwcenable{lua-widow-control <v2.1.0>} %%version
 \_namespace{lwc}
 
 \_clubpenalty=1
@@ -19,14 +19,6 @@
 
 \_directlua{require "lua-widow-control"}
 
-% Define \TeX{} wrappers for Lua functions
-\_def\.enable{\_directlua{lwc.enable_callbacks()}}
-\_def\.disable{\_directlua{lwc.disable_callbacks()}}
-\_def\.iflwc{\_directlua{lwc.if_lwc_enabled()}}
-
-\_let\lwcenable=\.enable
-\_let\lwcdisable=\.disable
-
 % Enable \lwc/ by default when the package is loaded.
 \.enable
 
@@ -37,7 +29,7 @@
 \_newcount\.disable_count
 
 \_def\.patch_pre{%
-    \.iflwc%
+    \.if_enabled%
         \_advance\.disable_count by 1%
         \.disable%
     \_fi%
@@ -70,11 +62,18 @@
         \_endgroup%
     \_fi%
 }
-\_let\lwcdisablecmd=\.disable_cmd
 
 \.disable_cmd{\_printchap}
 \.disable_cmd{\_printsec}
 \.disable_cmd{\_printsecc}
 
+% Make the commands public
+\_let\lwcenable=\.enable
+\_let\lwcdisable=\.disable
+\_let\lwcdisablecmd=\.disable_cmd
+\_let\lwcdebug=\.debug
+\_let\iflwc=\.if_enabled
+\_let\lwcnobreak=\.nobreak
+
 \_endnamespace
 \_endcode



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