Skip to content

Commit 3f3944f

Browse files
committed
refactor(langserver): correct refresh handling and remove some unneeded code
1 parent 3adddd1 commit 3f3944f

File tree

16 files changed

+118
-179
lines changed

16 files changed

+118
-179
lines changed

packages/core/src/robotcode/core/async_itertools.py

Lines changed: 0 additions & 93 deletions
This file was deleted.

packages/core/src/robotcode/core/async_tools.py

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -519,29 +519,6 @@ def set_result(w: asyncio.Future[Any], ev: threading.Event) -> None:
519519
self._wake_up_first()
520520

521521

522-
class RLock(Lock):
523-
def __init__(self) -> None:
524-
super().__init__()
525-
self._task: Optional[asyncio.Task[Any]] = None
526-
self._depth = 0
527-
528-
async def acquire(self) -> bool:
529-
if self._task is None or self._task != asyncio.current_task():
530-
await super().acquire()
531-
self._task = asyncio.current_task()
532-
assert self._depth == 0
533-
self._depth += 1
534-
535-
return True
536-
537-
def release(self) -> None:
538-
if self._depth > 0:
539-
self._depth -= 1
540-
if self._depth == 0:
541-
super().release()
542-
self._task = None
543-
544-
545522
_global_futures_set: Set[asyncio.Future[Any]] = set()
546523

547524

packages/core/src/robotcode/core/concurrent.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from threading import Event, RLock, Thread, current_thread, local
44
from typing import Any, Callable, Dict, Generic, List, Optional, Tuple, TypeVar, cast, overload
55

6+
from typing_extensions import ParamSpec
7+
68
_F = TypeVar("_F", bound=Callable[..., Any])
79
_TResult = TypeVar("_TResult")
810

@@ -118,7 +120,10 @@ def _remove_future_from_running_callables(future: FutureEx[Any]) -> None:
118120
_running_callables.pop(future, None)
119121

120122

121-
def run_in_thread(callable: Callable[..., _TResult], *args: Any, **kwargs: Any) -> FutureEx[_TResult]:
123+
_P = ParamSpec("_P")
124+
125+
126+
def run_in_thread(callable: Callable[_P, _TResult], *args: _P.args, **kwargs: _P.kwargs) -> FutureEx[_TResult]:
122127
future: FutureEx[_TResult] = FutureEx()
123128
with _running_callables_lock:
124129
thread = Thread(

packages/debugger/src/robotcode/debugger/launcher/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def __del__(self) -> None:
6464
self.close()
6565

6666
@_logger.call
67-
async def on_connection_lost(self, sender: Any, exc: Optional[BaseException]) -> None:
67+
def on_connection_lost(self, sender: Any, exc: Optional[BaseException]) -> None:
6868
if sender == self._protocol:
6969
self._protocol = None
7070

packages/jsonrpc2/src/robotcode/jsonrpc2/protocol.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@
3333
)
3434

3535
from robotcode.core.async_tools import (
36-
async_event,
3736
create_sub_task,
3837
run_coroutine_in_thread,
3938
)
4039
from robotcode.core.concurrent import FutureEx, is_threaded_callable, run_in_thread
40+
from robotcode.core.event import event
4141
from robotcode.core.utils.dataclasses import as_json, from_dict
4242
from robotcode.core.utils.inspect import ensure_coroutine, iter_methods
4343
from robotcode.core.utils.logging import LoggingDescriptor
@@ -374,12 +374,12 @@ def __init__(self) -> None:
374374
def loop(self) -> Optional[asyncio.AbstractEventLoop]:
375375
return self._loop
376376

377-
@async_event
378-
async def on_connection_made(sender, transport: asyncio.BaseTransport) -> None:
377+
@event
378+
def on_connection_made(sender, transport: asyncio.BaseTransport) -> None:
379379
...
380380

381-
@async_event
382-
async def on_connection_lost(sender, exc: Optional[BaseException]) -> None:
381+
@event
382+
def on_connection_lost(sender, exc: Optional[BaseException]) -> None:
383383
...
384384

385385
def connection_made(self, transport: asyncio.BaseTransport) -> None:
@@ -390,10 +390,10 @@ def connection_made(self, transport: asyncio.BaseTransport) -> None:
390390
if isinstance(transport, asyncio.WriteTransport):
391391
self.write_transport = transport
392392

393-
create_sub_task(self.on_connection_made(self, transport))
393+
self.on_connection_made(self, transport)
394394

395395
def connection_lost(self, exc: Optional[BaseException]) -> None:
396-
create_sub_task(self.on_connection_lost(self, exc))
396+
self.on_connection_lost(self, exc)
397397
self._loop = None
398398

399399
def eof_received(self) -> Optional[bool]:
@@ -451,6 +451,7 @@ def __init__(self) -> None:
451451
self._received_request: OrderedDict[Union[str, int, None], ReceivedRequestEntry] = OrderedDict()
452452
self._received_request_lock = threading.RLock()
453453
self._signature_cache: Dict[Callable[..., Any], inspect.Signature] = {}
454+
self._running_handle_message_tasks: Set[asyncio.Future[Any]] = set()
454455

455456
@staticmethod
456457
def _generate_json_rpc_messages_from_dict(
@@ -494,15 +495,10 @@ def _handle_body(self, body: bytes, charset: str) -> None:
494495
self.send_error(JsonRPCErrors.PARSE_ERROR, f"{type(e).__name__}: {e}")
495496

496497
def _handle_messages(self, iterator: Iterator[JsonRPCMessage]) -> None:
497-
def done(f: asyncio.Future[Any]) -> None:
498-
if f.done() and not f.cancelled():
499-
ex = f.exception()
500-
501-
if ex is None or isinstance(ex, asyncio.CancelledError):
502-
return
503-
504498
for m in iterator:
505-
create_sub_task(self.handle_message(m)).add_done_callback(done)
499+
task = asyncio.create_task(self.handle_message(m))
500+
self._running_handle_message_tasks.add(task)
501+
task.add_done_callback(self._running_handle_message_tasks.discard)
506502

507503
@__logger.call
508504
async def handle_message(self, message: JsonRPCMessage) -> None:

packages/language_server/src/robotcode/language_server/common/parts/code_lens.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from concurrent.futures import CancelledError
22
from typing import TYPE_CHECKING, Any, Final, List, Optional
33

4-
from robotcode.core.concurrent import FutureEx, check_current_thread_canceled, threaded
4+
from robotcode.core.concurrent import FutureEx, check_current_thread_canceled, run_in_thread, threaded
55
from robotcode.core.event import event
66
from robotcode.core.lsp.types import (
77
CodeLens,
@@ -90,13 +90,20 @@ def _code_lens_resolve(self, params: CodeLens, *args: Any, **kwargs: Any) -> Cod
9090

9191
return params
9292

93-
def refresh(self) -> None:
94-
if not (
93+
def refresh(self, now: bool = True) -> None:
94+
if self.refresh_task is not None and not self.refresh_task.done():
95+
self.refresh_task.cancel()
96+
97+
self.refresh_task = run_in_thread(self._refresh, now)
98+
99+
def _refresh(self, now: bool = True) -> None:
100+
if (
95101
self.parent.client_capabilities is not None
96102
and self.parent.client_capabilities.workspace is not None
97103
and self.parent.client_capabilities.workspace.code_lens is not None
98104
and self.parent.client_capabilities.workspace.code_lens.refresh_support
99105
):
100-
return
106+
if not now:
107+
check_current_thread_canceled(1)
101108

102-
self.parent.send_request("workspace/codeLens/refresh").result(self._refresh_timeout)
109+
self.parent.send_request("workspace/codeLens/refresh").result(self._refresh_timeout)

packages/language_server/src/robotcode/language_server/common/parts/diagnostics.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ def __init__(self, protocol: "LanguageServerProtocol") -> None:
100100

101101
self.client_supports_pull = False
102102

103+
self._refresh_timeout = 5
104+
103105
def server_initialized(self, sender: Any) -> None:
104106
self._workspace_diagnostics_task = run_in_thread(self.run_workspace_diagnostics)
105107

@@ -221,6 +223,8 @@ def run_workspace_diagnostics(self) -> None:
221223
"Analyse workspace", cancellable=False, current=0, max=len(documents) + 1, start=False
222224
) as progress:
223225
for i, document in enumerate(documents):
226+
check_current_thread_canceled()
227+
224228
mode = self.get_diagnostics_mode(document.uri)
225229
if mode == DiagnosticsMode.OFF:
226230
self.get_diagnostics_data(document).version = document.version
@@ -418,23 +422,20 @@ def get_diagnostics_mode(self, uri: Uri) -> DiagnosticsMode:
418422

419423
return DiagnosticsMode.OPENFILESONLY
420424

421-
def __do_refresh(self, now: bool = False) -> None:
422-
if not now:
423-
check_current_thread_canceled(1)
424-
425-
self.__refresh()
426-
427425
def refresh(self, now: bool = False) -> None:
428426
if self.refresh_task is not None and not self.refresh_task.done():
429427
self.refresh_task.cancel()
430428

431-
self.refresh_task = run_in_thread(self.__do_refresh, now)
429+
self.refresh_task = run_in_thread(self._refresh, now)
432430

433-
def __refresh(self) -> None:
431+
def _refresh(self, now: bool = False) -> None:
434432
if (
435433
self.parent.client_capabilities
436434
and self.parent.client_capabilities.workspace
437435
and self.parent.client_capabilities.workspace.diagnostics
438436
and self.parent.client_capabilities.workspace.diagnostics.refresh_support
439437
):
440-
self.parent.send_request("workspace/diagnostic/refresh").result(30)
438+
if not now:
439+
check_current_thread_canceled(1)
440+
441+
self.parent.send_request("workspace/diagnostic/refresh").result(self._refresh_timeout)

packages/language_server/src/robotcode/language_server/common/parts/inlay_hint.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from concurrent.futures import CancelledError
22
from typing import TYPE_CHECKING, Any, Final, List, Optional
33

4-
from robotcode.core.concurrent import threaded
4+
from robotcode.core.concurrent import FutureEx, check_current_thread_canceled, run_in_thread, threaded
55
from robotcode.core.event import event
66
from robotcode.core.lsp.types import (
77
InlayHint,
@@ -27,6 +27,8 @@ class InlayHintProtocolPart(LanguageServerProtocolPart):
2727

2828
def __init__(self, parent: "LanguageServerProtocol") -> None:
2929
super().__init__(parent)
30+
self.refresh_task: Optional[FutureEx[Any]] = None
31+
self._refresh_timeout = 5
3032

3133
@event
3234
def collect(sender, document: TextDocument, range: Range) -> Optional[List[InlayHint]]: # NOSONAR
@@ -98,11 +100,20 @@ def _inlay_hint_resolve(
98100

99101
return params
100102

101-
def refresh(self) -> None:
103+
def refresh(self, now: bool = True) -> None:
104+
if self.refresh_task is not None and not self.refresh_task.done():
105+
self.refresh_task.cancel()
106+
107+
self.refresh_task = run_in_thread(self._refresh, now)
108+
109+
def _refresh(self, now: bool = True) -> None:
102110
if (
103111
self.parent.client_capabilities is not None
104112
and self.parent.client_capabilities.workspace is not None
105113
and self.parent.client_capabilities.workspace.inlay_hint is not None
106114
and self.parent.client_capabilities.workspace.inlay_hint.refresh_support
107115
):
108-
self.parent.send_request("workspace/inlayHint/refresh").result(30)
116+
if not now:
117+
check_current_thread_canceled(1)
118+
119+
self.parent.send_request("workspace/inlayHint/refresh").result(self._refresh_timeout)

packages/language_server/src/robotcode/language_server/common/parts/inline_value.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from asyncio import CancelledError
22
from typing import TYPE_CHECKING, Any, Final, List, Optional
33

4-
from robotcode.core.concurrent import check_current_thread_canceled, threaded
4+
from robotcode.core.concurrent import FutureEx, check_current_thread_canceled, run_in_thread, threaded
55
from robotcode.core.event import event
66
from robotcode.core.lsp.types import (
77
DocumentSelector,
@@ -31,6 +31,8 @@ class InlineValueProtocolPart(LanguageServerProtocolPart):
3131

3232
def __init__(self, parent: "LanguageServerProtocol") -> None:
3333
super().__init__(parent)
34+
self.refresh_task: Optional[FutureEx[Any]] = None
35+
self._refresh_timeout = 5
3436

3537
@event
3638
def collect(
@@ -88,11 +90,20 @@ def _text_document_inline_value(
8890

8991
return results
9092

91-
def refresh(self) -> None:
93+
def refresh(self, now: bool = True) -> None:
94+
if self.refresh_task is not None and not self.refresh_task.done():
95+
self.refresh_task.cancel()
96+
97+
self.refresh_task = run_in_thread(self._refresh, now)
98+
99+
def _refresh(self, now: bool = True) -> None:
92100
if (
93101
self.parent.client_capabilities
94102
and self.parent.client_capabilities.workspace
95103
and self.parent.client_capabilities.workspace.inline_value
96104
and self.parent.client_capabilities.workspace.inline_value.refresh_support
97105
):
98-
self.parent.send_request("workspace/inlineValue/refresh").result(30)
106+
if not now:
107+
check_current_thread_canceled(1)
108+
109+
self.parent.send_request("workspace/inlineValue/refresh").result(self._refresh_timeout)

0 commit comments

Comments
 (0)