Estoy usando Plain TeX (en realidad, XeTeX por razones de fuente, pero lo estoy usando básicamente como si fuera Plain, a lo que estoy acostumbrado). Estoy escribiendo un poema para alguien y quiero crear un efecto parecido a
it's magic
tragic
Pensé que tal vez podría usarlo \phantom
para este propósito, como
\begingroup\obeylines
it's magic
\hphantom{it's} tragic
\endgroup%obeylines
Lo usé \hphantom
porque quiero espacio horizontal, pero no conozco totalmente la diferencia. La salida con cualquiera \hphantom
y \phantom
es la misma:
Tampoco parece importar si pongo el espacio dentro \phantom
o fuera de la caja.
No estoy tan seguro de por qué ponen al fantasma en su propia línea, pero imagino que tiene algo que ver con \obeylines
eso que no entiendo. Gracias de antemano por la ayuda y lo siento si quizás se trata de un error estúpido.
Respuesta1
Si usa LaTeX, el marcado que muestra tiene el efecto deseado.
\documentclass{article}
\begin{document}
\begingroup\obeylines
it's magic
\hphantom{it's} tragic
\endgroup%obeylines
\end{document}
En TeX simple \hphantom
no comienza un párrafo, por lo que:
\begingroup\obeylines
it's magic
\leavevmode\hphantom{it's} tragic
\endgroup%obeylines
\bye
Pero solo usaría TeX simple para pequeños ejemplos de prueba, no para documentos reales.
Respuesta2
Respuesta3
Si está dispuesto a utilizar LuaTeX (que generalmente debería ser compatible con XeTeX), podemos definir un entorno que alinee automáticamente cualquier sangría inicial con la línea anterior, sin necesidad de ningún marcado adicional:
%%%%%%%%%%%%%%%%%%
%%% Formatting %%%
%%%%%%%%%%%%%%%%%%
% Make LuaTeX load fonts like XeTeX
\input luaotfload.sty
\directlua{
config.luaotfload.default_features.global.tlig = true
config.luaotfload.default_features.global.trep = true
}
% Load the fonts
\font\seventeenrm="[lmroman17-regular]" at 17pt
\font\adventorbold="TeX Gyre Adventor/B" at 12pt
% Set the main font
\seventeenrm
\baselineskip=1.2em
\nopagenumbers
%%%%%%%%%%%%%%%%
%%% TeX Code %%%
%%%%%%%%%%%%%%%%
\newattribute\alignspacesattr
\def\beginalignspaces{%
\bgroup%
\alignspacesattr=1% Mark all nodes with this attribute
\catcode`\ =12% Make the space into a regular character
\obeylines% Process line-by-line
\toksapp\everypar{\setbox0=\lastbox}% Remove the indent from every line
}
\def\endalignspaces{%
\par% Make sure that the last line is processed
\egroup%
}
%%%%%%%%%%%%%%%%
%%% Lua Code %%%
%%%%%%%%%%%%%%%%
\directlua{
% Helper function to traverse through any marked nodes
local n_attr
local function get_next_attr(n)
local next = n.next
if next then
n_attr = select(2, node.find_attribute(next, "alignspacesattr"))
return n_attr
end
end
% Replaces a node with another node
local function replace_node(head, n1, n2)
local head, current = node.remove(head, n1)
head, n2 = node.insert_before(head, current, n2)
return head, n2
end
local prev_widths = {}
% Define the callback, which runs for every line
luatexbase.add_to_callback("pre_linebreak_filter", function (head)
% Remove any discretionaries
local head = head
if get_next_attr(head) then
head = node.flatten_discretionaries(head)
end
% Initialize the line-local variables
local this_widths = {}
local before_chars = true
n_attr = head
% Iterate over every character in a marked line
while get_next_attr(n_attr) do
local char = n_attr.char
% Replace space glyphs with some sort of glue
if char == string.byte(" ") then
local hskip = node.new("glue")
if before_chars then
% If we're at the start of the line, then make the space the
% same width as the character immediately above it.
hskip.width = prev_widths[rawlen(this_widths) + 1]
else
% If we're in the middle of the line, set it to the regular
% space width.
local params = font.getfont(n_attr.font).parameters
node.setglue(
hskip,
params.space, params.space_stretch, params.space_shrink,
0, 0
)
end
head, n_attr = replace_node(head, n_attr, hskip)
else
% If we're not at a space, then set that we're not at the start
% of the line.
before_chars = false
end
% Recurse through any ligatures
local chars = {}
local function check_components(n)
if n.components then
for m in node.traverse(n.components) do
check_components(m)
end
elseif char and
(n.id == node.id("glyph") or n.id == node.id("glue"))
then
chars[rawlen(chars) + 1] = n
end
end
check_components(n_attr)
% Save the widths of the characters on this line
for _, n in ipairs(chars) do
this_widths[rawlen(this_widths) + 1] = (n.width or 0)
end
end
prev_widths = this_widths
return head
end, "align_spaces")
}
%%%%%%%%%%%%
%%% Demo %%%
%%%%%%%%%%%%
\beginalignspaces
% Works with different character widths
abc def ghi jkl mno pqr
def ghi
hi jkl m
no pqr
r stu
f ghi jkl mno pqr stu
% And with em-dashes
M l M --- M
l M --- M
M --- M
--- M
M
% And with ligatures
waffles
les
% And with different fonts
ABCDEF G {\adventorbold H I} J K
{\adventorbold I} J
EF G {\adventorbold H I}
ABCDEF G {\adventorbold H }
abM l M --- ABC
---
\endalignspaces
\bye