3

I've got a code snippet, that I'd like to annotate with arrows, boxes, and bubbles pointing to the various parts of the code.

Right now, I've got the code in a minted environment, inside a minipage, inside a tikzpicture.

I'm wondering, is it possible to draw on top of the minipage, so that I can point to various parts of the code inside the minipage with arrows?

What I have:

\documentclass{article}
\usepackage{tikz}
\usepackage{minted}

\begin{document}

\tikzstyle{mybox} = [draw=blue, fill=green!20, very thick,
    rectangle, rounded corners, inner sep=10pt, inner ysep=20pt]
%
\begin{tikzpicture}[transform shape,  baseline=-3.5cm]
\node [mybox] (box) {%
\begin{minipage}[t!]{0.5\linewidth}
Foo
\end{minipage}

    \begin{minipage}[t!]{0.5\linewidth}
        \begin{minted}{haskell}   
let 
  map = \f -> \l -> case l of
    [] -> []
    (a :: b) -> (f a) :: (map f b)
in case map (\x->x) [1,2] of
        (h :: t) -> (h,t)
\end{minted}
\end{minipage}

};
\end{tikzpicture}
%

\end{document}

What I want:

enter image description here

7
  • Maybe use the TikZ library tikzmark?
    – cfr
    Commented Jan 13, 2016 at 23:55
  • The contents of the node is much too wide for the width of text. First, the box itself takes up width and then you also have space between the two minipages.
    – cfr
    Commented Jan 14, 2016 at 0:02
  • @cfr So, right now I'm using the left minipage to push the minted environment to the right, but that could easily change. The point is to leave space for the diagrams I'd like to add on top. Commented Jan 14, 2016 at 0:06
  • 1
    I would suggest using tcolorbox for the background box and to align the two parts you want aligned. However, I don't know about marking up the code. It seems that tikzmark works with listings / lstlistings and has specific code to modify the hooks provided, but minted isn't mentioned. (For some reason, I thought it was, but I must have been confused.)
    – cfr
    Commented Jan 14, 2016 at 0:30
  • 1
    Someone else will probably have a better idea than me. I've never used minted but it seems quite popular.
    – cfr
    Commented Jan 14, 2016 at 1:37

2 Answers 2

5

If you can change to listings, with tikzmark, tikzmarklistings library and tcolorbox's comment and listing option you can do something similar to what you want. This is just a starting example. You will need to customize tcolorbox and listing, but also fight with how to define comment to fit your needs.

enter image description here

Following code shows how to do it. tcolorbox offers a listing and comment option which allows to include any text beside a listing. A mybox has been declared with a parameter which can be used to define the comment you want.

Because \usetikzmarlibrary{listings} is loaded several tikzmarks are defined for every listing line. You need to name every code fragment with name=..., then pic cs:line-name-... can be used for pointing arrows. While writing this I think that code name should be another parameter but ... I told you, it's just a starting example ;-)

\documentclass[a4paper]{article}
\usepackage{tikz}
\usepackage[most]{tcolorbox}
\usetikzlibrary{tikzmark}
\usetikzmarklibrary{listings}
\usepackage{lipsum}

\newtcblisting{mybox}[1]{
notitle,
colback=green!30,
colframe=blue,
listing only,
listing options={language=haskell, basicstyle=\ttfamily, name=code},
comment side listing,
lefthand width=.24\linewidth,
#1
}

\begin{document}

\lipsum[1]

\begin{mybox}{comment={\begin{tabular}{l}
Explanation\tikzmark{a}\tikz[remember picture,overlay]{\draw (pic cs: a)--(pic cs:line-code-1-start);}\\
\rule{0pt}{1cm}
More Explanation\tikzmark{b}
\end{tabular}
\tikz[remember picture,overlay]{
\draw[->,red] (pic cs:b)--(pic cs:line-code-6-first);}
}}
let 
  map = \f -> \l -> case l of
    [] -> []
    (a :: b) -> (f a) :: (map f b)
in case map (\x->x) [1,2] of
        (h :: t) -> (h,t)
\end{mybox}

\end{document}
2
  • When I run your code verbatim the arrows don't show up. Perhaps its because cs:line-code-6-first, etc. is never remembered? Commented May 8, 2020 at 18:44
  • @LeifAndersen I don't understand your comment. I've tested my code again and it works for me. Could you better explain what's wrong for you?
    – Ignasi
    Commented May 9, 2020 at 9:07
3

This is as far as I got. I can only run minted in draft mode and could not get escapeinside to work for any characters.

\documentclass[draft]{article}
\usepackage{tikz}
\usetikzlibrary{tikzmark,calc,shapes.geometric}
\usepackage{minted}

\begin{document}

\noindent\begin{tikzpicture}[remember picture,baseline=(n1.north)]
\node[minimum width=0.5\textwidth,minimum height=3cm] (box) {};
\node[right,green] at (box.west) {Foo:};
\node[draw,ellipse] (n1) at ($(box.south)!.667!(box.north)$) {Explanation};
\node[draw] (n2) at ($(box.south)!.333!(box.north)$) {More explanation};
\end{tikzpicture}%
\begin{minipage}[t]{0.5\linewidth}
\begin{minted}[escapeinside=||] {haskell}
let 
  |\tikzmark{p1}|map = \f -> \l -> case l of
    [] -> []
    (a :: b) -> (f a) :: (map f b)
in case map (\x->x) [1,2] of
        |\tikzmark{p2}|(h :: t) -> (h,t)
\end{minted}
\end{minipage}

\begin{tikzpicture}[remember picture,overlay]
\draw[->] (n1.east) -- (pic cs:p1);
\draw[->] (n2.east) -- (pic cs:p2);
\end{tikzpicture}

\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .