@@ -75,6 +75,9 @@ class PythonLanguageServer(MethodDispatcher):
75
75
def __init__ (self , rx , tx , check_parent_process = False ):
76
76
self .workspace = None
77
77
self .config = None
78
+ self .root_uri = None
79
+ self .workspaces = {}
80
+ self .uri_workspace_mapper = {}
78
81
79
82
self ._jsonrpc_stream_reader = JsonRpcStreamReader (rx )
80
83
self ._jsonrpc_stream_writer = JsonRpcStreamWriter (tx )
@@ -115,11 +118,16 @@ def m_exit(self, **_kwargs):
115
118
self ._jsonrpc_stream_reader .close ()
116
119
self ._jsonrpc_stream_writer .close ()
117
120
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
+
118
125
def _hook (self , hook_name , doc_uri = None , ** kwargs ):
119
126
"""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
121
129
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 )
123
131
124
132
def capabilities (self ):
125
133
server_capabilities = {
@@ -152,6 +160,12 @@ def capabilities(self):
152
160
},
153
161
'openClose' : True ,
154
162
},
163
+ 'workspace' : {
164
+ 'workspaceFolders' : {
165
+ 'supported' : True ,
166
+ 'changeNotifications' : True
167
+ }
168
+ },
155
169
'experimental' : merge (self ._hook ('pyls_experimental_capabilities' ))
156
170
}
157
171
log .info ('Server capabilities: %s' , server_capabilities )
@@ -162,7 +176,10 @@ def m_initialize(self, processId=None, rootUri=None, rootPath=None, initializati
162
176
if rootUri is None :
163
177
rootUri = uris .from_fs_path (rootPath ) if rootPath is not None else ''
164
178
179
+ self .workspaces .pop (self .root_uri , None )
180
+ self .root_uri = rootUri
165
181
self .workspace = Workspace (rootUri , self ._endpoint )
182
+ self .workspaces [rootUri ] = self .workspace
166
183
self .config = config .Config (rootUri , initializationOptions or {},
167
184
processId , _kwargs .get ('capabilities' , {}))
168
185
self ._dispatchers = self ._hook ('pyls_dispatchers' )
@@ -224,8 +241,9 @@ def hover(self, doc_uri, position):
224
241
@_utils .debounce (LINT_DEBOUNCE_S , keyed_by = 'doc_uri' )
225
242
def lint (self , doc_uri , is_saved ):
226
243
# 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 (
229
247
doc_uri ,
230
248
flatten (self ._hook ('pyls_lint' , doc_uri , is_saved = is_saved ))
231
249
)
@@ -243,16 +261,19 @@ def signature_help(self, doc_uri, position):
243
261
return self ._hook ('pyls_signature_help' , doc_uri , position = position )
244
262
245
263
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' ])
247
266
248
267
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' ))
250
270
self ._hook ('pyls_document_did_open' , textDocument ['uri' ])
251
271
self .lint (textDocument ['uri' ], is_saved = True )
252
272
253
273
def m_text_document__did_change (self , contentChanges = None , textDocument = None , ** _kwargs ):
274
+ workspace = self ._match_uri_to_workspace (textDocument ['uri' ])
254
275
for change in contentChanges :
255
- self . workspace .update_document (
276
+ workspace .update_document (
256
277
textDocument ['uri' ],
257
278
change ,
258
279
version = textDocument .get ('version' )
@@ -303,8 +324,27 @@ def m_text_document__signature_help(self, textDocument=None, position=None, **_k
303
324
304
325
def m_workspace__did_change_configuration (self , settings = None ):
305
326
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
308
348
309
349
def m_workspace__did_change_watched_files (self , changes = None , ** _kwargs ):
310
350
changed_py_files = set ()
@@ -321,10 +361,12 @@ def m_workspace__did_change_watched_files(self, changes=None, **_kwargs):
321
361
# Only externally changed python files and lint configs may result in changed diagnostics.
322
362
return
323
363
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 )
328
370
329
371
def m_workspace__execute_command (self , command = None , arguments = None ):
330
372
return self .execute_command (command , arguments )
0 commit comments