mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
* for pull request #258: update CHANGES, add tests, add a document and refactoring.
This commit is contained in:
parent
4f357d9edd
commit
d39327d539
2
CHANGES
2
CHANGES
@ -184,6 +184,8 @@ Bugs fixed
|
|||||||
qualified name. It should be rather easy to change this behaviour and
|
qualified name. It should be rather easy to change this behaviour and
|
||||||
potentially index by namespaces/classes as well.
|
potentially index by namespaces/classes as well.
|
||||||
|
|
||||||
|
* PR#258: Add dedent option for :rst:dir:`code-block` and
|
||||||
|
:rst:dir:`literal-include`. Thanks to Zafar Siddiqui.
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
@ -208,6 +208,22 @@ additional feature that if you leave the value empty, the shown filename will be
|
|||||||
exactly the one given as an argument.
|
exactly the one given as an argument.
|
||||||
|
|
||||||
|
|
||||||
|
Dedent
|
||||||
|
^^^^^^
|
||||||
|
|
||||||
|
.. versionadded:: 1.3
|
||||||
|
|
||||||
|
A ``dedent`` option can be given to strip a precedence characters from the code
|
||||||
|
block. For example::
|
||||||
|
|
||||||
|
.. literalinclude:: example.rb
|
||||||
|
:language: ruby
|
||||||
|
:dedent: 4
|
||||||
|
:lines: 10-15
|
||||||
|
|
||||||
|
:rst:dir:`code-block` also supports the ``dedent`` option.
|
||||||
|
|
||||||
|
|
||||||
.. rubric:: Footnotes
|
.. rubric:: Footnotes
|
||||||
|
|
||||||
.. [1] There is a standard ``.. include`` directive, but it raises errors if the
|
.. [1] There is a standard ``.. include`` directive, but it raises errors if the
|
||||||
|
@ -44,6 +44,21 @@ class Highlight(Directive):
|
|||||||
linenothreshold=linenothreshold)]
|
linenothreshold=linenothreshold)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def dedent_lines(lines, dedent):
|
||||||
|
if not dedent:
|
||||||
|
return lines
|
||||||
|
|
||||||
|
new_lines = []
|
||||||
|
for line in lines:
|
||||||
|
new_line = line[dedent:]
|
||||||
|
if line.endswith('\n') and not new_line:
|
||||||
|
new_line = '\n' # keep CRLF
|
||||||
|
new_lines.append(new_line)
|
||||||
|
|
||||||
|
return new_lines
|
||||||
|
|
||||||
|
|
||||||
class CodeBlock(Directive):
|
class CodeBlock(Directive):
|
||||||
"""
|
"""
|
||||||
Directive for a code block with special highlighting or line numbering
|
Directive for a code block with special highlighting or line numbering
|
||||||
@ -77,13 +92,9 @@ class CodeBlock(Directive):
|
|||||||
hl_lines = None
|
hl_lines = None
|
||||||
|
|
||||||
if 'dedent' in self.options:
|
if 'dedent' in self.options:
|
||||||
linesArray = code.split('\n')
|
lines = code.split('\n')
|
||||||
for i in range(0, len(linesArray)):
|
lines = dedent_lines(lines, self.options['dedent'])
|
||||||
if len(linesArray[i]) <= self.options['dedent']:
|
code = '\n'.join(lines)
|
||||||
linesArray[i] = linesArray[i][len(linesArray[i]) - 1:]
|
|
||||||
else:
|
|
||||||
linesArray[i] = linesArray[i][self.options['dedent']:]
|
|
||||||
code = '\n'.join(linesArray)
|
|
||||||
|
|
||||||
literal = nodes.literal_block(code, code)
|
literal = nodes.literal_block(code, code)
|
||||||
literal['language'] = self.arguments[0]
|
literal['language'] = self.arguments[0]
|
||||||
@ -113,7 +124,7 @@ class LiteralInclude(Directive):
|
|||||||
optional_arguments = 0
|
optional_arguments = 0
|
||||||
final_argument_whitespace = True
|
final_argument_whitespace = True
|
||||||
option_spec = {
|
option_spec = {
|
||||||
'dedent': int,
|
'dedent': int,
|
||||||
'linenos': directives.flag,
|
'linenos': directives.flag,
|
||||||
'lineno-start': int,
|
'lineno-start': int,
|
||||||
'tab-width': int,
|
'tab-width': int,
|
||||||
@ -149,12 +160,7 @@ class LiteralInclude(Directive):
|
|||||||
f = codecs.StreamReaderWriter(open(filename, 'rb'),
|
f = codecs.StreamReaderWriter(open(filename, 'rb'),
|
||||||
codec_info[2], codec_info[3], 'strict')
|
codec_info[2], codec_info[3], 'strict')
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
if 'dedent' in self.options:
|
lines = dedent_lines(lines, self.options.get('dedent'))
|
||||||
for i in range(0, len(lines)):
|
|
||||||
if len(lines[i]) <= self.options['dedent']:
|
|
||||||
lines[i] = lines[i][len(lines[i]) - 1:]
|
|
||||||
else:
|
|
||||||
lines[i] = lines[i][self.options['dedent']:]
|
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
return [document.reporter.warning(
|
return [document.reporter.warning(
|
||||||
'Include file %r not found or reading it failed' % filename,
|
'Include file %r not found or reading it failed' % filename,
|
||||||
|
3
tests/roots/test-directive-code/conf.py
Normal file
3
tests/roots/test-directive-code/conf.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
master_doc = 'index'
|
22
tests/roots/test-directive-code/dedent.rst
Normal file
22
tests/roots/test-directive-code/dedent.rst
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
Dedent
|
||||||
|
======
|
||||||
|
|
||||||
|
Code blocks
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. code-block:: ruby
|
||||||
|
:linenos:
|
||||||
|
:dedent: 4
|
||||||
|
|
||||||
|
def ruby?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
Literal Include
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. literalinclude:: literal.inc
|
||||||
|
:language: python
|
||||||
|
:lines: 10-11
|
||||||
|
:dedent: 4
|
24
tests/roots/test-directive-code/index.rst
Normal file
24
tests/roots/test-directive-code/index.rst
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
test-directive-code
|
||||||
|
===================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
|
||||||
|
Code blocks
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. code-block:: ruby
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
def ruby?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
Literal Includes
|
||||||
|
----------------
|
||||||
|
|
||||||
|
.. literalinclude:: literal.inc
|
||||||
|
:language: python
|
13
tests/roots/test-directive-code/literal.inc
Normal file
13
tests/roots/test-directive-code/literal.inc
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Literally included file using Python highlighting
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
foo = "Including Unicode characters: üöä"
|
||||||
|
|
||||||
|
class Foo:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Bar:
|
||||||
|
def baz():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def bar(): pass
|
131
tests/test_directive_code.py
Normal file
131
tests/test_directive_code.py
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
test_directive_code
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Test the code-block directive.
|
||||||
|
|
||||||
|
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
|
from util import with_app, test_roots
|
||||||
|
|
||||||
|
|
||||||
|
def teardown_module():
|
||||||
|
(test_roots / 'test-directive-code' / '_build').rmtree(True)
|
||||||
|
|
||||||
|
|
||||||
|
@with_app(buildername='xml',
|
||||||
|
srcdir=(test_roots / 'test-directive-code'),
|
||||||
|
_copy_to_temp=True)
|
||||||
|
def test_code_block(app):
|
||||||
|
app.builder.build('index')
|
||||||
|
et = ElementTree.parse(app.outdir / 'index.xml')
|
||||||
|
secs = et.findall('/section/section')
|
||||||
|
code_block = secs[0].findall('literal_block')
|
||||||
|
assert len(code_block) > 0
|
||||||
|
actual = code_block[0].text
|
||||||
|
expect = (
|
||||||
|
" def ruby?\n" +
|
||||||
|
" false\n" +
|
||||||
|
" end"
|
||||||
|
)
|
||||||
|
assert actual == expect
|
||||||
|
|
||||||
|
|
||||||
|
@with_app(buildername='xml',
|
||||||
|
srcdir=(test_roots / 'test-directive-code'),
|
||||||
|
_copy_to_temp=True)
|
||||||
|
def test_code_block_dedent(app):
|
||||||
|
outdir = app.outdir
|
||||||
|
|
||||||
|
def get_dedent_actual(dedent):
|
||||||
|
dedent_text = (app.srcdir / 'dedent.rst').text(encoding='utf-8')
|
||||||
|
dedent_text = re.sub(
|
||||||
|
r':dedent: \d', ':dedent: %d' % dedent, dedent_text)
|
||||||
|
(app.srcdir / 'dedent.rst').write_text(dedent_text, encoding='utf-8')
|
||||||
|
|
||||||
|
# use another output dir to force rebuild
|
||||||
|
app.outdir = outdir / str(dedent)
|
||||||
|
app._init_env(freshenv=True)
|
||||||
|
app._init_builder(app.builder.name)
|
||||||
|
app.builder.build(['dedent'], method='specific')
|
||||||
|
|
||||||
|
et = ElementTree.parse(app.outdir / 'dedent.xml')
|
||||||
|
secs = et.findall('/section/section')
|
||||||
|
code_block = secs[0].findall('literal_block')
|
||||||
|
|
||||||
|
assert len(code_block) > 0
|
||||||
|
actual = code_block[0].text
|
||||||
|
return actual
|
||||||
|
|
||||||
|
for i in range(5): # 0-4
|
||||||
|
actual = get_dedent_actual(i)
|
||||||
|
indent = " " * (4 - i)
|
||||||
|
expect = (
|
||||||
|
indent + "def ruby?\n" +
|
||||||
|
indent + " false\n" +
|
||||||
|
indent + "end"
|
||||||
|
)
|
||||||
|
assert (i, actual) == (i, expect)
|
||||||
|
|
||||||
|
actual = get_dedent_actual(1000)
|
||||||
|
assert actual == '\n\n'
|
||||||
|
|
||||||
|
|
||||||
|
@with_app(buildername='xml',
|
||||||
|
srcdir=(test_roots / 'test-directive-code'),
|
||||||
|
_copy_to_temp=True)
|
||||||
|
def test_literal_include(app):
|
||||||
|
app.builder.build('index')
|
||||||
|
et = ElementTree.parse(app.outdir / 'index.xml')
|
||||||
|
secs = et.findall('/section/section')
|
||||||
|
literal_include = secs[1].findall('literal_block')
|
||||||
|
literal_src = (app.srcdir / 'literal.inc').text(encoding='utf-8')
|
||||||
|
assert len(literal_include) > 0
|
||||||
|
actual = literal_include[0].text
|
||||||
|
assert actual == literal_src
|
||||||
|
|
||||||
|
|
||||||
|
@with_app(buildername='xml',
|
||||||
|
srcdir=(test_roots / 'test-directive-code'),
|
||||||
|
_copy_to_temp=True)
|
||||||
|
def test_literal_include_dedent(app):
|
||||||
|
outdir = app.outdir
|
||||||
|
literal_src = (app.srcdir / 'literal.inc').text(encoding='utf-8')
|
||||||
|
literal_lines = [l[4:] for l in literal_src.split('\n')[9:11]]
|
||||||
|
|
||||||
|
def get_dedent_actual(dedent):
|
||||||
|
dedent_text = (app.srcdir / 'dedent.rst').text(encoding='utf-8')
|
||||||
|
dedent_text = re.sub(
|
||||||
|
r':dedent: \d', ':dedent: %d' % dedent, dedent_text)
|
||||||
|
(app.srcdir / 'dedent.rst').write_text(dedent_text, encoding='utf-8')
|
||||||
|
|
||||||
|
# use another output dir to force rebuild
|
||||||
|
app.outdir = outdir / str(dedent)
|
||||||
|
app._init_env(freshenv=True)
|
||||||
|
app._init_builder(app.builder.name)
|
||||||
|
app.builder.build(['dedent'])
|
||||||
|
|
||||||
|
et = ElementTree.parse(app.outdir / 'dedent.xml')
|
||||||
|
secs = et.findall('/section/section')
|
||||||
|
literal_include = secs[1].findall('literal_block')
|
||||||
|
|
||||||
|
assert len(literal_include) > 0
|
||||||
|
actual = literal_include[0].text
|
||||||
|
return actual
|
||||||
|
|
||||||
|
|
||||||
|
for i in range(5): # 0-4
|
||||||
|
actual = get_dedent_actual(i)
|
||||||
|
indent = " " * (4 - i)
|
||||||
|
expect = '\n'.join(indent + l for l in literal_lines) + '\n'
|
||||||
|
assert (i, actual) == (i, expect)
|
||||||
|
|
||||||
|
|
||||||
|
actual = get_dedent_actual(1000)
|
||||||
|
assert actual == '\n\n'
|
Loading…
Reference in New Issue
Block a user