emmylua_code_analysis/
lib.rs

1mod compilation;
2mod config;
3mod db_index;
4mod diagnostic;
5mod locale;
6mod profile;
7mod resources;
8mod semantic;
9mod test_lib;
10mod vfs;
11
12pub use compilation::*;
13pub use config::*;
14pub use db_index::*;
15pub use diagnostic::*;
16pub use emmylua_codestyle::*;
17pub use locale::get_locale_code;
18use lsp_types::Uri;
19pub use profile::Profile;
20use resources::load_resource_std;
21pub use semantic::*;
22use std::{collections::HashSet, path::PathBuf, sync::Arc};
23pub use test_lib::VirtualWorkspace;
24use tokio_util::sync::CancellationToken;
25pub use vfs::*;
26
27#[macro_use]
28extern crate rust_i18n;
29
30rust_i18n::i18n!("./locales", fallback = "en");
31
32pub fn set_locale(locale: &str) {
33    rust_i18n::set_locale(locale);
34}
35
36#[derive(Debug)]
37pub struct EmmyLuaAnalysis {
38    pub compilation: LuaCompilation,
39    pub diagnostic: LuaDiagnostic,
40    pub emmyrc: Arc<Emmyrc>,
41    lib_workspace_counter: u32,
42}
43
44impl EmmyLuaAnalysis {
45    pub fn new() -> Self {
46        let emmyrc = Arc::new(Emmyrc::default());
47        Self {
48            compilation: LuaCompilation::new(emmyrc.clone()),
49            diagnostic: LuaDiagnostic::new(),
50            emmyrc,
51            lib_workspace_counter: 2,
52        }
53    }
54
55    pub fn init_std_lib(&mut self, allow_create_resources_dir: bool) {
56        let (std_root, files) = load_resource_std(allow_create_resources_dir);
57        self.compilation
58            .get_db_mut()
59            .get_module_index_mut()
60            .add_workspace_root(std_root, WorkspaceId::STD);
61
62        let files = files
63            .into_iter()
64            .filter_map(|file| {
65                if file.path.ends_with(".lua") {
66                    Some((PathBuf::from(file.path), Some(file.content)))
67                } else {
68                    None
69                }
70            })
71            .collect::<Vec<_>>();
72        self.update_files_by_path(files);
73    }
74
75    pub fn get_file_id(&self, uri: &Uri) -> Option<FileId> {
76        self.compilation.get_db().get_vfs().get_file_id(uri)
77    }
78
79    pub fn get_uri(&self, file_id: FileId) -> Option<Uri> {
80        self.compilation.get_db().get_vfs().get_uri(&file_id)
81    }
82
83    pub fn add_main_workspace(&mut self, root: PathBuf) {
84        self.compilation
85            .get_db_mut()
86            .get_module_index_mut()
87            .add_workspace_root(root, WorkspaceId::MAIN);
88    }
89
90    pub fn add_library_workspace(&mut self, root: PathBuf) {
91        let id = WorkspaceId {
92            id: self.lib_workspace_counter,
93        };
94        self.lib_workspace_counter += 1;
95
96        self.compilation
97            .get_db_mut()
98            .get_module_index_mut()
99            .add_workspace_root(root, id);
100    }
101
102    pub fn update_file_by_uri(&mut self, uri: &Uri, text: Option<String>) -> Option<FileId> {
103        let is_removed = text.is_none();
104        let file_id = self
105            .compilation
106            .get_db_mut()
107            .get_vfs_mut()
108            .set_file_content(uri, text);
109
110        self.compilation.remove_index(vec![file_id]);
111        if !is_removed {
112            self.compilation.update_index(vec![file_id]);
113        }
114
115        Some(file_id)
116    }
117
118    pub fn update_file_by_path(&mut self, path: &PathBuf, text: Option<String>) -> Option<FileId> {
119        let uri = file_path_to_uri(&path)?;
120        self.update_file_by_uri(&uri, text)
121    }
122
123    pub fn update_files_by_uri(&mut self, files: Vec<(Uri, Option<String>)>) -> Vec<FileId> {
124        let mut removed_files = HashSet::new();
125        let mut updated_files = HashSet::new();
126        {
127            let _p = Profile::new("update files");
128            for (uri, text) in files {
129                let is_new_text = text.is_some();
130                let file_id = self
131                    .compilation
132                    .get_db_mut()
133                    .get_vfs_mut()
134                    .set_file_content(&uri, text);
135                removed_files.insert(file_id);
136                if is_new_text {
137                    updated_files.insert(file_id);
138                }
139            }
140        }
141        self.compilation
142            .remove_index(removed_files.into_iter().collect());
143        let updated_files: Vec<FileId> = updated_files.into_iter().collect();
144        self.compilation.update_index(updated_files.clone());
145        updated_files
146    }
147
148    pub fn update_files_by_path(&mut self, files: Vec<(PathBuf, Option<String>)>) -> Vec<FileId> {
149        let files = files
150            .into_iter()
151            .filter_map(|(path, text)| {
152                let uri = file_path_to_uri(&path)?;
153                Some((uri, text))
154            })
155            .collect();
156        self.update_files_by_uri(files)
157    }
158
159    pub fn update_config(&mut self, config: Arc<Emmyrc>) {
160        self.emmyrc = config.clone();
161        self.compilation.update_config(config.clone());
162        self.diagnostic.update_config(config);
163    }
164
165    pub fn get_emmyrc(&self) -> Arc<Emmyrc> {
166        self.emmyrc.clone()
167    }
168
169    pub fn diagnose_file(
170        &self,
171        file_id: FileId,
172        cancel_token: CancellationToken,
173    ) -> Option<Vec<lsp_types::Diagnostic>> {
174        self.diagnostic
175            .diagnose_file(&self.compilation, file_id, cancel_token)
176    }
177
178    pub fn reindex(&mut self) {
179        let module = self.compilation.get_db().get_module_index();
180        let std_file_ids = module.get_std_file_ids();
181        let main_file_ids = module.get_main_workspace_file_ids();
182        let lib_file_ids = module.get_lib_file_ids();
183        self.compilation.clear_index();
184
185        self.compilation.update_index(std_file_ids);
186        self.compilation.update_index(lib_file_ids);
187        self.compilation.update_index(main_file_ids);
188    }
189}
190
191unsafe impl Send for EmmyLuaAnalysis {}
192unsafe impl Sync for EmmyLuaAnalysis {}