Adding a horizontal rule between caption and lstlisting inside a tcolorbox

I have example listings for a book.

I'd like a horizontal rule the width of the tcolorbox between the caption and the listing.

The code used to produce it:

\documentclass[letterpaper,oneside,12pt]{book}
\usepackage{listings}
\usepackage[most]{tcolorbox}
\usepackage{caption}
\usepackage{xcolor}

\definecolor{captionbox}{cmyk}{0.43, 0.35, 0.35,0.01}

\tcbset{colback=captionbox!5!white,colframe=captionbox!75!black}

\BeforeBeginEnvironment{lstlisting}{\begin{tcolorbox}[toprule=3mm]\vskip-.5\baselineskip}
\AfterEndEnvironment{lstlisting}{\end{tcolorbox}}

\DeclareCaptionFormat{listing}{\parbox{\textwidth}{#1#2#3}}

\captionsetup[lstlisting]{format=listing,skip=10pt}

\lstset{numbers=none}

\begin{document}

\begin{lstlisting}[caption=Sample code block]
This is a code block
\end{lstlisting}

\end{document}


My only constraint is that I need to use the listings package and lstlisting because Pandoc requires that for listings. I am happy to replace anything else to produce the same effect of a box around the caption and listing with the rule between the caption and listing and a similar style feel.

• Your code doesn't work for me. Did you tested? And I think that the figure doesn't correspond to code. Where is title box (Sample code block) defined? Feb 17, 2015 at 15:14
• @Ignasi My apologies - I must have culled too much when I tried to make a MWE. I've updated it to code that works. Feb 17, 2015 at 15:34

Update: changed overlay first to overlay unbroken and first for the line to also appear in unbroken boxes. My mistake.

Too bad you can't use tcblistings, which seems to have been made specifically for this purpose and internally uses listings (I've read but not verified this).

Although I do not like "specific" solutions (i.e. solutions which need manual fiddling), I nonetheless propose this to you simply because it "works":

\documentclass[letterpaper,oneside,12pt]{book}

\usepackage{xcolor}

\usepackage{listings}
\usepackage{tcolorbox}
\tcbuselibrary{breakable}
\tcbuselibrary{skins}
\usepackage{caption}

\usepackage{tikz}

\usepackage{lipsum}

\definecolor{captionbox}{cmyk}{0.43, 0.35, 0.35,0.01}

\tcbset{%
colback=captionbox!5!white,%
colframe=captionbox!75!black,%
top=1mm,%   %% Used to manually align the caption with the horizontal line
%
%% Create a new "style" for your titled listings tcolorbox
mylistingwithtitle/.style = {%
breakable,%
%% Use tcolorbox's internal tikz object name (frame) to draw a horizontal line
overlay unbroken and first={\draw[shorten >=1.4pt, shorten <=1.4pt] ([yshift=-3em]frame.north west) -- ([yshift=-3em]frame.north east);}%
}%
}

\BeforeBeginEnvironment{lstlisting}{%
\begin{tcolorbox}[enhanced, toprule=3mm, mylistingwithtitle]%
\vskip-.5\baselineskip%
}

\AfterEndEnvironment{lstlisting}{\end{tcolorbox}}

\DeclareCaptionFormat{listing}{\parbox{\textwidth}{#1#2#3}}
\captionsetup[lstlisting]{format=listing,skip=15pt}

\begin{document}

%% This following line is only useful to execute \lipsum[1-4] inside the listing
\lstset{numbers=none, escapeinside={(*}{*)}}

\begin{lstlisting}[caption=Sample code block]
This is a code block

(*\lipsum[1-4]*)
\end{lstlisting}

\end{document}


If you change the caption formatting, you will need to manually fiddle with the vertical spacing, i.e the top=1mm option for the tcolorbox and the [yshift=-3em] to draw the horizontal line. You will also have to fiddle with the latter option, along with the shorten >=1.4pt and shorten <=1.4pt options, if you decide to change the formatting (top line, border width, inner margins, etc.) of the tcolorbox.

I took the liberty to add the breakable option to the tcolorbox to allow it to break over several pages.

Output:

• This is awesome. Thanks for humoring my specific constraints! Feb 18, 2015 at 18:18