texlive[63081] Master: luamathalign (19apr22)

commits+karl at tug.org commits+karl at tug.org
Tue Apr 19 22:10:27 CEST 2022


Revision: 63081
          http://tug.org/svn/texlive?view=revision&revision=63081
Author:   karl
Date:     2022-04-19 22:10:27 +0200 (Tue, 19 Apr 2022)
Log Message:
-----------
luamathalign (19apr22)

Modified Paths:
--------------
    trunk/Master/tlpkg/bin/tlpkg-ctan-check
    trunk/Master/tlpkg/libexec/ctan2tds
    trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/lualatex/luamathalign/
    trunk/Master/texmf-dist/doc/lualatex/luamathalign/README.md
    trunk/Master/texmf-dist/doc/lualatex/luamathalign/luamathalign.pdf
    trunk/Master/texmf-dist/source/lualatex/luamathalign/
    trunk/Master/texmf-dist/source/lualatex/luamathalign/luamathalign.dtx
    trunk/Master/texmf-dist/tex/lualatex/luamathalign/
    trunk/Master/texmf-dist/tex/lualatex/luamathalign/build.lua
    trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign-luacmd.lua
    trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign-luaprop.lua
    trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign.lua
    trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign.sty
    trunk/Master/tlpkg/tlpsrc/luamathalign.tlpsrc

Added: trunk/Master/texmf-dist/doc/lualatex/luamathalign/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luamathalign/README.md	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/lualatex/luamathalign/README.md	2022-04-19 20:10:27 UTC (rev 63081)
@@ -0,0 +1,29 @@
+# The `luamathalign` package for LuaLaTeX
+
+With `amsmath`'s `align` environment simple equations can be aligned easily, e.g.
+
+```tex
+2  &=1+1\\
+2-1&=1
+```
+
+but even just adding an underline makes this much more complicated. E.g.
+
+```tex
+2  &=1+1\\
+\underline{2-1&=1}
+```
+
+is not allowed. Similarly alignment points surrounded by `\left` and `\right`
+or points nested in other environments do not work.
+
+For LuaLaTeX this can be solved with luamathalign. It adds a command `\AlignHere`
+which behaves mustly like `&` except that it's allowed almost anywhere. E.g.
+
+```
+                      2 &= 1+1\\
+\underline{2-1 \AlignHere= 1}
+```
+
+
+Licensed under the LPPL v1.3c or later.


Property changes on: trunk/Master/texmf-dist/doc/lualatex/luamathalign/README.md
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/lualatex/luamathalign/luamathalign.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/lualatex/luamathalign/luamathalign.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luamathalign/luamathalign.pdf	2022-04-19 20:06:58 UTC (rev 63080)
+++ trunk/Master/texmf-dist/doc/lualatex/luamathalign/luamathalign.pdf	2022-04-19 20:10:27 UTC (rev 63081)

Property changes on: trunk/Master/texmf-dist/doc/lualatex/luamathalign/luamathalign.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Added: trunk/Master/texmf-dist/source/lualatex/luamathalign/luamathalign.dtx
===================================================================
--- trunk/Master/texmf-dist/source/lualatex/luamathalign/luamathalign.dtx	                        (rev 0)
+++ trunk/Master/texmf-dist/source/lualatex/luamathalign/luamathalign.dtx	2022-04-19 20:10:27 UTC (rev 63081)
@@ -0,0 +1,655 @@
+% \iffalse meta-comment
+%
+%% Copyright (C) 2019--2022 by Marcel Krueger
+%%
+%% This file may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either
+%% version 1.3c of this license or (at your option) any later
+%% version. The latest version of this license is in:
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% and version 1.3 or later is part of all distributions of
+%% LaTeX version 2005/12/01 or later.
+%
+%<*batch>
+%<*gobble>
+\ifx\jobname\relax\let\documentclass\undefined\fi
+\ifx\documentclass\undefined
+\csname fi\endcsname
+%</gobble>
+\input l3docstrip.tex
+\keepsilent
+\preamble
+\endpreamble
+\generate{\file{luamathalign.sty}{\from{luamathalign.dtx}{package}}}
+\begingroup
+\def\MetaPrefix{--}
+\preamble
+\endpreamble
+\postamble
+\endpostamble
+\generate{\file{luamathalign.lua}{\from{luamathalign.dtx}{lua}}}
+\endgroup
+\endbatchfile
+%</batch>
+%<*gobble>
+\fi
+\expandafter\ifx\csname @currname\endcsname\empty
+\csname fi\endcsname
+%</gobble>
+%<*driver>
+\documentclass[full]{l3doc}
+\usepackage{luamathalign}
+\usepackage{csquotes}
+\MakeShortVerb{\|}
+\setlength\IndexMin{100pt}
+\begin{document}
+\DocInput{luamathalign.dtx}
+\PrintIndex
+\PrintChanges
+\end{document}
+%</driver>
+%<*gobble>
+\fi
+%</gobble>
+% \fi
+%
+% \GetFileInfo{luamathalign.dtx}
+% \title{The \pkg{luamathalign} package\thanks{This document
+%        corresponds to \pkg{luamathalign}~v0.1, dated~2022-04-18.}}
+% \author{Marcel Kr\"uger \\ \href{mailto:tex at 2krueger.de}{tex at 2krueger.de}}
+% 
+% \maketitle
+%
+% \begin{documentation}
+% \section{The problem}
+% In most cases, |amsmath| makes it simple to align multiple equations in a
+% |align| environment. But sometimes, special requirements come up.
+%
+% Maybe one of your alignment points is in an exponent, or in a radical?
+% The first attempts for such alignments often fail. For example, assume that
+% you want to align the following radicals like this (at the $x^3$ term):
+% \begin{align*}
+%   \sqrt{1-3x+3x^2+(\AlignHere x-1)^3}\\
+%   =\sqrt{1-3x+3x^2+{\AlignHere x}^3-3x^2+3x-1}\\
+%   =\sqrt{\AlignHere x^3}
+% \end{align*}
+% \enquote{Just adding \texttt{\&} at the alignment points} doesn't work:
+% \begin{verbatim}
+% \begin{align*}
+%   \sqrt{1-3x+3x^2+(&x-1)^3}\\
+%   =\sqrt{1-3x+3x^2+&x^3-3x^2+3x-1}\\
+%   =\sqrt{&x^3}
+% \end{align*}
+% \end{verbatim}
+% fails with
+% \begin{verbatim}
+% ! Missing } inserted.
+% <inserted text> 
+% }
+% l.73 \end{align*}
+% \end{verbatim}
+%
+% Another problem are nested alignments. Take this sample from \href{https://tex.stackexchange.com/questions/68547/alignment-across-nested-aligned-environments}{anonymous on \TeX\ -- \LaTeX\ StackExchange}: We want alignment like
+% \begin{align*}
+% aaaa &= 1  &&\text{for $X$} \\
+% bbbb &= 1  &&\text{for $Y$} \\
+% \left. \begin{aligned}
+%   c \SetAlignmentPoint1 &= 1 \\
+%   d &= 12
+% \end{aligned} \right\}\ExecuteAlignment1 &&\text{for $Z$}
+% \end{align*}
+% but in
+% \begin{verbatim}
+% \begin{align*}
+% aaaa &= 1  &&\text{for $X$} \\
+% bbbb &= 1  &&\text{for $Y$} \\
+% \left. \begin{aligned}
+%   c &= 1 \\
+%   d &= 12
+% \end{aligned} \right\}&&&\text{for $Z$}
+% \end{align*}
+% \end{verbatim}
+% there is not obvious way to align the equal signs in the nested |aligned| with the outer signs.
+% \section{The solution}
+% \pkg{luamathalign} provides solutions for both problems under Lua\LaTeX:
+% \begin{function}{\AlignHere}
+% The most important new macro is \cmd\AlignHere:
+% It generates an alignment point like \texttt{\&},
+% but it can be used almost everywhere.
+% 
+% So problems like our first example can be implemented by just using \cmd\AlignHere\ instead of \texttt{\&}:
+% \begin{verbatim}
+% \begin{align*}
+%   \sqrt{1-3x+3x^2+(\AlignHere x-1)^3}\\
+%   =\sqrt{1-3x+3x^2+{\AlignHere x}^3-3x^2+3x-1}\\
+%   =\sqrt{\AlignHere x^3}
+% \end{align*}
+% \end{verbatim}
+% \begin{align*}
+%   \sqrt{1-3x+3x^2+(\AlignHere x-1)^3}\\
+%   =\sqrt{1-3x+3x^2+{\AlignHere x}^3-3x^2+3x-1}\\
+%   =\sqrt{\AlignHere x^3}
+% \end{align*}
+% \end{function}
+% Sadly, this doesn't really help with the nested alignment problem:
+% Even if we use \cmd\AlignHere\ in the \env{aligned} environment, the alignment points
+% would be inserted in the inner and not in the outer alignment.
+% For such cases, there is a variant which allows to specify at which level the alignment should happen:
+% \begin{function}{\SetAlignmentPoint,\ExecuteAlignment}
+% The primary command for this is \cmd\SetAlignmentPoint\meta{number}. When called with a negative number it specifies the nesting level.
+% For example when \meta{number} is -1 it is the same as \cmd\AlignHere, while for -2 it is aligning one level higher and so on.
+%
+% For example, our nested alignment above wanted to align the inner \env{aligned} and the outer \env{align*} at the same point,
+% so |\SetAlignmentPoint-2| is used directly next to a inner alignment point (here |&|, \cmd\AlignHere\ would work too).
+% Then the \cmd\ExecuteAlignment\ has to appear in the context of the outer \env{align*}, so it can be written e.g. directly before the next |&| of the outer \env{align*}:
+% \begin{verbatim}
+% \begin{align*}
+% aaaa &= 1  &&\text{for $X$} \\
+% bbbb &= 1  &&\text{for $Y$} \\
+% \left. \begin{aligned}
+%   c \SetAlignmentPoint-2 &= 1 \\
+%   d &= 12
+% \end{aligned} \right\}&&\text{for $Z$}
+% \end{align*}
+% \end{verbatim}
+% \begin{align*}
+% aaaa &= 1  &&\text{for $X$} \\
+% bbbb &= 1  &&\text{for $Y$} \\
+% \left. \begin{aligned}
+%   c \SetAlignmentPoint-2 &= 1 \\
+%   d &= 12
+% \end{aligned} \right\}&&\text{for $Z$}
+% \end{align*}
+%
+% If you do not want to keep track of the right nesting level you can explicitly mark a level and refer to it.
+% To do so, use a non-negative \meta{number}.
+% When \cmd\SetAlignmentPoint\ is used with a non-negative \meta{number} then \cmd\ExecuteAlignment\meta{number}
+% must be executed afterwards with the same \meta{number} at a point where adding a |&| would add a valid alignment point at the right level.
+%
+% Our example above could therefore also be written as
+% \begin{verbatim}
+% \begin{align*}
+% aaaa &= 1  &&\text{for $X$} \\
+% bbbb &= 1  &&\text{for $Y$} \\
+% \left. \begin{aligned}
+%   c \SetAlignmentPoint0 &= 1 \\
+%   d &= 12
+% \end{aligned} \right\}\ExecuteAlignment0 &&\text{for $Z$}
+% \end{align*}
+% \end{verbatim}
+% \begin{align*}
+% aaaa &= 1  &&\text{for $X$} \\
+% bbbb &= 1  &&\text{for $Y$} \\
+% \left. \begin{aligned}
+%   c \SetAlignmentPoint0 &= 1 \\
+%   d &= 12
+% \end{aligned} \right\}\ExecuteAlignment0 &&\text{for $Z$}
+% \end{align*}
+%
+% This variant is also useful when working with custom alignment environment not prepared to work with luamathalign.
+% By default \cmd\SetAlignmentPoint\meta{number} with negative numbers (and therefore also \cmd\AlignHere) only work with
+% amsmath's \texttt{\{align\}}, \texttt{\{aligned\}} and their variants.
+% If you have another environment which also follows similar alignment rules then you can either restrict yourself to
+% non-negative \meta{number}s in combination with \cmd\ExecuteAlignment\ or patch these environments similar to what luamathalign does for amsmath.
+% \end{function}
+% \end{documentation}
+% \begin{implementation}
+% \section{The implementation}
+% \subsection{Lua}
+% \iffalse
+%<*gobble>
+\RequirePackage{docstrip-luacode}
+\begin{docstrip-luacode}{luamathalign}
+%</gobble>
+%<*lua>
+% \fi
+%    \begin{macrocode}
+local luacmd       = require'luamathalign-luacmd'
+local luaprop      = require'luamathalign-luaprop'('mathalign')
+local hlist        = node.id'hlist'
+local vlist        = node.id'vlist'
+local whatsit      = node.id'whatsit'
+local kern         = node.id'kern'
+local user_defined = node.subtype'user_defined'
+local whatsit_id   = luatexbase.new_whatsit'mathalign'
+local node_cmd     = token.command_id'node'
+local ampersand    = token.new(38, 4)
+-- We might want to add y later
+local function is_marked(mark, list)
+  for n in node.traverse(list) do
+    local id = n.id
+    if id == hlist or id == vlist then
+      if is_marked(mark, n.head) then return true end
+    elseif id == whatsit and n.subtype == user_defined
+        and n.user_id == whatsit_id and n.value == mark then
+      return true
+    end
+  end
+  return false
+end
+local function assert_unmarked(mark, list, ...)
+  local marked = is_marked(mark, list)
+  if marked then
+  tex.error("Multiple alignment marks", "I found multiple alignment marks \z
+      of type " .. mark .. " in an alignment where I already had an \z
+      alignment mark of that type. You should look at both of them and \z
+      decide which one is right. I will continue with the first one for now.")
+  end
+  return ...
+end
+local measure do
+  local vmeasure
+  local function hmeasure(mark, list)
+    local x, last = 0, list.head
+    for n in node.traverse(last) do
+      local id = n.id
+      if id == hlist then
+        local w, h, d = node.rangedimensions(list, last, n)
+        x, last = x + w, n
+        local dx = hmeasure(mark, n)
+        if dx then return assert_unmarked(mark, n.next, dx + x) end
+      elseif id == vlist then
+        local w, h, d = node.rangedimensions(list, last, n)
+        x, last = x + w, n
+        local dx = vmeasure(mark, n)
+        if dx then return assert_unmarked(mark, n.next, dx + x) end
+      elseif id == whatsit and n.subtype == user_defined
+          and n.user_id == whatsit_id and n.value == mark then
+        local w, h, d = node.rangedimensions(list, last, n)
+        local after
+        list.head, after = node.remove(list.head, n)
+        return assert_unmarked(mark, after, x + w)
+      end
+    end
+  end
+  function vmeasure(mark, list)
+    for n in node.traverse(list.head) do
+      local id = n.id
+      if id == hlist then
+        local dx = hmeasure(mark, n)
+        if dx then return assert_unmarked(mark, n.next, dx + n.shift) end
+      elseif id == vlist then
+        local dx = vmeasure(mark, n)
+        if dx then return assert_unmarked(mark, n.next, dx + n.shift) end
+      elseif id == whatsit and n.subtype == user_defined
+          and n.user_id == whatsit_id and n.value == mark then
+        local after
+        list.head, after = node.remove(list.head, n)
+        return assert_unmarked(mark, after, 0)
+      end
+    end
+  end
+  function measure(mark, head)
+    local x, last = 0, head
+    for n in node.traverse(last) do
+      local id = n.id
+      if id == hlist then
+        local w, h, d = node.dimensions(last, n)
+        x, last = x + w, n
+        local dx = hmeasure(mark, n)
+        if dx then return assert_unmarked(mark, n.next, head, dx + x) end
+      elseif id == vlist then
+        local w, h, d = node.dimensions(last, n)
+        x, last = x + w, n
+        local dx = vmeasure(mark, n)
+        if dx then return assert_unmarked(mark, n.next, head, dx + x) end
+      elseif id == whatsit and n.subtype == user_defined
+          and n.user_id == whatsit_id and n.value == mark then
+        local w, h, d = node.dimensions(last, n)
+        local after
+        head, after = node.remove(head, n)
+        return assert_unmarked(mark, after, head, x + w)
+      end
+    end
+    return head
+  end
+end
+
+local isolate do
+  local visolate
+  local function hisolate(list, offset)
+    local x, last = 0, list.head
+    local newhead, newtail = nil, nil
+    local n = last
+    while n do
+      local id = n.id
+      if id == hlist then
+        local w, h, d = node.rangedimensions(list, last, n)
+        x, last = x + w, n
+        local inner_head, inner_tail, new_offset = hisolate(n, offset - x)
+        if inner_head then
+          if newhead then
+            newtail.next, inner_head.prev = inner_head, newtail
+          else
+            newhead = inner_head
+          end
+          newtail = inner_tail
+          offset = x + new_offset
+        end
+        n = n.next
+      elseif id == vlist then
+        local w, h, d = node.rangedimensions(list, last, n)
+        x, last = x + w, n
+        local inner_head, inner_tail, new_offset = visolate(n, offset - x)
+        if inner_head then
+          if newhead then
+            newtail.next, inner_head.prev = inner_head, newtail
+          else
+            newhead = inner_head
+          end
+          newtail = inner_tail
+          offset = x + new_offset
+        end
+        n = n.next
+      elseif id == whatsit and n.subtype == user_defined
+          and n.user_id == whatsit_id then
+        local w, h, d = node.rangedimensions(list, last, n)
+        x = x + w
+        list.head, last = node.remove(list.head, n)
+        if x ~= offset  then
+          local k = node.new(kern)
+          k.kern, offset = x - offset, x
+          newhead, newtail = node.insert_after(newhead, newtail, k)
+        end
+        newhead, newtail = node.insert_after(newhead, newtail, n)
+        n = last
+      else
+        n = n.next
+      end
+    end
+    return newhead, newtail, offset
+  end
+  function visolate(list, offset)
+    local newhead, newtail = nil, nil
+    local n = list.head
+    while n do
+      local id = n.id
+      if id == hlist then
+        if dx then return assert_unmarked(mark, n.next, dx + n.shift) end
+        local inner_head, inner_tail, new_offset = hisolate(n, offset)
+        if inner_head then
+          if newhead then
+            newtail.next, inner_head.prev = inner_head, newtail
+          else
+            newhead = inner_head
+          end
+          newtail = inner_tail
+          offset = new_offset
+        end
+        n = n.next
+      elseif id == vlist then
+        if dx then return assert_unmarked(mark, n.next, dx + n.shift) end
+        local inner_head, inner_tail, new_offset = visolate(n, offset)
+        if inner_head then
+          if newhead then
+            newtail.next, inner_head.prev = inner_head, newtail
+          else
+            newhead = inner_head
+          end
+          newtail = inner_tail
+          offset = new_offset
+        end
+        n = n.next
+      elseif id == whatsit and n.subtype == user_defined
+          and n.user_id == whatsit_id then
+        local after
+        list.head, after = node.remove(list.head, n)
+        if 0 ~= offset  then
+          local k = node.new(kern)
+          k.kern, offset = -offset, 0
+          newhead, newtail = node.insert_after(newhead, newtail, k)
+        end
+        newhead, newtail = node.insert_after(newhead, newtail, n)
+        n = last
+      else
+        n = n.next
+      end
+    end
+    return newhead, newtail, offset
+  end
+  function isolate(head)
+    local x, last = 0, head
+    local newhead, newtail, offset = nil, nil, 0
+    local n = last
+    while n do
+      local id = n.id
+      if id == hlist then
+        local w, h, d = node.dimensions(last, n)
+        x, last = x + w, n
+        local inner_head, inner_tail, new_offset = hisolate(n, offset - x)
+        if inner_head then
+          if newhead then
+            newtail.next, inner_head.prev = inner_head, newtail
+          else
+            newhead = inner_head
+          end
+          newtail = inner_tail
+          offset = x + new_offset
+        end
+        n = n.next
+      elseif id == vlist then
+        local w, h, d = node.dimensions(last, n)
+        x, last = x + w, n
+        local inner_head, inner_tail, new_offset = visolate(n, offset - x)
+        if inner_head then
+          if newhead then
+            newtail.next, inner_head.prev = inner_head, newtail
+          else
+            newhead = inner_head
+          end
+          newtail = inner_tail
+          offset = x + new_offset
+        end
+        n = n.next
+      elseif id == whatsit and n.subtype == user_defined
+          and n.user_id == whatsit_id then
+        local w, h, d = node.dimensions(last, n)
+        x = x + w
+        head, last = node.remove(head, n)
+        if x ~= offset  then
+          local k = node.new(kern)
+          k.kern, offset = x - offset, x
+          newhead, newtail = node.insert_after(newhead, newtail, k)
+        end
+        newhead, newtail = node.insert_after(newhead, newtail, n)
+        n = last
+      else
+        n = n.next
+      end
+    end
+    return head, newhead
+  end
+end
+
+local mark, afterkern
+luatexbase.add_to_callback('post_mlist_to_hlist_filter', function(n)
+  if mark then
+    local x
+    n, x = measure(mark, n)
+    local k = node.new'kern'
+    local off = x - n.width
+    k.kern, afterkern.kern = off, -off
+    node.insert_after(n.head, nil, k)
+    n.width = x
+    mark, afterkern = nil, nil
+  end
+  return n
+end, 'luamathalign')
+
+local function get_kerntoken(newmark)
+  assert(not mark)
+  mark, afterkern = newmark, node.new'kern'
+  return token.new(node.direct.todirect(afterkern), node_cmd)
+end
+
+local function insert_whatsit(mark)
+  local n = node.new(whatsit, user_defined)
+  n.user_id, n.type, n.value = whatsit_id, string.byte'd', mark
+  node.write(n)
+end
+luacmd("SetAlignmentPoint", function()
+  local mark = token.scan_int()
+  if mark < 0 then
+    for i=tex.nest.ptr,0,-1 do
+      local t = tex.nest[i].head
+      if luaprop.query(t) ~= nil then
+        mark = mark + 1
+        if mark == 0 then
+          luaprop.set(t, true)
+          return insert_whatsit(-i)
+        end
+      end
+    end
+    tex.error('No compatible alignment environment found',
+      'This either means that \\SetAlignmentPoint was used outside\n\z
+      of an alignment or the used alignment is not setup for use with\n\z
+      luamathalign. In the latter case you might want to look at\n\z
+      non-negative alignment marks.')
+  else
+    return insert_whatsit(mark)
+  end
+end, "protected")
+
+function handle_whatsit(mark)
+  token.put_next(ampersand, get_kerntoken(mark))
+end
+luacmd("ExecuteAlignment", function()
+  return handle_whatsit(token.scan_int())
+end, "protected")
+
+luacmd("LuaMathAlign at begin", function()
+  local nest = tex.nest.top
+  luaprop.set(nest.head, false)
+end, "protected")
+luacmd("LuaMathAlign at end@early", function()
+  local t = tex.nest.top.head
+  if luaprop.set(t, nil) == true then
+    handle_whatsit(-tex.nest.ptr)
+  end
+end, "protected")
+local delayed
+luacmd("LuaMathAlign at end", function()
+  local nest = tex.nest.top
+  local t = nest.head
+  if luaprop.set(t, nil) == true then
+    assert(not delayed)
+    delayed = {get_kerntoken(-tex.nest.ptr), ampersand}
+  end
+end, "protected")
+luatexbase.add_to_callback("hpack_filter", function(head, groupcode)
+  if delayed and groupcode == "align_set" then
+-- HACK: token.put_next puts the tokens into the input stream after the cell
+-- is fully read, before the next starts. This will act as if the content was
+-- written as the first element of the next field.
+    token.put_next(delayed)
+    delayed = nil
+  end
+  return true
+end, "luamathalign.delayed")
+
+luacmd("LuaMathAlign at IsolateAlignmentPoints", function()
+  local main = token.scan_int()
+  if not token.scan_keyword 'into' then
+  tex.error'Expected "into"'
+  end
+  local marks = token.scan_int()
+  local head, newhead = isolate(tex.box[main])
+  tex.box[marks] = node.direct.tonode(node.direct.hpack(
+      newhead and node.direct.todirect(newhead) or 0))
+end, "protected")
+%    \end{macrocode}
+% \subsection{LaTeX}
+% \iffalse
+%</lua>
+%<*gobble>
+\end{docstrip-luacode}
+%</gobble>
+%<*package>
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage
+  {luamathalign}
+  [2022-04-18 v0.1 additional math alignment tricks using Lua]
+% \fi
+% The actual \LaTeX\ package just loads the Lua module and patches \pkg{amsmath}:
+%    \begin{macrocode}
+% \RequirePackage{scrlfile}
+\directlua{require'luamathalign'}
+\IfPackageLoadedTF{amsmath}{%
+  \@firstofone
+}{%
+  \AddToHook{package/amsmath/after}
+}
+{%
+  \def\align at preamble{%
+     &\hfil
+      \strut@
+      \setboxz at h{\@lign$\m at th\displaystyle{%
+          \LuaMathAlign at begin##\LuaMathAlign at end}$}%
+      \ifmeasuring@\savefieldlength@\fi
+      \set at field
+      \tabskip\z at skip
+     &\setboxz at h{\@lign$\m at th\displaystyle{{}##}$}%
+      \ifmeasuring@\savefieldlength@\fi
+      \set at field
+      \hfil
+      \tabskip\alignsep@
+  }
+  \renewcommand{\start at aligned}[2]{%
+    \RIfM@\else
+        \nonmatherr@{\begin{\@currenvir}}%
+    \fi
+    \savecolumn@ % Assumption: called inside a group
+    \alignedspace at left
+    \if #1t\vtop \else \if#1b \vbox \else \vcenter \fi \fi \bgroup
+        \maxfields@#2\relax
+        \ifnum\maxfields@>\m at ne
+            \multiply\maxfields@\tw@
+            \let\math at cr@@@\math at cr@@@alignedat
+            \alignsep@\z at skip
+        \else
+            \let\math at cr@@@\math at cr@@@aligned
+            \alignsep@\minalignsep
+        \fi
+        \Let@ \chardef\dspbrk at context\@ne
+        \default at tag
+        \spread at equation % no-op if already called
+        \global\column@\z@
+        \ialign\bgroup
+           &\column at plus
+            \hfil
+            \strut@
+            $\m at th\displaystyle{\LuaMathAlign at begin##\LuaMathAlign at end}$%
+            \tabskip\z at skip
+           &\column at plus
+            $\m at th\displaystyle{{}##}$%
+            \hfil
+            \tabskip\alignsep@
+            \crcr
+  }
+  \edef\math at cr@@@alignedat{\LuaMathAlign at end@early
+    \unexpanded\expandafter{\math at cr@@@alignedat}}
+  \edef\math at cr{\LuaMathAlign at end@early
+    \unexpanded\expandafter{\math at cr}}
+  \edef\endaligned{\LuaMathAlign at end@early
+    \unexpanded\expandafter{\endaligned}}
+}
+\protected\def\AlignHere{\SetAlignmentPoint\m at ne}
+\begingroup
+  \def\patch at finph@nt\setbox\tw@\null{%
+    \LuaMathAlign at IsolateAlignmentPoints\z@ into \tw@
+  }%
+\expanded{\endgroup%
+\protected\def\noexpand\finph at nt{%
+  \unexpanded\expandafter\expandafter\expandafter{%
+    \expandafter\patch at finph@nt\finph at nt
+  }%
+}}
+\ExplSyntaxOff
+%    \end{macrocode}
+% \iffalse
+%</package>
+% \fi
+% \end{implementation}
+\endinput


Property changes on: trunk/Master/texmf-dist/source/lualatex/luamathalign/luamathalign.dtx
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/lualatex/luamathalign/build.lua
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/luamathalign/build.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/lualatex/luamathalign/build.lua	2022-04-19 20:10:27 UTC (rev 63081)
@@ -0,0 +1,21 @@
+module = "luamathalign"
+typesetexe = "lualatex"
+tdsroot = "lualatex"
+checkengines = {"luatex"}
+unpackfiles = {"*.dtx"}
+installfiles = {"*.sty", "*.lua"}
+sourcefiles = {"*.dtx", "*.lua"}
+
+uploadconfig = {
+  pkg = "luamathalign",
+  version = "v0.1",
+  author = "Marcel Krüger",
+  license = "lppl1.3c",
+  summary = "More flexible alignment in amsmath environments",
+  ctanPath = "/macros/luatex/latex/luamathalign/",
+  -- repository = "https://github.com/zauguin/luamathalign/"
+  description = "Allow aligning mathematical expressions on points where \z
+    where direcly using & is not possible, especially in nested macros or environments.",
+  topic = {'maths', 'luatex'},
+  -- update = true,
+}


Property changes on: trunk/Master/texmf-dist/tex/lualatex/luamathalign/build.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign-luacmd.lua
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign-luacmd.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign-luacmd.lua	2022-04-19 20:10:27 UTC (rev 63081)
@@ -0,0 +1,19 @@
+----Copyright (C) 2019--2022 by Marcel Krueger
+---
+--- This file may be distributed and/or modified under the
+--- conditions of the LaTeX Project Public License, either
+--- version 1.3c of this license or (at your option) any later
+--- version. The latest version of this license is in:
+---
+--- http://www.latex-project.org/lppl.txt
+---
+--- and version 1.3 or later is part of all distributions of
+--- LaTeX version 2005/12/01 or later.
+local func_tbl = lua.get_functions_table()
+local set_lua = token.set_lua
+local new_luafunction = luatexbase.new_luafunction
+return function(name, func, ...)
+  local idx = new_luafunction(name)
+  set_lua(name, idx, ...)
+  func_tbl[idx] = func
+end


Property changes on: trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign-luacmd.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign-luaprop.lua
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign-luaprop.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign-luaprop.lua	2022-04-19 20:10:27 UTC (rev 63081)
@@ -0,0 +1,42 @@
+----Copyright (C) 2019--2022 by Marcel Krueger
+---
+--- This file may be distributed and/or modified under the
+--- conditions of the LaTeX Project Public License, either
+--- version 1.3c of this license or (at your option) any later
+--- version. The latest version of this license is in:
+---
+--- http://www.latex-project.org/lppl.txt
+---
+--- and version 1.3 or later is part of all distributions of
+--- LaTeX version 2005/12/01 or later.
+return function(namespace)
+  return {
+    query = function(n)
+      local p = node.getproperty(n)
+      return p and p[namespace]
+    end,
+    get = function(n, ...)
+      local p = node.getproperty(n)
+      if not p then
+        p = {}
+        node.setproperty(n, p)
+      end
+      local n = p[namespace]
+      if nil == p[namespace] then
+        local d = select('#', ...) ~= 0 and ... or {}
+        n, p[namespace] = d, d
+      end
+      return n
+    end,
+    set = function(n, v)
+      local p = node.getproperty(n)
+      if not p then
+        p = {}
+        node.setproperty(n, p)
+      end
+      local old = p[namespace]
+      p[namespace] = v
+      return old
+    end,
+  }
+end


Property changes on: trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign-luaprop.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign.lua
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign.lua	2022-04-19 20:10:27 UTC (rev 63081)
@@ -0,0 +1,375 @@
+--
+-- This is file `luamathalign.lua',
+-- generated with the docstrip utility.
+--
+-- The original source files were:
+--
+-- luamathalign.dtx  (with options: `lua')
+-- 
+-- Copyright (C) 2019--2022 by Marcel Krueger
+--
+-- This file may be distributed and/or modified under the
+-- conditions of the LaTeX Project Public License, either
+-- version 1.3c of this license or (at your option) any later
+-- version. The latest version of this license is in:
+--
+-- http://www.latex-project.org/lppl.txt
+--
+-- and version 1.3 or later is part of all distributions of
+-- LaTeX version 2005/12/01 or later.
+local luacmd       = require'luamathalign-luacmd'
+local luaprop      = require'luamathalign-luaprop'('mathalign')
+local hlist        = node.id'hlist'
+local vlist        = node.id'vlist'
+local whatsit      = node.id'whatsit'
+local kern         = node.id'kern'
+local user_defined = node.subtype'user_defined'
+local whatsit_id   = luatexbase.new_whatsit'mathalign'
+local node_cmd     = token.command_id'node'
+local ampersand    = token.new(38, 4)
+-- We might want to add y later
+local function is_marked(mark, list)
+  for n in node.traverse(list) do
+    local id = n.id
+    if id == hlist or id == vlist then
+      if is_marked(mark, n.head) then return true end
+    elseif id == whatsit and n.subtype == user_defined
+        and n.user_id == whatsit_id and n.value == mark then
+      return true
+    end
+  end
+  return false
+end
+local function assert_unmarked(mark, list, ...)
+  local marked = is_marked(mark, list)
+  if marked then
+  tex.error("Multiple alignment marks", "I found multiple alignment marks \z
+      of type " .. mark .. " in an alignment where I already had an \z
+      alignment mark of that type. You should look at both of them and \z
+      decide which one is right. I will continue with the first one for now.")
+  end
+  return ...
+end
+local measure do
+  local vmeasure
+  local function hmeasure(mark, list)
+    local x, last = 0, list.head
+    for n in node.traverse(last) do
+      local id = n.id
+      if id == hlist then
+        local w, h, d = node.rangedimensions(list, last, n)
+        x, last = x + w, n
+        local dx = hmeasure(mark, n)
+        if dx then return assert_unmarked(mark, n.next, dx + x) end
+      elseif id == vlist then
+        local w, h, d = node.rangedimensions(list, last, n)
+        x, last = x + w, n
+        local dx = vmeasure(mark, n)
+        if dx then return assert_unmarked(mark, n.next, dx + x) end
+      elseif id == whatsit and n.subtype == user_defined
+          and n.user_id == whatsit_id and n.value == mark then
+        local w, h, d = node.rangedimensions(list, last, n)
+        local after
+        list.head, after = node.remove(list.head, n)
+        return assert_unmarked(mark, after, x + w)
+      end
+    end
+  end
+  function vmeasure(mark, list)
+    for n in node.traverse(list.head) do
+      local id = n.id
+      if id == hlist then
+        local dx = hmeasure(mark, n)
+        if dx then return assert_unmarked(mark, n.next, dx + n.shift) end
+      elseif id == vlist then
+        local dx = vmeasure(mark, n)
+        if dx then return assert_unmarked(mark, n.next, dx + n.shift) end
+      elseif id == whatsit and n.subtype == user_defined
+          and n.user_id == whatsit_id and n.value == mark then
+        local after
+        list.head, after = node.remove(list.head, n)
+        return assert_unmarked(mark, after, 0)
+      end
+    end
+  end
+  function measure(mark, head)
+    local x, last = 0, head
+    for n in node.traverse(last) do
+      local id = n.id
+      if id == hlist then
+        local w, h, d = node.dimensions(last, n)
+        x, last = x + w, n
+        local dx = hmeasure(mark, n)
+        if dx then return assert_unmarked(mark, n.next, head, dx + x) end
+      elseif id == vlist then
+        local w, h, d = node.dimensions(last, n)
+        x, last = x + w, n
+        local dx = vmeasure(mark, n)
+        if dx then return assert_unmarked(mark, n.next, head, dx + x) end
+      elseif id == whatsit and n.subtype == user_defined
+          and n.user_id == whatsit_id and n.value == mark then
+        local w, h, d = node.dimensions(last, n)
+        local after
+        head, after = node.remove(head, n)
+        return assert_unmarked(mark, after, head, x + w)
+      end
+    end
+    return head
+  end
+end
+
+local isolate do
+  local visolate
+  local function hisolate(list, offset)
+    local x, last = 0, list.head
+    local newhead, newtail = nil, nil
+    local n = last
+    while n do
+      local id = n.id
+      if id == hlist then
+        local w, h, d = node.rangedimensions(list, last, n)
+        x, last = x + w, n
+        local inner_head, inner_tail, new_offset = hisolate(n, offset - x)
+        if inner_head then
+          if newhead then
+            newtail.next, inner_head.prev = inner_head, newtail
+          else
+            newhead = inner_head
+          end
+          newtail = inner_tail
+          offset = x + new_offset
+        end
+        n = n.next
+      elseif id == vlist then
+        local w, h, d = node.rangedimensions(list, last, n)
+        x, last = x + w, n
+        local inner_head, inner_tail, new_offset = visolate(n, offset - x)
+        if inner_head then
+          if newhead then
+            newtail.next, inner_head.prev = inner_head, newtail
+          else
+            newhead = inner_head
+          end
+          newtail = inner_tail
+          offset = x + new_offset
+        end
+        n = n.next
+      elseif id == whatsit and n.subtype == user_defined
+          and n.user_id == whatsit_id then
+        local w, h, d = node.rangedimensions(list, last, n)
+        x = x + w
+        list.head, last = node.remove(list.head, n)
+        if x ~= offset  then
+          local k = node.new(kern)
+          k.kern, offset = x - offset, x
+          newhead, newtail = node.insert_after(newhead, newtail, k)
+        end
+        newhead, newtail = node.insert_after(newhead, newtail, n)
+        n = last
+      else
+        n = n.next
+      end
+    end
+    return newhead, newtail, offset
+  end
+  function visolate(list, offset)
+    local newhead, newtail = nil, nil
+    local n = list.head
+    while n do
+      local id = n.id
+      if id == hlist then
+        if dx then return assert_unmarked(mark, n.next, dx + n.shift) end
+        local inner_head, inner_tail, new_offset = hisolate(n, offset)
+        if inner_head then
+          if newhead then
+            newtail.next, inner_head.prev = inner_head, newtail
+          else
+            newhead = inner_head
+          end
+          newtail = inner_tail
+          offset = new_offset
+        end
+        n = n.next
+      elseif id == vlist then
+        if dx then return assert_unmarked(mark, n.next, dx + n.shift) end
+        local inner_head, inner_tail, new_offset = visolate(n, offset)
+        if inner_head then
+          if newhead then
+            newtail.next, inner_head.prev = inner_head, newtail
+          else
+            newhead = inner_head
+          end
+          newtail = inner_tail
+          offset = new_offset
+        end
+        n = n.next
+      elseif id == whatsit and n.subtype == user_defined
+          and n.user_id == whatsit_id then
+        local after
+        list.head, after = node.remove(list.head, n)
+        if 0 ~= offset  then
+          local k = node.new(kern)
+          k.kern, offset = -offset, 0
+          newhead, newtail = node.insert_after(newhead, newtail, k)
+        end
+        newhead, newtail = node.insert_after(newhead, newtail, n)
+        n = last
+      else
+        n = n.next
+      end
+    end
+    return newhead, newtail, offset
+  end
+  function isolate(head)
+    local x, last = 0, head
+    local newhead, newtail, offset = nil, nil, 0
+    local n = last
+    while n do
+      local id = n.id
+      if id == hlist then
+        local w, h, d = node.dimensions(last, n)
+        x, last = x + w, n
+        local inner_head, inner_tail, new_offset = hisolate(n, offset - x)
+        if inner_head then
+          if newhead then
+            newtail.next, inner_head.prev = inner_head, newtail
+          else
+            newhead = inner_head
+          end
+          newtail = inner_tail
+          offset = x + new_offset
+        end
+        n = n.next
+      elseif id == vlist then
+        local w, h, d = node.dimensions(last, n)
+        x, last = x + w, n
+        local inner_head, inner_tail, new_offset = visolate(n, offset - x)
+        if inner_head then
+          if newhead then
+            newtail.next, inner_head.prev = inner_head, newtail
+          else
+            newhead = inner_head
+          end
+          newtail = inner_tail
+          offset = x + new_offset
+        end
+        n = n.next
+      elseif id == whatsit and n.subtype == user_defined
+          and n.user_id == whatsit_id then
+        local w, h, d = node.dimensions(last, n)
+        x = x + w
+        head, last = node.remove(head, n)
+        if x ~= offset  then
+          local k = node.new(kern)
+          k.kern, offset = x - offset, x
+          newhead, newtail = node.insert_after(newhead, newtail, k)
+        end
+        newhead, newtail = node.insert_after(newhead, newtail, n)
+        n = last
+      else
+        n = n.next
+      end
+    end
+    return head, newhead
+  end
+end
+
+local mark, afterkern
+luatexbase.add_to_callback('post_mlist_to_hlist_filter', function(n)
+  if mark then
+    local x
+    n, x = measure(mark, n)
+    local k = node.new'kern'
+    local off = x - n.width
+    k.kern, afterkern.kern = off, -off
+    node.insert_after(n.head, nil, k)
+    n.width = x
+    mark, afterkern = nil, nil
+  end
+  return n
+end, 'luamathalign')
+
+local function get_kerntoken(newmark)
+  assert(not mark)
+  mark, afterkern = newmark, node.new'kern'
+  return token.new(node.direct.todirect(afterkern), node_cmd)
+end
+
+local function insert_whatsit(mark)
+  local n = node.new(whatsit, user_defined)
+  n.user_id, n.type, n.value = whatsit_id, string.byte'd', mark
+  node.write(n)
+end
+luacmd("SetAlignmentPoint", function()
+  local mark = token.scan_int()
+  if mark < 0 then
+    for i=tex.nest.ptr,0,-1 do
+      local t = tex.nest[i].head
+      if luaprop.query(t) ~= nil then
+        mark = mark + 1
+        if mark == 0 then
+          luaprop.set(t, true)
+          return insert_whatsit(-i)
+        end
+      end
+    end
+    tex.error('No compatible alignment environment found',
+      'This either means that \\SetAlignmentPoint was used outside\n\z
+      of an alignment or the used alignment is not setup for use with\n\z
+      luamathalign. In the latter case you might want to look at\n\z
+      non-negative alignment marks.')
+  else
+    return insert_whatsit(mark)
+  end
+end, "protected")
+
+function handle_whatsit(mark)
+  token.put_next(ampersand, get_kerntoken(mark))
+end
+luacmd("ExecuteAlignment", function()
+  return handle_whatsit(token.scan_int())
+end, "protected")
+
+luacmd("LuaMathAlign at begin", function()
+  local nest = tex.nest.top
+  luaprop.set(nest.head, false)
+end, "protected")
+luacmd("LuaMathAlign at end@early", function()
+  local t = tex.nest.top.head
+  if luaprop.set(t, nil) == true then
+    handle_whatsit(-tex.nest.ptr)
+  end
+end, "protected")
+local delayed
+luacmd("LuaMathAlign at end", function()
+  local nest = tex.nest.top
+  local t = nest.head
+  if luaprop.set(t, nil) == true then
+    assert(not delayed)
+    delayed = {get_kerntoken(-tex.nest.ptr), ampersand}
+  end
+end, "protected")
+luatexbase.add_to_callback("hpack_filter", function(head, groupcode)
+  if delayed and groupcode == "align_set" then
+-- HACK: token.put_next puts the tokens into the input stream after the cell
+-- is fully read, before the next starts. This will act as if the content was
+-- written as the first element of the next field.
+    token.put_next(delayed)
+    delayed = nil
+  end
+  return true
+end, "luamathalign.delayed")
+
+luacmd("LuaMathAlign at IsolateAlignmentPoints", function()
+  local main = token.scan_int()
+  if not token.scan_keyword 'into' then
+  tex.error'Expected "into"'
+  end
+  local marks = token.scan_int()
+  local head, newhead = isolate(tex.box[main])
+  tex.box[marks] = node.direct.tonode(node.direct.hpack(
+      newhead and node.direct.todirect(newhead) or 0))
+end, "protected")
+-- 
+--
+-- End of file `luamathalign.lua'.


Property changes on: trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign.sty
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign.sty	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign.sty	2022-04-19 20:10:27 UTC (rev 63081)
@@ -0,0 +1,98 @@
+%%
+%% This is file `luamathalign.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% luamathalign.dtx  (with options: `package')
+%% 
+%% Copyright (C) 2019--2022 by Marcel Krueger
+%%
+%% This file may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either
+%% version 1.3c of this license or (at your option) any later
+%% version. The latest version of this license is in:
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% and version 1.3 or later is part of all distributions of
+%% LaTeX version 2005/12/01 or later.
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage
+  {luamathalign}
+  [2022-04-18 v0.1 additional math alignment tricks using Lua]
+\directlua{require'luamathalign'}
+\IfPackageLoadedTF{amsmath}{%
+  \@firstofone
+}{%
+  \AddToHook{package/amsmath/after}
+}
+{%
+  \def\align at preamble{%
+     &\hfil
+      \strut@
+      \setboxz at h{\@lign$\m at th\displaystyle{%
+          \LuaMathAlign at begin##\LuaMathAlign at end}$}%
+      \ifmeasuring@\savefieldlength@\fi
+      \set at field
+      \tabskip\z at skip
+     &\setboxz at h{\@lign$\m at th\displaystyle{{}##}$}%
+      \ifmeasuring@\savefieldlength@\fi
+      \set at field
+      \hfil
+      \tabskip\alignsep@
+  }
+  \renewcommand{\start at aligned}[2]{%
+    \RIfM@\else
+        \nonmatherr@{\begin{\@currenvir}}%
+    \fi
+    \savecolumn@ % Assumption: called inside a group
+    \alignedspace at left
+    \if #1t\vtop \else \if#1b \vbox \else \vcenter \fi \fi \bgroup
+        \maxfields@#2\relax
+        \ifnum\maxfields@>\m at ne
+            \multiply\maxfields@\tw@
+            \let\math at cr@@@\math at cr@@@alignedat
+            \alignsep@\z at skip
+        \else
+            \let\math at cr@@@\math at cr@@@aligned
+            \alignsep@\minalignsep
+        \fi
+        \Let@ \chardef\dspbrk at context\@ne
+        \default at tag
+        \spread at equation % no-op if already called
+        \global\column@\z@
+        \ialign\bgroup
+           &\column at plus
+            \hfil
+            \strut@
+            $\m at th\displaystyle{\LuaMathAlign at begin##\LuaMathAlign at end}$%
+            \tabskip\z at skip
+           &\column at plus
+            $\m at th\displaystyle{{}##}$%
+            \hfil
+            \tabskip\alignsep@
+            \crcr
+  }
+  \edef\math at cr@@@alignedat{\LuaMathAlign at end@early
+    \unexpanded\expandafter{\math at cr@@@alignedat}}
+  \edef\math at cr{\LuaMathAlign at end@early
+    \unexpanded\expandafter{\math at cr}}
+  \edef\endaligned{\LuaMathAlign at end@early
+    \unexpanded\expandafter{\endaligned}}
+}
+\protected\def\AlignHere{\SetAlignmentPoint\m at ne}
+\begingroup
+  \def\patch at finph@nt\setbox\tw@\null{%
+    \LuaMathAlign at IsolateAlignmentPoints\z@ into \tw@
+  }%
+\expanded{\endgroup%
+\protected\def\noexpand\finph at nt{%
+  \unexpanded\expandafter\expandafter\expandafter{%
+    \expandafter\patch at finph@nt\finph at nt
+  }%
+}}
+\ExplSyntaxOff
+\endinput
+%%
+%% End of file `luamathalign.sty'.


Property changes on: trunk/Master/texmf-dist/tex/lualatex/luamathalign/luamathalign.sty
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/tlpkg/bin/tlpkg-ctan-check
===================================================================
--- trunk/Master/tlpkg/bin/tlpkg-ctan-check	2022-04-19 20:06:58 UTC (rev 63080)
+++ trunk/Master/tlpkg/bin/tlpkg-ctan-check	2022-04-19 20:10:27 UTC (rev 63081)
@@ -500,7 +500,7 @@
     luabibentry luabidi luacensor luacode luacolor luafindfont luahyphenrules
     luaimageembed luaindex luainputenc luaintro luakeys
     lualatex-doc lualatex-doc-de
-    lualatex-math lualatex-truncate lualibs
+    lualatex-math lualatex-truncate lualibs luamathalign
     luamesh luamplib luaotfload luapackageloader luaprogtable luapstricks
     luarandom
     luasseq luatex85 luatexbase luatexja luatexko luatextra

Modified: trunk/Master/tlpkg/libexec/ctan2tds
===================================================================
--- trunk/Master/tlpkg/libexec/ctan2tds	2022-04-19 20:06:58 UTC (rev 63080)
+++ trunk/Master/tlpkg/libexec/ctan2tds	2022-04-19 20:10:27 UTC (rev 63081)
@@ -2121,6 +2121,7 @@
  'luaintro',    'NULL',         # doc pkg
  'luakeys',	'\.lua|luakeys\.tex|' . $standardtex,
  'lualatex-math', '\.sty',      # not phst-doc.cls
+ 'luamathalign','luam.*\.lua|' . $standardtex,	# not build.lua
  'luamesh',	'\.sty',        # not lltxdoc.cls
  'luapackageloader', '\.lua|' . $standardtex,
  'luaprogtable','\.lua|' . $standardtex,
@@ -3082,6 +3083,7 @@
  'lua-typo'	=> 'etex',
  'lua-ul'	=> 'etex-answer-y',	# https://github.com/latex3/latex2e/issues/558
  'luaindex'     => 'lualatex --shell-escape',
+ 'luamathalign'	=> 'etex',
  'luatexja'     => 'lualatex',
  'makelabels'	=> 'tex --8bit',
  'mandi'	=> 'pdflatex-preserve-pdf',

Modified: trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc	2022-04-19 20:06:58 UTC (rev 63080)
+++ trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc	2022-04-19 20:10:27 UTC (rev 63081)
@@ -44,6 +44,7 @@
 depend lualatex-math
 depend lualatex-truncate
 depend lualibs
+depend luamathalign
 depend luamplib
 depend luaotfload
 depend luapackageloader

Added: trunk/Master/tlpkg/tlpsrc/luamathalign.tlpsrc
===================================================================


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