7

The listings package defines a hook called EveryLine to allow users to execute TeX code at the beginning of each line of a listing; the following is taken directly from the listings source code (listings.dtx):

\hookname{EveryLine}

Executed at the beginning of each \emph{output} line, i.e.~more than once for broken lines. This hook must not change the horizontal or vertical position.

The code below is my attempt at using this hook to test whether the first character of each line is f and insert YES before it in that case. However, as you can see below, I'm not getting the expected output.

At first, I thought if might be a grouping problem: the code inserted at the EveryLine might be buried inside a group and, as a result, my test could not access the first token on the line, because that token lies outside the group in question. However, a quick test (consisting in locally incrementing a TeX register) shows that it's not the case.

Any idea what I'm doing wrong?

enter image description here

\documentclass{article}

\usepackage{listings}

\usepackage{filecontents} \begin{filecontents}{sample.c} foo bar frivolous thing discourse fragile \end{filecontents}

\makeatletter \lst@AddToHook{EveryLine}{@ddedToEveryline} \def\detectF#1{\ifx f#1 YES#1\fi} \newcount\mycount \def\advandprintCount{\advance\mycount by @ne\the\mycount} \makeatother

\begin{document}

\makeatletter

\let@ddedToEveryline\detectF \lstinputlisting[basicstyle=\ttfamily]{sample.c}

\let@ddedToEveryline\advandprintCount \lstinputlisting[basicstyle=\ttfamily]{sample.c}

\makeatother

\end{document}

Marijn
  • 37,699
jub0bs
  • 58,916
  • Not sure this is an answer, but 'this won't work'. If you insert a \showtokens into th ehook, you'll find that #1 is not the start of the line of output but a load of listings code: you therefore never see the letter you are after. – Joseph Wright Feb 07 '14 at 23:10
  • @JosephWright How do you insert showtokens into the hook? \makeatletter \lst@AddToHook{EveryLine}{\showtokens} \makeatother returns an error. – jub0bs Feb 07 '14 at 23:18
  • \def\detectF#1{\showtokens{#1}\ifx f#1 YES#1\fi}} then \def\detectF#1{\showtokens\expandafter{#1}\ifx f#1 YES#1\fi}} – Joseph Wright Feb 08 '14 at 07:05

1 Answers1

6

Here's my try:

\documentclass{article}
\usepackage{pdftexcmds}
\usepackage{listings}

\usepackage{filecontents}
\begin{filecontents*}{sample.c}
foo
bar
frivolous
thing
discourse
fragile
\end{filecontents*}

\makeatletter
\lst@AddToHook{EveryLine}{\@ddedToEveryline}

\def\@splitfirstchar#1#2\@nil{\gdef\@detectF{#1}}
\def\splitfirstchar#1{\@splitfirstchar#1\@nil} 
\def\@detectF{%
%  -\the\lst@token-
  \expandafter\splitfirstchar\expandafter{\the\lst@token}%
  \def\@tempa{f}%
%  -\@detectF-
  \ifnum\pdf@strcmp{\@detectF}{\@tempa}=\z@
     YES
  \else
     NO
  \fi%
}
\newcount\mycount
\def\advandprintCount{\advance\mycount by \@ne\the\mycount}
\makeatother
\begin{document}

\makeatletter

\let\@ddedToEveryline\@detectF
\lstinputlisting[basicstyle=\ttfamily]{sample.c}

\let\@ddedToEveryline\advandprintCount
\lstinputlisting[basicstyle=\ttfamily]{sample.c}

\makeatother

\end{document}

enter image description here

jub0bs
  • 58,916
Marco Daniel
  • 95,681
  • The output looks promising! Your code returned an error, so I took the liberty to edit it. Let me experiment with it a bit more before I give you the checkmark, but your solution looks like what I was looking for. Thanks so much! – jub0bs Feb 08 '14 at 11:30
  • Thanks again. At some stage, I should really allocate some time to read the listings source code from beginning to end. – jub0bs Feb 08 '14 at 12:25
  • Marco, here is a follow-up question (assuming it's not too involved): how could I also peek at the second token on the line? – jub0bs Feb 08 '14 at 19:06
  • @Jubobs: You can use: \def\@splitfirstchar#1#2#3\@nil{\gdef\@detectFirst{#1}\gdef\@detectSecond{#2}} – Marco Daniel Feb 08 '14 at 20:13