\phantom 和 \obeylines

\phantom 和 \obeylines

我使用的是 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

使用\halign

\halign{#&#\cr
  it's &magic\cr
       &tragic\cr}
\bye

在此处输入图片描述

答案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

输出

相关内容