55
55
from .session_buffer import SessionBuffer
56
56
from .session_view import SessionView
57
57
from functools import partial
58
- from typing import Any , Callable , Generator , Iterable
58
+ from functools import wraps
59
+ from typing import Any , Callable , Generator , Iterable , TypeVar
59
60
from typing import cast
61
+ from typing_extensions import ParamSpec
60
62
from weakref import WeakSet
61
63
from weakref import WeakValueDictionary
62
64
import itertools
68
70
69
71
SUBLIME_WORD_MASK = 515
70
72
73
+ P = ParamSpec ('P' )
74
+ R = TypeVar ('R' )
75
+
76
+
77
+ def requires_session (func : Callable [P , R ]) -> Callable [P , R | None ]:
78
+ """
79
+ A decorator for the `DocumentSyncListener` event handlers, which immediately returns `None` if there are no
80
+ `SessionView`s.
81
+ """
82
+ @wraps (func )
83
+ def wrapper (self : DocumentSyncListener , * args : P .args , ** kwargs : P .kwargs ) -> R | None :
84
+ if not self .session_views_async ():
85
+ return None
86
+ return func (self , * args , ** kwargs ) # pyright: ignore[reportCallIssue]
87
+ return wrapper # pyright: ignore[reportReturnType]
88
+
71
89
72
90
def is_regular_view (v : sublime .View ) -> bool :
73
91
# Not from the quick panel (CTRL+P), and not a special view like a console, output panel or find-in-files panels.
@@ -327,12 +345,10 @@ def session_buffers_async(self, capability: str | None = None) -> list[SessionBu
327
345
def session_views_async (self ) -> list [SessionView ]:
328
346
return list (self ._session_views .values ())
329
347
348
+ @requires_session
330
349
def on_text_changed_async (self , change_count : int , changes : Iterable [sublime .TextChange ]) -> None :
331
- session_views = self .session_views_async ()
332
- if not session_views :
333
- return
334
350
if self .view .is_primary ():
335
- for sv in session_views :
351
+ for sv in self . session_views_async () :
336
352
sv .on_text_changed_async (change_count , changes )
337
353
self ._on_view_updated_async ()
338
354
@@ -387,9 +403,9 @@ def on_activated_async(self) -> None:
387
403
sb .set_inlay_hints_pending_refresh (needs_refresh = False )
388
404
sb .do_inlay_hints_async (self .view )
389
405
406
+ @requires_session
390
407
def on_selection_modified_async (self ) -> None :
391
- if not self .session_views_async ():
392
- return
408
+ print ("LSP: on_selection_modified_async" )
393
409
first_region , _ = self ._update_stored_selection_async ()
394
410
if first_region is None :
395
411
return
@@ -490,9 +506,8 @@ def on_query_context(self, key: str, operator: int, operand: Any, match_all: boo
490
506
return operand == bool (session_view .session_buffer .get_document_link_at_point (self .view , position ))
491
507
return None
492
508
509
+ @requires_session
493
510
def on_hover (self , point : int , hover_zone : int ) -> None :
494
- if not self .session_views_async ():
495
- return
496
511
if self .view .is_popup_visible ():
497
512
return
498
513
window = self .view .window ()
@@ -534,9 +549,8 @@ def _on_hover_gutter_async(self, point: int) -> None:
534
549
location = point ,
535
550
on_navigate = lambda href : self ._on_navigate (href , point ))
536
551
552
+ @requires_session
537
553
def on_text_command (self , command_name : str , args : dict | None ) -> tuple [str , dict ] | None :
538
- if not self .session_views_async ():
539
- return None
540
554
if command_name == "auto_complete" :
541
555
self ._auto_complete_triggered_manually = True
542
556
elif command_name == "show_scope_name" and userprefs ().semantic_highlighting :
@@ -551,9 +565,8 @@ def on_text_command(self, command_name: str, args: dict | None) -> tuple[str, di
551
565
return ('paste' , {})
552
566
return None
553
567
568
+ @requires_session
554
569
def on_post_text_command (self , command_name : str , args : dict [str , Any ] | None ) -> None :
555
- if not self .session_views_async ():
556
- return
557
570
if command_name == 'paste' :
558
571
format_on_paste = self .view .settings ().get ('lsp_format_on_paste' , userprefs ().lsp_format_on_paste )
559
572
if format_on_paste and self .session_async ("documentRangeFormattingProvider" ):
@@ -566,9 +579,8 @@ def on_post_text_command(self, command_name: str, args: dict[str, Any] | None) -
566
579
# hide the popup when `esc` or arrows are pressed pressed
567
580
self .view .hide_popup ()
568
581
582
+ @requires_session
569
583
def on_query_completions (self , prefix : str , locations : list [int ]) -> sublime .CompletionList | None :
570
- if not self .session_views_async ():
571
- return None
572
584
completion_list = sublime .CompletionList ()
573
585
triggered_manually = self ._auto_complete_triggered_manually
574
586
self ._auto_complete_triggered_manually = False # reset state for next completion popup
0 commit comments