Open Ulrich-Diez opened 5 years ago
Hi Ulrich,
I really appreciate the detailed write up.
I would like to incorporate your suggestions and release a new version. If you feel like making pull requests for each of the issues, that would be very helpful for me. If not, that's okay, I can make the changes myself, but it'll take a little more time. I definitely won't get to this until at least this coming weekend.
Dear Mr Checkoway,
I just added another suggestion to the issue. The suggestion of taking the token-parameter \everyeof
into account also.
I don't think any of this is a matter of urgency. ;-)
I'd be glad if I could be of assistance with a pull request.
But there are some problems:
\RequirePackage{svn-prov}
and \ProvidesPackageSVN{...
.\ProvidesPackageSVN
as well.I don't know which level of excessiveness in the matter of commenting and explaining the code within the implementation-section of the .dtx-file would be welcome to you. ;-)
Therefore I added some attempts at explaining things to my first posting in this issue.
I would like to leave it to you to decide which passages of explanation to take and which ones to improve/to omit.
Dear Mr Checkoway,
some months ago at the TeX-LaTeX StackExchange forum a question was asked under the title "Macro only to be defined in math mode", https://tex.stackexchange.com/questions/477280/macro-only-to-be-defined-in-math-mode.
The questioner intended to use the everyhook-package for redefining macros that process arguments whenever
\everymath
gets carried out.The question at the TeX-LaTeX StackExchange Forum caused me to look at the code of the everyhook package.
Seems there are some problems with your package everyhook 2014/11/26 v1.2 (SVN Rev: 12)\ Hooks for low level TeX everyX primitives.
Problem 1:
Quote from the documentation (everyhook.pdf):
A token
\expandafter
is promised for ensuring that the macro code>\eh@post<i⟨foo⟩ gets expanded before code>\the\eh@private<i⟨foo⟩.The problem with the code in lines 24-27 is:
That code does not set the token register code>\eh@every<i⟨foo⟩ to
code>\eh@pre<i⟨foo⟩/i>\the\expandafter\eh@private<i⟨foo⟩/i>\eh@post<i⟨foo⟩
but it does set that register to:
code>\eh@pre<i⟨foo⟩/i>\the\eh@private<i⟨foo⟩/i>\eh@post<i⟨foo⟩
The promised
\expandafter
behind\the
is missing.You can easily test this with the following MWE:
Here
\showthe\eh@everypar
reveals:As you can see: The promised
\expandafter
behind\the
is missing.In order to fulfill the promise/in order to have that
\expandafter
behind\the
, two\expandafter
need to be added to line 25:Additionally to fulfilling the promise I'd probably add yet another two
\expandafter
to make sure everything is expanded when it comes to carrying out the very first token that comes from code>\eh@pre<i⟨foo⟩:This way code>\eh@pre<i⟨foo⟩ gets expanded when code>\the\eh@private<i⟨foo⟩ is already expanded while code>\the\eh@private<i⟨foo⟩ gets expanded when code>\eh@post<i⟨foo⟩ is already expanded.
So this will set the token register code>\eh@every<i⟨foo⟩ to
code>\expandafter\eh@pre<i⟨foo⟩/i>\the\expandafter\eh@private<i⟨foo⟩/i>\eh@post<i⟨foo⟩
Problem 2:
Seems a pair of empty braces is not in the right place with
\eh@checkhooknotempty
:Definition of
\eh@checkhooknotempty
as found in everyhook.sty v1.2, dated 2014/11/26:\PackageError
takes three arguments. In\eh@checkhooknotempty
four arguments are passed to it. The last one of them is empty.\ifcsempty
takes three arguments. In\eh@checkhooknotempty
only two arguments are passed to it.Thus
\ifcsempty
's third argument will be taken from the token-stream/input-stream.In case of the hook not being empty this may probably not matter as in this case the tokens which form that argument will be returned to the token-stream. "probably" because a pair of matching curly braces surrounding that argument will be removed after returning if previously present. This might make a difference.
In case of the hook being empty the tokens forming that argument will not be returned to the token-stream. The effect of the removal of these tokens is not predictable. In harmless cases this just leads to subsequent error-messages which are confusing.
Let's change the line-wrapping:
I suggest something like:
Problem 3:
You can use
\PushPreHook
/\PopPreHook
for adding tokens to / for removing tokens from the definitions of macros code>\eh@pre<i⟨foo⟩ .You can use
\PushPostHook
/\PopPostHook
for adding tokens to / for removing tokens from the definitions of macros\eh@post⟨foo⟩
.The problem is:
Somebody may add macro-definitions to code>\eh@pre<i⟨foo⟩ / code>\eh@post<i⟨foo⟩.
If this is done, then every subsequent use of
\PushPreHook{⟨foo⟩}...
or\PopPreHook{⟨foo⟩}...
respective
\PushPostHook{⟨foo⟩}...
or\PopPostHook{⟨foo⟩}...
will reduce the amount of hashes / the parameter-characters
#
that belong to these definitions.You can easily test with the following MWE:
I'd expect this to yield in the end:
The hashes within
\eh@prepar
's definition should be doubled because at the time of expanding\eh@prepar
, the amount of hashes will be reduced/halved.Instead
\show
reveals that the amount of hashes gets halved with each use of\PushPreHook
:In the end you get error-messages because hashes are reduced so much that remaining hashes are taken for a means of denoting arguments of
\eh@prepar
which were not declared in\eh@prepar
's parameter text.The same situation with
\PopPreHook
,\PushPostHook
and\PopPostHook
.In order to resolve this issue, it is helpful to keep in mind:
⟨parameter text⟩
and must have⟨balanced text⟩
.(
⟨definition⟩ → ⟨def⟩⟨control sequence⟩⟨definition text⟩
⟨def⟩ → \def | \gdef | \edef | \xdef
⟨definition text⟩ → ⟨parameter text⟩⟨left brace⟩⟨balanced text⟩⟨right brace⟩
)⟨balanced text⟩
that belongs to the⟨definition text⟩
of the⟨definition⟩
of a macro, two consecutive hashes of that⟨balanced text⟩
will be collapsed into one single hash at the time of having expanded the macro in question.(That's why you can use
##1
/##2
etc for the parameters with macro-definitions nested inside the⟨balanced text⟩
of macro-definitions.)In short: Macro expansion will reduce/halve the amount of consecutive hashes that come from the macro's definition's
⟨balanced text⟩
.⟨balanced text⟩
that belongs to⟨general text⟩
, e.g., the⟨balanced text⟩
of an assignment to a token-register, it will leave the amount of hashes contained in that⟨balanced text⟩
untouched:\the⟨token register⟩
under normal circumstances will yield the same amount of hashes as were contained in that⟨balanced text⟩
.(
⟨variable assignment⟩ → ... | ⟨token variable⟩⟨equals⟩⟨general text⟩
⟨token variable⟩ → ⟨token parameter⟩ | ⟨toksdef token⟩ | \toks⟨8-bit number⟩
⟨general text⟩ → ⟨filler⟩{⟨balanced text⟩⟨right brace⟩
)There are special circumstances when hashes will be doubled:
\message{This is my message: #}
yields on the screen:This is my message: ##
.Be aware that with
\show
and\message{\meaning\...}
you don't get this hash-doubling. The reason is: At the time of writing to screen\show
and\message
actually don't deal with hash-tokens of category-code 6 (parameter) but with the "stringified" variants thereof, i.e., with hash-tokens of category code 12(other).The ε-TeX primitive
\detokenize
is like unexpanded-immediate-writing tokens to an external file (hereby hash-dobling takes place!) and reading back that external file under a category-code-régime where everything but space (which has category code 10(space)) has category code 12(other).The ε-TeX primitive
\scantokens
is like unexpanded-immediate-writing tokens to an external file (hereby hash-dobling takes place!) and reading back that external file under the current category-code-régime.\the
delivers tokens of a⟨token variable⟩
, e.g., of a token-register or of a token-parameter like\everypar
or\everyeof
during an\edef
/\xdef
-expansion-context, hashes will be doubled.This hash-doubling is done for compensating the circumstance that hashes will be reduced after having expanded the macro in question.
\unexpanded
delivers its⟨balanced text⟩
during an\edef
/\xdef
-expansion-context, hashes will be doubled. This hash-doubling is done for compensating the circumstance that hashes will be reduced after having expanded the macro in question.\romannumeral0
-expansion is a powerful tool for reducing the amount of\expandafter
needed for triggering desired expansion-steps:\romannumeral
triggers expansion until (La)TeX finds a number. In the not so interesting case of the number found being positive, (La)TeX will deliver its representation in lowercase roman numerals. In the more interesting case of the number found being not positive, (La)TeX will silently not deliver any token at all but swallow the tokens that form the number.Therefore
\romannumeral
can be (ab?)used for triggering a lot of expansion-work as long as in the end the first tokens from the expansion-result form a non-positive number.In order to get the sequence
\relax6 5 4 3 2 1 0
from macrosyou could place (27-1) = 127
\expandafter
-tokens in front of the sequence\relax\top
.If you change the definition of
\sixth
to\def\sixth{ 6 }
, you can do:You get:
→
→
→
→
→
→
→
→
→ now digit
0
trailed by a space which terminates the digit-sequence that is to be converted is found during searching the number that is to be converted due to\romannumeral
.The terminating space is discarded. 0 is not a positive number. The tokens that form that number get swallowed silently while no tokens will be delivered:
→ as
\romannumeral
-expansion is done,\expandafter
-expansion is done also:\romannumeral0
-expansion is very useful in combination with exchanging macro-arguments.Armed with this knowledge, let's look at the definitions of the macros
\PushPreHook
,\PopPreHook
,\PushPostHook
and\PopPostHook
:Definition of
\PushPreHook
as found in everyhook.sty v1.2, dated 2014/11/26:\PushPreHook's
second argument become the⟨balenced text⟩
of the definition of the temporary macro\eh@tempi
.\expandafter
-chain both that macro\eh@tempi
and the macro\eh@tempii
(which at that time due to\letcs
is equal to code>\eh@pre<i⟨foo⟩) get expanded while no means are applied for ensuring that the reducing of hashes hereby will be compensated.I suggest something like this:
Definition of
\PopPreHook
as found in everyhook.sty v1.2, dated 2014/11/26:Besides the hash-reduction-problem
\eh@popprehook
might—in case of the list of\eh@hookseparator
-separated elements stored in code>\eh@pre<i⟨foo⟩ having only two elements—remove surrounding braces from the second/remaining element.I suggest something like this which does not have the hash-reduction problem and which does without returning whatsoever delimited arguments so that brace removal with delimited arguments does does not matter:
Definition of
\PushPostHook
as found in everyhook.sty v1.2, dated 2014/11/26:I suggest something like this:
Definition of
\PopPostHook
as found in everyhook.sty v1.2, dated 2014/11/26:Besides the hash-reduction-problem the
\eh@popposthook
-loop might remove surrounding braces with all elements of the list of\eh@hookseparator
-separated elements stored in code>\eh@post<i⟨name of hook⟩.I suggest something like this:
Problem 4:
With the package everyhook you are urged to run things under ε-TeX.
In section 5.1 "Mode-Independent Commands" of the ε-TeX manual, Version 2, February 1998 by The NTS Team — Peter Breitenlohner, Max-Planck-Institut füur Physik, München, on page 17 you find a paragraph about the additional possibilities for
⟨token parameter⟩
.This paragraph mentions another token-parameter
\everyeof
:\everyeof
is executed at the end of every\input
file.\everyeof
is also executed at the end of every pseudo-file generated and input by\scantokens
.\everyeof
is not executed at the end of pseudo-files generated and input by\detokenize
.You can nicely use
\everyeof
, e.g., for passing\noexpand
to the end of a (pseudo) file for neutralizing within\edef
/\xdef
-contexts the end-of-file-pseudo-token which usually gets attached by (La)TeX and which, if not neutralized, triggers an error-message in case it is encountered while scanning/gathering the text of a⟨definition⟩
:Perhaps everyhook's facilities can be made available for the
\everyeof
-token-parameter as well.I've allowed myself to create a file UDInterimEveryhook.sty based on your everyhook package where all the changes I've suggested are included:
This way you can easily test by "commenting out"
\usepackage...
-statements for alternately loading either everyhook.sty or UDInterimEveryhook.sty in order to see the difference in behavior between the two package variants.I also have made a small test file:
Sincerely
Ulrich Diez