summaryrefslogtreecommitdiff
path: root/macros/luatex
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-05-15 03:00:49 +0000
committerNorbert Preining <norbert@preining.info>2022-05-15 03:00:49 +0000
commitf8e05edb088c3b5246e016f68df9c4cadccfd34d (patch)
treebc2ad458c483af921298a66be3b70d0cc74f2c85 /macros/luatex
parent2afee5e322fb0dfc2764c270803bc6381b65636e (diff)
CTAN sync 202205150300
Diffstat (limited to 'macros/luatex')
-rw-r--r--macros/luatex/generic/lua-widow-control/README.md2
-rw-r--r--macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty9
-rw-r--r--macros/luatex/generic/lua-widow-control/lua-widow-control.lua637
-rw-r--r--macros/luatex/generic/lua-widow-control/lua-widow-control.opm21
-rw-r--r--macros/luatex/generic/lua-widow-control/lua-widow-control.pdfbin385495 -> 403738 bytes
-rw-r--r--macros/luatex/generic/lua-widow-control/lua-widow-control.sty32
-rw-r--r--macros/luatex/generic/lua-widow-control/lua-widow-control.tex22
-rw-r--r--macros/luatex/generic/lua-widow-control/lwc-documentation.tex15
-rw-r--r--macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkiv48
-rw-r--r--macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl48
10 files changed, 580 insertions, 254 deletions
diff --git a/macros/luatex/generic/lua-widow-control/README.md b/macros/luatex/generic/lua-widow-control/README.md
index 77dd7734da..cc6aed7ba0 100644
--- a/macros/luatex/generic/lua-widow-control/README.md
+++ b/macros/luatex/generic/lua-widow-control/README.md
@@ -48,4 +48,4 @@ Lua-widow-control is licensed under the [_Mozilla Public License_, version 2.0](
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-->
diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty b/macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty
index e8b2eefb0a..d67c68d2fd 100644
--- a/macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty
+++ b/macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty
@@ -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
diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.lua b/macros/luatex/generic/lua-widow-control/lua-widow-control.lua
index 94dd85e145..45360db209 100644
--- a/macros/luatex/generic/lua-widow-control/lua-widow-control.lua
+++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.lua
@@ -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 @@ end
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 @@ end
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 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 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 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 @@ elseif plain or latex or optex then
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 @@ paragraphs.]],
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 @@ end
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,78 +196,22 @@ end
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
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 @@ local function get_chars(head)
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 @@ function lwc.save_paragraphs(head)
-- 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,25 +314,41 @@ function lwc.save_paragraphs(head)
})
-- 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
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
+
+ local long_cost = lwc.paragraph_cost(long_info.demerits, long_info.prevgraf)
- if long_info.prevgraf == natural_info.prevgraf + 1 then
+ 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 @@ function lwc.save_paragraphs(head)
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 @@ end
--- 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,24 +444,15 @@ recover, but your output may be corrupted.
return head
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
---- end of the output routine, before the page is shipped out. If the output
---- 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.
-function lwc.remove_widows(head)
- local head_save = head -- Save the start of the `head` linked-list
-
- local penalty = tex.outputpenalty - tex.interlinepenalty
+--- 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
- 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.
@@ -366,26 +460,47 @@ 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 ~= 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
+ 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
+--- end of the output routine, before the page is shipped out. If the output
+--- 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
+
+ debug_print("outputpenalty", tex.outputpenalty .. " " .. #paragraphs)
+
+ 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 @@ function lwc.remove_widows(head)
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 @@ function lwc.remove_widows(head)
)
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 @@ function lwc.remove_widows(head)
-- 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 @@ function lwc.remove_widows(head)
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 @@ function lwc.remove_widows(head)
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 @@ function lwc.remove_widows(head)
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 @@ function lwc.remove_widows(head)
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 @@ function lwc.remove_widows(head)
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 @@ lwc.callbacks = {
local enabled = false
+--- Enable the paragraph callbacks
function lwc.enable_callbacks()
debug_print("callbacks", "enabling")
if not enabled then
@@ -568,6 +814,7 @@ function lwc.enable_callbacks()
end
end
+--- Disable the paragraph callbacks
function lwc.disable_callbacks()
debug_print("callbacks", "disabling")
if enabled then
@@ -588,12 +835,88 @@ end
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 @@ end
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
diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.opm b/macros/luatex/generic/lua-widow-control/lua-widow-control.opm
index afae1aa6a6..cb6f4c06f9 100644
--- a/macros/luatex/generic/lua-widow-control/lua-widow-control.opm
+++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.opm
@@ -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
diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.pdf b/macros/luatex/generic/lua-widow-control/lua-widow-control.pdf
index 3ab6e51886..709042c553 100644
--- a/macros/luatex/generic/lua-widow-control/lua-widow-control.pdf
+++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.pdf
Binary files differ
diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.sty b/macros/luatex/generic/lua-widow-control/lua-widow-control.sty
index a44b5af1da..e7179e6a9e 100644
--- a/macros/luatex/generic/lua-widow-control/lua-widow-control.sty
+++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.sty
@@ -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@sect, % Memoir
\@mem@old@ssect, % Memoir Starred
\ttl@straight@ii, % titlesec normal
@@ -112,11 +113,6 @@
\ttl@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,8 +220,12 @@
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,
diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.tex b/macros/luatex/generic/lua-widow-control/lua-widow-control.tex
index b667d05c11..78385ad698 100644
--- a/macros/luatex/generic/lua-widow-control/lua-widow-control.tex
+++ b/macros/luatex/generic/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 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@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@disable@count
\def\lwc@patch@pre{%
- \iflwc%
+ \lwc@if@enabled%
\advance\lwc@disable@count by 1%
- \lwcdisable%
+ \lwc@disable%
\fi%
}
\def\lwc@patch@post{
\ifnum\lwc@disable@count>0%
- \lwcenable%
+ \lwc@enable%
\advance\lwc@disable@count by -1%
\fi
}
@@ -89,6 +84,13 @@
\lwcdisablecmd{\beginsection} % Sectioning
\endgroup
+% Make the commands public
+\let\lwcenable=\lwc@enable
+\let\lwcdisable=\lwc@disable
+\let\lwcdebug=\lwc@debug
+\let\iflwc=\lwc@if@enabled
+\let\lwcnobreak=\lwc@nobreak
+
\catcode`@=12
\endinput
diff --git a/macros/luatex/generic/lua-widow-control/lwc-documentation.tex b/macros/luatex/generic/lua-widow-control/lwc-documentation.tex
index 7f05a344f0..23b13c0250 100644
--- a/macros/luatex/generic/lua-widow-control/lwc-documentation.tex
+++ b/macros/luatex/generic/lua-widow-control/lwc-documentation.tex
@@ -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 @@ Note that the \LaTeX{} option does not \emph{append} commands to the disable lis
\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 @@ When \lwc/ encounters an orphan, it removes it by removing the orphaned line to
\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 @@ Very advanced users may also set a custom cost function by redefining the \inlin
\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}}
diff --git a/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkiv b/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkiv
index 1e52f8d901..090ff5aa80 100644
--- a/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkiv
+++ b/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkiv
@@ -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,36 @@
\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}
+ \brokenpenalty=\lwcparameter{brokenpenalty}
+ \stopsetups
+
+ \startsetups[grid][*default]
+ \directsetup{*reset}
+
\clubpenalty=\lwcparameter{orphanpenalty}
\widowpenalty=\lwcparameter{widowpenalty}
\displaywidowpenalty=\lwcparameter{widowpenalty}
@@ -58,8 +55,6 @@
\setups[*default]
\to\everysetuplwc
-\define\iflwc{\ctxlua{lwc.if_lwc_enabled()}}
-
\ctxloadluafile{lua-widow-control}
\setuplwc[
@@ -86,14 +81,14 @@
\newcount\lwc_disable_count
\define\lwc_patch_pre{%
- \iflwc%
+ \lwc_if_enabled%
\advance\lwc_disable_count by 1%
\setuplwc[\c!state=\v!stop]%
\fi%
}
\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
diff --git a/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl b/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl
index 1e52f8d901..090ff5aa80 100644
--- a/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl
+++ b/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl
@@ -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,36 @@
\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}
+ \brokenpenalty=\lwcparameter{brokenpenalty}
+ \stopsetups
+
+ \startsetups[grid][*default]
+ \directsetup{*reset}
+
\clubpenalty=\lwcparameter{orphanpenalty}
\widowpenalty=\lwcparameter{widowpenalty}
\displaywidowpenalty=\lwcparameter{widowpenalty}
@@ -58,8 +55,6 @@
\setups[*default]
\to\everysetuplwc
-\define\iflwc{\ctxlua{lwc.if_lwc_enabled()}}
-
\ctxloadluafile{lua-widow-control}
\setuplwc[
@@ -86,14 +81,14 @@
\newcount\lwc_disable_count
\define\lwc_patch_pre{%
- \iflwc%
+ \lwc_if_enabled%
\advance\lwc_disable_count by 1%
\setuplwc[\c!state=\v!stop]%
\fi%
}
\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