Close #207: Now highlight_language supports multiple languages

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.
This commit is contained in:
Takeshi KOMIYA 2021-01-11 00:02:38 +09:00
parent 98993b40c5
commit 32ac5f2e57
9 changed files with 88 additions and 19 deletions

View File

@ -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
----------

View File

@ -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

View File

@ -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'),
@ -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)

View File

@ -439,11 +439,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
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

View File

@ -390,11 +390,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
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

View File

@ -1751,11 +1751,7 @@ class LaTeXTranslator(SphinxTranslator):
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,

View File

@ -0,0 +1,4 @@
highlight_options = {
'default': {'default_option': True},
'python': {'python_option': True}
}

View File

@ -0,0 +1,14 @@
test-highlight_options
======================
.. code-block::
blah blah blah
.. code-block:: python
blah blah blah
.. code-block:: java
blah blah blah

View File

@ -12,6 +12,7 @@ import os
import re
from distutils.version import LooseVersion
from itertools import chain, cycle
from unittest.mock import ANY, call, patch
import pygments
import pytest
@ -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={})