![使框在左邊距對齊,同時保持 \parindent 黏合/服從 \noindent(如果存在)](https://rvso.com/image/420064/%E4%BD%BF%E6%A1%86%E5%9C%A8%E5%B7%A6%E9%82%8A%E8%B7%9D%E5%B0%8D%E9%BD%8A%EF%BC%8C%E5%90%8C%E6%99%82%E4%BF%9D%E6%8C%81%20%5Cparindent%20%E9%BB%8F%E5%90%88%2F%E6%9C%8D%E5%BE%9E%20%5Cnoindent%EF%BC%88%E5%A6%82%E6%9E%9C%E5%AD%98%E5%9C%A8%EF%BC%89.png)
如何定義一個命令,該命令採用兩個參數並從第一個參數建立一個新段落,其中包含第二個參數的框的右邊界在該段落的左邊界處對齊,並且該框的參考點垂直位於該段落第一行文本的基線?
如果我做
\long\def\Command#1#2{\leavevmode\llap{#2}#1}
\Command{The text of the paragraph.}{Left justified?}
\Command{\noindent The text of the paragraph.}{Left justified?}
\bye
,那麼(如預期的那樣)\noindent
沒有效果,並且包含短語“左對齊?”的框的右邊距不是在段落的左邊距對齊,而是在字母的左側對齊T
。
如果不是\leavevmode
I do \noindent
,則包含短語「左對齊?」的框的右邊距在段落的左邊距和字母的左側都被證明是合理的,但是字母之前T
不會有-glue ,除非您“手動”將其添加為 的第一個參數的一部分:\parindent
T
\Command
\long\def\Command#1#2{\noindent\llap{#2}#1}
\Command{The text of the paragraph.}{Left justified?}
\Command{\noindent The text of the paragraph.}{Left justified?}
\bye
因此,在花了幾天時間解析 TeXbook 中難以理解的模棱兩可的短語之後,我確實只找到了達不到我想要的目標的方法,而且我只知道了為什麼我的嘗試不起作用。
有人可以指出方法嗎做工作?
答案1
答案2
我採納了你的評論
幾乎。謝謝。
\Command{\hbox{This box should be part of the paragraph, too} text text}{Left justified?}
不成功...
在大衛卡萊爾的回答考慮到:
\parindent
水平模式開始時寬度的水平盒是在不進行掛鉤的情況下產生和設定的\everyhbox
。
因此,您可以建立一種機制來設定\if...
-switch 以防\everyhbox
/\everyvbox
之前被觸發\everypar
:
\Command
從的第一個參數建立一個臨時垂直框。
在建立臨時垂直框時,在鉤子\everyhbox
/\everyvbox
全域設定 -switch 的巨集標記前面新增\if...
。
在每個鉤子前面加上 \everyhbox
/\everyvbox
和\everypar
一個指令來恢復所有這些鉤子。
影響:
如果在或\everypar
之前執行,鉤子將被恢復,因此更改附加到/ 的-switch 的指令將消失並且永遠不會被執行。\everyvbox
\everyhbox
\if..
\everyhbox
\everyvbox
如果\everyvbox
或在\everyhbox
之前執行\everypar
,則設定 -switch 的指令\if
將執行一次並恢復所有鉤子。
由於涉及三個鉤子(\everypar
、\everyvbox
、 ),我定義了一個遞歸例程,您可以在其中提供元組列表,第一個組件表示鉤子,第二個組件表示該鉤子在恢復元組列表中的所有鉤子並傳遞先前要傳遞的令牌鉤子在重新定義之前還傳遞的令牌。\everyhbox
\prependtorestorehooks
您還需要採取一些預防措施,以防機制/\Command
嵌套。
注意事項:
僅當鉤子本身不包含
\outer
-tokens 時,附加到鉤子/恢復鉤子才有效。例如,以下程式碼會產生錯誤訊息! Forbidden control sequence found while scanning text of \everypar.
:\begingroup \everypar={\problem}% \outer\def\problem{How to overcome the problem?}% \everypar=\expandafter{\the\everypar Again: How to overcome the problem?}% \endgroup \bye
\everyhbox
/在建立/\everyvbox
時觸發,無論該框是否進入輸出檔案或進入其內容永遠不會進入輸出檔案的框暫存器。因此,可以透過在的參數開頭放置例如 - 賦值來欺騙該機制。\hbox
\vbox
\setbox
\Command
從第一個參數
\vbox
建立一個臨時參數,用於設定-switch 以防/之前被觸發。因此 的第一個參數的材質被處理兩次:一次用於建立臨時框。一次用於建立應進入輸出檔案的段落。可能有些事情您不想執行兩次。不幸的是,沒有“獲取盒子屬性”/“盒子測量”模式可以關閉這些功能。\Command
\if...
\everyhbox
\everyvbox
\everypar
\Command
\immediate\write
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
%\prependtorestorehooks{%
% {{hook 1}{prepend 1}}%
% {{hook 2}{prepend 2}}%
% ...
%}%
\long\def\prependtorestorehooks#1{%
\prependtorestorehookscreraterestore{}{#1}#1\relax
}%
\long\def\prependtorestorehookscreraterestore#1#2#3{%
% #1 - Restore-List created so far
% #2 - entire list
% #3 - next element
\ifx\relax#3\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{\prependtorestorehooksprependtohooks{}{#1}#2\relax}%
{%
\prependtorestorehooksextract#3{#1}{#2}%
}%
}%
\long\def\prependtorestorehooksextract#1#2{%
\expandafter\prependtorestorehooksextractinner\expandafter{\the#1}{#1}%
}%
\long\def\prependtorestorehooksextractinner#1#2#3{%
\prependtorestorehookscreraterestore{#3#2={#1}}%
}%
\long\def\prependtorestorehooksprependtohooks#1#2#3{%
%#1 prepend-list-created so far
%#2 restore-list
%#3 {hook}{prepend}
\ifx\relax#3\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{#1}{%
\prependtorestorehooksprependtohooksb#3{#1}{#2}%
}%
}%
\long\def\prependtorestorehooksprependtohooksb#1{%
\expandafter\prependtorestorehooksprependtohooksc\expandafter{\the#1}{#1}%
}%
\long\def\prependtorestorehooksprependtohooksc#1#2#3#4#5{%
\prependtorestorehooksprependtohooks{#4#2={#3#5#1}}{#5}%
}%
%------------------------------------------------------------------------------------
\newbox\MyBox
\newif\ifleadingbox
\newif\ifintestbox\intestboxfalse
\newif\ifhookdone\hookdonefalse
\def\firstindent{}%
\long\def\setifleadingboxandfirstindent#1{%
\begingroup
\ifintestbox\else\global\hookdonefalse\global\leadingboxfalse\fi
\setbox\MyBox=\vbox{%
\intestboxtrue
\prependtorestorehooks{%
{{\everypar}{\ifhookdone\else\setbox\MyBox=\lastbox\xdef\firstindent{\the\wd\MyBox}\box\MyBox\global\hookdonetrue\fi}}%
{{\everyhbox}{\ifhookdone\else\global\leadingboxtrue\global\hookdonetrue\fi}}%
{{\everyvbox}{\ifhookdone\else\global\leadingboxtrue\global\hookdonetrue\fi}}%
}%
#1%
}%
\endgroup
}%
\long\def\Command#1#2{%
\par
\setifleadingboxandfirstindent{#1}%
\prependtorestorehooks{{{\everypar}{\setbox\MyBox\lastbox\llap{#2}\box\MyBox}}}%
\ifleadingbox\leavevmode\else\noindent\hbox to\firstindent{\hfill}\fi#1%
}%
\leavevmode
\kern-1in
\noindent test \hfill test \hfill test
\setifleadingboxandfirstindent{a}%
\ifleadingbox some \else no \fi leading h-or vbox.
\ifleadingbox\else Paragraph is indented by: \firstindent\fi
\smallskip\hrule\smallskip
\setifleadingboxandfirstindent{\hbox{a}}%
\ifleadingbox some \else no \fi leading h-or vbox.
\ifleadingbox\else Paragraph is indented by: \firstindent\fi
\smallskip\hrule\smallskip
\setifleadingboxandfirstindent{\vbox{a}}%
\ifleadingbox some \else no \fi leading h-or vbox.
\ifleadingbox\else Paragraph is indented by: \firstindent\fi
\smallskip\hrule\smallskip
\setifleadingboxandfirstindent{\noindent\vbox{a}}%
\ifleadingbox some \else no \fi leading h-or vbox.
\ifleadingbox\else Paragraph is indented by: \firstindent\fi
\smallskip\hrule\smallskip
\noindent {\bf Test 1:}
\Command{The text of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 2:}
\Command{\noindent The text of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 3:}
\Command{\hbox to 5cm{The\hfill wide\hfill text} of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 4:}
\Command{\noindent\hbox to 5cm{The\hfill wide\hfill text} of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 5:}
\Command{\vtop{\hbox to 5cm{The\hfill wide\hfill text}\hbox to 5cm{The\hfill wide\hfill text}} of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 6:}
\Command{\noindent\vtop{\hbox to 5cm{The\hfill wide\hfill text}\hbox to 5cm{The\hfill wide\hfill text}} of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 7:}
\Command{\vbox{\hbox to 5cm{The\hfill wide\hfill text}\hbox to 5cm{The\hfill wide\hfill text}} of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 8:}
\Command{\noindent\vbox{\hbox to 5cm{The\hfill wide\hfill text}\hbox to 5cm{The\hfill wide\hfill text}} of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 9:}
\newdimen\MyDimen
\setbox\MyBox=\hbox{Left justified?}
\MyDimen=\wd\MyBox
\Command{\noindent\kern\MyDimen The text of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 10:}
\Command{\leavevmode\kern\MyDimen The text of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 11:}
\Command{\noindent\kern\MyDimen \hbox{\vbox{\advance\hsize-\MyDimen\Command{\noindent The text of the paragraph.}{Left justified?}}}}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 12:}
\Command{\noindent\kern\MyDimen \hbox{\vbox{\advance\hsize-\MyDimen\Command{The text of the paragraph.}{Left justified?}}}}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 13:}
\Command{\leavevmode\kern\MyDimen \hbox{\vbox{\advance\hsize-\MyDimen\advance\hsize-\parindent\Command{\noindent The text of the paragraph.}{Left justified?}}}}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 14:}
\Command{\leavevmode\kern\MyDimen \hbox{\vbox{\advance\hsize-\MyDimen\advance\hsize-\parindent\Command{The text of the paragraph.}{Left justified?}}}}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 15:}
\Command{\kern\MyDimen The text of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 16:}
% `\Command` starts with `\par`, i.e., by resorting to (restricted) vertical mode. Thus \kerns at the beginning of \Command's first argument in any case are vertical.
\Command{\kern\MyDimen\noindent The text of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 17:}
% `\Command` starts with `\par`, i.e., by resorting to (restricted) vertical mode. Thus \kerns at the beginning of \Command's first argument in any case are vertical.
\Command{\kern\MyDimen\hbox{T}he text of the paragraph.}{Left justified?}
\smallskip\hrule\bigskip
\noindent {\bf Test 18:}
\Command{The text of the paragraph. \par The text of the paragraph. \par The text of the paragraph.\Command{\noindent The text of the paragraph. \par The text of the paragraph. \par The text of the paragraph.}{Left justified?}}{Left justified?}
\smallskip\hrule\bigskip
\noindent{\bf !!!! But: !!!}
\bigskip
\noindent {\bf Test 19:}
\Command{\setbox\MyBox=\hbox{Something to trigger the every-hook}\noindent This text is indented although it should not be indented. The reason is the triggering of {\tt\string\everyhbox} by {\tt\string\setbox...} right at the beginning of {\tt\string\Command}'s first argument.}{Left justified?}
\bye
說實話:
我不知道為什麼需要這一切。在手冊中\Command
只是告訴TeX在處理之前切換到垂直模式#1
。使用者可以自行決定是否明確\leavevmode
或\noindent
需要切換到水平模式。