* for pull request #258: update CHANGES, add tests, add a document and refactoring.

This commit is contained in:
Takayuki Shimizukawa 2014-08-10 23:03:02 +09:00
parent 4f357d9edd
commit d39327d539
8 changed files with 231 additions and 14 deletions

View File

@ -184,6 +184,8 @@ Bugs fixed
qualified name. It should be rather easy to change this behaviour and
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
-------------

View File

@ -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.
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
.. [1] There is a standard ``.. include`` directive, but it raises errors if the

View File

@ -44,6 +44,21 @@ class Highlight(Directive):
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):
"""
Directive for a code block with special highlighting or line numbering
@ -77,13 +92,9 @@ class CodeBlock(Directive):
hl_lines = None
if 'dedent' in self.options:
linesArray = code.split('\n')
for i in range(0, len(linesArray)):
if len(linesArray[i]) <= self.options['dedent']:
linesArray[i] = linesArray[i][len(linesArray[i]) - 1:]
else:
linesArray[i] = linesArray[i][self.options['dedent']:]
code = '\n'.join(linesArray)
lines = code.split('\n')
lines = dedent_lines(lines, self.options['dedent'])
code = '\n'.join(lines)
literal = nodes.literal_block(code, code)
literal['language'] = self.arguments[0]
@ -113,7 +124,7 @@ class LiteralInclude(Directive):
optional_arguments = 0
final_argument_whitespace = True
option_spec = {
'dedent': int,
'dedent': int,
'linenos': directives.flag,
'lineno-start': int,
'tab-width': int,
@ -149,12 +160,7 @@ class LiteralInclude(Directive):
f = codecs.StreamReaderWriter(open(filename, 'rb'),
codec_info[2], codec_info[3], 'strict')
lines = f.readlines()
if 'dedent' in self.options:
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']:]
lines = dedent_lines(lines, self.options.get('dedent'))
except (IOError, OSError):
return [document.reporter.warning(
'Include file %r not found or reading it failed' % filename,

View File

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
master_doc = 'index'

View 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

View 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

View 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

View 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'