Я пишу длинный документ и, чтобы облегчить себе жизнь, мне нравится определять используемые мной величины как макросы, чтобы мне приходилось обновлять их в одном месте, когда они меняются. Для меня имеет смысл определять их по мере продвижения, в разделе моего документа, который наиболее релевантен для них. Однако иногда мне хотелось бы использовать эти команды в других главах, иногда даже в предыдущих главах.
Поэтому я хотел бы добавить макрос, который выплевывает определение команды в .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}