diff --git a/doc/_themes/sphinx13b/static/sphinx13b.css b/doc/_themes/sphinx13b/static/sphinx13b.css index 9823f3b6..f658ea38 100644 --- a/doc/_themes/sphinx13b/static/sphinx13b.css +++ b/doc/_themes/sphinx13b/static/sphinx13b.css @@ -486,6 +486,12 @@ code.literal { color: #CE0000; } +h1 code.literal, +h2 code.literal, +h3 code.literal, +h4 code.literal, +h5 code.literal, +h6 code.literal, .sphinxsidebarwrapper code.literal { border: unset; padding: unset; diff --git a/doc/configuration.rst b/doc/configuration.rst index fe420519..6e968072 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -213,20 +213,27 @@ Generic configuration See also |confluence_publish_prefix|_. +.. |confluence_code_block_theme| replace:: ``confluence_code_block_theme`` +.. _confluence_code_block_theme: + .. confval:: confluence_code_block_theme .. versionadded:: 2.2 - Specifies the color scheme to use when displaying a Confluence code block macro. + .. note:: + + This option is only supported using the ``v1`` + :ref:`editor `. + + Specifies the color scheme to use when displaying a Confluence code + block macro. .. code-block:: python confluence_code_block_theme = 'Midnight' - .. note:: - - This option is only supported using the ``v1`` - :ref:`editor `. + For configuring the theme on individual code blocks, see + :ref:`class hints `. .. confval:: confluence_default_alignment diff --git a/doc/guide-class-hints.rst b/doc/guide-class-hints.rst new file mode 100644 index 00000000..3e1a559b --- /dev/null +++ b/doc/guide-class-hints.rst @@ -0,0 +1,31 @@ +.. index:: Class hints + +.. _confluence_class_hints: + +Class hints +=========== + +The following outlines all available class-related hints supported by the +Confluence builder extension. + +``confluence-theme-`` +---------------------------- + +.. versionadded:: 2.2 + +When this class hint is applied to a literal/code block, this provides the +ability to override the theme configured for an individual code-block macro. +For example: + +.. code-block:: none + + .. code-block:: python + :class: confluence-theme-FadeToGrey + + def main(): + print 'Hello, world!' + + if __name__ == '__main__': + main() + +See also :ref:`confluence_code_block_theme `. diff --git a/doc/guides.rst b/doc/guides.rst index c5448f8c..9f238b80 100644 --- a/doc/guides.rst +++ b/doc/guides.rst @@ -7,6 +7,7 @@ the Confluence Builder extension in a Sphinx-enabled environment. .. toctree:: :maxdepth: 1 + guide-class-hints guide-collapse guide-math guide-ci diff --git a/sphinxcontrib/confluencebuilder/config/notifications.py b/sphinxcontrib/confluencebuilder/config/notifications.py index adda5bf8..8d2f1f79 100644 --- a/sphinxcontrib/confluencebuilder/config/notifications.py +++ b/sphinxcontrib/confluencebuilder/config/notifications.py @@ -76,7 +76,7 @@ def warnings(validator): # confluence_code_block_theme assigned an unsupported theme if config.confluence_code_block_theme is not None: - theme = config.confluence_code_block_theme + theme = config.confluence_code_block_theme.lower() if theme not in SUPPORTED_CODE_BLOCK_THEMES: logger.warn('confluence_code_block_theme ' 'defines an unknown theme: ' + theme) diff --git a/sphinxcontrib/confluencebuilder/std/confluence.py b/sphinxcontrib/confluencebuilder/std/confluence.py index 30ee03b0..b4d698ad 100644 --- a/sphinxcontrib/confluencebuilder/std/confluence.py +++ b/sphinxcontrib/confluencebuilder/std/confluence.py @@ -478,23 +478,24 @@ # (see also: https://developer.atlassian.com/cloud/confluence/rate-limiting/) RSP_HEADER_RETRY_AFTER = 'Retry-After' +# default code block theme +DEFAULT_THEME_STYLE = 'default' + # supported code block themes # -# Ref: https://confluence.atlassian.com/doc/code-block-macro-139390.html -# -SUPPORTED_CODE_BLOCK_THEMES = [ - # Ordered to match Confluence documentation. - 'DJango', - 'Emacs', - 'FadeToGrey', - 'Midnight', - 'RDark', - 'Eclipse', - 'Confluence', +# (see also: https://confluence.atlassian.com/doc/code-block-macro-139390.html) +SUPPORTED_CODE_BLOCK_THEMES = { + 'confluence': 'Confluence', + 'django': 'DJango', + 'eclipse': 'Eclipse', + 'emacs': 'Emacs', + 'fadetogrey': 'FadeToGrey', + 'midnight': 'Midnight', + 'rdark': 'RDark', # 'Default' is also valid and is usually synonymous with 'Confluence', # unless changed by a user with Confluence Administrator permissions. - 'Default', -] + DEFAULT_THEME_STYLE: 'Default', +} # supported image types # diff --git a/sphinxcontrib/confluencebuilder/storage/translator.py b/sphinxcontrib/confluencebuilder/storage/translator.py index c446abdc..3eda6594 100644 --- a/sphinxcontrib/confluencebuilder/storage/translator.py +++ b/sphinxcontrib/confluencebuilder/storage/translator.py @@ -19,6 +19,7 @@ from sphinxcontrib.confluencebuilder.std.confluence import LITERAL2LANG_FBMAP_V2 from sphinxcontrib.confluencebuilder.std.confluence import LITERAL2LANG_MAP_V1 from sphinxcontrib.confluencebuilder.std.confluence import LITERAL2LANG_MAP_V2 +from sphinxcontrib.confluencebuilder.std.confluence import SUPPORTED_CODE_BLOCK_THEMES from sphinxcontrib.confluencebuilder.std.sphinx import DEFAULT_HIGHLIGHT_STYLE from sphinxcontrib.confluencebuilder.storage import encode_storage_format from sphinxcontrib.confluencebuilder.storage import intern_uri_anchor_value @@ -780,9 +781,21 @@ def visit_literal_block(self, node): self.body.append(self._build_ac_param(node, 'language', lang)) self.body.append(self._build_ac_param(node, 'linenumbers', num)) - if self.builder.config.confluence_code_block_theme: - theme = self.builder.config.confluence_code_block_theme - self.body.append(self._build_ac_param(node, 'theme', theme)) + theme = self.builder.config.confluence_code_block_theme + theme = theme.lower() if theme else None + theme_map = SUPPORTED_CODE_BLOCK_THEMES + + for class_ in node.get('classes', []): + if class_.startswith('confluence-theme-'): + theme = class_[len('confluence-theme-'):].lower() + if theme not in theme_map: + self.warn('confluence-theme-* defined an unknown theme: ' + + theme) + break + + theme_id = theme_map.get(theme) + if theme_id: + self.body.append(self._build_ac_param(node, 'theme', theme_id)) if firstline is not None and firstline > 1: self.body.append( diff --git a/tests/unit-tests/datasets/code-block-theme/index.rst b/tests/unit-tests/datasets/code-block-theme/index.rst new file mode 100644 index 00000000..07ff0562 --- /dev/null +++ b/tests/unit-tests/datasets/code-block-theme/index.rst @@ -0,0 +1,5 @@ +.. code-block:: python + :class: confluence-theme-eclipse + + import myexample + myexample.invoke() diff --git a/tests/unit-tests/test_sphinx_codeblock.py b/tests/unit-tests/test_sphinx_codeblock.py index da32bbf9..74e4e27c 100644 --- a/tests/unit-tests/test_sphinx_codeblock.py +++ b/tests/unit-tests/test_sphinx_codeblock.py @@ -28,22 +28,6 @@ def test_storage_sphinx_codeblock_caption(self): self.assertIsNotNone(title_param) self.assertEqual(title_param.text, 'code caption test') - @setup_builder('confluence') - def test_storage_sphinx_codeblock_theme(self): - theme = 'Midnight' - config = dict(self.config) - config['confluence_code_block_theme'] = theme - out_dir = self.build(self.dataset, filenames=['code-block'], config=config) - - with parse('code-block', out_dir) as data: - theme_params = data.find_all('ac:parameter', {'ac:name': 'theme'}) - self.assertIsNotNone(theme_params) - self.assertEqual(len(theme_params), 3) - - for theme_param in theme_params: - self.assertIsNotNone(theme_param) - self.assertEqual(theme_param.text, theme) - @setup_builder('confluence') def test_storage_sphinx_codeblock_default(self): out_dir = self.build(self.dataset, filenames=['code-block']) @@ -117,3 +101,30 @@ def test_storage_sphinx_codeblock_default(self): # (check at least one code block's content) self.assertEqual(ruby_block_cdata, "puts 'this is a print statement!'") + + @setup_builder('confluence') + def test_storage_sphinx_codeblock_theme_config(self): + theme = 'Midnight' + config = dict(self.config) + config['confluence_code_block_theme'] = theme + out_dir = self.build(self.dataset, filenames=['code-block'], config=config) + + with parse('code-block', out_dir) as data: + theme_params = data.find_all('ac:parameter', {'ac:name': 'theme'}) + self.assertIsNotNone(theme_params) + self.assertEqual(len(theme_params), 3) + + for theme_param in theme_params: + self.assertIsNotNone(theme_param) + self.assertEqual(theme_param.text, theme) + + @setup_builder('confluence') + def test_storage_sphinx_codeblock_theme_override(self): + expected_theme = 'Eclipse' + dataset = os.path.join(self.datasets, 'code-block-theme') + out_dir = self.build(dataset) + + with parse('index', out_dir) as data: + code_macro_theme = data.find('ac:parameter', {'ac:name': 'theme'}) + self.assertIsNotNone(code_macro_theme) + self.assertEqual(code_macro_theme.text, expected_theme)