Ich schreibe ein langes Dokument und um mir das Leben zu erleichtern, definiere ich die von mir verwendeten Mengen gerne als Makros, sodass ich sie bei Änderungen nur an einer Stelle aktualisieren muss. Für mich ist es sinnvoll, diese im Laufe der Arbeit in dem Abschnitt meines Dokuments zu definieren, der für sie am relevantesten ist. Manchmal möchte ich diese Befehle jedoch auch in anderen Kapiteln verwenden, manchmal sogar in vorherigen Kapiteln.
Ich möchte daher ein Makro hinzufügen, das die Definition eines Befehls in die Latex- .aux
Dateien einfügt, sodass ein Befehl überall verwendet werden kann, sobald er definiert wurde. Bisher habe ich Folgendes:
% 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
Dies fügt Folgendes in die AUX-Datei ein
\providecommand \tester {123}
für ein Kapitel wie dieses:
\chapter{Test chapter}
This is a test chapter!
Tester is \tester{}.
\doccommand{\tester}{123}
Leider funktioniert es nicht. Sogar wenn ich den Befehl im Testkapitel verwende, erhalte ich die Meldung „Undefinierte Steuersequenz“, und dasselbe gilt auch in anderen Kapiteln.
Ursprünglich dachte ich, dass dies möglicherweise etwas mit den Leerzeichen zu tun hat, die in der Datei gelandet sind .aux
, aber ich habe sie manuell entfernt und mit einem kompiliert, \includeonly{a_different_chapter}
was immer noch den gleichen Fehler erzeugt.
Was gibt?
Aktualisieren:
Dank der Hilfe hier habe ich es zum Laufen gebracht und es in ein kleines Paket geschrieben. Wenn Sie interessiert sind, finden Sie es auf CTAN unterhttps://ctan.org/pkg/globalvals
Antwort1
Ich würde eine andere Strategie verwenden: Verwenden Sie einen Wrapper-Befehl, anstatt Makros direkt zu definieren.
\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}
Ausgabe des ersten Durchlaufs
Ausgabe des zweiten Durchlaufs
Antwort2
Sie könnten schreiben
\makeatletter
\newcommand{\doccommand}[2]{%
\immediate\write\@auxout{\gdef\noexpand#1{\unexpanded{#2}}}%
\gdef#1{#2}%
}
\makeatother
Dadurch wird eine globale Definition durchgeführt, ohne dass der Ersetzungstext erweitert wird. Ich habe eine zusätzliche Direktive hinzugefügt, \gdef
damit der Befehl verwendet werden kann, ohne TeX erneut auszuführen.
Das ist jedoch keine gute Idee: Wenn Sie den Befehl nie vor dem Punkt verwenden, an dem er definiert ist, ist die Definition in der AUX-Datei nutzlos. Wenn Sie den Befehl vor seiner Definition verwenden, erreicht LaTeX nie den Punkt, an dem Sie den AUX-Dateieintrag schreiben.
Sie können den Befehl also erst verwenden, nachdem Sie TeX einmal mit dem definierten, aber nicht verwendeten Befehl ausgeführt haben. Wenn Sie die AUX-Datei jemals löschen, ist Ihr Dokument beschädigt. Wenn Sie jemals nur ein anderes Kapitel einbinden, wird der AUX-Dateieintrag nicht geschrieben, sodass Ihr Dokument beschädigt ist.
Stattdessen könnten Sie eine separate Datei mit den Definitionen erstellen, die Sie in das Präample aufnehmen. Das ist zwar mehr Arbeit, führt aber zu einem wesentlich stabileren Dokument.
Antwort3
Danke @egreg für den cleveren Ansatz. Ich habe seinen Code ganz leicht geändert, um eine Fehlermeldung hinzuzufügen, wenn zwei Definitionen im selben Dokument vorgenommen werden:
\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}