diff --git a/examples/servers-next/code_actions.py b/examples/servers-next/code_actions.py index 7753b0ee..d5f05137 100644 --- a/examples/servers-next/code_actions.py +++ b/examples/servers-next/code_actions.py @@ -33,7 +33,7 @@ def code_actions(params: types.CodeActionParams): items = [] document_uri = params.text_document.uri - document = server.workspace.get_document(document_uri) + document = server.workspace.get_text_document(document_uri) start_line = params.range.start.line end_line = params.range.end.line diff --git a/tests/conftest.py b/tests/conftest.py index 2662744e..b8a3c27b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -27,7 +27,7 @@ from pygls import IS_PYODIDE from pygls import uris from pygls.feature_manager import FeatureManager -from pygls.lsp._client import LanguageClient +from pygls.lsp._client import LanguageClient as LanguageClient_ from pygls.workspace import Workspace DOC = """document @@ -36,7 +36,21 @@ with "😋" unicode. """ DOC_URI = uris.from_fs_path(__file__) or "" -SERVER_DIR = pathlib.Path(__file__, "..", "..", "examples", "servers-next").resolve() +REPO_DIR = pathlib.Path(__file__, "..", "..").resolve() +SERVER_DIR = REPO_DIR / "examples" / "servers-next" +WORKSPACE_DIR = REPO_DIR / "examples" / "servers" / "workspace" + + +class LanguageClient(LanguageClient_): + """Language client to use for testing.""" + + async def server_exit(self, server: asyncio.subprocess.Process): + # -15: terminated (probably by the client) + # 0: all ok + if server.returncode not in {-15, 0}: + if server.stderr is not None: + err = await server.stderr.read() + self.logger.debug("stderr:\n%s", err.decode("utf8")) def pytest_addoption(parser): @@ -65,16 +79,20 @@ def uri_for(runtime): Takes into account the runtime. """ - base_dir = pathlib.Path( - __file__, "..", "..", "examples", "servers", "workspace" - ).resolve() def fn(*args): - fpath = pathlib.Path(base_dir, *args) + fpath = pathlib.Path(WORKSPACE_DIR, *args) assert fpath.exists() - if runtime != "cpython": + if runtime == "pyodide": raise NotImplementedError(f"uri_for: {runtime=}") + + elif runtime == "wasi": + # WASI cannot see the whole filesystem, so this needs to be made relative to + # the repo root + path = str(fpath).replace(str(REPO_DIR), "") + return uris.from_fs_path(path) + return uris.from_fs_path(str(fpath)) return fn @@ -106,6 +124,34 @@ async def fn(server_name: str): return fn +def get_client_for_wasi_server(uri_fixture): + """Return a client configured to communicate with a server running under WASI. + + This assumes the ``wasmtime`` executable is available to be used as the WASI host. + """ + + async def fn(server_name: str): + client = LanguageClient("pygls-test-suite", "v1") + + # WASI cannot see the whole filesystem, so this needs to be made relative to the + # repo root + server_py = str(SERVER_DIR / server_name).replace(str(REPO_DIR), "") + + # TODO: Un-nixfiy this + await client.start_io("python-wasi", server_py) + + response = await client.initialize( + types.InitializeParams( + capabilities=types.ClientCapabilities(), + root_uri=uri_fixture(""), + ) + ) + assert response is not None + return client, response + + return fn + + @pytest.fixture(scope="session") def get_client_for(runtime, uri_for): """Return a client configured to communicate with the specified server. @@ -115,9 +161,12 @@ def get_client_for(runtime, uri_for): It's the consuming fixture's responsibility to stop the client. """ # TODO: Add TCP/WS support. - if runtime != "cpython": + if runtime == "pyodide": raise NotImplementedError(f"get_client_for: {runtime=}") + elif runtime == "wasi": + return get_client_for_wasi_server(uri_for) + return get_client_for_cpython_server(uri_for)