Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hook after \par, even if issued in vertical mode #1478

Open
ysalmon opened this issue Sep 28, 2024 · 4 comments
Open

Hook after \par, even if issued in vertical mode #1478

ysalmon opened this issue Sep 28, 2024 · 4 comments

Comments

@ysalmon
Copy link

ysalmon commented Sep 28, 2024

Brief outline of the enhancement

Currently, there are hooks para/end and para/after that allow for putting code at the end of a paragraph, just before or just after TeX has returned to vertical mode. Due to the definition of \para_end:, these hooks are only executed when that command (for which initially \par is synonymous) is issued in horizontal mode. This makes sense most of the time because, if that is not the case, there is not an actual paragraph to end.

However, there are instances when one would want to execute a hook whenever a \para_end: command is issued. For example, doing something special when two \par are issued in a row, which can help to discriminate whether there was an empty line after an environment the code of which ends with a \par.

Minimal example showing the current behaviour

(this may not be the best use case, but is is short and very visual)

Another case is the following, where \@setpar{{\@@par}} has been eschewed in favour of a hook to retain \parshape for several paragraphs. The effect is lost on \lipsum[4] because it is following two \par, the second of which did not execute the para/after hook but did the effects of \tex_par:D.

\RequirePackage{latexbug}
\documentclass{article}
\usepackage{lipsum}

\makeatletter
\NewDocumentEnvironment{indented}{}
{\addtolength{\leftmargin}{2cm}
 \addtolength{\@totalleftmargin}{2cm}
 \addtolength{\linewidth}{-2cm}
 \parshape 1 \@totalleftmargin \linewidth
 \AddToHook{para/after}[test]{\parshape 1 \@totalleftmargin \linewidth}
}
{
  \RemoveFromHook{para/after}[test]
}

\begin{document}
\begin{indented}
\lipsum[1]\par\lipsum[2]\par\lipsum[3]\par\par\lipsum[4]\par\lipsum[5]
\end{indented}

\end{document}

The temptation is high to say \AddToHook{cmd/par/after}. This is discouraged, and the reason for this is probably that the first invokation of that command will rewrite the definition of \par to add the hook mechanism at the end. However, when \par is modified then restored at various times, it will be restored to the meaning of \@@par, that is the original definition of \para_end:, which will not use the cmd/par/after hook.

Proposal

To provide such a hook from the beginning, under the name para/afterpar, by defining

\hook_new_reversed:n {para/afterpar}  %%% NEW

\cs_new_protected:Npn \para_end: {
  \scan_stop:
  \mode_if_horizontal:TF {
    \mode_if_inner:F {
         \tex_unskip:D
         \hook_use:n{para/end}
         \@kernel@after@para@end
         \mode_if_horizontal:TF {
           \if_int_compare:w 11 = \tex_lastnodetype:D
             \tex_hskip:D \c_zero_dim
           \fi:
           \tex_par:D
           \hook_use:n{para/after}
           \@kernel@after@para@after
         }
         { \msg_error:nnnn { hooks }{ para-mode }{end}{horizontal} }
    }
  }
  \tex_par:D
  \hook_use:n{para/afterpar}  %%% NEW
}

This will allow to eschew \AddToHook{cmd/par/after} in favour of \AddToHook{para/afterpar}.

Backward compatibility should not be a problem, since for existing code, the hook will remain empty.
There is of course some danger if one puts code in the hook that creates a new paragraph, but the same problem exist for the para/after hook, and this is correctly documented.

I am not suggesting to add a similar para/beforepar hook because :

  • it looks more involved to implement right,
  • it is less useful, because the only novelty would be to execute code before \par when it is issued in vertical mode, but in that precise case just before and just after \par are not very different places.
@muzimuzhi
Copy link
Contributor

Perhaps you can use command hook cmd/<name>/after, though patching internal functions might not be recommended. See texdoc ltcmdhooks-doc for more info.

\documentclass{article}
\ExplSyntaxOn
% this will append "\UseHookWithArguments{cmd/para_end:/after}{0}" to
% \para_end: after the "begindocument" hook
\hook_gput_code:nnn { cmd/para_end:/after } {.} {}

\hook_gput_code:nnn {begindocument/end} {.} { \cs_show:N \para_end: }
\ExplSyntaxOff

\begin{document}
\end{document}

@ysalmon
Copy link
Author

ysalmon commented Sep 28, 2024 via email

@FrankMittelbach
Copy link
Member

Perhaps you can use command hook cmd/<name>/after, though patching internal functions might not be recommended. See texdoc ltcmdhooks-doc for more info.

Patching into the internals of the paragraph handling is a real no-go (and it doesn't help if that is done with a cmd hook), it will most certainly backfire eventually. In a recent issue I already worte that we will strengthen the documentation to say this should not be done --- and if necessary test that certain commands aren't manipulated by cmd hooks.

Despite of that I'll will take a look if there is a safe way to augment the paragraph handling in that direction with a further hook but it will take some time.

@ysalmon
Copy link
Author

ysalmon commented Sep 29, 2024

Thanks you for looking into the feasibility of this. I think I was the author of the other issue you are referring to : indeed, hooking into \par is tempting (@muzimuzhi's comment also shows this is a logical temptation) but dangerous. The idea is to make it so that people no longer have a reason to try to do so.

I will be using the proposed variation of \para_end: in my own documents and will report here if I discover adverse effects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Pool (unscheduled issues)
Development

No branches or pull requests

3 participants