summaryrefslogtreecommitdiff
path: root/support/texlab/src/features/rename/entry.rs
blob: 79ee25ac71c9ae62e5725581c7fafc852cbae3a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use rowan::{ast::AstNode, TextRange};
use rustc_hash::FxHashMap;

use crate::{
    db::parse::DocumentData,
    syntax::{
        bibtex::{self, HasName},
        latex,
    },
    util::cursor::CursorContext,
};

use super::{Indel, Params, RenameResult};

pub(super) fn prepare_rename<T>(context: &CursorContext<T>) -> Option<TextRange> {
    let (_, range) = context
        .find_citation_key_word()
        .or_else(|| context.find_entry_key())?;

    Some(range)
}

pub(super) fn rename(context: &CursorContext<Params>) -> Option<RenameResult> {
    prepare_rename(context)?;
    let (key_text, _) = context
        .find_citation_key_word()
        .or_else(|| context.find_entry_key())?;

    let mut changes = FxHashMap::default();
    for document in context.related() {
        match document.parse(context.db) {
            DocumentData::Tex(data) => {
                let root = data.root(context.db);
                let edits: Vec<_> = root
                    .descendants()
                    .filter_map(latex::Citation::cast)
                    .filter_map(|citation| citation.key_list())
                    .flat_map(|keys| keys.keys())
                    .filter(|key| key.to_string() == key_text)
                    .map(|key| Indel {
                        delete: latex::small_range(&key),
                        insert: context.params.new_name.clone(),
                    })
                    .collect();
                changes.insert(document, edits);
            }
            DocumentData::Bib(data) => {
                let root = data.root(context.db);
                let edits: Vec<_> = root
                    .descendants()
                    .filter_map(bibtex::Entry::cast)
                    .filter_map(|entry| entry.name_token())
                    .filter(|key| key.text() == key_text)
                    .map(|key| Indel {
                        delete: key.text_range(),
                        insert: context.params.new_name.clone(),
                    })
                    .collect();
                changes.insert(document, edits);
            }
            DocumentData::Log(_) => {}
        }
    }

    Some(RenameResult { changes })
}