编辑

编辑

不久前,我回答了一个问题,代码试图设置使用 Ti 生成的外部图像的名称Z 的external库,根据输入文件的名称进行替换。该答案按时间顺序排列,可在以下位置找到https://tex.stackexchange.com/a/334290/

首先,我提供了一个宏来明确执行此操作。

\extinput{<filename>}

用于<filename>为外部图像创建名称并读取文件作为输入。

其次,我提供了一个基于的自动化解决方案standalone。它通过修补sa@document环境来获取输入文件的当前名称。然后使用它来为外部化图像创建一个名称。

这似乎出奇地有效,我把它变成了 Ti我本人一直使用 Z 库,并且一直在使用它。

然而,\extinput{<filename>}不再起作用。原来这是因为它使用了

\file_input:n

而不是简单地

\input

这些之间有什么相关区别以及哪些变化导致我的代码被破坏?

这花了我一些时间才找到原因,因为我最初认为自动化解决方案肯定行不通,而显式宏更安全。(而且,事实上是自动化版本出了问题。然而,根本原因似乎是一样的。)

\begin{filecontents}{pic.tex}
\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
  \path [fill] circle (1);
\end{tikzpicture}
\end{document}
\end{filecontents}
\documentclass{article}
\usepackage{xparse,tikz,standalone,currfile,etoolbox}
\usetikzlibrary{external}
\ExplSyntaxOn
\makeatletter
\tl_new:N \g_enext_figurename_tl
\cs_new_protected_nopar:Nn \enext_settofilename:
{
  \enext_tikzsetfigurename:x { \currfilebase- }
}
\cs_new_protected_nopar:Nn \enext_tikzsetfigurename:n
{
  \tikzsetfigurename { #1 }
}
\cs_generate_variant:Nn \enext_tikzsetfigurename:n { x }
\cs_new_protected_nopar:Nn \enext_tikzsetnextfilename:n
{
  \tikzsetnextfilename { #1 }
}
\cs_generate_variant:Nn \enext_tikzsetnextfilename:n { V }
\cs_new_protected_nopar:Nn \enext_setfigurename:
{
  \enext_settofilename:
  \enext_tikzsetnextfilename:V \g_enext_figurename_tl
}
\cs_new_protected_nopar:Nn \enext_setfigurename:n
{
  \enext_tikzsetfigurename:n { #1 }
  \enext_tikzsetnextfilename:V \g_enext_figurename_tl
}
\msg_new:nnnn { enext } { append ~ failed }
{
  \msg_warning_text:n { enext } ~ :: ~ Append ~ to ~ #1 ~ failed ~ \msg_line_context: !
}
{
  This ~ is ~ probably ~ not ~ your ~ fault ~ unless ~ you ~ redefined ~ the ~ modified ~ functions. ~
  Either ~ fix ~ the ~ code ~ yourself ~ or ~ ask ~ for ~ help. ~
  Apologies ~ for ~ any ~ inconvenience. ~
  All ~ code ~ provided ~ as-is ~ for ~ use ~ at ~ your ~ own ~ risk! ~
  As ~ a ~ goodwill ~ gesture, ~ a ~ full ~ refund ~ will ~ be ~ provided ~ on ~ request, ~ less ~ a ~ small ~ fee ~ to ~ cover ~ administration.
}
\msg_new:nnn { enext } { append ~ succeeded }
{
  \msg_warning_text:n { enext } ~ :: ~ Modified ~ #1 ~ \msg_line_context: !
}
\NewDocumentCommand \extinput { m }
{
  \group_begin:
    \enext_setfigurename:n { #1 - }
    \file_input:n { #1 }
%     \input{#1}    % using \input rather than \file_input:n works
  \group_end:
}
\apptocmd \sa@document
{
  \enext_setfigurename:
}{
  \msg_warning:nnn { enext } { append ~ succeeded } { document ~ environment }
}{
  \msg_warning:nnn { enext } { append ~ failed } { document ~ environment }
}
\apptocmd \tikzsetnextfilename
{
  \tl_gset:Nn \g_enext_figurename_tl { #1 }
}{
  \msg_warning:nnn { enext } { append ~ succeeded } { \tikzsetnextfilename }
}{
  \msg_warning:nnn { enext } { append ~ failed } { \tikzsetnextfilename }
}
\apptocmd \tikzexternal@getnextfilename@resetglobals
{
  \tl_gclear:N \g_enext_figurename_tl
}{
  \msg_warning:nnn { enext } { append ~ succeeded } { \tikzexternal@getnextfilename@resetglobals }
}{
  \msg_warning:nnn { enext } { append ~ failed } { \tikzexternal@getnextfilename@resetglobals }
}
\makeatother
\ExplSyntaxOff
\tikzexternalize
\begin{document}
\tikzexternalenable
\begin{figure}
  \extinput{pic}
\end{figure}
\end{document}

似乎发生的情况是,外部化图形的名称从未正确设置,并且一些不应该优化的东西被优化掉了。

\g__file_internal_ior=\read2
(./<tikz picture filename>.tex
A tikzpicture has been optimized away. Use '/tikz/external/optimize=false' to disable this.
)

这是来自外部化运行的日志,<main filename>-0.log。该文件甚至不应该存在,因为它应该使用<tikz picture filename>而不是<main filename>创建名称。在本例中,它应该使用pic该名称,因此日志应该是pic-0.log

我认为它之所以对其进行优化正是因为名称不正确。

! Package tikz Error: Sorry, image externalization failed: the resulting image 
was EMPTY. I tried to externalize '<main filename>-0', but it seems there is no such image in the document!?  

如果我注释掉带有 的行\file_input:n并取消注释带有 的行\input,那么图像就会按预期写入,pic-0.pdf日志也会pic-0.log按预期写入 。

这两种情况之间的相关区别是什么以及/或者还有哪些变化导致了这个问题?

我怀疑\currfilebase在两种情况下的设置不同,或者在一种情况下没有设置,但我不确定,也不知道原因。如果我注释掉的补丁,它就可以工作了。那么现在和sa@document之间是否存在冲突?\currfilebase\file_input:n

编辑

我认为问题在于不再像以前那样\file_input:n触发包中的钩子,并且不会像以前那样。因此,这些钩子存储的当前文件信息不再通过它提供的宏获得,而这些宏依赖于数据。filehook\inputcurrfile

我知道我可以使用以下方法检索当前文件的名称

\g_file_current_name_tl

但是,我需要处理它以提取基本名称。显然这是可以做到的,但要稳健/安全地做到这一点似乎并不是一件容易的事。我可以通过其他方式获取此信息吗?

答案1

方法是expl3,每个命令都有明确、定义的语义,独立于其他加载的代码。相反,LaTeX 文档命令\input(如问题中观察到的)由filehooks包修改。因此,\file_input:n它更像是 TeX\input原语(\@@input在 LaTeX 中),而不是文档级\input命令。

在 中expl3\file_input:n是一个相对低级的函数,用于此时读取指定文件的内容,并对操作进行一些“整理”。如前所述,它确实设置了\g_file_current_name_tl(尽管目前该领域仍有一些问题需要解决)。如果需要提供其他数据(可能是“当前基本名称”),则向 LaTeX-L 列表或GitHub 问题跟踪器是合适的。

相关内容