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

Injecting arbitrary LaTeX code dynamically before \begin{document} #8081

Closed
yves-chevallier opened this issue Aug 9, 2020 · 3 comments
Closed
Labels
api builder:latex type:enhancement enhance or introduce a new feature

Comments

@yves-chevallier
Copy link
Contributor

When writing a Sphinx extension or, even when using native Sphinx directives, some specific packages or commands must be declared ahead, before the \begin{document}. From my knowledge, it is currently impossible to dynamically add LaTeX code into the header from an extension or a directive.

A usecase is for exemple the hlist refactoring #8072. This proposal would use a new LaTeX environment \hlist that relies on several packages (multicol, regexpatch...). IMHO adding them directly in sphinx.sty isn't a good solution because you could add some unused packages if the user doesn't use any hlist in its documentation. The same would apply for many other case.

So I propose a way for extensions or even Sphinx directives to dynamically include some LaTeX code based on the usage.

My current way of doing it is the following:

latex_preamble = r"""
%% BEGIN injection for extension <% extension_name %>
\newenvironment{foobar}
<% somevalue %>
...
%% END injection for extension <% extension_name %>
"""

def inject_latex_header(app, context):
    render = LaTeXRenderer()
    context['preamble'] += render.render_string(latex_preamble, extension_context)

def inject_headers(app, doctree, fromdocname):
    if doctree.traverse(foobar) and hasattr(app.builder, 'context'):
        inject_latex_header(app, app.builder.context)

def setup(app):
    ...

    app.connect('doctree-resolved', inject_headers)

    ...

While this snippet works, I would prefer having a more convenient way of doing it with some guards that could perform some checks automatically. We could imagine a method such as:

app.add_latex_header(latex_code, context)

I am not sure though when this should be done. After the doctree is resolved?

@yves-chevallier yves-chevallier added the type:enhancement enhance or introduce a new feature label Aug 9, 2020
@tk0miya
Copy link
Member

tk0miya commented Aug 9, 2020

Why do you need to insert "raw" LaTeX code to the preamble part? Why don't you create a .sty file (.cls file) and load it?

def create_mystyle(app, exception):
    if app.builder.name == 'latex' and exception is None:
        filename = path.join(app.outdir, 'mystyle.sty')
        with open(filename, 'w') as f:
            f.write(...)

def setup(app):
    app.connect('build-finished', create_mystyle)
    app.add_latex_package('mystyle')

@yves-chevallier
Copy link
Contributor Author

There are two reasons behind this:

  • The mystyle.sty you propose must be a template that must by rendered dynamically
  • There are no reason to insert the .sty if the user do not use any of the new Directives added. This make the LaTeX build longer to build.

I would like to add the LaTeX extra code only if some nodes are inserted into the doctree.

@tk0miya
Copy link
Member

tk0miya commented Aug 9, 2020

Indeed. It seems the add_latex_package() has been evaluated at the initialization of LaTeX builder. I think it is better to delay the evaluation until just before writing. Then we can determine to add a LaTeX package on resolving phase.

tk0miya added a commit to tk0miya/sphinx that referenced this issue Aug 9, 2020
…g tex file

This postpones the evaluation of LaTeX packages via
``app.add_latex_package()`` to just before writing .tex file.  That
allows extensions to add LaTeX packages during reading and resolving
phase.
tk0miya added a commit to tk0miya/sphinx that referenced this issue Aug 9, 2020
…g tex file

This postpones the evaluation of LaTeX packages via
``app.add_latex_package()`` to just before writing .tex file.  That
allows extensions to add LaTeX packages during reading and resolving
phase.
tk0miya added a commit to tk0miya/sphinx that referenced this issue Aug 9, 2020
…g tex file

This postpones the evaluation of LaTeX packages via
``app.add_latex_package()`` to just before writing .tex file.  That
allows extensions to add LaTeX packages during reading and resolving
phase.
tk0miya added a commit to tk0miya/sphinx that referenced this issue Aug 10, 2020
…g tex file

This postpones the evaluation of LaTeX packages via
``app.add_latex_package()`` to just before writing .tex file.  That
allows extensions to add LaTeX packages during reading and resolving
phase.
tk0miya added a commit that referenced this issue Sep 20, 2020
…ge_in_latter_phase

Close #8081: latex: Allow to add LaTeX package until writing tex file
jfbu added a commit to jfbu/sphinx that referenced this issue Jan 30, 2021
…inx-doc#8081

This is cosmetic as the blank line starting varwidth environment used
for merged table cells in latex output changed nothing to PDF.

Nevertheless I extended a unit test to have a multi-paragraph merged
cell using varwidth. What is important is that \sphinxAtStartPar line
itself is never followed by blank line.
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 19, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api builder:latex type:enhancement enhance or introduce a new feature
Projects
None yet
Development

No branches or pull requests

2 participants