diff --git a/.gitignore b/.gitignore index ac609b32..4f47251d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ __pycache__/ *.py[cod] *$py.class +# Mypy cache +.mypy_cache/ + # IntelliJ *.iml *.ipr diff --git a/README.md b/README.md index aa427aba..d0d362e8 100644 --- a/README.md +++ b/README.md @@ -84,8 +84,8 @@ All configuration options are described in [`CONFIGURATION.md`](https://github.c To run the test suite: -``` -pip install .[test] && pytest +```sh +pip install '.[test]' && pytest ``` After adding configuration options to `schema.json`, refresh the `CONFIGURATION.md` file with diff --git a/pylsp/python_lsp.py b/pylsp/python_lsp.py index 81efc353..8e96a8d4 100644 --- a/pylsp/python_lsp.py +++ b/pylsp/python_lsp.py @@ -199,7 +199,8 @@ def capabilities(self): log.info('Server capabilities: %s', server_capabilities) return server_capabilities - def m_initialize(self, processId=None, rootUri=None, rootPath=None, initializationOptions=None, **_kwargs): + def m_initialize(self, processId=None, rootUri=None, rootPath=None, + initializationOptions=None, workspaceFolders=None, **_kwargs): log.debug('Language server initialized with %s %s %s %s', processId, rootUri, rootPath, initializationOptions) if rootUri is None: rootUri = uris.from_fs_path(rootPath) if rootPath is not None else '' @@ -210,6 +211,19 @@ def m_initialize(self, processId=None, rootUri=None, rootPath=None, initializati processId, _kwargs.get('capabilities', {})) self.workspace = Workspace(rootUri, self._endpoint, self.config) self.workspaces[rootUri] = self.workspace + if workspaceFolders: + for folder in workspaceFolders: + uri = folder['uri'] + if uri == rootUri: + # Already created + continue + workspace_config = config.Config( + uri, self.config._init_opts, + self.config._process_id, self.config._capabilities) + workspace_config.update(self.config._settings) + self.workspaces[uri] = Workspace( + uri, self._endpoint, workspace_config) + self._dispatchers = self._hook('pylsp_dispatchers') self._hook('pylsp_initialize') diff --git a/test/fixtures.py b/test/fixtures.py index c50c1c10..cce5b328 100644 --- a/test/fixtures.py +++ b/test/fixtures.py @@ -34,6 +34,34 @@ def pylsp(tmpdir): return ls +@pytest.fixture +def pylsp_w_workspace_folders(tmpdir): + """ Return an initialized python LS """ + ls = PythonLSPServer(StringIO, StringIO) + + folder1 = tmpdir.mkdir('folder1') + folder2 = tmpdir.mkdir('folder2') + + ls.m_initialize( + processId=1, + rootUri=uris.from_fs_path(str(folder1)), + initializationOptions={}, + workspaceFolders=[ + { + 'uri': uris.from_fs_path(str(folder1)), + 'name': 'folder1' + }, + { + 'uri': uris.from_fs_path(str(folder2)), + 'name': 'folder2' + } + ] + ) + + workspace_folders = [folder1, folder2] + return (ls, workspace_folders) + + @pytest.fixture def workspace(tmpdir): """Return a workspace.""" diff --git a/test/test_workspace.py b/test/test_workspace.py index e8851e05..a008e7eb 100644 --- a/test/test_workspace.py +++ b/test/test_workspace.py @@ -69,6 +69,45 @@ def test_root_project_with_no_setup_py(pylsp): assert workspace_root in test_doc.sys_path() +def test_multiple_workspaces_from_initialize(pylsp_w_workspace_folders): + pylsp, workspace_folders = pylsp_w_workspace_folders + + assert len(pylsp.workspaces) == 2 + + folders_uris = [uris.from_fs_path(str(folder)) for folder in workspace_folders] + + for folder_uri in folders_uris: + assert folder_uri in pylsp.workspaces + + assert folders_uris[0] == pylsp.root_uri + + # Create file in the first workspace folder. + file1 = workspace_folders[0].join('file1.py') + file1.write('import os') + msg1 = { + 'uri': path_as_uri(str(file1)), + 'version': 1, + 'text': 'import os' + } + + pylsp.m_text_document__did_open(textDocument=msg1) + assert msg1['uri'] in pylsp.workspace._docs + assert msg1['uri'] in pylsp.workspaces[folders_uris[0]]._docs + + # Create file in the second workspace folder. + file2 = workspace_folders[1].join('file2.py') + file2.write('import sys') + msg2 = { + 'uri': path_as_uri(str(file2)), + 'version': 1, + 'text': 'import sys' + } + + pylsp.m_text_document__did_open(textDocument=msg2) + assert msg2['uri'] not in pylsp.workspace._docs + assert msg2['uri'] in pylsp.workspaces[folders_uris[1]]._docs + + def test_multiple_workspaces(tmpdir, pylsp): workspace1_dir = tmpdir.mkdir('workspace1') workspace2_dir = tmpdir.mkdir('workspace2')