Skip to content

Commit

Permalink
Close #207: Now highlight_language supports multiple languages
Browse files Browse the repository at this point in the history
This changes the structure of `highlight_options` to a dictionary that
maps language names to option dictionary.  It allows to setting pygments
options for multiple languages at once.
  • Loading branch information
tk0miya committed Jan 11, 2021
1 parent 98993b4 commit 32ac5f2
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Features added
type
* #6241: mathjax: Include mathjax.js only on the document using equations
* #8132: Add :confval:`project_copyright` as an alias of :confval:`copyright`
* #207: Now :confval:`highlight_language` supports multiple languages

Bugs fixed
----------
Expand Down
23 changes: 19 additions & 4 deletions doc/usage/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -582,12 +582,27 @@ General configuration

.. confval:: highlight_options

A dictionary of options that modify how the lexer specified by
:confval:`highlight_language` generates highlighted source code. These are
lexer-specific; for the options understood by each, see the
`Pygments documentation <https://pygments.org/docs/lexers>`_.
A dictionary that maps language names to options for the lexer modules of
Pygments. These are lexer-specific; for the options understood by each,
see the `Pygments documentation <https://pygments.org/docs/lexers>`_.

Example::

highlight_options = {
'default': {'stripall': True},
'php': {'startinline': True},
}

A single dictionary of options are also allowed. Then it is recognized
as options to the lexer specified by :confval:`highlight_language`::

# configuration for the ``highlight_language``
highlight_options = {'stripall': True}

.. versionadded:: 1.3
.. versionchanged:: 3.5

Allow to configure highlight options for multiple languages

.. confval:: pygments_style

Expand Down
13 changes: 13 additions & 0 deletions sphinx/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,18 @@ def convert_source_suffix(app: "Sphinx", config: Config) -> None:
"But `%r' is given." % source_suffix))


def convert_highlight_options(app: "Sphinx", config: Config) -> None:
"""Convert old styled highlight_options to new styled one.
* old style: options
* new style: dict that maps language names to options
"""
options = config.highlight_options
if options and not all(isinstance(v, dict) for v in options.values()):
# old styled option detected because all values are not dictionary.
config.highlight_options = {config.highlight_language: options} # type: ignore


def init_numfig_format(app: "Sphinx", config: Config) -> None:
"""Initialize :confval:`numfig_format`."""
numfig_format = {'section': _('Section %s'),
Expand Down Expand Up @@ -487,6 +499,7 @@ def check_master_doc(app: "Sphinx", env: "BuildEnvironment", added: Set[str],

def setup(app: "Sphinx") -> Dict[str, Any]:
app.connect('config-inited', convert_source_suffix, priority=800)
app.connect('config-inited', convert_highlight_options, priority=800)
app.connect('config-inited', init_numfig_format, priority=800)
app.connect('config-inited', correct_copyright_year, priority=800)
app.connect('config-inited', check_confval_types, priority=800)
Expand Down
6 changes: 1 addition & 5 deletions sphinx/writers/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,11 +439,7 @@ def visit_literal_block(self, node: Element) -> None:
linenos = node.get('linenos', False)
highlight_args = node.get('highlight_args', {})
highlight_args['force'] = node.get('force', False)
if lang == self.config.highlight_language:
# only pass highlighter options for original language
opts = self.config.highlight_options
else:
opts = {}
opts = self.config.highlight_options.get(lang, {})

if linenos and self.config.html_codeblock_linenos_style:
linenos = self.config.html_codeblock_linenos_style
Expand Down
6 changes: 1 addition & 5 deletions sphinx/writers/html5.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,11 +390,7 @@ def visit_literal_block(self, node: Element) -> None:
linenos = node.get('linenos', False)
highlight_args = node.get('highlight_args', {})
highlight_args['force'] = node.get('force', False)
if lang == self.config.highlight_language:
# only pass highlighter options for original language
opts = self.config.highlight_options
else:
opts = {}
opts = self.config.highlight_options.get(lang, {})

if linenos and self.config.html_codeblock_linenos_style:
linenos = self.config.html_codeblock_linenos_style
Expand Down
6 changes: 1 addition & 5 deletions sphinx/writers/latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -1751,11 +1751,7 @@ def visit_literal_block(self, node: Element) -> None:
linenos = node.get('linenos', False)
highlight_args = node.get('highlight_args', {})
highlight_args['force'] = node.get('force', False)
if lang == self.config.highlight_language:
# only pass highlighter options for original language
opts = self.config.highlight_options
else:
opts = {}
opts = self.config.highlight_options.get(lang, {})

hlcode = self.highlighter.highlight_block(
node.rawsource, lang, opts=opts, linenos=linenos,
Expand Down
4 changes: 4 additions & 0 deletions tests/roots/test-highlight_options/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
highlight_options = {
'default': {'default_option': True},
'python': {'python_option': True}
}
14 changes: 14 additions & 0 deletions tests/roots/test-highlight_options/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
test-highlight_options
======================

.. code-block::
blah blah blah
.. code-block:: python
blah blah blah
.. code-block:: java
blah blah blah
34 changes: 34 additions & 0 deletions tests/test_build_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import re
from distutils.version import LooseVersion
from itertools import chain, cycle
from unittest.mock import ANY, call, patch

import pygments
import pytest
Expand Down Expand Up @@ -1631,3 +1632,36 @@ def test_html_codeblock_linenos_style_inline(app):
assert '<span class="linenos">1</span>' in content
else:
assert '<span class="lineno">1 </span>' in content


@pytest.mark.sphinx('html', testroot='highlight_options')
def test_highlight_options(app):
subject = app.builder.highlighter
with patch.object(subject, 'highlight_block', wraps=subject.highlight_block) as highlight:
app.build()

call_args = highlight.call_args_list
assert len(call_args) == 3
assert call_args[0] == call(ANY, 'default', force=False, linenos=False,
location=ANY, opts={'default_option': True})
assert call_args[1] == call(ANY, 'python', force=False, linenos=False,
location=ANY, opts={'python_option': True})
assert call_args[2] == call(ANY, 'java', force=False, linenos=False,
location=ANY, opts={})


@pytest.mark.sphinx('html', testroot='highlight_options',
confoverrides={'highlight_options': {'default_option': True}})
def test_highlight_options_old(app):
subject = app.builder.highlighter
with patch.object(subject, 'highlight_block', wraps=subject.highlight_block) as highlight:
app.build()

call_args = highlight.call_args_list
assert len(call_args) == 3
assert call_args[0] == call(ANY, 'default', force=False, linenos=False,
location=ANY, opts={'default_option': True})
assert call_args[1] == call(ANY, 'python', force=False, linenos=False,
location=ANY, opts={})
assert call_args[2] == call(ANY, 'java', force=False, linenos=False,
location=ANY, opts={})

0 comments on commit 32ac5f2

Please sign in to comment.