Lua 中与 @ifpackageloaded 等效的

Lua 中与 @ifpackageloaded 等效的

我正在编写一个主要使用 Lua 文件的包。到目前为止,我还没有找到测试的方法在 Lua 代码中给定的包是否已加载。我正在做的是使用\@ifpackageloaded并调用 Lua 函数:

% Configure cref names if cleveref is loaded
\makeatletter
\@ifpackageloaded{cleveref}%
{\directlua{lyluatexmp.set_cref_names()}}%
\makeatother

但是我思考该信息也应该适用于 Lua,这使得处理这个问题变得更容易。

[编辑:]
虽然解决方案这个答案 工作(在 TeX Live 2019/2017 上)当将函数移到外部 Lua 文件(我希望它在该文件中)时它不起作用:

local function loaded(ext)
  local fmt = "ver@\\csstring\\%s." .. ext
  return function(name)
    return not not token.get_macro(fmt:format(name))
  end
end
return {
    package = loaded"sty",
    class = loaded"cls"
}

在 test-two.lua 文件中(注意这里需要双反斜杠)和

\directlua{
local mod = require('test-two.lua')
classloaded = mod.class
packageloaded = mod.package
}
\directlua{
if classloaded"article" then
  texio.write_nl"`article` loaded"
else
  texio.write_nl"`article` not loaded"
end
}
\documentclass{article}
\directlua{
if classloaded"article" then
  texio.write_nl"`article` loaded"
else
  texio.write_nl"`article` not loaded"
end
if packageloaded"cleveref" then
  texio.write_nl"`cleveref` loaded"
else
  texio.write_nl"`cleveref` not loaded"
end
}
\usepackage{cleveref}
\directlua{
  if packageloaded"cleveref" then
    texio.write_nl"`cleveref` loaded"
  else
    texio.write_nl"`cleveref` not loaded"
  end
}
\stop

总是返回false。事实证明,在第二个实现中(TeX Live 2017 和 2019),的结果get_macro始终为,而在第一个实现中,始终返回 的值。niltoken.create(fmt:format(name)).commandundefined_cs

有什么办法可以解决这个问题吗?

答案1

您可以通过将原始的 TeX 级实现转换为 Lua 来实现\@ifpackageloaded(和):\@ifclassloaded

\directlua{
  local not_loaded_cmds = {
    [token.command_id'undefined_cs'] = true,
    [token.command_id'relax'] = true,
  }
  local function loaded(ext)
    local fmt = "ver@\csstring\%s." .. ext
    return function(name)
      return not not_loaded_cmds[token.create(fmt:format(name)).command]
    end
  end
  packageloaded = loaded"sty"
  classloaded = loaded"cls"
}
\directlua{
if classloaded"article" then
  texio.write_nl"`article` loaded"
else
  texio.write_nl"`article` not loaded"
end
}
\documentclass{article}
\directlua{
if classloaded"article" then
  texio.write_nl"`article` loaded"
else
  texio.write_nl"`article` not loaded"
end
if packageloaded"cleveref" then
  texio.write_nl"`cleveref` loaded"
else
  texio.write_nl"`cleveref` not loaded"
end
}
\usepackage{cleveref}
\directlua{
  if packageloaded"cleveref" then
    texio.write_nl"`cleveref` loaded"
  else
    texio.write_nl"`cleveref` not loaded"
  end
}
\stop

这会写入标准输出(和日志)

[...]
`article` not loaded
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/article.cls
Document Class: article 2018/09/03 v1.4i Standard LaTeX document class
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/size10.clo))
`article` loaded
`cleveref` not loaded
(/usr/local/texlive/2019/texmf-dist/tex/latex/cleveref/cleveref.sty)
`cleveref` loaded)
[...]

可以使用而不是检查命令 id 来创建另一个与旧 LuaTeX 版本更兼容的版本(适用于 TeXLive 2017,我还没有测试过任何更早的版本)token.get_macro。理论上,这与 TeX 宏的兼容性较差,但我目前想不出任何与此相关的情况:

\directlua{
  local function loaded(ext)
    local fmt = "ver@\csstring\%s." .. ext
    return function(name)
      return not not token.get_macro(fmt:format(name))
    end
  end
  packageloaded = loaded"sty"
  classloaded = loaded"cls"
}
\directlua{
if classloaded"article" then
  texio.write_nl"`article` loaded"
else
  texio.write_nl"`article` not loaded"
end
}
\documentclass{article}
\directlua{
if classloaded"article" then
  texio.write_nl"`article` loaded"
else
  texio.write_nl"`article` not loaded"
end
if packageloaded"cleveref" then
  texio.write_nl"`cleveref` loaded"
else
  texio.write_nl"`cleveref` not loaded"
end
}
\usepackage{cleveref}
\directlua{
  if packageloaded"cleveref" then
    texio.write_nl"`cleveref` loaded"
  else
    texio.write_nl"`cleveref` not loaded"
  end
}
\stop

两个答案都使用了

local fmt = "ver@\csstring\%s." .. ext

这里\csstring\%只是扩展为%(带有 catcode other)。这是必要的,因为 TeX 否则会将其%视为注释字符。如果将此代码移动到普通 Lua 文件(或块luacode*)中,TeX 永远不会看到该行,因此\csstring\%必须将其替换为%。然后该行变为

local fmt = "ver@%s." .. ext

答案2

我已经接受了回答但我想展示一下我得出的结果,在 Lua 文件中实现解决方案

local function _loaded(ext)
--[[
    Returns a function that checks whether a class or a package is loaded
--]]
    local fmt = "ver@%s." .. ext
    return function(name)
        local macro = token.get_macro(fmt:format(name))
        return macro ~= nil
    end
end

-- Lua implementations of \@ifpackageloaded and \@ifclassloaded
lib.class_loaded = _loaded('cls')
lib.package_loaded = _loaded('sty')

lib是从模块返回的表,代码用于luaoptions包裹 (https://github.com/lualatex-tools/luaoptions/blob/master/luaoptions-lib.lua#L142) 即将在 CTAN 上发布。

相关内容