Disallowing paragraph breaks inside environment

Your feelings are right. With

\begin{singlepar}
Wrong.\endgraf Wrong.
\end{singlepar}

you'd get a paragraph break and no error. The LaTeX format does

\let\endgraf\par

so making \endgraf equivalent to the primitive \par. Also \@@par is equivalent to the primitive \par, but it shouldn't bother you because it has @ in its name.

You could say

\makeatletter
\newenvironment{singlepar}
 {%
  % Ensure that this environment starts a new paragraph
  \@@par
  % Save normal \par for later use
  % Use of \par should abort the typesetting process
  \def\par{\typeout{DISALLOWED}\QUIT}%
  \let\endgraf\par
 }
 {%
  % Issue a paragraph break
  \@@par
 }
\makeatother

but it wouldn't solve the problem, because some package could say \let\foo\@@par and then \foo in the environment would cause a paragraph break.

Since it's not possible to know what control sequences point to the primitive \par memory location for their meaning (like \endgraf and \@@par), the problem is not really solvable.

One could think to absorb the environment's body with a variant of \NewEnviron that makes a non \long macro (the standard action is to do like \newcommand), but this wouldn't solve the problem either. A non \long macro only disallows the token \par in its argument, but will happily accept \endgraf or any control sequence made equivalent to the primitive \par.

Finally, it's not possible to disable a primitive. You can hide it by redefining it, but control sequences already \let to it will continue to work.


I don't think you want to hook in to \par that is the end of the first paragraph which really you want to allow, for a one para environment it is natural to allow

\begin{singlepar}

aaa

\end{singlepar}

which would not be allowed if you make \par an error.

What you don't want to allow is a second paragraph to start and that's \everypar There are still some concerns about things (re) defining \everypar but this will catch many cases, and allow the above example.

\documentclass{article}

%\newenvironment{singlepar}
%{\def\par{\PackageError{pkg}{par DISALLOWED}{}\ignorespaces}}%
%{}


\newenvironment{singlepar}
{\everypar{\everypar{\PackageError{pkg}{par DISALLOWED}{}}}\ignorespaces}%
{}
\begin{document}

\begin{singlepar}

aaa

\end{singlepar}


\begin{singlepar}

aaa

b
\end{singlepar}

\end{document}