Silbentrennung bei aktiven Zeichen

Silbentrennung bei aktiven Zeichen

Nehmen wir an, ich möchte bestimmte Buchstaben aktivieren und damit ein paar abwegige Dinge anstellen, wie

\catcode`y=13
\defy{\leavevmode\raise.1ex\hbox{\char`y}}

(Ich weiß, dass das schrecklich ist, da es die Verwendung von Steuersequenzen, die ein „y“ enthalten, verbietet.)
Nun möchte ich, dass TeX die Silbentrennung am „y“ weiterhin normal berücksichtigt (Polyethylen). Ich weiß, dass TeX ein Wort, das ein\hbox , aber ist es möglich, TeX dazu zu bringen, zu glauben, dass es sich nur um einen harmlosen Buchstaben handelt? Warum ich denke, dass eskönntemöglich sein:

  • Ob die Zeichen eines Wortes aktiv sind oder nicht, ist TeX bei der Suche nach einem geeigneten Haltepunkt grundsätzlich egal;
  • zum Zeitpunkt des Auftretens des aktiven Zeichens ist noch bekannt, welcher Buchstabe dort stehen sollte.

Eine möglichst allgemeine Lösung wird empfohlen (d. h. unabhängig von der Funktion des aktiven Charakters). Wenn dies jedoch nicht umsetzbar ist, möchte ich einen aktiven Charakter möglicherweise folgendermaßen ausführen lassen:

  • druckt sich normal
  • fügt sich in ein \hboxund \raisees
  • füge davor oder danach ein paar Kerns hinzu
  • manipulieren Sie sein Aussehen mit \pdfliterals

Antwort1

Mit LuaTeX ist es möglich, die Aktivierung der Buchstaben zu vermeiden und sie erst nach der Silbentrennung zu bearbeiten, wie Ulrike Fischer in den Kommentaren anmerkte.

Nachfolgend sehen Sie eine Implementierung dieses Ansatzes, inspiriert von derchickenizePaket. Da dies das erste Mal ist, dass ich Code in Lua schreibe, sind alle Vorschläge willkommen.

transform.lua

Zuerst definiere ich eine Funktion, die die Glyphenknoten in einer Liste durchläuft und prüft, ob das Zeichen einen Eintrag in einer Tabelle namens hat chartbl. In diesem Fall ruft sie eine Funktion auf transform_char, die die Werte in der Tabelle verwendet, um den Glyphenknoten zu bearbeiten. Diese Funktion wird dann als registriert post_linebreak_filter, sodass sie auf eine Absatzliste angewendet wird, nachdem sie in Zeilen aufgeteilt wurde (und somit Silbentrennungsmuster befolgt):

transform_chars = function(head)
  for l in node.traverse_id(node.id("hhead"),head) do
    for n in node.traverse_id(node.id("glyph"),l.head) do
      chr = n.char
      if chartbl[chr] ~= nil then
        transformed = transform_char(n)
        l.head = node.insert_before(l.head,n,node.copy(transformed))
        node.remove(l.head,n)
      end
    end
  end
  return head
end

callback.register("post_linebreak_filter",transform_chars)

Nun transform_char(n)kann noch an die jeweiligen Bedürfnisse angepasst werden. In diesem Fall fügen wir vor und nach dem Zeichen einen Kern und ein PDF-Literal ein und verschieben das Zeichen virtuell:

transform_char = function(c)
  kbfn = node.new(node.id("kern")) -- additional kern before char
  pdfbfn = node.new(node.id("whatsit"),node.subtype("pdf_literal")) -- pdf literal before
  cn = node.new(node.id("glyph")) -- char
  cn = node.copy(c)
  pdfan = node.new(node.id("whatsit"),node.subtype("pdf_literal")) -- pdf literal after
  kan = node.new(node.id("kern")) -- additional kern after char

  tbl = chartbl[c.char]

  kbfn.kern = tex.sp(tbl["kbf"])
  pdfbfn.data = tbl["pdfbf"]
  cn.xoffset = tex.sp(tbl["xoff"])
  cn.yoffset = tex.sp(tbl["yoff"])
  pdfan.data = tbl["pdfa"]
  kan.kern = tex.sp(tbl["ka"])

  kbfn.next = pdfbfn
  pdfbfn.next = cn
  cn.next = pdfan
  pdfan.next = kan
  t = node.hpack(kbfn)
  return t
end

Die Werte für die einzelnen Operationen werden hier gespeichert chartbl:

chartbl = {
  [string.byte("y")] = {
    ["kbf"] = "-0.1em",
    ["pdfbf"] = "-1 0 0 1 5.5 0 cm",
    ["xoff"] = "0ex",
    ["yoff"] = "0.5ex",
    ["pdfa"] = "-1 0 0 1 -5.5 0 cm",
    ["ka"] = "0.2em"
  }
}

Beispiel:

\directlua{dofile("transform.lua")}
\hsize1cm
\noindent polyethylene

Polyethylen


Zur Dokumentation: Im Prinzip ist dieser Ansatz eine allgemeine Lösung, da, soweit ich verstanden habe, alles, was TeX mit einem Zeichen machen möchte, auch in Lua gemacht werden kann, mit möglichen Änderungen an der transform_charFunktion. Bei komplexeren Aufgaben scheint dies jedoch schwieriger zu sein, als es von TeX setzen zu lassen.

Ich habe also zunächst versucht, post_linebreak_filterfür jedes Zeichen ein TeX-Makro aufzurufen, das das Ergebnis der gewünschten Transformation in ein \boxRegister einträgt, und dann den Knoten von Lua durch dieses Feld ersetzen zu lassen.

Ich denke, das ist unmöglich. Jeder von aufgerufene Code tex.printwird erst nach dem Lua-Code ausgeführt, und die indiese Fragesind, wie mir scheint, auf diese Situation nicht anwendbar:

  1. Den Code in eine Coroutine einfügen cound aufrufen lassen
tex.print("\\directlua{coroutine.resume(co)}")
coroutine.yield()

wenn TeX ein Makro ausführen soll, bevor es weitergeht, funktioniert es für 14 Zeichen, danach bekomme ich
! TeX capacity exceeded, sorry [text input levels=15]

  1. In der Antwort auf die oben verlinkte Frage \loopwird im TeX-Code ein verwendet, um die Coroutine immer wieder fortzusetzen, was offensichtlich nicht funktioniert, wenn der Lua-Code in einem Callback verwendet werden soll.

Als letzten Ausweg sehe ich nur die Möglichkeit, die Zeichen zu aktivieren, die Absatzliste zu speichern und die vom aktiven Zeichen erstellten Kästchen vorübergehend durch einen Glyphenknoten zu ersetzen, der das ursprüngliche Zeichen enthält pre_linebreak_filter, und sie post_linebreak_filtermithilfe der gespeicherten Liste wieder in zu ändern. Aber das ist eine Aufgabe für einen anderen Tag ...

verwandte Informationen