假设我*.tex
在名为的子目录中有一些文件SourceFiles
,当且仅当此子目录中的任何 tex 文件发生更改时,我该如何让 arara 编译该文档?
我试过
% arara: lualatex if changed (toFile(
% arara: --> listFilesByExtensions( toFile('/SourceFiles'), [ 'tex' ], false)
% arara: --> ))
但我收到了这个错误
[错误:未找到空指针或函数:listFilesByExtensions] [附近:{... || 已更改(toFile(listFilesByExtensions(toFile(....}]
答案1
是的,没错:listFilesByExtensions
在指令上下文中不可用,仅在规则范围内可用。此外,如果评估设法到达外部函数调用,则会出现另一个问题:changed
一次仅支持单个文件,而不是文件列表。
在您的特定场景中,典型的解决方案是编写适当的规则。团队正在讨论,在未来版本中,采用一种功能路线,以便在指令范围内允许all
诸如any
和 之类的高级构造。none
这是该团队的官方回应。:)
话虽如此...
龙的踪迹
还...
吸血鬼的希望,你吸血鬼的希望
有一种非常狡猾的方法可以实现你想要的效果。我将利用表达式语言并通过完整限定名称触发函数调用。这完全不推荐,应该不惜一切代价避免。我认为我们喜欢挑战。:)
该标题应该适合您。
% arara: lualatex if
% arara: --> entries =
% arara: --> com.github.cereda.arara.utils.Methods.listFilesByExtensions(
% arara: --> toFile('SourceFiles/'), ['tex'], false
% arara: --> );
% arara: --> flag = false;
% arara: --> foreach(entry : entries) {
% arara: --> flag = changed(entry) || flag;
% arara: --> };
% arara: --> return flag
关于此标头的一些说明:
% arara: lualatex if
这里没有什么新东西,arara
当且仅当以下表达式成立时,才会运行引擎。
% arara: --> entries =
% arara: --> com.github.cereda.arara.utils.Methods.listFilesByExtensions(
现在情况有所不同:首先,我listFilesByExtensions
使用表达式语言中的完整限定名称进行调用。然后,此函数的返回值保存在名为的变量中entries
。
% arara: --> toFile('SourceFiles/'), ['tex'], false
% arara: --> );
这些是参数:目录(我/
在开始时删除了,因为它会被解析为从根目录开始的完整路径,而我相信这不是你想要的,并且添加了尾随/
只是为了满足我的编码强迫症),扩展列表(在本例中,我们正在寻找.tex
文件)和一个布尔值,指示搜索是否应该是递归的(在我们的例子中,否)。
% arara: --> flag = false;
我创建了一个名为的布尔变量flag
,最初设置为false
,它将保存上次搜索产生的任何文件是否已发生改变的指示。
% arara: --> foreach(entry : entries) {
% arara: --> flag = changed(entry) || flag;
% arara: --> };
现在这是一个循环,用于检查上一次搜索产生的每个文件。观察到它changed
位于操作的左侧||
。这不是一个表面选项,它有更深层的含义:如果我把它放在changed
右侧,短路可能会在flag
保留的情况下保存一个调用true
,因此从该迭代开始文件数据库将不再更新。
% arara: --> return flag
现在,flag
指示是否有任何文件已更改,因此编译将基于该决定。由于它是表达式中的最后一条语句,因此无论如何都会返回它,但我喜欢让事情更明确、更冗长、更复杂,因为我们不喜欢复杂的事情。:)
基本上就是这样。恭喜,您已使保修失效!:)
希望能帮助到你!:)
附录:注释中显示的标头至少有两个问题:第一个与语法有关,第二个与语义有关。第二个标头恰好起作用,因为短路会导致某些文件的状态不更新。这可能是对两个标头的修复:
标题 1
% arara: lualatex: { options: [ '-synctex=1',
% arara: --> '-shell-escape','-interaction=nonstopmode' ]}
% arara: --> if
% arara: --> flag = changed(currentFile());
% arara: --> entries =
% arara: --> com.github.cereda.arara.utils.Methods.listFilesByExtensions(
% arara: --> toFile('SourceFiles/'), ['tex'], false
% arara: --> );
% arara: --> foreach(entry : entries) {
% arara: --> flag = changed(entry) || flag;
% arara: --> };
% arara: --> flag = missing('log') || flag;
% arara: --> flag = missing('aux') || flag;
% arara: --> flag = (exists('log') && found ('log','(Undefined control sequence|Error)')) || flag;
% arara: --> return flag
标题 2
% arara: lualatex: { options: [ '-synctex=1',
% arara: --> '-shell-escape','-interaction=nonstopmode' ]}
% arara: --> if
% arara: --> entries =
% arara: --> com.github.cereda.arara.utils.Methods.listFilesByExtensions(
% arara: --> toFile('SourceFiles/'), ['tex'], false
% arara: --> ); flag = false;
% arara: --> foreach(entry : entries) {
% arara: --> flag = changed(entry) || flag;
% arara: --> };
% arara: --> flag = changed(currentFile()) || flag;
% arara: --> flag = missing('log') || flag;
% arara: --> flag = missing('aux') || flag;
% arara: --> flag = (exists('log') && found ('log','(Undefined control sequence|Error)')) || flag;
% arara: --> return flag
由于该语法利用了表达式语言机制,因此需要一定程度的编程和调整才能正常运行。这就是为什么我认为这是一种实现所需行为的黑客方法。