sphinx-doc / sphinx

The Sphinx documentation generator
https://www.sphinx-doc.org/
Other
6.38k stars 2.09k forks source link

How to force own template class in sphinx without howto/manual override #11481

Open CLargeron opened 1 year ago

CLargeron commented 1 year ago

Describe the bug

I am using the version sphinx 6.2.1 I want to use my own company template latex class in sphinx for the latex generation only (html unchanged). I have modified the conf.py in order to use the template class. The generated tex file contains: \def\sphinxdocclass{my_own_template}

The class is defined before begin{document}

However, after the begin{document}: the sphinx class howto/manual override the header of pages as well as the pagestyle with these following lines

\pagestyle{empty} \sphinxmaketitle \pagestyle{plain} \sphinxtableofcontents \pagestyle{normal}

Is there a way to use a specific template class with using sphinx without getting the sphinxclass which prevents the pagestyle the wanted class ?

Thank you

How to Reproduce

latex_elements = { 'papersize': 'mytemplate', 'passoptionstopackages' : '\PassOptionsToPackage{mytemplate}{my_template}', 'pointsize': '10pt', 'docclass' : 'my_template', }

latex_docclass = { 'manual': 'my_template', 'howto' : 'my_template', }

Environment Information

sphinx 6.2.1

Sphinx extensions

extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.napoleon',
    'sphinx.ext.mathjax',
    'myst_parser',
    'sphinx.ext.autosectionlabel',
    'sphinxcontrib.bibtex'
]

Additional context

No response

jfbu commented 1 year ago

I am really rusty on this. There is some sphinx.builders.latex.theming but I never looked at how it is supposed to be used.

And there is some sphinx.writers.latex.LaTeXWriter.docclasses which got removed at 7.0.

And I remember from past that the whole thing is quite sub-optimal, as examplified by #11128.

One way, say your class build upon report and you want to add a few modifications on top of it:

conf.py

latex_documents = [ 
    ('index', 'test.tex', 'test title', 'test author', 'mylatexclass')
]

latex_additional_files = ['mylatexclass.cls']

mylatexclass.cls:

\ProvidesClass{mylatexclass}[2023/07/03 my own class]
\def\sphinxdocclass{report}% this will be loaded by sphinxmanual, choose any
                           % reasonable base class
\LoadClass{sphinxmanual}

% extra definitions are done here by your class

We should not confuse a "template" with a "latex class". The Sphinx LaTeX template is at sphinx/templates/latex.tex_t. It is responsible for key mark-up, for example \sphinxtableofcontents to appear in tex file. This \sphinxtableofcontents is defined in sphinxmanual.cls or sphinxhowto.cls. These two load a base class which is passed to them in \sphinxdocclass macro.

The whole problem for us is how to influence this \sphinxdocclass? And this is where I recall it became very fishy some years back, and I am not up-to-date. This is a common problem with #11128. It seems one would have to define a latex theme but this looked like overkill.

So the following seems to work:

conf.py

latex_documents = [ 
    ('index', 'test.tex', 'test title', 'test author', 'manual')
]

latex_additional_files = ['mylatexclass.cls']

latex_docclass = { 'manual': 'mylatexclass' }

then what will happen is that tex file will contain:

\def\sphinxdocclass{mylatexclass}
\documentclass[letterpaper,10pt,english]{sphinxmanual}

so the sphinxmanual class will then load the mylatexclass.cls file.

Of course in such set-up you do NOT want mylatexclass to itself load sphinxmanual! This is very different from stuff above, it is exactly the opposite!

Notice that the definitions done by sphinxmanual of stuff such as \sphinxtableofcontents are done after loading the mylatexclass.cls.

But a base class is not good place to modify Sphinx specific things. You should do this in a preamble addition rather.

A class such as mylatexclass (in the second approach) should be a replacement for standard LaTeX classes such as report, which modifies non Sphinx related things.

But as I pointed out there is lot of stuff in the latex template file such as loading of fncychap or whatever, which you can try to modify via the corresponding latex_elements configuration key of the same names rather.

There is also a lot of stuff in auxiliary files loaded by sphinx.sty from the \usepackage{sphinx} done in the template. For example the fancyhdr related things are in file sphinxlatexstylepage.sty which you can completely overwrite via a custom file of same name added to latex_additional_files. The titlesec related things are in file sphinxlatexstyleheadings.sty which you can also completely replace with one of your own.

Sphinx also uses fncychap but here there is a latex_elements key of the same name, and you can use that key to not load at all fncychap. There is no such latex_elements key for titlesec package or fancyhdr package, this is all pretty much illogical incoherent confusing complex legacy inheritance.

CLargeron commented 1 year ago

Thank you for your quick reply.

As you mentioned, the way how to use the latexclass is latex_docclass = { 'manual': 'mylatexclass' } (or howto)

However, this is overrided by sphinxmanual. Since 'mylatexclass' is also used for other purpose (without sphinx), I cannot integrate sphinxdocclass into 'mylatexclass.cls'.

Filling all the options in the preamble is too restrictive and does not able to get all the options from 'mylatexclass'.

I am afraid there is no simple solution.

Torxed commented 5 months ago

Just dropping by to mention a perhaps not perfect solution but an easiest workaround. Copy _build/latex/sphinxmanual.cls after a build (or grab it from github) and place it in your project folder.

Add it to your additional files and keep "manual" as it is:

latex_documents = [ 
    ('index', 'test.tex', 'test title', 'test author', 'manual')
]
latex_additional_files = ['sphinxmanual.cls']

Modify sphinxmanual.cls to your heart's content. It won't get you that perfect totally custom template/class/thing I assume - but it will overwrite the default manual style/class with your file because of the order in which the files are copied in. Or maybe this works good enough? I'm not sure if this breaks the magic glue of Sphinx or not. But it did the trick for me.