@@ -6,9 +6,9 @@ use crate::config::Config;
66use crate :: linter:: diagnostics:: Diagnostic ;
77use crate :: metadata:: DocumentMetadata ;
88use crate :: syntax:: {
9- AstNode , AttributeNode , Citation , CodeBlock , Crossref , FootnoteDefinition , Heading , Link ,
10- ListItem , ParsedYamlRegionSnapshot , ReferenceDefinition , SyntaxKind , SyntaxNode , YamlRegion ,
11- collect_parsed_yaml_region_snapshots,
9+ AstNode , AttributeNode , Citation , CodeBlock , Crossref , FootnoteDefinition , FootnoteReference ,
10+ Heading , Link , ListItem , ParsedYamlRegionSnapshot , ReferenceDefinition , SyntaxKind , SyntaxNode ,
11+ YamlRegion , collect_parsed_yaml_region_snapshots,
1212} ;
1313use crate :: utils:: { implicit_heading_ids, normalize_label} ;
1414use salsa:: { Accumulator , Durability , Setter } ;
@@ -314,6 +314,8 @@ pub struct SymbolUsageIndex {
314314 heading_implicit_definition_ranges : HashMap < String , Vec < rowan:: TextRange > > ,
315315 reference_definitions : HashMap < String , Vec < rowan:: TextRange > > ,
316316 footnote_definitions : HashMap < String , Vec < rowan:: TextRange > > ,
317+ footnote_references : HashMap < String , Vec < rowan:: TextRange > > ,
318+ footnote_definition_id_ranges : HashMap < String , Vec < rowan:: TextRange > > ,
317319 example_label_definitions : HashMap < String , Vec < rowan:: TextRange > > ,
318320 heading_labels : HashMap < String , Vec < rowan:: TextRange > > ,
319321 heading_sequence : Vec < ( rowan:: TextRange , usize ) > ,
@@ -398,6 +400,21 @@ impl SymbolUsageIndex {
398400 self . footnote_definitions . get ( & normalize_label ( key) )
399401 }
400402
403+ pub fn footnote_rename_ranges ( & self , key : & str ) -> Vec < rowan:: TextRange > {
404+ let normalized = normalize_label ( key) ;
405+ let mut ranges = self
406+ . footnote_references
407+ . get ( & normalized)
408+ . cloned ( )
409+ . unwrap_or_default ( ) ;
410+ if let Some ( id_ranges) = self . footnote_definition_id_ranges . get ( & normalized) {
411+ ranges. extend ( id_ranges. iter ( ) . copied ( ) ) ;
412+ }
413+ ranges. sort_by_key ( |range| range. start ( ) ) ;
414+ ranges. dedup ( ) ;
415+ ranges
416+ }
417+
401418 pub fn example_label_definitions ( & self , key : & str ) -> Option < & Vec < rowan:: TextRange > > {
402419 self . example_label_definitions . get ( & normalize_label ( key) )
403420 }
@@ -535,6 +552,28 @@ pub fn symbol_usage_index_from_tree(
535552 . entry ( id)
536553 . or_default ( )
537554 . push ( def. syntax ( ) . text_range ( ) ) ;
555+ if let Some ( id_range) = def. id_value_range ( ) {
556+ index
557+ . footnote_definition_id_ranges
558+ . entry ( normalize_label ( & def. id ( ) ) )
559+ . or_default ( )
560+ . push ( id_range) ;
561+ }
562+ }
563+
564+ for footnote in tree. descendants ( ) . filter_map ( FootnoteReference :: cast) {
565+ db. unwind_if_revision_cancelled ( ) ;
566+ let id = normalize_label ( & footnote. id ( ) ) ;
567+ if id. is_empty ( ) {
568+ continue ;
569+ }
570+ if let Some ( id_range) = footnote. id_value_range ( ) {
571+ index
572+ . footnote_references
573+ . entry ( id)
574+ . or_default ( )
575+ . push ( id_range) ;
576+ }
538577 }
539578
540579 for item in tree. descendants ( ) . filter_map ( ListItem :: cast) {
@@ -1719,6 +1758,24 @@ mod tests {
17191758 assert_eq ! ( index. heading_rename_ranges( "heading" ) . len( ) , 3 ) ;
17201759 }
17211760
1761+ #[ test]
1762+ fn symbol_usage_index_collects_footnote_rename_ranges ( ) {
1763+ let db = SalsaDb :: default ( ) ;
1764+ let tree = crate :: parse (
1765+ "Text with footnote[^note] and another[^note].\n \n [^note]: Footnote text.\n " ,
1766+ None ,
1767+ ) ;
1768+ let index = symbol_usage_index_from_tree ( & db, & tree, & crate :: config:: Extensions :: default ( ) ) ;
1769+
1770+ assert_eq ! (
1771+ index
1772+ . footnote_definitions( "note" )
1773+ . map( |ranges| ranges. len( ) ) ,
1774+ Some ( 1 )
1775+ ) ;
1776+ assert_eq ! ( index. footnote_rename_ranges( "note" ) . len( ) , 3 ) ;
1777+ }
1778+
17221779 #[ test]
17231780 fn symbol_usage_index_collects_implicit_heading_insert_ranges ( ) {
17241781 let db = SalsaDb :: default ( ) ;
0 commit comments