Defina comandos globais no arquivo aux

Defina comandos globais no arquivo aux

Estou escrevendo um documento longo e, para facilitar minha vida, gosto de definir as quantidades que utilizo como macros para que só precise atualizá-las em um só lugar quando elas mudarem. Para mim, faz sentido defini-los à medida que prossigo, na seção do meu documento que é mais relevante para eles. Entretanto, às vezes eu gostaria de usar esses comandos em outros capítulos, às vezes até em capítulos anteriores.

Eu gostaria, portanto, de adicionar uma macro que cospe uma definição de um comando nos .auxarquivos de látex, para que um comando possa ser usado em qualquer lugar depois de definido. Até agora eu tenho isso:

% 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

Isso coloca o seguinte no arquivo aux

\providecommand \tester {123}

para um capítulo como este:

\chapter{Test chapter}

This is a test chapter!

Tester is \tester{}.

\doccommand{\tester}{123}

Infelizmente, não funciona. Mesmo usar o comando no capítulo de teste me dá "Sequência de controle indefinida" e o mesmo em outros capítulos.

Originalmente pensei que isso poderia ter algo a ver com os espaços que acabavam no .auxarquivo, mas os removi manualmente e compilei com um \includeonly{a_different_chapter}que ainda dá o mesmo erro.

O que da?

Atualizar:

Graças a toda a ajuda aqui, consegui fazer isso funcionar e escrevi em um pequeno pacote. Se você estiver interessado, você pode encontrá-lo no CTAN emhttps://ctan.org/pkg/globalvals

Responder1

Eu usaria uma estratégia diferente: usar um comando wrapper, em vez de definir macros diretamente.

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

Resultado da primeira execução

insira a descrição da imagem aqui

Resultado da segunda execução

insira a descrição da imagem aqui

Responder2

Você poderia escrever

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

Isto fará uma definição global sem expandir o texto de substituição. Adicionei um direct adicional \gdefpara que o comando possa ser usado sem executar novamente o TeX.

Mas isso não é uma boa ideia: se você nunca usar o comando antes do ponto onde ele está definido, defini-lo no arquivo aux é inútil. Se você usar o comando antes de defini-lo, o LaTeX nunca chegará ao ponto onde você escreve a entrada do arquivo aux.

Portanto, você só pode usar o comando após executar o TeX uma vez com o comando definido, mas não usado. Se você excluir o arquivo aux, seu documento será corrompido. Se você incluir apenas um capítulo diferente, a entrada do arquivo auxiliar não será gravada e seu documento será quebrado.

Em vez disso, você pode criar um arquivo separado com as definições incluídas no preâmbulo. É mais trabalhoso, mas resulta em um documento muito mais estável.

Responder3

Obrigado @egreg por uma abordagem inteligente. Alterei ligeiramente o código dele para adicionar uma mensagem de erro se duas definições forem feitas no mesmo documento:

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

informação relacionada