Я использую Plain TeX (на самом деле XeTeX из-за шрифтов, но я использую его в основном как Plain, к которому я привык). Я печатаю стихотворение для кого-то и хочу создать эффект в духе
it's magic
tragic
Я подумал, что, возможно, я мог бы использовать \phantom
для этой цели, например
\begingroup\obeylines
it's magic
\hphantom{it's} tragic
\endgroup%obeylines
Я использовал, \hphantom
потому что мне нужно горизонтальное пространство, но я не совсем понимаю разницу. Вывод с любым из них \hphantom
и \phantom
тот же:
При этом, похоже, не имеет значения, размещаю ли я пространство внутри коробки \phantom
или снаружи.
Я не совсем уверен, почему фантом помещают на отдельную линию, но я думаю, что это как-то связано с \obeylines
этим, чего я не понимаю. Заранее спасибо за помощь, и извините, если это, возможно, какая-то глупая ошибка.
решение1
Если вы используете LaTeX, то отображаемая вами разметка имеет тот эффект, который вы задумали.
\documentclass{article}
\begin{document}
\begingroup\obeylines
it's magic
\hphantom{it's} tragic
\endgroup%obeylines
\end{document}
В простом TeX \hphantom
абзац не начинается, поэтому:
\begingroup\obeylines
it's magic
\leavevmode\hphantom{it's} tragic
\endgroup%obeylines
\bye
Но я бы использовал простой TeX только для небольших тестовых примеров, а не для реальных документов.
решение2
решение3
Если вы готовы использовать LuaTeX (который, как правило, должен быть совместим с XeTeX), мы можем определить среду, которая автоматически выравнивает все начальные отступы с предыдущей строкой, без необходимости какой-либо дополнительной разметки:
%%%%%%%%%%%%%%%%%%
%%% 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