1

This is a continuation of a previous question: How to prevent collisions in custom shapes with header and footer using tikzpicture and fancyhdr?


What I want

Please consider this MWE (taken from the second code of Schrödinger's cat's answer):

\documentclass{article}
\usepackage{lipsum}
\def\maxwidth{16cm}
\def\maxheight{20cm}

\usepackage[a4paper,margin=.25in,top=0.2cm,bottom=1.4cm,footskip=0.25in]{geometry}

% From https://tex.stackexchange.com/a/529773/152550
\newif\ifStart
\Startfalse
\newif\ifImage
\Imagefalse
\newif\ifCalloutRight
\CalloutRightfalse

\usepackage[skins,breakable]{tcolorbox}
\newsavebox\OurNiceSandBox
\tcbset{start/.code={\Starttrue},callout right/.code={\CalloutRighttrue},
shrink/.code={\tcbset{whatsapp cont/.style={hbox}}},
whatsapp cont/.style={width=\maxwidth},
whatsapp/.style={empty,breakable,
left=2mm,right=2mm,top=2mm,bottom=2mm,fontupper=\sffamily,
whatsapp cont,after skip=1ex},
whatsap skin/.style={% code for unbroken boxes:
frame code={%
\ifStart
 \ifCalloutRight
    \path[fill=#1]([xshift=-3mm]frame.north east) -- ++ (9mm,0) 
    -- ([yshift=-6mm]frame.north east); 
 \else
    \path[fill=#1]([xshift=3mm]frame.north west) -- ++ (-9mm,0) 
    -- ([yshift=-6mm]frame.north west); 
 \fi
\fi},
interior code={
\path[fill=#1,rounded corners=3mm] 
 (frame.south west) rectangle (frame.north east);
},  
% code for the first part of a break sequence: 
skin first is subskin of={emptyfirst}{%
frame code={%
\ifStart
 \ifCalloutRight
    \path[fill=#1]([xshift=-3mm]frame.north east) -- ++ (9mm,0) 
    -- ([yshift=-6mm]frame.north east); 
 \else
    \path[fill=#1]([xshift=3mm]frame.north west) -- ++ (-9mm,0) 
    -- ([yshift=-6mm]frame.north west); 
 \fi
\fi},
interior code={
\path[fill=#1] 
 (frame.south west) [rounded corners=3mm] |-
 (frame.north)  -|  (frame.east) [rounded corners=0mm] |- cycle;
},  
},
% code for the middle part of a break sequence: 
skin middle is subskin of={emptymiddle}{%
frame code={%
},
interior code={
\path[fill=#1] 
 (frame.south west) rectangle (frame.north east);
},  
},
% code for the last part of a break sequence: 
skin last is subskin of={emptylast}{%
frame code={%
},
interior code={
\path[fill=#1] 
 (frame.north west) [rounded corners=3mm] |-
 (frame.south)  -|  (frame.east) [rounded corners=0mm] |- cycle;
},  
}}}

\newtcolorbox{Mebox}[1][]{#1,whatsapp,flush left,whatsap skin=white}
\newcommand{\Me}[2][]{\begin{lrbox}{\OurNiceSandBox}
#2
\end{lrbox}%
\ifdim\wd\OurNiceSandBox<\maxwidth
\begin{Mebox}[shrink,#1]
#2
\end{Mebox}
\else
\begin{Mebox}[#1]
#2
\end{Mebox}
\fi}


\newtcolorbox{Youbox}[1][]{flush right,right skip=15mm,#1,whatsapp,callout right,
    whatsap skin=green!60!black}
\newcommand{\You}[2][]{\begin{lrbox}{\OurNiceSandBox}
#2
\end{lrbox}%
\ifdim\wd\OurNiceSandBox<\maxwidth
\begin{Youbox}[shrink,#1]
#2
\end{Youbox}
\else
\begin{Youbox}[#1]
#2
\end{Youbox}
\fi}

\newtcolorbox{Exercisebox}[1][]{#1,whatsapp,coltext=white,center,whatsap skin=blue}
\newcommand{\Exercise}[2][]{\begin{lrbox}{\OurNiceSandBox}
#2
\end{lrbox}%
\ifdim\wd\OurNiceSandBox<\maxwidth
\begin{Exercisebox}[shrink,#1]
#2
\end{Exercisebox}
\else
\begin{Exercisebox}[#1]
#2
\end{Exercisebox}
\fi}

\usepackage[explicit]{titlesec}

\usepackage{eso-pic}
\AddToShipoutPictureBG{\includegraphics[width=\paperwidth,height=\paperheight]{example-image}}

%%%%%%%%%%%%%%%%%%%%

\begin{document}

\Exercise{Hello}    

\Me[start]{This is working}

\Me{\includegraphics[scale=0.75]{example-image}}

\You[start]{\includegraphics{example-image-duck}}

\end{document}

MWE output

I want \Me and \You commands the possibility of add:

  • Lists (enumerate and itemize, and variants).
  • Sample code (listings).
  • Math mode and tables (array and tabular).

The following output was made using the non-automatic code taken from an old Schrödinger's cat's answer. The only thing that I couldn't do with that answer was adding listings code (it throws me Paragraph ended before \lst@next was complete):

What I want

The code of \Me should look like:

\Me[start]{This is working\\ Lists:

\begin{itemize}
\item Item 1.
\item Item 2.
\end{itemize}

Sample code (it does not work so I edited the output):

\begin{lstlisting}
var i=0
\end{lstlisting}

Table:

\begin{center}\begin{tabular}{|c|c|}
\hline1&2\\\hline
3&4\\\hline
\end{tabular}\end{center}}

Pros and cons of the old answer

Pros:

  • We can add lists and tables.
  • We can add text in a new line without problems.

Cons:

  • We cannot add listings.
  • It uses tikzpicture.
  • It does not handle image boxes.

What I have done

I looked at the following links:

But none of the above helped me solve the problems I describe.

manooooh
  • 3,203
  • 2
  • 21
  • 46
  • Environments and macros that implement real verbatim (as opposed to \detokenize) need to see the characters of the “code snippet” before they have been tokenized (these envs or commands do the tokenization with very specific catcodes). But when a macro takes arguments, as soon as it is expanded, the arguments are “grabbed” and their contents is tokenized under the current catcode régime. Then, it is too late for verbatim, \lstlisting, etc. to properly handle the contents that has been tokenized. In your “desired example”, the \Me macro, when expanded, would tokenize var i=0... – frougon Mar 05 '20 at 13:31
  • (along with all the rest of its arguments) under the standard category code régime, which would prevent lstlisting from doing a proper job with it—and could possibly cause errors, depending on the particular code snippet. Thus, this kind of usage seems difficult to implement. It is easier when the verbatim contents is isolated in pseudo-arguments, as allowed by the collectbox package. – frougon Mar 05 '20 at 13:32
  • @frougon I see. So LaTeX cannot predict the code sample of verbatim, listings etc. So my question is: Can you make use of the functions of collectbox to implement \You and \Me? Is that possible without so many effort? – manooooh Mar 05 '20 at 14:58
  • Not with the syntax presented in your question. The verbatim parts need to be collected separately and typeset in boxes. Then you can easily insert these boxes in your texts, as you would do with any box saved with e.g. \sbox or the lrbox environment. See for instance the second code sample in this answer of Werner. – frougon Mar 05 '20 at 15:52
  • There is another example here (David Carlisle), which puts a gray background (or whatever colour you want) behind the listing. – frougon Mar 05 '20 at 16:04
  • @frougon thank you very much! I appreciate it. I have a question: When using the Werner's solution, it compiles but \Me now has the max width instead of the adjustable width (for instance, I used \begin{lstlisting}^^J var i=0^^J\end{lstlisting} after "Sample code..."). How can we use listings but keeping the variable width? – manooooh Mar 05 '20 at 22:17
  • @frougon oh, the second code of same Werner's answer solves the issue. I think you can make a nice answer quoting him and I will be grateful. – manooooh Mar 05 '20 at 22:23

1 Answers1

1

Dealing with verbatim material

Verbatim material, of which lstlisting is some kind, is very delicate matter for TeX and LaTeX. When something is read verbatim, all characters that are usually special for TeX are temporarily made not special anymore (spaces, end of lines, backslashes, curly braces, percent signs, #, &, etc.). This is done by assigning category codes like 12 (other) to these characters for the time the verbatim material is read (this is done with macros \@makeother and \dospecials of the LaTeX kernel).

The timing of these massive category code changes is very sensitive when a verbatim-like setup is implemented (i.e., the transition from “normal mode” to “verbatim mode” is a bit tricky to implement). In order to understand the problem with the syntax you proposed, one needs to realize that TeX assigns category codes to characters on the fly when characters are read from the input stream, based on an internal table that can change during the TeX run when one does a \catcode assignment. This in-memory table has, figuratively speaking, a lot of “lines” that say: “in the current state, if character code xx is encountered in the input stream, it will be assigned category code yy”. This is done during the process of tokenization (TeX's eyes), i.e. very early in the processing of the input file (stream). When a category code is attached, according to the category code table, to a character that has just been read, the result is a character token. Such a token has both of its attributes frozen: a character code and a category code. One can examine them separately, but not really change the token once it has been formed.

Now, the important bit: as soon as a macro is expanded, it grabs its arguments and everything inside each of these arguments is immediately tokenized. As said, once tokenized, the category codes don't change anymore (there are e-TeX primitives like \scantokens and \detokenize that do very interesting things, but there are side effects; you can't use them to perform real verbatim processing on something that has already been tokenized).

Thus, a macro \Me taking for instance one argument and called like \Me{abc \verb|\bla yay \a| def} can't properly handle the verbatim material in its argument, because when the control sequence token \Me is expanded, the argument would be tokenized as:

  • a, b and c with catcode 11 (letter);

  • a space token (character code 32, category code 10);

  • the \verb control sequence token;

  • | with catcode 12 (other);

  • the \bla control sequence token;

  • y, a, y with catcode 11;

  • a space token (yes, only one!);

  • the \a control sequence token;

  • | with catcode 12 (other);

  • a space token;

  • d, e and f with catcode 11 (letter).

(this is under the normal category code régime). At this point, \verb can't work properly anymore because \a (like \bla) has been tokenized as a single control sequence token, whereas if \verb had been used correctly, it would have set up the catcode table in such a way that two tokens of catcode 12 would have been formed, in order to print a \ and a a. There is also a problem with the 3 consecutive spaces, which have become a single space token. Another problem is that in the input, there was a space after \bla and none after \a, but due to how control sequences are tokenized, this difference has vanished during the tokenization process (the space has been skipped as part of \bla's tokenization).

For these reasons, it is generally agreed that verbatim material can't be used inside the arguments of a macro or environment. lstlisting being essentially like verbatim, this also applies to it.

A robust solution to this problem is to save the sensitive material in a box register. Then, with the \usebox command, one can output the boxed material wherever it is needed (note: this is very efficient if the box is reused many times: e.g., a pictogram drawn with TikZ, saved in a box register and reused thousands of times in the same document).

How to do this with lstlisting is shown in the second example of Werner's answer (lrbox is an environment defined by the LaTeX kernel):

% Reserve a box register and assign it a name. This can be done
% in the preamble or in the document body.
\newsavebox{\myBox}

...

% Store material in the box register (here, verbatim material)
\begin{lrbox}{\myBox}
  \begin{lstlisting}
This is read in verbatim mode.
  \end{lstlisting}%
\end{lrbox}

...

% Print the box
\usebox{\myBox}

As you asked in comments, it is possible to define a macro (called \saveListing here) in order to save a few keystrokes for the “storing phase”:

\newcommand*{\saveListing}[1]{\begin{lrbox}{#1}\begin{lstlisting}}

With this macro, a listing can be read as verbatim and stored this way in box register \myBox:

\saveListing{\myBox}
#! /usr/bin/env python3

print(r"\LaTeX is {}!".format("awesome"))
\end{lstlisting}%
\end{lrbox}

That said, I wouldn't use such a macro myself, because:

  • With it, the \end{lstlisting} and \end{lrbox} are visible where you save material in the box, but not their \begin counterparts. This looks a bit weird and confuses syntax highlighting in my text editor (and probably others).

  • It's only a matter of copying and pasting or using LaTeX-specific functions of your text editor to insert the appropriate \begin{...} ... \end{...} pairs—this shouldn't be a problem.

Changes to the code

I did a few changes to the code:

  • reindented many parts;

  • fixed an overfull \hbox in \You caused by the use of right skip;

  • refactored \You, \Me and \Exercise; now, they are only tiny wrappers around the internal macro \@OurBox which contains all the logic common to \Me, \You and \Exercise;

  • moved all our PGF keys to /tcb/WhatsApp/ in order to avoid potential clashes with tcolorbox keys or keys defined by applications similar to this one (this way, even if tcolorbox has a /tcb/fixed width key one day, it won't conflict with our /tcb/WhatsApp/fixed width key).

  • The \You, \Me and \Exercise macros now all accept two optional arguments instead of only one, and a mandatory argument as before (which is the “contents” to typeset). Their syntax is \Command[opt1][opt2]{contents}.

    • The first optional argument opt1 is for our own keys (most notably start, shrink, varwidth and fixed width). It is executed in namespace /tcb/WhatsApp.

    • The second optional argument opt2 is for tcolorbox keys; it is executed in namespace /tcb.

  • I added a varwidth key in /tcb/WhatsApp (this replaces the shrink, varwidth upper combination which was used in a previous revision of this answer). Use varwidth in the first optional argument of \You, \Me or \Exercise when the contents argument contains vertical material such as paragraphs or lists, and you want a box that is exactly as wide as the natural width of the contents.

    Note that with this option, automatic line wrapping won't happen unless you explicitly use a minipage or similar in the contents argument of \You, \Me or \Exercise. If this is a problem, use fixed width as described right below.

  • I added a fixed width key in /tcb/WhatsApp. Use it in the first optional argument of \You, \Me or \Exercise when the contents argument contains vertical material (paragraphs, lists, etc.) and you want it to be typeset in a known width. Your box will then behave like a minipage. The option can be used in three ways:

    • fixed width or fixed width=true causes the box to have width \maxwidth;

    • fixed width=〈some width〉 uses the prescribed width;

    • fixed width=false disables all this.

If, in the first argument of \You, \Me or \Exercise, you use none of shrink, varwidth and fixed width (or use only fixed width=false), then the same algorithm as in @Schrödinger'scat's original code is used, namely:

  • the material is first typeset in an lrbox in order to measure its natural width;

  • if this natural width is strictly less than \maxwidth, it will be typeset in LR-mode (no paragraphs, etc.) and the resulting box will tightly fit around the material (this is implemented via /tcb/WhatsApp/shrink);

  • otherwise, the material is typeset in a kind of minipage whose width is \maxwidth.

Example

The following example illustrates most of the options presented above.

\documentclass{article}
\usepackage{geometry}
\geometry{a4paper, margin=.25in, top=0.2cm, bottom=1.4cm, footskip=0.25in}
\usepackage{listings}
\usepackage[breakable, skins, xparse]{tcolorbox}
\usepackage{varwidth}
\usepackage{etoolbox}
\usepackage{xparse}
\usepackage{lipsum}

\newcommand*{\maxwidth}{16cm}

% From https://tex.stackexchange.com/a/529773/152550
\makeatletter
\newsavebox{\OurNiceSandBox}

\newif\ifStart
\Startfalse
\newif\ifImage
\Imagefalse
\newif\ifCalloutRight
\CalloutRightfalse

\tcbset{
  WhatsApp/.is family,
  WhatsApp/.cd,            % don't take the risk of overwriting tcolorbox keys
  start/.code={\Starttrue},
  callout right/.code={\CalloutRighttrue},
  whatsapp cont/.code={\pgfqkeys{/tcb}{width=\maxwidth}},
  shrink/.style={
    /tcb/WhatsApp/whatsapp cont/.code={\pgfqkeys{/tcb}{hbox}}},
  varwidth/.style={
    /tcb/WhatsApp/whatsapp cont/.code={\pgfqkeys{/tcb}{hbox, varwidth upper}}},
  fixed width/.code={%
    \ifstrequal{#1}{true}
      {\tcbset{WhatsApp/whatsapp cont/.code={\pgfqkeys{/tcb}{width=\maxwidth}}}}
      {\ifstrequal{#1}{false}
         {}
         {\tcbset{WhatsApp/whatsapp cont/.code={\pgfqkeys{/tcb}{width={#1}}}}}%
      }%
  },
  fixed width/.default=\maxwidth,
  whatsapp/.code={%
    \pgfqkeys{/tcb}{empty, breakable, left=2mm, right=2mm, top=2mm, bottom=2mm,
                    fontupper=\sffamily, after skip=1ex}%
    \pgfqkeys{/tcb/WhatsApp}{whatsapp cont}%
  },
  whatsapp skin/.code={%
    \pgfqkeys{/tcb}{
      % Code for unbroken boxes
      frame code={
        \ifStart
         \ifCalloutRight
            \path[fill=#1]([xshift=-3mm]frame.north east) -- ++ (9mm,0)
              -- ([yshift=-6mm]frame.north east);
         \else
            \path[fill=#1]([xshift=3mm]frame.north west) -- ++ (-9mm,0)
              -- ([yshift=-6mm]frame.north west);
         \fi
        \fi
      },
      interior code={
        \path[fill=#1,rounded corners=3mm]
          (frame.south west) rectangle (frame.north east);
      },
      % Code for the first part of a break sequence
      skin first is subskin of={emptyfirst}{%
        frame code={
          \ifStart
           \ifCalloutRight
              \path[fill=#1]([xshift=-3mm]frame.north east) -- ++ (9mm,0)
                -- ([yshift=-6mm]frame.north east);
           \else
              \path[fill=#1]([xshift=3mm]frame.north west) -- ++ (-9mm,0)
                -- ([yshift=-6mm]frame.north west);
           \fi
          \fi
        },
        interior code={
          \path[fill=#1]
            (frame.south west) [rounded corners=3mm] |-
            (frame.north)  -|  (frame.east) [rounded corners=0mm] |- cycle;
        },
      },
      % Code for the middle part of a break sequence
      skin middle is subskin of={emptymiddle}{
        frame code={
        },
        interior code={
          \path[fill=#1]
            (frame.south west) rectangle (frame.north east);
        },
      },
      % Code for the last part of a break sequence
      skin last is subskin of={emptylast}{
        frame code={
        },
        interior code={
          \path[fill=#1]
            (frame.north west) [rounded corners=3mm] |-
            (frame.south)  -|  (frame.east) [rounded corners=0mm] |- cycle;
        },
      },
    }%
  },
}

\NewTColorBox{Mebox}{O{} O{}}
  {
    WhatsApp/.cd, #1, whatsapp, whatsapp skin=white, /tcb/.cd, flush left, #2,
  }

% I (frougon) removed the 'right skip=15mm' in 'Youbox' because there is
% nothing symmetric in Mebox and it was causing overfull \hbox warnings.
\NewTColorBox{Youbox}{O{} O{}}
  {
    WhatsApp/.cd, #1, whatsapp, callout right, whatsapp skin=green!40!gray,
    /tcb/.cd, flush right, #2,
  }

\NewTColorBox{Exercisebox}{O{} O{}}
  {
    WhatsApp/.cd, #1, whatsapp, whatsapp skin=blue,
    /tcb/.cd, coltext=white, center, #2,
  }

\newif\ifOurFixedWidth
\renewcommand*{\OurFixedWidthtrue}{\global\let\ifOurFixedWidth=\iftrue}
\renewcommand*{\OurFixedWidthfalse}{\global\let\ifOurFixedWidth=\iffalse}

% Internal macro that factors out common code for \You, \Me and \Exercise.
% #1: box name
% #2: PGF keys run in /tcb/WhatsApp
% #3: PGF keys run in /tcb
% #4: box contents
\NewDocumentCommand{\@OurBox}{ m m m +m }{%
  \begingroup
    % Check if #2 contains a call to 'fixed width' that is not
    % 'fixed width=false'. The code in #2 had better not had side effects
    % once the following \endgroup has been executed, otherwise a different
    % approach would be needed (e.g., separate macros as we had in a previous
    % revision, but this is not as nice to use).
    \OurFixedWidthfalse
    \tcbset{WhatsApp/.cd,
            fixed width/.code={%
              \ifstrequal{##1}{false}{}{\OurFixedWidthtrue}},
            #2}%
  \endgroup
  \ifOurFixedWidth
    \begin{#1box}[#2][#3]
    #4%
    \end{#1box}%
  \else
    \begin{lrbox}{\OurNiceSandBox}
    #4%
    \end{lrbox}%
    \ifdim \wd\OurNiceSandBox<\maxwidth \relax
      \begin{#1box}[shrink, #2][#3]
      #4%
      \end{#1box}%
    \else
      \begin{#1box}[#2][#3]
      #4%
      \end{#1box}%
    \fi
  \fi
}

\NewDocumentCommand{\Me}{ O{} O{} +m }{\@OurBox{Me}{#1}{#2}{#3}}
\NewDocumentCommand{\You}{ O{} O{} +m }{\@OurBox{You}{#1}{#2}{#3}}
\NewDocumentCommand{\Exercise}{ O{} O{} +m }{\@OurBox{Exercise}{#1}{#2}{#3}}
\makeatother

\usepackage{eso-pic}
\AddToShipoutPictureBG{%
  \includegraphics[width=\paperwidth,height=\paperheight]{example-image}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newsavebox{\myBox}            % for storing listings, or anything else

% Offers a small shortcut, but I wouldn't use it, as it doesn't improve
% readability in my opinion and can easily ruin syntax highlighting in the
% text editor.
\newcommand*{\saveListing}[1]{\begin{lrbox}{#1}\begin{lstlisting}}

\begin{document}

% Store one listing in \myBox:
\begin{lrbox}{\myBox}
\begin{lstlisting}
#! /usr/bin/env python3

print(r"\LaTeX is {}!".format("awesome"))
\end{lstlisting}%
\end{lrbox}

\Exercise{Hello}
% One interword space added on either side
\Exercise{\mbox{}\ Hello\ \mbox{}}

\Me[start, fixed width=10cm]{%
  This is a list environment typeset in width $10\,$cm:

  \begin{itemize}
  \item \lipsum[1][1-3]
  \item \lipsum[2][1-3]
  \item \lipsum[3][1-3]
  \end{itemize}

  Now, a listing we've previously saved in a box register:\par\nobreak\medskip

  \usebox{\myBox}% output the boxed material (can be done several times)
}

\You[start, fixed width]{%
  This is a list environment typeset in width \texttt{\string\maxwidth}:

  \begin{enumerate}
  \item \lipsum[4][1-3]
  \item \lipsum[5][1-3]
  \item \lipsum[6][1-3]
  \end{enumerate}%
}

% Other assignment to \myBox
\begin{lrbox}{\myBox}
\begin{lstlisting}
#! /bin/sh

echo "Oh, TeX is nice. :-)"
\end{lstlisting}%
\end{lrbox}

\Me[start, varwidth]{%
  This box is no wider than the natural width of its contents\\
  (it has been set with option \texttt{varwidth}).

  \bigskip
  Some code:\par\nobreak\medskip
  \usebox{\myBox}% output the boxed material (can be done several times)
}

\Me{\includegraphics[scale=0.5]{example-image-duck}}

\You[start]{%
  Reuse \texttt{\string\myBox} with its new contents: \usebox{\myBox}%
}

\Exercise{How many boxes are there on this page?}

\end{document}

Output

frougon
  • 24,283
  • 1
  • 32
  • 55
  • I am reading between lines, I will read carefully later. Thank you so much! As I said, I found your solution by using \newsavebox{\myListing} etc., which does the work very well. The problem for me is that I have a lot of sample code around all document, including lstlisting and \lstinline. So repeating this code every time seems to be a bad automation. Can you confirm if this is the only way, or there's a way to create a command where we can put \newsavebox{\myListing}\begin{lrbox}{\myListing}...? – manooooh Mar 06 '20 at 00:16
  • 1
    You can trivially create a command that takes \myListing as an argument and outputs \newsavebox{\myListing}\begin{lrbox}{\myListing} \begin{lstlisting}. But you need to have the \end{lstlisting} explicit in the code. It can't result from expansion of the verbatim material... because the verbatim material is read verbatim! Also, you can reuse the same box for several listings (maybe a \newsavebox{\myListing} per listing is overkill; maybe such registers should be allocated in the preamble, not by the macro). – frougon Mar 06 '20 at 00:20
  • Putting \newsavebox{\myListing} and \usebox{\myListing} per listing is overkill is exactly my problem. I have a lot of code sample. I tried to create a command \newcommand{\mycode}[1]{ \newsavebox{\mylisting} \begin{lrbox}{\mylisting} \begin{lstlisting}#1\end{lstlisting} \end{lrbox}} in the preamble, and use \mycode{Code here} inside \Me, but there are errors. – manooooh Mar 06 '20 at 00:28
  • \newsavebox{\myboxA} \newcommand*{\mycmd}[1]{\begin{lrbox}{#1}\begin{lstlisting}}. Boxing the verbatim material: `\mycmd{\myboxA} #! /usr/bin/env python3

    print(r"\LaTeX is {}!".format("awesome")) \end{lstlisting}% \end{lrbox}and then, when you need the contents:\usebox{\myboxA}`.

    – frougon Mar 06 '20 at 00:31
  • But \myboxA always contain the same content, isn't it? – manooooh Mar 06 '20 at 00:33
  • I've added it to the answer due to the newlines that are indistinguishable from spaces in comments. The box contains the same material, until you do another assignment with \mycmd{\myboxA}...\end{lstlisting}% \end{lrbox}. – frougon Mar 06 '20 at 00:38
  • Thanks. I understand. Can you put the small (but sufficient) automation in your full code, please? I don't understand where I have to put \mycmd{\myboxA} #! /usr/bin/env python3.... – manooooh Mar 06 '20 at 00:40
  • Done. I was a bit surprised to see the second boxed contents on the same line as the introductory text, but so far haven't had the time to look at how \Me and \You are implemented. Apparently, there is some kind of wrapping if one adds more text before the \usebox{\myboxA}. Ah, yes, I see a test like \ifdim\wd\OurNiceSandBox<\maxwidth, that could explain this behavior. Going to bed now, it's late! – frougon Mar 06 '20 at 00:55
  • I love the way you explain the involved concepts! I studied some of that sort but for C, I found some coincidences (although I have not finished the course xD). I think you could explain why we must "Box the verbatim material" so a full answer is given. Finally, I realize that \Me (instead of \You which does the things correctly) set \maxwidth as the adjustable width (see the blank space between the text and the right margin of \Me). Can you solve this issue, having \Me box the automatic width length as before? – manooooh Mar 07 '20 at 00:59
  • I'm afraid I already explained why the boxing is necessary. This is the only way to correctly handle verbatim material among the other things that can occur in the mandatory argument of \You or \Me. As for your new question, what you observed has nothing to do with a difference between \You and \Me. What you saw with \Me is a natural consequence of how Schrödinger's cat coded \You and \Me: when the natural width of the contents exceeds \maxwidth (which is the case for the first \Me here), it is typeset in a kind of minipage of width \maxwidth: therefore, the contents... – frougon Mar 07 '20 at 13:56
  • ... is allowed to wrap, which then gives the blank space you saw on the right, because after wrapping, the resulting lines are shorter than \maxwidth. I modified the last example to show how to pass options shrink, varwidth upper in the optional argument of \You or \Me when you want line wrapping within a width that is no more than necessary. This requires using \usepackage{varwidth}. – frougon Mar 07 '20 at 13:58
  • I am trying to create a box for enumerate (and so itemize) using the same idea for listings but I couldn't. First in the preamble I created \newsavebox{\myboxB}. Then comes \newcommand*{\mylist}[1]{\begin{lrbox}{#1}\begin{enumerate}}. Then in the document I put \mylist{\myboxB}\item Item 1\end{enumerate}%\end{lrbox} but the error is Something's wrong--perhaps a missing \item. How can we do it? – manooooh Mar 08 '20 at 21:02
  • 1
    I'm on smartphone now, so not very comfortable. lrbox is an hbox (inside, TeX is in horizontal mode), however list environments require a vbox such as a minipage. But since this is not verbatim material, you don't even need to use the lrbox to capture your stuff, you can directly use a minipage inside the arg of You or Me. – frougon Mar 08 '20 at 21:12
  • Thanks. But minipage has a fixed width. But remember that \Me and \You have variable width. – manooooh Mar 08 '20 at 21:14
  • 1
    It depends. When natural width < maxwidth, the cmds use tcb hbox option, and there you would need to add an outer vbox such as a minipage or varwidth env. But in the other case, the whole is already a vbox, and list envs should work there... if you can trigger this mode. List envs do some line wrapping, so you need to decide on a width at some point. – frougon Mar 08 '20 at 21:18
  • Maybe what you want here is a variant of the macros that just imposes the width of your choice to the tcolorbox. Then the minipages inside could use this width (there must be \tcboxwidth or so to retrieve it dynamically when inside a tcolorbox of fixed width: /tcb/width to trigger this mode). – frougon Mar 08 '20 at 21:28
  • Is it easy to implement? Because if that is much more difficult than just using \begin{minipage}{<fixed width>}\begin{enumerate} inside \Me or \You then it does not matter. I can set <fixed width> by inspection when rendering the document. – manooooh Mar 08 '20 at 21:31
  • Should just be a simplification of the existing macros: no need to test, just forward the argument to the width tcb key. – frougon Mar 08 '20 at 21:33
  • I prefer that you implement it; I fear to make gross mistakes. – manooooh Mar 08 '20 at 21:34
  • I've updated the answer: 1) Code refactoring to reduce redundancy. 2) More unified syntax (no more \MeFixedWidth and \YouFixedWidth: this is now handled via a fixed width=... option). 3) Put our PGF keys in their own namespace to prevent clashes. 4) Fix an overfull \hbox in \You. 5) Improve answer text, include only one piece of code to keep the answer shorter and clearer, etc. I hope you'll like it. :-) Note: don't use shrink, varwidth upper anymore; just use varwidth to achieve the same effect. – frougon Mar 09 '20 at 19:20
  • Apparently, you liked. :-) I made a small change. The difference will show up if you do perverse things like \Exercise{Hello }. The previous code (from the original answer) would add a space at the end... but that was probably unintended (there were two space tokens in this situation, but one of them was cancelled by \unskip from \end{lrbox}). OTOH, \Exercise{ Hello} would not add a space, because \ignorespaces is very different from \unskip (it recursively expands expandable tokens and ignores space tokens along the way, until it finds an unexpandable, non-space token). – frougon Mar 10 '20 at 00:33
  • Long story short: the code doesn't rely on the spurious space at the end of the box anymore. Now, \Exercise{ Hello } adds a space neither at the beginning, nor at the end. This is not the same behavior as with \mbox or \hbox, but at least start and end now work in the same way and the code forgives you if you forget a % in the input. If you really want to add the spaces, the second box in my updated example shows how to do so. I think it should be fine now. – frougon Mar 10 '20 at 00:34