4

I'm trying to increase my LaTeX3-fu, but I'm getting an error about encountering printed output before the document begins.

I'm trying to generalize How to get the section title by section number?.

I also understand that LaTeX3's big punch is to (mostly) do away with \expandafter, but I don't know the equivalent syntax if there is a one-to-one relationship. (I'm really just trying to learn, here :-).)

Here is my code:

\documentclass{article}

\usepackage{xparse}

% Macro to insert labels at the end of other macros
\ExplSyntaxOn
\NewDocumentCommand{\labelize}{mm}{
  % Automatically inserts a label of the form \label{#2:\the#1}for
  % referencing after every #1

  % For example:
  % \labelize{section}{auto-section}
  % ...
  % \begin{document}
  % \section{something}
  % -->\label{auto-section:1}
  % \section{something else}
  % -->\label{auto-section:2}
  % \end{document}


  % #1 : Macro to labelize
  % #2 : Prefix for label

  % Store the old macro
  \let\expandafter\csname old#1\endcsname\expandafter\csname #1\endcsname

  % Adapted from https://tex.stackexchange.com/questions/76078/
               % how-to-get-the-section-title-by-section-number
  \expandafter\renewcommand\csname #1\endcsname[2]{
    \ifx##1\relax
      \csname old#1\endcsname{##2}
    \else
      \csname old#1\endcsname[##1]{##2}
    \fi
    \label{#2:\csname the#1\endcsname}%
  }
}
\ExplSyntaxOff

\labelize{section}{auto@section}

\begin{document}
Hi
\end{document}
Sean Allred
  • 27,421
  • You should know that \section takes no argument. It's not clear what the \labelize command should do. And, most importantly, you're trying to redefine \expandafter; at least switch the positions of \renewcommand and \expandafter; \expandafter\csname is a (minor) mistake, too. – egreg Jul 06 '13 at 20:28
  • @egreg ? but section{argument here?}? How then does the more explicit case (linked) work? I tried to model it exactly. – Sean Allred Jul 06 '13 at 20:31
  • Well, I'd say that Werner's answer is not the best LaTeX programming I've ever seen. Can you please state clearly what \labelize is supposed to do? – egreg Jul 06 '13 at 20:33
  • @egreg See my edit, I incorporated your notes from your first comment, although I'm still unsure of what you mean by "\section takes no arguments"... it at least seems to as an end-user. – Sean Allred Jul 06 '13 at 20:38
  • @egreg Do you think I need to \expandafter to hop over \let until the control sequences \csname ... \endcsname resolve? – Sean Allred Jul 06 '13 at 23:42
  • \let\expandafter\csname...\endcsname defines \expandafter to mean \csname, which is not what you want. Presumably, \expandafter\let\csname...\endcsname is wanted. – Bruno Le Floch Jul 07 '13 at 02:36
  • @BrunoLeFloch One of my many careless mistakes. I noticed the difference as I was going through egreg's answer and facepalm'd myself. Right, it was absolutely not what I meant, but it was absolutely what I told TeX to do. – Sean Allred Jul 07 '13 at 02:44

1 Answers1

7

I don't know what xparse and LaTeX3 has to do with this. You have almost all your \expandafter commands in the wrong place.

This works, but you lose the ability of using \section*.

\documentclass{article}

% Macro to insert labels at the end of other macros
\newcommand{\labelize}[2]{%
  % Automatically inserts a label of the form \label{#2:\the#1}for
  % referencing after every #1
  % For example:
  % \labelize{section}{auto-section}
  % ...
  % \begin{document}
  % \section{something}
  % -->\label{auto-section:1}
  % \section{something else}
  % -->\label{auto-section:2}
  % \end{document}
  % #1 : Macro to labelize
  % #2 : Prefix for label
  % Store the old macro
  \expandafter\let\csname old#1\expandafter\endcsname\csname #1\endcsname
  % Adapted from http://tex.stackexchange.com/questions/76078/
               % how-to-get-the-section-title-by-section-number
  \expandafter\renewcommand\csname #1\endcsname[2][]{
    \if\relax\detokenize{##1}\relax
      \csname old#1\endcsname{##2}%
    \else
      \csname old#1\endcsname[##1]{##2}%
    \fi
    \label{#2: \csname the#1\endcsname}%
  }
}

\labelize{section}{auto@section}

\begin{document}
\section{Test}
Hi

\ref{auto@section:1}
\end{document}

Of course using \ref{auto@section:1} is pointless, but if the automatically generated label is to be used via some macro, then it can be useful.

Here's a LaTeX3 version that allows for \section* as well as the optional argument. Note, however, that the first argument to \labelize should be the command (with the backslash). It would be possible to use the same syntax as before, but I believe this is clearer.

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% Macro to insert labels at the end of other macros
\NewDocumentCommand{\labelize}{mm}
 {
  \sean_labelize:Nn #1 { #2 }
 }

\cs_new_protected:Npn \sean_labelize:Nn #1 #2
 {
  \cs_set_eq:cN { original_ \cs_to_str:N #1 } #1
  \RenewDocumentCommand #1 { som }
   {
    \IfBooleanTF{##1}
     {
      \use:c { original_ \cs_to_str:N #1 }*{##3}
     }
     {
      \IfNoValueTF{##2}
       {
        \use:c { original_ \cs_to_str:N #1 } {##3}
       }
       {
        \use:c { original_ \cs_to_str:N #1 } [##2]{##3}
       }
      \label{#2: \use:c{the\cs_to_str:N #1} }%
     }
   }
 }
\ExplSyntaxOff

\labelize{\section}{auto@section}

\begin{document}
\section{Test}
Hi

\ref{auto@section:1}

\section*{Star}

Hi
\end{document}
egreg
  • 1,121,712
  • This works like a charm, but it isn't magic. I've got a date with the library's copy of the TeXbook this Tuesday; I've yet to read it so I'm not surprised about my own misuse and abuse of \expandafter. I'll have to study the syntax you've used, but I was looking for a LaTeX3 version, hence the tag. The reference will be automatically used in the breadcrumbs question. – Sean Allred Jul 07 '13 at 00:05