0

I want to create several minted listings inside tcolorboxes. Similarly to https://tex.stackexchange.com/a/396731, I would like to adjust the size of the tcolorbox to contain the line numbers. However, the linked solution uses a fixed offset of 4mm, which is too short for line numbers with 3 or more digits; this can easily happen when I want to print parts of some existing code using tcbinputlisting. Setting the offset to be big enough for 4 digit line numbers when all line numbers in a listing only use one or two digits also doesn't look too pretty to me. Ideally, I would like this offset to be automatically adjusted based on the length of the longest line number (which should always be the last line number).

Is this possible to do or do I have to use different macros depending on the number of digits in line numbers?

0

Try this not-elegant-enough attempt.

Some key ideas:

  • Assign a unique number to each Verbatim environment by using new counter verbatim@cnt.
  • Get the ending code line number per Verbatim env (stored in counter FancyVerbLine), convert it to a dimension, and make it linked with the unique env number.
  • Write this relation to aux file, which will be read at the second compilation.
  • In each customized tcolorbox env, use current Verbatim env number to retrieve the corresponding dimension, then use it to set both left padding /tcb/left and the offset of the background color of line numbers drawn in `/tcb/overlay.
\documentclass[11pt,letterpaper]{article}
\usepackage[most, minted]{tcolorbox}

\newcounter{verbatim@cnt}

\makeatletter
\AtEndEnvironment{Verbatim}{%
  \stepcounter{verbatim@cnt}%
  \protected@write\@auxout{}{%
    \global\protect\@namedef{verbatim@numwidth@\the\c@verbatim@cnt}{%
      \ifnum\c@FancyVerbLine>999
        7.5mm%
      \else\ifnum\c@FancyVerbLine>99
        6mm%
      \else
        4mm%
      \fi\fi
    }%
  }%
}

\def\minted@auto@numwidth#1{%
  \ifcsname verbatim@numwidth@\the\numexpr\c@verbatim@cnt#1\relax\endcsname
    \csname verbatim@numwidth@\the\numexpr\c@verbatim@cnt#1\relax\endcsname
  \else
    4mm%
  \fi
}
\makeatother

\makeatletter
\newtcblisting{myminted}[2][]{%
    listing engine=minted,
    minted language=#2,
    listing only,
    breakable,
    enhanced,
    minted options = {
        linenos, 
        breaklines=true, 
        breakbefore=., 
        fontsize=\footnotesize, 
        numbersep=2mm
    },
    overlay={%
        \begin{tcbclipinterior}
            \fill[gray!25] (frame.south west) rectangle ([xshift=\dimexpr\minted@auto@numwidth{}\relax]frame.north west);
        \end{tcbclipinterior}
    },
    % in "left", \c@verbatim@cnt is not stepped yet, hence the argument "+1"
    left=\dimexpr\minted@auto@numwidth{+1}\relax,
    #1   
}
\makeatother

%\usepackage{unravel}
\providecommand\unravel[1]{#1}
\providecommand\unravelsetup[1]{}
\unravelsetup{max-action=1000, max-input=1000, max-output=100}


\begin{document}

\begin{myminted}[minted options app={firstnumber=8}]{c}
#include <stdio.h>

void main ()
{
    printf("hello world");
}
\end{myminted}

\begin{myminted}[minted options app={firstnumber=98}]{c}
#include <stdio.h>

void main ()
{
    printf("hello world");
}
\end{myminted}

\begin{myminted}[minted options app={firstnumber=998}]{c}
#include <stdio.h>

void main ()
{
    printf("hello world");
}
\end{myminted}

\end{document}

enter image description here

5
  • Thanks, works perfectly! I think you have an off-by-one error when comparing FancyVerbLine, though. – Irgendwhy Feb 8 at 18:38
  • @Irgendwhy That +1 used in /tcb/left=... is required. When the value of key /tcb/left is used, the new counter verbatim@cnt is not yet stepped. – muzimuzhi Z Feb 8 at 19:06
  • @mizumuzhi I was referring to the lines \ifnum\c@FancyVerbLine>1000 and \else\ifnum\c@FancyVerbLine>100. It seems to me that the test should be against 999 and 99, respectively. Not a big deal either way, just wanted to mention it. – Irgendwhy Feb 8 at 19:36
  • @Irgendwhy Ah yes, you're right. I will fix this. What a pity that TeX does not support comparison operators like <= and >=. – muzimuzhi Z Feb 8 at 21:34
  • @Irgendwhy Answer updated. Thanks. – muzimuzhi Z Feb 8 at 21:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.