在 aux 檔案中定義全域指令

在 aux 檔案中定義全域指令

我正在編寫一份很長的文檔,為了讓我的生活更輕鬆,我喜歡定義用作巨集的數量,這樣當它們發生變化時我只需在一個地方更新它們。對我來說,在我的文件中與它們最相關的部分中定義這些是有意義的。然而,有時我想在其他章節中使用這些命令,有時甚至在前面的章節中。

因此,我想添加一個宏,它將命令的定義寫入乳膠.aux檔案中,以便命令一旦定義就可以在任何地方使用。到目前為止我已經得到了這個:

% Make a command which defines a macro with \providecommand but in the aux file,
% so it's accessible to all other chapters
\makeatletter
\newcommand{\doccommand}[2]{%
\protected@write\@auxout{}{\protect\providecommand\protect#1{#2}}%
}
\makeatother

這會將以下內容放入 aux 檔案中

\providecommand \tester {123}

對於這樣的章節:

\chapter{Test chapter}

This is a test chapter!

Tester is \tester{}.

\doccommand{\tester}{123}

不幸的是,它不起作用。即使在測試章節中使用命令也會給我“未定義的控制序列”,在其他章節中也是如此。

最初我認為這可能與文件中最終出現的空格有關.aux,但我手動刪除了它們並使用\includeonly{a_different_chapter}仍然給出相同錯誤的編譯。

是什麼賦予了?

更新:

感謝這裡的所有幫助,我得到了這個工作並將其寫入一個小包中。如果您有興趣,可以在 CTAN 上找到它:https://ctan.org/pkg/globalvals

答案1

我會使用不同的策略:使用包裝器命令,而不是直接定義巨集。

\documentclass{article}

\makeatletter
\newcommand{\usevalue}[1]{%
  \ifcsname usevalue@#1\endcsname
    \csname usevalue@#1\endcsname
  \else
    ??%
  \fi
}
\newcommand{\definevalue}[2]{%
  \write\@auxout{%
    \unexpanded{\global\@namedef{usevalue@#1}{#2}}%
  }
}
\makeatother

\begin{document}

Something with \usevalue{tester}.

Something else.

Now we can define \texttt{tester} and use again it: \usevalue{tester}.

\definevalue{tester}{42}

\end{document}

第一次運行的輸出

在此輸入影像描述

第二次運行的輸出

在此輸入影像描述

答案2

你可以寫

\makeatletter
\newcommand{\doccommand}[2]{%
  \immediate\write\@auxout{\gdef\noexpand#1{\unexpanded{#2}}}%
  \gdef#1{#2}%
}
\makeatother

這將進行全域定義而不擴展替換文字。我添加了一個額外的直接命令,\gdef以便可以在不重新運行 TeX 的情況下使用該命令。

但這不是一個好主意:如果您在定義該命令之前從未使用過該命令,那麼在 aux 檔案中定義它是沒有用的。如果您在定義命令之前使用該命令,LaTeX 永遠不會到達您寫入 aux 文件條目的位置。

因此,只有在定義但未使用指令的情況下執行一次 TeX 後才能使用該指令。如果您刪除了 aux 文件,您的文件就會損壞。如果您只包含不同的章節,則不會寫入輔助文件條目,因此您的文件已損壞。

相反,您可以使用前言中包含的定義來建立一個單獨的檔案。雖然工作量更大,但文件更加穩定。

答案3

感謝@egreg 提供了一個聰明的方法。如果在同一個文檔中進行了兩個定義,我對他的程式碼進行了輕微的修改以添加錯誤訊息:

\documentclass{article}    

\usepackage{siunitx}

\makeatletter
\newcommand{\useVal}[1]{%
  \ifcsname useVal@#1\endcsname
    \csname useVal@#1\endcsname
  \else
    ??%
  \fi
}
\newcommand{\defVal}[2]{%
\ifcsname useVal@#1@defined\endcsname
    \PackageError{useVal}{Value "#1" already defined}{}
\else
  \write\@auxout{%
    \unexpanded{\global\@namedef{useVal@#1}{#2}}%
  }
  \global\@namedef{useVal@#1@defined}{}
\fi
}
\makeatother

\begin{document}

Testval is \useVal{testVal}.

Now defining testval...

\defVal{testVal}{\SI{123}{\meter}}

Now it's \useVal{testVal}. 

% This would throw an error:
% \defVal{testVal}{Not this please!}

\end{document}

相關內容