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)

2
  • 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, 2019 at 12:41
  • Thanks! I added a MWE, I hope it's clearer. Jul 23, 2019 at 13:11

2 Answers 2

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}
5
  • Thanks! the first solution works perfectly, and I can even chain more \ifx for catching multiple punctuation symbols. Jul 25, 2019 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. Jul 25, 2019 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, 2019 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! Jul 25, 2019 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, 2019 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

1
  • 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. Jul 24, 2019 at 16:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .