From 5f53c3c83e64c7791fa98e0cf4411725a1a1d7e9 Mon Sep 17 00:00:00 2001 From: oxalica Date: Mon, 26 Sep 2022 00:23:46 +0800 Subject: [PATCH] Recalculate all diagnostics after config change --- crates/nil/src/handler.rs | 19 ++++++++--- crates/nil/src/state.rs | 68 +++++++++++++++++++++++++-------------- 2 files changed, 59 insertions(+), 28 deletions(-) diff --git a/crates/nil/src/handler.rs b/crates/nil/src/handler.rs index 49a0834..d38a03b 100644 --- a/crates/nil/src/handler.rs +++ b/crates/nil/src/handler.rs @@ -1,13 +1,24 @@ use crate::{convert, Result, StateSnapshot}; use ide::FileRange; use lsp_types::{ - CompletionParams, CompletionResponse, GotoDefinitionParams, GotoDefinitionResponse, Hover, - HoverParams, Location, PrepareRenameResponse, ReferenceParams, RenameParams, SelectionRange, - SelectionRangeParams, SemanticTokens, SemanticTokensParams, SemanticTokensRangeParams, - SemanticTokensRangeResult, SemanticTokensResult, TextDocumentPositionParams, WorkspaceEdit, + CompletionParams, CompletionResponse, Diagnostic, GotoDefinitionParams, GotoDefinitionResponse, + Hover, HoverParams, Location, PrepareRenameResponse, ReferenceParams, RenameParams, + SelectionRange, SelectionRangeParams, SemanticTokens, SemanticTokensParams, + SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, + TextDocumentPositionParams, Url, WorkspaceEdit, }; use text_size::TextRange; +const MAX_DIAGNOSTICS_CNT: usize = 128; + +pub(crate) fn diagnostics(snap: StateSnapshot, uri: &Url) -> Result> { + let file = snap.vfs().file_for_uri(uri)?; + let mut diags = snap.analysis.diagnostics(file)?; + diags.retain(|diag| !snap.config.diagnostics_ignored.contains(diag.code())); + diags.truncate(MAX_DIAGNOSTICS_CNT); + Ok(convert::to_diagnostics(&snap.vfs(), file, &diags)) +} + pub(crate) fn goto_definition( snap: StateSnapshot, params: GotoDefinitionParams, diff --git a/crates/nil/src/state.rs b/crates/nil/src/state.rs index c65b714..5f194a6 100644 --- a/crates/nil/src/state.rs +++ b/crates/nil/src/state.rs @@ -15,13 +15,12 @@ use std::path::PathBuf; use std::sync::{Arc, Once, RwLock}; use std::{fs, panic}; -const MAX_DIAGNOSTICS_CNT: usize = 128; const FILTER_FILE_EXTENTION: &str = "nix"; const CONFIG_KEY: &str = "nil"; -#[derive(Debug, Default, Deserialize)] +#[derive(Debug, Clone, Default, Deserialize)] pub struct Config { - diagnostics_ignored: HashSet, + pub(crate) diagnostics_ignored: HashSet, } type ReqHandler = fn(&mut State, Response); @@ -34,7 +33,7 @@ pub struct State { req_queue: ReqQueue<(), ReqHandler>, sender: Sender, is_shutdown: bool, - config: Config, + config: Arc, } impl State { @@ -50,7 +49,7 @@ impl State { req_queue: ReqQueue::default(), sender: responder, is_shutdown: false, - config: Config::default(), + config: Arc::new(Config::default()), } } @@ -220,9 +219,14 @@ impl State { } fn update_config(&mut self, mut v: serde_json::Value) { + let mut updated_diagnostics = false; + let mut config = Config::clone(&self.config); if let Some(v) = v.pointer_mut("/diagnostics/ignored") { match serde_json::from_value(v.take()) { - Ok(v) => self.config.diagnostics_ignored = v, + Ok(v) => { + config.diagnostics_ignored = v; + updated_diagnostics = true; + } Err(e) => { self.show_message( MessageType::ERROR, @@ -231,13 +235,31 @@ impl State { } } } + self.config = Arc::new(config); tracing::debug!("Updated config: {:?}", self.config); + + // Refresh all diagnostics since the filter may be changed. + if updated_diagnostics { + for uri in &*self.opened_files.read().unwrap() { + tracing::debug!("Recalculate diagnostics of {uri}"); + + let snap = self.snapshot(); + // TODO: Error is ignored. + let diagnostics = handler::diagnostics(snap, uri).unwrap_or_default(); + self.send_notification::(PublishDiagnosticsParams { + uri: uri.clone(), + diagnostics, + version: None, + }); + } + } } fn snapshot(&self) -> StateSnapshot { StateSnapshot { analysis: self.host.snapshot(), vfs: Arc::clone(&self.vfs), + config: Arc::clone(&self.config), } } @@ -248,34 +270,31 @@ impl State { } fn apply_vfs_change(&mut self) { - let mut vfs = self.vfs.write().unwrap(); - let change = vfs.take_change(); - let file_changes = change - .file_changes - .iter() - .map(|(file, text)| (*file, !text.is_empty())) - .collect::>(); - tracing::debug!("Change: {:?}", change); - self.host.apply_change(change); + let file_changes = { + let mut vfs = self.vfs.write().unwrap(); + let change = vfs.take_change(); + let file_changes = change + .file_changes + .iter() + .map(|(file, text)| (vfs.uri_for_file(*file), !text.is_empty())) + .collect::>(); + tracing::debug!("Change: {:?}", change); + self.host.apply_change(change); + file_changes + }; - let snap = self.host.snapshot(); let opened_files = self.opened_files.read().unwrap(); - for (file, has_text) in file_changes { - let uri = vfs.uri_for_file(file); + for (uri, has_text) in file_changes { if !opened_files.contains(&uri) { continue; } // TODO: Error is ignored. let diagnostics = has_text - .then(|| { - let mut diags = snap.diagnostics(file).ok()?; - diags.retain(|diag| !self.config.diagnostics_ignored.contains(diag.code())); - diags.truncate(MAX_DIAGNOSTICS_CNT); - Some(convert::to_diagnostics(&vfs, file, &diags)) - }) + .then(|| handler::diagnostics(self.snapshot(), &uri).ok()) .flatten() .unwrap_or_default(); + self.send_notification::(PublishDiagnosticsParams { uri, diagnostics, @@ -422,6 +441,7 @@ fn result_to_response(id: RequestId, ret: Result) -> Result>, + pub(crate) config: Arc, } impl StateSnapshot {