Skip to content

Commit

Permalink
Close sphinx-doc#2155: Support code directive
Browse files Browse the repository at this point in the history
  • Loading branch information
tk0miya committed Mar 3, 2019
1 parent bfbb3bb commit d4d60ef
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Bugs fixed
* #5508: ``linenothreshold`` option for ``highlight`` directive was ignored
* texinfo: ``make install-info`` causes syntax error
* texinfo: ``make install-info`` fails on macOS
* #2155: Support ``code`` directive

Testing
--------
Expand Down
37 changes: 25 additions & 12 deletions sphinx/directives/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,6 @@
from sphinx.util.docfields import DocFieldTransformer
from sphinx.util.docutils import SphinxDirective

# import all directives sphinx provides
from sphinx.directives.code import ( # noqa
Highlight, CodeBlock, LiteralInclude
)
from sphinx.directives.other import ( # noqa
TocTree, Author, Index, VersionChange, SeeAlso,
TabularColumns, Centered, Acks, HList, Only, Include, Class
)
from sphinx.directives.patches import ( # noqa
Figure, Meta
)

if False:
# For type annotation
from typing import Any, Dict # NOQA
Expand All @@ -46,6 +34,19 @@
strip_backslash_re = re.compile(r'\\(.)')


def optional_int(argument):
"""
Check for an integer argument or None value; raise ``ValueError`` if not.
"""
if argument is None:
return None
else:
value = int(argument)
if value < 0:
raise ValueError('negative value; must be positive or zero')
return value


class ObjectDescription(SphinxDirective):
"""
Directive to describe a class, function or similar object. Not used
Expand Down Expand Up @@ -243,6 +244,18 @@ def run(self):
self.env.temp_data['default_domain'] = self.env.domains.get(domain_name)
return []

# import all directives sphinx provides (for compatibility)
from sphinx.directives.code import ( # noqa
Highlight, CodeBlock, LiteralInclude
)
from sphinx.directives.other import ( # noqa
TocTree, Author, Index, VersionChange, SeeAlso,
TabularColumns, Centered, Acks, HList, Only, Include, Class
)
from sphinx.directives.patches import ( # noqa
Figure, Meta
)


def setup(app):
# type: (Sphinx) -> Dict[str, Any]
Expand Down
46 changes: 46 additions & 0 deletions sphinx/directives/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from sphinx import addnodes
from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.directives import optional_int
from sphinx.locale import __
from sphinx.util import logging
from sphinx.util import parselinenos
Expand Down Expand Up @@ -392,6 +393,50 @@ def dedent_filter(self, lines, location=None):
return lines


class Code(SphinxDirective):
"""Parse and mark up content of a code block.
"""
optional_arguments = 1
option_spec = {
'class': directives.class_option,
'name': directives.unchanged,
'number-lines': optional_int,
}
has_content = True

def run(self):
# type: () -> List[nodes.Node]
self.assert_has_content()

code = '\n'.join(self.content)
node = nodes.literal_block(code, code,
classes=self.options.get('classes', []),
highlight_args={})
self.add_name(node)
set_source_info(self, node)

if self.arguments:
# highlight language specified
node['language'] = self.arguments[0]
node['force_highlighting'] = True
else:
# no highlight language specified. Then this directive refers the current
# highlight setting via ``highlight`` directive or ``highlight_language``
# configuration.
node['language'] = self.env.temp_data.get('highlight_language',
self.config.highlight_language)
node['force_highlighting'] = False

if 'number-lines' in self.options:
node['linenos'] = True

# if number given, treat as lineno-start.
if self.options['number-lines']:
node['highlight_args']['linenostart'] = self.options['number-lines']

return [node]


class LiteralInclude(SphinxDirective):
"""
Like ``.. include:: :literal:``, but only warns if the include file is
Expand Down Expand Up @@ -482,6 +527,7 @@ def setup(app):
# type: (Sphinx) -> Dict[str, Any]
directives.register_directive('highlight', Highlight)
directives.register_directive('highlightlang', HighlightLang)
directives.register_directive('code', Code)
directives.register_directive('code-block', CodeBlock)
directives.register_directive('sourcecode', CodeBlock)
directives.register_directive('literalinclude', LiteralInclude)
Expand Down
43 changes: 42 additions & 1 deletion tests/test_directive_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@

from sphinx.config import Config
from sphinx.directives.code import LiteralIncludeReader
from sphinx.testing.util import etree_parse
from sphinx.testing import restructuredtext
from sphinx.testing.util import assert_node, etree_parse

DUMMY_CONFIG = Config({}, {})

Expand Down Expand Up @@ -614,3 +615,43 @@ def test_linenothreshold(app, status, warning):
'2\n'
'3' + lineos_tail)
assert not matched


def test_code_directive(app):
# normal case
text = ('.. code::\n'
'\n'
' print("hello world")\n')

doctree = restructuredtext.parse(app, text)
assert_node(doctree, [nodes.document, nodes.literal_block, 'print("hello world")'])
assert_node(doctree[0], language="default", highlight_args={})

# with language
text = ('.. code:: python\n'
'\n'
' print("hello world")\n')

doctree = restructuredtext.parse(app, text)
assert_node(doctree, [nodes.document, nodes.literal_block, 'print("hello world")'])
assert_node(doctree[0], language="python", highlight_args={})

# :number-lines: option
text = ('.. code:: python\n'
' :number-lines:\n'
'\n'
' print("hello world")\n')

doctree = restructuredtext.parse(app, text)
assert_node(doctree, [nodes.document, nodes.literal_block, 'print("hello world")'])
assert_node(doctree[0], language="python", linenos=True, highlight_args={})

# :number-lines: option
text = ('.. code:: python\n'
' :number-lines: 5\n'
'\n'
' print("hello world")\n')

doctree = restructuredtext.parse(app, text)
assert_node(doctree, [nodes.document, nodes.literal_block, 'print("hello world")'])
assert_node(doctree[0], language="python", linenos=True, highlight_args={'linenostart': 5})

0 comments on commit d4d60ef

Please sign in to comment.