emmylua_code_analysis/
lib.rs1mod 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 {}