我正在制作一个角色扮演游戏系统。我想将咒语的内容与咒语的格式分开,例如,能够针对角色表和专用咒语文档对咒语进行不同的格式化,等等。
我正在尝试使用一个单独的文件,该文件包含以预定义方式排列的格式化宏(\spell)的参数,然后将其输入到文档中。
这是我尝试过的。
\documentclass{article}
\newcommand{\spell}[4]{
\noindent \textbf{#1}
\\ \underline{#2}
\\ \textit{#3}
\\ #4
}
\newcommand{\info}{
{SPELL NAME}
{MANA COST}
{CASTING TIME}
{DESCRIPTION}
}
\begin{document}
\input{spells/spell template.tex}
\spell{spell name}{mana cost}{casting time}{description}
\expandafter\spell\info
% \expandafter\spell\input{spells/spell template.tex}
\end{document}
咒语/咒语模板.tex 包含
{Spell Name}
{Mana Cost}
{Casting Time}
{Description}
我在这个文件中的前三个测试运行得很好,但当我试图取消注释第四个测试时,LaTeX 崩溃了。我读过它\input
不可扩展,但我还没有看到任何可以解决这个问题的解决方案。这篇文章看起来很有希望,但似乎已经过时了(https://tex.stackexchange.com/a/282602/301785)任何帮助我都会很感激,谢谢。
答案1
假设您需要从文件中选择参数的行为不仅仅是\spell
,下面定义了一个辅助宏\FromFile
,它将文件内容应插入其后的代码作为第一个参数,将文件路径作为第二个参数。
\documentclass{article}
\begin{filecontents}{spell_template.tex}
{SPELL NAME}
{MANA COST}
{CASTING TIME}
{DESCRIPTION}
\end{filecontents}
\newcommand{\spell}[4]{%
\noindent \textbf{#1}
\\ \underline{#2}
\\ \textit{#3}
\\ #4%
}
\ExplSyntaxOn
\msg_new:nnn { amit } { file-not-found }
{ File~ #1~ not~ found.~ RPG-element~ not~ defined! }
\NewDocumentCommand \FromFile { m m }
{
\file_get:nnNTF {#2} {} \l_tmpa_tl
{ \exp_last_unbraced:Nno \use:n {#1} \l_tmpa_tl }
{ \msg_error:nnn { amit } { file-not-found } {#2} }
}
\ExplSyntaxOff
\newcommand\info
{%
{SPELL NAME}%
{MANA COST}%
{CASTING TIME}%
{DESCRIPTION}%
}
\begin{document}
\input{spell_template.tex}
\spell{spell name}{mana cost}{casting time}{description}
\expandafter\spell\info
\FromFile\spell{spell_template.tex}
\end{document}
如果处理前导和尾随空格很重要,则可以使用以下变体:
\documentclass{article}
\begin{filecontents}{spell_template.tex}
{SPELL NAME}
{MANA COST}
{CASTING TIME}
{DESCRIPTION}
\end{filecontents}
\newcommand{\spell}[4]{%
\noindent \textbf{#1}
\\ \underline{#2}
\\ \textit{#3}
\\ #4%
}
\ExplSyntaxOn
\msg_new:nnn { amit } { file-not-found }
{ File~ #1~ not~ found.~ RPG-element~ not~ defined! }
\NewDocumentCommand \FromFile { m m }
{
\file_get:nnNTF {#2} {} \l_tmpa_tl
{ \use:e { \exp_not:n {#1} \tl_trim_spaces:o \l_tmpa_tl } }
{ \msg_error:nnn { amit } { file-not-found } {#2} }
}
\ExplSyntaxOff
\newcommand\info
{%
{SPELL NAME}%
{MANA COST}%
{CASTING TIME}%
{DESCRIPTION}%
}
\begin{document}
\input{spell_template.tex}
\spell{spell name}{mana cost}{casting time}{description}
\expandafter\spell\info
\FromFile\spell{spell_template.tex}
\end{document}
答案2
LaTeX 将 TeX 基元隐藏\input
到控制序列中\@@input
。您可以通过以下方式设置等效命令\primitiveinput
:
{\catcode`\@=11 \global\let\primitiveinput=\@@input}
然后你可以说
\expandafter\spell\primitiveinput{spells/spell-template.tex}
编辑:接受的答案实现了一个\FromFile
宏,用于测试给定文件是否存在。我可以使用 OpTeX 展示这样的实现,仅用于比较
\fontfam[lm]
\def\spell#1#2#3#4{1:#1, 2:#2, 3:#3, 4:#4}
\def\FromFile#1#2{%
\isfile{#2}\iftrue \ea#1\input{#2}%
\else \opwarning{File "#2" not found, \string#1 not executed}\fi
}
\FromFile\spell{template.tex}
\bye
答案3
这个答案和 wipet 给出的答案类似。这个想法是使用 的原始含义\input
。使用 XeTeX 或 LuaTeX,您可以使用\primitive
原始含义(在 pdfTeX 中称为\pdfprimitive
)。
\documentclass{article}
\begin{filecontents}{spell_template.tex}
{SPELL NAME}
{MANA COST}
{CASTING TIME}
{DESCRIPTION}
\end{filecontents}
\newcommand{\spell}[4]{
\noindent \textbf{#1}
\\ \underline{#2}
\\ \textit{#3}
\\ #4
}
\newcommand{\info}{
{SPELL NAME}
{MANA COST}
{CASTING TIME}
{DESCRIPTION}
}
\begin{document}
\input{spell_template.tex}
\spell{spell name}{mana cost}{casting time}{description}
\expandafter\spell\info
\expandafter\spell\primitive\input spell_template.tex
\end{document}
答案4
这是一个变体,它尝试处理文件中四个参数后面的空格和其他内容。
\documentclass{article}
\begin{filecontents*}{template.tex}
{SPELL NAME}
{MANA COST}
{CASTING TIME}
{DESCRIPTION} Something that gets ignored.
Something that gets ignored, too.
\end{filecontents*}
\newcommand{\spell}[4]{%
\par
\noindent\textbf{#1}\\%
\underline{#2}\\%
\textit{#3}\\%
#4%
}%
\newcommand\spellGetArguments[4]{\spellRemoveToEndOfLine{\spell{#1}{#2}{#3}{#4}}}%
\newcommand\SpellSwitchEndlinecharcategory{\catcode\endlinechar=12 }%
\makeatletter
\begingroup
\catcode`\^^M=12 %
\@firstofone{%
\endgroup%
\@ifdefinable\spellRemoveToEndOfLine{%
\long\def\spellRemoveToEndOfLine#1#2^^M{\endgroup#1}%
}%
}%
\newcommand\spellinput[1]{%
\begingroup
\expandafter\expandafter\expandafter\SpellSwitchEndlinecharcategory
\expandafter\expandafter\expandafter\endinput
\expandafter\spellGetArguments\@@input"#1" %
}%
\makeatother
\begin{document}
\spellinput{template.tex} Space.
\bigskip
\spellinput{template.tex}NoSpace.
\end{document}