MiKTeX 中无需安装即可进行包检测

MiKTeX 中无需安装即可进行包检测

最近我一直在使用一台安装了 MiKTeX 的 W eird indows 机器。通过它的自动软件包安装程序,我注意到,如果我检查一个我确信没有安装的软件包文件是否存在:

\documentclass{article}
\begin{document}
\IfFileExists{abntex2.cls}{Oh, no!}{Phew :)}
\end{document}

MikTeX 将安装包,测试将返回 true。当然,这是完全合理的(安装,而不是包),因为\IfFileExists打开文件进行读取以测试其存在,一旦打开文件,MiKTeX 就会尝试安装它。

为了避免这种情况,我可以使用--disable-installer选项,不出所料,该选项将禁用自动软件包安装程序。但是我想知道是否有(或者我是否可以制作)一个宏级接口,允许我检查软件包是否已安装或是否是安装候选,而不会触发软件包的自动安装。最好不管软件包管理器的当前设置如何。可能吗?

答案1

在这个答案中,我将假设一个 Lua 支持引擎(LuaTeX、HarfTeX 等)

MiKTeX 非常渴望安装软件包,所以你必须欺骗它:如果你正在寻找的文件已经存在于当前目录中,MiKTeX 会很高兴,并且当你向它询问该文件时,它不会安装该软件包。

计划是这样的:在当前工作目录中放置一个虚拟文件。然后通过 kpathsea 模拟询问 MiKTeX全部已知与名称匹配的文件。当然第一个将是本地虚拟文件,但如果找到另一个,则表示已安装该包。然后最后删除虚拟文件。

\documentclass{article}
\newluafunction\filereallyexistsfuncid
\directlua{
local truetok, falsetok = token.create'@firstoftwo', token.create'@secondoftwo'
lua.get_functions_table()[\the\filereallyexistsfuncid] = function()
  local filename = token.scan_string()
  local f = io.open(filename) % First test if the file exists in the current folder
  if f then
    f:close()
    return token.put_next(truetok) % In this case we are done, the file exists
  end
  f = io.open(filename, "w") f:close() % Otherwise create it to stop MiKTeX from installing anything
  local _, f2 = kpse.lookup(filename,{all=true}) % Now we will always find the local file first and MiKTeX is happy. If the file existed before, it will be found too.
  os.remove(filename) % The local file did it's job, delete it
  token.put_next(f2 and truetok or falsetok) % And write the answer to TeX
end
}
\newcommand\filereallyexists{\luafunction\filereallyexistsfuncid}
\begin{document}
\filereallyexists{hyperbar.sty}{AWESOME!}{How can you be so cruel?}
\end{document}

这里需要注意 Lua 语言中比较特殊的结构: kpse.lookup如果 ,则对找到的每个文件返回all=true一个返回值。因此,如果只找到一个文件,则只返回一个值。如果找到两个文件,则返回两个值……该行

local _, f2 = kpse.lookup(...)

将前两个返回值存储在变量_和 中f2。(在 Lua 中_是一个常规变量,但按照惯例,_如果要忽略某个值,则使用 )存储在那里的实际值是找到的文件的完整绝对文件名。但如果只找到一个文件会发生什么?那么就没有“前两个返回值”,只返回一个文件名。在这种情况下,Lua 将其余变量设置为特殊值nil

在我们的代码中,唯一重要的问题是:是f2字符串还是nil?在 Lua 中,每一个字符串(包括空字符串"")被视为真,但nil被视为false。所以我们可以将其视为f2布尔值。这将我们带到最后一行:

token.put_next(f2 and truetok or falsetok)

a and b or cLuaa ? b : c中与 C 语言中的三级条件运算符等价的运算符:如果a(在我们的例子中f2)为true,则得到btruetok),否则得到cfalsetok)。只要b永远不会false(或)作为 Lua 的与的nil短路的结果,此运算符就有效:我们有被视为。如果被视为,则当且仅当。因此 Lua 只需评估为andora and b or c(a and b) or catruea and bba and bb 无需将其转换为布尔值。我们假设b为真,所以(a and b) or c === b or c始终为true,甚至c不必进行求值,因此 Lua 只需返回b,无需转换为布尔值。因此 Lua 的andor 总是返回确定其真值的第一个参数。(对于值会发生什么,false留给a读者练习 ;-))

相关内容