Skip to content

Commit fd858f5

Browse files
committed
support workspace/diagnostic
1 parent 9ef30ae commit fd858f5

File tree

14 files changed

+388
-89
lines changed

14 files changed

+388
-89
lines changed

crates/emmylua_ls/src/context/client.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,8 @@ impl ClientProxy {
156156
let request_id = self.next_id();
157157
self.send_request_no_wait(request_id, method, params);
158158
}
159+
160+
pub fn refresh_workspace_diagnostics(&self) {
161+
self.send_request_no_response("workspace/diagnostic/refresh", ());
162+
}
159163
}

crates/emmylua_ls/src/context/file_diagnostic.rs

Lines changed: 144 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ impl FileDiagnostic {
8686
}
8787

8888
/// 清除指定文件的诊断信息
89-
pub fn clear_file_diagnostics(&self, uri: lsp_types::Uri) {
89+
pub fn clear_push_file_diagnostics(&self, uri: lsp_types::Uri) {
9090
let diagnostic_param = lsp_types::PublishDiagnosticsParams {
9191
uri,
9292
diagnostics: vec![],
@@ -112,7 +112,7 @@ impl FileDiagnostic {
112112
tokio::spawn(async move {
113113
tokio::select! {
114114
_ = tokio::time::sleep(Duration::from_millis(interval)) => {
115-
workspace_diagnostic(analysis, client_proxy, status_bar, silent, cancel_token).await
115+
push_workspace_diagnostic(analysis, client_proxy, status_bar, silent, cancel_token).await
116116
}
117117
_ = cancel_token.cancelled() => {
118118
log::info!("cancel workspace diagnostic");
@@ -130,6 +130,15 @@ impl FileDiagnostic {
130130
tokens.clear();
131131
}
132132

133+
pub async fn cancel_workspace_diagnostic(&self) {
134+
let mut token = self.workspace_diagnostic_token.lock().await;
135+
if let Some(token) = token.as_ref() {
136+
token.cancel();
137+
debug!("cancel workspace diagnostic");
138+
}
139+
token.take();
140+
}
141+
133142
pub async fn pull_file_diagnostics(
134143
&self,
135144
uri: Uri,
@@ -140,14 +149,137 @@ impl FileDiagnostic {
140149
return vec![];
141150
};
142151

143-
self.clear_file_diagnostics(uri);
144-
145152
let diagnostics = analysis.diagnose_file(file_id, cancel_token);
146153
diagnostics.unwrap_or_default()
147154
}
155+
156+
pub async fn pull_workspace_diagnostics_slow(
157+
&self,
158+
cancel_token: CancellationToken,
159+
) -> Vec<(Uri, Vec<Diagnostic>)> {
160+
let mut token = self.workspace_diagnostic_token.lock().await;
161+
if let Some(token) = token.as_ref() {
162+
token.cancel();
163+
debug!("cancel workspace diagnostic");
164+
}
165+
token.replace(cancel_token.clone());
166+
drop(token);
167+
168+
let mut result = Vec::new();
169+
let analysis = self.analysis.read().await;
170+
let main_workspace_file_ids = analysis
171+
.compilation
172+
.get_db()
173+
.get_module_index()
174+
.get_main_workspace_file_ids();
175+
drop(analysis);
176+
177+
for file_id in main_workspace_file_ids {
178+
if cancel_token.is_cancelled() {
179+
break;
180+
}
181+
let analysis = self.analysis.read().await;
182+
if let Some(uri) = analysis.get_uri(file_id) {
183+
let diagnostics = analysis.diagnose_file(file_id, cancel_token.clone());
184+
if let Some(diagnostics) = diagnostics {
185+
result.push((uri, diagnostics));
186+
}
187+
}
188+
}
189+
190+
result
191+
}
192+
193+
pub async fn pull_workspace_diagnostics_fast(
194+
&self,
195+
cancel_token: CancellationToken,
196+
) -> Vec<(Uri, Vec<Diagnostic>)> {
197+
let mut token = self.workspace_diagnostic_token.lock().await;
198+
if let Some(token) = token.as_ref() {
199+
token.cancel();
200+
debug!("cancel workspace diagnostic");
201+
}
202+
token.replace(cancel_token.clone());
203+
drop(token);
204+
205+
let mut result = Vec::new();
206+
let analysis = self.analysis.read().await;
207+
let main_workspace_file_ids = analysis
208+
.compilation
209+
.get_db()
210+
.get_module_index()
211+
.get_main_workspace_file_ids();
212+
drop(analysis);
213+
214+
let status_bar = self.status_bar.clone();
215+
status_bar
216+
.create_progress_task(ProgressTask::DiagnoseWorkspace)
217+
.await;
218+
219+
let (tx, mut rx) = tokio::sync::mpsc::channel::<Option<(Vec<Diagnostic>, Uri)>>(100);
220+
let valid_file_count = main_workspace_file_ids.len();
221+
if valid_file_count == 0 {
222+
return result;
223+
}
224+
225+
let analysis = self.analysis.clone();
226+
for file_id in main_workspace_file_ids {
227+
let analysis = analysis.clone();
228+
let token = cancel_token.clone();
229+
let tx = tx.clone();
230+
tokio::spawn(async move {
231+
let analysis = analysis.read().await;
232+
let diagnostics = analysis.diagnose_file(file_id, token);
233+
if let Some(diagnostics) = diagnostics {
234+
let uri = analysis.get_uri(file_id).unwrap();
235+
let _ = tx.send(Some((diagnostics, uri))).await;
236+
} else {
237+
let _ = tx.send(None).await;
238+
}
239+
});
240+
}
241+
242+
let mut count = 0;
243+
if valid_file_count != 0 {
244+
let text = format!("diagnose {} files", valid_file_count);
245+
let _p = Profile::new(text.as_str());
246+
let mut last_percentage = 0;
247+
while let Some(file_diagnostic_result) = rx.recv().await {
248+
if cancel_token.is_cancelled() {
249+
break;
250+
}
251+
252+
if let Some((diagnostics, uri)) = file_diagnostic_result {
253+
result.push((uri, diagnostics));
254+
}
255+
256+
count += 1;
257+
let percentage_done = ((count as f32 / valid_file_count as f32) * 100.0) as u32;
258+
if last_percentage != percentage_done {
259+
last_percentage = percentage_done;
260+
let message = format!("diagnostic {}%", percentage_done);
261+
status_bar.update_progress_task(
262+
ProgressTask::DiagnoseWorkspace,
263+
Some(percentage_done),
264+
Some(message),
265+
);
266+
}
267+
if count == valid_file_count {
268+
break;
269+
}
270+
}
271+
}
272+
273+
status_bar.finish_progress_task(
274+
ProgressTask::DiagnoseWorkspace,
275+
Some("Diagnosis complete".to_string()),
276+
);
277+
278+
result
279+
}
148280
}
149281

150-
async fn workspace_diagnostic(
282+
async fn push_workspace_diagnostic(
151283
analysis: Arc<RwLock<EmmyLuaAnalysis>>,
152284
client_proxy: Arc<ClientProxy>,
153285
status_bar: Arc<StatusBar>,
@@ -217,13 +349,16 @@ async fn workspace_diagnostic(
217349
);
218350
}
219351
if count == valid_file_count {
220-
status_bar.finish_progress_task(
221-
ProgressTask::DiagnoseWorkspace,
222-
Some("Diagnosis complete".to_string()),
223-
);
224352
break;
225353
}
226354
}
227355
}
228356
}
357+
358+
if !silent {
359+
status_bar.finish_progress_task(
360+
ProgressTask::DiagnoseWorkspace,
361+
Some("Diagnosis complete".to_string()),
362+
);
363+
}
229364
}

crates/emmylua_ls/src/context/lsp_features.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,25 @@ impl LspFeatures {
3333
false
3434
}
3535

36-
pub fn supports_pull_diagnostics(&self) -> bool {
36+
pub fn supports_pull_diagnostic(&self) -> bool {
3737
if let Some(text_document) = &self.client_capabilities.text_document {
3838
return text_document.diagnostic.is_some();
3939
}
4040
false
4141
}
42+
43+
pub fn supports_workspace_diagnostic(&self) -> bool {
44+
self.supports_pull_diagnostic()
45+
}
46+
47+
pub fn supports_refresh_diagnostic(&self) -> bool {
48+
if let Some(workspace) = &self.client_capabilities.workspace {
49+
if let Some(diagnostic) = &workspace.diagnostic {
50+
if let Some(supports) = diagnostic.refresh_support {
51+
return supports;
52+
}
53+
}
54+
}
55+
false
56+
}
4257
}

crates/emmylua_ls/src/context/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub use client::ClientProxy;
1010
pub use client_id::{ClientId, get_client_id};
1111
use emmylua_code_analysis::EmmyLuaAnalysis;
1212
pub use file_diagnostic::FileDiagnostic;
13+
pub use lsp_features::LspFeatures;
1314
use lsp_server::{Connection, ErrorCode, Message, RequestId, Response};
1415
use lsp_types::ClientCapabilities;
1516
pub use snapshot::ServerContextSnapshot;
@@ -18,11 +19,8 @@ pub use status_bar::StatusBar;
1819
use std::{collections::HashMap, future::Future, sync::Arc};
1920
use tokio::sync::{Mutex, RwLock};
2021
use tokio_util::sync::CancellationToken;
21-
pub use workspace_manager::WorkspaceFileMatcher;
22-
pub use workspace_manager::WorkspaceManager;
23-
pub use workspace_manager::load_emmy_config;
22+
pub use workspace_manager::*;
2423

25-
use crate::context::lsp_features::LspFeatures;
2624
use crate::context::snapshot::ServerContextInner;
2725

2826
pub struct ServerContext {
@@ -46,13 +44,14 @@ impl ServerContext {
4644
status_bar.clone(),
4745
client.clone(),
4846
));
47+
let lsp_features = Arc::new(LspFeatures::new(client_capabilities));
4948
let workspace_manager = Arc::new(RwLock::new(WorkspaceManager::new(
5049
analysis.clone(),
5150
client.clone(),
5251
status_bar.clone(),
5352
file_diagnostic.clone(),
53+
lsp_features.clone(),
5454
)));
55-
let lsp_features = Arc::new(LspFeatures::new(client_capabilities));
5655

5756
ServerContext {
5857
conn,

0 commit comments

Comments
 (0)