11"""Code block processing."""
2+ import re
3+
24from typing import List
35from pathlib import Path
46from warnings import warn
@@ -182,6 +184,11 @@ def link_html(document: Path, transforms: List[SourceTransforms], inventory: dic
182184
183185 lines = str (inner ).split ('\n ' )
184186
187+ # Expression asserts no dots before or after content nor a link after,
188+ # i.e. a self-contained name or attribute that hasn't been linked yet
189+ # so we are free to replace any occurrences, since the order of
190+ # multiple identical replacements doesn't matter.
191+ ex = r'(?<!<span class="o">\.</span>){content}(?!(<span class="o">\.)|(</a>))'
185192 for name in trans .names :
186193 if name .import_name not in inventory :
187194 continue
@@ -190,9 +197,10 @@ def link_html(document: Path, transforms: List[SourceTransforms], inventory: dic
190197 name_pattern .format (name = part ) for part in name .used_name .split ('.' )
191198 )
192199 line = lines [name .lineno - 1 ]
193- first = line .find (html )
194- second = line [first + 1 :].find (html )
195- if first == - 1 or second != - 1 :
200+
201+ # Reverse because a.b = a.b should replace from the right
202+ matches = list (re .finditer (ex .format (content = html ), line ))[::- 1 ]
203+ if not matches :
196204 msg = (
197205 f'Could not match transformation of `{ name .used_name } ` '
198206 f'on source line { name .lineno } in document "{ document } ", '
@@ -206,7 +214,8 @@ def link_html(document: Path, transforms: List[SourceTransforms], inventory: dic
206214 title = name .import_name ,
207215 text = html
208216 )
209- lines [name .lineno - 1 ] = line .replace (html , link )
217+ start , end = matches [0 ].span ()
218+ lines [name .lineno - 1 ] = line [:start ] + link + line [end :]
210219
211220 inner .replace_with (BeautifulSoup ('\n ' .join (lines ), 'html.parser' ))
212221
0 commit comments