From 94e8c32862ea6145869cda06c1d64293e23859bd Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 13 Jul 2024 21:59:21 +0300 Subject: [PATCH] Do not send `textDocument/didSave` message if server does not declare its support (#14412) Release Notes: - Improved Zed logic for sending `textDocument/didSave` request ([14286](https://github.com/zed-industries/zed/issues/14286)) --- crates/lsp/src/lsp.rs | 6 ++- crates/project/src/project.rs | 59 ++++++++++++++++++----------- crates/project/src/project_tests.rs | 12 ++++++ 3 files changed, 53 insertions(+), 24 deletions(-) diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index f8c4e259fcc88b501d52042757fbda5799c8b0b6..26339de41a95d6a7c579459db8de54b99bab8133 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -649,7 +649,11 @@ impl LanguageServer { on_type_formatting: Some(DynamicRegistrationClientCapabilities { dynamic_registration: Some(true), }), - ..Default::default() + synchronization: Some(TextDocumentSyncClientCapabilities { + did_save: Some(true), + ..TextDocumentSyncClientCapabilities::default() + }), + ..TextDocumentClientCapabilities::default() }), experimental: Some(json!({ "serverStatusNotification": true, diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 4f5f32cdfb925a8b0fae86abb058c7d3cc15ba31..20043d14dd0df3bbb8d37e570371658fc4db45ee 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -2853,15 +2853,21 @@ impl Project { }; for (_, _, server) in self.language_servers_for_worktree(worktree_id) { - let text = include_text(server.as_ref()).then(|| buffer.read(cx).text()); - server - .notify::( - lsp::DidSaveTextDocumentParams { - text_document: text_document.clone(), - text, - }, - ) - .log_err(); + if let Some(include_text) = include_text(server.as_ref()) { + let text = if include_text { + Some(buffer.read(cx).text()) + } else { + None + }; + server + .notify::( + lsp::DidSaveTextDocumentParams { + text_document: text_document.clone(), + text, + }, + ) + .log_err(); + } } for language_server_id in self.language_server_ids_for_buffer(buffer.read(cx), cx) { @@ -11834,20 +11840,27 @@ fn is_not_found_error(error: &anyhow::Error) -> bool { .is_some_and(|err| err.kind() == io::ErrorKind::NotFound) } -fn include_text(server: &lsp::LanguageServer) -> bool { - server - .capabilities() - .text_document_sync - .as_ref() - .and_then(|sync| match sync { - lsp::TextDocumentSyncCapability::Kind(_) => None, - lsp::TextDocumentSyncCapability::Options(options) => options.save.as_ref(), - }) - .and_then(|save_options| match save_options { - lsp::TextDocumentSyncSaveOptions::Supported(_) => None, - lsp::TextDocumentSyncSaveOptions::SaveOptions(options) => options.include_text, - }) - .unwrap_or(false) +fn include_text(server: &lsp::LanguageServer) -> Option { + match server.capabilities().text_document_sync.as_ref()? { + lsp::TextDocumentSyncCapability::Kind(kind) => match kind { + &lsp::TextDocumentSyncKind::NONE => None, + &lsp::TextDocumentSyncKind::FULL => Some(true), + &lsp::TextDocumentSyncKind::INCREMENTAL => Some(false), + _ => None, + }, + lsp::TextDocumentSyncCapability::Options(options) => match options.save.as_ref()? { + lsp::TextDocumentSyncSaveOptions::Supported(supported) => { + if *supported { + Some(true) + } else { + None + } + } + lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => { + Some(save_options.include_text.unwrap_or(false)) + } + }, + } } async fn load_shell_environment(dir: &Path) -> Result> { diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index 4945d89ce74633b227286b079b3fcfd7b1949626..7be271e4bb88b0cfd3c6730bc0d6d0e6b344b435 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -322,6 +322,12 @@ async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) { trigger_characters: Some(vec![".".to_string(), "::".to_string()]), ..Default::default() }), + text_document_sync: Some(lsp::TextDocumentSyncCapability::Options( + lsp::TextDocumentSyncOptions { + save: Some(lsp::TextDocumentSyncSaveOptions::Supported(true)), + ..Default::default() + }, + )), ..Default::default() }, ..Default::default() @@ -336,6 +342,12 @@ async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) { trigger_characters: Some(vec![":".to_string()]), ..Default::default() }), + text_document_sync: Some(lsp::TextDocumentSyncCapability::Options( + lsp::TextDocumentSyncOptions { + save: Some(lsp::TextDocumentSyncSaveOptions::Supported(true)), + ..Default::default() + }, + )), ..Default::default() }, ..Default::default()