mirror of
				https://github.com/astral-sh/ruff.git
				synced 2025-10-31 12:05:57 +00:00 
			
		
		
		
	[ty] Send a single request for registrations/unregistrations (#19822)
## Summary This is a small refactor to update the server to send a single request to perform registrations and unregistrations of dynamic capabilities. ## Test Plan Existing E2E test cases pass, add a new test case to verify multiple registrations.
This commit is contained in:
		
							parent
							
								
									827456f977
								
							
						
					
					
						commit
						fc72ff4a94
					
				
					 2 changed files with 153 additions and 101 deletions
				
			
		|  | @ -570,8 +570,7 @@ impl Session { | ||||||
|             self.global_settings = Arc::new(global_settings); |             self.global_settings = Arc::new(global_settings); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         self.register_diagnostic_capability(client); |         self.register_capabilities(client); | ||||||
|         self.register_rename_capability(client); |  | ||||||
| 
 | 
 | ||||||
|         assert!( |         assert!( | ||||||
|             self.workspaces.all_initialized(), |             self.workspaces.all_initialized(), | ||||||
|  | @ -587,134 +586,137 @@ impl Session { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // TODO: Merge the following two methods as `register_capability` and `unregister_capability`
 |     /// Registers the dynamic capabilities with the client as per the resolved global settings.
 | ||||||
| 
 |  | ||||||
|     /// Sends a registration notification to the client to enable / disable workspace diagnostics
 |  | ||||||
|     /// as per the `ty.diagnosticMode` global setting.
 |  | ||||||
|     ///
 |     ///
 | ||||||
|     /// This method is a no-op if the client doesn't support dynamic registration of diagnostic
 |     /// ## Diagnostic capability
 | ||||||
|     /// capability.
 |     ///
 | ||||||
|     fn register_diagnostic_capability(&mut self, client: &Client) { |     /// This capability is used to enable / disable workspace diagnostics as per the
 | ||||||
|  |     /// `ty.diagnosticMode` global setting.
 | ||||||
|  |     ///
 | ||||||
|  |     /// ## Rename capability
 | ||||||
|  |     ///
 | ||||||
|  |     /// This capability is used to enable / disable rename functionality as per the
 | ||||||
|  |     /// `ty.experimental.rename` global setting.
 | ||||||
|  |     fn register_capabilities(&mut self, client: &Client) { | ||||||
|         static DIAGNOSTIC_REGISTRATION_ID: &str = "ty/textDocument/diagnostic"; |         static DIAGNOSTIC_REGISTRATION_ID: &str = "ty/textDocument/diagnostic"; | ||||||
|  |         static RENAME_REGISTRATION_ID: &str = "ty/textDocument/rename"; | ||||||
| 
 | 
 | ||||||
|         if !self |         let mut registrations = vec![]; | ||||||
|  |         let mut unregistrations = vec![]; | ||||||
|  | 
 | ||||||
|  |         if self | ||||||
|             .resolved_client_capabilities |             .resolved_client_capabilities | ||||||
|             .supports_diagnostic_dynamic_registration() |             .supports_diagnostic_dynamic_registration() | ||||||
|         { |         { | ||||||
|             return; |             if self | ||||||
|         } |                 .registrations | ||||||
|  |                 .contains(DocumentDiagnosticRequest::METHOD) | ||||||
|  |             { | ||||||
|  |                 unregistrations.push(Unregistration { | ||||||
|  |                     id: DIAGNOSTIC_REGISTRATION_ID.into(), | ||||||
|  |                     method: DocumentDiagnosticRequest::METHOD.into(), | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|         let registered = self |             let diagnostic_mode = self.global_settings.diagnostic_mode; | ||||||
|             .registrations |  | ||||||
|             .contains(DocumentDiagnosticRequest::METHOD); |  | ||||||
| 
 | 
 | ||||||
|         if registered { |             tracing::debug!( | ||||||
|             client.send_request::<UnregisterCapability>( |                 "Registering diagnostic capability with {diagnostic_mode:?} diagnostic mode" | ||||||
|                 self, |  | ||||||
|                 UnregistrationParams { |  | ||||||
|                     unregisterations: vec![Unregistration { |  | ||||||
|                         id: DIAGNOSTIC_REGISTRATION_ID.into(), |  | ||||||
|                         method: DocumentDiagnosticRequest::METHOD.into(), |  | ||||||
|                     }], |  | ||||||
|                 }, |  | ||||||
|                 |_: &Client, ()| { |  | ||||||
|                     tracing::debug!("Unregistered diagnostic capability"); |  | ||||||
|                 }, |  | ||||||
|             ); |             ); | ||||||
|  |             registrations.push(Registration { | ||||||
|  |                 id: DIAGNOSTIC_REGISTRATION_ID.into(), | ||||||
|  |                 method: DocumentDiagnosticRequest::METHOD.into(), | ||||||
|  |                 register_options: Some( | ||||||
|  |                     serde_json::to_value(DiagnosticServerCapabilities::RegistrationOptions( | ||||||
|  |                         DiagnosticRegistrationOptions { | ||||||
|  |                             diagnostic_options: server_diagnostic_options( | ||||||
|  |                                 diagnostic_mode.is_workspace(), | ||||||
|  |                             ), | ||||||
|  |                             ..Default::default() | ||||||
|  |                         }, | ||||||
|  |                     )) | ||||||
|  |                     .unwrap(), | ||||||
|  |                 ), | ||||||
|  |             }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let diagnostic_mode = self.global_settings.diagnostic_mode; |         if self | ||||||
| 
 |  | ||||||
|         let registration = Registration { |  | ||||||
|             id: DIAGNOSTIC_REGISTRATION_ID.into(), |  | ||||||
|             method: DocumentDiagnosticRequest::METHOD.into(), |  | ||||||
|             register_options: Some( |  | ||||||
|                 serde_json::to_value(DiagnosticServerCapabilities::RegistrationOptions( |  | ||||||
|                     DiagnosticRegistrationOptions { |  | ||||||
|                         diagnostic_options: server_diagnostic_options( |  | ||||||
|                             diagnostic_mode.is_workspace(), |  | ||||||
|                         ), |  | ||||||
|                         ..Default::default() |  | ||||||
|                     }, |  | ||||||
|                 )) |  | ||||||
|                 .unwrap(), |  | ||||||
|             ), |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         client.send_request::<RegisterCapability>( |  | ||||||
|             self, |  | ||||||
|             RegistrationParams { |  | ||||||
|                 registrations: vec![registration], |  | ||||||
|             }, |  | ||||||
|             move |_: &Client, ()| { |  | ||||||
|                 tracing::debug!( |  | ||||||
|                     "Registered diagnostic capability in {diagnostic_mode:?} diagnostic mode" |  | ||||||
|                 ); |  | ||||||
|             }, |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         if !registered { |  | ||||||
|             self.registrations |  | ||||||
|                 .insert(DocumentDiagnosticRequest::METHOD.to_string()); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Sends a registration notification to the client to enable / disable rename capability as
 |  | ||||||
|     /// per the `ty.experimental.rename` global setting.
 |  | ||||||
|     ///
 |  | ||||||
|     /// This method is a no-op if the client doesn't support dynamic registration of rename
 |  | ||||||
|     /// capability.
 |  | ||||||
|     fn register_rename_capability(&mut self, client: &Client) { |  | ||||||
|         static RENAME_REGISTRATION_ID: &str = "ty/textDocument/rename"; |  | ||||||
| 
 |  | ||||||
|         if !self |  | ||||||
|             .resolved_client_capabilities |             .resolved_client_capabilities | ||||||
|             .supports_rename_dynamic_registration() |             .supports_rename_dynamic_registration() | ||||||
|         { |         { | ||||||
|             return; |             let is_rename_enabled = self.global_settings.is_rename_enabled(); | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         let registered = self.registrations.contains(Rename::METHOD); |             if !is_rename_enabled { | ||||||
| 
 |                 tracing::debug!("Rename capability is disabled in the resolved global settings"); | ||||||
|         if registered { |                 if self.registrations.contains(Rename::METHOD) { | ||||||
|             client.send_request::<UnregisterCapability>( |                     unregistrations.push(Unregistration { | ||||||
|                 self, |  | ||||||
|                 UnregistrationParams { |  | ||||||
|                     unregisterations: vec![Unregistration { |  | ||||||
|                         id: RENAME_REGISTRATION_ID.into(), |                         id: RENAME_REGISTRATION_ID.into(), | ||||||
|                         method: Rename::METHOD.into(), |                         method: Rename::METHOD.into(), | ||||||
|                     }], |                     }); | ||||||
|                 }, |                 } | ||||||
|                 move |_: &Client, ()| { |             } | ||||||
|                     tracing::debug!("Unregistered rename capability"); | 
 | ||||||
|                 }, |             if is_rename_enabled { | ||||||
|             ); |                 registrations.push(Registration { | ||||||
|  |                     id: RENAME_REGISTRATION_ID.into(), | ||||||
|  |                     method: Rename::METHOD.into(), | ||||||
|  |                     register_options: Some(serde_json::to_value(server_rename_options()).unwrap()), | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if !self.global_settings.experimental.rename { |         // First, unregister any existing capabilities and then register or re-register them.
 | ||||||
|             tracing::debug!("Rename capability is disabled in the client settings"); |         self.unregister_dynamic_capability(client, unregistrations); | ||||||
|  |         self.register_dynamic_capability(client, registrations); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Registers a list of dynamic capabilities with the client.
 | ||||||
|  |     fn register_dynamic_capability(&mut self, client: &Client, registrations: Vec<Registration>) { | ||||||
|  |         if registrations.is_empty() { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let registration = Registration { |         for registration in ®istrations { | ||||||
|             id: RENAME_REGISTRATION_ID.into(), |             self.registrations.insert(registration.method.clone()); | ||||||
|             method: Rename::METHOD.into(), |         } | ||||||
|             register_options: Some(serde_json::to_value(server_rename_options()).unwrap()), |  | ||||||
|         }; |  | ||||||
| 
 | 
 | ||||||
|         client.send_request::<RegisterCapability>( |         client.send_request::<RegisterCapability>( | ||||||
|             self, |             self, | ||||||
|             RegistrationParams { |             RegistrationParams { registrations }, | ||||||
|                 registrations: vec![registration], |             |_: &Client, ()| { | ||||||
|             }, |                 tracing::debug!("Registered dynamic capabilities"); | ||||||
|             move |_: &Client, ()| { |  | ||||||
|                 tracing::debug!("Registered rename capability"); |  | ||||||
|             }, |             }, | ||||||
|         ); |         ); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|         if !registered { |     /// Unregisters a list of dynamic capabilities with the client.
 | ||||||
|             self.registrations.insert(Rename::METHOD.to_string()); |     fn unregister_dynamic_capability( | ||||||
|  |         &mut self, | ||||||
|  |         client: &Client, | ||||||
|  |         unregistrations: Vec<Unregistration>, | ||||||
|  |     ) { | ||||||
|  |         if unregistrations.is_empty() { | ||||||
|  |             return; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         for unregistration in &unregistrations { | ||||||
|  |             if !self.registrations.remove(&unregistration.method) { | ||||||
|  |                 tracing::debug!( | ||||||
|  |                     "Unregistration for `{}` was requested, but it was not registered", | ||||||
|  |                     unregistration.method | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         client.send_request::<UnregisterCapability>( | ||||||
|  |             self, | ||||||
|  |             UnregistrationParams { | ||||||
|  |                 unregisterations: unregistrations, | ||||||
|  |             }, | ||||||
|  |             |_: &Client, ()| { | ||||||
|  |                 tracing::debug!("Unregistered dynamic capabilities"); | ||||||
|  |             }, | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Creates a document snapshot with the URL referencing the document to snapshot.
 |     /// Creates a document snapshot with the URL referencing the document to snapshot.
 | ||||||
|  |  | ||||||
|  | @ -508,3 +508,53 @@ fn not_register_rename_capability_when_disabled() -> Result<()> { | ||||||
| 
 | 
 | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /// Tests that the server can register multiple capabilities at once.
 | ||||||
|  | ///
 | ||||||
|  | /// This test would need to be updated when the server supports additional capabilities in the
 | ||||||
|  | /// future.
 | ||||||
|  | #[test] | ||||||
|  | fn register_multiple_capabilities() -> Result<()> { | ||||||
|  |     let workspace_root = SystemPath::new("foo"); | ||||||
|  |     let mut server = TestServerBuilder::new()? | ||||||
|  |         .with_workspace(workspace_root, None)? | ||||||
|  |         .with_initialization_options( | ||||||
|  |             ClientOptions::default() | ||||||
|  |                 .with_experimental_rename(true) | ||||||
|  |                 .with_diagnostic_mode(DiagnosticMode::Workspace), | ||||||
|  |         ) | ||||||
|  |         .enable_rename_dynamic_registration(true) | ||||||
|  |         .enable_diagnostic_dynamic_registration(true) | ||||||
|  |         .build()? | ||||||
|  |         .wait_until_workspaces_are_initialized()?; | ||||||
|  | 
 | ||||||
|  |     let (_, params) = server.await_request::<RegisterCapability>()?; | ||||||
|  |     let registrations = params.registrations; | ||||||
|  | 
 | ||||||
|  |     assert_eq!(registrations.len(), 2); | ||||||
|  | 
 | ||||||
|  |     insta::assert_json_snapshot!(registrations, @r#" | ||||||
|  |     [ | ||||||
|  |       { | ||||||
|  |         "id": "ty/textDocument/diagnostic", | ||||||
|  |         "method": "textDocument/diagnostic", | ||||||
|  |         "registerOptions": { | ||||||
|  |           "documentSelector": null, | ||||||
|  |           "identifier": "ty", | ||||||
|  |           "interFileDependencies": true, | ||||||
|  |           "workDoneProgress": true, | ||||||
|  |           "workspaceDiagnostics": true | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         "id": "ty/textDocument/rename", | ||||||
|  |         "method": "textDocument/rename", | ||||||
|  |         "registerOptions": { | ||||||
|  |           "prepareProvider": true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     ] | ||||||
|  |     "#);
 | ||||||
|  | 
 | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dhruv Manilawala
						Dhruv Manilawala