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

Don't restart servers when userprefs change #2448

Merged
merged 17 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
14 changes: 13 additions & 1 deletion plugin/core/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,9 @@ def present_diagnostics_async(
) -> None:
...

def redraw_diagnostics_async(self) -> None:
...

def on_request_started_async(self, request_id: int, request: Request) -> None:
...

Expand Down Expand Up @@ -663,6 +666,9 @@ def get_document_link_at_point(self, view: sublime.View, point: int) -> Document
def update_document_link(self, new_link: DocumentLink) -> None:
...

def redraw_document_links_async(self) -> None:
...

def do_semantic_tokens_async(self, view: sublime.View) -> None:
...

Expand All @@ -672,6 +678,9 @@ def set_semantic_tokens_pending_refresh(self, needs_refresh: bool = True) -> Non
def get_semantic_tokens(self) -> list[Any]:
...

def clear_semantic_tokens_async(self) -> None:
...

def do_inlay_hints_async(self, view: sublime.View) -> None:
...

Expand Down Expand Up @@ -1335,8 +1344,11 @@ def set_config_status_async(self, message: str) -> None:
:param message: The message
"""
self.config_status_message = message.strip()
self.redraw_config_status_async()

def redraw_config_status_async(self) -> None:
for sv in self.session_views_async():
self.config.set_view_status(sv.view, message)
self.config.set_view_status(sv.view, self.config_status_message)

def set_window_status_async(self, key: str, message: str) -> None:
self._status_messages[key] = message
Expand Down
30 changes: 24 additions & 6 deletions plugin/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .types import Settings
from .types import SettingsRegistration
from typing import Any, Callable
import json
import os
import sublime

Expand All @@ -15,11 +16,17 @@ class ClientConfigs:
def __init__(self) -> None:
self.all: dict[str, ClientConfig] = {}
self.external: dict[str, ClientConfig] = {}
self._listener: Callable[[str | None], None] | None = None
self._clients_listener: Callable[[str | None], None] | None = None
self._userprefs_listener: Callable[[], None] | None = None
self._clients_hash: int | None = None

def _notify_listener(self, config_name: str | None = None) -> None:
jwortmann marked this conversation as resolved.
Show resolved Hide resolved
if callable(self._listener):
self._listener(config_name)
if callable(self._clients_listener):
self._clients_listener(config_name)

def _notify_userprefs_listener(self) -> None:
if callable(self._userprefs_listener):
self._userprefs_listener()

def add_for_testing(self, config: ClientConfig) -> None:
assert config.name not in self.all
Expand Down Expand Up @@ -72,8 +79,14 @@ def update_configs(self) -> None:
global _settings_obj
if _settings_obj is None:
return
clients_dict = read_dict_setting(_settings_obj, "clients", {})
_clients_hash = hash(json.dumps(clients_dict, sort_keys=True))
if _clients_hash == self._clients_hash:
self._notify_userprefs_listener()
return
self._clients_hash = _clients_hash
clients = DottedDict(read_dict_setting(_settings_obj, "default_clients", {}))
clients.update(read_dict_setting(_settings_obj, "clients", {}))
clients.update(clients_dict)
self.all.clear()
self.all.update({name: ClientConfig.from_dict(name, d) for name, d in clients.get().items()})
self.all.update(self.external)
Expand Down Expand Up @@ -104,8 +117,13 @@ def enable(self, config_name: str) -> None:
def disable(self, config_name: str) -> None:
self._set_enabled(config_name, False)

def set_listener(self, recipient: Callable[[str | None], None]) -> None:
self._listener = recipient
def set_listeners(
self,
clients_listener: Callable[[str | None], None],
userprefs_listener: Callable[[], None]
) -> None:
self._clients_listener = clients_listener
self._userprefs_listener = userprefs_listener


_settings_obj: sublime.Settings | None = None
Expand Down
2 changes: 2 additions & 0 deletions plugin/core/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,8 @@ def set_view_status(self, view: sublime.View, message: str) -> None:
if sublime.load_settings("LSP.sublime-settings").get("show_view_status"):
status = f"{self.name} ({message})" if message else self.name
view.set_status(self.status_key, status)
else:
self.erase_view_status(view)

def erase_view_status(self, view: sublime.View) -> None:
view.erase_status(self.status_key)
Expand Down
17 changes: 16 additions & 1 deletion plugin/core/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,12 +522,27 @@ class WindowRegistry:
def __init__(self) -> None:
self._enabled = False
self._windows: dict[int, WindowManager] = {}
client_configs.set_listener(self._on_client_config_updated)
client_configs.set_listeners(self._on_client_config_updated, self._on_userprefs_updated)
rchl marked this conversation as resolved.
Show resolved Hide resolved

def _on_client_config_updated(self, config_name: str | None = None) -> None:
for wm in self._windows.values():
wm.get_config_manager().update(config_name)

def _on_userprefs_updated(self) -> None:
sublime.set_timeout_async(self._on_userprefs_updated_async)

def _on_userprefs_updated_async(self) -> None:
for wm in self._windows.values():
wm.on_diagnostics_updated()
for session in wm.get_sessions():
session.redraw_config_status_async()
for sb in session.session_buffers_async():
sb.redraw_document_links_async()
if not userprefs().semantic_highlighting:
sb.clear_semantic_tokens_async()
for sv in session.session_views_async():
sv.redraw_diagnostics_async()
jwortmann marked this conversation as resolved.
Show resolved Hide resolved

def enable(self) -> None:
self._enabled = True
# Initialize manually at plugin_loaded as we'll miss out on "on_new_window_async" events.
Expand Down
22 changes: 16 additions & 6 deletions plugin/session_buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,14 +426,20 @@ def _do_document_link_async(self, view: sublime.View, version: int) -> None:

def _on_document_link_async(self, view: sublime.View, response: list[DocumentLink] | None) -> None:
self._document_links = response or []
self.redraw_document_links_async()

def redraw_document_links_async(self) -> None:
if self._document_links and userprefs().link_highlight_style == "underline":
view.add_regions(
"lsp_document_link",
[range_to_region(link["range"], view) for link in self._document_links],
scope="markup.underline.link.lsp",
flags=DOCUMENT_LINK_FLAGS)
view = self.some_view()
if not view:
return
regions = [range_to_region(link["range"], view) for link in self._document_links]
for sv in self.session_views:
sv.view.add_regions(
"lsp_document_link", regions, scope="markup.underline.link.lsp", flags=DOCUMENT_LINK_FLAGS)
rchl marked this conversation as resolved.
Show resolved Hide resolved
else:
view.erase_regions("lsp_document_link")
for sv in self.session_views:
sv.view.erase_regions("lsp_document_link")

def get_document_link_at_point(self, view: sublime.View, point: int) -> DocumentLink | None:
for link in self._document_links:
Expand Down Expand Up @@ -702,6 +708,10 @@ def set_semantic_tokens_pending_refresh(self, needs_refresh: bool = True) -> Non
def get_semantic_tokens(self) -> list[SemanticToken]:
return self.semantic_tokens.tokens

def clear_semantic_tokens_async(self) -> None:
for sv in self.session_views:
self._clear_semantic_token_regions(sv.view)

# --- textDocument/inlayHint ----------------------------------------------------------------------------------

def do_inlay_hints_async(self, view: sublime.View) -> None:
Expand Down
20 changes: 11 additions & 9 deletions plugin/session_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class SessionView:
def __init__(self, listener: AbstractViewListener, session: Session, uri: DocumentUri) -> None:
self._view = listener.view
self._session = session
self._diagnostics_data_per_severity: dict[tuple[int, bool], DiagnosticSeverityData] = {}
self._diagnostic_annotations = DiagnosticsAnnotationsView(self._view, session.config.name)
self._initialize_region_keys()
self._active_requests: dict[int, ActiveRequest] = {}
Expand Down Expand Up @@ -301,22 +302,23 @@ def diagnostics_tag_scope(self, tag: int) -> str | None:
def present_diagnostics_async(
self, is_view_visible: bool, data_per_severity: dict[tuple[int, bool], DiagnosticSeverityData]
) -> None:
self._diagnostics_data_per_severity = data_per_severity
jwortmann marked this conversation as resolved.
Show resolved Hide resolved
self.redraw_diagnostics_async()
listener = self.listener()
if listener:
listener.on_diagnostics_updated_async(is_view_visible)

def redraw_diagnostics_async(self) -> None:
flags = userprefs().diagnostics_highlight_style_flags() # for single lines
multiline_flags = None if userprefs().show_multiline_diagnostics_highlights else sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.NO_UNDO # noqa: E501
level = userprefs().show_diagnostics_severity_level
for sev in reversed(range(1, len(DIAGNOSTIC_SEVERITY) + 1)):
self._draw_diagnostics(
data_per_severity, sev, level, flags[sev - 1] or DIAGNOSTIC_SEVERITY[sev - 1][4], multiline=False)
self._draw_diagnostics(
data_per_severity, sev, level, multiline_flags or DIAGNOSTIC_SEVERITY[sev - 1][5], multiline=True)
self._draw_diagnostics(sev, level, flags[sev - 1] or DIAGNOSTIC_SEVERITY[sev - 1][4], multiline=False)
self._draw_diagnostics(sev, level, multiline_flags or DIAGNOSTIC_SEVERITY[sev - 1][5], multiline=True)
self._diagnostic_annotations.draw(self.session_buffer.diagnostics)
listener = self.listener()
if listener:
listener.on_diagnostics_updated_async(is_view_visible)

def _draw_diagnostics(
self,
data_per_severity: dict[tuple[int, bool], DiagnosticSeverityData],
severity: int,
max_severity_level: int,
flags: int,
Expand All @@ -325,7 +327,7 @@ def _draw_diagnostics(
ICON_FLAGS = sublime.HIDE_ON_MINIMAP | sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.NO_UNDO
key = self.diagnostics_key(severity, multiline)
tags = {tag: TagData(f'{key}_tags_{tag}') for tag in DIAGNOSTIC_TAG_VALUES}
data = data_per_severity.get((severity, multiline))
data = self._diagnostics_data_per_severity.get((severity, multiline))
if data and severity <= max_severity_level:
non_tag_regions = data.regions
for tag, regions in data.regions_with_tag.items():
Expand Down