Skip to content

Commit d08ea2b

Browse files
committed
Initialize workspaces from the initialize request
Don't ignore workspace folders provided through the initialize request expecting that the client calls sends the workspace/didChangeWorkspaceFolders notification. Expecting that notification is a bug since it only needs to be sent when folders change, relative to the ones reported in initialize. Fixes #48
1 parent cfe7994 commit d08ea2b

File tree

5 files changed

+88
-3
lines changed

5 files changed

+88
-3
lines changed

Diff for: .gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ __pycache__/
33
*.py[cod]
44
*$py.class
55

6+
# Mypy cache
7+
.mypy_cache/
8+
69
# IntelliJ
710
*.iml
811
*.ipr

Diff for: README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ To enable pydocstyle for linting docstrings add the following setting in your LS
8282

8383
To run the test suite:
8484

85-
```
86-
pip install .[test] && pytest
85+
```sh
86+
pip install '.[test]' && pytest
8787
```
8888

8989
## License

Diff for: pylsp/python_lsp.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ def capabilities(self):
199199
log.info('Server capabilities: %s', server_capabilities)
200200
return server_capabilities
201201

202-
def m_initialize(self, processId=None, rootUri=None, rootPath=None, initializationOptions=None, **_kwargs):
202+
def m_initialize(self, processId=None, rootUri=None, rootPath=None,
203+
initializationOptions=None, workspaceFolders=None, **_kwargs):
203204
log.debug('Language server initialized with %s %s %s %s', processId, rootUri, rootPath, initializationOptions)
204205
if rootUri is None:
205206
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
210211
processId, _kwargs.get('capabilities', {}))
211212
self.workspace = Workspace(rootUri, self._endpoint, self.config)
212213
self.workspaces[rootUri] = self.workspace
214+
if workspaceFolders:
215+
for folder in workspaceFolders:
216+
uri = folder['uri']
217+
if uri == rootUri:
218+
# Already created
219+
continue
220+
workspace_config = config.Config(
221+
uri, self.config._init_opts,
222+
self.config._process_id, self.config._capabilities)
223+
workspace_config.update(self.config._settings)
224+
self.workspaces[uri] = Workspace(
225+
uri, self._endpoint, workspace_config)
226+
213227
self._dispatchers = self._hook('pylsp_dispatchers')
214228
self._hook('pylsp_initialize')
215229

Diff for: test/fixtures.py

+29
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,35 @@ def pylsp(tmpdir):
3434
return ls
3535

3636

37+
@pytest.fixture
38+
def pylsp_w_workspace_folders(tmpdir):
39+
""" Return an initialized python LS """
40+
ls = PythonLSPServer(StringIO, StringIO)
41+
42+
folder1 = tmpdir.mkdir('folder1')
43+
folder2 = tmpdir.mkdir('folder2')
44+
45+
ls.m_initialize(
46+
processId=1,
47+
rootUri=uris.from_fs_path(str(folder1)),
48+
initializationOptions={},
49+
workspaceFolders=[
50+
{
51+
'uri': uris.from_fs_path(str(folder1)),
52+
'name': 'folder1'
53+
},
54+
{
55+
'uri': uris.from_fs_path(str(folder2)),
56+
'name': 'folder2'
57+
}
58+
]
59+
60+
)
61+
62+
workspace_folders = [folder1, folder2]
63+
return (ls, workspace_folders)
64+
65+
3766
@pytest.fixture
3867
def workspace(tmpdir):
3968
"""Return a workspace."""

Diff for: test/test_workspace.py

+39
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,45 @@ def test_root_project_with_no_setup_py(pylsp):
6969
assert workspace_root in test_doc.sys_path()
7070

7171

72+
def test_multiple_workspaces_from_initialize(pylsp_w_workspace_folders):
73+
pylsp, workspace_folders = pylsp_w_workspace_folders
74+
75+
assert len(pylsp.workspaces) == 2
76+
77+
folders_uris = [uris.from_fs_path(str(folder)) for folder in workspace_folders]
78+
79+
for folder_uri in folders_uris:
80+
assert folder_uri in pylsp.workspaces
81+
82+
assert folders_uris[0] == pylsp.root_uri
83+
84+
# Create file in the first workspace folder.
85+
file1 = workspace_folders[0].join('file1.py')
86+
file1.write('import os')
87+
msg1 = {
88+
'uri': path_as_uri(str(file1)),
89+
'version': 1,
90+
'text': 'import os'
91+
}
92+
93+
pylsp.m_text_document__did_open(textDocument=msg1)
94+
assert msg1['uri'] in pylsp.workspace._docs
95+
assert msg1['uri'] in pylsp.workspaces[folders_uris[0]]._docs
96+
97+
# Create file in the second workspace folder.
98+
file2 = workspace_folders[1].join('file2.py')
99+
file2.write('import sys')
100+
msg2 = {
101+
'uri': path_as_uri(str(file2)),
102+
'version': 1,
103+
'text': 'import sys'
104+
}
105+
106+
pylsp.m_text_document__did_open(textDocument=msg2)
107+
assert msg2['uri'] not in pylsp.workspace._docs
108+
assert msg2['uri'] in pylsp.workspaces[folders_uris[1]]._docs
109+
110+
72111
def test_multiple_workspaces(tmpdir, pylsp):
73112
workspace1_dir = tmpdir.mkdir('workspace1')
74113
workspace2_dir = tmpdir.mkdir('workspace2')

0 commit comments

Comments
 (0)