Skip to content

Commit a55a765

Browse files
authored
Merge pull request #9661 from latosha-maltba/dedent
code-block: Fix handling of :dedent: and add unit tests
2 parents 0938c19 + ff54f97 commit a55a765

File tree

5 files changed

+96
-4
lines changed

5 files changed

+96
-4
lines changed

CHANGES

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ Bugs fixed
7878
* #9979: Error level messages were displayed as warning messages
7979
* #10057: Failed to scan documents if the project is placed onto the root
8080
directory
81-
81+
* #9636: code-block: ``:dedent:`` without argument did strip newlines
8282

8383
Testing
8484
--------

doc/usage/restructuredtext/directives.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,7 @@ __ https://pygments.org/docs/lexers
598598
are removed via :func:`textwrap.dedent()`. For example::
599599
600600
.. code-block:: ruby
601+
:linenos:
601602
:dedent: 4
602603
603604
some ruby code

sphinx/directives/code.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def run(self) -> List[Node]:
5757

5858

5959
def dedent_lines(lines: List[str], dedent: int, location: Tuple[str, int] = None) -> List[str]:
60-
if not dedent:
60+
if dedent is None:
6161
return textwrap.dedent(''.join(lines)).splitlines(True)
6262

6363
if any(s[:dedent].strip() for s in lines):
@@ -138,9 +138,9 @@ def run(self) -> List[Node]:
138138

139139
if 'dedent' in self.options:
140140
location = self.state_machine.get_source_and_line(self.lineno)
141-
lines = code.split('\n')
141+
lines = code.splitlines(True)
142142
lines = dedent_lines(lines, self.options['dedent'], location=location)
143-
code = '\n'.join(lines)
143+
code = ''.join(lines)
144144

145145
literal: Element = nodes.literal_block(code, code)
146146
if 'linenos' in self.options or 'lineno-start' in self.options:
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
dedent option
2+
-------------
3+
4+
.. code-block::
5+
6+
First line
7+
Second line
8+
Third line
9+
Fourth line
10+
11+
ReST has no fixed indent and only a change in indention is significant not the amount [1]_.
12+
Thus, the following code inside the code block is not indent even it looks so with respect to the previous block.
13+
14+
.. code-block::
15+
16+
First line
17+
Second line
18+
Third line
19+
Fourth line
20+
21+
Having an option "fixates" the indent to be 3 spaces, thus the code inside the code block is indented by 4 spaces.
22+
23+
.. code-block::
24+
:class: dummy
25+
26+
First line
27+
Second line
28+
Third line
29+
Fourth line
30+
31+
The code has 6 spaces indent, minus 4 spaces dedent should yield a 2 space indented code in the output.
32+
33+
.. code-block::
34+
:dedent: 4
35+
36+
First line
37+
Second line
38+
Third line
39+
Fourth line
40+
41+
Dedenting by zero, should not strip any spaces and be a no-op.
42+
43+
.. note::
44+
This can be used as an alternative to ``:class: dummy`` above, to fixate the ReST indention of the block.
45+
46+
.. code-block::
47+
:dedent: 0
48+
49+
First line
50+
Second line
51+
Third line
52+
Fourth line
53+
54+
Dedent without argument should autostrip common whitespace at the beginning.
55+
56+
.. code-block::
57+
:dedent:
58+
59+
First line
60+
Second line
61+
Third line
62+
Fourth line
63+
64+
.. [1] https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#indentation

tests/test_directive_code.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,3 +580,30 @@ def test_linenothreshold(app, status, warning):
580580
# literal include not using linenothreshold (no line numbers)
581581
assert ('<span></span><span class="c1"># Very small literal include '
582582
'(linenothreshold check)</span>' in html)
583+
584+
585+
@pytest.mark.sphinx('dummy', testroot='directive-code')
586+
def test_code_block_dedent(app, status, warning):
587+
app.builder.build(['dedent'])
588+
doctree = app.env.get_doctree('dedent')
589+
codeblocks = list(doctree.traverse(nodes.literal_block))
590+
# Note: comparison string should not have newlines at the beginning or end
591+
text_0_indent = '''First line
592+
Second line
593+
Third line
594+
Fourth line'''
595+
text_2_indent = ''' First line
596+
Second line
597+
Third line
598+
Fourth line'''
599+
text_4_indent = ''' First line
600+
Second line
601+
Third line
602+
Fourth line'''
603+
604+
assert codeblocks[0].astext() == text_0_indent
605+
assert codeblocks[1].astext() == text_0_indent
606+
assert codeblocks[2].astext() == text_4_indent
607+
assert codeblocks[3].astext() == text_2_indent
608+
assert codeblocks[4].astext() == text_4_indent
609+
assert codeblocks[5].astext() == text_0_indent

0 commit comments

Comments
 (0)