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}
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}
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);
}
printf("Adios!\n");
(*@\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:
Best Answer
The following seems a bit of a hack, but provides the output you're after:
numbersep=2.5em
pushes the listing numbers2.5em
away from the listing edge. As such, this leaves room to push\lnote
a length4em
from where it's called; into the gap. This is the hack I'm referring to: moving the TikZ node4em
(a fixed length), since one may require a length that depends on the indentation of the listing.\linenum{<num>}
now sets\lnnum
withanchor=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. :)
The modifications include:
numbers
key-value is handled. The modification inserts\insertnotenum
as part of the line number printing mechanism (or\lst@PlaceNumber
);\insertnotenum
is a self-destruct macro that removes itself after it is used;(*@\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.