# Position tikz pictures at left margin of a listing code block

I'm trying to finish my attempt at having good looking unlimited line annotations for the listing environments, using tikz. The original problem was that indentation caused shifts in the positioning, so I changed the code to use the overlay feature.

My original question is here: How to add numerical (ala No Starch Press) listing notes without XeTeX?

Unfortunately, I'm still unable to figure out how to properly align them:

Update: the code is merged with Werner's version.

\documentclass{article}
\usepackage{libertine}
\usepackage[log-declarations=false]{xparse}
\usepackage[quiet]{fontspec}
\setromanfont[Ligatures={Common,TeX}]{Linux  Libertine O}
\setmainfont[Ligatures={Common,TeX}]{Linux  Libertine O}
\setmonofont[SmallCapsFont={Latin Modern Mono Caps}]{Latin Modern Mono Light}
\setsansfont{Linux Biolinum O}
\usepackage{xunicode}
\usepackage[x11names, rgb]{xcolor}
\usepackage{tikz}
\usetikzlibrary{snakes,arrows,shapes}
\usepackage{amsmath}
\usepackage{listings}

\newcommand{\mynumold}[1]{{\oldstylenums{#1}}}

\newcounter{lstNoteCounter}

\newcommand*\lnnum[2][,]{\tikz[baseline=(char.base), overlay]{
\node[shape=circle,draw,inner sep=0.8pt,
fill=black, text=white, #1] (char) {\rmfamily\bfseries\footnotesize#2};}}

\newcommand*{\lnote}{\stepcounter{lstNoteCounter}\llap{{\lnnum{\thelstNoteCounter}}\hskip 4em}}
\newcommand*{\linenum}[1]{%
\setbox0=\hbox{\rmfamily\bfseries\footnotesize#1}%
\lnnum[anchor=west]{#1}\hspace*{\dimexpr1ex+\wd0\relax}%
}
\lstnewenvironment{annotatedcsource}[1][]
{
\setcounter{lstNoteCounter}{0}
\lstset{
basicstyle=\ttfamily,
frame=lines,
framexleftmargin=0.5em,
framexrightmargin=0.5em,
basicstyle=\ttfamily\footnotesize,
numberstyle=\normalsize\itshape\mynumold,
backgroundcolor=\color{LemonChiffon1},
showstringspaces=false,
numbers=left,
numbersep=2.5em,
escapeinside={(*@}{@*)},#1}
}
{}

\begin{document}
\pagestyle{empty}

\begin{annotatedcsource}[caption={RC4 blues}]
void
rc4_init(struct rc4_state *const state, const u_char *key, int keylen)
{
u_char j;
int i, k;

/* Initialize state with identity permutation */
for (i = 0; i < 256; i++)
(*@\lnote@*)state->perm[i] = (u_char)i;
state->index1 = 0;
(*@\lnote@*)state->index2 = 0;

/* Randomize the permutation using key data */
for (j = i = k = 0; i < 256; i++) {
j += state->perm[i] + key[k];
(*@\lnote@*)swap_bytes(&state->perm[i], &state->perm[j]);
if (++k >= keylen)
(*@\lnote@*)k = 0;
}
\end{annotatedcsource}

Some source code doing whatever \linenum{1}, with line numbers and annotations \linenum{2}.

\begin{annotatedcsource}[caption={Hello blues}]
void hello(int times)
{
int i;

(*@\lnote@*)if (times > 4) {
printf("Feeling chatty today?\n");
return;
}

/* foobar */
(*@\lnote@*)for (i = 0; i < times; i++) {
printf("Hello %d!\n", i);
}

(*@\lnote@*)return;
}
\end{annotatedcsource}

Some source code doing whatever \linenum{1}, with line numbers and annotations \linenum{2}.

\end{document}


Output:

Desired output:

• Properly aligned circled numbers to the left or right margins along the line numbers.
• In other words, the circled numbers must appear outside of the code block box, to the right or left of the line numbers.
• Any kind of source code listing should work fine, no indentation assumptions (please).
• Properly spaced circled numbers for the actual references embedded in the text.

Like this:

-
Somehow I can't get XeTeX working so I used PFDLaTeX by adding anchor=west, option to the tikzpicture and using say Some source code doing whatever \lnnum{1}\quad, with line numbers and annotations \lnnum{2}\quad. solves the second problem. Frankly, I couldn't understand what your first problem is. Note that snakes library is deprecated and replaced with decorations. –  percusse Apr 13 '12 at 19:53
percusse, I've clarified the desired output. It's the alignment and positioning of the circled numbers in the code block that bothers me. \quad seems like it should go into a new command defined for the references, to avoid duplicating the code. Re: snakes, correct, I took the minimal example template from an old file and forgot to remove it (obvious as there are no snake decorations anywhere). –  soze Apr 13 '12 at 20:04

The following seems a bit of a hack, but provides the output you're after:

\documentclass{article}
%\usepackage{libertine}
%\usepackage[log-declarations=false]{xparse}
%\usepackage[quiet]{fontspec}
%\setromanfont[Ligatures={Common,TeX}]{Linux  Libertine O}
%\setmainfont[Ligatures={Common,TeX}]{Linux  Libertine O}
%\setmonofont[SmallCapsFont={Latin Modern Mono Caps}]{Latin Modern Mono Light}
%\setsansfont{Linux Biolinum O}
%\usepackage{xunicode}
\usepackage[x11names, rgb]{xcolor}
\usepackage{tikz}
%\usetikzlibrary{snakes,arrows,shapes}
\usepackage{amsmath}
\usepackage{listings}

\newcommand{\mynumold}[1]{{\oldstylenums{#1}}}

\newcounter{lstNoteCounter}

\newcommand*\lnnum[2][,]{\tikz[baseline=(char.base), overlay]{
\node[shape=circle,draw,inner sep=0.8pt,
fill=black, text=white, #1] (char) {\rmfamily\bfseries\footnotesize#2};}}

\newcommand*{\lnote}{\stepcounter{lstNoteCounter}\llap{{\lnnum{\thelstNoteCounter}}\hskip 4em}}
\newcommand*{\linenum}[1]{%
\setbox0=\hbox{\rmfamily\bfseries\footnotesize#1}%
\lnnum[anchor=west]{#1}\hspace*{\dimexpr1ex+\wd0\relax}%
}
\lstnewenvironment{annotatedcsource}[1][]
{
\setcounter{lstNoteCounter}{0}
\lstset{
basicstyle=\ttfamily,
frame=lines,
framexleftmargin=0.5em,
framexrightmargin=0.5em,
basicstyle=\ttfamily\footnotesize,
numberstyle=\normalsize\itshape\mynumold,
backgroundcolor=\color{LemonChiffon1},
showstringspaces=false,
numbers=left,
numbersep=2.5em,
escapeinside={(*@}{@*)},#1}
}
{}

\begin{document}
\pagestyle{empty}

\begin{annotatedcsource}[caption={Foobar}]
void hello(int times)
{
int i;

(*@\lnote@*)if (times > 4) {
printf("Feeling chatty today?\n");
return;
}

/* foobar */
(*@\lnote@*)for (i = 0; i < times; i++) {
printf("Hello %d!\n", i);
}

(*@\lnote@*)return;
}
\end{annotatedcsource}

Some source code doing whatever \linenum{1}, with line numbers and annotations \linenum{2}.

\end{document}


numbersep=2.5em pushes the listing numbers 2.5em away from the listing edge. As such, this leaves room to push \lnote a length 4em from where it's called; into the gap. This is the hack I'm referring to: moving the TikZ node 4em (a fixed length), since one may require a length that depends on the indentation of the listing. \linenum{<num>} now sets \lnnum with anchor=west and pads it with some horizontal space to properly align any following text.

An alternative version that sets the TikZ node in a "less-hacky" way. :)

\documentclass{article}
%\usepackage{libertine}
%\usepackage[log-declarations=false]{xparse}
%\usepackage[quiet]{fontspec}
%\setromanfont[Ligatures={Common,TeX}]{Linux  Libertine O}
%\setmainfont[Ligatures={Common,TeX}]{Linux  Libertine O}
%\setmonofont[SmallCapsFont={Latin Modern Mono Caps}]{Latin Modern Mono Light}
%\setsansfont{Linux Biolinum O}
%\usepackage{xunicode}
\usepackage[x11names, rgb]{xcolor}
\usepackage{tikz}
%\usetikzlibrary{snakes,arrows,shapes}
\usepackage{amsmath}
\usepackage{listings}

\makeatletter
\let\insertnotenum\relax
\lst@Key{numbers}{none}{%
\let\lst@PlaceNumber\@empty
\lstKV@SwitchCases{#1}%
{none&\\%
left&\def\lst@PlaceNumber{\llap{\normalfont
\lst@numberstyle{\thelstnumber}\kern\lst@numbersep\insertnotenum}}\\%
right&\def\lst@PlaceNumber{\rlap{\normalfont
\kern\linewidth \kern\lst@numbersep
\lst@numberstyle{\thelstnumber}}}%
}{\PackageError{Listings}{Numbers #1 unknown}\@ehc}}
\makeatother

\newcommand{\mynumold}[1]{{\oldstylenums{#1}}}

\newcounter{lstNoteCounter}

\newcommand*\lnnum[2][,]{\tikz[baseline=(char.base), overlay]{
\node[shape=circle,draw,inner sep=0.8pt,
fill=black, text=white, #1] (char) {\normalfont\rmfamily\bfseries\footnotesize#2};}}
\makeatletter
\newcommand*{\lnote}{%
\stepcounter{lstNoteCounter}%
\global\def\insertnotenum{\lnnum[anchor=east,xshift=-1.5ex]{\thelstNoteCounter}%
\global\let\insertnotenum\relax}%
}
\makeatother
\newcommand*{\linenum}[1]{%
\setbox0=\hbox{\rmfamily\bfseries\footnotesize#1}%
\lnnum[anchor=west]{#1}\hspace*{\dimexpr1ex+\wd0\relax}%
}
\lstnewenvironment{annotatedcsource}[1][]
{
\setcounter{lstNoteCounter}{0}
\lstset{
basicstyle=\ttfamily,
frame=lines,
framexleftmargin=0.5em,
framexrightmargin=0.5em,
basicstyle=\ttfamily\footnotesize,
numberstyle=\normalsize\itshape\mynumold,
backgroundcolor=\color{LemonChiffon1},
showstringspaces=false,
numbers=left,
numbersep=2.5em,
escapeinside={(*@}{@*)},#1}
}
{}

\begin{document}
\pagestyle{empty}

\begin{annotatedcsource}[caption={Foobar}]
void hello(int times)(*@\lnote@*)
{
int i;
(*@\lnote@*)
if (times > 4) {
printf("Feeling chatty today?\n");
return;
}

(*@\lnote@*)/* foobar */
for (i = 0; i < times; i++) {(*@\lnote@*)
printf("Hello %d!\n", i);
}

(*@\lnote@*)
return;
}
\end{annotatedcsource}

Some source code doing whatever \linenum{1}, with line numbers and annotations \linenum{2}.

\end{document}


The modifications include:

1. A change in the way the numbers key-value is handled. The modification inserts \insertnotenum as part of the line number printing mechanism (or \lst@PlaceNumber);
2. \insertnotenum is a self-destruct macro that removes itself after it is used;
3. Use (*@\lnote@*) before the line that you want referenced, so that the line number of the following line is appropriately marked.

Note that this version now sets \lnote at the same horizontal distance, regardless of the code indentation.

-

Like so:

\documentclass{article}
\usepackage[OT1]{fontenc}
\usepackage{lmodern}
\usepackage{beramono}
\usepackage[x11names, rgb]{xcolor}
\usepackage{tikz}
\usetikzlibrary{snakes,arrows,shapes}
\usepackage{amsmath}
\usepackage{listings}

\newcommand{\mynumold}[1]{{\oldstylenums{#1}}}

\newcounter{lstNoteCounter}

\newcommand*\lnnum[1]{\tikz[baseline=(char.base), overlay]{
\node[shape=circle,draw,inner sep=0.8pt,
fill=black, text=white, xshift=-4ex] (char) {\rmfamily\bfseries\footnotesize#1};}}

\newcommand*{\lnote}{\stepcounter{lstNoteCounter}\llap{{\lnnum{\thelstNoteCounter}}\hskip 3em}}

\lstnewenvironment{annotatedcsource}[1][]
{
\setcounter{lstNoteCounter}{0}
\lstset{
basicstyle=\ttfamily,
frame=lines,
framexleftmargin=0.5em,
framexrightmargin=0.5em,
basicstyle=\ttfamily\footnotesize,
numberstyle=\normalsize\itshape\mynumold,
backgroundcolor=\color{LemonChiffon1},
showstringspaces=false,
numbers=left,
numbersep=8ex,
escapeinside={(*@}{@*)},#1}
}
{}

\begin{document}
\pagestyle{empty}

\begin{annotatedcsource}[caption={Foobar}]
void hello(int times)
{
int i;

(*@\lnote@*)if (times > 4) {
printf("Feeling chatty today?\n");
return;
}

/* foobar */
(*@\lnote@*)for (i = 0; i < times; i++) {
printf("Hello %d!\n", i);
}

(*@\lnote@*)return;
}
\end{annotatedcsource}

Some source code doing whatever \lnnum{1}, with line numbers and annotations \lnnum{2}.

\end{document}


The "trick" is to pass some numbersep= value to listings and use the xshift= option for the TikZ node.

(I have changed some packages in order to use pdflatex instead of xelatex, which I currently have not available. However, that should not be the point).

Is that what you are after?

-
Hm... seems that Werner basically had the same idea – and quick as he always is, he was about 3 Minutes earlier :-) –  Daniel Apr 13 '12 at 20:34
Werner is epic. Thank you both, I'm checking this. Bear with my tikz absolute rookie status, I bet this one was a tad stupid, but I also bet some people will appreciate the annotation hack for listings. –  soze Apr 13 '12 at 20:43