4

I am trying to define a new reference style with cleveref:

\crefname{prop}{property}{properties}
\creflabelformat{prop}{#2#1.\@#3}

This is meant to be used in a list of numbered properties in an enumerate environment. Labels should render as "property 1.", and "properties 1. to 4." for a range.

It works as intended, but I want to deal with cases where a certain punctuation mark (in normal text) follows the \cref command. For example, \cref{my:label}, should render as "property 1," and not as "property 1.,".

I tried to use @ifnextchar in the label definition but (I guess due to how cleveref parses the command) the token following \cref is not the one that gets fed into @ifnextchar.

Is it possible to define a label format conditioned by which character follows the \cref command?

EDIT: Added MWE (slightly different example)

\documentclass{article}
\usepackage{cleveref}

\makeatletter
\crefname{prop}{property}{properties}
\creflabelformat{prop}{#2#1#3\@ifnextchar.{}{.\@}}
\makeatother

\begin{document}
    \begin{enumerate}
        \item \label[prop]{my:firstlabel}
        First property of the list

        \item \label[prop]{my:secondlabel}
        Second property of the list
    \end{enumerate}

    We will discuss the implications of \cref{my:firstlabel} and we will
    follow with \cref{my:secondlabel}.
\end{document}

The intended result would be "We will discuss the implications of property 1. and we will follow with property 2.", but the last period is actually printed twice (\@ifnextchar is not triggered).

I get the same behavior if I modify the standard enumi label format instead of specifying a new one, or if I use another environment (e.g. equation)

  • Welcome to TeX SX! I think this is more of a configuration problem of the ` enumerate` environment. Could you post a minimal compilable code? – Bernard Jul 23 at 12:41
  • Thanks! I added a MWE, I hope it's clearer. – Andrea Olivo Jul 23 at 13:11
1

With that code, \@ifnextchar will never see a period. If I change the definition to

\creflabelformat{prop}{#2#1#3\@ifnextchar.{}{\show\@let@token.\@}}

TeX will show in both cases

> \@let@token=\fi.
\reserved@c ->\show \@let@token 
                                .\@

When the replacement text deriving from \creflabelformat is used, LaTeX is in the middle of a long processing. However you're lucky! Everything is performed in a single group, so we can solve the problem with \aftergroup that pushes a token to be executed when the current group ends.

In order to avoid \@ifnextchar gobbling spaces, a lower level technique has to be used.

\documentclass{article}
\usepackage{cleveref}

\makeatletter
\crefname{prop}{property}{properties}
\creflabelformat{prop}{#2#1#3\aftergroup\possible@period}
\newcommand{\possible@period}{\futurelet\@let@token\perhaps@add@period}
\newcommand\perhaps@add@period{\ifx\@let@token.\else.\@\fi}
\makeatother

\begin{document}

\begin{enumerate}
\item \label[prop]{my:firstlabel}
   First property of the list

\item \label[prop]{my:secondlabel}
   Second property of the list
\end{enumerate}

We will discuss the implications of \cref{my:firstlabel}
and we will follow with \cref{my:secondlabel}. Some text.

\end{document}

enter image description here

It's shorter with expl3, but the technique is the same.

\documentclass{article}
\usepackage{cleveref,expl3}

\crefname{prop}{property}{properties}

\ExplSyntaxOn
\cs_new_protected:Npn \olivo_period:w
 {
  \peek_charcode:NF { . } { .\@ }
 }
\creflabelformat{prop}{#2#1#3\group_insert_after:N \olivo_period:w}
\ExplSyntaxOff

\begin{document}

\begin{enumerate}
\item \label[prop]{my:firstlabel}
   First property of the list

\item \label[prop]{my:secondlabel}
   Second property of the list
\end{enumerate}

We will discuss the implications of \cref{my:firstlabel}
and we will follow with \cref{my:secondlabel}. Some text.

\end{document}
  • Thanks! the first solution works perfectly, and I can even chain more \ifx for catching multiple punctuation symbols. – Andrea Olivo Jul 25 at 10:40
  • unfortunately it breaks with ranges and multiple references. \cref{my:firstlabel,my:secondlabel}. is rendered as property 1 and 2.. instead of properties 1. and 2. (and analogously for ranges). I can fix the range behavior overriding it with \crefrangelabelformat but it seems there is no equivalent \crefmultilabelformat. – Andrea Olivo Jul 25 at 13:40
  • @AndreaOlivo That was something I feared. As I said, the command \cref does many things after processing the replacement text in \creflabelformat, so when the \@ifnextchar will happen to be evaluated is quite unpredictable. – egreg Jul 25 at 13:44
  • It's OK, I'm starting to think that my style is not even typographically clear. I'll use a combination of normal refs and manual punctuation. Thank you for your time! – Andrea Olivo Jul 25 at 13:49
  • @AndreaOlivo Actually I hate those styles such as “1)”, “a)” or “1.” I know they're used, but can't stand them: a period means period and an closed parenthesis requires an open one. – egreg Jul 25 at 14:02
1

Here is a solution with enumitem, which defines the ref=... key. I added the possibility to define a new list type, based on enumerate, which you can completely customise:

\documentclass{article}
\usepackage{cleveref}
\usepackage{enumitem}

\crefname{prop}{property}{properties}
\newlist{Prop}{enumerate}{1}
\setlist[Prop]{label=\arabic*., ref=\arabic*}
\crefname{Prop}{property}{properties}

\begin{document}

    \begin{enumerate}[ref=\arabic*]
        \item \label[prop]{my:firstlabel}
        First property of the list

        \item \label[prop]{my:secondlabel}
        Second property of the list
    \end{enumerate}

    We will discuss the implications of \cref{my:firstlabel} and we will
    follow with \cref{my:secondlabel}.\bigskip

    \begin{Prop}[start=3]
        \item \label[Prop]{My:firstlabel}
        First property of this list

        \item \label[Prop]{My:secondlabel}
        Second property of this list
    \end{Prop}
    We will now discuss the implications of \cref{My:firstlabel} and we will
    follow with \cref{My:secondlabel}.

    \end{document} 

enter image description here

  • I think my question was confusing. Cleveref works as intended and already provides the functionality you implemented with enumitem. What I want to achieve is a way to print labels conditioned on what punctuation mark follows the \cref{} command, so that (for example) properties are printed in text as "property 1." (with a period) but not as "property 1.," if a comma follows the cref command. – Andrea Olivo Jul 24 at 16:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.