Определить глобальные команды в aux-файле

Определить глобальные команды в aux-файле

Я пишу длинный документ и, чтобы облегчить себе жизнь, мне нравится определять используемые мной величины как макросы, чтобы мне приходилось обновлять их в одном месте, когда они меняются. Для меня имеет смысл определять их по мере продвижения, в разделе моего документа, который наиболее релевантен для них. Однако иногда мне хотелось бы использовать эти команды в других главах, иногда даже в предыдущих главах.

Поэтому я хотел бы добавить макрос, который выплевывает определение команды в .auxфайлы latex, чтобы команду можно было использовать везде, как только она определена. Пока что у меня получилось следующее:

% 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-файл, ваш документ будет поврежден. Если вы когда-либо включите только другую главу, запись 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}

Связанный контент