0

I am currently trying my hand at latex3 to get a deeper understanding of programming with latex. For this I have created a simple settings system.

It works as follows:

  1. You create a setting via \NewSetting[type = <type>, init = <init-value>]{<Name>}
  2. Based on its type it calls its corresponding setting macro: e.g. for a string setting it will call \NewStringSetting[<init-value>]{<Name>}.
  3. \NewStringSetting will create the string, set the initial value of the string and create all needed macros to use the string, e.g. Clear<Name>, Set<Name> and Get<Name>.

Example | A string setting for author:

  1. I create a setting by calling \NewSetting[type = string, init = Dave]{Author}
  2. Internal: \NewSetting calls \NewStringSetting[Dave]{Author}
  3. Internal: \NewStringSetting creates an expl3 string (g_my_author_str), sets if needed a value and creates 3 macros: \ClearAuthor, \SetAuthor{<Content>} and \GetAuthor.

Now I can clear, set and get the content for the string author.

Problem: I use xkeyval for key-value pairs. They get set in \NewSetting via \setkeys within a group so they reset after leaving the group (see David Carlisle's comment). But then all created macros (\ClearAuthor, \SetAuthor{<Content>} and \GetAuthor) are undefined after leaving the group. A solution would be to get rid of the group but then the key-value pairs wont reset as intended. So not really a solution. Then I stumbled across @wipet's solution to forward the macros out of the group; thus keeping the macros while still all keys reset at the end of the group. Looks like a working solution.

Question: I am still quite new to LaTeX, especially latex3. I'm fairly satisfied with the result so far (it works, after all) but I'd like to know what you think. I would like to know if there is an easier way and what I could improve.

The biggest difficulty I had was expansion. Are there any good references (e.g. Youtube, forum posts, etc.)? (especially those that also address latex3 and their primitives like \exp_last_unbraced ...)

Summa summarum:

  1. how could the code be improved (especially with regard to the problem I described)?
  2. are there any good references explaining latex3 (I know of LaTeX3's manual)?
  3. is there some rule of thumb to get expansion right without trial and error

Code of string setting:

\documentclass{book}

\usepackage{expl3} % Only needed for IDE-autocomplete (aka IntelliSense) \usepackage{xkeyval}

\makeatletter \ExplSyntaxOn

% By egreg https://tex.stackexchange.com/a/63233/293060 \NewExpandableDocumentCommand{\IfNoValueOrEmptyTF}{m m m}{% \IfNoValueTF{#1}{#2}{% \tl_if_empty:nTF{#1}{#2}{#3}% }% }%

% By wipet https://tex.stackexchange.com/a/690710/293060 \def\keepaftergroup#1{% \global \expandafter\let \csname x:\string#1\endcsname =#1 \aftergroup\let \aftergroup#1% \expandafter\aftergroup \csname x:\string#1\endcsname

}

\define@key[DAVE]{settings}{type}{\def\DAVE@Settings@Type{#1}} \define@key[DAVE]{settings}{init}{\def\DAVE@Settings@Init{#1}}

\NewDocumentCommand{\NewSetting}{o m}{% \begingroup \setkeys[DAVE]{settings}{#1}% \cs_if_exist:NTF\DAVE@Settings@Type{% \str_case:NnF{\DAVE@Settings@Type}{% {string}{\begingroup\edef\x{\endgroup\noexpand\NewStringSetting[\cs_if_exist:NT\DAVE@Settings@Init{\DAVE@Settings@Init}]{#2}}\keepaftergroup\x} % <--- Wont work without \keepaftergroup, only if \begingroup + \endgroup removed (but then keys wont reset) %{bool}{...} }{% \ClassError{SETTINGS}{Unknown~settings~type~for~setting~'#2'}{} } }{% \ClassError{SETTINGS}{Cannot~create~setting~'#2'~due~to~missing~setting~type}{} } \endgroup \x % <--- Calling }

\NewDocumentCommand{\NewStringSetting}{o m}{% \str_if_exist:cTF{g_DAVE_#2_str}{% \ClassError{SETTINGS}{String~with~the~name~'#2'~already~exist}{} }{% \str_gclear_new:c{g_DAVE_#2_str} \IfValueT{#1}{% \str_gset:cn{g_DAVE_#2_str}{#1} } \expandafter\NewExpandableDocumentCommand\expandafter{\csname Clear#2\endcsname}{}{% \str_gclear:c{g_DAVE_#1_str} } \expandafter\NewExpandableDocumentCommand\expandafter{\csname Set#2\endcsname}{m}{% \IfNoValueOrEmptyTF{##1}{% \ClassWarning{SETTINGS}{Could~not~set~value~for~setting~'#2'~due~to~the~passed~value~being~of~type~'NoValue'~or~empty}% }{% \str_gset:cn{g_DAVE_#2_str}{##1}% }% } \expandafter\NewExpandableDocumentCommand\expandafter{\csname Get#2\endcsname}{}{% \str_use:c{g_DAVE_#2_str} } } }

\ExplSyntaxOff \makeatother

\NewSetting[type = string]{Forum} \NewSetting[type = string, init = Dave]{Author}

\SetForum{StackExchange}

\begin{document} Hello \TeX-\GetForum \space it's \GetAuthor \end{document}

Dave
  • 111
  • 1
    don't use xkeyval here if your aim is to use L3 use l3keys which is anyway preloaded in latex so requires no package – David Carlisle Dec 27 '23 at 23:30
  • 1
    also don't reset after a group with macros that have been set globally, as here. as the initial setting applies to all nested group levels but the reset is a local setting for just one level, which is well defined but weird. – David Carlisle Dec 27 '23 at 23:37

0 Answers0