mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
#3998: Add optional section numbering in plain text output
Controlled by new config values: text_add_secnumbers and text_secnumber_suffix.
This commit is contained in:
1
AUTHORS
1
AUTHORS
@@ -67,6 +67,7 @@ Other contributors, listed alphabetically, are:
|
|||||||
* Barry Warsaw -- setup command improvements
|
* Barry Warsaw -- setup command improvements
|
||||||
* Sebastian Wiesner -- image handling, distutils support
|
* Sebastian Wiesner -- image handling, distutils support
|
||||||
* Michael Wilson -- Intersphinx HTTP basic auth support
|
* Michael Wilson -- Intersphinx HTTP basic auth support
|
||||||
|
* Matthew Woodcraft -- text output improvements
|
||||||
* Joel Wurtz -- cellspanning support in LaTeX
|
* Joel Wurtz -- cellspanning support in LaTeX
|
||||||
* Hong Xu -- svg support in imgmath extension and various bug fixes
|
* Hong Xu -- svg support in imgmath extension and various bug fixes
|
||||||
* Stephen Finucane -- setup command improvements and documentation
|
* Stephen Finucane -- setup command improvements and documentation
|
||||||
|
|||||||
2
CHANGES
2
CHANGES
@@ -43,6 +43,8 @@ Features added
|
|||||||
* #4168: improve zh search with jieba
|
* #4168: improve zh search with jieba
|
||||||
* HTML themes can set up default sidebars through ``theme.conf``
|
* HTML themes can set up default sidebars through ``theme.conf``
|
||||||
* #3160: html: Use ``<kdb>`` to represent ``:kbd:`` role
|
* #3160: html: Use ``<kdb>`` to represent ``:kbd:`` role
|
||||||
|
* #3998: text: Add new config values :confval:`text_add_secnumbers` and
|
||||||
|
:confval:`text_secnumber_suffix`
|
||||||
|
|
||||||
|
|
||||||
Features removed
|
Features removed
|
||||||
|
|||||||
@@ -1959,6 +1959,20 @@ These options influence text output.
|
|||||||
|
|
||||||
.. versionadded:: 1.1
|
.. versionadded:: 1.1
|
||||||
|
|
||||||
|
.. confval:: text_add_secnumbers
|
||||||
|
|
||||||
|
A boolean that decides whether section numbers are included in text output.
|
||||||
|
Default is ``False``.
|
||||||
|
|
||||||
|
.. versionadded:: 1.7
|
||||||
|
|
||||||
|
.. confval:: text_secnumber_suffix
|
||||||
|
|
||||||
|
Suffix for section numbers in text output. Default: ``". "``. Set to ``" "``
|
||||||
|
to suppress the final dot on section numbers.
|
||||||
|
|
||||||
|
.. versionadded:: 1.7
|
||||||
|
|
||||||
|
|
||||||
.. _man-options:
|
.. _man-options:
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ class TextBuilder(Builder):
|
|||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
pass
|
# section numbers for headings in the currently visited document
|
||||||
|
self.secnumbers = {} # type: Dict[unicode, Tuple[int, ...]]
|
||||||
|
|
||||||
def get_outdated_docs(self):
|
def get_outdated_docs(self):
|
||||||
# type: () -> Iterator[unicode]
|
# type: () -> Iterator[unicode]
|
||||||
@@ -72,6 +73,7 @@ class TextBuilder(Builder):
|
|||||||
def write_doc(self, docname, doctree):
|
def write_doc(self, docname, doctree):
|
||||||
# type: (unicode, nodes.Node) -> None
|
# type: (unicode, nodes.Node) -> None
|
||||||
self.current_docname = docname
|
self.current_docname = docname
|
||||||
|
self.secnumbers = self.env.toc_secnumbers.get(docname, {})
|
||||||
destination = StringOutput(encoding='utf-8')
|
destination = StringOutput(encoding='utf-8')
|
||||||
self.writer.write(doctree, destination)
|
self.writer.write(doctree, destination)
|
||||||
outfilename = path.join(self.outdir, os_path(docname) + self.out_suffix)
|
outfilename = path.join(self.outdir, os_path(docname) + self.out_suffix)
|
||||||
@@ -93,6 +95,8 @@ def setup(app):
|
|||||||
|
|
||||||
app.add_config_value('text_sectionchars', '*=-~"+`', 'env')
|
app.add_config_value('text_sectionchars', '*=-~"+`', 'env')
|
||||||
app.add_config_value('text_newlines', 'unix', 'env')
|
app.add_config_value('text_newlines', 'unix', 'env')
|
||||||
|
app.add_config_value('text_add_secnumbers', False, 'env')
|
||||||
|
app.add_config_value('text_secnumber_suffix', '. ', 'env')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'version': 'builtin',
|
'version': 'builtin',
|
||||||
|
|||||||
@@ -183,6 +183,8 @@ class TextTranslator(nodes.NodeVisitor):
|
|||||||
else:
|
else:
|
||||||
self.nl = '\n'
|
self.nl = '\n'
|
||||||
self.sectionchars = builder.config.text_sectionchars
|
self.sectionchars = builder.config.text_sectionchars
|
||||||
|
self.add_secnumbers = builder.config.text_add_secnumbers
|
||||||
|
self.secnumber_suffix = builder.config.text_secnumber_suffix
|
||||||
self.states = [[]] # type: List[List[Tuple[int, Union[unicode, List[unicode]]]]]
|
self.states = [[]] # type: List[List[Tuple[int, Union[unicode, List[unicode]]]]]
|
||||||
self.stateindent = [0]
|
self.stateindent = [0]
|
||||||
self.list_counter = [] # type: List[int]
|
self.list_counter = [] # type: List[int]
|
||||||
@@ -307,6 +309,17 @@ class TextTranslator(nodes.NodeVisitor):
|
|||||||
raise nodes.SkipNode
|
raise nodes.SkipNode
|
||||||
self.new_state(0)
|
self.new_state(0)
|
||||||
|
|
||||||
|
def get_section_number_string(self, node):
|
||||||
|
# type: (nodes.Node) -> unicode
|
||||||
|
if isinstance(node.parent, nodes.section):
|
||||||
|
anchorname = '#' + node.parent['ids'][0]
|
||||||
|
numbers = self.builder.secnumbers.get(anchorname)
|
||||||
|
if numbers is None:
|
||||||
|
numbers = self.builder.secnumbers.get('')
|
||||||
|
if numbers is not None:
|
||||||
|
return '.'.join(map(str, numbers)) + self.secnumber_suffix
|
||||||
|
return ''
|
||||||
|
|
||||||
def depart_title(self, node):
|
def depart_title(self, node):
|
||||||
# type: (nodes.Node) -> None
|
# type: (nodes.Node) -> None
|
||||||
if isinstance(node.parent, nodes.section):
|
if isinstance(node.parent, nodes.section):
|
||||||
@@ -315,6 +328,8 @@ class TextTranslator(nodes.NodeVisitor):
|
|||||||
char = '^'
|
char = '^'
|
||||||
text = None # type: unicode
|
text = None # type: unicode
|
||||||
text = ''.join(x[1] for x in self.states.pop() if x[0] == -1) # type: ignore
|
text = ''.join(x[1] for x in self.states.pop() if x[0] == -1) # type: ignore
|
||||||
|
if self.add_secnumbers:
|
||||||
|
text = self.get_section_number_string(node) + text
|
||||||
self.stateindent.pop()
|
self.stateindent.pop()
|
||||||
title = ['', text, '%s' % (char * column_width(text)), ''] # type: List[unicode]
|
title = ['', text, '%s' % (char * column_width(text)), ''] # type: List[unicode]
|
||||||
if len(self.states) == 2 and len(self.states[-1]) == 0:
|
if len(self.states) == 2 and len(self.states[-1]) == 0:
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
|
:numbered:
|
||||||
|
|
||||||
|
doc1
|
||||||
|
doc2
|
||||||
maxwidth
|
maxwidth
|
||||||
lineblock
|
lineblock
|
||||||
nonascii_title
|
nonascii_title
|
||||||
|
|||||||
2
tests/roots/test-build-text/doc1.txt
Normal file
2
tests/roots/test-build-text/doc1.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Section A
|
||||||
|
=========
|
||||||
9
tests/roots/test-build-text/doc2.txt
Normal file
9
tests/roots/test-build-text/doc2.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Section B
|
||||||
|
=========
|
||||||
|
|
||||||
|
Sub Ba
|
||||||
|
------
|
||||||
|
|
||||||
|
Sub Bb
|
||||||
|
------
|
||||||
|
|
||||||
@@ -110,3 +110,57 @@ def test_list_items_in_admonition(app, status, warning):
|
|||||||
assert lines[2] == " * item 1"
|
assert lines[2] == " * item 1"
|
||||||
assert lines[3] == ""
|
assert lines[3] == ""
|
||||||
assert lines[4] == " * item 2"
|
assert lines[4] == " * item 2"
|
||||||
|
|
||||||
|
|
||||||
|
@with_text_app()
|
||||||
|
def test_secnums(app, status, warning):
|
||||||
|
app.builder.build_all()
|
||||||
|
result = (app.outdir / 'doc2.txt').text(encoding='utf8')
|
||||||
|
expect = (
|
||||||
|
"Section B\n"
|
||||||
|
"*********\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"Sub Ba\n"
|
||||||
|
"======\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"Sub Bb\n"
|
||||||
|
"======\n"
|
||||||
|
)
|
||||||
|
assert result == expect
|
||||||
|
|
||||||
|
app.config.text_add_secnumbers = True
|
||||||
|
app.builder.build_all()
|
||||||
|
result = (app.outdir / 'doc2.txt').text(encoding='utf8')
|
||||||
|
expect = (
|
||||||
|
"2. Section B\n"
|
||||||
|
"************\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"2.1. Sub Ba\n"
|
||||||
|
"===========\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"2.2. Sub Bb\n"
|
||||||
|
"===========\n"
|
||||||
|
)
|
||||||
|
assert result == expect
|
||||||
|
|
||||||
|
app.config.text_secnumber_suffix = " "
|
||||||
|
app.builder.build_all()
|
||||||
|
result = (app.outdir / 'doc2.txt').text(encoding='utf8')
|
||||||
|
expect = (
|
||||||
|
"2 Section B\n"
|
||||||
|
"***********\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"2.1 Sub Ba\n"
|
||||||
|
"==========\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"2.2 Sub Bb\n"
|
||||||
|
"==========\n"
|
||||||
|
)
|
||||||
|
assert result == expect
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user