Allow using `rst_prolog` with a role in a document title (#11445)

Fix the field list field name recognition regular expression to avoid false positives,
as interpreted text roles may not be field name blocks.

Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com>
This commit is contained in:
picnixz 2023-07-23 18:14:01 +02:00 committed by GitHub
parent c583e0f9b0
commit 12e7cff0b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 75 additions and 9 deletions

15
CHANGES
View File

@ -35,6 +35,21 @@ Features added
Bugs fixed Bugs fixed
---------- ----------
* #11437: Top-level headings starting with a reStructuredText role
now render properly when :confval:`rst_prolog` is set.
Previously, a file starting with the below would have
improperly rendered due to where the prologue text
was inserted into the document.
.. code:: rst
:mod:`lobster` -- The lobster module
====================================
...
Patch by Bénédikt Tran.
Testing Testing
-------- --------

View File

@ -10,22 +10,17 @@ from unicodedata import east_asian_width
from docutils.parsers.rst import roles from docutils.parsers.rst import roles
from docutils.parsers.rst.languages import en as english from docutils.parsers.rst.languages import en as english
from docutils.parsers.rst.states import Body
from docutils.statemachine import StringList from docutils.statemachine import StringList
from docutils.utils import Reporter from docutils.utils import Reporter
from jinja2 import Environment from jinja2 import Environment, pass_environment
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import docutils, logging from sphinx.util import docutils, logging
try:
from jinja2.utils import pass_environment
except ImportError:
from jinja2 import environmentfilter as pass_environment
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
docinfo_re = re.compile(':\\w+:.*?') FIELD_NAME_RE = re.compile(Body.patterns['field_marker'])
symbols_re = re.compile(r'([!-\-/:-@\[-`{-~])') # symbols without dot(0x2e) symbols_re = re.compile(r'([!-\-/:-@\[-`{-~])') # symbols without dot(0x2e)
SECTIONING_CHARS = ['=', '-', '~'] SECTIONING_CHARS = ['=', '-', '~']
@ -80,7 +75,7 @@ def prepend_prolog(content: StringList, prolog: str) -> None:
if prolog: if prolog:
pos = 0 pos = 0
for line in content: for line in content:
if docinfo_re.match(line): if FIELD_NAME_RE.match(line):
pos += 1 pos += 1
else: else:
break break
@ -91,6 +86,7 @@ def prepend_prolog(content: StringList, prolog: str) -> None:
pos += 1 pos += 1
# insert prolog (after docinfo if exists) # insert prolog (after docinfo if exists)
lineno = 0
for lineno, line in enumerate(prolog.splitlines()): for lineno, line in enumerate(prolog.splitlines()):
content.insert(pos + lineno, line, '<rst_prolog>', lineno) content.insert(pos + lineno, line, '<rst_prolog>', lineno)

View File

@ -78,6 +78,61 @@ def test_prepend_prolog_without_CR(app):
('dummy.rst', 1, 'Sphinx is a document generator')] ('dummy.rst', 1, 'Sphinx is a document generator')]
def test_prepend_prolog_with_roles_in_sections(app):
prolog = 'this is rst_prolog\nhello reST!'
content = StringList([':title: test of SphinxFileInput',
':author: Sphinx team',
'', # this newline is required
':mod:`foo`',
'----------',
'',
'hello'],
'dummy.rst')
prepend_prolog(content, prolog)
assert list(content.xitems()) == [('dummy.rst', 0, ':title: test of SphinxFileInput'),
('dummy.rst', 1, ':author: Sphinx team'),
('<generated>', 0, ''),
('<rst_prolog>', 0, 'this is rst_prolog'),
('<rst_prolog>', 1, 'hello reST!'),
('<generated>', 0, ''),
('dummy.rst', 2, ''),
('dummy.rst', 3, ':mod:`foo`'),
('dummy.rst', 4, '----------'),
('dummy.rst', 5, ''),
('dummy.rst', 6, 'hello')]
def test_prepend_prolog_with_roles_in_sections_with_newline(app):
# prologue with trailing line break
prolog = 'this is rst_prolog\nhello reST!\n'
content = StringList([':mod:`foo`', '-' * 10, '', 'hello'], 'dummy.rst')
prepend_prolog(content, prolog)
assert list(content.xitems()) == [('<rst_prolog>', 0, 'this is rst_prolog'),
('<rst_prolog>', 1, 'hello reST!'),
('<generated>', 0, ''),
('dummy.rst', 0, ':mod:`foo`'),
('dummy.rst', 1, '----------'),
('dummy.rst', 2, ''),
('dummy.rst', 3, 'hello')]
def test_prepend_prolog_with_roles_in_sections_without_newline(app):
# prologue with no trailing line break
prolog = 'this is rst_prolog\nhello reST!'
content = StringList([':mod:`foo`', '-' * 10, '', 'hello'], 'dummy.rst')
prepend_prolog(content, prolog)
assert list(content.xitems()) == [('<rst_prolog>', 0, 'this is rst_prolog'),
('<rst_prolog>', 1, 'hello reST!'),
('<generated>', 0, ''),
('dummy.rst', 0, ':mod:`foo`'),
('dummy.rst', 1, '----------'),
('dummy.rst', 2, ''),
('dummy.rst', 3, 'hello')]
def test_textwidth(): def test_textwidth():
assert textwidth('Hello') == 5 assert textwidth('Hello') == 5
assert textwidth('русский язык') == 12 assert textwidth('русский язык') == 12