LuaTeX: Markieren Sie mathematische Grenzen, ohne die Satzausgabe zu beeinflussen (sowohl Form als auch Leerzeichen).

Nov 21 2020

Wie aus den Antworten auf meine vorherige Frage hervorgeht , sind mathematische Grenzknoten keine zuverlässige Methode zum Markieren von mathematischen Grenzen. Es gibt zwei mögliche Problemumgehungen, mit denen Grenzen markiert werden können: 1) Hinzufügen benutzerdefinierter Whatsit-Knoten um die Mathematikliste, 2) Definieren und Festlegen eines "Mathematik" -Attributs für Knoten in der Mathematikliste. Eine solche Markierung der Grenze kann in vielerlei Hinsicht nützlich sein, um die Knotenliste nach dem Brechen von Linien durch TeX nachzubearbeiten: a) Fügen Sie Trennzeichen vom Typ <beginmath> <endmath> hinzu, während Sie versuchen, Text zu extrahieren. B) selektives Färben von Text und Mathematik, c) usw. a) kann auch zusammen mit "alternativem Text" verwendet werden, der hinzugefügt wird, um den Wert zu beginnen, um eine alternative / Textbeschreibung der Gleichung bereitzustellen.

In Bezug auf Ansatz 1) heißt es im LuaTeX-Dokument: "Die LuaTEX-Engine wird einfach über solche Whatsits hinweggehen, ohne jemals den Inhalt zu betrachten." Es gibt jedoch Beiträge, die darauf hinweisen, dass Whatsits die Ausgabe von Mikrotypografie, Zeilenumbruch und Seitenumbruch beeinflussen können: Link zu einem Beitrag , der den betroffenen Seitenumbruch anzeigt, und Link zu einem Beitrag , der die betroffene Mikrotypografie zeigt (was auch den Zeilenumbruch in TeX beeinflussen kann).

Bei gegebenem Ansatz 2) muss der gesamte Inhalt der mathematischen Liste durchlaufen werden. Dies wäre langsamer als bei 1), wenn der Filter mlist_to_hlist verwendet wird. (Es sei denn, es $<tex_equation>$kann wahrscheinlich sicher neu definiert werden, um ein Attribut vor und nach dem $Trennzeichen festzulegen und zu deaktivieren , obwohl es mehr solche Trennzeichen gibt ...). Die Frage ist also, wie man mit Ansatz 1) die mathematische Grenze so markieren kann, dass sie die Mikrotypografie, den Zeilenumbruch und den Seitenumbruch wirklich nicht beeinflusst. Oder ist Ansatz 2) die einzig sichere Wette?

Hier ist mein erster Versuch für Inline-Mathematik. Ich suche eine Expertenbewertung und eine Erweiterung für Anzeigemathematik (Ausrichten usw.-Umgebungen).

Code:

% >>> lualatex mathmode.tex
\documentclass{article}
\usepackage[callback={}]{nodetree}

\begin{document}

\directlua{
local function mathboundary(h,d,p)
    local beginmath = node.new("whatsit","user_defined")
    beginmath.type = string.byte("s")
    beginmath.value = "beginmath"
    beginmath.attr = h.attr
    beginmath.user_id = luatexbase.new_whatsit'beginmath'
    local endmath = node.new("whatsit","user_defined")
    endmath.type = string.byte("s")
    endmath.value = "endmath"
    endmath.attr = h.attr
    endmath.user_id = luatexbase.new_whatsit'endmath'
    h = node.insert_after(h,node.tail(h),endmath)
    h = node.insert_before(h,h,beginmath)
    return node.mlist_to_hlist(h,d,p)
end

luatexbase.add_to_callback('mlist_to_hlist', mathboundary, 'Mark math')
}

\setbox0=\vbox{{\noindent Hello\\ $x=a+b^2$}}

\directlua{
    local nodetree = require('nodetree')
    nodetree.print(tex.box[0])
}

\box0

\end{document}

Konsole (suchen nach WHATSIT subtype: user_defined):

└─VLIST width: 345pt, depth: 0.83pt, height: 18.94pt
  ╚═head:
    ├─HLIST subtype: line, width: 345pt, depth: 0.11pt, height: 6.94pt
    │ ╚═head:
    │   ├─LOCAL_PAR 
    │   ├─GLYPH subtype: 256, char: H, width: 7.5pt, height: 6.83pt
    │   ├─GLYPH subtype: 256, char: e, width: 4.44pt, height: 4.48pt, depth: 0.11pt
    │   ├─GLYPH subtype: 256, char: l, width: 2.78pt, height: 6.94pt
    │   ├─GLYPH subtype: 256, char: l, width: 2.78pt, height: 6.94pt
    │   ├─GLYPH subtype: 256, char: o, width: 5pt, height: 4.48pt, depth: 0.11pt
    │   ├─PENALTY penalty: 10000
    │   ├─GLUE stretch: +1fil
    │   ├─PENALTY penalty: -10000
    │   └─GLUE subtype: rightskip
    ├─PENALTY subtype: linebreakpenalty, penalty: 300
    ├─GLUE subtype: baselineskip, width: 3.75pt
    └─HLIST subtype: line, width: 345pt, depth: 0.83pt, height: 8.14pt
      ╚═head:
        ├─WHATSIT subtype: user_defined, user_id: 1, type: 115, value: beginmath
        ├─GLYPH subtype: 256, char: x, width: 5.72pt, height: 4.31pt
        ├─GLUE subtype: thickmuskip, width: 2.78pt, stretch: 2.78pt
        ├─GLYPH subtype: 256, char: =, width: 7.78pt, height: 3.67pt, depth: -1.33pt
        ├─PENALTY subtype: noadpenalty, penalty: 500
        ├─GLUE subtype: thickmuskip, width: 2.78pt, stretch: 2.78pt
        ├─GLYPH subtype: 256, char: a, width: 5.29pt, height: 4.31pt
        ├─GLUE subtype: medmuskip, width: 2.22pt, stretch: 1.11pt, shrink: 2.22pt
        ├─GLYPH subtype: 256, char: +, width: 7.78pt, height: 5.83pt, depth: 0.83pt
        ├─PENALTY subtype: noadpenalty, penalty: 700
        ├─GLUE subtype: medmuskip, width: 2.22pt, stretch: 1.11pt, shrink: 2.22pt
        ├─GLYPH subtype: 256, char: b, width: 4.29pt, height: 6.94pt
        ├─HLIST subtype: sup, width: 4.49pt, height: 4.51pt, shift: -3.63pt
        │ ╚═head:
        │   └─GLYPH char: 2, width: 3.99pt, height: 4.51pt
        ├─WHATSIT subtype: user_defined, user_id: 2, type: 115, value: endmath
        ├─MATH subtype: endmath
        ├─PENALTY subtype: linepenalty, penalty: 10000
        ├─GLUE subtype: parfillskip, stretch: +1fil
        └─GLUE subtype: rightskip

Antworten

7 MarcelKrüger Nov 21 2020 at 16:09

Bei der Betrachtung von Knotenlisten nach dem Zeilenumbruch sind Grenzknoten keine zuverlässige Lösung. Dies hat mindestens zwei Gründe:

  1. Jeder Knoten kann entweder verworfen oder nicht verworfen werden. Wenn Ihr Grenzknoten verworfen werden kann, tritt das gleiche Problem auf wie bei Mathe-Ein / Mathe-Aus-Knoten: Sie verschwinden am Anfang einer Zeile. Der gewünschte Knoten kann also nicht verworfen werden. Beachten Sie jedoch die Regel für verworfene Knoten am Anfang einer Zeile: Nach einem Zeilenumbruch werden alle verworfenen Knoten gelöscht, bis der erste nicht verworfene Knoten gefunden wird. Dies impliziert insbesondere, dass Ihr neuer nicht verworfener Grenzknoten das Entfernen potenziell folgender verworfener Knoten unterdrücken würde, was sich auf die Ausgabe auswirkt. (Es gibt andere Gründe, warum das Hinzufügen eines nicht verwerfbaren Knotens, z. B. eines Whatsits, immer den Zeilenumbruch beeinflusst, aber dieser ist am einfachsten zu beschreiben.)

  2. Sobald der Zeilenumbruch erfolgt ist, können Sie eine Liste haben, die Mathematik enthält, aber keine Mathematikgrenze enthält. Ein ziemlich extremes Beispiel wäre:

    \documentclass{article}
    \begin{document}
    \showoutput
    \setbox0\vbox{
      \hsize=1cm
      \noindent
      Hi $1+2+3+4$
    }
    \setbox1\vsplit0 to\baselineskip 
    \setbox2\vsplit0 to\baselineskip
    \showbox0
    \showbox1
    \showbox2
    \end{document}
    

    Hier enthält Feld 1 nur einen mittleren Teil einer mathematischen Formel, daher gibt es keinen Grund dafür, dass es irgendeine Art von Grenzknoten enthält. Es ist immer noch Mathe.

    (Eine Variante davon, die in der Praxis eher vorkommt, ist eine mathematische Formel, die über mehrere Seiten verteilt ist. Die zweite Seite hat keinen Start-Mathematikknoten, da dort keine Mathematik beginnt.)

Was kann man dagegen tun? Es gibt zwei Möglichkeiten:

  1. Während Ihr Ansatz 1) nicht zuverlässig funktioniert, können Sie 2) implementieren und ein Attribut hinzufügen. Sie können die Knotenliste in post_mlist_to_hlist_filter¹ einfach durchlaufen , um dies hinzuzufügen. Dann werden sowohl Inline- als auch Anzeigemathematik behandelt.
  2. Machen Sie vor dem Zeilenumbruch, was Sie wollen, und verwenden Sie einfach die vorhandenen mathematischen Grenzknoten. In den meisten Fällen möchten Sie ohnehin vor dem Zeilenumbruch etwas arbeiten, daher ist dies ganz natürlich.

Je nach Anwendungsfall ist eine der Lösungen oft ganz natürlich. ZB sollte die Textextraktion sowieso fast immer auf Text vor dem Zeilenumbruch (oder sogar vor dem Formen) basieren, damit er gut zu 2 passt, während das Hinzufügen verschiedener Farben für mathematische Knoten effektiv nur das Hinzufügen eines Attributs bedeutet, sodass er natürlich zu 1 passt .

¹: In modernen LuaLaTeX-Versionen mlist_to_hlistsollte fast nie direkt eingestellt werden, sondern stattdessen pre_mlist_to_hlist_filteroder post_mlist_to_hlist_filterverwendet werden. Sie haben im Grunde die gleiche Schnittstelle wie mlist_to_hlist, aber Sie müssen sich nicht selbst aufrufen node.mlist_to_hlistund Ihr Code bleibt mit anderen Paketen kompatibel, die diese Rückrufe verwenden. Der Code in Ihrer Frage könnte beispielsweise durch Ersetzen angepasst werden

luatexbase.add_to_callback('mlist_to_hlist', mathboundary, 'Mark math')

mit

luatexbase.add_to_callback('pre_mlist_to_hlist_filter', mathboundary, 'Mark math')

und ersetzen

return node.mlist_to_hlist(h,d,p)

nur mit

return h