代码注释的宏

代码注释的宏

我想知道是否有一些宏可以轻松注释下面的列表。它们主要用于 Manning 的书籍中。

代码注释

解决方案

对于任何感兴趣的人,这是我最终得到的宏:

    \newcommand*{\AddNote}[5]{%
    \begin{tikzpicture}[overlay, remember picture]
    \coordinate (x) at (#2,0);
    \coordinate (a) at ($(x)!(#1.north)!($(x)+(0,1)$)$);
    \coordinate (b) at ($(a)+(0.8,0)$);
    \coordinate (c) at ($(b)+(0,#3)$);
    \draw [open triangle 45-] (a) -- (b) -- (c);
    \node[#5] at (c) {\bf\sffamily\smaller#4};
    \end{tikzpicture}%
    }

用法是:\AddNote{linemarker}{x-offset}{y-offset}{text}{style}

答案1

编辑2018-05-13:这是tikzmark所有优秀的 TeX 发行版都提供该软件包。请参阅tikzmark文档以获取最新说明。


如果没有 MWE,很难确切地知道你在追求什么,但我思考扩展listings可以tikzmark处理这类事情。你tikzmark.dtx需要TeX-SX 启动板,运行tex tikzmark.dtx并将生成的文件放在tex可以找到它们的地方(如果您运行latex tikzmark.dtx或者pdflatex tikzmark.dtx它会抱怨文件丢失 - 请忽略它)。

然后是以下代码:

\documentclass{article}
%\url{http://tex.stackexchange.com/q/86309/86}
\usepackage{listings}
\usepackage{tikz}
\usetikzlibrary{arrows,tikzmark,shadows}
\usetikzmarkextra{listings}

\tikzset{
  comment/.style={
    draw,
    fill=blue!70,
    text=white,
    rounded corners,
    drop shadow,
    align=left,
  },
}

\begin{document}

\begin{lstlisting}[language=TeX,name=texcode,numbers=left,breakatwhitespace=true,breaklines=true]
\newcommand\balloon[4]{%
  \pgfmathtruncatemacro\firstline{%
    #3-1
  }%
  \iftikzmark{line-#2-\firstline-start}{%
    \iftikzmark{line-#2-#3-first}{%
      \xdef\blines{({pic cs:line-#2-\firstline-start} -| {pic           cs:line-#2-#3-first})}%
    }{%
      \iftikzmark{line-#2-#3-start}{%
        \xdef\blines{({pic cs:line-#2-\firstline-start} -| {pic             cs:line-#2-#3-start})}%
      }{%
        \xdef\blines{(pic cs:line-#2-\firstline-start)}%
      }%
    }%
  }{%
    \xdef\blines{}%
  }%
  \foreach \k in {#3,...,#4} {%
    \iftikzmark{line-#2-\k-first}{%
      \xdef\blines{\blines (pic cs:line-#2-\k-first) }
    }{}
    \iftikzmark{line-#2-\k-end}{%
      \xdef\blines{\blines (pic cs:line-#2-\k-end) }
    }{}
  }%
  \ifx\blines\empty
  \else
  \edef\temp{\noexpand\tikz[remember picture,overlay] \noexpand\node[fit={\blines},balloon] (#1) {};}%
\temp
  \fi
}
\end{lstlisting}

\begin{tikzpicture}[remember picture,overlay,>=stealth']
\draw[<-,ultra thick] (pic cs:line-texcode-1-end) +(1em,.7ex) -| +(2.5,1) node[above,comment,thin] {Command name};
\draw[<-,ultra thick] (pic cs:line-texcode-3-end) ++(1em,.7ex) -| +(5.8,1) node[above right,comment,thin] {Find previous line};
\draw[<-,ultra thick] (pic cs:line-texcode-5-end) ++(1em,.7ex) -| +(2.2,.5) node[above,comment,thin] {If previous line exists, add to the list};
\draw[<-,ultra thick] (pic cs:line-texcode-18-end) ++(1em,.7ex) -| +(2.2,.5) node[above,comment,thin] {Loop through rest of lines};
\draw[<-,ultra thick] (pic cs:line-texcode-28-end) ++(1em,.7ex) -| +(1,1.5) node[above,comment,thin] {Add a node covering all the lines};
\end{tikzpicture}
\end{document}

生成:

注释清单

(只有它在 PDF 中看起来更美观。请注意,有一个著名的建议用它替换,\usetikzmarkextra\usetikzmarklibrary将很快发生,所以如果上面的抱怨\usetikzmarkextra尝试切换它。)

答案2

我承诺提供一个不一定很漂亮的解决方案来扩展 Andrew Stacey 的优秀答案,以支持代码跨越多页的情况:

\documentclass{article}
\usepackage{listings}
\usepackage{tikz}
\usetikzlibrary{arrows,tikzmark,shadows,calc}
\usetikzmarklibrary{listings}

\tikzset{
  comment/.style={
    draw,
    fill=blue!70,
    text=white,
    rounded corners,
    drop shadow,
    align=left,
  },
}

\usepackage{eso-pic}
\usepackage[calc]{picture}
\newcommand{\addstufftoforegroundall}[1]{%
  \AddToShipoutPictureFG{% Add <stuff> to all following pages' foreground
    \put(0,\paperheight){\vtop{{\null}\makebox[0pt][l]{#1}}}%
  }%
}%
\newcommand{\addstufftoforegroundthis}[1]{%
  \AddToShipoutPictureFG*{% Add <stuff> to the current page foreground
    \put(0,\paperheight){\vtop{{\null}\makebox[0pt][l]{#1}}}%
  }%
}%

\setcounter{errorcontextlines}{\maxdimen}


\makeatletter
\def\getpicturepage#1{%
  \@nameuse{save@pg@\@nameuse{save@pt@#1}}%
}

\newcommand*{\iftikzmarkcurrentpage}[3]{%
    \iftikzmark{#1}{%
        \ifcsname save@pg@\@nameuse{save@pt@#1}\endcsname
            \expandafter\ifnum\getpicturepage{#1}=\the\c@page\relax
                #2%
            \else
                #3%
            \fi
        \else
            #3%
        \fi
    }{%
        #3
    }%
}

\newcommand*{\appendhookorcreatenew}[2]{%#1<- hook csname, #2<- code to add
    % note: code in #2 is not expanded at this stage!
    \ifcsname #1\endcsname
        \expandafter\g@addto@macro\csname #1\endcsname{\unexpanded{#2}}%
    \else
        \@namedef{#1}{\unexpanded{#2}}%
    \fi
}
\newcommand*{\deferlinecode}[3]{% #1<-listing name, #2<-line number, #3<-code
    \appendhookorcreatenew{listings-deferline-#1-#2}{#3}%
}
\newcommand*{\atEOLcode}[3]{% #1<-listing name, #2<-line number, #3<-code
    \appendhookorcreatenew{listings-eol-execute-#1-#2}{#3}%
}
\newcommand*{\commenton}[4][comment,thin]{% #1<- node keys, #2<- listing name, #3<- line number, #4<- comment text
    \deferlinecode{#2}{#3}{\tikz[overlay,remember picture] \draw[,>=stealth',<-,ultra thick] (pic cs:line-#2-#3-end) +(1em,.7ex) -| ($(node cs:name=current page,anchor=north east)!(pic cs:line-#2-#3-end)!(node cs:name=current page,anchor=south east) +(-5cm,0cm)$) node[#1] {#4};}%
}

\lst@AddToHook{EOL}{%
    \begingroup
    \ifcsname listings-deferline-\lst@name-\the\c@lstnumber\endcsname
        \iftikzmarkcurrentpage{line-\lst@name-\the\c@lstnumber-end}{%
            \let\addstufftoforeground\addstufftoforegroundthis
        }{%
            \let\addstufftoforeground\addstufftoforegroundall
        }%
        \edef\pagehookstuff{%
            \noexpand\addstufftoforeground{%
                \noexpand\iftikzmarkcurrentpage{line-\lst@name-\the\c@lstnumber-end}{%
                    \@nameuse{listings-deferline-\lst@name-\the\c@lstnumber}%
                }{}%
            }%
        }%
        \global\expandafter\let\csname listings-deferline-\lst@name-\the\c@lstnumber\endcsname\@undefined
        \pagehookstuff
    \fi
    \ifcsname listings-eol-execute-\lst@name-\the\c@lstnumber\endcsname
        \@nameuse{listings-eol-execute-\lst@name-\the\c@lstnumber}%
    \fi
    \endgroup
}



\commenton[comment,thin,text width=5cm]{texcode}{3}{This line sets the title of the document but does not result in any visible output, yet.}
\atEOLcode{texcode}{3}{\vspace{5ex}}
\commenton[comment,thin]{texcode}{4}{Similarly for author.}
\atEOLcode{texcode}{4}{\vspace{2ex}}
\commenton[comment,thin]{texcode}{5}{And date.}
\commenton[comment,thin,fill=red!70,text=black]{texcode}{7}{This line actually shows them.}


\lstset{
    language={[LaTeX]TeX},
    numbers=left,
    breaklines=true,
    basicstyle=\small\ttfamily,
    columns=flexible,
}

\usepackage[a5paper,landscape]{geometry}
\usepackage{url}

\begin{document}

\title{Example output of code annotation}
\author{\url{http://tex.stackexchange.com/questions/86309/macros-for-code-annotations}}
\date{16 December 2012}
\maketitle

This is only to illustrate how one might go about adding annotations to code that spans across more than one page.

The annotations to be added have to specified before the listing appears.
It is not very robust to lost notes, eg if attempting to add an annotation to a blank line where there may not be an end marker.

\begin{lstlisting}[name=texcode]
\documentclass{article}
\usepackage{listings}
\title{Sample Document}
\author{John Smith}
\date{\today}
\begin{document}
\maketitle
Hello World!
% This is a comment.
\end{document}
\end{lstlisting}

\end{document}

(示例列表借自其他地方。)

如果相邻的注释节点可能重叠,我建议在注释行下方添加一些额外的空间。很明显,我在 TikZ 中定位时遇到了很多困难。

在此处输入图片描述

答案3

根据以前的答案,我创建了一些通用宏,它们也可以处理跨多页的列表:

\documentclass{article}
\usepackage[a5paper,landscape]{geometry}
\usepackage{url}
\usepackage{listings}
\usepackage{tikz}
\usepackage{eso-pic}
\usepackage[calc]{picture}
\usetikzlibrary{decorations.pathreplacing,arrows,tikzmark,calc}

\usetikzmarklibrary{listings}

\newcommand{\addstufftoforegroundall}[1]{%
    \AddToShipoutPictureFG{% Add <stuff> to all following pages' foreground
        \put(0,\paperheight){\vtop{{\null}\makebox[0pt][l]{#1}}}%
    }%
}%
\newcommand{\addstufftoforegroundthis}[1]{%
    \AddToShipoutPictureFG*{% Add <stuff> to the current page foreground
        \put(0,\paperheight){\vtop{{\null}\makebox[0pt][l]{#1}}}%
    }%
}%

\makeatletter
\def\getpicturepage#1{%
    \@nameuse{save@pg@\@nameuse{save@pt@#1}}%
}

\lst@AddToHook{EOL}{%
    \begingroup
    \ifcsname listings-deferline-\lst@name-\the\c@lstnumber\endcsname
    \iftikzmarkcurrentpage{line-\lst@name-\the\c@lstnumber-end}{%
        \let\addstufftoforeground\addstufftoforegroundthis
    }{%
        \let\addstufftoforeground\addstufftoforegroundall
    }%
    \edef\pagehookstuff{%
        \noexpand\addstufftoforeground{%
            \noexpand\iftikzmarkcurrentpage{line-\lst@name-\the\c@lstnumber-end}{%
                \@nameuse{listings-deferline-\lst@name-\the\c@lstnumber}%
            }{}%
        }%
    }%
    \global\expandafter\let\csname listings-deferline-\lst@name-\the\c@lstnumber\endcsname\@undefined
    \pagehookstuff
    \fi
    \ifcsname listings-eol-execute-\lst@name-\the\c@lstnumber\endcsname
    \@nameuse{listings-eol-execute-\lst@name-\the\c@lstnumber}%
    \fi
    \endgroup
}

\newcommand*{\iftikzmarkcurrentpage}[3]{%
    \iftikzmark{#1}{%
        \ifcsname save@pg@\@nameuse{save@pt@#1}\endcsname
        \expandafter\ifnum\getpicturepage{#1}=\the\c@page\relax
        #2%
        \else
        #3%
        \fi
        \else
        #3%
        \fi
    }{%
        #3
    }%
}
\newcommand*{\appendhookorcreatenew}[2]{%#1<- hook csname, #2<- code to add
    % note: code in #2 is not expanded at this stage!
    \ifcsname #1\endcsname
    \expandafter\g@addto@macro\csname #1\endcsname{\unexpanded{#2}}%
    \else
    \@namedef{#1}{\unexpanded{#2}}%
    \fi
}
\newcommand*{\deferlinecode}[3]{% #1<-listing name, #2<-line number, #3<-code
    \appendhookorcreatenew{listings-deferline-#1-#2}{#3}%
}

\colorlet{annotationColor}{red}
\newlength\annotationLinewidth
\setlength\annotationLinewidth{0.6pt}
\tikzset{%
    note/.style={annotationColor,
        font=\sffamily\scriptsize,%\bfseries
        align=center, 
        text width=2.5cm
    },
    every round node/.style={
        draw,
        shape=rounded rectangle,
        rounded rectangle arc length=180,
        inner sep=+.333em,
        text depth=+.1ex}
}
% utility function
\makeatletter
\def\ifPositive#1{%
    \@ifnextchar{-}%
    {\expandafter\@secondoftwo\remove@to@nnil}%
    {\expandafter\@firstoftwo\remove@to@nnil}%
    #1\@nnil
}
\makeatother
%\AddNoteVBrace{listing}{line-start}{line-end}{x-pos}{text}
\newcommand*{\AddNoteVBrace}[5]{%
    \deferlinecode{#1}{#2}{\tikz[overlay, remember picture]
        \draw [decoration={brace,amplitude=0.5em},decorate,annotationColor,line width=\annotationLinewidth]
        ($([xshift=#4]pic cs:line-#1-#2-start)!([yshift=1ex]pic cs:line-#1-#2-start)!($([xshift=#4]pic cs:line-#1-#2-start)-(0,1)$)$) --  
        ($([xshift=#4]pic cs:line-#1-#3-start)!([yshift=-.25ex]pic cs:line-#1-#3-start)!($([xshift=#4]pic cs:line-#1-#3-start)-(0,1)$)$)
        node [note, pos=0.5,anchor=west] {#5};}%
}%
%\AddNoteVLine{listing}{line-start}{line-end}{x-pos}{text}
\newcommand*{\AddNoteVLine}[5]{%
    \deferlinecode{#1}{#2}{\tikz[overlay, remember picture]
        \draw [annotationColor,line width=\annotationLinewidth]
        ($([xshift=#4]pic cs:line-#1-#2-start)!([yshift=1ex]pic cs:line-#1-#2-start)!($([xshift=#4]pic cs:line-#1-#2-start)-(0,1)$)$) --  
        ($([xshift=#4]pic cs:line-#1-#3-start)!([yshift=-.25ex]pic cs:line-#1-#3-start)!($([xshift=#4]pic cs:line-#1-#2-start)-(0,1)$)$)
        node [note, align=left, pos=0.5, anchor=west] {#5};}%
}%
%\AddNoteRight{listing}{line}{label-x-offset}{label-y-offset}{text}
\newcommand*{\AddNoteRight}[5]{%
    \deferlinecode{#1}{#2}{\tikz[overlay, remember picture]
        \def\anchor{south}\ifx&#4&\else \ifPositive{#4}{}{\def\anchor{north}}\fi
        \draw[<-,>=stealth,annotationColor,line width=\annotationLinewidth] (pic cs:line-#1-#2-end) +(0.25,.5ex) -| +(\ifx&#3&1\else#3\fi,\ifx&#4&2.5ex\else#4\fi) node[note,anchor=\anchor] {#5};}%
}%
%\AddNoteTop{listing}{line}{x-pos}{label-x-offset}{label-y-offset}{text}
\newcommand*{\AddNoteTop}[6]{%
    \deferlinecode{#1}{#2}{\tikz[overlay, remember picture]
        \def\anchor{west}\def\align{left}
        \ifx&#4&\else \ifPositive{#4}{}{\def\anchor{east}\def\align{right}}\fi
        \draw[<-,>=stealth,annotationColor,line width=\annotationLinewidth] ($([xshift=#3]pic cs:line-#1-#2-start) +(0,2.5ex)$) |- +(\ifx&#4&1\else#4\fi,\ifx&#5&2.5ex\else#5\fi) 
        node[note,align=\align,anchor=\anchor] {#6};}%
}%
%\AddNoteBottom{listing}{line}{x-pos}{label-x-offset}{label-y-offset}{text}
\newcommand*{\AddNoteBottom}[6]{%
    \deferlinecode{#1}{#2}{\tikz[overlay, remember picture]
        \def\anchor{west}\def\align{left}
        \ifx&#4&\else \ifPositive{#4}{}{\def\anchor{east}\def\align{right}}\fi
        \draw[<-,>=stealth,annotationColor,line width=\annotationLinewidth] ($([xshift=#3]pic cs:line-#1-#2-start) +(0,-1.5ex)$) |- +(\ifx&#4&1\else#4\fi,\ifx&#5&-2.5ex\else-#5\fi) 
        node[note,align=\align,anchor=\anchor] {#6};}%
}%
%\AddBox{listing}{line}{x-start}{x-end}
\newcommand*{\AddBox}[4]{%
    \deferlinecode{#1}{#2}{\tikz[overlay, remember picture]
    \draw[annotationColor,line width=\annotationLinewidth] ($([xshift=#3]pic cs:line-#1-#2-start) +(-.25ex,-.25ex)$) rectangle ($([xshift=#4]pic cs:line-#1-#2-start) +(.5ex,2.0ex)$);}%
}%
%\AddUnderline{listing}{line}{x-start}{x-end}
\newcommand*{\AddUnderline}[4]{%
    \deferlinecode{#1}{#2}{\tikz[overlay, remember picture]
        \draw[annotationColor,line width=\annotationLinewidth] ($([xshift=#3]pic cs:line-#1-#2-start) +(0,-.25ex)$) -- ($([xshift=#4]pic cs:line-#1-#2-start) +(0,-.25ex)$);}%
}%


\AddNoteVBrace{texcode}{1}{3}{4cm}{Note VBrace}
\AddNoteVLine{texcode}{5}{7}{4cm}{Note VLine}
\AddUnderline{texcode}{9}{0cm}{3cm}
\AddBox{texcode}{11}{1cm}{3cm}
\AddNoteTop{texcode}{15}{0cm}{5cm}{}{Note Top}
\AddNoteRight{texcode}{15}{3cm}{-2cm}{Note Right}
\AddNoteBottom{texcode}{15}{1cm}{}{}{Note Bottom}

\lstset{
    language={[LaTeX]TeX},
    numbers=left,
    breaklines=true,
    basicstyle=\small\ttfamily,
    columns=flexible,
}

\begin{document}
    
\title{Example output of code annotation}
\author{\url{http://tex.stackexchange.com/questions/86309/macros-for-code-annotations}}
\maketitle

This is only to illustrate how one might go about adding annotations to code that spans across more than one page.

The annotations to be added have to specified before the listing appears.
It is not very robust to lost notes, eg if attempting to add an annotation to a blank line where there may not be an end marker.

\begin{lstlisting}[name=texcode]
\documentclass{article}

\usepackage{listings}

\title{Sample Document}
\author{John Smith}
\date{\today}

\begin{document}
    
    \maketitle
    Hello World!
    % This is a comment.
    
\end{document}
\end{lstlisting}
    
\end{document}

在此处输入图片描述

相关内容