From a3d49af2089159e44332e099b902e24b59787b44 Mon Sep 17 00:00:00 2001 From: "Andrei G." Date: Wed, 29 Apr 2026 14:40:08 +0200 Subject: [PATCH 1/2] fix: sync clippy.toml msrv with Cargo.toml rust-version Update msrv from "1.85" to "1.88" to match workspace rust-version bumped in commit 5d938b9. Eliminates the MSRV mismatch warning on every clippy run and ensures linting targets the correct API surface. Closes #107 --- clippy.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy.toml b/clippy.toml index 5be6fe6..242a4ed 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,5 +1,5 @@ # Clippy configuration # See: https://doc.rust-lang.org/clippy/configuration.html -msrv = "1.85" +msrv = "1.88" cognitive-complexity-threshold = 25 From d4c9b54848f81f25c3aa3438275285ed88afbb3b Mon Sep 17 00:00:00 2001 From: "Andrei G." Date: Wed, 29 Apr 2026 14:40:19 +0200 Subject: [PATCH 2/2] fix(bridge): pass extension map to Translator in integration tests setup_rust_analyzer() called Translator::new() which initializes with an empty extension_map. detect_language() fell back to "plaintext" for .rs files, so the client registered under "rust" could not be found, causing NoServerForLanguage("plaintext") in 12 of 19 tests. Fix: chain with_extensions({"rs" => "rust"}) on the test Translator to match the registration key used in setup_rust_analyzer(). Also applies let-chain flattening (if let A && let B) across translator, config, lsp modules to remove nested if-let blocks now valid under Rust 1.88 (MSRV bump from #107). Closes #106 --- crates/mcpls-core/src/bridge/translator.rs | 34 +++++++++---------- crates/mcpls-core/src/config/server.rs | 19 +++++------ crates/mcpls-core/src/lsp/client.rs | 28 +++++++-------- crates/mcpls-core/src/lsp/lifecycle.rs | 2 +- crates/mcpls-core/src/lsp/types.rs | 24 ++++++------- .../tests/integration/rust_analyzer_tests.rs | 3 +- 6 files changed, 54 insertions(+), 56 deletions(-) diff --git a/crates/mcpls-core/src/bridge/translator.rs b/crates/mcpls-core/src/bridge/translator.rs index a9e0539..70a07db 100644 --- a/crates/mcpls-core/src/bridge/translator.rs +++ b/crates/mcpls-core/src/bridge/translator.rs @@ -441,10 +441,10 @@ impl Translator { // Check if path is within any workspace root for root in &self.workspace_roots { - if let Ok(canonical_root) = root.canonicalize() { - if canonical.starts_with(&canonical_root) { - return Ok(canonical); - } + if let Ok(canonical_root) = root.canonicalize() + && canonical.starts_with(&canonical_root) + { + return Ok(canonical); } } @@ -995,15 +995,14 @@ impl Translator { } // Validate kind filter - if let Some(ref kind) = kind_filter { - if !VALID_SYMBOL_KINDS + if let Some(ref kind) = kind_filter + && !VALID_SYMBOL_KINDS .iter() .any(|k| k.eq_ignore_ascii_case(kind)) - { - return Err(Error::InvalidToolParams(format!( - "Invalid kind_filter: '{kind}'. Valid values: {VALID_SYMBOL_KINDS:?}" - ))); - } + { + return Err(Error::InvalidToolParams(format!( + "Invalid kind_filter: '{kind}'. Valid values: {VALID_SYMBOL_KINDS:?}" + ))); } // Workspace search requires at least one LSP client @@ -1075,15 +1074,14 @@ impl Translator { ]; // Validate kind filter - if let Some(ref kind) = kind_filter { - if !VALID_ACTION_KINDS + if let Some(ref kind) = kind_filter + && !VALID_ACTION_KINDS .iter() .any(|k| k.eq_ignore_ascii_case(kind)) - { - return Err(Error::InvalidToolParams(format!( - "Invalid kind_filter: '{kind}'. Valid values: {VALID_ACTION_KINDS:?}" - ))); - } + { + return Err(Error::InvalidToolParams(format!( + "Invalid kind_filter: '{kind}'. Valid values: {VALID_ACTION_KINDS:?}" + ))); } // Validate range diff --git a/crates/mcpls-core/src/config/server.rs b/crates/mcpls-core/src/config/server.rs index f6c5da6..ecd14d2 100644 --- a/crates/mcpls-core/src/config/server.rs +++ b/crates/mcpls-core/src/config/server.rs @@ -118,12 +118,11 @@ impl ServerHeuristics { .standard_filters(false) .filter_entry(|entry| { // Skip excluded directories entirely (prevents descending into them) - if entry.file_type().is_some_and(|ft| ft.is_dir()) { - if let Some(name) = entry.file_name().to_str() { - if EXCLUDED_DIRECTORIES.contains(&name) { - return false; - } - } + if entry.file_type().is_some_and(|ft| ft.is_dir()) + && let Some(name) = entry.file_name().to_str() + && EXCLUDED_DIRECTORIES.contains(&name) + { + return false; } true }); @@ -132,10 +131,10 @@ impl ServerHeuristics { let path = entry.path(); // Check if this entry matches any marker - if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) { - if self.project_markers.iter().any(|m| m == file_name) { - return true; - } + if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) + && self.project_markers.iter().any(|m| m == file_name) + { + return true; } } diff --git a/crates/mcpls-core/src/lsp/client.rs b/crates/mcpls-core/src/lsp/client.rs index 786d3d7..713460d 100644 --- a/crates/mcpls-core/src/lsp/client.rs +++ b/crates/mcpls-core/src/lsp/client.rs @@ -620,13 +620,13 @@ mod tests { }; let sender = pending_requests.lock().await.remove(&error_response.id); - if let Some(sender) = sender { - if let Some(error) = error_response.error { - let _ = sender.send(Err(Error::LspServerError { - code: error.code, - message: error.message, - })); - } + if let Some(sender) = sender + && let Some(error) = error_response.error + { + let _ = sender.send(Err(Error::LspServerError { + code: error.code, + message: error.message, + })); } let result = response_rx.await.unwrap(); @@ -682,13 +682,13 @@ mod tests { }; let sender = pending_requests.lock().await.remove(&error_response.id); - if let Some(sender) = sender { - if let Some(error) = error_response.error { - let _ = sender.send(Err(Error::LspServerError { - code: error.code, - message: error.message, - })); - } + if let Some(sender) = sender + && let Some(error) = error_response.error + { + let _ = sender.send(Err(Error::LspServerError { + code: error.code, + message: error.message, + })); } let result = response_rx.await.unwrap(); diff --git a/crates/mcpls-core/src/lsp/lifecycle.rs b/crates/mcpls-core/src/lsp/lifecycle.rs index fcef85b..ed924a1 100644 --- a/crates/mcpls-core/src/lsp/lifecycle.rs +++ b/crates/mcpls-core/src/lsp/lifecycle.rs @@ -139,7 +139,7 @@ impl ServerInitResult { /// Get the number of failures. #[must_use] - pub fn failure_count(&self) -> usize { + pub const fn failure_count(&self) -> usize { self.failures.len() } diff --git a/crates/mcpls-core/src/lsp/types.rs b/crates/mcpls-core/src/lsp/types.rs index e2adaf3..2a9c5a1 100644 --- a/crates/mcpls-core/src/lsp/types.rs +++ b/crates/mcpls-core/src/lsp/types.rs @@ -137,10 +137,10 @@ impl LspNotification { pub fn parse(method: &str, params: Option) -> Self { match method { "textDocument/publishDiagnostics" => { - if let Some(p) = params { - if let Ok(parsed) = serde_json::from_value(p) { - return Self::PublishDiagnostics(parsed); - } + if let Some(p) = params + && let Ok(parsed) = serde_json::from_value(p) + { + return Self::PublishDiagnostics(parsed); } Self::Other { method: Cow::Owned(method.to_string()), @@ -148,10 +148,10 @@ impl LspNotification { } } "window/logMessage" => { - if let Some(p) = params { - if let Ok(parsed) = serde_json::from_value(p) { - return Self::LogMessage(parsed); - } + if let Some(p) = params + && let Ok(parsed) = serde_json::from_value(p) + { + return Self::LogMessage(parsed); } Self::Other { method: Cow::Owned(method.to_string()), @@ -159,10 +159,10 @@ impl LspNotification { } } "window/showMessage" => { - if let Some(p) = params { - if let Ok(parsed) = serde_json::from_value(p) { - return Self::ShowMessage(parsed); - } + if let Some(p) = params + && let Ok(parsed) = serde_json::from_value(p) + { + return Self::ShowMessage(parsed); } Self::Other { method: Cow::Owned(method.to_string()), diff --git a/crates/mcpls-core/tests/integration/rust_analyzer_tests.rs b/crates/mcpls-core/tests/integration/rust_analyzer_tests.rs index 12a3e79..33c8c09 100644 --- a/crates/mcpls-core/tests/integration/rust_analyzer_tests.rs +++ b/crates/mcpls-core/tests/integration/rust_analyzer_tests.rs @@ -69,7 +69,8 @@ async fn setup_rust_analyzer() -> Arc> { let client = server.client().clone(); - let mut translator = Translator::new(); + let extension_map = std::collections::HashMap::from([("rs".to_string(), "rust".to_string())]); + let mut translator = Translator::new().with_extensions(extension_map); translator.set_workspace_roots(vec![workspace_path]); translator.register_client("rust".to_string(), client); translator.register_server("rust".to_string(), server);