@@ -215,10 +215,17 @@ def match_size(re_match):
215215def clean_paragraph (paragraph ):
216216 paragraph = escape2null (paragraph )
217217 while True :
218- potential_inline_literal = min (inline_literal_re .finditer (paragraph , overlapped = True ),key = match_size , default = None )
218+ potential_inline_literal = min (
219+ inline_literal_re .finditer (paragraph , overlapped = True ),
220+ key = match_size ,
221+ default = None ,
222+ )
219223 if potential_inline_literal is None :
220224 break
221- paragraph = paragraph [:potential_inline_literal .start ()] + paragraph [potential_inline_literal .end ():]
225+ paragraph = (
226+ paragraph [: potential_inline_literal .start ()]
227+ + paragraph [potential_inline_literal .end () :]
228+ )
222229 paragraph = normal_role_re .sub ("" , paragraph )
223230 return paragraph .replace ("\x00 " , "\\ " )
224231
@@ -352,31 +359,40 @@ def inline_markup_gen(start_string, end_string):
352359 inline_markup_gen('**', '**') geneates a regex matching strong
353360 emphasis inline markup.
354361 """
362+ ascii_allowed_before = r"""[-:/'"<(\[{]"""
363+ unicode_allowed_before = r"[\p{Ps}\p{Pi}\p{Pf}\p{Pd}\p{Po}]"
364+ ascii_allowed_after = r"""[-.,:;!?/'")\]}>]"""
365+ unicode_allowed_after = r"[\p{Pe}\p{Pi}\p{Pf}\p{Pd}\p{Po}]"
355366 return re .compile (
356- r"""
357- (?<!\x00) # Both inline markup start-string and end-string must not be preceded by an unescaped backslash
358- (?<= # Inline markup start-strings must:
367+ fr"""
368+ (?<!\x00) # Both inline markup start-string and end-string must not be preceded by
369+ # an unescaped backslash
370+
371+ (?<= # Inline markup start-strings must:
359372 ^| # start a text block
360373 \s| # or be immediately preceded by whitespace,
361- [-:/'"<([{]| # one of the ASCII characters
362- [\p{Ps}\p{Pi}\p{Pf}\p{Pd}\p{Po}] # or a similar non-ASCII punctuation character.
374+ { ascii_allowed_before } | # one of the ASCII characters
375+ { unicode_allowed_before } # or a similar non-ASCII punctuation character.
376+ )
377+
378+ (?P<inline_markup>
379+ { start_string } # Inline markup start
380+ \S # Inline markup start-strings must be immediately followed by
381+ # non-whitespace.
382+ # The inline markup end-string must be separated by at least one
383+ # character from the start-string.
384+ { QUOTE_PAIRS_NEGATIVE_LOOKBEHIND }
385+ .*?
386+ (?<=\S) # Inline markup end-strings must be immediately preceded by non-whitespace.
387+ { end_string } # Inline markup end
363388 )
364- (?P<inline_markup>"""
365- + start_string
366- + r""" # Inline markup start
367- \S # Inline markup start-strings must be immediately followed by non-whitespace.
368- # The inline markup end-string must be separated by at least one character from the start-string.
369- """
370- + QUOTE_PAIRS_NEGATIVE_LOOKBEHIND
371- + ".*?"
372- + end_string
373- + r""") # Inline markup end
389+
374390 (?= # Inline markup end-strings must
375391 $| # end a text block or
376392 \s| # be immediately followed by whitespace,
377393 \x00|
378- [-.,:;!?/'")\]}>] | # one of the ASCII characters
379- [\p{Pe}\p{Pi}\p{Pf}\p{Pd}\p{Po}] # or a similar non-ASCII punctuation character.
394+ { ascii_allowed_after } | # one of the ASCII characters
395+ { unicode_allowed_after } # or a similar non-ASCII punctuation character.
380396 )
381397 """ ,
382398 flags = re .VERBOSE | re .DOTALL ,
@@ -390,8 +406,7 @@ def inline_markup_gen(start_string, end_string):
390406 f":{ SIMPLENAME } :{ interpreted_text_re .pattern } " , flags = re .VERBOSE | re .DOTALL
391407)
392408backtick_in_front_of_role = re .compile (
393- rf"(^|\s)`:{ SIMPLENAME } :{ interpreted_text_re .pattern } " ,
394- flags = re .VERBOSE | re .DOTALL
409+ rf"(^|\s)`:{ SIMPLENAME } :{ interpreted_text_re .pattern } " , flags = re .VERBOSE | re .DOTALL
395410)
396411
397412
@@ -525,12 +540,37 @@ def check_role_with_double_backticks(file, lines, options=None):
525540
526541 Bad: :fct:``sum``
527542 Good: :fct:`sum`
543+
544+ The hard thing is that :fct:``sum`` is a legitimate
545+ restructuredtext construction:
546+
547+ :fct: is just plain text.
548+ ``sum`` is an inline literal.
549+
550+ So to properly detect this one we're searching for actual inline
551+ literals that have a role tag.
528552 """
529- for lno , line in enumerate (lines , start = 1 ):
530- if "`" not in line :
553+ for paragraph_lno , paragraph in paragraphs (lines ):
554+ if "`" not in paragraph :
531555 continue
532- if double_backtick_role .search (line ):
533- yield lno , "role use a single backtick, double backtick found."
556+ if paragraph .count ("|" ) > 4 :
557+ return # we don't handle tables yet.
558+ paragraph = escape2null (paragraph )
559+ while True :
560+ inline_literal = min (
561+ inline_literal_re .finditer (paragraph , overlapped = True ),
562+ key = match_size ,
563+ default = None ,
564+ )
565+ if inline_literal is None :
566+ break
567+ before = paragraph [: inline_literal .start ()]
568+ if re .search (ROLE_TAG + "$" , before ):
569+ error_offset = paragraph [: inline_literal .start ()].count ("\n " )
570+ yield paragraph_lno + error_offset , "role use a single backtick, double backtick found."
571+ paragraph = (
572+ paragraph [: inline_literal .start ()] + paragraph [inline_literal .end () :]
573+ )
534574
535575
536576@checker (".rst" )
@@ -661,7 +701,10 @@ def hide_non_rst_blocks(lines, hidden_block_cb=None):
661701 in_literal = len (re .match (" *" , line ).group (0 ))
662702 block_line_start = lineno
663703 assert not excluded_lines
664- if re .match (r" *\.\. " , line ) and type_of_explicit_markup (line ) == "comment" :
704+ if (
705+ re .match (r" *\.\. " , line )
706+ and type_of_explicit_markup (line ) == "comment"
707+ ):
665708 line = "\n "
666709 output .append (line )
667710 if excluded_lines and hidden_block_cb :
0 commit comments