0

I saved the following code in the file ~/Test.tex.

\documentclass{article}

\usepackage{pgfkeys}

\pgfkeys{
   precision/.code={precision=#1},
   unit/.code={unit=#1},
   /handlers/first char syntax=true,
   /handlers/first char syntax/the character 0/.initial=\Precision,
   /handlers/first char syntax/the letter a/.initial=\Unit
}

\def\Precision#1{\pgfkeysalso{precision=#1}}
\def\Unit#1{\pgfkeysalso{unit=#1}}

\begin{document}

\pgfkeys{0}

\end{document}

The code configures the \pgfkeys command to inspect the first character of each key, and if this character is the digit 0, or the letter a, to call the the \Precision, resp. \Unit command, with a single argument: the key. The \Precision command expands to the string "precision=#1", where #1 is its argument, and similarly the \Unit command expands to "unit=#1". The code then calls \pgfkeys, passing it the key 0 (i.e. the digit zero).

Then I executed the following commands in the Terminal.

> cd ~
> pdflatex Test

Consequently the file ~/Test.pdf was created. When opened in a PDF viewer it displayed the string "precision=0", as expected.

I then changed the code in the following way. I replaced the stringthe letter a by the stringthe letter p. I then recompiled. The generated PDF file now displayed the string "unit=precision".

This caught me by surprise. I expected the outcome of the second compilation to be the same as the outcome of the first compilation, since the argument to the \pgfkeys command that's in the document's body hasn't changed, and it is neither a nor p.

Furthermore, I don't understand how the string "unit" came to be on the right hand side of the equality symbol.

Questions

  1. Why did the second compilation not produce the string "precision=0" as the first compilation had done?
  2. Why did the second compilation produce the string "unit=precision"?
9
  • 2
    well you have \pgfkeysalso{precision=#1}} which starts with p so you stop that acting as a normal key Commented Dec 14, 2022 at 23:01
  • 1
    presumably it splits on =first.. But the whole construct is so weird I can't guess what you really want to do here. Also it will fail for any non ascii characters. Commented Dec 14, 2022 at 23:14
  • 1
    why not simply declare keys 2 and cm instead of breaking every key that happens to start with c ? Commented Dec 14, 2022 at 23:23
  • 2
    sure but you could declare a key cm that sets the unit, why disable every key starting with c (or as in the question disable every key starting p) Commented Dec 14, 2022 at 23:32
  • 1
    Maybe it would be better to use .unknown handler to check those “keys” whether they are a number (e.g. start with digit, ., + or -) or not, those are units. Though, it would be much easier just to define keys for the units and treat everything else that's unknown as the number. Commented Dec 15, 2022 at 0:04

1 Answer 1

0

This answer is based on David Carlisle's advice. I got the list of TeX dimensions from here. I only need the six precision values 0 to 5.

\documentclass{article}

\usepackage{pgfkeys}

\pgfkeys{
   /stripdim/.cd,
   precision/.value required,
   precision/.code={\pgfkeyssetvalue{/stripdim/precision}{#1}[precision=#1]},
   unit/.value required,
   unit/.initial=cm,
   unit/.code={\pgfkeyssetvalue{/stripdim/unit}{#1}[unit=#1]},
   pt/.style={unit=pt},
   pc/.style={unit=pc},
   bp/.style={unit=bp},
   in/.style={unit=in},
   cm/.style={unit=cm},
   mm/.style={unit=mm},
   dd/.style={unit=dd},
   cc/.style={unit=cc},
   sp/.style={unit=sp},
   ex/.style={unit=ex},
   em/.style={unit=em},
   fil/.style={unit=fil},
   fill/.style={unit=fill},
   filll/.style={unit=filll},
   0/.style={precision=0},
   1/.style={precision=1},
   2/.style={precision=2},
   3/.style={precision=3},
   4/.style={precision=4},
   5/.style={precision=5}
}

\newcommand{\stripdim}[1][]{%
   \pgfkeys{/stripdim/.cd,#1}%
}

\begin{document}

[\stripdim]\par
\stripdim[precision=3]\par
\stripdim[unit=cm]\par
\stripdim[precision=3,unit=cm]\par
\stripdim[unit=cm,precision=3]\par
\stripdim[3]\par
\stripdim[cm]\par
\stripdim[3,cm]\par
\stripdim[cm,3]\par

\end{document}

Using pgfkeys to infer the keys.

4
  • 1
    precision/.style={precision/.initial=#1}, is weird. Just give it an initial, say precision/.initial=0 and after that all precision=<num> just store <num> in that key. No need to re.initialize. Commented Dec 15, 2022 at 16:24
  • @Qrrbrbirlbel The precision key is not supposed to have an initial value. It is supposed to indicate the number of places after the decimal point, but if it isn't specified, the number of places after the decimal point is whatever happens to be the case.
    – Evan Aad
    Commented Dec 15, 2022 at 16:27
  • @Qrrbrbirlbel Also: I did it this way for the sake of this example, in order to be able both to set a key's value as well as have it perform a command (in this case, print something). Normally when a key performs a command, it doesn't store a value, and vice versa.
    – Evan Aad
    Commented Dec 15, 2022 at 16:30
  • 1
    precision/.initial= would be valid, too. It might be easier to test against an empty value than an undefined one. But of course this will all depend on your project and how it should work. Re second point. Yes. But maybe just precision/.code=\pgfkeyssetvalue{/stripdim/precision}{#1}, precision/.append code=<stuff> would be a clearer (and faster) indication on what's going on. Commented Dec 15, 2022 at 16:47

You must log in to answer this question.

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