TransWikia.com

How can I get the theorem name when using cleveref?

TeX - LaTeX Asked on April 10, 2021

Consider the following MWE

documentclass{article}

usepackage{amsthm}
usepackage{thmtools}
usepackage[nameinlink]{cleveref}

usepackage{xparse}
ExplSyntaxOn
NewDocumentCommand{ IfEmptyTF }{ m m m }
  {
    sbox0{#1}
    ifdimwd0=0pt
      #2
    else
      #3
    fi
  }
ExplSyntaxOff

makeatletter
declaretheoremstyle[
  postheadspace=.5em,
  headpunct={},
  notebraces={}{},
  notefont=bfseries,
  headformat=IfEmptyTF{NOTE}{NAME~NUMBER}{letthmt@space@emptyNOTE}
]{theorem}
makeatother

declaretheorem[
  style=theorem,
  name=Theorem
]{theorem}

crefname{theorem}{Theorem}{Theorems}

begin{document}

begin{theorem}[label=thm:a]
  A theorem.
end{theorem}

begin{theorem}[name=Important theorem, label=thm:b]
  Another theorem.
end{theorem}

cref{thm:a} and cref{thm:b} % <-- should be 'Theorem 1 and Important theorem'

end{document}

which produces

enter image description here

I’d like to modify the content of crefname{theorem}{..}{..} so that cref{..} prints Theorem n if the nth theorem doesn’t have a name, but if it does it just prints the name.

I know it can probably be done using nameref or autoref, but is a cref only solution possible?

One Answer

I'm not sure this is doable using the cleveref machinery, because crefformat doesn't seem to have access to the label. Moreover, cleveref is designed to be able to combine several numbered items while not repeating the item type (e.g., “theorems 1, 3 and 10”), which doesn't fit very well with what you want to do (articles would need to be added...).

That being said, one can redefine cref to:

  • detect if the argument consists of only one label;

  • if this is the case and if it has a name recorded by the nameref package, retrieve this name and print it (I use the great refcount package for this);

  • otherwise, let the normal cref command handle the situation.

Unrelated: your dimension test in IfEmptyTF is a bit weird. I reimplemented it in a better way,1 but it may be that you'd rather want to test whether the first-level expansion of the first argument of IfEmptyTF is empty. It's easy to do, but I kept the principle of “boxing + dimension test” in case this matters for your real life documents.

documentclass{article}
usepackage{letltxmacro}
usepackage{nameref}
usepackage{refcount}
usepackage{amsthm}
usepackage{thmtools}
usepackage[nameinlink]{cleveref}
usepackage{xparse}

ExplSyntaxOn
NewDocumentCommand { IfEmptyTF } { m }
  {
    hbox_set:Nw l_tmpa_box #1 hbox_set_end:
    dim_compare:nNnTF { box_wd:N l_tmpa_box } = { c_zero_dim }
    % The T and F clauses are taken from what follows in the input stream
  }

% Save the original cref commmand
LetLtxMacro{__noibe_orig_cref:n}{cref}

tl_new:N l__noibe_theorem_name_tl

RenewDocumentCommand{ cref }{ m }
  {
    int_compare:nNnTF { clist_count:n {#1} } > { 1 }
      { __noibe_orig_cref:n {#1} }
      {
        exp_args:NNo tl_set:No l__noibe_theorem_name_tl
          { getrefbykeydefault {#1} { name } { } }
        tl_if_empty:NTF l__noibe_theorem_name_tl
          { __noibe_orig_cref:n {#1} }
          { l__noibe_theorem_name_tl }
      }
  }
ExplSyntaxOff

makeatletter
declaretheoremstyle[
  postheadspace=.5em,
  headpunct={},
  notebraces={}{},
  notefont=bfseries,
  headformat=IfEmptyTF{NOTE}{NAME~NUMBER}{letthmt@space@emptyNOTE}
]{theorem}
makeatother

declaretheorem[
  style=theorem,
  name=Theorem
]{theorem}

crefname{theorem}{Theorem}{Theorems}

begin{document}

begin{theorem}[label=thm:a]
  A theorem.
end{theorem}

begin{theorem}[name=Important theorem, label=thm:b]
  Another theorem.
end{theorem}

cref{thm:a} and cref{thm:b} % “Theorem 1 and Important theorem”

cref{thm:a,thm:b}            % “Theorems 1 and 2”

end{document}

enter image description here

Problematic example for your IfEmptyTF

Here is a simple example where my implementation of IfEmptyTF works fine whereas yours produces an error:

documentclass{article}
usepackage{xparse}

ExplSyntaxOn
NewDocumentCommand{ YourIfEmptyTF }{ m m m }
  {
    sbox0{#1}
    ifdimwd0=0pt
      #2
    else
      #3
    fi
  }

NewDocumentCommand { MyIfEmptyTF } { m }
  {
    hbox_set:Nw l_tmpa_box #1 hbox_set_end:
    dim_compare:nNnTF { box_wd:N l_tmpa_box } = { c_zero_dim }
  }
ExplSyntaxOff

begin{document}

%YourIfEmptyTF{}{textbf}{textit}{foo bar} % Error: Too many }'s.

MyIfEmptyTF{}{textbf}{textit}{foo bar} % 'foo bar' is typeset in bold

MyIfEmptyTF{non-empty}{textbf}{textit}{foo bar} % 'foo bar' is typeset in italics

end{document}

enter image description here


Footnote

  1. No risk of expanding the start of #2 when reading the second ⟨dimen⟩ and, more importantly, allow each of the T and F clauses to act on tokens that follow the IfEmptyTF{...}{T}{F} in the input stream (with your code, #2 is followed by else in the input stream, and #3 is followed by fi, which can be a showstopper when you want to implement certain things—this is demonstrated under Problematic example for your IfEmptyTF in this answer).

Correct answer by frougon on April 10, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP