[ty] Add ty.experimental.rename server setting (#19800)

## Summary

This PR is a follow-up from https://github.com/astral-sh/ruff/pull/19551
and adds a new `ty.experimental.rename` setting to conditionally
register for the rename capability. The complementary PR in ty VS Code
extension is https://github.com/astral-sh/ty-vscode/pull/111.

This is done using dynamic registration after the settings have been
resolved. The experimental group is part of the global settings because
they're applied for all workspaces that are managed by the client.

## Test Plan

Add E2E tests.

In VS Code, with the following setting:
```json
{
	"ty.experimental.rename": "true",
	"python.languageServer": "None"
}
```

I get the relevant log entry:
```
2025-08-07 16:05:40.598709000 DEBUG client_response{id=3 method="client/registerCapability"}: Registered rename capability
```

And, I'm able to rename a symbol. Once I set it to `false`, then I can
see this log entry:

```
2025-08-07 16:08:39.027876000 DEBUG Rename capability is disabled in the client settings
```

And, I don't see the "Rename Symbol" open in the VS Code dropdown.


https://github.com/user-attachments/assets/501659df-ba96-4252-bf51-6f22acb4920b
This commit is contained in:
Dhruv Manilawala 2025-08-07 18:24:58 +05:30 committed by GitHub
parent b005cdb7ff
commit 7b6abfb030
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 259 additions and 32 deletions

View file

@ -9,6 +9,7 @@ use lsp_types::{
};
use crate::PositionEncoding;
use crate::session::GlobalSettings;
bitflags::bitflags! {
/// Represents the resolved client capabilities for the language server.
@ -31,6 +32,7 @@ bitflags::bitflags! {
const FILE_WATCHER_SUPPORT = 1 << 12;
const DIAGNOSTIC_DYNAMIC_REGISTRATION = 1 << 13;
const WORKSPACE_CONFIGURATION = 1 << 14;
const RENAME_DYNAMIC_REGISTRATION = 1 << 15;
}
}
@ -110,6 +112,11 @@ impl ResolvedClientCapabilities {
self.contains(Self::DIAGNOSTIC_DYNAMIC_REGISTRATION)
}
/// Returns `true` if the client supports dynamic registration for rename capabilities.
pub(crate) const fn supports_rename_dynamic_registration(self) -> bool {
self.contains(Self::RENAME_DYNAMIC_REGISTRATION)
}
pub(super) fn new(client_capabilities: &ClientCapabilities) -> Self {
let mut flags = Self::empty();
@ -246,6 +253,13 @@ impl ResolvedClientCapabilities {
flags |= Self::HIERARCHICAL_DOCUMENT_SYMBOL_SUPPORT;
}
if text_document
.and_then(|text_document| text_document.rename.as_ref()?.dynamic_registration)
.unwrap_or_default()
{
flags |= Self::RENAME_DYNAMIC_REGISTRATION;
}
if client_capabilities
.window
.as_ref()
@ -259,9 +273,12 @@ impl ResolvedClientCapabilities {
}
}
/// Creates the server capabilities based on the resolved client capabilities and resolved global
/// settings from the initialization options.
pub(crate) fn server_capabilities(
position_encoding: PositionEncoding,
resolved_client_capabilities: ResolvedClientCapabilities,
global_settings: &GlobalSettings,
) -> ServerCapabilities {
let diagnostic_provider =
if resolved_client_capabilities.supports_diagnostic_dynamic_registration() {
@ -275,6 +292,18 @@ pub(crate) fn server_capabilities(
))
};
let rename_provider = if resolved_client_capabilities.supports_rename_dynamic_registration() {
// If the client supports dynamic registration, we will register the rename capabilities
// dynamically based on the `ty.experimental.rename` setting.
None
} else {
// Otherwise, we check whether user has enabled rename support via the resolved settings
// from initialization options.
global_settings
.is_rename_enabled()
.then(|| OneOf::Right(server_rename_options()))
};
ServerCapabilities {
position_encoding: Some(position_encoding.into()),
diagnostic_provider,
@ -289,10 +318,7 @@ pub(crate) fn server_capabilities(
definition_provider: Some(OneOf::Left(true)),
declaration_provider: Some(DeclarationCapability::Simple(true)),
references_provider: Some(OneOf::Left(true)),
rename_provider: Some(OneOf::Right(RenameOptions {
prepare_provider: Some(true),
work_done_progress_options: WorkDoneProgressOptions::default(),
})),
rename_provider,
document_highlight_provider: Some(OneOf::Left(true)),
hover_provider: Some(HoverProviderCapability::Simple(true)),
signature_help_provider: Some(SignatureHelpOptions {
@ -344,3 +370,10 @@ pub(crate) fn server_diagnostic_options(workspace_diagnostics: bool) -> Diagnost
},
}
}
pub(crate) fn server_rename_options() -> RenameOptions {
RenameOptions {
prepare_provider: Some(true),
work_done_progress_options: WorkDoneProgressOptions::default(),
}
}