10

I'm writing a custom command that uses minipages to display its contents:

\newcommand{\example}[1]{\noindent\begin{minipage}{\linewidth}#1\end{minipage}}

The spacing around this command should be similar to that of the align environment: \abovedisplayskip above, and \belowdisplayskip after, so I add \par\vspace{…} before and after:

\newcommand{\example}[1]{%
  \par\vspace{\abovedisplayskip}
  \noindent\begin{minipage}{\linewidth}#1\end{minipage}
  \par\addvspace{\belowdisplayskip}}

This isn't perfect, though: it adds an extra \parskip before and after the contents, even if there are no blank lines around the command:

AAA % too much space (extra \parskip) after this
\example{\lipsum[1]}
BBB % too much space (extra \parskip) before that

I can remove the first one by changing the definition to this:

\newcommand{\example}[1]{%
  \ifvmode\else\par\vspace{-\parskip}\fi\vspace{\abovedisplayskip}
  \noindent\begin{minipage}{\linewidth}#1\end{minipage}
  \par\addvspace{\belowdisplayskip}}

But what's the equivalent fix for the bottom of the command? If I use a negative space the \parskip will always be suppressed. Ideally, I'd like text immediately following the command to not be indented, just like with \[\].

Here's a minimal example:

\documentclass{minimal}

\usepackage{lipsum}
\setlength{\parskip}{50pt}

\newcommand{\example}[1]{%
  \ifvmode\else\par\vspace{-\parskip}\fi\vspace{\abovedisplayskip}
  \noindent\begin{minipage}{\linewidth}#1\end{minipage}
  \par\addvspace{\belowdisplayskip}}

\begin{document}

% There should be small spaces after AAA and before BBB
AAA
\example{\lipsum[1]}
BBB

% There should be a large space after AAA and a small one before BBB
% And BBB shouldn't be indented
AAA

\example{\lipsum[1]}
BBB

% There should be a small space after AAA and a large one before BBB
AAA
\example{\lipsum[1]}

BBB
\end{document} 
Clément
  • 4,004

2 Answers2

10

The standard way to do this would be to define your environment as a trivlist, almost all latex display environments (verbatim, center, quote,..) are defined as trivlists (special one-item version of list) exactly for this reason.

The trivlist code detects whether there is a paragraph break before the list and if so has paragraph spacing before and after, but if there is no paragraph break before the list then the internal \par after the list is hidden and paragraph indentation of the following text is suppressed.

\begin{center}\end{center} for example is defined by

\def\center{\trivlist \centering\item\relax}
\def\endcenter{\endtrivlist}
David Carlisle
  • 757,742
  • I believe this just inhibits paragraph indents, but not skips. If you enter word\begin{center}centred words\end{center}word, then \parskip is still inserted twice. – Circumscribe Nov 05 '18 at 12:04
  • @Circumscribe it uses \partopsep as \parskip in the \par case and \topsep as \parskip in the no-\par case, so by setting up those list parameters you can achieve (some) control over that – David Carlisle Nov 05 '18 at 12:15
  • @Circumscribe topsep=0pt isn't it? but something like that, yes, this is consistent with all other latex displays so hopefully packages like \parskip which set things up for non zero parskip would automatically do the right thing here. – David Carlisle Nov 05 '18 at 12:47
  • 2
    Sorry, I had deleted my comment (before you had replied, I thought) because I wasn't sure about it anymore. For me setting \partopsep=\parskip and \topsep=-\parskip works. I think both \parskip and \topsep are always inserted (so this way they cancel out) and \partopsep is only inserted when there is a preceding paragraph break. – Circumscribe Nov 05 '18 at 12:57
  • @Circumscribe er yes that sounds about right:-) – David Carlisle Nov 05 '18 at 13:02
  • Thanks! This is very helpful. But I can only make it work for spaces above the list; it seems that \trivlist always puts the same amount of space after the list too, regardless of whether the list is followed by a new paragraph. Do you have suggestions for that? – Clément Nov 05 '18 at 19:11
  • @Clément yes that's a feature (not clear it's always the optimal design but it is what it is) I think somewhere ther's a package that uses different parameters for the bottom space (otherwise you'd basically copy trivilist but replace "end" uses of \partopsep by some new \parbottomsep length) – David Carlisle Nov 05 '18 at 19:14
4

Here is a possible solution. I'm defining the macro \tentativepar which inserts \par and sets both \parskip and \parindent to 0pt. It moreover temporarily redefines \par and \everypar (which is inserted at the start of every paragraph) to reset the original values (and themselves).

The net effect is that \tentativepar will insert a paragraph break without any skip or indentation unless it is followed by another \par.

Here is an example:

\documentclass{article}

\setlength{\parskip}{50pt}

%% vv We need to store a couple of values
\newskip\savedparskip
\newskip\savedparindent
\newtoks\savedeverypar

\makeatletter
\newcommand*\tentativepar{%
  \par
  \savedparskip\parskip         %% <- store original parskip
  \savedparindent\parindent     %% <- store original parindent
  \expandafter\savedeverypar\expandafter{\the\everypar}
  %% ^^ store original \everypar
  \parskip0pt                   %% <- set parskip to 0pt
  \parindent0pt                 %% <- set parindent to 0pt
  %% vv restore everything that was saved after the first \par
  \def\par{%
    \@restorepar                  %% <- restore original \par
    \expandafter\everypar\expandafter{\the\savedeverypar}%
    \parskip\savedparskip         %% <- reset parskip
    \parindent\savedparindent     %% <- reset parindent
    \par                          %% still insert a paragraph break
  }%
  %% vv or at the stat of the next paragraph
  \expandafter\everypar\expandafter{%
    \the\savedeverypar
    \@restorepar                  %% <- restore original \par
    \expandafter\everypar\expandafter{\the\savedeverypar}%
    \parskip\savedparskip         %% <- reset parskip
    \parindent\savedparindent     %% <- reset parindent
  }
}
\makeatother

\newcommand{\example}[1]{%
  \ifvmode\else\tentativepar\fi
  \vspace{\abovedisplayskip}
  \noindent\begin{minipage}{.5\linewidth}#1\end{minipage}%
  \vspace{\belowdisplayskip}
  \tentativepar
}

\begin{document}

AAA
\example{There should be small spaces after AAA and before BBB}
BBB

AAA

\example{There should be a large space after AAA and a small one before BBB. And BBB shouldn't be indented.}
BBB

AAA
\example{There should be a small space after AAA and a large one before BBB}

BBB

CCC

\end{document}

Output

Circumscribe
  • 10,856