@@ -75,6 +75,9 @@ class PythonLanguageServer(MethodDispatcher):
7575 def __init__ (self , rx , tx , check_parent_process = False ):
7676 self .workspace = None
7777 self .config = None
78+ self .root_uri = None
79+ self .workspaces = {}
80+ self .uri_workspace_mapper = {}
7881
7982 self ._jsonrpc_stream_reader = JsonRpcStreamReader (rx )
8083 self ._jsonrpc_stream_writer = JsonRpcStreamWriter (tx )
@@ -115,11 +118,16 @@ def m_exit(self, **_kwargs):
115118 self ._jsonrpc_stream_reader .close ()
116119 self ._jsonrpc_stream_writer .close ()
117120
121+ def _match_uri_to_workspace (self , uri ):
122+ workspace_uri = _utils .match_uri_to_workspace (uri , self .workspaces )
123+ return self .workspaces .get (workspace_uri , self .workspace )
124+
118125 def _hook (self , hook_name , doc_uri = None , ** kwargs ):
119126 """Calls hook_name and returns a list of results from all registered handlers"""
120- doc = self .workspace .get_document (doc_uri ) if doc_uri else None
127+ workspace = self ._match_uri_to_workspace (doc_uri )
128+ doc = workspace .get_document (doc_uri ) if doc_uri else None
121129 hook_handlers = self .config .plugin_manager .subset_hook_caller (hook_name , self .config .disabled_plugins )
122- return hook_handlers (config = self .config , workspace = self . workspace , document = doc , ** kwargs )
130+ return hook_handlers (config = self .config , workspace = workspace , document = doc , ** kwargs )
123131
124132 def capabilities (self ):
125133 server_capabilities = {
@@ -152,6 +160,12 @@ def capabilities(self):
152160 },
153161 'openClose' : True ,
154162 },
163+ 'workspace' : {
164+ 'workspaceFolders' : {
165+ 'supported' : True ,
166+ 'changeNotifications' : True
167+ }
168+ },
155169 'experimental' : merge (self ._hook ('pyls_experimental_capabilities' ))
156170 }
157171 log .info ('Server capabilities: %s' , server_capabilities )
@@ -162,7 +176,10 @@ def m_initialize(self, processId=None, rootUri=None, rootPath=None, initializati
162176 if rootUri is None :
163177 rootUri = uris .from_fs_path (rootPath ) if rootPath is not None else ''
164178
179+ self .workspaces .pop (self .root_uri , None )
180+ self .root_uri = rootUri
165181 self .workspace = Workspace (rootUri , self ._endpoint )
182+ self .workspaces [rootUri ] = self .workspace
166183 self .config = config .Config (rootUri , initializationOptions or {},
167184 processId , _kwargs .get ('capabilities' , {}))
168185 self ._dispatchers = self ._hook ('pyls_dispatchers' )
@@ -224,8 +241,9 @@ def hover(self, doc_uri, position):
224241 @_utils .debounce (LINT_DEBOUNCE_S , keyed_by = 'doc_uri' )
225242 def lint (self , doc_uri , is_saved ):
226243 # Since we're debounced, the document may no longer be open
227- if doc_uri in self .workspace .documents :
228- self .workspace .publish_diagnostics (
244+ workspace = self ._match_uri_to_workspace (doc_uri )
245+ if doc_uri in workspace .documents :
246+ workspace .publish_diagnostics (
229247 doc_uri ,
230248 flatten (self ._hook ('pyls_lint' , doc_uri , is_saved = is_saved ))
231249 )
@@ -243,16 +261,19 @@ def signature_help(self, doc_uri, position):
243261 return self ._hook ('pyls_signature_help' , doc_uri , position = position )
244262
245263 def m_text_document__did_close (self , textDocument = None , ** _kwargs ):
246- self .workspace .rm_document (textDocument ['uri' ])
264+ workspace = self ._match_uri_to_workspace (textDocument ['uri' ])
265+ workspace .rm_document (textDocument ['uri' ])
247266
248267 def m_text_document__did_open (self , textDocument = None , ** _kwargs ):
249- self .workspace .put_document (textDocument ['uri' ], textDocument ['text' ], version = textDocument .get ('version' ))
268+ workspace = self ._match_uri_to_workspace (textDocument ['uri' ])
269+ workspace .put_document (textDocument ['uri' ], textDocument ['text' ], version = textDocument .get ('version' ))
250270 self ._hook ('pyls_document_did_open' , textDocument ['uri' ])
251271 self .lint (textDocument ['uri' ], is_saved = True )
252272
253273 def m_text_document__did_change (self , contentChanges = None , textDocument = None , ** _kwargs ):
274+ workspace = self ._match_uri_to_workspace (textDocument ['uri' ])
254275 for change in contentChanges :
255- self . workspace .update_document (
276+ workspace .update_document (
256277 textDocument ['uri' ],
257278 change ,
258279 version = textDocument .get ('version' )
@@ -303,8 +324,27 @@ def m_text_document__signature_help(self, textDocument=None, position=None, **_k
303324
304325 def m_workspace__did_change_configuration (self , settings = None ):
305326 self .config .update ((settings or {}).get ('pyls' , {}))
306- for doc_uri in self .workspace .documents :
307- self .lint (doc_uri , is_saved = False )
327+ for workspace_uri in self .workspaces :
328+ workspace = self .workspaces [workspace_uri ]
329+ for doc_uri in workspace .documents :
330+ self .lint (doc_uri , is_saved = False )
331+
332+ def m_workspace__did_change_workspace_folders (self , added = None , removed = None , ** _kwargs ):
333+ for removed_info in removed :
334+ removed_uri = removed_info ['uri' ]
335+ self .workspaces .pop (removed_uri )
336+
337+ for added_info in added :
338+ added_uri = added_info ['uri' ]
339+ self .workspaces [added_uri ] = Workspace (added_uri , self ._endpoint )
340+
341+ # Migrate documents that are on the root workspace and have a better
342+ # match now
343+ doc_uris = list (self .workspace ._docs .keys ())
344+ for uri in doc_uris :
345+ doc = self .workspace ._docs .pop (uri )
346+ new_workspace = self ._match_uri_to_workspace (uri )
347+ new_workspace ._docs [uri ] = doc
308348
309349 def m_workspace__did_change_watched_files (self , changes = None , ** _kwargs ):
310350 changed_py_files = set ()
@@ -321,10 +361,12 @@ def m_workspace__did_change_watched_files(self, changes=None, **_kwargs):
321361 # Only externally changed python files and lint configs may result in changed diagnostics.
322362 return
323363
324- for doc_uri in self .workspace .documents :
325- # Changes in doc_uri are already handled by m_text_document__did_save
326- if doc_uri not in changed_py_files :
327- self .lint (doc_uri , is_saved = False )
364+ for workspace_uri in self .workspaces :
365+ workspace = self .workspaces [workspace_uri ]
366+ for doc_uri in workspace .documents :
367+ # Changes in doc_uri are already handled by m_text_document__did_save
368+ if doc_uri not in changed_py_files :
369+ self .lint (doc_uri , is_saved = False )
328370
329371 def m_workspace__execute_command (self , command = None , arguments = None ):
330372 return self .execute_command (command , arguments )
0 commit comments