use base_db::{ semantics::{tex, Span}, util::queries::{self, Object}, }; use crate::{RenameBuilder, RenameInformation, RenameParams}; struct PrefixInformation<'a> { def_prefixes: &'a Vec<(String, String)>, ref_prefixes: &'a Vec<(String, String)>, } fn label_has_prefix(pref_info: &PrefixInformation, label: &tex::Label) -> Option { match label.kind { tex::LabelKind::Definition => pref_info.def_prefixes.iter(), _ => pref_info.ref_prefixes.iter(), } .find_map(|(k, v)| { if k == &label.cmd.clone().unwrap_or(String::new()) { Some(v) } else { None } }) .cloned() } fn find_prefix_in_any( builder: &mut RenameBuilder, pref_info: &PrefixInformation, name: &str, ) -> Option { let project = &builder.params.feature.project; queries::objects_with_name::(project, name) .find_map(|(_, label)| label_has_prefix(&pref_info, label)) } pub(super) fn prepare_rename(params: &RenameParams) -> Option { let data = params.feature.document.data.as_tex()?; let labels = &data.semantics.labels; let label = queries::object_at_cursor(labels, params.offset, queries::SearchMode::Name)?; Some(Span::new(label.object.name.text.clone(), label.range)) } pub(super) fn rename(builder: &mut RenameBuilder) -> Option<()> { let name = prepare_rename(&builder.params)?; let syn = &builder.params.feature.workspace.config().syntax; let pref_info = PrefixInformation { def_prefixes: &syn.label_definition_prefixes, ref_prefixes: &syn.label_reference_prefixes, }; let prefix = find_prefix_in_any(builder, &pref_info, &name.text); let project = &builder.params.feature.project; for (document, label) in queries::objects_with_name::(project, &name.text) { let prefix = label_has_prefix(&pref_info, label).map_or(prefix.clone(), |_| None); let entry = builder.result.changes.entry(document); entry.or_default().push(RenameInformation { range: label.name_range(), prefix: prefix.clone(), }); } Some(()) }