diff --git a/pygls/capabilities.py b/pygls/capabilities.py index 44a6d2ed..48aece7e 100644 --- a/pygls/capabilities.py +++ b/pygls/capabilities.py @@ -248,9 +248,25 @@ def _with_document_on_type_formatting(self): return self def _with_rename(self): - value = self._provider_options(types.TEXT_DOCUMENT_RENAME, default=True) - if value is not None: - self.server_cap.rename_provider = value + server_supports_rename = types.TEXT_DOCUMENT_RENAME in self.features + if server_supports_rename is False: + return self + + client_prepare_support = get_capability( + self.client_capabilities, "text_document.rename.prepare_support", False + ) + + # From the spec: + # > RenameOptions may only be specified if the client states that it supports + # > prepareSupport in its initial initialize request. + if not client_prepare_support: + self.server_cap.rename_provider = server_supports_rename + + else: + self.server_cap.rename_provider = types.RenameOptions( + prepare_provider=types.TEXT_DOCUMENT_PREPARE_RENAME in self.features + ) + return self def _with_folding_range(self): diff --git a/tests/test_feature_manager.py b/tests/test_feature_manager.py index 744fcdb1..48bad6a9 100644 --- a/tests/test_feature_manager.py +++ b/tests/test_feature_manager.py @@ -709,6 +709,60 @@ def _(): assert expected == actual +def test_register_prepare_rename_no_client_support(feature_manager: FeatureManager): + + @feature_manager.feature(lsp.TEXT_DOCUMENT_RENAME) + def _(): + pass + + @feature_manager.feature(lsp.TEXT_DOCUMENT_PREPARE_RENAME) + def _(): + pass + + expected = server_capabilities(rename_provider=True) + + actual = ServerCapabilitiesBuilder( + lsp.ClientCapabilities(), + feature_manager.features.keys(), + feature_manager.feature_options, + [], + None, + None, + ).build() + + assert expected == actual + + +def test_register_prepare_rename_with_client_support(feature_manager: FeatureManager): + + @feature_manager.feature(lsp.TEXT_DOCUMENT_RENAME) + def _(): + pass + + @feature_manager.feature(lsp.TEXT_DOCUMENT_PREPARE_RENAME) + def _(): + pass + + expected = server_capabilities( + rename_provider=lsp.RenameOptions(prepare_provider=True) + ) + + actual = ServerCapabilitiesBuilder( + lsp.ClientCapabilities( + text_document=lsp.TextDocumentClientCapabilities( + rename=lsp.RenameClientCapabilities(prepare_support=True) + ) + ), + feature_manager.features.keys(), + feature_manager.feature_options, + [], + None, + None, + ).build() + + assert expected == actual + + def test_register_inlay_hint_resolve(feature_manager: FeatureManager): @feature_manager.feature(lsp.TEXT_DOCUMENT_INLAY_HINT) def _():