12

I use LuaLaTeX. Today I decided to try the gridset package. To my surprise, \usepackage{gridset} produced an error, telling me that the \savepos command was already defined.

MWE:

\documentclass{article}
% will be undefined in pdflatex, defines as itself in lualatex: 
\show\savepos
\begin{document}
yada yada
\end{document}

It seems that LuaLaTeX defines \savepos=\savepos. That's odd.

If I first un-define \savepos then I can load gridset in LuaLaTeX, and it appears to work:

\let\savepos\relax
\usepackage{gridset}
% Then I can use \savepos in the document body.

Is this an "oops," or is there a reason for that behavior in LuaLaTex?

EDIT: In response to ShreevatsaR's answer:

\documentclass{article}
% compile with lualatex
\begin{document}
yada yada\savepos{eek}\par
yada yada
\end{document}

Result: No error, but "eek" is printed, and there is nothing in the aux file. Alternatively, using pdfsavepos{eek} produces an error. Using TeXlive 2017, up to date.

EDIT2: The accepted answer is very informative. I was able to solve the problem for which I originally asked the question, and posted the solution as a follow-up answer, below.

5
  • 1
    @HenriMenke Downloaded the article, will look. But of course, mere sniveling users, such as myself, do not expect to read that kind of thing. All we want is an example of usage. As this linked page says, "TeX was not designed as a programming language...". So do not be surprised if users are not programmers. tex.ac.uk/FAQ-repeat-num.html
    – user139954
    Commented Apr 20, 2018 at 14:09
  • @RobtAll Good idea to have different names. You don't necessarily have to reimplement \savepos; I edited the suggestion at the top of the answer to a different approach. Commented Apr 20, 2018 at 16:33
  • 1
    @ShreevatsaR Yes, now that I understand what is going on, I have made progress. What I want to do can be done directly using the luatex \savepos command, without loading another package. When I get it working, I'll add an answer showing the code, in case anyone else finds it useful.
    – user139954
    Commented Apr 20, 2018 at 16:49
  • Several years later: Note that the package has been updated, simply use \SavePos.
    – user202729
    Commented Jan 28 at 1:41

3 Answers 3

19

Your immediate problem

Unfortunately the gridset package defines a \savepos macro which has the same name as a LuaTeX primitive. If you don't need the LuaTeX \savepos functionality (at least under that exact name), you can do:

\let\luatexPrimitiveSavepos=\savepos
\let\savepos=\relax
\usapackage{gridset}
\let\gridsetPackageSavepos=\savepos

similar to what you mentioned in the question, and then use either \luatexPrimitiveSavepos or \gridsetPackageSavepos, whichever you need, avoiding the ambiguous name \savepos.

Maybe the package could be changed to do something reasonable under LuaTeX automatically, or (if feasible) just use a different name instead of \savepos.


The “why”, as asked

In the LuaTeX engine, \savepos is a primitive. When TeX is asked to \show a primitive, it shows it as itself (for example, \show\def will show \def=\def).

This primitive is also present in the pdfTeX and XeTeX engines, under the name \pdfsavepos, but in the LuaTeX program they removed the pdf prefix. This is documented in the LuaTeX manual, section 2.1.4 Changes from pdfTeX 1.40:

Because position tracking is also available in dvi mode the \savepos, \lastxpos and \lastypos commands now replace their pdf prefixed originals.

Also (section 2.2 The backend primitives \pdf *):

If you also want some backward compatibility, you can add:
...
\let\pdfsavepos \savepos

(There are a bunch of such renamed primitives.)


What is \savepos (or \pdfsavepos)

Some notes on this primitive \savepos (in LuaTeX) or \pdfsavepos (in pdfTeX and XeTeX). It originates with pdfTeX, and is best documented in the pdfTeX manual:

\pdflastxpos (read–only integer)
This primitive returns an integer number representing the absolute x coordinate of the last point marked by \pdfsavepos. The unit is ‘scaled points’ (sp).
\pdflastypos (read–only integer)
Completely analogous to \pdflastxpos, returning the y coordinate.
...
▶ \pdfsavepos (h, v, m)
This primitive marks the current absolute (x, y) position on the media, with the reference point in the lower left corner. It is active only during page shipout, when the page is finally assembled. The position coordinates can then be retrieved by the \pdflastxpos and \pdflastypos primitives, and e.g. written out to some auxiliary file. The coordinates can be used only after the current \shipout has been finalized, therefore normally two pdfTeX runs are required to utilize these primitives. Starting with pdfTeX 1.40.0, this mechanism can be used also while running in DVI mode.

(As pointed out by @MarcelKrüger in a comment, the (h, v, m) indicates that this primitive can be used in any of the modes: horizontal mode / vertical mode / math mode.)

(As these primitives comes from pdfTeX, its extensions XeTeX and LuaTeX don't document them very extensively, the same way they don't document TeX primitives: in the XeTeX manual the explanation is brief, and entirely omitted in the LuaTeX manual.)

You can use them as follows:

% 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}

or

% 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}

Both of which produce:

output

(Here, when compiling with lualatex and xelatex the “x” number is slightly different compared to compiling with pdflatex: the reason as @HenriMenke points out is that these two load Latin Modern by default, instead of pdflatex which loads cmr (Computer Modern) by default—and these fonts have slightly different metrics.)

See also the article pdfTeX’s little secret: Tracking positions by Hans Hagen in MAPS 25 (2000) pp. 74–78, which seems to be about these primitives.

This primitive (whether called \pdfsavepos or \savepos) is of course entirely unrelated to the \savepos macro defined by the gridset package. The package has unfortunately chosen a name that is used for a primitive by a newer engine.

14
  • Really? See my edit to the original question.
    – user139954
    Commented Apr 20, 2018 at 3:22
  • 2
    @RobtAll Yes really. :-) \pdfsavepos gives an error because it's not defined by default in LuaTeX. And it's not surprising that with \savepos you get "eek" in the output and nothing in the aux file; after all this is the same behaviour if you have \pdfsavepos and compile with pdflatex. Commented Apr 20, 2018 at 3:37
  • Maybe that's what it does, but it makes no sense at all. If \savepos is a lualatex primitive, then it ought to DO something. Instead, it exhibits no behavior that I can discern. So, how is it used?
    – user139954
    Commented Apr 20, 2018 at 3:48
  • Further: I should note that "read the manual" is not adequate. Nobody reads a manual to find how to use a command that is mentioned numerous times in search results - but doesn't work that way any longer!
    – user139954
    Commented Apr 20, 2018 at 3:51
  • 1
    You get slightly different numbers because the LuaLaTeX format loads Latin Modern instead of cmr by default and the metrics are slightly different. Commented Apr 20, 2018 at 5:39
2

I asked my question with a particular application in mind. For the benefit of anyone, I will now show you what I did. Similar code will appear in the next update of my custom document class (novel), but the following code will work in any document class using LuaLaTeX.

Nature of the problem: I write only fiction for print to paper. That means continuous text, not equations. From time to time, there is a scene break within a chapter. The scene break is denoted by a blank line.

However, good typographic practice forbids placing the blank line at the very top or bottom of a page, where it might not be noticed. Also, placing it with only one line above or below looks bad.

So, the following code detects the page position of my \scenebreak command. If it is badly placed, a Warning is issued.

To see it in operation, load the code into an editor (such as TeXworks) that displays Warnings. Vary the number of \yadayada from 43 to 48. At 43 and 48, no problem. At 44 and 47, you will be warned that \scenebreak is too close to page top/bottom. At 45 and 46, you will be warned that \scenebreak is at top/bottom.

\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}
1

I am late to the show, but here is one additional solution:

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.

You must log in to answer this question.