我正在寻找一种在 Plain TeX 中沿段落(或任意文本块)左侧创建连续垂直规则的方法,以便它遵守正常的分页规则。我从以下内容开始,它看起来正是我想要的,当然,它有一个不良的副作用,即阻止大段文本的分页,因为它使用了\vbox
:
% Definition
\def\codeblock#1{%
\hbox{%
{\vrule width .6pt}%
\hskip 1em%
\vbox{\tt #1}%
}%
}
% Example
\codeblock{%
\hbox{void main(int argc, char *argv[]) \char123}%
\hbox{{\ }{\ }printf("Hello, world!{\char92}n");}%
\hbox{\char125}%
}
作为一种解决方法,我目前采取将事物分成单独的行和一系列不连续但重叠的垂直规则段的办法:
% Definition
\def\codeline#1{%
\hbox{%
\vrule width .6pt height .85em depth .46em%
\hskip 1em%
\tt #1%
}%
\vskip -.11em%
}
% Example
\codeline{void main(int argc, char *argv[]) \char123}
\codeline{{\ }{\ }printf("Hello, world!{\char92}n");}
\codeline{\char125}
在理想情况下,我只想将任意文本块传递给宏,并让其将正常的分页规则应用于文本块,同时在左侧制作垂直规则。我对 TeX 经验不多,但我怀疑答案是这并不简单?
在输入这个问题的时候,类似的问题出现在页边。我肯定会尝试一下——它看起来非常强大且经过深思熟虑——但对于我认为应该相当简单的东西来说,它似乎也相当沉重。另外,我并不是反对 LaTeX,但我更喜欢使用尽可能接近 Plain TeX 的解决方案,这样我才有可能理解它。
答案1
尝试下面的文件。您要求使用 Plain TeX - 因此必须使用pdftex
(而不是pdflatex
)运行。此文件(vert.tex
)和一些测试文件托管在 GitHub 上https://github.com/m4dc4p/vert。
%% Justin Bailey 2011
%% [email protected]
%%
%% To use: surround paragraphs to place a rule
%% with \startrule and \endrule.
%%
%% E.g.:
%%
%% \startrule
%% This paragraph will have a rule around it.
%% \endrule
%%
%% Multiple paragraphs can be spanned as well. Rules will break across
%% pages. Unfortunately, glue between paragraphs will not stretch
%% in that case, but usually it's not noticeable.
%%
%% You can change the offset of the rule by setting \ruleoffset. Rules
%% are always offset from the left margin.
%%
%% A simple \codeblock environment is included too.
%%
%% To use it, surround the code with \codeblock{
%%
%% }
%%
%% Code must appear in the group. The group must immediately follow \codeblock.
%% Code is set ragged right, obeying newlines, using typewriter font.
\newdimen\ruleoffset \ruleoffset=-10pt %% Horizontal offset for the
%% rule. This is the parameter that
%% should be set by the user.
\newdimen\roffset %% For calculating offset from left margin for rule.
\newbox\savedbox \newif\ifoutputran \newbox\rulebox
\newdimen\splitheight \newdimen\interparskip
\newtoks\codetoks
%% The basic idea is to use TeX's output routines
%% to determine if our ruled box is too high. If so
%% we split the box, set a rule, and put the rest on
%% the next page. \endrule does most of the work.
\def\startrule{%%
%% Clear our saved box.
\setbox0=\hbox{\box\savedbox}\par%%
%% Save \ruleoffset for later use.
\xdef\setroffset{\roffset=\the\leftskip \advance\roffset by \the\ruleoffset}%%
%% Save \prevdepth so we can use it to calculate interparagraph
%% glue.
\xdef\theprevdepth{\the\prevdepth}%%
%% Save material proceeding \startrule unless we're at
%% the top of the page.
\output={\accum}\ifnum\pagegoal<\maxdimen\relax%%
\vfil\break\outputranfalse%%
%% Capture everything up to \endrule in a \vbox.
\fi\setbox\rulebox=\vbox\bgroup}
\def\endrule{\egroup%%
%% Test if \rulebox + \savedbox will overflow
%% the page.
\output{\test}%%
\setinterparskip\setroffset%%
\setbox4=\makerule\copy\rulebox/%%
%% \vfuzz and \vbadness set to avoid overfull/underfull warnings
%% while testing.
\edef\thevfuzz{\the\vfuzz}\edef\thevbadness{\the\vbadness}%%
\vfuzz=10in\box4\penalty0%%
%% Restore default output routine.
\output={\savedout}\vfuzz=\thevfuzz%%
\ifoutputran\outputranfalse%%
%% The material overflowed the page, so we split off what
%% can fit (\splitheight) and put that on the page.
\vfuzz=10in\vbadness=10000%%
\setbox0=\vsplit\rulebox to \splitheight\vbadness=\thevbadness%%
\makerule\box0/\break\vfuzz=\thevfuzz%%
%% Put remaining material in a ruled box unless
%% nothing was left (\ifvoid)
\ifvoid\rulebox%%
\else\startrule\unvbox\rulebox\endrule%%
\fi%%
\fi}
%% Ensures spaces at the beginning of the line are always
%% preserved. TABs will not be. Thanks to TeX for the Impatient
%% (eplain) for \alwayspace.
{\gdef\alwaysspace{\hglue\fontdimen2\the\font \relax}%%
\obeyspaces\gdef {\alwaysspace}}
%% Define new lines so that in \codeblock they don't start a new
%% paragraph - they just insert a line break.
{\catcode`\^^M=\active \gdef^^M{\null\hfil\break} \global\let\ret=^^M}
\newtoks\codetoks
%% \codeblock must be followed by a group or it has no effect.
%% When followed by a group, the text found will be set on
%% individual lines as they appear in the group (i.e. new lines
%% are obeyed). The entire group will be have a rule next to it.
%% The group is also set in typewriter font, with ragged-right
%% margins.
%%
%% Note that text in the group is NOT set verbatim.
\def\codeblock{\codetoks={}%%
%% Removes final lineskip if one was there.
\gdef\endo{\unpenalty\endrule\prevdepth=0pt\relax}%%
%% Removes initial newline, if one was there. Otherwise, reinsert the
%% token captured.
\gdef\ignorenewline{\ifx\next\ret%%
\else\next%%
\fi}%%
\gdef\do{\ifx\next\bgroup%%
\codetoks={\startrule\noindent\bgroup%%
\ttraggedright%%
\parindent=0pt%%
\tt%%
\aftergroup\endo%%
\ignorespaces%%
\catcode`\^^M=\active\obeyspaces%%
\afterassignment\ignorenewline\let\next= }%%
\fi\the\codetoks}%%
\ignorespaces\afterassignment\do\let\next= }
\edef\savedout{\the\output}
%% Accumulate vertical material into a box.
\def\accum{\global\setbox\savedbox=\vbox{\unvbox\savedbox\unvbox255\unskip}}
%% An output routine that tells us it ran and
%% throws away the page built.
\def\test{\global\outputrantrue%%
\global\splitheight=\vsize%%
\global\advance\splitheight by -\ht\savedbox%%
\global\advance\splitheight by -\dp\savedbox%%
\setbox0=\vbox{\box255}}
\def\makerule#1/{\vbox{\unvcopy\savedbox%%
\vskip\interparskip\par\penalty0%%
\hbox{\hskip \roffset \vrule \hss \hskip -\roffset \strut#1\strut}}}%%
\def\setinterparskip{\setbox2=\vtop{X\par}%%
\setbox4=\vtop{\unvcopy\rulebox}%%
%% Set \prevdepth so inter-paragraph glue is calculated based
%% on the paragraph that really preceded \startrule, not our
%% fake paragraph.
\setbox0=\vbox{\copy2\par\prevdepth=\theprevdepth\copy4}%%
\interparskip=\ht0 \advance\interparskip by -\ht4 \advance\interparskip by -\ht2}%%
答案2
leftbar
从包中复制环境代码framed
,您将得到一条垂直线,可能出现分页符。它可以轻松应用于纯 TeX。
答案3
另一种 LaTeX 解决方案。
tcolorbox
是你的朋友(通过它的xparse
库,可以轻松处理两个可选参数):
代码(根据需要调整设置):
\documentclass{article}
\usepackage{xparse}
\usepackage[many]{tcolorbox}
\usepackage{lipsum}
\DeclareTColorBox{mybox}{O{orange}O{0cm}}{
breakable,
outer arc=0pt,
arc=0pt,
colback=white,
rightrule=0pt,
toprule=0pt,
top=0pt,
right=0pt,
bottom=0pt,
bottomrule=0pt,
colframe=#1,
enlarge left by=#2,
width=\linewidth-#2,
}
\begin{document}
\lipsum[4]
\begin{mybox}
\lipsum[4]
\end{mybox}
\lipsum[4]
\begin{mybox}[green][2cm]
\lipsum[4]
\end{mybox}
\end{document}
答案4
也可以通过以下方式实现mdframed
:
笔记:
- 包裹
showframe
仅用于显示页边距。实际使用中不需要它。
参考:
- 另请参阅用于在视觉上区分文本的环境
代码:
\documentclass{article}
\usepackage{xcolor}
\usepackage{mdframed}
\usepackage{showframe}
\usepackage{lipsum}
\newmdenv[
topline=false,
bottomline=false,
rightline=false,
linewidth=3pt,
linecolor=orange,
innerleftmargin=5pt,
leftmargin=10pt,
rightmargin=0pt,
innerrightmargin=0pt,
]{textbox}
\begin{document}
\lipsum[4]
\begin{textbox}
\lipsum[4]
\end{textbox}
\lipsum[4]
\begin{textbox}[linecolor=green, leftmargin=1.0cm]
\lipsum[4]
\end{textbox}
\end{document}