我正在尝试使用 tikz 为列表环境提供美观的无限行注释。最初的问题是缩进导致定位发生变化,因此我更改了代码以使用覆盖功能。
我原来的问题是在这里: 如何在没有 XeTeX 的情况下添加数字(ala No Starch Press)列表注释?
不幸的是,我仍然无法弄清楚如何正确对齐它们:
更新:该代码与Werner的版本合并。
\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);
}
printf("Adios!\n");
(*@\lnote@*)return;
}
\end{annotatedcsource}
Some source code doing whatever \linenum{1}, with line numbers and annotations \linenum{2}.
\end{document}
输出:
期望输出:
- 将带圆圈的数字与行号左侧或右侧边距正确对齐。
- 换句话说,带圈的数字必须出现在代码块框的外面,位于行号的右侧或左侧。
- 任何类型的源代码列表都应该可以正常工作,请不要缩进假设。
- 文本中嵌入的实际引用的带圆圈数字间距适当。
像这样:
答案1
下面的代码看起来有点像 hack,但是提供了你想要的输出:
\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]{{\addfontfeature{Numbers=OldStyle}#1}}
\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);
}
printf("Adios!\n");
(*@\lnote@*)return;
}
\end{annotatedcsource}
Some source code doing whatever \linenum{1}, with line numbers and annotations \linenum{2}.
\end{document}
numbersep=2.5em
将列表编号推2.5em
离列表边缘。这样,就留出了空间来将\lnote
长度4em
从其调用的位置推入间隙。这是我指的 hack:移动 TikZ 节点4em
(固定长度),因为可能需要一个取决于列表缩进的长度。\linenum{<num>}
现在设置\lnnum
并anchor=west
用一些水平空间填充它以正确对齐任何后续文本。
另一个版本以“不太黑客”的方式设置 TikZ 节点。:)
\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]{{\addfontfeature{Numbers=OldStyle}#1}}
\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);
}
printf("Adios!\n");
(*@\lnote@*)
return;
}
\end{annotatedcsource}
Some source code doing whatever \linenum{1}, with line numbers and annotations \linenum{2}.
\end{document}
修改内容包括:
numbers
键值处理方式的改变。此修改\insertnotenum
作为行号打印机制 (或\lst@PlaceNumber
) 的一部分插入;\insertnotenum
是一个自毁宏,使用后会自动删除;- 使用
(*@\lnote@*)
前您想要引用的行,以便行号下列的线路已适当标记。
请注意,此版本现在设置\lnote
相同的水平距离,无论代码缩进如何。
答案2
就像这样:
\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]{{\addfontfeature{Numbers=OldStyle}#1}}
\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);
}
printf("Adios!\n");
(*@\lnote@*)return;
}
\end{annotatedcsource}
Some source code doing whatever \lnnum{1}, with line numbers and annotations \lnnum{2}.
\end{document}
“技巧”是传递一些numbersep=
值listings
并使用该xshift=
选项。
(我已经更改了一些包以便使用 pdflatex 而不是 xelatex,因为我目前还没有 xelatex。但是,这不是重点)。
这就是你所追求的吗?