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

  • Maybe use the TikZ library tikzmark? – cfr Jan 13 '16 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 Jan 14 '16 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. – jmite Jan 14 '16 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 Jan 14 '16 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 Jan 14 '16 at 1:37
4

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 'tcolorboxand listing, but also fight with how to definecomment` 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}
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}

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.