Your version doesn't seem to work because ' isn't just a simple character in listings but a macro called \lst@um' internally. Apparently, this is used to choose between normal and upright quote characters. I don't know how the regex package can be made matching on this, so here's a version that uses the traditional approach.
The idea is basically the same as in the regex version. First we make ' a letter so that it's part of all identifier names. Then our \lifetime macro hooks into the identifier printing and scans the \lst@token token list (which stores the identifier tokens) before they are printed with the appropriate style applied. I won't explain the scanning in detail here, feel free to expand a few examples by hand to convince yourself they work. :)
With that scan we are able to distinguish three cases, where each can be assigned an individual style:
- Identifiers that don't start with
' (\@normalstyle),
- identifiers that start with
' but don't end in ' (\@lifetimestyle), and
- identifier that both start with and end in
' (\@charlitstyle).
Note the \unskip that is used when the style is applied in \@setlststyle to gobble up some spurious glues that would otherwise add unwanted space in the output. Perhaps they need to be removed if other column formats are used.
\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}

! Incomplete \iffalse; all text was ignored after line 28.Unfortunately, I do not know expl3 regex machinations well enough to fix the problem; could you revisit your answer? – Alex Nelson Nov 13 '22 at 21:02