这是关于 Rust 及其生命周期符号:
\documentclass[crop,varwidth]{standalone}
\usepackage{listings}
\usepackage{xparse}
\usepackage{expl3}
\usepackage[svgnames]{xcolor}
\def\noprint#1{}
\ExplSyntaxOn
\NewDocumentCommand \lifetime { }
{
\tl_set:No \l_demo_tl {\the\use:c{lst@token}}
\regex_replace_all:nnN { ([\'\:][a-zA-Z]+[^\'\:]) } { \c{textcolor}\cB{ Violet \cE}\cB{ \1 \cE} } \l_demo_tl
\tl_use:N \l_demo_tl
\noprint
}
\ExplSyntaxOff
\lstset{
basicstyle=\ttfamily,
alsoletter={':},
identifierstyle=\lifetime
}
\begin{document}
\begin{lstlisting}
struct Foo<'a, 'b>{} // highlight 'a and 'b -- doesn't work
struct Foo<:a, :b>{} // highlight :a and :b -- works
'a' // not highlighted
:a: // not highlighted
\end{lstlisting}
\end{document}
我尝试从这个问题调整解决方案[1] 但不知何故,正则表达式与单引号不匹配——如果我用冒号替换单引号,它就会按预期突出显示。
keywordsprefix
对我来说没用moredelim
亮点太多
答案1
您的版本似乎不起作用,因为'
不仅仅是一个简单的字符,listings
而是一个内部调用的宏\lst@um'
。显然,这是用来在正常和直立引号字符之间进行选择的。我不知道如何使正则表达式包匹配这个,所以这里有一个使用传统方法的版本。
这个想法与正则表达式版本基本相同。首先,我们制作'
一个字母,使其成为所有标识符名称的一部分。然后我们的\lifetime
宏挂接到标识符打印中,并\lst@token
在应用适当的样式打印之前扫描标记列表(存储标识符标记)。我不会在这里详细解释扫描,请随意手动扩展几个示例以确保您能正常工作。:)
通过扫描,我们可以区分三种情况,每种情况都可以分配一种单独的样式:
- 不以
'
(\@normalstyle
) 开头的标识符, - 以 ( ) 开头
'
但不以'
(\@lifetimestyle
) 结尾的标识符,以及 '
以( )开头和结尾的标识符\@charlitstyle
。
请注意,\unskip
在应用样式时使用的 ,\@setlststyle
用于吞噬一些虚假的粘连,否则会在输出中添加不必要的空间。如果使用其他列格式,可能需要删除它们。
\documentclass{article}
\usepackage{listings}
\usepackage[svgnames]{xcolor}
\lstset{
basicstyle=\ttfamily\small,
alsoletter={'},
identifierstyle=\lifetime,
morecomment=[l][\color{gray}]{//},
}
\makeatletter
\def\@normalstyle{\color{blue}}
\def\@lifetimestyle{\color{red}}
\def\@charlitstyle{\color{green}}
\def\@setlststyle#1{%
\edef\lt@temp{{\unskip\bgroup\noexpand#1}\the\lst@token{\unskip\egroup}}%
\lst@token=\expandafter{\lt@temp}%
}
\begingroup
\catcode`\'=11
\gdef\lifetime{%
\expandafter\lifetime@\the\lst@token\lst@um'\@end
}
\gdef\lifetime@#1\lst@um'#2\@end{%
\if\relax\detokenize{#1}\relax
\lifetime@'#2\@end
\else
\@setlststyle\@normalstyle
\fi
}
\gdef\lifetime@'#1\lst@um'#2\@end{%
\if\relax\detokenize{#2}\relax
\@setlststyle\@lifetimestyle
\else
\@setlststyle\@charlitstyle
\fi
}
\endgroup
\makeatother
\begin{document}
\begin{lstlisting}
a abc // normal identifier
a' abc' // normal identifier
'a 'abc // timelife identifier
'a' 'abc' // character literal
struct Foo<'a, 'b>{} // highlight 'a and 'b
\end{lstlisting}
\end{document}
答案2
在 @siracusa 发布他的解决方案后,我再次查看了这个问题,确实如他指出的那样,这'
是一个宏,而不是扩展为正则表达式中可以使用的“正常”符号。幸运的是,正则表达式包允许我们使用宏——而不是'
正\'
则表达式\c{lst@um'}
用来匹配的或'
。lst@um
宏必须用于所有“不可打印或难以打印”的字符(_
、$
、*
、-
......)——请参阅列表文档。
\documentclass[crop,varwidth]{standalone}
\usepackage{listings}
\usepackage{xparse}
\usepackage{expl3}
\usepackage[svgnames]{xcolor}
\def\noprint#1{}
\ExplSyntaxOn
\NewDocumentCommand \lifetime { }
{
\tl_set:No \l_demo_tl {\the\use:c{lst@token}}
\regex_replace_all:nnN { ([\c{lst@um'}\:][a-zA-Z]+[^\c{lst@um'}\:]) } { \c{textcolor}\cB{ Violet \cE}\cB{ \1 \cE} } \l_demo_tl
\tl_use:N \l_demo_tl
\noprint
}
\ExplSyntaxOff
\lstset{
basicstyle=\ttfamily,
alsoletter={':},
identifierstyle=\lifetime
}
\begin{document}
\begin{lstlisting}
struct Foo<'a, 'b>{} // highlight 'a and 'b -- works
struct Foo<:a, :b>{} // highlight :a and :b -- works
'a' // not highlighted
:a: // not highlighted
\end{lstlisting}
\end{document}