Skip to content
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

Make DocumentSyncListener more efficient if no server is running #2532

Merged
merged 4 commits into from
Oct 20, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions plugin/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@
from .session_buffer import SessionBuffer
from .session_view import SessionView
from functools import partial
from typing import Any, Callable, Generator, Iterable
from functools import wraps
from typing import Any, Callable, Generator, Iterable, TypeVar
from typing import cast
from typing_extensions import Concatenate, ParamSpec
Comment on lines -58 to +61
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some crazy type stuff that I'm not gonna invest time in learning now but I'm glad you found a way to type this properly :)

from weakref import WeakSet
from weakref import WeakValueDictionary
import itertools
Expand All @@ -68,6 +70,24 @@

SUBLIME_WORD_MASK = 515

P = ParamSpec('P')
R = TypeVar('R')


def requires_session(
func: Callable[Concatenate[DocumentSyncListener, P], R]
) -> Callable[Concatenate[DocumentSyncListener, P], R | None]:
"""
A decorator for the `DocumentSyncListener` event handlers, which immediately returns `None` if there are no
`SessionView`s.
"""
@wraps(func)
def wrapper(self: DocumentSyncListener, *args: P.args, **kwargs: P.kwargs) -> R | None:
if not self.session_views_async():
return None
return func(self, *args, **kwargs)
return wrapper


def is_regular_view(v: sublime.View) -> bool:
# Not from the quick panel (CTRL+P), and not a special view like a console, output panel or find-in-files panels.
Expand Down Expand Up @@ -327,6 +347,7 @@ def session_buffers_async(self, capability: str | None = None) -> list[SessionBu
def session_views_async(self) -> list[SessionView]:
return list(self._session_views.values())

@requires_session
def on_text_changed_async(self, change_count: int, changes: Iterable[sublime.TextChange]) -> None:
if self.view.is_primary():
for sv in self.session_views_async():
Expand Down Expand Up @@ -364,9 +385,12 @@ def on_activated_async(self) -> None:
return
if not self._registered:
self._register_async()
session_views = self.session_views_async()
if not session_views:
return
if userprefs().show_code_actions:
self._do_code_actions_async()
for sv in self.session_views_async():
for sv in session_views:
if sv.code_lenses_needs_refresh:
sv.set_code_lenses_pending_refresh(needs_refresh=False)
sv.start_code_lenses_async()
Expand All @@ -381,6 +405,7 @@ def on_activated_async(self) -> None:
sb.set_inlay_hints_pending_refresh(needs_refresh=False)
sb.do_inlay_hints_async(self.view)

@requires_session
def on_selection_modified_async(self) -> None:
first_region, _ = self._update_stored_selection_async()
if first_region is None:
Expand Down Expand Up @@ -482,6 +507,7 @@ def on_query_context(self, key: str, operator: int, operand: Any, match_all: boo
return operand == bool(session_view.session_buffer.get_document_link_at_point(self.view, position))
return None

@requires_session
def on_hover(self, point: int, hover_zone: int) -> None:
if self.view.is_popup_visible():
return
Expand Down Expand Up @@ -524,6 +550,7 @@ def _on_hover_gutter_async(self, point: int) -> None:
location=point,
on_navigate=lambda href: self._on_navigate(href, point))

@requires_session
def on_text_command(self, command_name: str, args: dict | None) -> tuple[str, dict] | None:
if command_name == "auto_complete":
self._auto_complete_triggered_manually = True
Expand All @@ -539,6 +566,7 @@ def on_text_command(self, command_name: str, args: dict | None) -> tuple[str, di
return ('paste', {})
return None

@requires_session
def on_post_text_command(self, command_name: str, args: dict[str, Any] | None) -> None:
if command_name == 'paste':
format_on_paste = self.view.settings().get('lsp_format_on_paste', userprefs().lsp_format_on_paste)
Expand All @@ -552,6 +580,7 @@ def on_post_text_command(self, command_name: str, args: dict[str, Any] | None) -
# hide the popup when `esc` or arrows are pressed pressed
self.view.hide_popup()

@requires_session
def on_query_completions(self, prefix: str, locations: list[int]) -> sublime.CompletionList | None:
completion_list = sublime.CompletionList()
triggered_manually = self._auto_complete_triggered_manually
Expand Down