Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LuaMetaLaTeX and LuaMetaPlain support #40

Merged
merged 13 commits into from Oct 31, 2022
14 changes: 14 additions & 0 deletions .github/workflows/build-test-bundle.yml
Expand Up @@ -26,6 +26,7 @@ jobs:
sudo apt-get install --no-install-recommends -y
poppler-utils
xsltproc
libcurl4-openssl-dev
) & disown

# From https://github.com/zauguin/install-texlive
Expand Down Expand Up @@ -92,6 +93,19 @@ jobs:
echo "tl_context=$HOME/texlive/bin/x86_64-linux/context" >> $GITHUB_ENV
echo "TEXMFHOME=$GITHUB_WORKSPACE/texmf" >> $GITHUB_ENV

- name: Install LuaMetaLaTeX
run: |
cd ~
git clone --depth 1 https://github.com/zauguin/luametalatex.git
cd luametalatex
l3build install
mktexlsr

cd ~
wget https://lmltx.typesetting.eu/installer-linux64.zip
unzip installer-linux64.zip
./installer

- name: Build Documentation
run: |
cd "$GITHUB_WORKSPACE"
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,8 @@ All notable changes to lua-widow-control will be listed here, in reverse chronol

## Unreleased

- Add support for [LuaMetaLaTeX and LuaMetaPlain](https://github.com/zauguin/luametalatex). All features should work identically to the LuaTeX-based version, although there are a few minor bugs. ([#40](https://github.com/gucci-on-fleek/lua-widow-control/pull/40))

- Fully support inserts/footnotes in LuaMetaTeX ([#38](https://github.com/gucci-on-fleek/lua-widow-control/issues/38)).

- Add support for presets in ConTeXt.
Expand Down
4 changes: 4 additions & 0 deletions docs/manual/lwc-manual.tex
Expand Up @@ -295,6 +295,10 @@ \subsection{\ConTeXt{}}
\subsection{\OpTeX{}}
\Lwc/ works with any version of \OpTeX{} and has no dependencies.

\subsection{LuaMeta\TeX{}}

\Lwc/ has preliminary support for LuaMeta\LaTeX{} and LuaMetaPlain. All features should work identically to the \LuaTeX{}-based version, although there are a few minor bugs. You should always make sure to use the latest engine, format, and \lwc/ since these formats are under rapid development.


\section[sec:usage]{Loading the Package}

Expand Down
123 changes: 96 additions & 27 deletions source/lua-widow-control.lua
Expand Up @@ -59,14 +59,18 @@ end
local format = tex.formatname
local context, latex, plain, optex, lmtx

if status.luatex_engine == "luametatex" then
lmtx = true
end

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, ...
latex = true
elseif format == "luatex" or format == "luahbtex" then -- Plain
elseif format == "luatex" or
format == "luahbtex" or
format:find("plain")
then -- Plain
plain = true
elseif format:find("optex") then -- OpTeX
optex = _G.optex
Expand All @@ -89,6 +93,12 @@ local line_subid = 1
local linebreakpenalty_subid = 1
local par_id = id_from_name("par") or id_from_name("local_par")
local penalty_id = id_from_name("penalty")
local parfill_subids = {
parfillleftskip = 17,
parfillrightskip = 16,
parinitleftskip = 19,
parinitrightskip = 18,
}

-- Local versions of globals
local abs = math.abs
Expand All @@ -105,6 +115,7 @@ local new_node = node.new
local remove = node.remove
local set_attribute = node.set_attribute or node.setattribute
local string_char = string.char
local subtype = node.subtype
local tex_box = tex.box
local tex_count = tex.count
local tex_dimen = tex.dimen
Expand Down Expand Up @@ -143,7 +154,9 @@ local contrib_head,
insert_attribute,
max_cost,
pagenum,
page_head,
paragraph_attribute,
set_whatsit_field,
shrink_order,
stretch_order,
warning
Expand All @@ -155,11 +168,15 @@ if lmtx then
shrink_order = "shrinkorder"
stretch_order = "stretchorder"
hold_head = "holdhead"
page_head = "pagehead"
set_whatsit_field = node.setwhatsitfield
else
contrib_head = "contrib_head"
shrink_order = "shrink_order"
stretch_order = "stretch_order"
hold_head = "hold_head"
page_head = "page_head"
set_whatsit_field = node.setfield
end

if context then
Expand Down Expand Up @@ -225,6 +242,7 @@ else -- This shouldn't ever happen
Please use LaTeX, Plain TeX, ConTeXt or OpTeX.]]
end


--[[ Select the fonts

We want to use cmr7 for the draft mode cost displays, and the easiest
Expand Down Expand Up @@ -349,6 +367,38 @@ local function next_of_type(head, id, args)
end


--- Ensures that a paragraph is ready to be broken
---
--- Only applies to LMTX
--- @param head node
--- @return nil
local function prepare_linebreak(head)
if not lmtx then
return
end

local parfills = {}
local count = 0
for name, subid in pairs(parfill_subids) do
parfills[name] = next_of_type(head, glue_id, { subtype = subid })
if parfills[name] then
count = count + 1
end
end

if count == 0 then
-- Usual case
tex.preparelinebreak(head)
elseif count == 4 then
-- Already prepared for some reason, ignored
else
-- Uh oh
warning("Weird par(fill/init)skips found!")
tex.preparelinebreak(head) -- Try to fix it
end
end


--- Breaks a paragraph one line longer than natural
---
--- @param head node The unbroken paragraph
Expand All @@ -358,9 +408,7 @@ local function long_paragraph(head)
-- We can't modify the original paragraph
head = copy_list(head)

if lmtx then
tex.preparelinebreak(head)
end
prepare_linebreak(head)

-- Prevent ultra-short last lines (\TeX{}Book p. 104), except with narrow columns
-- Equivalent to \\parfillskip=0pt plus 0.8\\hsize
Expand All @@ -387,9 +435,7 @@ local function natural_paragraph(head)
-- We can't modify the original paragraph
head = copy_list(head)

if lmtx then
tex.preparelinebreak(head)
end
prepare_linebreak(head)

-- Break the paragraph naturally to get \\prevgraf
local natural_node, natural_info = linebreak(head)
Expand Down Expand Up @@ -430,14 +476,14 @@ local function colour_list(head, colour)

-- Adapted from https://tex.stackexchange.com/a/372437
-- \\pdfextension colorstack is ignored in LMTX
local start_colour = new_node("whatsit", "pdf_colorstack")
start_colour.stack = 0
start_colour.command = 1
start_colour.data = pdf_colour
local start_colour = new_node("whatsit", subtype("pdf_colorstack"))
set_whatsit_field(start_colour, "stack", 0)
set_whatsit_field(start_colour, "command", 1)
set_whatsit_field(start_colour, "data", pdf_colour)

local end_colour = new_node("whatsit", "pdf_colorstack")
end_colour.stack = 0
end_colour.command = 2
local end_colour = new_node("whatsit", subtype("pdf_colorstack"))
set_whatsit_field(end_colour, "stack", 0)
set_whatsit_field(end_colour, "command", 2)

start_colour.next = head
last(head).next = end_colour
Expand Down Expand Up @@ -755,7 +801,7 @@ local function remove_widows_fail()
warning("Widow/Orphan/broken hyphen NOT removed on page " .. pagenum())

local last_line = next_of_type(
last(tex_lists.page_head),
last(tex_lists[page_head]),
hlist_id,
{ subtype = line_subid, reverse = true }
)
Expand Down Expand Up @@ -886,23 +932,34 @@ local function get_inserts(last_line)

if lmtx then
insert_box = tex.getinsertcontent(class)
tex.setinsertcontent(class, insert_box)
else
insert_box = tex_box[class]
end

-- Get any portions of the insert held over until the next page
local split_insert = next_of_type(
tex_lists[hold_head],
insert_id,
{ subtype = class }
)
local split_insert
if lmtx then
split_insert = next_of_type(
tex_lists[hold_head],
insert_id,
{ index = class }
)
else
split_insert = next_of_type(
tex_lists[hold_head],
insert_id,
{ subtype = class }
)
end

for i, insert in ipairs { insert_box, split_insert } do
local m = insert and insert.list

while m do -- Iterate through the insert box
local box_value
box_value, m = find_attribute(m, insert_attribute)
local next = m.next

if not m then
break
Expand All @@ -918,10 +975,10 @@ local function get_inserts(last_line)
table.insert(selected_inserts, copy(inserts[box_value]))
end

m = free(m)
else
m = m.next
free(m)
end

m = next
end
end

Expand Down Expand Up @@ -1039,7 +1096,19 @@ end
--- @param head node
--- @param paragraph_index number
local function replace_paragraph(head, paragraph_index)
local target_node = copy_list(paragraphs[paragraph_index].node)
-- Remove any inserts
local target_node, last_target_node
for n in traverse(paragraphs[paragraph_index].node) do
if n.id ~= insert_id then
if not target_node then
target_node = copy(n)
last_target_node = target_node
else
last_target_node.next = copy(n)
last_target_node = last_target_node.next
end
end
end

local start_found = false
local end_found = false
Expand Down
14 changes: 14 additions & 0 deletions source/lua-widow-control.sty
Expand Up @@ -145,6 +145,14 @@
\fi
}

\prg_new_conditional:Nnn \__lwc_if_lmtx: { T, F, TF } {
\int_compare:nNnTF { \tex_luatexversion:D } > { 200 } {
\prg_return_true:
} {
\prg_return_false:
}
}

% Expansion of some parts of the document, such as section headings, is quite
% undesirable, so we'll disable \lwc/ for certain commands.
\int_new:N \g__lwc_disable_int
Expand Down Expand Up @@ -197,6 +205,12 @@
\clist_map_function:NN \g__lwc_disablecmds_cl \__lwc_patch_cmd:n
}

\__lwc_if_lmtx:T {
\int_gset:Nn \normalizelinemode {
\numexpression\normalizelinemode bor 2\relax
}
}

%%% Class and package-specifc patches

% KOMA-Script
Expand Down
19 changes: 16 additions & 3 deletions source/lua-widow-control.tex
Expand Up @@ -14,6 +14,9 @@

\catcode`@=11

% We need to change some code if we're using LuaMetaTeX
\def\lwc@iflmtx{\ifnum\luatexversion>200\relax}

\input ltluatex % \LuaTeX{}Base

\clubpenalty=1
Expand All @@ -32,12 +35,20 @@
% Here, we enable font expansion/contraction. It isn't strictly necessary for
% \lwc/'s functionality; however, it is required for the
% lengthened paragraphs to not have terrible spacing.
\expandglyphsinfont\the\font 20 20 5
\adjustspacing=2
\lwc@iflmtx\else
\expandglyphsinfont\the\font 20 20 5
\adjustspacing=2
\fi

% Enable \lwc/ by default when the package is loaded.
\lwc@enable

% Fix some strange LMTX bugs
\lwc@iflmtx
\normalizelinemode=\numexpression\normalizelinemode bor 2\relax
\fi


% Expansion of some parts of the document, such as section headings, is quite
% undesirable, so we'll disable \lwc/ for certain commands.

Expand Down Expand Up @@ -80,7 +91,9 @@
}

\begingroup
\suppressoutererror=1
\lwc@iflmtx\else
\suppressoutererror=1
\fi
\lwcdisablecmd{\beginsection} % Sectioning
\endgroup

Expand Down
11 changes: 11 additions & 0 deletions tests/common/luametatex-wrapper
@@ -0,0 +1,11 @@
#!/bin/sh
# lua-widow-control
# https://github.com/gucci-on-fleek/lua-widow-control
# SPDX-License-Identifier: MPL-2.0+
# SPDX-FileCopyrightText: 2022 Max Chernoff
set -eu

format=$(echo "$@" | sed -E 's/^.*--fmt=([^ ]*) .*$/\1/')
filename=$(echo "$@" | sed -E 's/^.*\input ([^ ]*).*$/\1/')

exec "$format" "$filename"