summaryrefslogtreecommitdiff
path: root/support/texlab/src/document.rs
blob: adb6bad5ac6361a02a1d27c7696d0f285249bd0b (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
123
124
125
126
127
128
129
130
131
use std::{fmt, sync::Arc};

use derive_more::From;
use lsp_types::Url;

use crate::{
    line_index::LineIndex,
    syntax::{
        bibtex, build_log,
        latex::{self, LatexAnalyzerContext},
    },
    DocumentLanguage, Environment,
};

#[derive(Debug, Clone)]
pub struct LatexDocumentData {
    pub green: rowan::GreenNode,
    pub extras: Arc<latex::Extras>,
}

#[derive(Debug, Clone)]
pub struct BibtexDocumentData {
    pub green: rowan::GreenNode,
}

#[derive(Debug, Clone, From)]
pub enum DocumentData {
    Latex(Box<LatexDocumentData>),
    Bibtex(BibtexDocumentData),
    BuildLog(Arc<build_log::Parse>),
}

impl DocumentData {
    pub fn language(&self) -> DocumentLanguage {
        match self {
            Self::Latex(_) => DocumentLanguage::Latex,
            Self::Bibtex(_) => DocumentLanguage::Bibtex,
            Self::BuildLog(_) => DocumentLanguage::BuildLog,
        }
    }

    pub fn as_latex(&self) -> Option<&LatexDocumentData> {
        if let Self::Latex(data) = self {
            Some(data)
        } else {
            None
        }
    }

    pub fn as_bibtex(&self) -> Option<&BibtexDocumentData> {
        if let Self::Bibtex(data) = self {
            Some(data)
        } else {
            None
        }
    }

    pub fn as_build_log(&self) -> Option<&build_log::Parse> {
        if let Self::BuildLog(v) = self {
            Some(v)
        } else {
            None
        }
    }
}

#[derive(Clone)]
pub struct Document {
    pub uri: Arc<Url>,
    pub text: Arc<String>,
    pub line_index: Arc<LineIndex>,
    pub data: DocumentData,
}

impl fmt::Debug for Document {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.uri)
    }
}

impl Document {
    pub fn parse(
        environment: &Environment,
        uri: Arc<Url>,
        text: Arc<String>,
        language: DocumentLanguage,
    ) -> Self {
        let line_index = Arc::new(LineIndex::new(&text));
        let data = match language {
            DocumentLanguage::Latex => {
                let green = latex::parse(&text).green;
                let root = latex::SyntaxNode::new_root(green.clone());

                let base_uri = match &environment.options.root_directory {
                    Some(root_dir) => {
                        let root_dir = environment.current_directory.join(&root_dir);
                        Url::from_directory_path(root_dir)
                            .map(Arc::new)
                            .unwrap_or_else(|()| Arc::clone(&uri))
                    }
                    None => Arc::clone(&uri),
                };

                let mut context = LatexAnalyzerContext {
                    environment,
                    extras: latex::Extras::default(),
                    document_uri: Arc::clone(&uri),
                    base_uri,
                };
                latex::analyze(&mut context, &root);
                let extras = Arc::new(context.extras);
                DocumentData::Latex(Box::new(LatexDocumentData { green, extras }))
            }
            DocumentLanguage::Bibtex => {
                let green = bibtex::parse(&text);
                DocumentData::Bibtex(BibtexDocumentData { green })
            }
            DocumentLanguage::BuildLog => {
                let data = Arc::new(build_log::parse(&text));
                DocumentData::BuildLog(data)
            }
        };

        Self {
            uri,
            text,
            line_index,
            data,
        }
    }
}