summaryrefslogtreecommitdiff
path: root/support/texlab/src/db/analysis/label.rs
blob: 77ee5268eb0da330821175e4da967153d833ba34 (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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use rowan::{
    ast::{AstNode, AstPtr},
    TextRange,
};

use crate::{db::Word, syntax::latex, Db};

#[salsa::tracked]
pub struct Number {
    pub name: Word,
    pub text: Word,
}

impl Number {
    pub(super) fn of_number(
        db: &dyn Db,
        node: latex::SyntaxNode,
        results: &mut Vec<Self>,
    ) -> Option<()> {
        let number = latex::LabelNumber::cast(node)?;
        let name = number.name()?.key()?.to_string();
        let text = number
            .text()?
            .syntax()
            .descendants_with_tokens()
            .filter_map(|element| element.into_node())
            .find(|node| node.kind() == latex::TEXT || node.kind() == latex::MIXED_GROUP)?
            .text()
            .to_string();

        results.push(Self::new(db, Word::new(db, name), Word::new(db, text)));

        Some(())
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum Origin {
    Definition(AstPtr<latex::LabelDefinition>),
    Reference(AstPtr<latex::LabelReference>),
    ReferenceRange(AstPtr<latex::LabelReferenceRange>),
}

impl Origin {
    pub fn as_definition(&self) -> Option<&AstPtr<latex::LabelDefinition>> {
        match self {
            Self::Definition(ptr) => Some(ptr),
            _ => None,
        }
    }
}

#[salsa::tracked]
pub struct Name {
    pub origin: Origin,
    pub name: Word,
    pub range: TextRange,
}

impl Name {
    pub(super) fn of_definition(
        db: &dyn Db,
        node: latex::SyntaxNode,
        results: &mut Vec<Self>,
    ) -> Option<()> {
        let label = latex::LabelDefinition::cast(node)?;
        let name = label.name()?.key()?;
        results.push(Self::new(
            db,
            Origin::Definition(AstPtr::new(&label)),
            Word::new(db, name.to_string()),
            latex::small_range(&name),
        ));

        Some(())
    }

    pub(super) fn of_reference(
        db: &dyn Db,
        node: latex::SyntaxNode,
        results: &mut Vec<Self>,
    ) -> Option<()> {
        let label = latex::LabelReference::cast(node)?;
        for name in label.name_list()?.keys() {
            results.push(Self::new(
                db,
                Origin::Reference(AstPtr::new(&label)),
                Word::new(db, name.to_string()),
                latex::small_range(&name),
            ));
        }

        Some(())
    }

    pub(super) fn of_reference_range(
        db: &dyn Db,
        node: latex::SyntaxNode,
        results: &mut Vec<Self>,
    ) -> Option<()> {
        let label = latex::LabelReferenceRange::cast(node)?;
        if let Some(name) = label.from().and_then(|name| name.key()) {
            results.push(Self::new(
                db,
                Origin::ReferenceRange(AstPtr::new(&label)),
                Word::new(db, name.to_string()),
                latex::small_range(&name),
            ));
        }

        if let Some(name) = label.to().and_then(|name| name.key()) {
            results.push(Self::new(
                db,
                Origin::ReferenceRange(AstPtr::new(&label)),
                Word::new(db, name.to_string()),
                latex::small_range(&name),
            ));
        }

        Some(())
    }
}