mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Support user defined LaTeX themes
This commit is contained in:
parent
a13ec4f41c
commit
cdbefb600f
@ -1904,7 +1904,7 @@ These options influence LaTeX output.
|
|||||||
|
|
||||||
This value determines how to group the document tree into LaTeX source files.
|
This value determines how to group the document tree into LaTeX source files.
|
||||||
It must be a list of tuples ``(startdocname, targetname, title, author,
|
It must be a list of tuples ``(startdocname, targetname, title, author,
|
||||||
documentclass, toctree_only)``, where the items are:
|
theme, toctree_only)``, where the items are:
|
||||||
|
|
||||||
*startdocname*
|
*startdocname*
|
||||||
String that specifies the :term:`document name` of the LaTeX file's master
|
String that specifies the :term:`document name` of the LaTeX file's master
|
||||||
@ -1926,13 +1926,8 @@ These options influence LaTeX output.
|
|||||||
applies. Use ``\\and`` to separate multiple authors, as in:
|
applies. Use ``\\and`` to separate multiple authors, as in:
|
||||||
``'John \\and Sarah'`` (backslashes must be Python-escaped to reach LaTeX).
|
``'John \\and Sarah'`` (backslashes must be Python-escaped to reach LaTeX).
|
||||||
|
|
||||||
*documentclass*
|
*theme*
|
||||||
Normally, one of ``'manual'`` or ``'howto'`` (provided by Sphinx and based
|
LaTeX theme. See :confval:`latex_theme`.
|
||||||
on ``'report'``, resp. ``'article'``; Japanese documents use ``'jsbook'``,
|
|
||||||
resp. ``'jreport'``.) "howto" (non-Japanese) documents will not get
|
|
||||||
appendices. Also they have a simpler title page. Other document classes
|
|
||||||
can be given. Independently of the document class, the "sphinx" package is
|
|
||||||
always loaded in order to define Sphinx's custom LaTeX commands.
|
|
||||||
|
|
||||||
*toctree_only*
|
*toctree_only*
|
||||||
Must be ``True`` or ``False``. If true, the *startdoc* document itself is
|
Must be ``True`` or ``False``. If true, the *startdoc* document itself is
|
||||||
@ -2087,6 +2082,33 @@ These options influence LaTeX output.
|
|||||||
This overrides the files which is provided from Sphinx such as
|
This overrides the files which is provided from Sphinx such as
|
||||||
``sphinx.sty``.
|
``sphinx.sty``.
|
||||||
|
|
||||||
|
.. confval:: latex_theme
|
||||||
|
|
||||||
|
The "theme" that the LaTeX output should use. It is a collection of settings
|
||||||
|
for LaTeX output (ex. document class, top level sectioning unit and so on).
|
||||||
|
|
||||||
|
As a built-in LaTeX themes, ``manual`` and ``howto`` are bundled.
|
||||||
|
|
||||||
|
``manual``
|
||||||
|
A LaTeX theme for writing a manual. It imports the ``report`` document
|
||||||
|
class (Japanese documents use ``jsbook``).
|
||||||
|
|
||||||
|
``howto``
|
||||||
|
A LaTeX theme for writing an article. It imports the ``article`` document
|
||||||
|
class (Japanese documents use ``jreport`` rather). :confval:`latex_appendices`
|
||||||
|
is available only for this theme.
|
||||||
|
|
||||||
|
It defaults to ``'manual'``.
|
||||||
|
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
|
||||||
|
.. confval:: latex_theme_path
|
||||||
|
|
||||||
|
A list of paths that contain custom LaTeX themes as subdirectories. Relative
|
||||||
|
paths are taken as relative to the configuration directory.
|
||||||
|
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
|
||||||
|
|
||||||
.. _text-options:
|
.. _text-options:
|
||||||
|
|
||||||
|
@ -493,7 +493,7 @@ def default_latex_documents(config: Config) -> List[Tuple[str, str, str, str, st
|
|||||||
make_filename_from_project(config.project) + '.tex',
|
make_filename_from_project(config.project) + '.tex',
|
||||||
texescape.escape_abbr(project),
|
texescape.escape_abbr(project),
|
||||||
texescape.escape_abbr(author),
|
texescape.escape_abbr(author),
|
||||||
'manual')]
|
config.latex_theme)]
|
||||||
|
|
||||||
|
|
||||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||||
@ -516,6 +516,8 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
|||||||
app.add_config_value('latex_show_pagerefs', False, None)
|
app.add_config_value('latex_show_pagerefs', False, None)
|
||||||
app.add_config_value('latex_elements', {}, None)
|
app.add_config_value('latex_elements', {}, None)
|
||||||
app.add_config_value('latex_additional_files', [], None)
|
app.add_config_value('latex_additional_files', [], None)
|
||||||
|
app.add_config_value('latex_theme', 'manual', None, [str])
|
||||||
|
app.add_config_value('latex_theme_path', [], None, [list])
|
||||||
|
|
||||||
app.add_config_value('latex_docclass', default_latex_docclass, None)
|
app.add_config_value('latex_docclass', default_latex_docclass, None)
|
||||||
|
|
||||||
|
@ -8,10 +8,17 @@
|
|||||||
:license: BSD, see LICENSE for details.
|
:license: BSD, see LICENSE for details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import configparser
|
||||||
|
from os import path
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
from sphinx.application import Sphinx
|
from sphinx.application import Sphinx
|
||||||
from sphinx.config import Config
|
from sphinx.config import Config
|
||||||
|
from sphinx.errors import ThemeError
|
||||||
|
from sphinx.locale import __
|
||||||
|
from sphinx.util import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Theme:
|
class Theme:
|
||||||
@ -56,11 +63,30 @@ class BuiltInTheme(Theme):
|
|||||||
return 'chapter'
|
return 'chapter'
|
||||||
|
|
||||||
|
|
||||||
|
class UserTheme(Theme):
|
||||||
|
"""A user defined LaTeX theme."""
|
||||||
|
|
||||||
|
def __init__(self, name: str, filename: str) -> None:
|
||||||
|
self.name = name
|
||||||
|
self.config = configparser.RawConfigParser()
|
||||||
|
self.config.read(path.join(filename))
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.docclass = self.config.get('theme', 'docclass')
|
||||||
|
self.wrapperclass = self.config.get('theme', 'wrapperclass')
|
||||||
|
self.toplevel_sectioning = self.config.get('theme', 'toplevel_sectioning')
|
||||||
|
except configparser.NoSectionError:
|
||||||
|
raise ThemeError(__('%r doesn\'t have "theme" setting') % filename)
|
||||||
|
except configparser.NoOptionError as exc:
|
||||||
|
raise ThemeError(__('%r doesn\'t have "%s" setting') % (filename, exc.args[0]))
|
||||||
|
|
||||||
|
|
||||||
class ThemeFactory:
|
class ThemeFactory:
|
||||||
"""A factory class for LaTeX Themes."""
|
"""A factory class for LaTeX Themes."""
|
||||||
|
|
||||||
def __init__(self, app: Sphinx) -> None:
|
def __init__(self, app: Sphinx) -> None:
|
||||||
self.themes = {} # type: Dict[str, Theme]
|
self.themes = {} # type: Dict[str, Theme]
|
||||||
|
self.theme_paths = [path.join(app.srcdir, p) for p in app.config.latex_theme_path]
|
||||||
self.load_builtin_themes(app.config)
|
self.load_builtin_themes(app.config)
|
||||||
|
|
||||||
def load_builtin_themes(self, config: Config) -> None:
|
def load_builtin_themes(self, config: Config) -> None:
|
||||||
@ -70,7 +96,23 @@ class ThemeFactory:
|
|||||||
|
|
||||||
def get(self, name: str) -> Theme:
|
def get(self, name: str) -> Theme:
|
||||||
"""Get a theme for given *name*."""
|
"""Get a theme for given *name*."""
|
||||||
if name not in self.themes:
|
if name in self.themes:
|
||||||
return Theme(name)
|
|
||||||
else:
|
|
||||||
return self.themes[name]
|
return self.themes[name]
|
||||||
|
else:
|
||||||
|
theme = self.find_user_theme(name)
|
||||||
|
if theme:
|
||||||
|
return theme
|
||||||
|
else:
|
||||||
|
return Theme(name)
|
||||||
|
|
||||||
|
def find_user_theme(self, name: str) -> Theme:
|
||||||
|
"""Find a theme named as *name* from latex_theme_path."""
|
||||||
|
for theme_path in self.theme_paths:
|
||||||
|
config_path = path.join(theme_path, name, 'theme.conf')
|
||||||
|
if path.isfile(config_path):
|
||||||
|
try:
|
||||||
|
return UserTheme(name, config_path)
|
||||||
|
except ThemeError as exc:
|
||||||
|
logger.warning(exc)
|
||||||
|
|
||||||
|
return None
|
||||||
|
2
tests/roots/test-latex-theme/conf.py
Normal file
2
tests/roots/test-latex-theme/conf.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
latex_theme = 'custom'
|
||||||
|
latex_theme_path = ['theme']
|
2
tests/roots/test-latex-theme/index.rst
Normal file
2
tests/roots/test-latex-theme/index.rst
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
latex_theme
|
||||||
|
===========
|
4
tests/roots/test-latex-theme/theme/custom/theme.conf
Normal file
4
tests/roots/test-latex-theme/theme/custom/theme.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[theme]
|
||||||
|
docclass = book
|
||||||
|
wrapperclass = sphinxbook
|
||||||
|
toplevel_sectioning = chapter
|
@ -20,7 +20,7 @@ from test_build_html import ENV_WARNINGS
|
|||||||
|
|
||||||
from sphinx.builders.latex import default_latex_documents
|
from sphinx.builders.latex import default_latex_documents
|
||||||
from sphinx.config import Config
|
from sphinx.config import Config
|
||||||
from sphinx.errors import SphinxError
|
from sphinx.errors import SphinxError, ThemeError
|
||||||
from sphinx.testing.util import strip_escseq
|
from sphinx.testing.util import strip_escseq
|
||||||
from sphinx.util import docutils
|
from sphinx.util import docutils
|
||||||
from sphinx.util.osutil import cd, ensuredir
|
from sphinx.util.osutil import cd, ensuredir
|
||||||
@ -215,6 +215,15 @@ def test_latex_basic_howto_ja(app, status, warning):
|
|||||||
assert r'\documentclass[letterpaper,10pt,dvipdfmx]{sphinxhowto}' in result
|
assert r'\documentclass[letterpaper,10pt,dvipdfmx]{sphinxhowto}' in result
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('latex', testroot='latex-theme')
|
||||||
|
def test_latex_theme(app, status, warning):
|
||||||
|
app.builder.build_all()
|
||||||
|
result = (app.outdir / 'python.tex').read_text(encoding='utf8')
|
||||||
|
print(result)
|
||||||
|
assert r'\def\sphinxdocclass{book}' in result
|
||||||
|
assert r'\documentclass[letterpaper,10pt,english]{sphinxbook}' in result
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx('latex', testroot='basic', confoverrides={'language': 'zh'})
|
@pytest.mark.sphinx('latex', testroot='basic', confoverrides={'language': 'zh'})
|
||||||
def test_latex_additional_settings_for_language_code(app, status, warning):
|
def test_latex_additional_settings_for_language_code(app, status, warning):
|
||||||
app.builder.build_all()
|
app.builder.build_all()
|
||||||
@ -1465,6 +1474,7 @@ def test_default_latex_documents():
|
|||||||
'author': "Wolfgang Schäuble & G'Beckstein."})
|
'author': "Wolfgang Schäuble & G'Beckstein."})
|
||||||
config.init_values()
|
config.init_values()
|
||||||
config.add('latex_engine', None, True, None)
|
config.add('latex_engine', None, True, None)
|
||||||
|
config.add('latex_theme', 'manual', True, None)
|
||||||
expected = [('index', 'stasi.tex', 'STASI™ Documentation',
|
expected = [('index', 'stasi.tex', 'STASI™ Documentation',
|
||||||
r"Wolfgang Schäuble \& G\textquotesingle{}Beckstein.\@{}", 'manual')]
|
r"Wolfgang Schäuble \& G\textquotesingle{}Beckstein.\@{}", 'manual')]
|
||||||
assert default_latex_documents(config) == expected
|
assert default_latex_documents(config) == expected
|
||||||
|
Loading…
Reference in New Issue
Block a user