55from collections .abc import AsyncGenerator
66from contextlib import asynccontextmanager , suppress
77from pathlib import Path
8- from typing import Literal , Self , override
8+ from typing import Any , Literal , Self , override
99
1010import anyio
1111import asyncer
1212from anyio import AsyncContextManagerMixin
13- from attrs import define , field
13+ from attrs import Factory , define , field
1414from loguru import logger
1515
1616from lsp_client .capability .build import (
1919)
2020from lsp_client .capability .notification import WithNotifyTextDocumentSynchronize
2121from lsp_client .client .buffer import LSPFileBuffer
22- from lsp_client .client .lang import LanguageConfig
2322from lsp_client .jsonrpc .convert import (
2423 notification_serialize ,
2524 request_deserialize ,
2625 request_serialize ,
2726 response_deserialize ,
2827 response_serialize ,
2928)
30- from lsp_client .protocol import (
31- CapabilityClientProtocol ,
32- CapabilityProtocol ,
33- )
29+ from lsp_client .protocol import CapabilityClientProtocol , CapabilityProtocol
3430from lsp_client .server import DefaultServers , Server , ServerRuntimeError
3531from lsp_client .server .types import ServerRequest
3632from lsp_client .utils .channel import Receiver , channel
@@ -64,6 +60,7 @@ class Client(
6460 _server : Server = field (init = False )
6561 _workspace : Workspace = field (init = False )
6662 _buffer : LSPFileBuffer = field (factory = LSPFileBuffer , init = False )
63+ _config : ConfigurationMap = Factory (ConfigurationMap )
6764
6865 async def _iter_candidate_servers (self ) -> AsyncGenerator [Server ]:
6966 """
@@ -95,53 +92,25 @@ async def _iter_candidate_servers(self) -> AsyncGenerator[Server]:
9592 def get_workspace (self ) -> Workspace :
9693 return self ._workspace
9794
95+ @override
96+ def get_config_map (self ) -> ConfigurationMap :
97+ return self ._config
98+
9899 def get_server (self ) -> Server :
99100 return self ._server
100101
101- @abstractmethod
102- def get_language_config (self ) -> LanguageConfig :
103- """Get language-specific configuration for this client."""
104-
105102 @abstractmethod
106103 def create_default_servers (self ) -> DefaultServers :
107104 """Create default servers for this client."""
108105
106+ def create_default_config (self ) -> dict [str , Any ] | None :
107+ """Create default configuration map for this client."""
108+ return
109+
109110 @abstractmethod
110111 def check_server_compatibility (self , info : lsp_type .ServerInfo | None ) -> None :
111112 """Check if the available server capabilities are compatible with the client."""
112113
113- def create_default_configuration_map (self ) -> ConfigurationMap | None :
114- """
115- Create default configuration map for this client.
116-
117- This method can be overridden by subclasses to provide default configurations
118- that enable extra features like inlay hints, diagnostics, etc.
119-
120- The base implementation returns None, meaning no default configuration.
121- Subclasses that support configuration should override this method to provide
122- sensible defaults that enable commonly-used features.
123-
124- Returns:
125- ConfigurationMap with default settings, or None if no defaults are needed.
126-
127- Example:
128- Override this method in a client subclass to provide defaults:
129-
130- ```python
131- @override
132- def create_default_configuration_map(self) -> ConfigurationMap | None:
133- config_map = ConfigurationMap()
134- config_map.update_global({
135- "myserver": {
136- "inlayHints": {"enable": True},
137- "diagnostics": {"enable": True},
138- }
139- })
140- return config_map
141- ```
142- """
143- return None
144-
145114 @override
146115 @asynccontextmanager
147116 async def open_files (self , * file_paths : AnyPath ) -> AsyncGenerator [None ]:
@@ -173,7 +142,6 @@ async def open_files(self, *file_paths: AnyPath) -> AsyncGenerator[None]:
173142 tg .soonify (self .notify_text_document_closed )(item .file_path )
174143
175144 @override
176- # @retry(stop=tenacity.stop_after_attempt(3), reraise=True)
177145 async def request [R ](
178146 self ,
179147 req : Request ,
@@ -185,7 +153,6 @@ async def request[R](
185153 return response_deserialize (raw_resp , schema )
186154
187155 @override
188- # @retry(stop=tenacity.stop_after_attempt(3), reraise=True)
189156 async def notify (self , msg : Notification ) -> None :
190157 noti = notification_serialize (msg )
191158 with anyio .fail_after (self .request_timeout ):
@@ -279,17 +246,8 @@ async def _run_server(
279246 async def __asynccontextmanager__ (self ) -> AsyncGenerator [Self ]:
280247 self ._workspace = format_workspace (self ._workspace_arg )
281248
282- # Initialize default configuration map if the client supports configuration
283- # and no configuration map has been set yet
284- from lsp_client .capability .server_request import WithRespondConfigurationRequest
285-
286- if (
287- isinstance (self , WithRespondConfigurationRequest )
288- and self .configuration_map is None
289- ):
290- default_config = self .create_default_configuration_map ()
291- if default_config is not None :
292- self .configuration_map = default_config
249+ if init_config := self .create_default_config ():
250+ await self ._config .update_global (init_config )
293251
294252 async with (
295253 asyncer .create_task_group () as tg ,
0 commit comments