7

I'm trying to write a custom package MyUnicodefonts where I'd like to store all my font settings for various math fonts and roman fonts (later also mono and sans).

In my document I intend to choose the font with a key-value option, like:

\documentclass{article}

\usepackage[math=xits,roman=myriad]{MyUnicodefonts}
\usepackage{blindtext}

\begin{document}

\blindmathpaper

\end{document}

For the package file MyUnicodefonts.sty I used the switch from this answer as is appeared handy and sufficient for me and I didn't understood the other answers. I tried to apply it for string comparison.

Using the kvoptions package my file finally looks as follows:

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{MyUnicodefonts}[2015/06/21 Load fonts]

\RequirePackage{fontspec}

\RequirePackage{kvoptions}
\DeclareStringOption[minion]{roman}
\DeclareStringOption[xits]{math}
\ProcessKeyvalOptions*

\RequirePackage{xifthen}
\newcommand{\ifequals}[3]{\ifthenelse{\ifstrequal{#1}{#2}{TRUE}{}}{#3}{}}
\newcommand{\case}[2]{#1 #2} % Dummy, so \renewcommand has something to overwrite...
\newenvironment{switch}[1]{\renewcommand{\case}{\ifequals{#1}}}{}

\begin{switch}{\MyUnicodefonts@roman}
    \case{minion}{\setmainfont[Numbers = OldStyle,
                               Ligatures = TeX,
                              ]{Minion Pro}}
    \case{myriad}{\setmainfont[Numbers={Uppercase,OldStyle},
                              ]{Myriad Pro}}
\end{switch}
\begin{switch}{\MyUnicodefonts@math}
    \case{xits}{%
        \RequirePackage{unicode-math}
        \setmathfont{XITS Math}
        \setmathfont[range={"002B,"002D,"003A-"003E} ]{MnSymbol} % + - < = >
        }
    \case{iwona}{%
        \RequirePackage[math]{iwona}
        \RequirePackage[mathscr]{eucal}
        }
\end{switch}

\endinput

As the kvoptions manual is lacking a comprehensive example I fail to identify the reason for the appearing Undefined control sequence error.

The error would disappear if I'd load unicode-math also before the switch, but I don't want that, as there will be cases, where I don't want to use an unicode-math font. However a new error appears:

! Missing number, treated as zero. \begingroup l.18 \case{myriad}{\setmainfont{Myriad Pro}} A number should have been here; I inserted '0'. (If you can't figure out why I needed to see a number, look up 'weird error' in the index to The TeXbook.)

Which I don't understand, as I substituted the \equal{#1}{#2} from the original switch (see linked answer) to \ifstrequal{#1}{#2}{TRUE}{}.

I hope you can help me find the error or suggest a completely different approach.

1
  • The undefined command is shown in the error message: \ifstrequal. It is defined by package etoolbox, which is not loaded. This and how option strings are processed further are not related to package kvoptions. Jun 7, 2015 at 19:27

2 Answers 2

6

The code in the question has some problems:

  • \ifstrequal is not defined, as shown by the error message. It is defined by package etoolbox.

  • Environment switch makes a group, all local settings are lost after the end of the environment.

There are lots of ways to implement "switches", this is not covered by package kvoptions, which tries to be simple and easy to use.

A classical way to implement a switch depending on a simple text string is using the hash table of TeX. The following example puts the implementation for an option value in a macro with a name of the form \<prefix>@<option>@<value>. The option setting of kvoptions stores the value in \<prefix>@<option>. Then a simple test using \@ifundefined checks, if the option/value implementation exists and throws an error, if the option value is not supported/unknown.

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{MyUnicodefonts}[2015/06/21 Load fonts]

\RequirePackage{fontspec}

\RequirePackage{kvoptions}
\DeclareStringOption[minion]{roman}
\DeclareStringOption[xits]{math}
\ProcessKeyvalOptions*

% Implementations for option "roman"
\@namedef{MyUnicodefonts@roman@minion}{%
  \setmainfont[
    Numbers = OldStyle,
    Ligatures = TeX,
  ]{Minion Pro}%
}
\@namedef{MyUnicodefonts@roman@myriad}{%
  \setmainfont[
    Numbers={Uppercase,OldStyle},
  ]{Myriad Pro}%
}

% Implementations for option "math"
\@namedef{MyUnicodefonts@math@xits}{%
  \RequirePackage{unicode-math}%
  \setmathfont{XITS Math}%
  \setmathfont[range={"002B,"002D,"003A-"003E}]{MnSymbol}%
}
\@namedef{MyUnicodefonts@math@iwona}{%
  \RequirePackage[math]{iwona}%
  \RequirePakcage[mathscr]{eucal}%
}

% Evaluate option settings
\newcommand*{\MyUnicodefonts@evaluate}[1]{%
  % Check, if option value in \<prefix>@<option> exists
  \@ifundefined{MyUnicodefonts@#1}{%
    % Should not happen
    \PackageError{MyUnicodefonts}{Evaluating unknown option `#1'}\@ehc
  }{%
    % Check, if there is an implementation for the value of the option
    % in macro \<prefix>@<option>@<value>
    \@ifundefined{MyUnicodefonts@#1@\csname MyUnicodefonts@#1\endcsname}{%
      \PackageError{MyUnicodefonts}{%
        Unknown option setting: #1=%
        \csname MyUnicodefonts@#1\endcsname
      }\@ehc
    }{%
      % Call the implementation for the value
      \csname MyUnicodefonts@#1@%
              \csname MyUnicodefonts@#1\endcsname
      \endcsname
      \relax
    }%
  }%
}
\MyUnicodefonts@evaluate{roman}
\MyUnicodefonts@evaluate{math}

\endinput
6

You could use l3keys2e.

File myunicodefonts.sty

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{myunicodefonts}[2015/06/21 Load fonts]

\RequirePackage{fontspec}
\RequirePackage{l3keys2e}

\ExplSyntaxOn
\bool_new:N \g_myunicodefonts_mathfont_bool
\tl_new:N \g_myunicodefonts_textfont_tl
\tl_new:N \g_myunicodefonts_mathfont_tl

\keys_define:nn { myunicodefonts }
 {
  textfont .choice:,
  textfont/minion .code:n = \tl_gset:Nn \g_myunicodefonts_textfont_tl {Minion~Pro},
  textfont/myriad .code:n = \tl_gset:Nn \g_myunicodefonts_textfont_tl {Myriad~Pro},
  textfont .initial:n = minion,
  textoptions .tl_gset:N = \g_myunicodefonts_textfont_options_tl,
  mathfont .choice:,
  mathfont/xits .code:n =
   {
    \bool_gset_true:N \g_myunicodefonts_mathfont_bool
    \tl_gset:Nn \g_myunicodefonts_mathfont_tl {XITS~Math}
   },
  mathfont/asana .code:n =
   { 
    \bool_gset_true:N \g_myunicodefonts_mathfont_bool
    \tl_gset:Nn \g_myunicodefonts_mathfont_tl {Asana~Math}
   },
  mathoptions .tl_gset:N = \g_myunicodefonts_mathfont_options_tl,
 }


\ProcessKeysPackageOptions{myunicodefonts}

\use:x
 {
  \setmainfont{\g_myunicodefonts_textfont_tl}[\g_myunicodefonts_textfont_options_tl]
 }

\bool_if:NT \g_myunicodefonts_mathfont_bool
 {
  \RequirePackage{unicode-math}
  \use:x
   {
    \setmathfont[\g_myunicodefonts_mathfont_options_tl]{\g_myunicodefonts_mathfont_tl}
   }
 }
\ExplSyntaxOff

\endinput

File myunicodefonts.tex for testing

\documentclass{article}

\usepackage[
  mathfont=xits,
  textfont=myriad,
  textoptions={Scale=0.8},
]{myunicodefonts}
\usepackage{blindtext}

\begin{document}

\blindmathpaper

\end{document}

One can supplement this with error checking for wrong options.

Different code

If you want to set yourself the options for the fonts, just do so in the .case:n code.

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{MyUnicodefonts}[2015/06/21 Load fonts]

\RequirePackage{fontspec}
\RequirePackage{l3keys2e}

\ExplSyntaxOn

\keys_define:nn { myunicodefonts }
 {
  textfont .choice:,
  textfont/minion .code:n =
   {
    \setmainfont{Minion~Pro}[
      Numbers = OldStyle,
      Ligatures = TeX,
    ]
   },
  textfont/myriad .code:n =
   {
    \setmainfont{Myriad~Pro}[
      Numbers={Uppercase,OldStyle},
    ]
   },
  textfont .initial:n = minion,
  mathfont .choice:,
  mathfont/xits .code:n =
   {
    \RequirePackage{unicode-math}
    \setmathfont{XITS~Math}
    \setmathfont[range={"002B,"002D,"003A-"003E}]{MnSymbol} % + - < = >
   },
  mathfont/iwona .code:n =
   { 
    \RequirePackage[math]{iwona}
    \RequirePackage[mathscr]{eucal}
   },
 }

\ProcessKeysPackageOptions{myunicodefonts}
\ExplSyntaxOff

\endinput
6
  • Thank you for this exhausting piece of code, but I'm a little struggling to apply it to the full case. First it seems I'm limited to the options I could define within the [] in \setmathfont[<options>]{font} - is that right? But I actually have multiple of these lines for different ranges. Also the options for the roman fonts should be defined within the class and not be editable from outside. Could you please have a look at my edited MWE and insert it in you code? That would help me to understand where all the definitions reappears. Thank you! Jun 7, 2015 at 17:19
  • @thewaywewalk That's a good reason for not having such a package in the first place.
    – egreg
    Jun 7, 2015 at 17:46
  • @thewaywewalk Remove the textoptions key and set the token list variable yourself. Similarly add the code you want to the mathfont options.
    – egreg
    Jun 7, 2015 at 17:51
  • possibly. It seemed to be a easy thing to do for me in the first place. I will work through your code again tomorrow. Jun 7, 2015 at 18:13
  • @thewaywewalk I added an example of what I meant.
    – egreg
    Jun 7, 2015 at 18:20

You must log in to answer this question.

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