
특정 문자를 활성화하고 이를 사용하여 다음과 같은 사악한 작업을 수행하고 싶다고 가정해 보겠습니다.
\catcode`y=13
\defy{\leavevmode\raise.1ex\hbox{\char`y}}
(나는 이것이 "y"를 포함하는 제어 시퀀스의 사용을 금지한다는 점에서 이것이 끔찍하다는 것을 알고 있습니다.)
이제 나는 TeX가 여전히 "y"에 일반적으로 하이픈 넣기를 고려하기를 바랍니다(폴리-에틸렌-렌). 나는 TeX가 가 포함된 단어를 깨뜨리지 않는다는 것을 알고 있습니다 \hbox
. 그러나 TeX를 속여 순수한 문자만 있다고 생각하도록 하는 것이 가능합니까? 내가 생각하는 이유~할 것 같다가능하다:
- TeX는 적절한 중단점을 찾을 때 단어의 문자가 활성화되어 있는지 여부 자체에는 신경 쓰지 않습니다.
- 활성 문자가 발생할 때 여전히 어떤 문자가 있어야 하는지 알고 있습니다.
가능한 한 일반적인 해결책이 권장됩니다(즉, 활성 캐릭터가 수행하는 작업에 관계없이). 하지만 이것이 가능하지 않은 경우 이러한 활성 캐릭터가 수행하도록 할 수 있는 작업은 다음과 같습니다.
- 정상적으로 인쇄
- 자신을 an 에 삽입
\hbox
하고\raise
- 그 앞이나 뒤에 약간의 커른을 추가하세요
\pdfliteral
s 로 모양을 조작하세요
답변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.print
Lua 코드 이후에만 실행되며 동시 상호 작용에 대한 접근 방식은 다음에서 논의됩니다.이 질문제가 보기에는 이 상황에는 적용되지 않는 것 같습니다.
- 코드를 코루틴에 넣고
co
호출하기
tex.print("\\directlua{coroutine.resume(co)}")
coroutine.yield()
TeX가 14자 작업을 계속하기 전에 일부 매크로를 실행해야 할 때마다, 그 후에 나는 다음과 같은 결과를 얻습니다.
! TeX capacity exceeded, sorry [text input levels=15]
- 위에 링크된 질문에 대한 답변에서 a는
\loop
TeX 코드에서 코루틴을 반복적으로 재개하는 데 사용됩니다. 이는 Lua 코드가 콜백에서 사용되는 경우 분명히 작동하지 않습니다.
최후의 수단으로 문자를 활성화하고 단락 hlist를 저장하고 활성 문자가 만든 상자를 의 원래 문자가 포함된 문자 모양 노드로 일시적으로 교체한 다음 저장된 목록을 사용하여 pre_linebreak_filter
다시 변경하는 가능성만 봅니다. post_linebreak_filter
. 하지만 그건 다른 날의 과제입니다 ...