활성 문자에 하이픈 넣기

활성 문자에 하이픈 넣기

특정 문자를 활성화하고 이를 사용하여 다음과 같은 사악한 작업을 수행하고 싶다고 가정해 보겠습니다.

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

(나는 이것이 "y"를 포함하는 제어 시퀀스의 사용을 금지한다는 점에서 이것이 끔찍하다는 것을 알고 있습니다.)
이제 나는 TeX가 여전히 "y"에 일반적으로 하이픈 넣기를 고려하기를 바랍니다(폴리-에틸렌-렌). 나는 TeX가 가 포함된 단어를 깨뜨리지 않는다는 것을 알고 있습니다 \hbox. 그러나 TeX를 속여 순수한 문자만 있다고 생각하도록 하는 것이 가능합니까? 내가 생각하는 이유~할 것 같다가능하다:

  • TeX는 적절한 중단점을 찾을 때 단어의 문자가 활성화되어 있는지 여부 자체에는 신경 쓰지 않습니다.
  • 활성 문자가 발생할 때 여전히 어떤 문자가 있어야 하는지 알고 있습니다.

가능한 한 일반적인 해결책이 권장됩니다(즉, 활성 캐릭터가 수행하는 작업에 관계없이). 하지만 이것이 가능하지 않은 경우 이러한 활성 캐릭터가 수행하도록 할 수 있는 작업은 다음과 같습니다.

  • 정상적으로 인쇄
  • 자신을 an 에 삽입 \hbox하고\raise
  • 그 앞이나 뒤에 약간의 커른을 추가하세요
  • \pdfliterals 로 모양을 조작하세요

답변1

LuaTeX를 사용하면 문자를 활성화하는 것을 피하고 Ulrike Fischer가 주석에서 지적한 것처럼 하이픈 뒤에 문자를 조작하는 것이 가능합니다.

다음은 다음에서 영감을 받아 이 접근 방식을 구현한 것입니다.chickenize패키지. Lua로 코드를 작성하는 것은 이번이 처음이므로 어떤 제안이라도 환영합니다.

transform.lua

먼저 목록의 글리프 노드를 반복하고 문자에 라는 테이블에 항목이 있는지 확인하는 함수를 정의합니다 chartbl. 이 경우 transform_char테이블의 값을 사용하여 글리프 노드를 조작하는 함수를 호출합니다. 그런 다음 이 함수는 로 등록되어 행으로 post_linebreak_filter구분된 후 단락 목록에 적용됩니다(따라서 하이픈 넣기 패턴을 따릅니다).

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)

이제 transform_char(n)특정 요구 사항에 맞게 조정할 수 있습니다. 이 경우 문자 앞뒤에 kern과 pdfliteral을 추가하고 사실상 문자를 이동합니다.

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

각 작업의 값은 다음 위치에 저장됩니다 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"
  }
}

예:

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

폴리에틸렌


문서화: 원칙적으로 이 접근 방식은 내가 이해하는 한 TeX가 캐릭터와 관련하여 수행하려는 모든 작업을 Lua에서도 수행할 수 있으며 기능이 잠재적으로 변경될 수 있으므로 일반적인 솔루션입니다 transform_char. 그러나 더 복잡한 작업의 경우 TeX를 조판하는 것보다 수행하기가 더 어려운 것 같습니다.

그래서 처음에 시도한 것은 post_linebreak_filter원하는 변환의 결과를 \box레지스터에 넣는 모든 문자에 대해 TeX 매크로를 호출한 다음 Lua가 해당 상자로 노드를 바꾸도록 하는 것이었습니다.

나는 이것이 불가능하다고 생각한다. 에 의해 호출되는 모든 코드는 tex.printLua 코드 이후에만 실행되며 동시 상호 작용에 대한 접근 방식은 다음에서 논의됩니다.이 질문제가 보기에는 이 상황에는 적용되지 않는 것 같습니다.

  1. 코드를 코루틴에 넣고 co호출하기
tex.print("\\directlua{coroutine.resume(co)}")
coroutine.yield()

TeX가 14자 작업을 계속하기 전에 일부 매크로를 실행해야 할 때마다, 그 후에 나는 다음과 같은 결과를 얻습니다.
! TeX capacity exceeded, sorry [text input levels=15]

  1. 위에 링크된 질문에 대한 답변에서 a는 \loopTeX 코드에서 코루틴을 반복적으로 재개하는 데 사용됩니다. 이는 Lua 코드가 콜백에서 사용되는 경우 분명히 작동하지 않습니다.

최후의 수단으로 문자를 활성화하고 단락 hlist를 저장하고 활성 문자가 만든 상자를 의 원래 문자가 포함된 문자 모양 노드로 일시적으로 교체한 다음 저장된 목록을 사용하여 pre_linebreak_filter다시 변경하는 가능성만 봅니다. post_linebreak_filter. 하지만 그건 다른 날의 과제입니다 ...

관련 정보