summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshimizukawa <shimizukawa@gmail.com>2014-08-10 23:03:02 +0900
committershimizukawa <shimizukawa@gmail.com>2014-08-10 23:03:02 +0900
commitb1d122e2446d16452711023561614869e74fb77f (patch)
tree661708835e2d98ee78cd12b22c70858728e26732
parentaa0520d0d8818b58856fabaf1408dfe0fe439235 (diff)
downloadsphinx-b1d122e2446d16452711023561614869e74fb77f.tar.gz
* for pull request #258: update CHANGES, add tests, add a document and refactoring.
-rw-r--r--CHANGES2
-rw-r--r--doc/markup/code.rst16
-rw-r--r--sphinx/directives/code.py34
-rw-r--r--tests/roots/test-directive-code/conf.py3
-rw-r--r--tests/roots/test-directive-code/dedent.rst22
-rw-r--r--tests/roots/test-directive-code/index.rst24
-rw-r--r--tests/roots/test-directive-code/literal.inc13
-rw-r--r--tests/test_directive_code.py131
8 files changed, 231 insertions, 14 deletions
diff --git a/CHANGES b/CHANGES
index 8f08f142..084a2856 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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
-------------
diff --git a/doc/markup/code.rst b/doc/markup/code.rst
index 9dafdb18..936080d6 100644
--- a/doc/markup/code.rst
+++ b/doc/markup/code.rst
@@ -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
diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py
index a3e32be1..7f08b814 100644
--- a/sphinx/directives/code.py
+++ b/sphinx/directives/code.py
@@ -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,
diff --git a/tests/roots/test-directive-code/conf.py b/tests/roots/test-directive-code/conf.py
new file mode 100644
index 00000000..f81c30bc
--- /dev/null
+++ b/tests/roots/test-directive-code/conf.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+master_doc = 'index'
diff --git a/tests/roots/test-directive-code/dedent.rst b/tests/roots/test-directive-code/dedent.rst
new file mode 100644
index 00000000..d29e2cfa
--- /dev/null
+++ b/tests/roots/test-directive-code/dedent.rst
@@ -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
diff --git a/tests/roots/test-directive-code/index.rst b/tests/roots/test-directive-code/index.rst
new file mode 100644
index 00000000..ac7e519e
--- /dev/null
+++ b/tests/roots/test-directive-code/index.rst
@@ -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
diff --git a/tests/roots/test-directive-code/literal.inc b/tests/roots/test-directive-code/literal.inc
new file mode 100644
index 00000000..694f15ed
--- /dev/null
+++ b/tests/roots/test-directive-code/literal.inc
@@ -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
diff --git a/tests/test_directive_code.py b/tests/test_directive_code.py
new file mode 100644
index 00000000..bc2609df
--- /dev/null
+++ b/tests/test_directive_code.py
@@ -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'