@@ -338,83 +338,102 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
338
338
}
339
339
340
340
/// Make headings links with anchor IDs and build up TOC.
341
- struct LinkReplacer < ' a , ' b , I : Iterator < Item = Event < ' a > > > {
341
+ struct LinkReplacer < ' a , I : Iterator < Item = Event < ' a > > > {
342
342
inner : I ,
343
343
links : & ' a [ RenderedLink ] ,
344
- shortcut_link : Option < & ' b RenderedLink > ,
344
+ shortcut_link : Option < & ' a RenderedLink > ,
345
345
}
346
346
347
- impl < ' a , I : Iterator < Item = Event < ' a > > > LinkReplacer < ' a , ' _ , I > {
347
+ impl < ' a , I : Iterator < Item = Event < ' a > > > LinkReplacer < ' a , I > {
348
348
fn new ( iter : I , links : & ' a [ RenderedLink ] ) -> Self {
349
349
LinkReplacer { inner : iter, links, shortcut_link : None }
350
350
}
351
351
}
352
352
353
- impl < ' a : ' b , ' b , I : Iterator < Item = Event < ' a > > > Iterator for LinkReplacer < ' a , ' b , I > {
353
+ impl < ' a , I : Iterator < Item = Event < ' a > > > Iterator for LinkReplacer < ' a , I > {
354
354
type Item = Event < ' a > ;
355
355
356
356
fn next ( & mut self ) -> Option < Self :: Item > {
357
+ use pulldown_cmark:: LinkType ;
358
+
357
359
let mut event = self . inner . next ( ) ;
358
360
359
- // Remove disambiguators from shortcut links (`[fn@f]`)
361
+ // Replace intra-doc links and remove disambiguators from shortcut links (`[fn@f]`).
360
362
match & mut event {
363
+ // This is a shortcut link that was resolved by the broken_link_callback: `[fn@f]`
364
+ // Remove any disambiguator.
361
365
Some ( Event :: Start ( Tag :: Link (
362
- pulldown_cmark:: LinkType :: ShortcutUnknown ,
366
+ // [fn@f] or [fn@f][]
367
+ LinkType :: ShortcutUnknown | LinkType :: CollapsedUnknown ,
363
368
dest,
364
369
title,
365
370
) ) ) => {
366
371
debug ! ( "saw start of shortcut link to {} with title {}" , dest, title) ;
367
- let link = if let Some ( link) =
368
- self . links . iter ( ) . find ( |& link| * link. original_text == * * dest)
369
- {
370
- // Not sure why this is necessary - maybe the broken_link_callback doesn't always work?
371
- * dest = CowStr :: Borrowed ( link. href . as_ref ( ) ) ;
372
- Some ( link)
373
- } else {
374
- self . links . iter ( ) . find ( |& link| * link. href == * * dest)
375
- } ;
372
+ // If this is a shortcut link, it was resolved by the broken_link_callback.
373
+ // So the URL will already be updated properly.
374
+ let link = self . links . iter ( ) . find ( |& link| * link. href == * * dest) ;
375
+ // Since this is an external iterator, we can't replace the inner text just yet.
376
+ // Store that we saw a link so we know to replace it later.
376
377
if let Some ( link) = link {
377
378
trace ! ( "it matched" ) ;
378
379
assert ! ( self . shortcut_link. is_none( ) , "shortcut links cannot be nested" ) ;
379
380
self . shortcut_link = Some ( link) ;
380
381
}
381
382
}
382
- Some ( Event :: End ( Tag :: Link ( pulldown_cmark:: LinkType :: ShortcutUnknown , dest, _) ) ) => {
383
+ // Now that we're done with the shortcut link, don't replace any more text.
384
+ Some ( Event :: End ( Tag :: Link (
385
+ LinkType :: ShortcutUnknown | LinkType :: CollapsedUnknown ,
386
+ dest,
387
+ _,
388
+ ) ) ) => {
383
389
debug ! ( "saw end of shortcut link to {}" , dest) ;
384
- if let Some ( _link ) = self . links . iter ( ) . find ( |& link| * link. href == * * dest) {
390
+ if self . links . iter ( ) . find ( |& link| * link. href == * * dest) . is_some ( ) {
385
391
assert ! ( self . shortcut_link. is_some( ) , "saw closing link without opening tag" ) ;
386
392
self . shortcut_link = None ;
387
393
}
388
394
}
389
- // Handle backticks in inline code blocks
395
+ // Handle backticks in inline code blocks, but only if we're in the middle of a shortcut link.
396
+ // [`fn@f`]
390
397
Some ( Event :: Code ( text) ) => {
391
398
trace ! ( "saw code {}" , text) ;
392
399
if let Some ( link) = self . shortcut_link {
393
400
trace ! ( "original text was {}" , link. original_text) ;
401
+ // NOTE: this only replaces if the code block is the *entire* text.
402
+ // If only part of the link has code highlighting, the disambiguator will not be removed.
403
+ // e.g. [fn@`f`]
404
+ // This is a limitation from `collect_intra_doc_links`: it passes a full link,
405
+ // and does not distinguish at all between code blocks.
406
+ // So we could never be sure we weren't replacing too much:
407
+ // [fn@my_`f`unc] is treated the same as [my_func()] in that pass.
408
+ //
409
+ // NOTE: &[1..len() - 1] is to strip the backticks
394
410
if * * text == link. original_text [ 1 ..link. original_text . len ( ) - 1 ] {
395
411
debug ! ( "replacing {} with {}" , text, link. new_text) ;
396
- * text = link. new_text . clone ( ) . into ( ) ;
412
+ * text = CowStr :: Borrowed ( & link. new_text ) ;
397
413
}
398
414
}
399
415
}
400
- // Replace plain text in links
416
+ // Replace plain text in links, but only in the middle of a shortcut link.
417
+ // [fn@f]
401
418
Some ( Event :: Text ( text) ) => {
402
419
trace ! ( "saw text {}" , text) ;
403
420
if let Some ( link) = self . shortcut_link {
404
421
trace ! ( "original text was {}" , link. original_text) ;
422
+ // NOTE: same limitations as `Event::Code`
405
423
if * * text == * link. original_text {
406
424
debug ! ( "replacing {} with {}" , text, link. new_text) ;
407
- * text = link. new_text . clone ( ) . into ( ) ;
425
+ * text = CowStr :: Borrowed ( & link. new_text ) ;
408
426
}
409
427
}
410
428
}
429
+ // If this is a link, but not a shortcut link,
430
+ // replace the URL, since the broken_link_callback was not called.
411
431
Some ( Event :: Start ( Tag :: Link ( _, dest, _) ) ) => {
412
432
if let Some ( link) = self . links . iter ( ) . find ( |& link| * link. original_text == * * dest) {
413
- // Not sure why this is necessary - maybe the broken_link_callback doesn't always work?
414
433
* dest = CowStr :: Borrowed ( link. href . as_ref ( ) ) ;
415
434
}
416
435
}
417
- // Anything else couldn't have been a valid Rust path
436
+ // Anything else couldn't have been a valid Rust path, so no need to replace the text.
418
437
_ => { }
419
438
}
420
439
0 commit comments