-
Notifications
You must be signed in to change notification settings - Fork 196
Use asyncio #2880
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Use asyncio #2880
Changes from 65 commits
699dad3
908c849
b4f0420
76f3c3f
45d7ea6
e8fae30
c511cec
7438d4a
6a104b0
d59bb1c
c0bea09
c1fc59c
e35b611
6cad098
1597782
cc642f4
cea0e99
3d30ad4
472705b
ea34714
069ed50
776749a
0227877
2649a6f
54af917
1a4589c
900f721
35621cf
dbf4d7d
f3b2f84
a9c1692
7004df5
a876949
d27aa93
341ff99
4ed4e3f
7aba65e
e3ccba2
c2c2a8c
af561a8
7260c90
a60ddd2
23210e3
73ed644
6d6e772
a84f3dd
f7702c2
bb51929
7d58862
e2119a1
ce27231
a4aba53
c215234
ae081e3
e4d3324
6e5ca85
4866feb
73a658a
8a6de63
fcb8717
8997d51
5943571
7485b90
edd3ccd
91af0e0
da1fc1d
34697be
aa37898
9335c7d
afde9fb
0795ee4
4659e8d
76aeba1
66bd43a
a143bdf
69fd44d
c2a9e30
8835214
668846c
c6a89b1
9d8c1b3
d271624
68b8945
a3c88ec
3915ca6
82973a5
1ae40fe
45bbb05
998ac1c
9c761d1
056359b
aca3b34
1a6448b
dd2b791
ff9cfd7
5e3af9c
d91eeda
8676dc4
c6efba4
2c2e7b3
119fa99
9e35cc4
8c83c96
691d8ea
0aa553b
e9d65dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
| "bracex", | ||
| "mdpopups", | ||
| "orjson", | ||
| "sublime_aio", | ||
| "typing_extensions", | ||
| "wcmatch" | ||
| ] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,22 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from ..protocol import ConfigurationItem | ||
| from ..protocol import DocumentUri | ||
| from ..protocol import ExecuteCommandParams | ||
| from ..protocol import LSPAny | ||
| from .core.constants import ST_STORAGE_PATH | ||
| from .core.logging import exception_log | ||
| from .core.logging import debug | ||
| from .core.protocol import Notification | ||
| from .core.protocol import Request | ||
|
Comment on lines
+3
to
+10
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All of those additions can be removed (debug unused, the rest duplicated)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BTW. There are still repeated imports in in here and in TYPE_CHECKING section. Would be nice if ruff reported those. |
||
| from .core.protocol import Response | ||
| from .core.settings import client_configs | ||
| from .core.types import method2attr | ||
| from .core.url import parse_uri | ||
| from .core.views import uri_from_view | ||
| from abc import ABC | ||
| from abc import abstractmethod | ||
| from collections.abc import Awaitable | ||
| from dataclasses import dataclass | ||
| from functools import wraps | ||
| from pathlib import Path | ||
|
|
@@ -222,31 +229,33 @@ def decorator(func: Callable[[Any, P], None]) -> Callable[[Any, P], None]: | |
|
|
||
| def request_handler( | ||
| method: str | ||
| ) -> Callable[[Callable[[Any, P], Promise[R]]], Callable[[Any, P, int], Promise[Response[R]]]]: | ||
| ) -> Callable[[Callable[[Any, P], Awaitable[R]]], Callable[[Any, P, int], Awaitable[Response[R]]]]: | ||
| """ | ||
| Decorator to mark a method as a handler for a specific LSP request. | ||
| Decorator to mark a coroutine method as a handler for a specific LSP request. | ||
|
|
||
| Usage: | ||
| ```py | ||
| @request_handler('eslint/openDoc') | ||
| def on_open_doc(self, params: TextDocumentIdentifier) -> Promise[bool]: | ||
| async def on_open_doc(self, params: TextDocumentIdentifier) -> bool: | ||
|
rchl marked this conversation as resolved.
|
||
| ... | ||
| ``` | ||
|
|
||
| The decorated method will be called with the request parameters whenever the specified | ||
| request is received from the language server. The method must return a Promise that resolves | ||
| to the response value. The framework will automatically send it back to the server. | ||
| The decorated coroutine method will be called with the request parameters whenever the specified | ||
| request is received from the language server. The coroutine method must return a response value. | ||
| The framework will automatically send it back to the server. | ||
|
|
||
| An older, but backwards-compatible way to define a request handler is by defining a function that returns a Promise. | ||
| While that works, the advice is to define a coroutine function. | ||
|
|
||
| :param method: The LSP request method name (e.g., 'eslint/openDoc'). | ||
| :returns: A decorator that registers the function as a request handler. | ||
| :returns: A decorator that registers the coroutine function as a request handler. | ||
| """ | ||
|
|
||
| def decorator(func: Callable[[Any, P], Promise[R]]) -> Callable[[Any, P, int], Promise[Response[R]]]: | ||
| def decorator(func: Callable[[Any, P], Awaitable[R]]) -> Callable[[Any, P, int], Awaitable[Response[R]]]: | ||
|
|
||
| @wraps(func) | ||
| def wrapper(self: Any, params: P, request_id: int) -> Promise[Response[Any]]: | ||
| promise = func(self, params) | ||
| return promise.then(lambda result: Response(request_id, result)) | ||
| async def wrapper(self: Any, params: P, request_id: int) -> Response[Any]: | ||
| return Response(request_id, await func(self, params)) | ||
|
|
||
| setattr(wrapper, HANDLER_MARKER, method) | ||
| return wrapper | ||
|
|
@@ -423,6 +432,11 @@ def plugin_unloaded() -> None: | |
| """ | ||
| unregister_plugin_impl(cls) | ||
|
|
||
| @classmethod | ||
| def use_asyncio(cls) -> bool: | ||
| """Override and return `true` to make LSP use `async def` variants.""" | ||
| return False | ||
|
rchl marked this conversation as resolved.
Outdated
|
||
|
|
||
| @classmethod | ||
| def is_applicable_async(cls, context: IsApplicableContext) -> bool: | ||
| """ | ||
|
|
@@ -452,8 +466,8 @@ def on_pre_start_async(cls, context: OnPreStartContext) -> None: | |
| Override to perform any preparation needed before startup - for example installing or updating server binaries, | ||
| resolving the working directory, or injecting extra template variables into `context.variables`. | ||
|
|
||
| This method runs on a worker thread so perform any blocking I/O (e.g. downloading a binary, running | ||
| `npm install`) directly here without spawning additional threads. | ||
| Attempt to use non-blocking functionality for downloading binaries and running subprocesses in order to not | ||
| block the asyncio thread. | ||
|
|
||
| Mutations to `context.working_directory` and `context.variables` are picked up and used when launching the | ||
| server process. | ||
|
|
@@ -465,6 +479,16 @@ def on_pre_start_async(cls, context: OnPreStartContext) -> None: | |
| """ | ||
| pass | ||
|
|
||
| @classmethod | ||
| async def on_pre_start(cls, context: OnPreStartContext) -> None: | ||
| """ | ||
| Async version of on_pre_start_async. | ||
|
|
||
| :param context: The startup context. `context.configuration`, `context.variables` and | ||
| `context.working_directory` can be mutated to influence how the server is launched. | ||
| """ | ||
| pass | ||
|
|
||
| def __init__(self, weaksession: ref[Session]) -> None: | ||
| """ | ||
| Constructs a new instance. | ||
|
|
@@ -483,7 +507,7 @@ def __init_subclass__(cls, **kwargs: Any) -> None: | |
| cls.name = cls.__module__.split('.')[0] # pyright: ignore[reportAttributeAccessIssue] | ||
| cls.plugin_storage_path = Path(ST_STORAGE_PATH, cls.name) # pyright: ignore[reportAttributeAccessIssue] | ||
|
|
||
| def on_transport_ready_async(self, transport: TransportWrapper) -> None: | ||
| async def on_transport_ready(self, transport: TransportWrapper) -> None: | ||
| """ | ||
| Called after the transport is established but before the LSP `initialize` request is sent. | ||
|
|
||
|
|
@@ -501,10 +525,12 @@ def on_transport_ready_async(self, transport: TransportWrapper) -> None: | |
| """ | ||
| pass | ||
|
|
||
| def on_initialize_async(self) -> None: | ||
| async def on_initialize(self) -> None: | ||
| """ | ||
| Called after the `initialize` response has been received from the language server. | ||
|
|
||
| TODO: invoked before or after the `initialized` notification? | ||
|
rchl marked this conversation as resolved.
Outdated
|
||
|
|
||
| Override to perform any post-initialization work, such as sending custom notifications or requests | ||
| that depend on the server's capabilities reported in the `initialize` response. | ||
| """ | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.