突出显示代码列表中的文本,同时保持语法突出显示

突出显示代码列表中的文本,同时保持语法突出显示

我正在使用列表\hl代码清单包。现在我尝试使用灵魂包裹。

下面是结果查询的示例,其中应突出显示 SQL 注入的注入部分:

\begin{lstlisting}[escapechar=@,language=SQL]
SELECT name, password FROM users WHERE name='@\hl{' UNION SELECT "10", 1 \#}@';
\end{lstlisting}

但是在突出显示的部分中,SQL 语法突出显示不适用。

因此我也尝试使用\lstlinline里面的代码部分,\hl但没有效果:

\begin{lstlisting}[escapechar=@,language=SQL]
SELECT name, password FROM users WHERE name='@\hl{\lstinline[language=SQL]$' UNION SELECT "10", 1 #$}@';
\end{lstlisting}

虽然这\lstinline部分工作在列表块,它无法在其中工作。我在该特定行中得到的错误是:

额外},或者被遗忘的\endgroup。

也许我只是缺少一些特殊语法来实现这个功能。或者根本就不可能为\hl-highlighted 部分获得正确的语法突出显示?

答案1

已经快一年了,但是由于 OP 还没有接受答案,我仍然看到了我的机会:-)

在下文中,我使用与我的其他答案即使用listings moredelim=**选项来定义分隔符,然后应用哪些样式在上面所有其他格式,以便保留语法格式。

但是,现在我不再局限于使用标准的字体命令来设置分隔符样式,而是使用lrbox来获取当前组的内容。结果框包含 的(语法格式)输出listings,可用于实现更花哨的突出显示样式。

在示例代码中,命令的实现\btHL使用 TikZ 将 排版lrbox为 TikZ 节点。 tikzpicture 和 节点的附加 TikZ/PGF 选项可以在可选参数(例如\btHL[fill=red!20,draw=red])中给出,这提供了非常灵活的高亮显示。

(注意:当在某些参数中使用可选参数时listings,整个\btHL[<key>=<value>,...]命令必须放入花括号中以免混淆listingskey=value 解析器。)

\btHL命令也可以在普通文本中使用。但是,它不能跨换行符工作,与从Bens 的回答。然而,在列表内部,这通常不是问题。

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{listings,xcolor,beramono}
\usepackage{tikz}


\makeatletter
\newenvironment{btHighlight}[1][]
{\begingroup\tikzset{bt@Highlight@par/.style={#1}}\begin{lrbox}{\@tempboxa}}
{\end{lrbox}\bt@HL@box[bt@Highlight@par]{\@tempboxa}\endgroup}

\newcommand\btHL[1][]{%
  \begin{btHighlight}[#1]\bgroup\aftergroup\bt@HL@endenv%
}
\def\bt@HL@endenv{%
  \end{btHighlight}%   
  \egroup
}
\newcommand{\bt@HL@box}[2][]{%
  \tikz[#1]{%
    \pgfpathrectangle{\pgfpoint{1pt}{0pt}}{\pgfpoint{\wd #2}{\ht #2}}%
    \pgfusepath{use as bounding box}%
    \node[anchor=base west, fill=orange!30,outer sep=0pt,inner xsep=1pt, inner ysep=0pt, rounded corners=3pt, minimum height=\ht\strutbox+1pt,#1]{\raisebox{1pt}{\strut}\strut\usebox{#2}};
  }%
}
\makeatother

\lstdefinestyle{SQL}{
    language={SQL},basicstyle=\ttfamily, 
    moredelim=**[is][\btHL]{`}{`},
    moredelim=**[is][{\btHL[fill=green!30,draw=red,dashed,thin]}]{@}{@},
}

\begin{document}

A listing with {\btHL highlighting of all \textbf{important} elements} looks as follows:

\begin{lstlisting}[style=SQL]
SELECT name, password `FROM` users @WHERE@ name=@UNION SELECT@
\end{lstlisting}

在此处输入图片描述

答案2

我认为 \hl + \lstinline 的组合不起作用。soul 和 listings 都会逐个分析和处理输入的标记,并执行大量 \catcode 魔法。它们会触犯其他规则。但您可以尝试以下方法:

 \documentclass{article}
  \usepackage{listings,xcolor,tikz}
  \newcommand\bh{\tikz[remember picture]
                    \node (begin highlight) {};
                 }
  \newcommand\eh{\tikz[remember picture]
                 \node (end highlight) {};
                 \tikz[remember picture, overlay] 
                 \draw[yellow,line width=10pt,opacity=0.3] (begin highlight) -- (end
                  highlight);
                 }


 \begin{document}

\bh abc bce bde bde \eh

\begin{lstlisting}[escapechar=@,language=SQL]
WHERE name=@\bh@UNION SELECT@\eh@
\end{lstlisting}

\end{document}

答案3

Ulrike 的建议非常聪明。我的版本受到@Ulrike 的启发,但有一些改进:

  • 突出显示阴影的样式被明确地分解出来,\tikzstyle{highlighter} = [...]以清楚地显示如何自定义视觉外观。例如,我的解决方案中的两行注释显示了如何使突出显示略微波浪形滑动以获得更人性化的效果。

  • \coordinate在突出显示区域的开头或结尾处不添加额外的空格。这需要避免在宏定义中使用换行符,使用而不是创建 tikz 锚点\node,并创建全部tikz 图表作为overlay图表。

  • 已添加突出显示笔划以下文本而不是多于它。这样可以防止高亮影响文本墨水颜色。带有黄色高亮的黑色文本保持纯黑色,而不是变成深黄色。请注意,这也意味着在设置了背景颜色的列表中,突出显示不起作用因为高亮笔触将位于背景后面。

  • \bh和宏共享的一些通用代码\eh被分解成一个新的\tikzhighlight宏。这没有视觉效果,但垂直居中代码非常微妙,我觉得值得分解出来。

考虑到这些诱惑,以下是我对 Ulrike 的解决方案的看法:

\documentclass{article}

% required packages
\usepackage{atbegshi,ifthen,listings,tikz}

% change this to customize the appearance of the highlight
\tikzstyle{highlighter} = [
  yellow,
  line width = \baselineskip,
]

% enable these two lines for a more human-looking highlight
%\usetikzlibrary{decorations.pathmorphing}
%\tikzstyle{highlighter} += [decorate, decoration = random steps]

% implementation of the core highlighting logic; do not change!
\newcounter{highlight}[page]
\newcommand{\tikzhighlightanchor}[1]{\ensuremath{\vcenter{\hbox{\tikz[remember picture, overlay]{\coordinate (#1 highlight \arabic{highlight});}}}}}
\newcommand{\bh}[0]{\stepcounter{highlight}\tikzhighlightanchor{begin}}
\newcommand{\eh}[0]{\tikzhighlightanchor{end}}
\AtBeginShipout{\AtBeginShipoutUpperLeft{\ifthenelse{\value{highlight} > 0}{\tikz[remember picture, overlay]{\foreach \stroke in {1,...,\arabic{highlight}} \draw[highlighter] (begin highlight \stroke) -- (end highlight \stroke);}}{}}}

\begin{document}

Works in \bh{}plain text too\eh{} (but not across line breaks).

\begin{lstlisting}[escapechar=@, language=SQL, basicstyle=\sffamily, columns=fullflexible]
SELECT name, password FROM users WHERE name='@\bh@' UNION SELECT "10", 1 #@\eh@';
\end{lstlisting}

\end{document}

代码输出

我所知道的唯一限制(也适用于 Ulrike 的版本)是突出显示不能正确跨越换行符。

答案4

如果您不打算使用\hl(或模拟使用),而愿意接受一些基于字体的格式,listings moredelim那么选项将是最优雅的解决方案。使用moredelim=**语法,您可以定义应用样式的分隔符在上面所有其他格式:

\documentclass{article}
\usepackage{listings,xcolor}

\lstdefinestyle{SQL}{
    language={SQL}, 
    moredelim=**[is][\slshape]{`}{`},
    moredelim=**[is][\color{orange}]{@}{@},
}

\begin{document}

\begin{lstlisting}[style=SQL]
SELECT name, password `FROM` users @WHERE@ name=@`UNION SELECT`@
\end{lstlisting}

\end{document}

输出

不幸的是,与 中的所有格式一样listings,您只能使用影响当前组内文本的宏。因此\color和字体命令可以工作,但\hl不能以这种方式应用。

相关内容