我使用 LuaLaTeX。今天我决定尝试一下这个gridset
包。令我惊讶的是,\usepackage{gridset}
它产生了一个错误,告诉我该\savepos
命令已经定义。
梅威瑟:
\documentclass{article}
% will be undefined in pdflatex, defines as itself in lualatex:
\show\savepos
\begin{document}
yada yada
\end{document}
看起来 LuaLaTeX 定义了\savepos=\savepos
。这很奇怪。
如果我先取消定义,\savepos
然后我就可以加载gridset
LuaLaTeX,而且它似乎可以工作:
\let\savepos\relax
\usepackage{gridset}
% Then I can use \savepos in the document body.
这是一个“哎呀”,还是 LuaLaTex 中这种行为有原因?
编辑:回应 ShreevatsaR 的回答:
\documentclass{article}
% compile with lualatex
\begin{document}
yada yada\savepos{eek}\par
yada yada
\end{document}
结果:没有错误,但打印了“eek”,文件中没有任何内容aux
。或者,使用pdfsavepos{eek}
会产生错误。使用 TeXlive 2017,最新版。
EDIT2:接受的答案非常有用。我能够解决我最初提出问题的问题,并将解决方案作为后续答案发布在下面。
答案1
您的迫切问题
不幸的是,该gridset
包定义了一个\savepos
与 LuaTeX 原语同名的宏。如果您不需要 LuaTeX\savepos
功能(至少不需要该名称),您可以执行以下操作:
\let\luatexPrimitiveSavepos=\savepos
\let\savepos=\relax
\usapackage{gridset}
\let\gridsetPackageSavepos=\savepos
类似于您在问题中提到的,然后使用\luatexPrimitiveSavepos
或\gridsetPackageSavepos
,无论您需要哪一个,避免使用歧义的名称\savepos
。
也许可以将该包更改为在 LuaTeX 下自动执行一些合理的操作,或者(如果可行的话)只是使用不同的名称而不是\savepos
。
被问到的“为什么”
在 LuaTeX 引擎中,\savepos
是一个基元。当 TeX 被要求处理\show
一个基元时,它会将其显示为自身(例如,\show\def
将显示\def=\def
)。
此原语也存在于 pdfTeX 和 XeTeX 引擎中,名称为\pdfsavepos
,但在 LuaTeX 程序中,他们删除了pdf
前缀。这记录在LuaTeX 手册,第 2.1.4 节与 pdfTeX 1.40 的变化:
由于位置跟踪在 dvi 模式下也可用,因此
\savepos
、\lastxpos
和\lastypos
命令现在取代了其
还 (第 2.2 节 后端原语 \pdf *):
如果您还想要一些向后兼容性,您可以添加:
...
\let\pdfsavepos \savepos
(有很多这样的重命名原语。)
什么是\savepos
(或\pdfsavepos
)
关于此原语的一些注释\savepos
(在 LuaTeX 中)或\pdfsavepos
(在 pdfTeX 和 XeTeX 中)。它起源于 pdfTeX,最好的文档是pdfTeX 手册:
▶
\pdflastxpos
(只读整数)
此基元返回一个整数,表示 标记的最后一个点的绝对 x 坐标\pdfsavepos
。单位是“缩放点数”(sp)。
▶\pdflastypos
(只读整数)
与 完全类似\pdflastxpos
,返回 y 坐标。...
▶
\pdfsavepos (h, v, m)
此基元标记介质上当前的绝对 (x, y) 位置,参考点位于左下角。它只在页面输出期间(即页面最终组装时)处于活动状态。然后可以通过\pdflastxpos
和\pdflastypos
基元检索位置坐标,并将其写入某个辅助文件。只有在当前坐标\shipout
完成后才能使用这些坐标,因此通常需要运行两次 pdfTeX 才能使用这些基元。从 pdfTeX 1.40.0 开始,在 DVI 模式下运行时也可以使用此机制。
(正如@MarcelKrüger 在评论中指出的那样,(h, v, m)
表示该原语可以在任何模式下使用:水平模式/垂直模式/数学模式。)
(由于这些原语来自 pdfTeX,它的扩展 XeTeX 和 LuaTeX 没有对它们进行非常广泛的记录,就像它们没有记录 TeX 原语一样:在XeTeX 手册解释很简短,在 LuaTeX 手册中完全省略了。
您可以按如下方式使用它们:
% compile with pdflatex or xelatex
\documentclass{article}
\begin{document}
\pdfpageheight=2.5in % Really short pages, just so that I can get a screenshot.
yada yada\pdfsavepos eek\par
yada yada
\newpage
The last saved position was x=\the\pdflastxpos, and y=\the\pdflastypos.
\end{document}
或者
% compile with lualatex
\documentclass{article}
\begin{document}
\pageheight=2.5in % Really short pages, just so that I can get a screenshot.
yada yada\savepos eek\par
yada yada
\newpage
The last saved position was x=\the\lastxpos, and y=\the\lastypos.
\end{document}
二者均能产生:
(这里,使用lualatex
和进行编译时, xelatex
“x”数字与使用 进行编译时略有不同pdflatex
:原因正如@HenriMenke 指出的,是这两个默认加载 Latin Modern,而不是默认pdflatex
加载cmr
(Computer Modern)——并且这些字体的度量略有不同。)
另请参阅文章pdfTeX 的小秘密:跟踪位置作者:Hans Hagen地图 25(2000)第 74-78 页,似乎是关于这些原语的。
当然,这个原语(无论称为\pdfsavepos
或)与包定义的宏完全无关。不幸的是,包选择的名称已被较新的引擎用作原语。\savepos
\savepos
gridset
答案2
我问这个问题时脑子里想的是某个特定的应用。为了方便大家,我现在将向大家展示我做了什么。类似的代码将出现在我的自定义文档类 (novel) 的下一次更新中,但以下代码将适用于任何使用 LuaLaTeX 的文档类。
问题性质:我只写小说,用于印刷。这意味着连续的文字,而不是方程式。有时,一章中会有场景中断。场景中断用空白行表示。
然而,良好的排版习惯不允许将空白行放在页面的最顶部或最底部,因为在那里可能不引人注意。此外,将其放在上面或下面只有一行看起来也不好。
因此,以下代码检测我的\scenebreak
命令的页面位置。如果位置不正确,则会发出警告。
要查看其运行情况,请将代码加载到显示警告的编辑器(例如 TeXworks)中。将数字\yadayada
从 43 变为 48。在 43 和 48 时,没有问题。在 44 和 47 时,系统会警告您\scenebreak
太靠近页面顶部/底部。在 45 和 46 时,系统会警告您\scenebreak
位于顶部/底部。
\documentclass[letterpaper]{article}
% Compile with LuaLaTeX.
\usepackage{fp}
\usepackage{xifthen}
\setlength\parskip{0pt}
\flushbottom
%
\makeatletter
% Assumes contast \baselineskip.
\def\@LinesPerPage{46} % Main text. Change to actual value for your document.
%
\newlength\TotalYpos
\def\InitialYpos{% top of text block
\begingroup%
\savepos%
\protected@write\@auxout{}{%
\protect\@TotalYpos{\noexpand\number\lastypos}%
}%
\endgroup%
}
%
\def\@TotalYpos#1{\setlength\TotalYpos{#1sp}}
%
\newcommand\scenebreak{%
\leavevmode\getBreakpos{scenebreak}~\par
}
\newlength\CurrentBreakpos
\def\getBreakpos#1{%
\begingroup%
\savepos%
\protected@write\@auxout{}{%
\protect\@getBreakpos{\noexpand\number\lastypos}{\thepage}{#1}%
}%
\endgroup%
}
\gdef\@getBreakpos#1#2#3{} % nothing, when reading aux at beginning
\AtBeginDocument{
\gdef\@getBreakpos#1#2#3{% numerical position sp, page, break type
\setlength\CurrentBreakpos{#1sp}% measured up from very bottom of page.
\FPsub{\@BreakLines}{\strip@pt\TotalYpos}{\strip@pt\CurrentBreakpos}
\FPdiv{\@BreakLines}{\@BreakLines}{\strip@pt\baselineskip}%
\FPround{\@BreakLines}{\@BreakLines}{0}% integer lines from text top
\ifthenelse{\equal{#3}{scenebreak}}{%
\xdef\thisline{\@BreakLines}%
\ifnum\@BreakLines=1%
\ClassWarning{any}{Replace \string\scenebreak\space at top of ^^J%
page #2 with alternative.}%
\fi%
\ifnum\@BreakLines=\@LinesPerPage%
\ClassWarning{any}{Replace \string\scenebreak\space at bottom of ^^J%
page #2 with alternative.}%
\fi%
}{}%
\FPsub{\@nearthebottom}{\@LinesPerPage}{1}%
\ifnum\@BreakLines=2%
\ClassWarning{any}{\string\ #3 too close to top of page #2.}%
\fi%
\ifnum\@BreakLines=\@nearthebottom%
\ClassWarning{any}{\string\ #3 too close to bottom of page #2.}%
\fi%
}%
} % end \AtBeginDocument
\makeatother
%
% This is for the MWE, not part of the position code:
\newcount\yadacurrentcount
\newcount\yadaendcount
\newcommand\yadayada[1]{%
\yadacurrentcount=1%
\yadaendcount=#1%
\loop%
\makebox[\parindent][l]{\the\yadacurrentcount.}%
Yada yada.\par
\advance\yadacurrentcount 1%
\ifnum\yadacurrentcount<\yadaendcount%
\repeat%
}
%
\begin{document}
\InitialYpos%
\yadayada{43} % vary from 43 to 48 to see effect
\scenebreak
\yadayada{30}
\end{document}
答案3
我迟到了,但这里还有一个额外的解决方案:
Markus Kohm, author of the gridset
package has an updated version, dated 2017, on his own website: https://komascript.de/gridset. This version correctly deals with LuaTeX.
However, that site contains two disclaimers:
Note: I do not longer recommend to use this package!
Note: You cannot find the current release on CTAN.
So, YMMV.