From eef2114053d2533b5bd9113dca97003130994cec Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 22 May 2022 23:13:16 +0900 Subject: [PATCH 1/2] Close #10444: html theme: Allow to specify multiple CSS files via "stylesheet" setting --- CHANGES | 3 +++ doc/development/theming.rst | 11 +++++++---- sphinx/builders/html/__init__.py | 13 ++++++++++++- .../_themes/mytheme/_static/extra.css | 0 .../_themes/mytheme/_static/mytheme.css | 0 .../_themes/mytheme/theme.conf | 3 +++ .../conf.py | 2 ++ .../index.rst | 2 ++ tests/test_build_html.py | 9 +++++++++ 9 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 tests/roots/test-build-html-theme-having-multiple-stylesheets/_themes/mytheme/_static/extra.css create mode 100644 tests/roots/test-build-html-theme-having-multiple-stylesheets/_themes/mytheme/_static/mytheme.css create mode 100644 tests/roots/test-build-html-theme-having-multiple-stylesheets/_themes/mytheme/theme.conf create mode 100644 tests/roots/test-build-html-theme-having-multiple-stylesheets/conf.py create mode 100644 tests/roots/test-build-html-theme-having-multiple-stylesheets/index.rst diff --git a/CHANGES b/CHANGES index ff6b56c89be..7d798a331ae 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,9 @@ Deprecated Features added -------------- +* #10444: html theme: Allow to specify multiple CSS files via ``stylesheet`` + setting on ``theme.conf`` + Bugs fixed ---------- diff --git a/doc/development/theming.rst b/doc/development/theming.rst index fcbeb030a61..b46ba0362e6 100644 --- a/doc/development/theming.rst +++ b/doc/development/theming.rst @@ -56,10 +56,10 @@ Python :mod:`ConfigParser` module) and has the following structure: want to also inherit the stylesheet, include it via CSS' ``@import`` in your own. -* The **stylesheet** setting gives the name of a CSS file which will be - referenced in the HTML header. If you need more than one CSS file, either - include one from the other via CSS' ``@import``, or use a custom HTML template - that adds ```` tags as necessary. Setting the +* The **stylesheet** setting gives a list of CSS filenames separated commas which + will be referenced in the HTML header. You can also use CSS' ``@import`` + technique to include one from the other, or use a custom HTML template that + adds ```` tags as necessary. Setting the :confval:`html_style` config value will override this setting. * The **pygments_style** setting gives the name of a Pygments style to use for @@ -82,6 +82,9 @@ Python :mod:`ConfigParser` module) and has the following structure: .. versionadded:: 1.7 sidebar settings +.. versionchanged:: 5.1 + + The stylesheet setting accepts multiple CSS filenames .. _distribute-your-theme: diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py index b320b0df588..05efcbcea57 100644 --- a/sphinx/builders/html/__init__.py +++ b/sphinx/builders/html/__init__.py @@ -272,6 +272,15 @@ def _get_style_filename(self) -> str: else: return 'default.css' + def get_style_filenames(self) -> str: + if self.config.html_style is not None: + return [self.config.html_style] + elif self.theme: + stylesheet = self.theme.get_config('theme', 'stylesheet') + return [s.strip() for s in stylesheet.split(',')] + else: + return ['default.css'] + def get_theme_config(self) -> Tuple[str, Dict]: return self.config.html_theme, self.config.html_theme_options @@ -309,7 +318,9 @@ def init_highlighter(self) -> None: def init_css_files(self) -> None: self.css_files = [] self.add_css_file('pygments.css', priority=200) - self.add_css_file(self._get_style_filename(), priority=200) + + for filename in self.get_style_filenames(): + self.add_css_file(filename, priority=200) for filename, attrs in self.app.registry.css_files: self.add_css_file(filename, **attrs) diff --git a/tests/roots/test-build-html-theme-having-multiple-stylesheets/_themes/mytheme/_static/extra.css b/tests/roots/test-build-html-theme-having-multiple-stylesheets/_themes/mytheme/_static/extra.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/roots/test-build-html-theme-having-multiple-stylesheets/_themes/mytheme/_static/mytheme.css b/tests/roots/test-build-html-theme-having-multiple-stylesheets/_themes/mytheme/_static/mytheme.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/roots/test-build-html-theme-having-multiple-stylesheets/_themes/mytheme/theme.conf b/tests/roots/test-build-html-theme-having-multiple-stylesheets/_themes/mytheme/theme.conf new file mode 100644 index 00000000000..c87296e7eb8 --- /dev/null +++ b/tests/roots/test-build-html-theme-having-multiple-stylesheets/_themes/mytheme/theme.conf @@ -0,0 +1,3 @@ +[theme] +inherit = basic +stylesheet = mytheme.css, extra.css diff --git a/tests/roots/test-build-html-theme-having-multiple-stylesheets/conf.py b/tests/roots/test-build-html-theme-having-multiple-stylesheets/conf.py new file mode 100644 index 00000000000..3cb43d6110e --- /dev/null +++ b/tests/roots/test-build-html-theme-having-multiple-stylesheets/conf.py @@ -0,0 +1,2 @@ +html_theme_path = ['_themes'] +html_theme = 'mytheme' diff --git a/tests/roots/test-build-html-theme-having-multiple-stylesheets/index.rst b/tests/roots/test-build-html-theme-having-multiple-stylesheets/index.rst new file mode 100644 index 00000000000..b8b81f9d3f9 --- /dev/null +++ b/tests/roots/test-build-html-theme-having-multiple-stylesheets/index.rst @@ -0,0 +1,2 @@ +test-build-html-theme-having-multiple-stylesheets +================================================= diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 75f89a67a0f..217e66394be 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -1735,3 +1735,12 @@ def test_html_code_role(app): assert ('
' + '
' +
             common_content) in content
+
+
+@pytest.mark.sphinx('html', testroot='build-html-theme-having-multiple-stylesheets')
+def test_theme_having_multiple_stylesheets(app):
+    app.build()
+    content = (app.outdir / 'index.html').read_text(encoding='utf-8')
+
+    assert '' in content
+    assert '' in content

From 6c6d967018b15f505c3fac32dc5f9521f86488aa Mon Sep 17 00:00:00 2001
From: Adam Turner <9087854+aa-turner@users.noreply.github.com>
Date: Sun, 17 Jul 2022 12:09:18 +0100
Subject: [PATCH 2/2] Update implementation, documentation

---
 CHANGES                          |  4 ++--
 doc/templating.rst               | 18 ++++++++++++++++++
 sphinx/builders/html/__init__.py | 28 ++++++++++++----------------
 3 files changed, 32 insertions(+), 18 deletions(-)

diff --git a/CHANGES b/CHANGES
index 7d798a331ae..efa08246c10 100644
--- a/CHANGES
+++ b/CHANGES
@@ -13,8 +13,8 @@ Deprecated
 Features added
 --------------
 
-* #10444: html theme: Allow to specify multiple CSS files via ``stylesheet``
-  setting on ``theme.conf``
+* #10444: html theme: Allow specifying multiple CSS files through the ``stylesheet``
+  setting in ``theme.conf`` or by setting ``html_style`` to an iterable of strings.
 
 Bugs fixed
 ----------
diff --git a/doc/templating.rst b/doc/templating.rst
index 3d80edd6009..5f570f67731 100644
--- a/doc/templating.rst
+++ b/doc/templating.rst
@@ -383,11 +383,29 @@ in the future.
 
    .. versionadded:: 4.2
 
+.. data:: styles
+
+   A list of the names of the main stylesheets as given by the theme or
+   :confval:`html_style`.
+
+   .. versionadded:: 5.1
+
 .. data:: style
 
    The name of the main stylesheet, as given by the theme or
    :confval:`html_style`.
 
+   .. versionchanged:: 5.1
+
+      The theme or :confval:`html_style` are now able to specify multiple
+      stylesheets, the ``style`` key returns the last stylesheet when more than
+      one is specified.
+
+   .. deprecated:: 5.1
+
+      Use the :data:`styles` key instead, as there is no longer a single main
+      stylesheet. The ``style`` key will be removed in Sphinx 7.0.
+
 .. data:: title
 
    The title of the current document, as used in the ```` tag.
diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py
index 05efcbcea57..cd796ef3856 100644
--- a/sphinx/builders/html/__init__.py
+++ b/sphinx/builders/html/__init__.py
@@ -264,22 +264,16 @@ def _get_translations_js(self) -> str:
                 return jsfile
         return None
 
-    def _get_style_filename(self) -> str:
-        if self.config.html_style is not None:
-            return self.config.html_style
-        elif self.theme:
-            return self.theme.get_config('theme', 'stylesheet')
-        else:
-            return 'default.css'
-
-    def get_style_filenames(self) -> str:
-        if self.config.html_style is not None:
-            return [self.config.html_style]
+    def _get_style_filenames(self) -> Iterator[str]:
+        if isinstance(self.config.html_style, str):
+            yield self.config.html_style
+        elif self.config.html_style is not None:
+            yield from self.config.html_style
         elif self.theme:
             stylesheet = self.theme.get_config('theme', 'stylesheet')
-            return [s.strip() for s in stylesheet.split(',')]
+            yield from map(str.strip, stylesheet.split(','))
         else:
-            return ['default.css']
+            yield 'default.css'
 
     def get_theme_config(self) -> Tuple[str, Dict]:
         return self.config.html_theme, self.config.html_theme_options
@@ -319,7 +313,7 @@ def init_css_files(self) -> None:
         self.css_files = []
         self.add_css_file('pygments.css', priority=200)
 
-        for filename in self.get_style_filenames():
+        for filename in self._get_style_filenames():
             self.add_css_file(filename, priority=200)
 
         for filename, attrs in self.app.registry.css_files:
@@ -521,6 +515,7 @@ def prepare_writing(self, docnames: Set[str]) -> None:
         # back up script_files and css_files to allow adding JS/CSS files to a specific page.
         self._script_files = list(self.script_files)
         self._css_files = list(self.css_files)
+        styles = list(self._get_style_filenames())
 
         self.globalcontext = {
             'embedded': self.embedded,
@@ -547,7 +542,8 @@ def prepare_writing(self, docnames: Set[str]) -> None:
             'css_files': self.css_files,
             'sphinx_version': __display_version__,
             'sphinx_version_tuple': sphinx_version,
-            'style': self._get_style_filename(),
+            'styles': styles,
+            'style': styles[-1],  # xref RemovedInSphinx70Warning
             'rellinks': rellinks,
             'builder': self.name,
             'parents': [],
@@ -1351,7 +1347,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
                          lambda self: _('%s %s documentation') % (self.project, self.release),
                          'html', [str])
     app.add_config_value('html_short_title', lambda self: self.html_title, 'html')
-    app.add_config_value('html_style', None, 'html', [str])
+    app.add_config_value('html_style', None, 'html', [list, str])
     app.add_config_value('html_logo', None, 'html', [str])
     app.add_config_value('html_favicon', None, 'html', [str])
     app.add_config_value('html_css_files', [], 'html')