@@ -1740,7 +1740,7 @@ where
17401740 Self :: find_footnote_definitions ( self . root , & mut fd_map) ;
17411741
17421742 let mut next_ix = 0 ;
1743- Self :: find_footnote_references ( self . root , & mut fd_map, & mut next_ix) ;
1743+ self . find_footnote_references ( & mut fd_map, & mut next_ix) ;
17441744
17451745 let mut fds = fd_map. into_values ( ) . collect :: < Vec < _ > > ( ) ;
17461746 fds. sort_unstable_by ( |a, b| a. ix . cmp ( & b. ix ) ) ;
@@ -1786,13 +1786,14 @@ where
17861786 }
17871787
17881788 fn find_footnote_references (
1789- root : Node < ' a > ,
1789+ & mut self ,
17901790 map : & mut HashMap < String , FootnoteDefinition > ,
17911791 ixp : & mut u32 ,
17921792 ) {
1793- let mut stack = vec ! [ root] ;
1793+ let mut stack = vec ! [ self . root] ;
17941794 while let Some ( node) = stack. pop ( ) {
17951795 let mut ast = node. data_mut ( ) ;
1796+ let sp = ast. sourcepos ;
17961797 match ast. value {
17971798 NodeValue :: FootnoteReference ( ref mut nfr) => {
17981799 let normalized = strings:: normalize_label ( & nfr. name , Case :: Fold ) ;
@@ -1810,7 +1811,41 @@ where
18101811 nfr. ix = ix;
18111812 nfr. name = strings:: normalize_label ( & footnote. name , Case :: Preserve ) ;
18121813 } else {
1813- ast. value = NodeValue :: Text ( format ! ( "[^{}]" , nfr. name) . into ( ) ) ;
1814+ // Restore the nodes as they were-ish. We restore each
1815+ // Text node as it was found, preserving the sourcepos
1816+ // spans. This is important for accurate sourcepos
1817+ // tracking; we assert when 'consuming' sourcepos
1818+ // lengths in post-processing that either the span
1819+ // length matches the byte count of the string (meaning
1820+ // we can reliably subset them both), or that we're
1821+ // consuming a whole span. Trying to consume part of a
1822+ // span without a matching length is undefined, and we
1823+ // will crash; see Spx::consume.
1824+ //
1825+ // See HACK comment in
1826+ // `inlines::Subject::handle_close_bracket` for the
1827+ // producer of these values.
1828+ assert ! ( !nfr. texts. is_empty( ) ) ;
1829+ let mut lc = sp. start ;
1830+ let mut target = node;
1831+
1832+ let mut texts = mem:: take ( & mut nfr. texts ) ;
1833+ texts. insert ( 0 , ( "[" . into ( ) , 1 ) ) ;
1834+ texts. push ( ( "]" . into ( ) , 1 ) ) ;
1835+
1836+ for ( text, span) in & mut texts {
1837+ let inl = self . arena . alloc (
1838+ Ast :: new_with_sourcepos (
1839+ NodeValue :: Text ( mem:: take ( text) . into ( ) ) ,
1840+ ( lc, lc. column_add ( * span as isize - 1 ) ) . into ( ) ,
1841+ )
1842+ . into ( ) ,
1843+ ) ;
1844+ target. insert_after ( inl) ;
1845+ target = inl;
1846+ lc = lc. column_add ( * span as isize ) ;
1847+ }
1848+ node. detach ( ) ;
18141849 }
18151850 }
18161851 _ => {
0 commit comments