Everything works fine if I do not use \PassOptionsToPackage{french}{babel}.
My document class abntex2 already loads babel, then, to load the french language I need to use \PassOptionsToPackage{french}{babel} before my document class.
% \PassOptionsToPackage{french}{babel}
\documentclass[english,12pt,a4paper,twoside]{abntex2}
\usepackage{caption,xpatch,listings}
\makeatletter
\tracingpatches
\newcommand{\specialcodelistingcontentsline}[1]{\contentsline{lstlisting}}
\newenvironment{code}{
\captionsetup{type=listing}
\xshowcmd\addcontentsline
\xpatchcmd{\addcontentsline}
{\contentsline}
{\specialcodelistingcontentsline}
{}
{\FAILEDPATCHSPECIALCONTENTSLINE}
}{}
\makeatother
\begin{document}
\begin{code}
Hi.
\end{code}
\end{document}
Here on this log, we can see the patch was successful:
> \addcontentsline=macro:
#1#2#3->\begingroup \let \label \@gobble \ifx \@currentHref \@empty \Hy@Warning
{No destination for bookmark of \string \addcontentsline ,\MessageBreak destin
ation is added}\phantomsection \fi \expandafter \ifx \csname toclevel@#2\endcsn
ame \relax \begingroup \def \Hy@tempa {#1}\ifx \Hy@tempa \Hy@bookmarkstype \Hy@
WarningNoLine {bookmark level for unknown #2 defaults to 0}\else \Hy@Info {book
mark level for unknown #2 defaults to 0}\fi \endgroup \expandafter \gdef \csnam
e toclevel@#2\endcsname {0}\fi \edef \Hy@toclevel {\csname toclevel@#2\endcsnam
e }\Hy@writebookmark {\csname the#2\endcsname }{#3}{\@currentHref }{\Hy@tocleve
l }{#1}\ifHy@verbose \begingroup \def \Hy@tempa {#3}\@onelevel@sanitize \Hy@tem
pa \let \temp@online \on@line \let \on@line \@empty \Hy@Info {bookmark\temp@onl
ine :\MessageBreak thecounter {\csname the#2\endcsname }\MessageBreak text {\Hy
@tempa }\MessageBreak reference {\@currentHref }\MessageBreak toclevel {\Hy@toc
level }\MessageBreak type {#1}}\endgroup \fi \addtocontents {#1}{\protect \cont
entsline {#2}{#3}{\thepage }{\@currentHref }}\endgroup .
<recently read> \addcontentsline
l.23 \begin{code}
?
[debug] tracing \patchcmd on input line 23
[debug] analyzing '\addcontentsline'
[debug] ++ control sequence is defined
[debug] ++ control sequence is a macro
[debug] ++ macro can be retokenized cleanly
[debug] ++ search pattern found in replacement text
[debug] ++ patching possible
[debug] == retokenizing macro now
However, after uncommenting the \PassOptionsToPackage{french}{babel} on the minimal example, results in a failed patch:
> \addcontentsline=macro:
#1#2#3->\begingroup \let \label \@gobble \ifx \@currentHref \@empty \Hy@Warning
{No destination for bookmark of \string \addcontentsline ,\MessageBreak destin
ation is added}\phantomsection \fi \expandafter \ifx \csname toclevel@#2\endcsn
ame \relax \begingroup \def \Hy@tempa {#1}\ifx \Hy@tempa \Hy@bookmarkstype \Hy@
WarningNoLine {bookmark level for unknown #2 defaults to 0}\else \Hy@Info {book
mark level for unknown #2 defaults to 0}\fi \endgroup \expandafter \gdef \csnam
e toclevel@#2\endcsname {0}\fi \edef \Hy@toclevel {\csname toclevel@#2\endcsnam
e }\Hy@writebookmark {\csname the#2\endcsname }{#3}{\@currentHref }{\Hy@tocleve
l }{#1}\ifHy@verbose \begingroup \def \Hy@tempa {#3}\@onelevel@sanitize \Hy@tem
pa \let \temp@online \on@line \let \on@line \@empty \Hy@Info {bookmark\temp@onl
ine :\MessageBreak thecounter {\csname the#2\endcsname }\MessageBreak text {\Hy
@tempa }\MessageBreak reference {\@currentHref }\MessageBreak toclevel {\Hy@toc
level }\MessageBreak type {#1}}\endgroup \fi \addtocontents {#1}{\protect \cont
entsline {#2}{#3}{\thepage }{\@currentHref }}\endgroup .
<recently read> \addcontentsline
l.23 \begin{code}
?
[debug] tracing \patchcmd on input line 23
[debug] analyzing '\addcontentsline'
[debug] ++ control sequence is defined
[debug] ++ control sequence is a macro
[debug] -- macro cannot be retokenized cleanly
[debug] -> the macro may have been defined under a category
[debug] code regime different from the current one
[debug] -> the replacement text may contain special control
[debug] sequence tokens formed with \csname...\endcsname;
[debug] -> the replacement text may contain carriage return,
[debug] newline, or similar characters
! Undefined control sequence.
<argument> \FAILEDPATCHSPECIALCONTENTSLINE
Update
As pointed out by @Phelype Oleinik, changing the catcode of : temporarily to 12 fixed the issue. However, I cannot manage to restore the catcode correctly.
The following does not work because I used \begingroup to restore the catcode, but it also restores/nullifies the patch I just did to \addcontentlines
\PassOptionsToPackage{french}{babel}
\documentclass[english,12pt,a4paper,twoside]{abntex2}
\usepackage{caption,xpatch,listings}
\makeatletter
\tracingpatches
\newcommand{\specialcodelistingcontentsline}[1]{\contentsline{lstlisting}}
\newenvironment{code}{
\captionsetup{type=listing}
\xshowcmd\addcontentsline
\begingroup
\catcode`\:=12
\xpatchcmd{\addcontentsline}
{\contentsline}
{\specialcodelistingcontentsline}
{}
{\FAILEDPATCHSPECIALCONTENTSLINE}
\endgroup
% Here the catcode is restored, however, my patch is also undone
}{}
\makeatother
\begin{document}
\begin{code}
Hi.
\end{code}
\end{document}
Related:
\addcontentslinecontains a:which, at the time the macro was defined, was a catcode-12 token. The patch fails becausebabel-frenchmakes:an active character, so when rescanning the definitionetoolboxdetects that the patching is not possible there. Temporarily setting\catcode`\:=12should work... – Phelype Oleinik Nov 04 '19 at 03:54