From 9fa2f43d066483c0351578316c0903c9f843e3ee Mon Sep 17 00:00:00 2001 From: zc he Date: Sat, 8 Feb 2025 20:49:38 +0800 Subject: [PATCH] fix(lsp): exit on null root_dir (#15051) # Description This PR fixes one reported bug of recent lsp changes. It exit unexpectedly with empty `root_dir` settings in neovim. # User-Facing Changes # Tests + Formatting +1 test case # After Submitting --- crates/nu-lsp/src/lib.rs | 8 +-- crates/nu-lsp/src/workspace.rs | 107 +++++++++++++++++++++------------ 2 files changed, 72 insertions(+), 43 deletions(-) diff --git a/crates/nu-lsp/src/lib.rs b/crates/nu-lsp/src/lib.rs index 5ba35e75ce..4762cc6ed8 100644 --- a/crates/nu-lsp/src/lib.rs +++ b/crates/nu-lsp/src/lib.rs @@ -151,7 +151,7 @@ impl LanguageServer { !self.initial_engine_state.signals().interrupted() }) .into_diagnostic()?; - self.initialize_workspace_folders(init_params)?; + self.initialize_workspace_folders(init_params); while !self.initial_engine_state.signals().interrupted() { // first check new messages from child thread @@ -730,7 +730,7 @@ mod tests { DidChangeTextDocument, DidOpenTextDocument, Exit, Initialized, Notification, }, request::{Completion, HoverRequest, Initialize, Request, Shutdown}, - CompletionParams, DidChangeTextDocumentParams, DidOpenTextDocumentParams, InitializeParams, + CompletionParams, DidChangeTextDocumentParams, DidOpenTextDocumentParams, InitializedParams, PartialResultParams, Position, TextDocumentContentChangeEvent, TextDocumentIdentifier, TextDocumentItem, TextDocumentPositionParams, WorkDoneProgressParams, @@ -740,7 +740,7 @@ mod tests { use std::time::Duration; pub(crate) fn initialize_language_server( - params: Option, + params: Option, ) -> (Connection, Receiver>) { use std::sync::mpsc; let (client_connection, server_connection) = Connection::memory(); @@ -757,7 +757,7 @@ mod tests { .send(Message::Request(lsp_server::Request { id: 1.into(), method: Initialize::METHOD.to_string(), - params: serde_json::to_value(params.unwrap_or_default()).unwrap(), + params: params.unwrap_or(serde_json::Value::Null), })) .unwrap(); client_connection diff --git a/crates/nu-lsp/src/workspace.rs b/crates/nu-lsp/src/workspace.rs index 9a8a943a03..65095bfe0b 100644 --- a/crates/nu-lsp/src/workspace.rs +++ b/crates/nu-lsp/src/workspace.rs @@ -50,15 +50,14 @@ impl LanguageServer { pub(crate) fn initialize_workspace_folders( &mut self, init_params: serde_json::Value, - ) -> Result<()> { + ) -> Option<()> { if let Some(array) = init_params.get("workspaceFolders") { - let folders: Vec = - serde_json::from_value(array.clone()).into_diagnostic()?; + let folders: Vec = serde_json::from_value(array.clone()).ok()?; for folder in folders { self.workspace_folders.insert(folder.name.clone(), folder); } } - Ok(()) + Some(()) } /// Highlight all occurrences of the text at cursor, in current file @@ -568,18 +567,36 @@ mod tests { .unwrap() } + /// Should not exit on malformed init_params + #[test] + fn malformed_init_params() { + let mut script = fixtures(); + script.push("lsp"); + script.push("workspace"); + let (client_connection, _recv) = initialize_language_server(Some( + serde_json::json!({ "workspaceFolders": serde_json::Value::Null }), + )); + script.push("foo.nu"); + let script = path_to_uri(&script); + + open_unchecked(&client_connection, script.clone()); + } + #[test] fn command_reference_in_workspace() { let mut script = fixtures(); script.push("lsp"); script.push("workspace"); - let (client_connection, _recv) = initialize_language_server(Some(InitializeParams { - workspace_folders: Some(vec![WorkspaceFolder { - uri: path_to_uri(&script), - name: "random name".to_string(), - }]), - ..Default::default() - })); + let (client_connection, _recv) = initialize_language_server( + serde_json::to_value(InitializeParams { + workspace_folders: Some(vec![WorkspaceFolder { + uri: path_to_uri(&script), + name: "random name".to_string(), + }]), + ..Default::default() + }) + .ok(), + ); script.push("foo.nu"); let script = path_to_uri(&script); @@ -620,13 +637,16 @@ mod tests { let mut script = fixtures(); script.push("lsp"); script.push("workspace"); - let (client_connection, _recv) = initialize_language_server(Some(InitializeParams { - workspace_folders: Some(vec![WorkspaceFolder { - uri: path_to_uri(&script), - name: "random name".to_string(), - }]), - ..Default::default() - })); + let (client_connection, _recv) = initialize_language_server( + serde_json::to_value(InitializeParams { + workspace_folders: Some(vec![WorkspaceFolder { + uri: path_to_uri(&script), + name: "random name".to_string(), + }]), + ..Default::default() + }) + .ok(), + ); script.push("foo.nu"); let script = path_to_uri(&script); @@ -667,13 +687,16 @@ mod tests { let mut script = fixtures(); script.push("lsp"); script.push("workspace"); - let (client_connection, _recv) = initialize_language_server(Some(InitializeParams { - workspace_folders: Some(vec![WorkspaceFolder { - uri: path_to_uri(&script), - name: "random name".to_string(), - }]), - ..Default::default() - })); + let (client_connection, _recv) = initialize_language_server( + serde_json::to_value(InitializeParams { + workspace_folders: Some(vec![WorkspaceFolder { + uri: path_to_uri(&script), + name: "random name".to_string(), + }]), + ..Default::default() + }) + .ok(), + ); script.push("foo.nu"); let script = path_to_uri(&script); @@ -742,13 +765,16 @@ mod tests { let mut script = fixtures(); script.push("lsp"); script.push("workspace"); - let (client_connection, _recv) = initialize_language_server(Some(InitializeParams { - workspace_folders: Some(vec![WorkspaceFolder { - uri: path_to_uri(&script), - name: "random name".to_string(), - }]), - ..Default::default() - })); + let (client_connection, _recv) = initialize_language_server( + serde_json::to_value(InitializeParams { + workspace_folders: Some(vec![WorkspaceFolder { + uri: path_to_uri(&script), + name: "random name".to_string(), + }]), + ..Default::default() + }) + .ok(), + ); script.push("foo.nu"); let script = path_to_uri(&script); @@ -807,13 +833,16 @@ mod tests { let mut script = fixtures(); script.push("lsp"); script.push("workspace"); - let (client_connection, _recv) = initialize_language_server(Some(InitializeParams { - workspace_folders: Some(vec![WorkspaceFolder { - uri: path_to_uri(&script), - name: "random name".to_string(), - }]), - ..Default::default() - })); + let (client_connection, _recv) = initialize_language_server( + serde_json::to_value(InitializeParams { + workspace_folders: Some(vec![WorkspaceFolder { + uri: path_to_uri(&script), + name: "random name".to_string(), + }]), + ..Default::default() + }) + .ok(), + ); script.push("foo.nu"); let script = path_to_uri(&script);