Skip to content

Commit

Permalink
Don't restart servers when userprefs changes
Browse files Browse the repository at this point in the history
  • Loading branch information
jwortmann committed Apr 15, 2024
1 parent 5891ff4 commit 18db9d0
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 23 deletions.
14 changes: 13 additions & 1 deletion plugin/core/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,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 @@ -650,6 +653,9 @@ def get_document_link_at_point(self, view: sublime.View, point: int) -> Optional
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 @@ -659,6 +665,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 @@ -1322,8 +1331,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 @@ -5,6 +5,7 @@
from .types import Settings
from .types import SettingsRegistration
from .typing import Any, Optional, Dict, Callable
import json
import os
import sublime

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

def _notify_listener(self, config_name: Optional[str] = None) -> None:
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 @@ -71,8 +78,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 @@ -103,8 +116,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[[Optional[str]], None]) -> None:
self._listener = recipient
def set_listeners(
self,
clients_listener: Callable[[Optional[str]], None],
userprefs_listener: Callable[[], None]
) -> None:
self._clients_listener = clients_listener
self._userprefs_listener = userprefs_listener


_settings_obj = None # type: Optional[sublime.Settings]
Expand Down
2 changes: 2 additions & 0 deletions plugin/core/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,8 @@ def set_view_status(self, view: sublime.View, message: str) -> None:
if sublime.load_settings("LSP.sublime-settings").get("show_view_status"):
status = "{} ({})".format(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 = {} # type: 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)

def _on_client_config_updated(self, config_name: Optional[str] = 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()

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 @@ -418,14 +418,20 @@ def _do_document_link_async(self, view: sublime.View, version: int) -> None:

def _on_document_link_async(self, view: sublime.View, response: Optional[List[DocumentLink]]) -> 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)
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) -> Optional[DocumentLink]:
for link in self._document_links:
Expand Down Expand Up @@ -692,6 +698,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 @@ -55,6 +55,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 = {} # type: Dict[Tuple[int, bool], DiagnosticSeverityData]
self._diagnostic_annotations = DiagnosticsAnnotationsView(self._view, session.config.name)
self._initialize_region_keys()
self._active_requests = {} # type: Dict[int, ActiveRequest]
Expand Down Expand Up @@ -300,22 +301,23 @@ def diagnostics_tag_scope(self, tag: int) -> Optional[str]:
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
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 @@ -324,7 +326,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('{}_tags_{}'.format(key, 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

0 comments on commit 18db9d0

Please sign in to comment.