\minipage 是否应该恢复 \@par 的默认定义?

\minipage 是否应该恢复 \@par 的默认定义?

我在思考时偶然发现了标题中暗示的问题 这个问题 (“用户定义环境周围的不规则间距”) 和 它的答案

\@endparenv所有“列表制作”环境都会调用该命令(通过\endtrivlist),以确保“当且仅当您在 \end命令后留出一个空行时,LaTeX 才会开始一个新段落”(引自)。它通过在环境本身的最末端对 的含义ltlists.dtx应用“临时更改”(由 指定的意义)来实现这一点 。另一方面,“列表制作”环境还需要 在其初始化阶段 对 的含义应用“长期更改” ,更准确地说是在执行 时(参见2015/05/10,第 78-86 行)。在 中设计的用于改变 的含义的机制可确保当“列表制作”环境相互嵌套时,这两个更改以一致的方式协同工作。ltpar.dtx\par\par\@trivlistltlists.dtxltpar.dtx\par

然而,我想知道,在当前的 LaTeX 内核中,当列表环境出现在minipage嵌套在另一个列表环境中的 中时,这种机制是否也能正常运行:事实上,在这种情况下, 应该minipage充当“沙箱”,将内部环境与外部环境“屏蔽”,这似乎是合理的;但目前情况并非如此,如下例所示。实际上,该示例并不直接使用列表环境,而是flushleft,但它是通过 实现的\trivlist;这样做是为了更接近在 中讨论的情况 上述问题

在继续阅读之前,请您编译以下代码并检查其输出以及源代码本身。

% My standard header for TeX.SX answers:
\documentclass[a4paper]{article} % To avoid confusion, let us explicitly 
                                 % declare the paper format.

\usepackage[T1]{fontenc}         % Not always necessary, but recommended.

\usepackage[ascii]{inputenc}     % Just to check that the source is still pure,
                                 % 7-bit-clean ASCII when you execute it, as it
                                 % was when I wrote it.
% End of standard header.  What follows pertains to the problem at hand.

\makeatletter

\newcommand*\@SHOW[1]{%
    \texttt{\char\escapechar #1} $\Longrightarrow$
        \texttt{\expandafter\meaning\csname #1\endcsname}%
}
\newcommand*\SHOW{%
    \myNL\@SHOW{par}\myNL\@SHOW{@par}%
}
\newcommand*\MyParShape{%
    \hangafter \@ne \hangindent \thr@@ pc \noindent
}
\newcommand*\myNL{\hfill\break}

\makeatother



\begin{document}

\section{Base scenario}
\label{S:Base}

Consider the following:
\begin{flushleft}
    Some text marked~(A)\@.
\end{flushleft}
Not preceded by blank line:\SHOW
\begin{flushleft}
    Some text marked~(B)\@.
\end{flushleft}

Preceded by blank line:\SHOW

\MyParShape
All this is quite OK\@.  This paragraph does have hanging indentation,
but the following one won't\ldots

\ldots as you can see here.  Lorem ipsum dolor sit amet consectetur adipisci
elit, ridiculus mus.  Fringilla eius partorietur.



\section{\texttt{flushleft} inside \texttt{flushleft}}
\label{S:fl<fl}

Now consider:
\begin{flushleft}
    \setlength{\parindent}{1pc}
    We nest here the same contruction presented in Section~\ref{S:Base}:
    \begin{flushleft}
        Some text marked~(C)\@.
    \end{flushleft}
    Not preceded by blank line:\SHOW
    \begin{flushleft}
        Some text marked~(D)\@.
    \end{flushleft}

    Preceded by blank line:\SHOW

    \MyParShape
    This paragraph has hanging indentation, but this time the hanging 
    indentation is carried over also to the following one.

    But this could be considered OK\@ too, because, after all, we are still
    inside the \texttt{list} environment implied by the outer
    \texttt{flushleft}: indeed, preserving \verb|\parshape| setting is essential
    for the implementation of ``list-making'' environments.  And
    \texttt{flushleft} environments should \textbf{not} be nested!
\end{flushleft}
Not preceded by blank line:\SHOW

Again, this is what we expect.



\section{\texttt{flushleft} inside \texttt{minipage} inside \texttt{flushleft}}
\label{S:fl<mp<fl}

But consider this other situation:
\begin{flushleft}
    \begin{minipage}[b]{.9\linewidth}
        \raggedright % to avoid underfull boxes
        \setlength{\parindent}{1pc}
        Start of the \texttt{minipage}.  Note that \verb|\par| has its primitive
        meaning:\SHOW

        Also here, we nest the same contruction presented in
        Section~\ref{S:Base}:
        \begin{flushleft}
            Some text marked~(E)\@.
        \end{flushleft}
        Not preceded by blank line:\SHOW
        \begin{flushleft}
            Some text marked~(F)\@.
        \end{flushleft}

        Preceded by blank line:\SHOW

        \MyParShape
        As we see, the meaning of \verb|\par| has not reverted to what it was at
        the beginning.  Why is this not good at all?  Well, for a number of
        reasons, of which the fact that hanging indentation is carried over from
        one paragraph to another,\ldots

        (\emph{continuing from the previous paragraph}) \ldots as you can see
        here, is just the first---and rather silly---example that comes to my
        mind.  Lorem ipsum dolor sit amet consectetur adipisci elit, ridiculus
        mus.  Fringilla eius partorietur.

        End of the \texttt{minipage}.
    \end{minipage}

    Thus, we see that, inside the \texttt{minipage}, we do \emph{not} get the
    same behavior as in the ``base scenario'' of Section~\ref{S:Base}, but
    rather the behavior of Section~\ref{S:fl<fl}.
\end{flushleft}

Should this be considered a (tiny) bug in the \LaTeXe\ kernel?



\clearpage

\makeatletter

\def\@minipagerestore{%
    \def\@par{\let\par\@@par\par}
}

\makeatother

\section{Possible fix}
\label{S:Fix}

Consider, finally, what happens now:
\begin{flushleft}
    \begin{minipage}[b]{.9\linewidth}
        \raggedright % to avoid underfull boxes
        \setlength{\parindent}{1pc}
        Start of the \texttt{minipage}.  Note that \verb|\par| has its primitive
        meaning:\SHOW

        Once more, we nest here the same contruction presented in
        Section~\ref{S:Base}:
        \begin{flushleft}
            Some text marked~(G)\@.
        \end{flushleft}
        Not preceded by blank line:\SHOW
        \begin{flushleft}
            Some text marked~(H)\@.
        \end{flushleft}

        Preceded by blank line:\SHOW

        \MyParShape
        As we see, this time the meaning of \verb|\par| \emph{has} reverted to
        what it was at the beginning.  Indeed, hanging indentation is no longer
        being carried over from one paragraph to another,\ldots

        (\emph{continuing from the previous paragraph}) \ldots as you can see
        here.  Lorem ipsum dolor sit amet consectetur adipisci elit, ridiculus
        mus.  Fringilla eius partorietur.

        End of the \texttt{minipage}.
    \end{minipage}

    Thus, we see that, inside the \texttt{minipage}, we \emph{do} get, now, the
    same behavior as in the ``base scenario'' of Section~\ref{S:Base}.
\end{flushleft}

\end{document}

请注意,我们\parindent在某些地方手动重置以使效果\@endparenv可见。您获得的文档包含四个部分。

在第一部分中,这里以环境的简单顶层使用 flushleft为例,作为下文介绍的其他案例的基准。在这里,我们可以看到,当“临时更改”自行发生时,其\@endarenv含义是 如何被撤销的,而没有同时发生的“长期更改”。\par

第二部分说明了直接嵌套的情况。结果乍一看可能很奇怪,但这只是因为人们没有立即意识到内部 flushleft实际上是嵌套在外部所表示的第一级列表中的第二级列表flushleft。实际上,典型的用户不会意识到这一点,因为他们不知道如何实现的细节flushleft,可以给他们的最好建议是避免嵌套 center/ flushleft/flushright环境。

在第三部分中,然而,情况却不那么明朗:flushleft包含在 中的环境难道不应该minipage 以与第一部分中所示的顶级环境相同的方式运行,而不管 本身minipage又包含在另一个flushleft(或center,或 ) flushright环境中?甚至在列表中?实际上, minipage重置\par为其原始含义,但是——啊哈!——它无法以类似的方式重置\@par,因此外部列表所做的“长期更改”渗透到内部列表,从而确定与直接嵌套相同的结果。

最后,第四节\@par提出了一种可能的,甚至是过于明显的修复方法:在 s 的开头 包括重置minipage。这里是通过 \@minipagerestore钩子来完成的。

我的问题是:上述分析是否正确?与此相关的是:是否还有其他方面我没有考虑到,这意味着选择不是minipage 重新定义环境是\@par故意的吗?

答案1

大约五年后!

LaTeX有五十种颜色\par!楼主做了许多我认为很复杂的测试,最后得出结论 LaTeX 可能有 bug。幸好没有 bug!

OP 得出的​​结论是,他插入了一个\MyParshape基于 的特殊宏,\hangafter\hangindent并且这个宏在更多段落中延续,这可能是一个错误。如果他\@@par当时在宏之前的段落中插入一个,那么一切都会好起来。现在我必须保存\@@par在序言中并在测试中使用它(因为我们现在有了新的钩子系统,现在还有其他复杂情况)。在列表中,这种行为是正确的,因为可能存在更多级别的列表,并且程序需要控制它\par。OP 应该\MyParShape 通过适当定义它来确保列表中的正确工作。

我附上了我的测试图片和代码。我删除了 OP 中不必要的代码。我们只需要测试三个条件 a)par普通段落中的值、迷你页面中的值和列表中的值。测试 9,解决了 OP 的问题。

顺便说一下\par,现在有一个双胞胎姐妹,当我们说\par我们有两个时!取消注释下面代码的末尾即可获得惊喜!

\documentclass[a4paper]{scrartcl} 
\usepackage{xcolor}
\definecolor{green}{rgb}{0.06,0.44,0.08}
\makeatletter
\newcommand*\MyParShape{%
    \hangafter \@ne \hangindent \thr@@ pc \noindent
}
\ExplSyntaxOn
\let\ATATPAR\@@par
\def\LISTPAR{\if@newlist \advance \par@deathcycles \@ne \ifnum \par@deathcycles >\@m 
\@noitemerr {\@@par }\fi \else {\@@par }\fi} 
\def\PASS{{\ttfamily\color{green} ~ PASS~}}
\def\FAIL{{\ttfamily\color{red} ~ FAIL~}}
\int_new:N \testcounter
\int_gset:Nn \testcounter{1}
\cs_gset:Npn\TEST #1#2#3
{ \makeatletter
  \int_use:N \testcounter :~~
  \token_if_eq_meaning:NNTF #1#2{\PASS}{\FAIL}
  {\ttfamily \tl_to_str:n {#3} }
  \int_gincr:N \testcounter
}
\ExplSyntaxOff
\makeatother
\parindent0pt
\begin{document}

\makeatletter

\subsection*{At start of document}
\TEST{\par}{\@@par}{\par==\@@par}\par
\ExplSyntaxOn
\TEST{\par}{\tex_par:D}{\par != \tex_par:D }

\ExplSyntaxOff

\subsection*{In minipage tests}

\begin{minipage}{1\linewidth}
\TEST{\par}{\ATATPAR}{In minipage \par == \@@par}\par
\end{minipage}

\subsection*{In flushleft tests}
\begin{flushleft}
    \TEST{\par}{\@par}{in flush left \par=\@par (in list definition)}\par
    Some text marked~(A).
\end{flushleft}
\subsection*{Between flush left environments}
\TEST{\par}{\@@par}{between two flush enviroments \par=\@@par l3 wins}  % TEST 5
\makeatother
\begin{flushleft}
    Some text marked~(B).
\end{flushleft}

\subsection*{Nested minipage in flushleft}
\begin{flushleft}
\raggedright
    \begin{minipage}[b]{.9\linewidth}
    \makeatletter
       \TEST{\par}{\@@par}{In a list first line of minipage \par=\@@par}\par
   
       \begin{flushleft}
            \TEST{\par}{\@par}{In flusleft>minipage>flushleft \par=\@par (list def.)}
            Some text marked~(E).
        \end{flushleft}
        Not preceded by blank line:\par
        \makeatletter 
        \TEST{\@par}{\LISTPAR}{In list \par=\@par i.e, as defined in lists}
        \makeatother
        \begin{flushleft}
            Some text marked~(F).
        \end{flushleft}
        \MyParShape
        \color{orange}
        As we see, the meaning of \verb|\par| has not reverted to what it was at
        the beginning.  Why is this not good at all?  Well, for a number of
        reasons, of which the fact that hanging indentation is carried over from
        one paragraph to another,\ldots\color{black}\ATATPAR
       
        \makeatletter
        \TEST{\@par}{\LISTPAR}{After \MyParshape \par=\@par=\LISTPAR}
        \makeatother
        
        Continuing from the previous paragraph \ldots as you can see
        here\ldots. There is no issue with the \verb+\MyParShape+!
    \end{minipage}
    
\end{flushleft}


%\ttfamily
%\ExplSyntaxOn
%\meaning\par
%
%
%\meaning\tex_par:D\par
\end{document}

在此处输入图片描述

相关内容