project: Add more dynamic capability registrations for LSP (#35306)

Closes #34204

Adds the ability to dynamically register and unregister code actions for
language servers such as Biome.

See more:
https://github.com/zed-industries/zed/issues/34204#issuecomment-3134227856

Release Notes:

- Fixed an issue where the Biome formatter was always used even when
`require_config_file` was set to true and the project had no config
file.

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
smit 2025-08-11 15:29:41 +05:30 committed by GitHub
parent e132c7cad9
commit 422e0a2eb7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 435 additions and 223 deletions

View file

@ -651,7 +651,7 @@ impl LanguageServer {
capabilities: ClientCapabilities { capabilities: ClientCapabilities {
general: Some(GeneralClientCapabilities { general: Some(GeneralClientCapabilities {
position_encodings: Some(vec![PositionEncodingKind::UTF16]), position_encodings: Some(vec![PositionEncodingKind::UTF16]),
..Default::default() ..GeneralClientCapabilities::default()
}), }),
workspace: Some(WorkspaceClientCapabilities { workspace: Some(WorkspaceClientCapabilities {
configuration: Some(true), configuration: Some(true),
@ -665,6 +665,7 @@ impl LanguageServer {
workspace_folders: Some(true), workspace_folders: Some(true),
symbol: Some(WorkspaceSymbolClientCapabilities { symbol: Some(WorkspaceSymbolClientCapabilities {
resolve_support: None, resolve_support: None,
dynamic_registration: Some(true),
..WorkspaceSymbolClientCapabilities::default() ..WorkspaceSymbolClientCapabilities::default()
}), }),
inlay_hint: Some(InlayHintWorkspaceClientCapabilities { inlay_hint: Some(InlayHintWorkspaceClientCapabilities {
@ -688,21 +689,21 @@ impl LanguageServer {
..WorkspaceEditClientCapabilities::default() ..WorkspaceEditClientCapabilities::default()
}), }),
file_operations: Some(WorkspaceFileOperationsClientCapabilities { file_operations: Some(WorkspaceFileOperationsClientCapabilities {
dynamic_registration: Some(false), dynamic_registration: Some(true),
did_rename: Some(true), did_rename: Some(true),
will_rename: Some(true), will_rename: Some(true),
..Default::default() ..WorkspaceFileOperationsClientCapabilities::default()
}), }),
apply_edit: Some(true), apply_edit: Some(true),
execute_command: Some(ExecuteCommandClientCapabilities { execute_command: Some(ExecuteCommandClientCapabilities {
dynamic_registration: Some(false), dynamic_registration: Some(true),
}), }),
..Default::default() ..WorkspaceClientCapabilities::default()
}), }),
text_document: Some(TextDocumentClientCapabilities { text_document: Some(TextDocumentClientCapabilities {
definition: Some(GotoCapability { definition: Some(GotoCapability {
link_support: Some(true), link_support: Some(true),
dynamic_registration: None, dynamic_registration: Some(true),
}), }),
code_action: Some(CodeActionClientCapabilities { code_action: Some(CodeActionClientCapabilities {
code_action_literal_support: Some(CodeActionLiteralSupport { code_action_literal_support: Some(CodeActionLiteralSupport {
@ -725,7 +726,8 @@ impl LanguageServer {
"command".to_string(), "command".to_string(),
], ],
}), }),
..Default::default() dynamic_registration: Some(true),
..CodeActionClientCapabilities::default()
}), }),
completion: Some(CompletionClientCapabilities { completion: Some(CompletionClientCapabilities {
completion_item: Some(CompletionItemCapability { completion_item: Some(CompletionItemCapability {
@ -751,7 +753,7 @@ impl LanguageServer {
MarkupKind::Markdown, MarkupKind::Markdown,
MarkupKind::PlainText, MarkupKind::PlainText,
]), ]),
..Default::default() ..CompletionItemCapability::default()
}), }),
insert_text_mode: Some(InsertTextMode::ADJUST_INDENTATION), insert_text_mode: Some(InsertTextMode::ADJUST_INDENTATION),
completion_list: Some(CompletionListCapability { completion_list: Some(CompletionListCapability {
@ -764,18 +766,20 @@ impl LanguageServer {
]), ]),
}), }),
context_support: Some(true), context_support: Some(true),
..Default::default() dynamic_registration: Some(true),
..CompletionClientCapabilities::default()
}), }),
rename: Some(RenameClientCapabilities { rename: Some(RenameClientCapabilities {
prepare_support: Some(true), prepare_support: Some(true),
prepare_support_default_behavior: Some( prepare_support_default_behavior: Some(
PrepareSupportDefaultBehavior::IDENTIFIER, PrepareSupportDefaultBehavior::IDENTIFIER,
), ),
..Default::default() dynamic_registration: Some(true),
..RenameClientCapabilities::default()
}), }),
hover: Some(HoverClientCapabilities { hover: Some(HoverClientCapabilities {
content_format: Some(vec![MarkupKind::Markdown]), content_format: Some(vec![MarkupKind::Markdown]),
dynamic_registration: None, dynamic_registration: Some(true),
}), }),
inlay_hint: Some(InlayHintClientCapabilities { inlay_hint: Some(InlayHintClientCapabilities {
resolve_support: Some(InlayHintResolveClientCapabilities { resolve_support: Some(InlayHintResolveClientCapabilities {
@ -787,7 +791,7 @@ impl LanguageServer {
"label.command".to_string(), "label.command".to_string(),
], ],
}), }),
dynamic_registration: Some(false), dynamic_registration: Some(true),
}), }),
publish_diagnostics: Some(PublishDiagnosticsClientCapabilities { publish_diagnostics: Some(PublishDiagnosticsClientCapabilities {
related_information: Some(true), related_information: Some(true),
@ -818,26 +822,29 @@ impl LanguageServer {
}), }),
active_parameter_support: Some(true), active_parameter_support: Some(true),
}), }),
dynamic_registration: Some(true),
..SignatureHelpClientCapabilities::default() ..SignatureHelpClientCapabilities::default()
}), }),
synchronization: Some(TextDocumentSyncClientCapabilities { synchronization: Some(TextDocumentSyncClientCapabilities {
did_save: Some(true), did_save: Some(true),
dynamic_registration: Some(true),
..TextDocumentSyncClientCapabilities::default() ..TextDocumentSyncClientCapabilities::default()
}), }),
code_lens: Some(CodeLensClientCapabilities { code_lens: Some(CodeLensClientCapabilities {
dynamic_registration: Some(false), dynamic_registration: Some(true),
}), }),
document_symbol: Some(DocumentSymbolClientCapabilities { document_symbol: Some(DocumentSymbolClientCapabilities {
hierarchical_document_symbol_support: Some(true), hierarchical_document_symbol_support: Some(true),
dynamic_registration: Some(true),
..DocumentSymbolClientCapabilities::default() ..DocumentSymbolClientCapabilities::default()
}), }),
diagnostic: Some(DiagnosticClientCapabilities { diagnostic: Some(DiagnosticClientCapabilities {
dynamic_registration: Some(false), dynamic_registration: Some(true),
related_document_support: Some(true), related_document_support: Some(true),
}) })
.filter(|_| pull_diagnostics), .filter(|_| pull_diagnostics),
color_provider: Some(DocumentColorClientCapabilities { color_provider: Some(DocumentColorClientCapabilities {
dynamic_registration: Some(false), dynamic_registration: Some(true),
}), }),
..TextDocumentClientCapabilities::default() ..TextDocumentClientCapabilities::default()
}), }),
@ -850,7 +857,7 @@ impl LanguageServer {
show_message: Some(ShowMessageRequestClientCapabilities { show_message: Some(ShowMessageRequestClientCapabilities {
message_action_item: None, message_action_item: None,
}), }),
..Default::default() ..WindowClientCapabilities::default()
}), }),
}, },
trace: None, trace: None,
@ -862,8 +869,7 @@ impl LanguageServer {
} }
}), }),
locale: None, locale: None,
..InitializeParams::default()
..Default::default()
} }
} }
@ -1672,7 +1678,7 @@ impl LanguageServer {
workspace_symbol_provider: Some(OneOf::Left(true)), workspace_symbol_provider: Some(OneOf::Left(true)),
implementation_provider: Some(ImplementationProviderCapability::Simple(true)), implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)), type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
..Default::default() ..ServerCapabilities::default()
} }
} }
} }

View file

@ -638,139 +638,27 @@ impl LocalLspStore {
language_server language_server
.on_request::<lsp::request::RegisterCapability, _, _>({ .on_request::<lsp::request::RegisterCapability, _, _>({
let this = this.clone(); let lsp_store = this.clone();
move |params, cx| { move |params, cx| {
let lsp_store = this.clone(); let lsp_store = lsp_store.clone();
let mut cx = cx.clone(); let mut cx = cx.clone();
async move { async move {
for reg in params.registrations { lsp_store
match reg.method.as_str() { .update(&mut cx, |lsp_store, cx| {
"workspace/didChangeWatchedFiles" => { if lsp_store.as_local().is_some() {
if let Some(options) = reg.register_options { match lsp_store
let options = serde_json::from_value(options)?; .register_server_capabilities(server_id, params, cx)
lsp_store.update(&mut cx, |this, cx| { {
this.as_local_mut()?.on_lsp_did_change_watched_files( Ok(()) => {}
server_id, &reg.id, options, cx, Err(e) => {
log::error!(
"Failed to register server capabilities: {e:#}"
); );
Some(())
})?;
}
}
"textDocument/rangeFormatting" => {
lsp_store.update(&mut cx, |lsp_store, cx| {
if let Some(server) =
lsp_store.language_server_for_id(server_id)
{
let options = reg
.register_options
.map(|options| {
serde_json::from_value::<
lsp::DocumentRangeFormattingOptions,
>(
options
)
})
.transpose()?;
let provider = match options {
None => OneOf::Left(true),
Some(options) => OneOf::Right(options),
};
server.update_capabilities(|capabilities| {
capabilities.document_range_formatting_provider =
Some(provider);
});
notify_server_capabilities_updated(&server, cx);
} }
anyhow::Ok(()) };
})??;
} }
"textDocument/onTypeFormatting" => { })
lsp_store.update(&mut cx, |lsp_store, cx| { .ok();
if let Some(server) =
lsp_store.language_server_for_id(server_id)
{
let options = reg
.register_options
.map(|options| {
serde_json::from_value::<
lsp::DocumentOnTypeFormattingOptions,
>(
options
)
})
.transpose()?;
if let Some(options) = options {
server.update_capabilities(|capabilities| {
capabilities
.document_on_type_formatting_provider =
Some(options);
});
notify_server_capabilities_updated(&server, cx);
}
}
anyhow::Ok(())
})??;
}
"textDocument/formatting" => {
lsp_store.update(&mut cx, |lsp_store, cx| {
if let Some(server) =
lsp_store.language_server_for_id(server_id)
{
let options = reg
.register_options
.map(|options| {
serde_json::from_value::<
lsp::DocumentFormattingOptions,
>(
options
)
})
.transpose()?;
let provider = match options {
None => OneOf::Left(true),
Some(options) => OneOf::Right(options),
};
server.update_capabilities(|capabilities| {
capabilities.document_formatting_provider =
Some(provider);
});
notify_server_capabilities_updated(&server, cx);
}
anyhow::Ok(())
})??;
}
"workspace/didChangeConfiguration" => {
// Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
}
"textDocument/rename" => {
lsp_store.update(&mut cx, |lsp_store, cx| {
if let Some(server) =
lsp_store.language_server_for_id(server_id)
{
let options = reg
.register_options
.map(|options| {
serde_json::from_value::<lsp::RenameOptions>(
options,
)
})
.transpose()?;
let options = match options {
None => OneOf::Left(true),
Some(options) => OneOf::Right(options),
};
server.update_capabilities(|capabilities| {
capabilities.rename_provider = Some(options);
});
notify_server_capabilities_updated(&server, cx);
}
anyhow::Ok(())
})??;
}
_ => log::warn!("unhandled capability registration: {reg:?}"),
}
}
Ok(()) Ok(())
} }
} }
@ -779,79 +667,27 @@ impl LocalLspStore {
language_server language_server
.on_request::<lsp::request::UnregisterCapability, _, _>({ .on_request::<lsp::request::UnregisterCapability, _, _>({
let this = this.clone(); let lsp_store = this.clone();
move |params, cx| { move |params, cx| {
let lsp_store = this.clone(); let lsp_store = lsp_store.clone();
let mut cx = cx.clone(); let mut cx = cx.clone();
async move { async move {
for unreg in params.unregisterations.iter() { lsp_store
match unreg.method.as_str() { .update(&mut cx, |lsp_store, cx| {
"workspace/didChangeWatchedFiles" => { if lsp_store.as_local().is_some() {
lsp_store.update(&mut cx, |lsp_store, cx| { match lsp_store
lsp_store .unregister_server_capabilities(server_id, params, cx)
.as_local_mut()? {
.on_lsp_unregister_did_change_watched_files( Ok(()) => {}
server_id, &unreg.id, cx, Err(e) => {
log::error!(
"Failed to unregister server capabilities: {e:#}"
); );
Some(())
})?;
}
"workspace/didChangeConfiguration" => {
// Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
}
"textDocument/rename" => {
lsp_store.update(&mut cx, |lsp_store, cx| {
if let Some(server) =
lsp_store.language_server_for_id(server_id)
{
server.update_capabilities(|capabilities| {
capabilities.rename_provider = None
});
notify_server_capabilities_updated(&server, cx);
} }
})?; }
} }
"textDocument/rangeFormatting" => { })
lsp_store.update(&mut cx, |lsp_store, cx| { .ok();
if let Some(server) =
lsp_store.language_server_for_id(server_id)
{
server.update_capabilities(|capabilities| {
capabilities.document_range_formatting_provider =
None
});
notify_server_capabilities_updated(&server, cx);
}
})?;
}
"textDocument/onTypeFormatting" => {
lsp_store.update(&mut cx, |lsp_store, cx| {
if let Some(server) =
lsp_store.language_server_for_id(server_id)
{
server.update_capabilities(|capabilities| {
capabilities.document_on_type_formatting_provider =
None;
});
notify_server_capabilities_updated(&server, cx);
}
})?;
}
"textDocument/formatting" => {
lsp_store.update(&mut cx, |lsp_store, cx| {
if let Some(server) =
lsp_store.language_server_for_id(server_id)
{
server.update_capabilities(|capabilities| {
capabilities.document_formatting_provider = None;
});
notify_server_capabilities_updated(&server, cx);
}
})?;
}
_ => log::warn!("unhandled capability unregistration: {unreg:?}"),
}
}
Ok(()) Ok(())
} }
} }
@ -3519,6 +3355,30 @@ impl LocalLspStore {
Ok(workspace_config) Ok(workspace_config)
} }
fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
Some(server.clone())
} else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
Some(Arc::clone(server))
} else {
None
}
}
}
fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
reg: lsp::Registration,
) -> anyhow::Result<OneOf<bool, T>> {
let caps = match reg
.register_options
.map(|options| serde_json::from_value::<T>(options))
.transpose()?
{
None => OneOf::Left(true),
Some(options) => OneOf::Right(options),
};
Ok(caps)
} }
fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) { fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
@ -9434,16 +9294,7 @@ impl LspStore {
} }
pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> { pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
let local_lsp_store = self.as_local()?; self.as_local()?.language_server_for_id(id)
if let Some(LanguageServerState::Running { server, .. }) =
local_lsp_store.language_servers.get(&id)
{
Some(server.clone())
} else if let Some((_, server)) = local_lsp_store.supplementary_language_servers.get(&id) {
Some(Arc::clone(server))
} else {
None
}
} }
fn on_lsp_progress( fn on_lsp_progress(
@ -11808,6 +11659,361 @@ impl LspStore {
.log_err(); .log_err();
} }
} }
fn register_server_capabilities(
&mut self,
server_id: LanguageServerId,
params: lsp::RegistrationParams,
cx: &mut Context<Self>,
) -> anyhow::Result<()> {
let server = self
.language_server_for_id(server_id)
.with_context(|| format!("no server {server_id} found"))?;
for reg in params.registrations {
match reg.method.as_str() {
"workspace/didChangeWatchedFiles" => {
if let Some(options) = reg.register_options {
let notify = if let Some(local_lsp_store) = self.as_local_mut() {
let caps = serde_json::from_value(options)?;
local_lsp_store
.on_lsp_did_change_watched_files(server_id, &reg.id, caps, cx);
true
} else {
false
};
if notify {
notify_server_capabilities_updated(&server, cx);
}
}
}
"workspace/didChangeConfiguration" => {
// Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
}
"workspace/symbol" => {
let options = parse_register_capabilities(reg)?;
server.update_capabilities(|capabilities| {
capabilities.workspace_symbol_provider = Some(options);
});
notify_server_capabilities_updated(&server, cx);
}
"workspace/fileOperations" => {
let caps = reg
.register_options
.map(serde_json::from_value)
.transpose()?
.unwrap_or_default();
server.update_capabilities(|capabilities| {
capabilities
.workspace
.get_or_insert_default()
.file_operations = Some(caps);
});
notify_server_capabilities_updated(&server, cx);
}
"workspace/executeCommand" => {
let options = reg
.register_options
.map(serde_json::from_value)
.transpose()?
.unwrap_or_default();
server.update_capabilities(|capabilities| {
capabilities.execute_command_provider = Some(options);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/rangeFormatting" => {
let options = parse_register_capabilities(reg)?;
server.update_capabilities(|capabilities| {
capabilities.document_range_formatting_provider = Some(options);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/onTypeFormatting" => {
let options = reg
.register_options
.map(serde_json::from_value)
.transpose()?
.unwrap_or_default();
server.update_capabilities(|capabilities| {
capabilities.document_on_type_formatting_provider = Some(options);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/formatting" => {
let options = parse_register_capabilities(reg)?;
server.update_capabilities(|capabilities| {
capabilities.document_formatting_provider = Some(options);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/rename" => {
let options = parse_register_capabilities(reg)?;
server.update_capabilities(|capabilities| {
capabilities.rename_provider = Some(options);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/inlayHint" => {
let options = parse_register_capabilities(reg)?;
server.update_capabilities(|capabilities| {
capabilities.inlay_hint_provider = Some(options);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/documentSymbol" => {
let options = parse_register_capabilities(reg)?;
server.update_capabilities(|capabilities| {
capabilities.document_symbol_provider = Some(options);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/codeAction" => {
let options = reg
.register_options
.map(serde_json::from_value)
.transpose()?;
let provider_capability = match options {
None => lsp::CodeActionProviderCapability::Simple(true),
Some(options) => lsp::CodeActionProviderCapability::Options(options),
};
server.update_capabilities(|capabilities| {
capabilities.code_action_provider = Some(provider_capability);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/definition" => {
let caps = parse_register_capabilities(reg)?;
server.update_capabilities(|capabilities| {
capabilities.definition_provider = Some(caps);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/completion" => {
let caps = reg
.register_options
.map(serde_json::from_value)
.transpose()?
.unwrap_or_default();
server.update_capabilities(|capabilities| {
capabilities.completion_provider = Some(caps);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/hover" => {
let caps = reg
.register_options
.map(serde_json::from_value)
.transpose()?
.unwrap_or_else(|| lsp::HoverProviderCapability::Simple(true));
server.update_capabilities(|capabilities| {
capabilities.hover_provider = Some(caps);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/signatureHelp" => {
let caps = reg
.register_options
.map(serde_json::from_value)
.transpose()?
.unwrap_or_default();
server.update_capabilities(|capabilities| {
capabilities.signature_help_provider = Some(caps);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/synchronization" => {
let caps = reg
.register_options
.map(serde_json::from_value)
.transpose()?
.unwrap_or_else(|| {
lsp::TextDocumentSyncCapability::Options(
lsp::TextDocumentSyncOptions::default(),
)
});
server.update_capabilities(|capabilities| {
capabilities.text_document_sync = Some(caps);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/codeLens" => {
let caps = reg
.register_options
.map(serde_json::from_value)
.transpose()?
.unwrap_or_else(|| lsp::CodeLensOptions {
resolve_provider: None,
});
server.update_capabilities(|capabilities| {
capabilities.code_lens_provider = Some(caps);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/diagnostic" => {
let caps = reg
.register_options
.map(serde_json::from_value)
.transpose()?
.unwrap_or_else(|| {
lsp::DiagnosticServerCapabilities::RegistrationOptions(
lsp::DiagnosticRegistrationOptions::default(),
)
});
server.update_capabilities(|capabilities| {
capabilities.diagnostic_provider = Some(caps);
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/colorProvider" => {
let caps = reg
.register_options
.map(serde_json::from_value)
.transpose()?
.unwrap_or_else(|| lsp::ColorProviderCapability::Simple(true));
server.update_capabilities(|capabilities| {
capabilities.color_provider = Some(caps);
});
notify_server_capabilities_updated(&server, cx);
}
_ => log::warn!("unhandled capability registration: {reg:?}"),
}
}
Ok(())
}
fn unregister_server_capabilities(
&mut self,
server_id: LanguageServerId,
params: lsp::UnregistrationParams,
cx: &mut Context<Self>,
) -> anyhow::Result<()> {
let server = self
.language_server_for_id(server_id)
.with_context(|| format!("no server {server_id} found"))?;
for unreg in params.unregisterations.iter() {
match unreg.method.as_str() {
"workspace/didChangeWatchedFiles" => {
let notify = if let Some(local_lsp_store) = self.as_local_mut() {
local_lsp_store
.on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
true
} else {
false
};
if notify {
notify_server_capabilities_updated(&server, cx);
}
}
"workspace/didChangeConfiguration" => {
// Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
}
"workspace/symbol" => {
server.update_capabilities(|capabilities| {
capabilities.workspace_symbol_provider = None
});
notify_server_capabilities_updated(&server, cx);
}
"workspace/fileOperations" => {
server.update_capabilities(|capabilities| {
capabilities
.workspace
.get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
workspace_folders: None,
file_operations: None,
})
.file_operations = None;
});
notify_server_capabilities_updated(&server, cx);
}
"workspace/executeCommand" => {
server.update_capabilities(|capabilities| {
capabilities.execute_command_provider = None;
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/rangeFormatting" => {
server.update_capabilities(|capabilities| {
capabilities.document_range_formatting_provider = None
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/onTypeFormatting" => {
server.update_capabilities(|capabilities| {
capabilities.document_on_type_formatting_provider = None;
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/formatting" => {
server.update_capabilities(|capabilities| {
capabilities.document_formatting_provider = None;
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/rename" => {
server.update_capabilities(|capabilities| capabilities.rename_provider = None);
notify_server_capabilities_updated(&server, cx);
}
"textDocument/codeAction" => {
server.update_capabilities(|capabilities| {
capabilities.code_action_provider = None;
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/definition" => {
server.update_capabilities(|capabilities| {
capabilities.definition_provider = None;
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/completion" => {
server.update_capabilities(|capabilities| {
capabilities.completion_provider = None;
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/hover" => {
server.update_capabilities(|capabilities| {
capabilities.hover_provider = None;
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/signatureHelp" => {
server.update_capabilities(|capabilities| {
capabilities.signature_help_provider = None;
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/synchronization" => {
server.update_capabilities(|capabilities| {
capabilities.text_document_sync = None;
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/codeLens" => {
server.update_capabilities(|capabilities| {
capabilities.code_lens_provider = None;
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/diagnostic" => {
server.update_capabilities(|capabilities| {
capabilities.diagnostic_provider = None;
});
notify_server_capabilities_updated(&server, cx);
}
"textDocument/colorProvider" => {
server.update_capabilities(|capabilities| {
capabilities.color_provider = None;
});
notify_server_capabilities_updated(&server, cx);
}
_ => log::warn!("unhandled capability unregistration: {unreg:?}"),
}
}
Ok(())
}
} }
fn subscribe_to_binary_statuses( fn subscribe_to_binary_statuses(