將分組轉義為巨集 + 回饋

將分組轉義為巨集 + 回饋

我目前正在嘗試 Latex3,以更深入地了解 Latex 編程。為此,我創建了一個簡單的設定係統。

其工作原理如下:

  1. 您透過以下方式建立設置\NewSetting[type = <type>, init = <init-value>]{<Name>}
  2. 根據其類型,它調用相應的設置宏:例如,對於字串設置,它將調用\NewStringSetting[<init-value>]{<Name>}.
  3. \NewStringSetting將建立字串、設定字串的初始值並建立使用該字串所需的所有宏,例如Clear<Name>Set<Name>Get<Name>

範例|作者的字串設定:

  1. 我透過調用創建一個設置\NewSetting[type = string, init = Dave]{Author}
  2. 內部的:\NewSetting來電\NewStringSetting[Dave]{Author}
  3. 內部的\NewStringSetting建立一個 expl3 字串 ( g_my_author_str),根據需要設定一個值並建立 3 個巨集:\ClearAuthor\SetAuthor{<Content>}\GetAuthor

現在我可以清除、設定和取得字串作者的內容。

問題:我用於xkeyval鍵值對。它們透過群組內的\NewSetting方式設置\setkeys,因此在離開群組後它們會重置(請參閱大衛卡萊爾的評論)。但是,所有建立的巨集(\ClearAuthor\SetAuthor{<Content>}\GetAuthor)在離開群組後都未定義。解決方案是刪除該組,但鍵值對不會按預期重置。所以這並不是真正的解決方案。然後我偶然發現@wipet的解決方案將巨集轉送出群組;從而保留宏,同時所有鍵仍然在群組末尾重置。看起來是一個有效的解決方案。

問題:我對 LaTeX 還是很陌生,尤其是 Latex3。到目前為止,我對結果相當滿意(畢竟它有效),但我想知道你的想法。我想知道是否有更簡單的方法以及我可以改進的地方。

我遇到的最大的困難是擴展。有沒有好的參考資料(例如 Youtube、論壇貼文等)? (特別是那些也解決 Latex3 及其原語的問題,例如\exp_last_unbraced...)

總結:

  1. 如何改進程式碼(特別是關於我描述的問題)?
  2. 有沒有什麼好的參考資料解釋latex3(我知道LaTeX3的手冊)?
  3. 是否有一些經驗法則可以在不反覆試驗的情況下獲得正確的擴展

字串設定代碼:

\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}

相關內容