将 tikz 图片放置在列表代码块的左边距

将 tikz 图片放置在列表代码块的左边距

我正在尝试使用 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}

输出: 错误对齐的输出让 soze 变成了一只悲伤的熊猫

期望输出:

  • 将带圆圈的数字与行号左侧或右侧边距正确对齐。
    • 换句话说,带圈的数字必须出现在代码块框的外面,位于行号的右侧或左侧。
  • 任何类型的源代码列表都应该可以正常工作,请不要缩进假设。
  • 文本中嵌入的实际引用的带圆圈数字间距适当。

像这样:

在此处输入图片描述

答案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>}现在设置\lnnumanchor=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}

修改内容包括:

  1. numbers键值处理方式的改变。此修改\insertnotenum作为行号打印机制 (或\lst@PlaceNumber) 的一部分插入;
  2. \insertnotenum是一个自毁宏,使用后会自动删除;
  3. 使用(*@\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。但是,这不是重点)。

这就是你所追求的吗?

相关内容