Fake CAPTCHA image spelling "unit propagation". Generated with Wolfram Alpha.
The Blog of Bob Rubbens

Centering two wide code listings in LaTeX

Thursday, November 28, 2024

In our recent paper we have quite a few figures that contained two code snippets side by side. Every single one was a pain, because I somehow couldn't figure out how to center such a figure properly. The paper employs multiple solutions, because they were all suboptimal, for various small reasons that I unfortunately can't recall. Today I ran into this yet again, so I took another half hour to try and find a proper solution to this problem. Lo and behold, I did! At least, partially. It still requires specifying the width of the code listings up front, but that's not too bad. This method also has a nice additional feature: if it goes beyond a specified width, it scales down the contents. This might not be a general solution, but I'm sure this would've been nice to have while writing the previous paper!

\begin{figure}[t]
\begin{adjustbox}{max width=1.4\linewidth,center}
\centering
\begin{subfigure}[t]{0.45\textwidth}
\begin{lstlisting}[style=pvl, xleftmargin=0.7cm]
(Left)
\end{lstlisting}
\end{subfigure}
\qquad
\begin{subfigure}[t]{0.7\textwidth}
\begin{lstlisting}[style=pvl, xleftmargin=0.7cm]
(Right)
\end{lstlisting}
\end{subfigure}
\end{adjustbox}
\end{figure}

This solution is due to "user11232" over at tex.stackexchange. Somehow I was unable to find this post even though it solves exactly my problem. At least I can use it now!

The only problem left to solve is to somehow make this process of determining the width to set easier. I use the mdframed environment for this, because a plain fbox{...} command around the lstlisting environment breaks for some reason. By wrapping the lstlisting in an mdframed environment, a border is drawn around the code listing, allowing me to check if the code overflows the box anywhere. If so, the size needs to be incremented. If not, the size can be made smaller, or be left alone if I like how it looks. It's not as good as automating determining the size, but it's also simple and maintainable.

Here is a complete example, with some code fluff adde in to show the code overflowing:

\documentclass{article}

\usepackage{
  listings,  % lstlisting environment
  adjustbox, % adjustbox environment
  subcaption, % subfigure environment
  mdframed, % mdframed environment
}
% Remove all margins in mdframed environment
\mdfsetup{
  skipabove=0pt,
  skipbelow=0pt,
  leftmargin=0pt,
  rightmargin=0pt,
  innerleftmargin=0pt,
  innerrightmargin=0pt,
  innertopmargin=0pt,
  innerbottommargin=0pt
}

\begin{document}

\begin{figure}[t]
\begin{adjustbox}{max width=1.4\linewidth,center}
\centering
\begin{subfigure}[t]{0.45\textwidth}
\begin{mdframed}
\begin{lstlisting}
choreography increment(Store s) {
  endpoint a = Role(s);
  endpoint b = Role(null);

  requires Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 0;
  ensures Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 2;
  run {
    a: a.s.x := a.s.x + 1;
    channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1) ** a.s.x > 1;
    communicate a: a.s -> b: b.s;
    assert Perm[b](a.s, 1\2) ** Perm[b](a.s.x, 1);
    b: a.s.x := a.s.x + 1;
    channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1\2) ** a.s.x > 2;
    communicate b: b.s -> a: a.s;
} }
\end{lstlisting}
\end{mdframed}
\end{subfigure}
\qquad % Add space to taste
\begin{subfigure}[t]{0.7\textwidth}
\begin{mdframed}
\begin{lstlisting}
choreography increment(Store s) {
  endpoint a = Role(s);
  endpoint b = Role(null);

  requires Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 0;
  ensures Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 2;
  run {
    a: a.s.x := a.s.x + 1;
    channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1) ** a.s.x > 1;
    communicate a: a.s -> b: b.s;
    assert Perm[b](a.s, 1\2) ** Perm[b](a.s.x, 1);
    b: a.s.x := a.s.x + 1;
    channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1\2) ** a.s.x > 2;
    communicate b: b.s -> a: a.s;
} }
\end{lstlisting}
\end{mdframed}
\end{subfigure}
\end{adjustbox}
\caption{Overflowing}
\end{figure}

\begin{figure}[t]
\begin{adjustbox}{max width=1.4\linewidth,center}
\centering
\begin{subfigure}[t]{0.6\textwidth}
\begin{mdframed}
\begin{lstlisting}[breaklines]
choreography increment(Store s) {
  endpoint a = Role(s);
  endpoint b = Role(null);

  requires Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 0;
  ensures Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 2;
  run {
    a: a.s.x := a.s.x + 1;
    channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1) ** a.s.x > 1;
    communicate a: a.s -> b: b.s;
    assert Perm[b](a.s, 1\2) ** Perm[b](a.s.x, 1);
    b: a.s.x := a.s.x + 1;
    channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1\2) ** a.s.x > 2;
    communicate b: b.s -> a: a.s;
} }
\end{lstlisting}
\end{mdframed}
\end{subfigure}
\qquad % Add space to taste
\begin{subfigure}[t]{0.9\textwidth}
\begin{mdframed}
\begin{lstlisting}[breaklines]
choreography increment(Store s) {
  endpoint a = Role(s);
  endpoint b = Role(null);

  requires Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 0;
  ensures Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 2;
  run {
    a: a.s.x := a.s.x + 1;
    channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1) ** a.s.x > 1;
    communicate a: a.s -> b: b.s;
    assert Perm[b](a.s, 1\2) ** Perm[b](a.s.x, 1);
    b: a.s.x := a.s.x + 1;
    channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1\2) ** a.s.x > 2;
    communicate b: b.s -> a: a.s;
} }
\end{lstlisting}
\end{mdframed}
\end{subfigure}
\end{adjustbox}
\caption{Boxed}
\end{figure}

\end{document}

Which ends up looking something like:

code_listings.png